mitchellh-lightcloud 0.5 → 0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +21 -0
- data/lib/lightcloud.rb +59 -29
- data/spec/lightcloud_spec.rb +41 -10
- metadata +1 -1
data/README.rdoc
CHANGED
@@ -12,6 +12,8 @@ http://opensource.plurk.com/LightCloud/
|
|
12
12
|
|
13
13
|
== Usage
|
14
14
|
|
15
|
+
You can use it with class methods:
|
16
|
+
|
15
17
|
require 'rubygems'
|
16
18
|
require 'lightcloud'
|
17
19
|
|
@@ -29,6 +31,25 @@ http://opensource.plurk.com/LightCloud/
|
|
29
31
|
|
30
32
|
print LightCloud.get("hello") # => nil
|
31
33
|
|
34
|
+
Or you can also use it with instances:
|
35
|
+
|
36
|
+
require 'rubygems'
|
37
|
+
require 'lightcloud'
|
38
|
+
|
39
|
+
LIGHT_CLOUD = {
|
40
|
+
'lookup1_A' => ['127.0.0.1:41401', '127.0.0.1:41402'],
|
41
|
+
'storage1_A' => ['192.168.0.2:51401', '192.168.0.2:51402']
|
42
|
+
}
|
43
|
+
|
44
|
+
lookup_nodes, storage_nodes = LightCloud.generate_nodes(LIGHT_CLOUD)
|
45
|
+
cloud = LightCloud.new(lookup_nodes, storage_nodes)
|
46
|
+
|
47
|
+
cloud.set("hello", "world")
|
48
|
+
print cloud.get("hello") # => world
|
49
|
+
cloud.delete("hello")
|
50
|
+
|
51
|
+
print cloud.get("hello") # => nil
|
52
|
+
|
32
53
|
== Installation
|
33
54
|
|
34
55
|
sudo gem install mitchellh-lightcloud
|
data/lib/lightcloud.rb
CHANGED
@@ -35,46 +35,76 @@ require File.join(File.dirname(__FILE__), 'tyrant_client')
|
|
35
35
|
# print LightCloud.get("hello") # => nil
|
36
36
|
#
|
37
37
|
class LightCloud
|
38
|
-
VERSION = '0.
|
38
|
+
VERSION = '0.6'
|
39
39
|
DEFAULT_SYSTEM = 'default'
|
40
40
|
|
41
41
|
@@systems = {}
|
42
42
|
|
43
|
-
|
43
|
+
# Initialize LightCloud as an instance instead of using the class
|
44
|
+
# methods. Expects the same arguments as LightCloud.init, except
|
45
|
+
# this will return a new instance of LightCloud.
|
46
|
+
#
|
47
|
+
# Any nodes initialized through here will not work one class methods.
|
48
|
+
def initialize(lookup_nodes, storage_nodes, system=DEFAULT_SYSTEM)
|
49
|
+
@systems = {}
|
50
|
+
self.class.init(lookup_nodes, storage_nodes, system, @systems)
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.init(lookup_nodes, storage_nodes, system=DEFAULT_SYSTEM, systems=@@systems)
|
44
54
|
lookup_ring, name_to_l_nodes = self.generate_ring(lookup_nodes)
|
45
55
|
storage_ring, name_to_s_nodes = self.generate_ring(storage_nodes)
|
46
56
|
|
47
|
-
|
57
|
+
systems[system] = [lookup_ring, storage_ring, name_to_l_nodes, name_to_s_nodes]
|
48
58
|
end
|
49
59
|
|
50
60
|
#--
|
51
61
|
# Get/Set/Delete
|
52
62
|
#++
|
63
|
+
# Sets a value to a key on a LightCloud instance. See
|
64
|
+
# LightCloud.set for more information
|
65
|
+
def set(key, value, system=DEFAULT_SYSTEM)
|
66
|
+
self.class.set(key, value, system, @systems)
|
67
|
+
end
|
68
|
+
|
69
|
+
#
|
70
|
+
# Gets a value to a key on a LightCloud instance. See
|
71
|
+
# LightCloud.get for more information.
|
72
|
+
def get(key, system=DEFAULT_SYSTEM)
|
73
|
+
self.class.get(key, system, @systems)
|
74
|
+
end
|
75
|
+
|
76
|
+
#
|
77
|
+
# Delete a value from a LightCloud instance. See
|
78
|
+
# LightCloud.delete for more information.
|
79
|
+
def delete(key, system=DEFAULT_SYSTEM)
|
80
|
+
self.class.delete(key, system, @systems)
|
81
|
+
end
|
82
|
+
|
53
83
|
#
|
54
84
|
# Sets a value to a key in the LightCloud system.
|
55
85
|
#
|
56
86
|
# Set first checks to see if the key is already stored. If it is
|
57
87
|
# it uses that same node to store the new value. Otherwise, it
|
58
88
|
# determines where to store the value based on the hash_ring
|
59
|
-
def self.set(key, value, system=DEFAULT_SYSTEM)
|
60
|
-
storage_node = self.locate_node_or_init(key, system)
|
89
|
+
def self.set(key, value, system=DEFAULT_SYSTEM, systems=@@systems)
|
90
|
+
storage_node = self.locate_node_or_init(key, system, systems)
|
61
91
|
return storage_node.set(key, value)
|
62
92
|
end
|
63
93
|
|
64
94
|
#
|
65
95
|
# Gets a value based on a key.
|
66
|
-
def self.get(key, system=DEFAULT_SYSTEM)
|
96
|
+
def self.get(key, system=DEFAULT_SYSTEM, systems=@@systems)
|
67
97
|
result = nil
|
68
98
|
|
69
99
|
# Try to lookup key directly
|
70
|
-
storage_node = self.get_storage_ring(system).get_node(key)
|
100
|
+
storage_node = self.get_storage_ring(system, systems).get_node(key)
|
71
101
|
value = storage_node.get(key)
|
72
102
|
|
73
103
|
result = value unless value.nil?
|
74
104
|
|
75
105
|
# Else use the lookup ring
|
76
106
|
if result.nil?
|
77
|
-
storage_node = self.locate_node(key, system)
|
107
|
+
storage_node = self.locate_node(key, system, systems)
|
78
108
|
|
79
109
|
result = storage_node.get(key) unless storage_node.nil?
|
80
110
|
end
|
@@ -85,11 +115,11 @@ class LightCloud
|
|
85
115
|
#
|
86
116
|
# Lookup the key and delete it from both the storage ring
|
87
117
|
# and lookup ring
|
88
|
-
def self.delete(key, system=DEFAULT_SYSTEM)
|
89
|
-
storage_node = self.locate_node(key, system)
|
118
|
+
def self.delete(key, system=DEFAULT_SYSTEM, systems=@@systems)
|
119
|
+
storage_node = self.locate_node(key, system, systems)
|
90
120
|
|
91
|
-
storage_node = get_storage_ring(system).get_node(key) if storage_node.nil?
|
92
|
-
lookup_nodes = get_lookup_ring(system).iterate_nodes(key)
|
121
|
+
storage_node = get_storage_ring(system, systems).get_node(key) if storage_node.nil?
|
122
|
+
lookup_nodes = get_lookup_ring(system, systems).iterate_nodes(key)
|
93
123
|
lookup_nodes.each_index do |i|
|
94
124
|
break if i > 1
|
95
125
|
|
@@ -103,13 +133,13 @@ class LightCloud
|
|
103
133
|
#--
|
104
134
|
# Lookup Cloud
|
105
135
|
#++
|
106
|
-
def self.locate_node_or_init(key, system)
|
107
|
-
storage_node = self.locate_node(key, system)
|
136
|
+
def self.locate_node_or_init(key, system, systems=@@systems)
|
137
|
+
storage_node = self.locate_node(key, system, systems)
|
108
138
|
|
109
139
|
if storage_node.nil?
|
110
|
-
storage_node = self.get_storage_ring(system).get_node(key)
|
140
|
+
storage_node = self.get_storage_ring(system, systems).get_node(key)
|
111
141
|
|
112
|
-
lookup_node = self.get_lookup_ring(system).get_node(key)
|
142
|
+
lookup_node = self.get_lookup_ring(system, systems).get_node(key)
|
113
143
|
lookup_node.set(key, storage_node.to_s)
|
114
144
|
end
|
115
145
|
|
@@ -119,8 +149,8 @@ class LightCloud
|
|
119
149
|
#
|
120
150
|
# Locates a node in the lookup ring, returning the node if it is found, or
|
121
151
|
# nil otherwise.
|
122
|
-
def self.locate_node(key, system=DEFAULT_SYSTEM)
|
123
|
-
nodes = self.get_lookup_ring(system).iterate_nodes(key)
|
152
|
+
def self.locate_node(key, system=DEFAULT_SYSTEM, systems=@@systems)
|
153
|
+
nodes = self.get_lookup_ring(system, systems).iterate_nodes(key)
|
124
154
|
|
125
155
|
lookups = 0
|
126
156
|
value = nil
|
@@ -137,14 +167,14 @@ class LightCloud
|
|
137
167
|
return nil if value.nil?
|
138
168
|
|
139
169
|
if lookups == 0
|
140
|
-
return self.get_storage_node(value, system)
|
170
|
+
return self.get_storage_node(value, system, systems)
|
141
171
|
else
|
142
|
-
return self._clean_up_ring(key, value, system)
|
172
|
+
return self._clean_up_ring(key, value, system, systems)
|
143
173
|
end
|
144
174
|
end
|
145
175
|
|
146
|
-
def self._clean_up_ring(key, value, system)
|
147
|
-
nodes = self.get_lookup_ring(system).iterate_nodes(key)
|
176
|
+
def self._clean_up_ring(key, value, system, systems=@@systems)
|
177
|
+
nodes = self.get_lookup_ring(system, systems).iterate_nodes(key)
|
148
178
|
|
149
179
|
nodes.each_index do |i|
|
150
180
|
break if i > 1
|
@@ -157,25 +187,25 @@ class LightCloud
|
|
157
187
|
end
|
158
188
|
end
|
159
189
|
|
160
|
-
return self.get_storage_node(value, system)
|
190
|
+
return self.get_storage_node(value, system, systems)
|
161
191
|
end
|
162
192
|
|
163
193
|
#--
|
164
194
|
# Accessors for rings
|
165
195
|
#++
|
166
|
-
def self.get_lookup_ring(system=DEFAULT_SYSTEM)
|
167
|
-
|
196
|
+
def self.get_lookup_ring(system=DEFAULT_SYSTEM, systems=@@systems)
|
197
|
+
systems[system][0]
|
168
198
|
end
|
169
199
|
|
170
|
-
def self.get_storage_ring(system=DEFAULT_SYSTEM)
|
171
|
-
|
200
|
+
def self.get_storage_ring(system=DEFAULT_SYSTEM, systems=@@systems)
|
201
|
+
systems[system][1]
|
172
202
|
end
|
173
203
|
|
174
204
|
#--
|
175
205
|
# Accessors for nodes
|
176
206
|
#++
|
177
|
-
def self.get_storage_node(name, system=DEFAULT_SYSTEM)
|
178
|
-
|
207
|
+
def self.get_storage_node(name, system=DEFAULT_SYSTEM, systems=@@systems)
|
208
|
+
systems[system][3][name]
|
179
209
|
end
|
180
210
|
|
181
211
|
#--
|
data/spec/lightcloud_spec.rb
CHANGED
@@ -86,8 +86,8 @@ describe LightCloud do
|
|
86
86
|
|
87
87
|
describe "locating or initting a storage node by key" do
|
88
88
|
after do
|
89
|
-
LightCloud.should_receive(:locate_node).with(@key, anything).once.and_return(@storage_node)
|
90
|
-
LightCloud.locate_node_or_init(@key, LightCloud::DEFAULT_SYSTEM)
|
89
|
+
LightCloud.should_receive(:locate_node).with(@key, anything, anything).once.and_return(@storage_node)
|
90
|
+
LightCloud.locate_node_or_init(@key, LightCloud::DEFAULT_SYSTEM, anything)
|
91
91
|
end
|
92
92
|
|
93
93
|
it "should just return the storage node if it was found" do
|
@@ -106,7 +106,7 @@ describe LightCloud do
|
|
106
106
|
describe "locating a storage node by key" do
|
107
107
|
it "should return the storage node if the key is found in the lookup ring" do
|
108
108
|
@nodes[0].should_receive(:get).with(@key).and_return(@storage_node)
|
109
|
-
LightCloud.should_receive(:get_storage_node).with(@storage_node, anything).once
|
109
|
+
LightCloud.should_receive(:get_storage_node).with(@storage_node, anything, anything).once
|
110
110
|
|
111
111
|
LightCloud.locate_node(@key)
|
112
112
|
end
|
@@ -118,7 +118,7 @@ describe LightCloud do
|
|
118
118
|
it "should attempt to clean up the lookup ring if the value is NOT found in the first node" do
|
119
119
|
@nodes[1].should_receive(:get).with(@key).and_return(@storage_node)
|
120
120
|
LightCloud.should_not_receive(:get_storage_node)
|
121
|
-
LightCloud.should_receive(:_clean_up_ring).with(@key, @storage_node, anything).once
|
121
|
+
LightCloud.should_receive(:_clean_up_ring).with(@key, @storage_node, anything, anything).once
|
122
122
|
|
123
123
|
LightCloud.locate_node(@key)
|
124
124
|
end
|
@@ -144,7 +144,7 @@ describe LightCloud do
|
|
144
144
|
end
|
145
145
|
|
146
146
|
it "should return the storage node lookup" do
|
147
|
-
LightCloud.should_receive(:get_storage_node).with(@storage_node, anything).once
|
147
|
+
LightCloud.should_receive(:get_storage_node).with(@storage_node, anything, anything).once
|
148
148
|
end
|
149
149
|
end
|
150
150
|
end
|
@@ -162,7 +162,7 @@ describe LightCloud do
|
|
162
162
|
end
|
163
163
|
|
164
164
|
it "should lookup the node or init for where to place key" do
|
165
|
-
LightCloud.should_receive(:locate_node_or_init).with(@key, anything).once.and_return(@generic_node)
|
165
|
+
LightCloud.should_receive(:locate_node_or_init).with(@key, anything, anything).once.and_return(@generic_node)
|
166
166
|
end
|
167
167
|
|
168
168
|
it "should set the value on the node returned by locate node or init" do
|
@@ -190,7 +190,7 @@ describe LightCloud do
|
|
190
190
|
it "should get the storage node from the lookup table if it can't find the key directly" do
|
191
191
|
@generic_node.should_receive(:get).once.and_return(nil)
|
192
192
|
|
193
|
-
LightCloud.should_receive(:locate_node).with(@key, anything).and_return(@storage_valid_node)
|
193
|
+
LightCloud.should_receive(:locate_node).with(@key, anything, anything).and_return(@storage_valid_node)
|
194
194
|
@storage_valid_node.should_receive(:get).with(@key).and_return(@value)
|
195
195
|
end
|
196
196
|
end
|
@@ -217,13 +217,13 @@ describe LightCloud do
|
|
217
217
|
end
|
218
218
|
|
219
219
|
it "should first try to get the storage node from lookup ring" do
|
220
|
-
LightCloud.should_receive(:locate_node).with(@key, anything).once.and_return(@generic_node)
|
220
|
+
LightCloud.should_receive(:locate_node).with(@key, anything, anything).once.and_return(@generic_node)
|
221
221
|
LightCloud.should_not_receive(:get_storage_ring)
|
222
222
|
|
223
223
|
end
|
224
224
|
|
225
225
|
it "should try to get storage node directly if lookup ring failed" do
|
226
|
-
LightCloud.should_receive(:locate_node).with(@key, anything).once.and_return(nil)
|
226
|
+
LightCloud.should_receive(:locate_node).with(@key, anything, anything).once.and_return(nil)
|
227
227
|
LightCloud.should_receive(:get_storage_ring).once.and_return(@storage_ring)
|
228
228
|
@storage_ring.should_receive(:get_node).with(@key).once.and_return(@generic_node)
|
229
229
|
|
@@ -231,9 +231,40 @@ describe LightCloud do
|
|
231
231
|
end
|
232
232
|
|
233
233
|
it "should only delete from a storage node if one was found" do
|
234
|
-
LightCloud.should_receive(:locate_node).with(@key, anything).once.and_return(nil)
|
234
|
+
LightCloud.should_receive(:locate_node).with(@key, anything, anything).once.and_return(nil)
|
235
235
|
LightCloud.should_receive(:get_storage_ring).once.and_return(@storage_ring)
|
236
236
|
@storage_ring.should_receive(:get_node).with(@key).once.and_return(nil)
|
237
237
|
end
|
238
238
|
end
|
239
|
+
|
240
|
+
describe "lightcloud instances" do
|
241
|
+
before do
|
242
|
+
cloud_config = {
|
243
|
+
'lookup1_A' => ['127.0.0.1:1234', '127.0.0.2:1234'],
|
244
|
+
'storage1_A' => ['127.0.0.1:4567', '127.0.0.2:4567']
|
245
|
+
}
|
246
|
+
|
247
|
+
@cloud = LightCloud.new(*LightCloud.generate_nodes(cloud_config))
|
248
|
+
end
|
249
|
+
|
250
|
+
it "should forward arguments to class method init on initialize" do
|
251
|
+
LightCloud.should_receive(:init).with('a', 'b', 'c', {}).once
|
252
|
+
LightCloud.new('a','b','c')
|
253
|
+
end
|
254
|
+
|
255
|
+
it "should forward set arguments to class method" do
|
256
|
+
LightCloud.should_receive(:set).with('key', 'value', anything, anything).once
|
257
|
+
@cloud.set('key', 'value')
|
258
|
+
end
|
259
|
+
|
260
|
+
it "should forward get arguments to class method" do
|
261
|
+
LightCloud.should_receive(:get).with('key', anything, anything).once
|
262
|
+
@cloud.get('key')
|
263
|
+
end
|
264
|
+
|
265
|
+
it "should forward delete arguments to class method" do
|
266
|
+
LightCloud.should_receive(:delete).with('key', anything, anything).once
|
267
|
+
@cloud.delete('key')
|
268
|
+
end
|
269
|
+
end
|
239
270
|
end
|