dcell 0.10.0 → 0.12.0.pre
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/CHANGES.md +4 -0
- data/Gemfile +1 -1
- data/README.md +85 -4
- data/benchmarks/messaging.rb +7 -1
- data/benchmarks/receiver.rb +3 -3
- data/dcell.gemspec +3 -3
- data/explorer/index.html.erb +1 -1
- data/lib/dcell.rb +5 -18
- data/lib/dcell/actor_proxy.rb +26 -1
- data/lib/dcell/celluloid_ext.rb +19 -8
- data/lib/dcell/directory.rb +3 -15
- data/lib/dcell/explorer.rb +0 -1
- data/lib/dcell/mailbox_proxy.rb +8 -12
- data/lib/dcell/messages.rb +7 -20
- data/lib/dcell/node.rb +20 -24
- data/lib/dcell/node_manager.rb +2 -34
- data/lib/dcell/registries/cassandra_adapter.rb +32 -0
- data/lib/dcell/registries/moneta_adapter.rb +7 -0
- data/lib/dcell/registries/redis_adapter.rb +31 -0
- data/lib/dcell/registries/zk_adapter.rb +39 -1
- data/lib/dcell/router.rb +0 -22
- data/lib/dcell/server.rb +1 -1
- data/lib/dcell/version.rb +1 -1
- data/spec/dcell/directory_spec.rb +1 -1
- data/spec/dcell/global_spec.rb +0 -4
- data/spec/spec_helper.rb +3 -6
- data/spec/support/registry_examples.rb +18 -0
- data/spec/test_node.rb +3 -7
- metadata +66 -30
- data/lib/dcell/registries/gossip/core.rb +0 -235
- data/lib/dcell/registries/gossip_adapter.rb +0 -26
- data/spec/dcell/registries/gossip_adapter_spec.rb +0 -6
metadata
CHANGED
@@ -1,52 +1,67 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dcell
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.12.0.pre
|
5
|
+
prerelease: 7
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Tony Arcieri
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-11-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: celluloid
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 0.
|
21
|
+
version: 0.12.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.12.0
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
31
|
name: celluloid-zmq
|
27
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
28
33
|
none: false
|
29
34
|
requirements:
|
30
35
|
- - ~>
|
31
36
|
- !ruby/object:Gem::Version
|
32
|
-
version: 0.
|
37
|
+
version: 0.12.0
|
33
38
|
type: :runtime
|
34
39
|
prerelease: false
|
35
|
-
version_requirements:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 0.12.0
|
36
46
|
- !ruby/object:Gem::Dependency
|
37
47
|
name: reel
|
38
|
-
requirement:
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
39
49
|
none: false
|
40
50
|
requirements:
|
41
|
-
- -
|
51
|
+
- - ! '>='
|
42
52
|
- !ruby/object:Gem::Version
|
43
|
-
version: 0
|
53
|
+
version: '0'
|
44
54
|
type: :runtime
|
45
55
|
prerelease: false
|
46
|
-
version_requirements:
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
47
62
|
- !ruby/object:Gem::Dependency
|
48
63
|
name: redis
|
49
|
-
requirement:
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
50
65
|
none: false
|
51
66
|
requirements:
|
52
67
|
- - ! '>='
|
@@ -54,10 +69,15 @@ dependencies:
|
|
54
69
|
version: '0'
|
55
70
|
type: :runtime
|
56
71
|
prerelease: false
|
57
|
-
version_requirements:
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
58
78
|
- !ruby/object:Gem::Dependency
|
59
79
|
name: redis-namespace
|
60
|
-
requirement:
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
61
81
|
none: false
|
62
82
|
requirements:
|
63
83
|
- - ! '>='
|
@@ -65,10 +85,15 @@ dependencies:
|
|
65
85
|
version: '0'
|
66
86
|
type: :runtime
|
67
87
|
prerelease: false
|
68
|
-
version_requirements:
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
69
94
|
- !ruby/object:Gem::Dependency
|
70
95
|
name: moneta
|
71
|
-
requirement:
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
72
97
|
none: false
|
73
98
|
requirements:
|
74
99
|
- - ! '>='
|
@@ -76,10 +101,15 @@ dependencies:
|
|
76
101
|
version: '0'
|
77
102
|
type: :runtime
|
78
103
|
prerelease: false
|
79
|
-
version_requirements:
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
80
110
|
- !ruby/object:Gem::Dependency
|
81
111
|
name: rake
|
82
|
-
requirement:
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
83
113
|
none: false
|
84
114
|
requirements:
|
85
115
|
- - ! '>='
|
@@ -87,10 +117,15 @@ dependencies:
|
|
87
117
|
version: '0'
|
88
118
|
type: :development
|
89
119
|
prerelease: false
|
90
|
-
version_requirements:
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
91
126
|
- !ruby/object:Gem::Dependency
|
92
127
|
name: rspec
|
93
|
-
requirement:
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
94
129
|
none: false
|
95
130
|
requirements:
|
96
131
|
- - ! '>='
|
@@ -98,7 +133,12 @@ dependencies:
|
|
98
133
|
version: '0'
|
99
134
|
type: :development
|
100
135
|
prerelease: false
|
101
|
-
version_requirements:
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
102
142
|
description: DCell is an distributed object framework based on Celluloid built on
|
103
143
|
0MQ and Zookeeper
|
104
144
|
email:
|
@@ -143,8 +183,6 @@ files:
|
|
143
183
|
- lib/dcell/node.rb
|
144
184
|
- lib/dcell/node_manager.rb
|
145
185
|
- lib/dcell/registries/cassandra_adapter.rb
|
146
|
-
- lib/dcell/registries/gossip/core.rb
|
147
|
-
- lib/dcell/registries/gossip_adapter.rb
|
148
186
|
- lib/dcell/registries/moneta_adapter.rb
|
149
187
|
- lib/dcell/registries/redis_adapter.rb
|
150
188
|
- lib/dcell/registries/zk_adapter.rb
|
@@ -161,7 +199,6 @@ files:
|
|
161
199
|
- spec/dcell/explorer_spec.rb
|
162
200
|
- spec/dcell/global_spec.rb
|
163
201
|
- spec/dcell/node_spec.rb
|
164
|
-
- spec/dcell/registries/gossip_adapter_spec.rb
|
165
202
|
- spec/dcell/registries/moneta_adapter_spec.rb
|
166
203
|
- spec/dcell/registries/redis_adapter_spec.rb
|
167
204
|
- spec/dcell/registries/zk_adapter_spec.rb
|
@@ -187,12 +224,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
187
224
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
188
225
|
none: false
|
189
226
|
requirements:
|
190
|
-
- - ! '
|
227
|
+
- - ! '>'
|
191
228
|
- !ruby/object:Gem::Version
|
192
|
-
version:
|
229
|
+
version: 1.3.1
|
193
230
|
requirements: []
|
194
231
|
rubyforge_project:
|
195
|
-
rubygems_version: 1.8.
|
232
|
+
rubygems_version: 1.8.24
|
196
233
|
signing_key:
|
197
234
|
specification_version: 3
|
198
235
|
summary: An asynchronous distributed object framework based on Celluloid
|
@@ -203,7 +240,6 @@ test_files:
|
|
203
240
|
- spec/dcell/explorer_spec.rb
|
204
241
|
- spec/dcell/global_spec.rb
|
205
242
|
- spec/dcell/node_spec.rb
|
206
|
-
- spec/dcell/registries/gossip_adapter_spec.rb
|
207
243
|
- spec/dcell/registries/moneta_adapter_spec.rb
|
208
244
|
- spec/dcell/registries/redis_adapter_spec.rb
|
209
245
|
- spec/dcell/registries/zk_adapter_spec.rb
|
@@ -1,235 +0,0 @@
|
|
1
|
-
require 'forwardable'
|
2
|
-
require 'uri'
|
3
|
-
|
4
|
-
module DCell
|
5
|
-
module Gossip
|
6
|
-
class VersionVector
|
7
|
-
extend Forwardable
|
8
|
-
|
9
|
-
class Status
|
10
|
-
STATES = [:precedes, :equal, :concurrent, :succeeds]
|
11
|
-
|
12
|
-
STATES.each do |state|
|
13
|
-
class_eval %Q{
|
14
|
-
def #{state}?
|
15
|
-
@state == '#{state}'.to_sym
|
16
|
-
end
|
17
|
-
def #{state}!
|
18
|
-
@state = '#{state}'.to_sym
|
19
|
-
end
|
20
|
-
}
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def_delegators :@versions, :[]
|
25
|
-
attr_reader :versions
|
26
|
-
|
27
|
-
def initialize(id)
|
28
|
-
@versions = {}
|
29
|
-
update_at id
|
30
|
-
end
|
31
|
-
|
32
|
-
def update_at(id)
|
33
|
-
observe id
|
34
|
-
@versions[id] += 1
|
35
|
-
end
|
36
|
-
|
37
|
-
def observe(id)
|
38
|
-
@versions[id] ||= 0
|
39
|
-
end
|
40
|
-
|
41
|
-
def covers?(nodes, vector)
|
42
|
-
nodes.each do |node|
|
43
|
-
# We must have an entry for the node
|
44
|
-
return false unless @versions.keys.include? node
|
45
|
-
|
46
|
-
# And someone else must have seen the entry, too.
|
47
|
-
version = vector.versions[node] || 0
|
48
|
-
return false if @versions[node] != version
|
49
|
-
end
|
50
|
-
true
|
51
|
-
end
|
52
|
-
|
53
|
-
def compare(other)
|
54
|
-
v1_bigger = false
|
55
|
-
v2_bigger = false
|
56
|
-
|
57
|
-
@versions.each do |id, version|
|
58
|
-
if not other.versions.include? id
|
59
|
-
# Version vectors behave like vector clocks, with slightly
|
60
|
-
# different update rules. A vector clock assumes that all
|
61
|
-
# processes initially observe version 0. Since we don't
|
62
|
-
# know the topology ahead of time, we assume that a missing
|
63
|
-
# entry corresponds to a node that has not yet been discovered,
|
64
|
-
# and thus the version is implicitly 0.
|
65
|
-
v1_bigger = true if version > 0
|
66
|
-
else
|
67
|
-
v1_bigger = true if version > other.versions[id]
|
68
|
-
v2_bigger = true if version < other.versions[id]
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
other.versions.each do |id, version|
|
73
|
-
if not @versions.include? id
|
74
|
-
# See the comment above for the similar v1_bigger calculation.
|
75
|
-
v2_bigger = true if version > 0
|
76
|
-
else
|
77
|
-
v2_bigger = true if version > @versions[id]
|
78
|
-
v1_bigger = true if version < @versions[id]
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
status = Status.new
|
83
|
-
if !v1_bigger
|
84
|
-
if !v2_bigger
|
85
|
-
status.equal!
|
86
|
-
else
|
87
|
-
status.precedes!
|
88
|
-
end
|
89
|
-
elsif !v2_bigger
|
90
|
-
status.succeeds!
|
91
|
-
else
|
92
|
-
status.concurrent!
|
93
|
-
end
|
94
|
-
return status
|
95
|
-
end
|
96
|
-
|
97
|
-
# Take the entrywise maximum of the versions
|
98
|
-
def merge!(other)
|
99
|
-
@versions.each do |id, version|
|
100
|
-
if other.versions.include? id
|
101
|
-
@versions[id] = other.versions[id] if other.versions[id] > version
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
other.versions.each do |id, version|
|
106
|
-
if @versions.include? id
|
107
|
-
@versions[id] = @versions[id] if @versions[id] > version
|
108
|
-
end
|
109
|
-
end
|
110
|
-
@versions.merge!(other.versions.reject { |k,v| @versions.include? k })
|
111
|
-
end
|
112
|
-
|
113
|
-
def to_s
|
114
|
-
@versions.to_s
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
class Store
|
119
|
-
class Data
|
120
|
-
attr_reader :key, :value, :vector
|
121
|
-
def initialize(key, value, id)
|
122
|
-
@key = key
|
123
|
-
@value = value
|
124
|
-
@vector = VersionVector.new(id)
|
125
|
-
@changed = true
|
126
|
-
end
|
127
|
-
|
128
|
-
def clear
|
129
|
-
@vector.update_at DCell.id
|
130
|
-
@deleted = true
|
131
|
-
@value = nil
|
132
|
-
@changed = true
|
133
|
-
end
|
134
|
-
|
135
|
-
def deleted?
|
136
|
-
@deleted
|
137
|
-
end
|
138
|
-
|
139
|
-
def changed?
|
140
|
-
@changed
|
141
|
-
end
|
142
|
-
|
143
|
-
def observe
|
144
|
-
@vector.observe DCell.id
|
145
|
-
end
|
146
|
-
|
147
|
-
def value=(value)
|
148
|
-
if @value != value
|
149
|
-
@vector.update_at DCell.id
|
150
|
-
@value = value
|
151
|
-
@deleted = value.nil?
|
152
|
-
@changed = true
|
153
|
-
Celluloid::Logger.debug "Updated key #{key} to #{value}"
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
def merge!(other)
|
158
|
-
# We'll take other if we preceded it, or if we are
|
159
|
-
# concurrent with it (though issue a warning that data
|
160
|
-
# has been lost).
|
161
|
-
status = @vector.compare(other.vector)
|
162
|
-
if status.precedes? or status.concurrent?
|
163
|
-
if other.value != @value
|
164
|
-
if status.concurrent?
|
165
|
-
Celluloid::Logger.debug "Dropping local copy of concurrent data for #{@key}"
|
166
|
-
else
|
167
|
-
Celluloid::Logger.debug "Observed updated data #{key} => #{other.value}"
|
168
|
-
end
|
169
|
-
@value = other.value
|
170
|
-
@deleted = @value.nil?
|
171
|
-
end
|
172
|
-
elsif status.succeeds?
|
173
|
-
Celluloid::Logger.debug "Local data succeeds for #{@key}"
|
174
|
-
end
|
175
|
-
@vector.merge!(other.vector) unless status.equal?
|
176
|
-
|
177
|
-
# Stop gossiping if this has been seen by every known, healthy node
|
178
|
-
nodes = DCell::Node.all.map { |node| node.state == :connected }
|
179
|
-
@changed = false if @vector.covers?(nodes, other.vector)
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
def initialize(base_path)
|
184
|
-
@base_path = base_path
|
185
|
-
@data = {}
|
186
|
-
end
|
187
|
-
|
188
|
-
def path_for(key)
|
189
|
-
"#{@base_path}/#{key}"
|
190
|
-
end
|
191
|
-
|
192
|
-
def get(key)
|
193
|
-
data = @data[path_for(key)]
|
194
|
-
return data.value if data and not data.deleted?
|
195
|
-
nil
|
196
|
-
end
|
197
|
-
|
198
|
-
def set(key, value)
|
199
|
-
key = path_for(key)
|
200
|
-
if not @data[key]
|
201
|
-
@data[key] = Data.new(key, value, DCell.id)
|
202
|
-
else
|
203
|
-
@data[key].value = value
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
def observe(other)
|
208
|
-
key = other.key
|
209
|
-
if not @data[key]
|
210
|
-
@data[key] = other
|
211
|
-
@data[key].observe
|
212
|
-
Celluloid::Logger.debug "Observed new data #{key} => #{other.value}"
|
213
|
-
else
|
214
|
-
@data[key].merge!(other)
|
215
|
-
end
|
216
|
-
end
|
217
|
-
|
218
|
-
def keys
|
219
|
-
@data.keys.map { |k| k =~ /#{@base_path}\/(.+)$/; $1 }
|
220
|
-
end
|
221
|
-
|
222
|
-
def clear
|
223
|
-
@data.map(&:clear)
|
224
|
-
end
|
225
|
-
|
226
|
-
def changed
|
227
|
-
@data.each_value.select(&:changed?)
|
228
|
-
end
|
229
|
-
|
230
|
-
def values
|
231
|
-
@data.values
|
232
|
-
end
|
233
|
-
end
|
234
|
-
end
|
235
|
-
end
|
@@ -1,26 +0,0 @@
|
|
1
|
-
require 'forwardable'
|
2
|
-
|
3
|
-
module DCell
|
4
|
-
module Registry
|
5
|
-
class GossipAdapter
|
6
|
-
extend Forwardable
|
7
|
-
PREFIX = "/dcell"
|
8
|
-
|
9
|
-
def_delegator :@global_registry, :get, :get_global
|
10
|
-
def_delegator :@global_registry, :set, :set_global
|
11
|
-
def_delegator :@global_registry, :clear, :clear_globals
|
12
|
-
def_delegator :@global_registry, :keys, :global_keys
|
13
|
-
def_delegators :@global_registry, :changed, :observe, :values
|
14
|
-
|
15
|
-
def initialize(options)
|
16
|
-
# Convert all options to symbols :/
|
17
|
-
options = options.inject({}) { |h,(k,v)| h[k.to_sym] = v; h }
|
18
|
-
|
19
|
-
@env = options[:env] || 'production'
|
20
|
-
@base_path = options[:namespace] || "#{PREFIX}/#{@env}"
|
21
|
-
|
22
|
-
@global_registry = Gossip::Store.new("#{@base_path}/globals")
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|