dcell 0.16.0 → 0.16.1
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.
- checksums.yaml +4 -4
- data/.rspec +1 -1
- data/.travis.yml +13 -2
- data/CHANGES.md +4 -0
- data/Gemfile +5 -4
- data/README.md +0 -1
- data/dcell.gemspec +5 -4
- data/examples/itchy.rb +4 -3
- data/examples/scratchy.rb +3 -3
- data/lib/dcell.rb +19 -6
- data/lib/dcell/actor_proxy.rb +3 -2
- data/lib/dcell/celluloid_ext.rb +5 -4
- data/lib/dcell/directory.rb +8 -0
- data/lib/dcell/explorer.rb +1 -1
- data/lib/dcell/node.rb +11 -1
- data/lib/dcell/node_manager.rb +30 -0
- data/lib/dcell/registries/cassandra_adapter.rb +13 -5
- data/lib/dcell/registries/mongodb_adapter.rb +85 -0
- data/lib/dcell/registries/redis_adapter.rb +13 -5
- data/lib/dcell/registries/zk_adapter.rb +40 -4
- data/lib/dcell/server.rb +4 -2
- data/lib/dcell/version.rb +1 -1
- data/spec/dcell/actor_proxy_spec.rb +3 -3
- data/spec/dcell/celluloid_ext_spec.rb +1 -1
- data/spec/dcell/directory_spec.rb +15 -1
- data/spec/dcell/explorer_spec.rb +1 -1
- data/spec/dcell/global_spec.rb +1 -1
- data/spec/dcell/node_spec.rb +2 -2
- data/spec/dcell/registries/mongodb_adapter_spec.rb +7 -0
- data/spec/dcell/registries/redis_adapter_spec.rb +3 -3
- data/spec/dcell/registries/zk_adapter_spec.rb +24 -3
- data/spec/options/01-options.rb +10 -0
- data/spec/options/02-registry.rb +13 -0
- data/spec/spec_helper.rb +9 -2
- data/spec/support/helpers.rb +1 -3
- data/spec/support/registry_examples.rb +1 -1
- data/spec/test_node.rb +6 -2
- metadata +35 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5b7abd2458deb859bd4f406ee25e70e2a2acefb1
|
4
|
+
data.tar.gz: 37da6fd6c1177b19898b048eade8700fd965cd25
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a37879c2a2962fcf4dbcb6b424357b1686e4689a4cefcb6627936d08c66ac998ccc0faac64d1c54d5eb26b3df8de7656fa5991677c7f9ad87493e2433b9a139b
|
7
|
+
data.tar.gz: 9566d8144677141bc87a371f3f8ba70641b78538e804ed79f3481417dd04e5b06aea6124980227e913789925ae5f5ea821258fd24dd25dfc5e2377f3bf5e2db9
|
data/.rspec
CHANGED
data/.travis.yml
CHANGED
@@ -1,5 +1,11 @@
|
|
1
|
+
language: ruby
|
2
|
+
|
1
3
|
before_install: sudo apt-get install libzmq3-dev
|
2
4
|
|
5
|
+
services:
|
6
|
+
- mongodb
|
7
|
+
- redis-server
|
8
|
+
|
3
9
|
rvm:
|
4
10
|
- 1.9.3
|
5
11
|
- 2.0.0
|
@@ -15,5 +21,10 @@ matrix:
|
|
15
21
|
- rvm: jruby-19mode
|
16
22
|
- rvm: rbx-19mode # rbx seems to be losing exception messages o_O
|
17
23
|
|
18
|
-
|
19
|
-
|
24
|
+
branches:
|
25
|
+
only:
|
26
|
+
- master
|
27
|
+
|
28
|
+
env:
|
29
|
+
- DCELL_TEST_ADAPTER=redis
|
30
|
+
- DCELL_TEST_ADAPTER=mongodb
|
data/CHANGES.md
CHANGED
data/Gemfile
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
2
|
|
3
|
-
gem 'celluloid', github: 'celluloid/celluloid',
|
4
|
-
gem 'celluloid-io', github: 'celluloid/celluloid-io',
|
5
|
-
gem 'celluloid-zmq', github: 'celluloid/celluloid-zmq',
|
3
|
+
gem 'celluloid', github: 'celluloid/celluloid', tag: 'v0.16.0'
|
4
|
+
gem 'celluloid-io', github: 'celluloid/celluloid-io', tag: 'v0.16.1'
|
5
|
+
gem 'celluloid-zmq', github: 'celluloid/celluloid-zmq', tag: 'v0.16.0'
|
6
6
|
gem 'celluloid-redis', github: 'celluloid/celluloid-redis', branch: 'master'
|
7
|
-
gem 'reel', github: 'celluloid/reel',
|
7
|
+
gem 'reel', github: 'celluloid/reel', tag: 'v0.4.0'
|
8
8
|
|
9
9
|
#gem 'ffi-rzmq', github: 'chuckremes/ffi-rzmq'
|
10
10
|
|
@@ -15,3 +15,4 @@ gem 'coveralls', require: false
|
|
15
15
|
gemspec
|
16
16
|
|
17
17
|
gem 'zk'
|
18
|
+
gem 'mongoid'
|
data/README.md
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
=====
|
3
3
|
[](http://rubygems.org/gems/dcell)
|
4
4
|
[](http://travis-ci.org/celluloid/dcell)
|
5
|
-
[](https://gemnasium.com/celluloid/dcell)
|
6
5
|
[](https://codeclimate.com/github/celluloid/dcell)
|
7
6
|
[](https://coveralls.io/r/celluloid/dcell)
|
8
7
|
|
data/dcell.gemspec
CHANGED
@@ -17,12 +17,13 @@ Gem::Specification.new do |gem|
|
|
17
17
|
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
18
|
gem.require_paths = ["lib"]
|
19
19
|
|
20
|
-
gem.add_runtime_dependency "celluloid", "
|
21
|
-
gem.add_runtime_dependency "celluloid-zmq", "
|
22
|
-
gem.add_runtime_dependency "reel"
|
20
|
+
gem.add_runtime_dependency "celluloid", "~> 0.16.0"
|
21
|
+
gem.add_runtime_dependency "celluloid-zmq", "~> 0.16.0"
|
22
|
+
gem.add_runtime_dependency "reel", "~> 0.4.0"
|
23
|
+
gem.add_runtime_dependency "http", "~> 0.5.0"
|
23
24
|
gem.add_runtime_dependency "celluloid-redis"
|
24
25
|
gem.add_runtime_dependency "redis-namespace"
|
25
26
|
|
26
27
|
gem.add_development_dependency "rake"
|
27
|
-
gem.add_development_dependency "rspec"
|
28
|
+
gem.add_development_dependency "rspec", "~> 2.14.0"
|
28
29
|
end
|
data/examples/itchy.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'dcell'
|
3
3
|
|
4
|
-
DCell.start :id => "itchy"
|
4
|
+
DCell.start :id => "itchy"
|
5
5
|
|
6
6
|
class Itchy
|
7
7
|
include Celluloid
|
@@ -12,12 +12,13 @@ class Itchy
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def fight
|
15
|
-
@n
|
16
|
-
if @n
|
15
|
+
@n += 1
|
16
|
+
if @n % 6 == 0
|
17
17
|
puts "Bite!"
|
18
18
|
else
|
19
19
|
puts "Fight!"
|
20
20
|
end
|
21
|
+
@n
|
21
22
|
end
|
22
23
|
end
|
23
24
|
|
data/examples/scratchy.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'dcell'
|
3
3
|
|
4
|
-
DCell.start
|
4
|
+
DCell.start
|
5
5
|
itchy_node = DCell::Node["itchy"]
|
6
6
|
|
7
7
|
puts "Fighting itchy! (check itchy's output)"
|
8
8
|
|
9
|
-
|
10
|
-
itchy_node[:itchy].fight
|
9
|
+
300.times do
|
10
|
+
puts itchy_node[:itchy].fight
|
11
11
|
sleep 1
|
12
12
|
end
|
data/lib/dcell.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'celluloid'
|
2
2
|
require 'reel'
|
3
3
|
require 'celluloid/zmq'
|
4
|
+
require 'socket'
|
5
|
+
require 'securerandom'
|
4
6
|
|
5
7
|
Celluloid::ZMQ.init
|
6
8
|
|
@@ -27,7 +29,6 @@ require 'dcell/celluloid_ext'
|
|
27
29
|
module DCell
|
28
30
|
class NotConfiguredError < RuntimeError; end # Not configured yet
|
29
31
|
|
30
|
-
DEFAULT_PORT = 7777 # Default DCell port
|
31
32
|
@config_lock = Mutex.new
|
32
33
|
|
33
34
|
class << self
|
@@ -45,11 +46,11 @@ module DCell
|
|
45
46
|
@config_lock.synchronize do
|
46
47
|
@configuration = {
|
47
48
|
'id' => generate_node_id,
|
48
|
-
'addr' => "tcp://127.0.0.1
|
49
|
+
'addr' => "tcp://127.0.0.1:*",
|
49
50
|
'registry' => {'adapter' => 'redis', 'server' => 'localhost'}
|
50
51
|
}.merge(options)
|
51
52
|
|
52
|
-
@me = Node.new @configuration['id'],
|
53
|
+
@me = Node.new @configuration['id'], nil
|
53
54
|
|
54
55
|
registry_adapter = @configuration['registry'][:adapter] || @configuration['registry']['adapter']
|
55
56
|
raise ArgumentError, "no registry adapter given in config" unless registry_adapter
|
@@ -64,8 +65,7 @@ module DCell
|
|
64
65
|
|
65
66
|
@registry = registry_class.new(@configuration['registry'])
|
66
67
|
|
67
|
-
|
68
|
-
DCell::Directory.set @configuration['id'], addr
|
68
|
+
ObjectSpace.define_finalizer(me, proc {Directory.remove @configuration['id']})
|
69
69
|
end
|
70
70
|
|
71
71
|
me
|
@@ -81,9 +81,22 @@ module DCell
|
|
81
81
|
def addr; @configuration['addr']; end
|
82
82
|
alias_method :address, :addr
|
83
83
|
|
84
|
+
def addr=(addr)
|
85
|
+
@configuration['addr'] = addr
|
86
|
+
@me.update_server_address addr
|
87
|
+
end
|
88
|
+
alias_method :address=, :addr=
|
89
|
+
|
84
90
|
# Attempt to generate a unique node ID for this machine
|
85
91
|
def generate_node_id
|
86
|
-
|
92
|
+
# a little bit more creative
|
93
|
+
if @registry.respond_to? :unique
|
94
|
+
@registry.unique
|
95
|
+
else
|
96
|
+
digest = Digest::SHA512.new
|
97
|
+
seed = Socket.gethostname + rand.to_s + Time.now.to_s + SecureRandom.hex
|
98
|
+
digest.update(seed).to_s
|
99
|
+
end
|
87
100
|
end
|
88
101
|
|
89
102
|
# Run the DCell application
|
data/lib/dcell/actor_proxy.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module DCell
|
2
2
|
# Proxy object for actors that live on remote nodes
|
3
|
-
class
|
3
|
+
class CellProxy < Celluloid::CellProxy; end
|
4
4
|
|
5
5
|
class ThreadHandleProxy
|
6
6
|
def kill
|
@@ -23,7 +23,8 @@ module DCell
|
|
23
23
|
@mailbox = mailbox
|
24
24
|
@thread = ThreadHandleProxy.new
|
25
25
|
@subject = SubjectProxy.new
|
26
|
+
@proxy = Celluloid::ActorProxy.new(@thread, @mailbox)
|
26
27
|
end
|
27
|
-
attr_reader :mailbox, :thread, :subject
|
28
|
+
attr_reader :mailbox, :thread, :subject, :proxy
|
28
29
|
end
|
29
30
|
end
|
data/lib/dcell/celluloid_ext.rb
CHANGED
@@ -9,7 +9,7 @@
|
|
9
9
|
# DCell overlay network back to the node where the actor actually exists
|
10
10
|
|
11
11
|
module Celluloid
|
12
|
-
class
|
12
|
+
class CellProxy
|
13
13
|
# Marshal uses respond_to? to determine if this object supports _dump so
|
14
14
|
# unfortunately we have to monkeypatch in _dump support as the proxy
|
15
15
|
# itself normally jacks respond_to? and proxies to the actor
|
@@ -33,11 +33,12 @@ module Celluloid
|
|
33
33
|
case mailbox
|
34
34
|
when ::DCell::MailboxProxy
|
35
35
|
actor = ::DCell::Actor.new(mailbox)
|
36
|
-
::DCell::
|
36
|
+
::DCell::CellProxy.new actor.proxy, mailbox, actor.subject.class.to_s
|
37
37
|
when ::Celluloid::Mailbox
|
38
38
|
actor = find_actor(mailbox)
|
39
|
-
::Celluloid::
|
40
|
-
else
|
39
|
+
::Celluloid::CellProxy.new actor.proxy, mailbox, actor.behavior.subject.class.to_s
|
40
|
+
else
|
41
|
+
::Kernel.raise "funny, I did not expect to see a #{mailbox.class} here"
|
41
42
|
end
|
42
43
|
end
|
43
44
|
|
data/lib/dcell/directory.rb
CHANGED
data/lib/dcell/explorer.rb
CHANGED
@@ -6,7 +6,7 @@ require 'erb'
|
|
6
6
|
module DCell
|
7
7
|
# Web UI for DCell
|
8
8
|
# TODO: rewrite this entire thing with less hax
|
9
|
-
class Explorer < Reel::Server
|
9
|
+
class Explorer < Reel::Server
|
10
10
|
ASSET_ROOT = Pathname.new File.expand_path("../../../explorer", __FILE__)
|
11
11
|
|
12
12
|
def initialize(host = "127.0.0.1", port = 7778)
|
data/lib/dcell/node.rb
CHANGED
@@ -18,6 +18,7 @@ module DCell
|
|
18
18
|
Celluloid::Logger.info "Connected to #{id}"
|
19
19
|
end
|
20
20
|
state :partitioned do
|
21
|
+
@heartbeat.cancel
|
21
22
|
Celluloid::Logger.warn "Communication with #{id} interrupted"
|
22
23
|
end
|
23
24
|
|
@@ -32,7 +33,7 @@ module DCell
|
|
32
33
|
include Enumerable
|
33
34
|
extend Forwardable
|
34
35
|
|
35
|
-
def_delegators "Celluloid::Actor[:node_manager]", :all, :each, :find, :[]
|
36
|
+
def_delegators "Celluloid::Actor[:node_manager]", :all, :each, :find, :[], :remove, :update
|
36
37
|
def_delegators "Celluloid::Actor[:node_manager]", :heartbeat_rate, :heartbeat_timeout
|
37
38
|
end
|
38
39
|
|
@@ -45,6 +46,15 @@ module DCell
|
|
45
46
|
attach self
|
46
47
|
end
|
47
48
|
|
49
|
+
def update_client_address( addr )
|
50
|
+
@addr = addr
|
51
|
+
send_heartbeat
|
52
|
+
end
|
53
|
+
|
54
|
+
def update_server_address(addr)
|
55
|
+
@addr = addr
|
56
|
+
end
|
57
|
+
|
48
58
|
def shutdown
|
49
59
|
transition :shutdown
|
50
60
|
@socket.close if @socket
|
data/lib/dcell/node_manager.rb
CHANGED
@@ -4,6 +4,8 @@ module DCell
|
|
4
4
|
include Celluloid::ZMQ
|
5
5
|
include Enumerable
|
6
6
|
|
7
|
+
trap_exit :node_died
|
8
|
+
|
7
9
|
attr_reader :heartbeat_rate, :heartbeat_timeout
|
8
10
|
|
9
11
|
def initialize
|
@@ -39,11 +41,39 @@ module DCell
|
|
39
41
|
node = DCell.me
|
40
42
|
else
|
41
43
|
node = Node.new(id, addr)
|
44
|
+
self.link node
|
42
45
|
end
|
43
46
|
|
44
47
|
@nodes[id] ||= node
|
45
48
|
@nodes[id]
|
46
49
|
end
|
47
50
|
alias_method :[], :find
|
51
|
+
|
52
|
+
def node_died(node, reason)
|
53
|
+
if reason.nil? # wtf?
|
54
|
+
# this wtf error seems to come from node socket writes
|
55
|
+
# when the socket is not reachable anymore
|
56
|
+
Celluloid::logger.debug "wtf?"
|
57
|
+
return
|
58
|
+
end
|
59
|
+
# Handle dead node???
|
60
|
+
end
|
61
|
+
|
62
|
+
def update(id)
|
63
|
+
addr = Directory[id]
|
64
|
+
return unless addr
|
65
|
+
if ( node = @nodes[id] ) and node.alive?
|
66
|
+
node.update_client_address( addr )
|
67
|
+
else
|
68
|
+
@nodes[id] = Node.new( id, addr )
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def remove(id)
|
73
|
+
if @nodes[id]
|
74
|
+
@nodes[id].terminate if @nodes[id].alive?
|
75
|
+
@nodes.delete(id)
|
76
|
+
end
|
77
|
+
end
|
48
78
|
end
|
49
79
|
end
|
@@ -48,12 +48,16 @@ module DCell
|
|
48
48
|
@global_registry = GlobalRegistry.new(cass, columnfamily)
|
49
49
|
end
|
50
50
|
|
51
|
-
def
|
52
|
-
@node_registry.
|
51
|
+
def remove_node(node)
|
52
|
+
@node_registry.remove node
|
53
|
+
end
|
54
|
+
|
55
|
+
def clear_all_nodes
|
56
|
+
@node_registry.clear_all
|
53
57
|
end
|
54
58
|
|
55
59
|
def clear_globals
|
56
|
-
@global_registry.
|
60
|
+
@global_registry.clear_all
|
57
61
|
end
|
58
62
|
|
59
63
|
class NodeRegistry
|
@@ -74,7 +78,11 @@ module DCell
|
|
74
78
|
@cass.get(@cf, "nodes").keys
|
75
79
|
end
|
76
80
|
|
77
|
-
def
|
81
|
+
def remove(node)
|
82
|
+
@cass.remove @cf, "nodes", { node_id => node }
|
83
|
+
end
|
84
|
+
|
85
|
+
def clear_all
|
78
86
|
@cass.del @cf, "nodes"
|
79
87
|
end
|
80
88
|
end
|
@@ -105,7 +113,7 @@ module DCell
|
|
105
113
|
@cass.get(@cf, "globals").keys
|
106
114
|
end
|
107
115
|
|
108
|
-
def
|
116
|
+
def clear_all
|
109
117
|
@cass.del @cf, "globals"
|
110
118
|
end
|
111
119
|
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'mongoid'
|
2
|
+
|
3
|
+
module DCell
|
4
|
+
module Registry
|
5
|
+
class MongodbAdapter
|
6
|
+
# Setup connection to mongodb
|
7
|
+
# config: path to mongoid configuration file
|
8
|
+
# env: mongoid environment to use
|
9
|
+
def initialize(options)
|
10
|
+
if options[:config]
|
11
|
+
Mongoid.load! options[:config], options[:env]
|
12
|
+
elsif options[:db]
|
13
|
+
Mongoid.connect_to options[:db]
|
14
|
+
end
|
15
|
+
if options[:options]
|
16
|
+
Mongoid.options = options[:options]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class DCellNode
|
21
|
+
include Mongoid::Document
|
22
|
+
|
23
|
+
field :key, type: String
|
24
|
+
field :value, type: Hash
|
25
|
+
end
|
26
|
+
|
27
|
+
class DCellGlobal
|
28
|
+
include Mongoid::Document
|
29
|
+
|
30
|
+
field :key, type: String
|
31
|
+
field :value, type: Hash
|
32
|
+
end
|
33
|
+
|
34
|
+
class Proxy
|
35
|
+
class << self
|
36
|
+
def set(storage, key, value)
|
37
|
+
entry = storage.find_or_create_by(key: key)
|
38
|
+
entry.value = {'v' => value}
|
39
|
+
entry.save!
|
40
|
+
value
|
41
|
+
end
|
42
|
+
|
43
|
+
def get(storage, key)
|
44
|
+
first = storage.where(key: key).first
|
45
|
+
if first and first.value
|
46
|
+
return first.value['v']
|
47
|
+
end
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
|
51
|
+
def all(storage)
|
52
|
+
keys = []
|
53
|
+
storage.each do |entry|
|
54
|
+
keys << entry.key
|
55
|
+
end
|
56
|
+
keys
|
57
|
+
end
|
58
|
+
|
59
|
+
def remove(storage, key)
|
60
|
+
begin
|
61
|
+
storage.where(key: key).delete
|
62
|
+
rescue
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def clear_all(storage)
|
67
|
+
storage.delete_all
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def get_node(node_id); Proxy.get(DCellNode, node_id) end
|
73
|
+
def set_node(node_id, addr); Proxy.set(DCellNode, node_id, addr) end
|
74
|
+
def nodes; Proxy.all(DCellNode) end
|
75
|
+
def remove_node(node_id); Proxy.remove(DCellNode, node_id) end
|
76
|
+
def clear_all_nodes; Proxy.clear_all(DCellNode) end
|
77
|
+
|
78
|
+
def get_global(key); Proxy.get(DCellGlobal, key) end
|
79
|
+
def set_global(key, value); Proxy.set(DCellGlobal, key, value) end
|
80
|
+
def global_keys; Proxy.all(DCellGlobal) end
|
81
|
+
def clear_globals; Proxy.clear_all(DCellGlobal) end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -19,12 +19,16 @@ module DCell
|
|
19
19
|
@global_registry = GlobalRegistry.new(@redis)
|
20
20
|
end
|
21
21
|
|
22
|
-
def
|
23
|
-
@node_registry.
|
22
|
+
def remove_node(node)
|
23
|
+
@node_registry.remove node
|
24
|
+
end
|
25
|
+
|
26
|
+
def clear_all_nodes
|
27
|
+
@node_registry.clear_all
|
24
28
|
end
|
25
29
|
|
26
30
|
def clear_globals
|
27
|
-
@global_registry.
|
31
|
+
@global_registry.clear_all
|
28
32
|
end
|
29
33
|
|
30
34
|
class NodeRegistry
|
@@ -44,7 +48,11 @@ module DCell
|
|
44
48
|
@redis.hkeys 'nodes'
|
45
49
|
end
|
46
50
|
|
47
|
-
def
|
51
|
+
def remove(node)
|
52
|
+
@redis.hdel 'nodes', node
|
53
|
+
end
|
54
|
+
|
55
|
+
def clear_all
|
48
56
|
@redis.del 'nodes'
|
49
57
|
end
|
50
58
|
end
|
@@ -74,7 +82,7 @@ module DCell
|
|
74
82
|
@redis.hkeys 'globals'
|
75
83
|
end
|
76
84
|
|
77
|
-
def
|
85
|
+
def clear_all
|
78
86
|
@redis.del 'globals'
|
79
87
|
end
|
80
88
|
end
|
@@ -46,15 +46,36 @@ module DCell
|
|
46
46
|
@base_path = File.join(base_path, name.to_s)
|
47
47
|
@ephemeral = ephemeral
|
48
48
|
@zk.mkdir_p @base_path
|
49
|
+
@events = {}
|
50
|
+
end
|
51
|
+
|
52
|
+
def register(key)
|
53
|
+
path = "#{@base_path}/#{key}"
|
54
|
+
@events[path] ||= @zk.register(path) do |event|
|
55
|
+
key = event.path.match(/#{@base_path}\/(\w+)/)[1]
|
56
|
+
@events[event.path].unsubscribe
|
57
|
+
@events[event.path] = nil
|
58
|
+
if event.node_changed?
|
59
|
+
Celluloid::logger.debug "zk callback: node changed!"
|
60
|
+
Node.update(key)
|
61
|
+
end
|
62
|
+
if event.node_deleted?
|
63
|
+
Celluloid::logger.debug "zk callback: node deleted!"
|
64
|
+
Node.remove(key)
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
49
68
|
end
|
50
69
|
|
51
70
|
def get(key)
|
52
|
-
|
71
|
+
register(key)
|
72
|
+
result, _ = @zk.get("#{@base_path}/#{key}", watch: true)
|
53
73
|
Marshal.load result
|
54
74
|
rescue ZK::Exceptions::NoNode
|
55
75
|
end
|
56
76
|
|
57
77
|
def set(key, value)
|
78
|
+
register(key)
|
58
79
|
path = "#{@base_path}/#{key}"
|
59
80
|
string = Marshal.dump value
|
60
81
|
@zk.set path, string
|
@@ -66,7 +87,21 @@ module DCell
|
|
66
87
|
@zk.children @base_path
|
67
88
|
end
|
68
89
|
|
69
|
-
def
|
90
|
+
def remove(key)
|
91
|
+
keys.each do |key|
|
92
|
+
path = "#{@base_path}/#{key}"
|
93
|
+
@zk.delete path
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def clear_all
|
98
|
+
# delete znodes so any registered
|
99
|
+
# callback is triggered
|
100
|
+
all.each do |key|
|
101
|
+
remove key
|
102
|
+
end
|
103
|
+
@events.values.compact.each(&:unsubscribe)
|
104
|
+
@events.clear
|
70
105
|
@zk.rm_rf @base_path
|
71
106
|
@zk.mkdir_p @base_path
|
72
107
|
end
|
@@ -75,12 +110,13 @@ module DCell
|
|
75
110
|
def get_node(node_id); @node_registry.get(node_id) end
|
76
111
|
def set_node(node_id, addr); @node_registry.set(node_id, addr) end
|
77
112
|
def nodes; @node_registry.all end
|
78
|
-
def
|
113
|
+
def remove_node(node_id); @node_registry.clear(node_id) end
|
114
|
+
def clear_all_nodes; @node_registry.clear_all end
|
79
115
|
|
80
116
|
def get_global(key); @global_registry.get(key) end
|
81
117
|
def set_global(key, value); @global_registry.set(key, value) end
|
82
118
|
def global_keys; @global_registry.all end
|
83
|
-
def clear_globals; @global_registry.
|
119
|
+
def clear_globals; @global_registry.clear_all end
|
84
120
|
|
85
121
|
end
|
86
122
|
end
|
data/lib/dcell/server.rb
CHANGED
@@ -10,11 +10,13 @@ module DCell
|
|
10
10
|
# The gossip protocol is dependent on the node manager
|
11
11
|
link Celluloid::Actor[:node_manager]
|
12
12
|
|
13
|
-
@addr = DCell.addr
|
14
13
|
@socket = PullSocket.new
|
15
14
|
|
16
15
|
begin
|
17
|
-
@socket.bind(
|
16
|
+
@socket.bind(DCell.addr)
|
17
|
+
real_addr = @socket.get(::ZMQ::LAST_ENDPOINT).strip
|
18
|
+
DCell::Directory.set DCell.id, real_addr
|
19
|
+
DCell.addr = real_addr
|
18
20
|
rescue IOError
|
19
21
|
@socket.close
|
20
22
|
raise
|
data/lib/dcell/version.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe DCell::
|
3
|
+
describe DCell::CellProxy do
|
4
4
|
before :all do
|
5
|
-
@node = DCell::Node[
|
6
|
-
@node.id.should ==
|
5
|
+
@node = DCell::Node[TEST_NODE[:id]]
|
6
|
+
@node.id.should == TEST_NODE[:id]
|
7
7
|
@remote_actor = @node[:test_actor]
|
8
8
|
|
9
9
|
class LocalActor
|
@@ -5,4 +5,18 @@ describe DCell::Directory do
|
|
5
5
|
DCell::Directory["foobar"] = "tcp://localhost:1870"
|
6
6
|
DCell::Directory["foobar"].should == "tcp://localhost:1870"
|
7
7
|
end
|
8
|
-
|
8
|
+
it "presents all stored addresses" do
|
9
|
+
DCell::Directory["foo"] = "tcp://fooaddress"
|
10
|
+
DCell::Directory["bar"] = "tcp://baraddress"
|
11
|
+
DCell::Directory.all.should include("foo")
|
12
|
+
DCell::Directory.all.should include("bar")
|
13
|
+
end
|
14
|
+
it "clears node addresses" do
|
15
|
+
DCell::Directory["foo"] = "tcp://fooaddress"
|
16
|
+
DCell::Directory["foobar"].should == "tcp://localhost:1870"
|
17
|
+
["foo", "foobar"].each do |node|
|
18
|
+
DCell::Directory.remove node
|
19
|
+
end
|
20
|
+
DCell::Directory["foobar"].should_not == "tcp://localhost:1870"
|
21
|
+
end
|
22
|
+
end
|
data/spec/dcell/explorer_spec.rb
CHANGED
@@ -12,6 +12,6 @@ describe DCell::Explorer do
|
|
12
12
|
|
13
13
|
it "reports the current node's status" do
|
14
14
|
response = Net::HTTP.get URI(EXPLORER_BASE)
|
15
|
-
response[%r{<
|
15
|
+
response[%r{<a href="/nodes/(.*?)">}, 1].should == DCell.id
|
16
16
|
end
|
17
17
|
end
|
data/spec/dcell/global_spec.rb
CHANGED
@@ -10,7 +10,7 @@ describe DCell::Global do
|
|
10
10
|
DCell::Global[:the_answer].should == 42
|
11
11
|
|
12
12
|
# Double check the global value is available on all nodes
|
13
|
-
node = DCell::Node[
|
13
|
+
node = DCell::Node[TEST_NODE[:id]]
|
14
14
|
node[:test_actor].the_answer.should == 42
|
15
15
|
end
|
16
16
|
|
data/spec/dcell/node_spec.rb
CHANGED
@@ -0,0 +1,7 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'dcell/registries/mongodb_adapter'
|
3
|
+
|
4
|
+
describe DCell::Registry::MongodbAdapter, :pending => TEST_ADEPTER != 'mongodb' && "no mongodb" do
|
5
|
+
subject { DCell::Registry::MongodbAdapter.new TEST_DB[:mongodb] }
|
6
|
+
it_behaves_like "a DCell registry"
|
7
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe DCell::Registry::RedisAdapter do
|
4
|
-
subject { DCell::Registry::RedisAdapter.new :
|
3
|
+
describe DCell::Registry::RedisAdapter, :pending => TEST_ADEPTER != 'redis' && "no redis" do
|
4
|
+
subject { DCell::Registry::RedisAdapter.new TEST_DB[:redis] }
|
5
5
|
it_behaves_like "a DCell registry"
|
6
|
-
end
|
6
|
+
end
|
@@ -1,7 +1,28 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'dcell/registries/zk_adapter'
|
3
3
|
|
4
|
-
describe DCell::Registry::ZkAdapter, :pending =>
|
5
|
-
subject { DCell::Registry::ZkAdapter.new :
|
6
|
-
it_behaves_like "a DCell registry"
|
4
|
+
describe DCell::Registry::ZkAdapter, :pending => TEST_ADEPTER != 'zk' && "no zookeeper" do
|
5
|
+
subject { DCell::Registry::ZkAdapter.new TEST_DB[:zk] }
|
6
|
+
it_behaves_like "a DCell registry" do
|
7
|
+
context "when one znode changes" do
|
8
|
+
it "updates a node" do
|
9
|
+
expect(DCell::Node).to receive(:update).with("foo")
|
10
|
+
subject.set_node("foo", "tcp://fooaddress")
|
11
|
+
# WARNING: only by calling get_node we renew the watcher
|
12
|
+
subject.get_node("foo").should eq("tcp://fooaddress")
|
13
|
+
subject.set_node("foo", "tcp://newaddress")
|
14
|
+
sleep 0.8 # takes some time to zookeeper watchers to take full effect
|
15
|
+
end
|
16
|
+
end
|
17
|
+
context "when one znode is deleted" do
|
18
|
+
it "deletes a node" do
|
19
|
+
expect(DCell::Node).to receive(:remove).with("foo")
|
20
|
+
subject.set_node("foo", "tcp://fooaddress")
|
21
|
+
# WARNING: only by calling get_node we renew the watcher
|
22
|
+
subject.get_node("foo").should eq("tcp://fooaddress")
|
23
|
+
subject.remove_node "foo"
|
24
|
+
sleep 0.8 # takes some time to zookeeper watchers to take full effect
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
7
28
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
TEST_ADEPTER = ENV['DCELL_TEST_ADAPTER'] || 'redis'
|
2
|
+
|
3
|
+
require "dcell/registries/#{TEST_ADEPTER}_adapter"
|
4
|
+
|
5
|
+
def test_db_options
|
6
|
+
options = {}
|
7
|
+
adapter = TEST_ADEPTER
|
8
|
+
if adapter
|
9
|
+
options[:registry] = {:adapter => adapter}
|
10
|
+
options[:registry].merge! TEST_DB[adapter.to_sym]
|
11
|
+
end
|
12
|
+
options
|
13
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -4,12 +4,19 @@ require 'coveralls'
|
|
4
4
|
Coveralls.wear!
|
5
5
|
|
6
6
|
require 'dcell'
|
7
|
+
Dir['./spec/options/*.rb'].map { |f| require f }
|
7
8
|
Dir['./spec/support/*.rb'].map { |f| require f }
|
8
9
|
|
9
10
|
RSpec.configure do |config|
|
10
11
|
config.before(:suite) do
|
11
|
-
|
12
|
-
|
12
|
+
options = {}
|
13
|
+
options.merge! test_db_options
|
14
|
+
begin
|
15
|
+
DCell.start options
|
16
|
+
rescue => e
|
17
|
+
puts e
|
18
|
+
raise
|
19
|
+
end
|
13
20
|
|
14
21
|
TestNode.start
|
15
22
|
TestNode.wait_until_ready
|
data/spec/support/helpers.rb
CHANGED
@@ -2,8 +2,6 @@
|
|
2
2
|
require 'rubygems'
|
3
3
|
|
4
4
|
module TestNode
|
5
|
-
PORT = 21264
|
6
|
-
|
7
5
|
def self.start
|
8
6
|
@pid = Process.spawn Gem.ruby, File.expand_path("../../test_node.rb", __FILE__)
|
9
7
|
unless @pid
|
@@ -18,7 +16,7 @@ module TestNode
|
|
18
16
|
socket = nil
|
19
17
|
30.times do
|
20
18
|
begin
|
21
|
-
socket = TCPSocket.open(
|
19
|
+
socket = TCPSocket.open(TEST_NODE[:addr], TEST_NODE[:port])
|
22
20
|
break if socket
|
23
21
|
rescue Errno::ECONNREFUSED
|
24
22
|
STDERR.print "."
|
data/spec/test_node.rb
CHANGED
@@ -6,7 +6,11 @@ require 'bundler'
|
|
6
6
|
Bundler.setup
|
7
7
|
|
8
8
|
require 'dcell'
|
9
|
-
|
9
|
+
Dir['./spec/options/*.rb'].map { |f| require f }
|
10
|
+
|
11
|
+
options = {:id => TEST_NODE[:id], :addr => "tcp://#{TEST_NODE[:addr]}:#{TEST_NODE[:port]}"}
|
12
|
+
options.merge! test_db_options
|
13
|
+
DCell.start options
|
10
14
|
|
11
15
|
class TestActor
|
12
16
|
include Celluloid
|
@@ -31,4 +35,4 @@ class TestActor
|
|
31
35
|
end
|
32
36
|
|
33
37
|
TestActor.supervise_as :test_actor
|
34
|
-
sleep
|
38
|
+
sleep
|
metadata
CHANGED
@@ -1,57 +1,71 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dcell
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.16.
|
4
|
+
version: 0.16.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tony Arcieri
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-12-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: celluloid
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 0.16.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 0.16.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: celluloid-zmq
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: 0.16.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 0.16.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: reel
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: 0.4.0
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
54
|
+
version: 0.4.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: http
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.5.0
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.5.0
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: celluloid-redis
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -98,16 +112,16 @@ dependencies:
|
|
98
112
|
name: rspec
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
100
114
|
requirements:
|
101
|
-
- - "
|
115
|
+
- - "~>"
|
102
116
|
- !ruby/object:Gem::Version
|
103
|
-
version:
|
117
|
+
version: 2.14.0
|
104
118
|
type: :development
|
105
119
|
prerelease: false
|
106
120
|
version_requirements: !ruby/object:Gem::Requirement
|
107
121
|
requirements:
|
108
|
-
- - "
|
122
|
+
- - "~>"
|
109
123
|
- !ruby/object:Gem::Version
|
110
|
-
version:
|
124
|
+
version: 2.14.0
|
111
125
|
description: DCell is an distributed object framework based on Celluloid built on
|
112
126
|
0MQ and Zookeeper
|
113
127
|
email:
|
@@ -155,6 +169,7 @@ files:
|
|
155
169
|
- lib/dcell/node.rb
|
156
170
|
- lib/dcell/node_manager.rb
|
157
171
|
- lib/dcell/registries/cassandra_adapter.rb
|
172
|
+
- lib/dcell/registries/mongodb_adapter.rb
|
158
173
|
- lib/dcell/registries/redis_adapter.rb
|
159
174
|
- lib/dcell/registries/zk_adapter.rb
|
160
175
|
- lib/dcell/responses.rb
|
@@ -170,8 +185,11 @@ files:
|
|
170
185
|
- spec/dcell/explorer_spec.rb
|
171
186
|
- spec/dcell/global_spec.rb
|
172
187
|
- spec/dcell/node_spec.rb
|
188
|
+
- spec/dcell/registries/mongodb_adapter_spec.rb
|
173
189
|
- spec/dcell/registries/redis_adapter_spec.rb
|
174
190
|
- spec/dcell/registries/zk_adapter_spec.rb
|
191
|
+
- spec/options/01-options.rb
|
192
|
+
- spec/options/02-registry.rb
|
175
193
|
- spec/spec_helper.rb
|
176
194
|
- spec/support/helpers.rb
|
177
195
|
- spec/support/registry_examples.rb
|
@@ -210,10 +228,12 @@ test_files:
|
|
210
228
|
- spec/dcell/explorer_spec.rb
|
211
229
|
- spec/dcell/global_spec.rb
|
212
230
|
- spec/dcell/node_spec.rb
|
231
|
+
- spec/dcell/registries/mongodb_adapter_spec.rb
|
213
232
|
- spec/dcell/registries/redis_adapter_spec.rb
|
214
233
|
- spec/dcell/registries/zk_adapter_spec.rb
|
234
|
+
- spec/options/01-options.rb
|
235
|
+
- spec/options/02-registry.rb
|
215
236
|
- spec/spec_helper.rb
|
216
237
|
- spec/support/helpers.rb
|
217
238
|
- spec/support/registry_examples.rb
|
218
239
|
- spec/test_node.rb
|
219
|
-
has_rdoc:
|