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
data/CHANGES.md
CHANGED
data/Gemfile
CHANGED
@@ -3,7 +3,7 @@ source "http://rubygems.org"
|
|
3
3
|
gem 'celluloid', :git => 'git://github.com/celluloid/celluloid'
|
4
4
|
gem 'celluloid-io', :git => 'git://github.com/celluloid/celluloid-io'
|
5
5
|
gem 'celluloid-zmq', :git => 'git://github.com/celluloid/celluloid-zmq'
|
6
|
-
|
6
|
+
gem 'reel', :git => 'git://github.com/celluloid/reel'
|
7
7
|
|
8
8
|
gem 'jruby-openssl', :platform => :jruby
|
9
9
|
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|

|
2
2
|
=====
|
3
|
-
[](http://travis-ci.org/celluloid/dcell)
|
4
4
|
[](https://gemnasium.com/celluloid/dcell)
|
5
5
|
|
6
6
|
> "Objects can message objects transparently that live on other machines
|
@@ -41,14 +41,86 @@ Like DCell? [Join the Celluloid Google Group][googlegroup]
|
|
41
41
|
[ffi-rzmq]: https://github.com/chuckremes/ffi-rzmq
|
42
42
|
[googlegroup]: http://groups.google.com/group/celluloid-ruby
|
43
43
|
|
44
|
-
### Is
|
44
|
+
### Is it any good?
|
45
45
|
|
46
|
-
Yes.
|
46
|
+
[Yes.](http://news.ycombinator.com/item?id=3067434)
|
47
47
|
|
48
48
|
### Is It "Production Ready™"?
|
49
49
|
|
50
50
|
Not entirely, but eager early adopters are welcome!
|
51
51
|
|
52
|
+
Installation
|
53
|
+
------------
|
54
|
+
|
55
|
+
Add this line to your application's Gemfile:
|
56
|
+
|
57
|
+
gem 'dcell'
|
58
|
+
|
59
|
+
And then execute:
|
60
|
+
|
61
|
+
$ bundle
|
62
|
+
|
63
|
+
Or install it yourself as:
|
64
|
+
|
65
|
+
$ gem install dcell
|
66
|
+
|
67
|
+
Inside of your Ruby program do:
|
68
|
+
|
69
|
+
require 'dcell'
|
70
|
+
|
71
|
+
...to pull it in as a dependency.
|
72
|
+
|
73
|
+
Example
|
74
|
+
-------
|
75
|
+
|
76
|
+
Create a ruby script with the following contents:
|
77
|
+
|
78
|
+
# node1.rb
|
79
|
+
|
80
|
+
require 'dcell'
|
81
|
+
|
82
|
+
class Duck
|
83
|
+
include Celluloid
|
84
|
+
|
85
|
+
def quack
|
86
|
+
puts "Quack!"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
Duck.supervise_as :duck_actor
|
91
|
+
|
92
|
+
DCell.start :id => "node1", :addr => "tcp://127.0.0.1:4000"
|
93
|
+
|
94
|
+
sleep
|
95
|
+
|
96
|
+
Now save and run the script via the command line and open a new shell. In there, create another ruby script:
|
97
|
+
|
98
|
+
# node2.rb
|
99
|
+
|
100
|
+
require 'dcell'
|
101
|
+
|
102
|
+
DCell.start :id => "node2", :addr => "tcp://127.0.0.1:4001", :directory => {:id => "node1", :addr => "tcp://127.0.0.1:4000"}
|
103
|
+
|
104
|
+
loop {
|
105
|
+
node = DCell::Node["node1"]
|
106
|
+
duck = node[:duck_actor]
|
107
|
+
duck.quack
|
108
|
+
sleep 3
|
109
|
+
}
|
110
|
+
|
111
|
+
When you run the second script in the second shell, you will see the following output in your first shell:
|
112
|
+
|
113
|
+
$ ruby node1.rb
|
114
|
+
I, [2012-08-30T20:00:00.759342 #26124] INFO -- : Connected to node1
|
115
|
+
I, [2012-08-30T20:00:04.454006 #26124] INFO -- : Connected to node2
|
116
|
+
Quack!
|
117
|
+
Quack!
|
118
|
+
Quack!
|
119
|
+
|
120
|
+
The loop in the second script looks up the node we registered in the first script, takes the registered Duck actor and calls the `quack` method every three seconds.
|
121
|
+
|
122
|
+
This is a basic example how individual DCell::Nodes have registered Celluloid actors which can be accessed remotely by other DCell::Nodes.
|
123
|
+
|
52
124
|
Supported Platforms
|
53
125
|
-------------------
|
54
126
|
|
@@ -60,7 +132,16 @@ box on MRI/YARV, and requires the following flags elsewhere:
|
|
60
132
|
* JRuby: --1.9 command line option, or JRUBY_OPTS=--1.9 environment variable
|
61
133
|
* rbx: -X19 command line option
|
62
134
|
|
135
|
+
Contributing to DCell
|
136
|
+
-------------------------
|
137
|
+
|
138
|
+
* Fork this repository on github
|
139
|
+
* Make your changes and send me a pull request
|
140
|
+
* If I like them I'll merge them
|
141
|
+
* If I've accepted a patch, feel free to ask for commit access
|
142
|
+
|
63
143
|
Copyright
|
64
144
|
---------
|
65
145
|
|
66
|
-
Copyright (c) 2012 Tony Arcieri.
|
146
|
+
Copyright (c) 2012 Tony Arcieri. Distributed under the MIT License.
|
147
|
+
See LICENSE.txt for further details.
|
data/benchmarks/messaging.rb
CHANGED
@@ -10,7 +10,7 @@ require 'dcell'
|
|
10
10
|
DCell.setup
|
11
11
|
DCell.run!
|
12
12
|
|
13
|
-
RECEIVER_PORT =
|
13
|
+
RECEIVER_PORT = 2043
|
14
14
|
|
15
15
|
$receiver_pid = Process.spawn Gem.ruby, File.expand_path("../receiver.rb", __FILE__)
|
16
16
|
STDERR.print "Waiting for test node to start up..."
|
@@ -52,6 +52,12 @@ class AsyncPerformanceTest
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
+
DCell.start :id => "messaging_node", :addr => "tcp://127.0.0.1:2042",
|
56
|
+
:directory => {
|
57
|
+
:id => "benchmark_receiver",
|
58
|
+
:addr => "tcp://127.0.0.1:#{RECEIVER_PORT}"
|
59
|
+
}
|
60
|
+
|
55
61
|
receiver = DCell::Node['benchmark_receiver']
|
56
62
|
progenator = receiver[:progenator]
|
57
63
|
|
data/benchmarks/receiver.rb
CHANGED
@@ -3,7 +3,7 @@ require 'bundler'
|
|
3
3
|
Bundler.setup
|
4
4
|
|
5
5
|
require 'dcell'
|
6
|
-
DCell.
|
6
|
+
DCell.start :id => 'benchmark_receiver', :addr => 'tcp://127.0.0.1:2043'
|
7
7
|
|
8
8
|
class AsyncReceiver
|
9
9
|
include Celluloid
|
@@ -29,8 +29,8 @@ class Progenator
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
-
class BenchmarkApplication < Celluloid::
|
33
|
-
supervise DCell::
|
32
|
+
class BenchmarkApplication < Celluloid::SupervisionGroup
|
33
|
+
supervise DCell::SupervisionGroup
|
34
34
|
supervise Progenator, :as => :progenator
|
35
35
|
end
|
36
36
|
|
data/dcell.gemspec
CHANGED
@@ -16,9 +16,9 @@ Gem::Specification.new do |gem|
|
|
16
16
|
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
17
17
|
gem.require_paths = ["lib"]
|
18
18
|
|
19
|
-
gem.add_runtime_dependency "celluloid", "~> 0.
|
20
|
-
gem.add_runtime_dependency "celluloid-zmq", "~> 0.
|
21
|
-
gem.add_runtime_dependency "reel"
|
19
|
+
gem.add_runtime_dependency "celluloid", "~> 0.12.0"
|
20
|
+
gem.add_runtime_dependency "celluloid-zmq", "~> 0.12.0"
|
21
|
+
gem.add_runtime_dependency "reel"
|
22
22
|
gem.add_runtime_dependency "redis"
|
23
23
|
gem.add_runtime_dependency "redis-namespace"
|
24
24
|
gem.add_runtime_dependency "moneta"
|
data/explorer/index.html.erb
CHANGED
@@ -89,6 +89,6 @@
|
|
89
89
|
================================================== -->
|
90
90
|
<!-- Placed at the end of the document so the pages load faster -->
|
91
91
|
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
|
92
|
-
<script src="js/bootstrap.min.js"></script>
|
92
|
+
<script src="/js/bootstrap.min.js"></script>
|
93
93
|
</body>
|
94
94
|
</html>
|
data/lib/dcell.rb
CHANGED
@@ -21,16 +21,13 @@ require 'dcell/info_service'
|
|
21
21
|
require 'dcell/registries/redis_adapter'
|
22
22
|
require 'dcell/registries/moneta_adapter'
|
23
23
|
|
24
|
-
require 'dcell/registries/gossip/core'
|
25
|
-
require 'dcell/registries/gossip_adapter'
|
26
|
-
|
27
24
|
require 'dcell/celluloid_ext'
|
28
25
|
|
29
26
|
# Distributed Celluloid
|
30
27
|
module DCell
|
31
28
|
class NotConfiguredError < RuntimeError; end # Not configured yet
|
32
29
|
|
33
|
-
DEFAULT_PORT =
|
30
|
+
DEFAULT_PORT = 7890 # Default DCell port
|
34
31
|
@config_lock = Mutex.new
|
35
32
|
|
36
33
|
class << self
|
@@ -39,7 +36,7 @@ module DCell
|
|
39
36
|
# Configure DCell with the following options:
|
40
37
|
#
|
41
38
|
# * id: to identify the local node, defaults to hostname
|
42
|
-
# * addr: 0MQ address of the local node (e.g. tcp://4.3.2.1:
|
39
|
+
# * addr: 0MQ address of the local node (e.g. tcp://4.3.2.1:7890)
|
43
40
|
# *
|
44
41
|
def setup(options = {})
|
45
42
|
# Stringify keys :/
|
@@ -54,16 +51,6 @@ module DCell
|
|
54
51
|
|
55
52
|
@me = Node.new @configuration['id'], @configuration['addr']
|
56
53
|
|
57
|
-
# Specify the directory server (defaults to me), and add it
|
58
|
-
# to the local directory.
|
59
|
-
directory = @configuration['directory'] || {}
|
60
|
-
directory = directory.inject({}) { |h,(k,v)| h[k.to_s] = v; h }
|
61
|
-
directory = {
|
62
|
-
'id' => @configuration['id'],
|
63
|
-
'addr' => @configuration['addr']
|
64
|
-
}.merge(directory)
|
65
|
-
DCell::Directory.set directory['id'], directory['addr']
|
66
|
-
|
67
54
|
registry_adapter = @configuration['registry'][:adapter] || @configuration['registry']['adapter']
|
68
55
|
raise ArgumentError, "no registry adapter given in config" unless registry_adapter
|
69
56
|
|
@@ -101,12 +88,12 @@ module DCell
|
|
101
88
|
|
102
89
|
# Run the DCell application
|
103
90
|
def run
|
104
|
-
DCell::
|
91
|
+
DCell::SupervisionGroup.run
|
105
92
|
end
|
106
93
|
|
107
94
|
# Run the DCell application in the background
|
108
95
|
def run!
|
109
|
-
DCell::
|
96
|
+
DCell::SupervisionGroup.run!
|
110
97
|
end
|
111
98
|
|
112
99
|
# Start combines setup and run! into a single step
|
@@ -117,7 +104,7 @@ module DCell
|
|
117
104
|
end
|
118
105
|
|
119
106
|
# DCell's actor dependencies
|
120
|
-
class
|
107
|
+
class SupervisionGroup < Celluloid::SupervisionGroup
|
121
108
|
supervise NodeManager, :as => :node_manager
|
122
109
|
supervise Server, :as => :dcell_server
|
123
110
|
supervise InfoService, :as => :info
|
data/lib/dcell/actor_proxy.rb
CHANGED
@@ -1,4 +1,29 @@
|
|
1
1
|
module DCell
|
2
2
|
# Proxy object for actors that live on remote nodes
|
3
3
|
class ActorProxy < Celluloid::ActorProxy; end
|
4
|
-
|
4
|
+
|
5
|
+
class ThreadHandleProxy
|
6
|
+
def kill
|
7
|
+
raise NotImplementedError, "remote kill not supported"
|
8
|
+
end
|
9
|
+
|
10
|
+
def join
|
11
|
+
raise NotImplementedError, "remote join not supported"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class SubjectProxy
|
16
|
+
def class
|
17
|
+
"[remote]"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Actor
|
22
|
+
def initialize(mailbox)
|
23
|
+
@mailbox = mailbox
|
24
|
+
@thread = ThreadHandleProxy.new
|
25
|
+
@subject = SubjectProxy.new
|
26
|
+
end
|
27
|
+
attr_reader :mailbox, :thread, :subject
|
28
|
+
end
|
29
|
+
end
|
data/lib/dcell/celluloid_ext.rb
CHANGED
@@ -28,16 +28,27 @@ module Celluloid
|
|
28
28
|
# Create an actor proxy object which routes messages over DCell's overlay
|
29
29
|
# network and back to the original mailbox
|
30
30
|
def self._load(string)
|
31
|
-
mailbox = Celluloid::Mailbox._load(string)
|
31
|
+
mailbox = ::Celluloid::Mailbox._load(string)
|
32
32
|
|
33
33
|
case mailbox
|
34
|
-
when DCell::MailboxProxy
|
35
|
-
DCell::
|
36
|
-
|
37
|
-
|
38
|
-
|
34
|
+
when ::DCell::MailboxProxy
|
35
|
+
actor = ::DCell::Actor.new(mailbox)
|
36
|
+
::DCell::ActorProxy.new actor
|
37
|
+
when ::Celluloid::Mailbox
|
38
|
+
actor = find_actor(mailbox)
|
39
|
+
::Celluloid::ActorProxy.new(actor)
|
40
|
+
else ::Kernel.raise "funny, I did not expect to see a #{mailbox.class} here"
|
39
41
|
end
|
40
42
|
end
|
43
|
+
|
44
|
+
def self.find_actor(mailbox)
|
45
|
+
::Thread.list.each do |t|
|
46
|
+
if actor = t[:actor]
|
47
|
+
return actor if actor.mailbox == mailbox
|
48
|
+
end
|
49
|
+
end
|
50
|
+
::Kernel.raise "no actor found for mailbox: #{mailbox.inspect}"
|
51
|
+
end
|
41
52
|
end
|
42
53
|
|
43
54
|
class Mailbox
|
@@ -45,7 +56,7 @@ module Celluloid
|
|
45
56
|
# be reached remotely.
|
46
57
|
def _dump(level)
|
47
58
|
mailbox_id = DCell::Router.register self
|
48
|
-
"#{mailbox_id}@#{DCell.id}
|
59
|
+
"#{mailbox_id}@#{DCell.id}"
|
49
60
|
end
|
50
61
|
|
51
62
|
# Create a mailbox proxy object which routes messages over DCell's overlay
|
@@ -70,7 +81,7 @@ module Celluloid
|
|
70
81
|
class Future
|
71
82
|
def _dump(level)
|
72
83
|
mailbox_id = DCell::Router.register self
|
73
|
-
"#{mailbox_id}@#{DCell.id}
|
84
|
+
"#{mailbox_id}@#{DCell.id}"
|
74
85
|
end
|
75
86
|
|
76
87
|
def self._load(string)
|
data/lib/dcell/directory.rb
CHANGED
@@ -3,33 +3,21 @@ module DCell
|
|
3
3
|
module Directory
|
4
4
|
extend self
|
5
5
|
|
6
|
-
@@directory = {}
|
7
|
-
@@directory_lock = Mutex.new
|
8
|
-
|
9
6
|
# Get the URL for a particular Node ID
|
10
7
|
def get(node_id)
|
11
|
-
|
12
|
-
@@directory[node_id]
|
13
|
-
end
|
8
|
+
DCell.registry.get_node node_id
|
14
9
|
end
|
15
10
|
alias_method :[], :get
|
16
11
|
|
17
12
|
# Set the address of a particular Node ID
|
18
13
|
def set(node_id, addr)
|
19
|
-
|
20
|
-
@@directory[node_id] = addr
|
21
|
-
end
|
14
|
+
DCell.registry.set_node node_id, addr
|
22
15
|
end
|
23
16
|
alias_method :[]=, :set
|
24
17
|
|
25
18
|
# List all of the node IDs in the directory
|
26
19
|
def all
|
27
|
-
|
28
|
-
end
|
29
|
-
|
30
|
-
# Clear the directory.
|
31
|
-
def clear
|
32
|
-
@@directory_lock.synchronize { @@directory.clear }
|
20
|
+
DCell.registry.nodes
|
33
21
|
end
|
34
22
|
end
|
35
23
|
end
|
data/lib/dcell/explorer.rb
CHANGED
data/lib/dcell/mailbox_proxy.rb
CHANGED
@@ -4,12 +4,13 @@ module DCell
|
|
4
4
|
class MailboxProxy
|
5
5
|
class InvalidNodeError < StandardError; end
|
6
6
|
|
7
|
-
def initialize(node_id,
|
7
|
+
def initialize(node_id, mailbox_id)
|
8
8
|
raise ArgumentError, "no mailbox_id given" unless mailbox_id
|
9
|
-
|
9
|
+
|
10
10
|
@node_id = node_id
|
11
11
|
@node = Node[node_id]
|
12
|
-
|
12
|
+
raise ArgumentError, "invalid node_id given" unless @node
|
13
|
+
|
13
14
|
@mailbox_id = mailbox_id
|
14
15
|
end
|
15
16
|
|
@@ -24,12 +25,7 @@ module DCell
|
|
24
25
|
|
25
26
|
# Send a message to the mailbox
|
26
27
|
def <<(message)
|
27
|
-
@node.send_message! Message::Relay.new(
|
28
|
-
end
|
29
|
-
|
30
|
-
# Send a system event
|
31
|
-
def system_event(event)
|
32
|
-
@node.send_message! Message::SystemEvent.new(@mailbox_id, event)
|
28
|
+
@node.send_message! Message::Relay.new(self, message)
|
33
29
|
end
|
34
30
|
|
35
31
|
# Is the remote mailbox still alive?
|
@@ -39,12 +35,12 @@ module DCell
|
|
39
35
|
|
40
36
|
# Custom marshaller for compatibility with Celluloid::Mailbox marshalling
|
41
37
|
def _dump(level)
|
42
|
-
"#{@mailbox_id}@#{@node_id}
|
38
|
+
"#{@mailbox_id}@#{@node_id}"
|
43
39
|
end
|
44
40
|
|
45
41
|
# Loader for custom marshal format
|
46
42
|
def self._load(string)
|
47
|
-
mailbox_id, node_id
|
43
|
+
mailbox_id, node_id = string.split("@")
|
48
44
|
|
49
45
|
if DCell.id == node_id
|
50
46
|
# If we're on the local node, find the real mailbox
|
@@ -53,7 +49,7 @@ module DCell
|
|
53
49
|
mailbox
|
54
50
|
else
|
55
51
|
# Create a proxy to the mailbox on the remote node
|
56
|
-
DCell::MailboxProxy.new(node_id,
|
52
|
+
DCell::MailboxProxy.new(node_id, mailbox_id)
|
57
53
|
end
|
58
54
|
end
|
59
55
|
end
|
data/lib/dcell/messages.rb
CHANGED
@@ -8,14 +8,15 @@ module DCell
|
|
8
8
|
@id = object_id
|
9
9
|
end
|
10
10
|
|
11
|
-
#
|
12
|
-
class
|
13
|
-
def initialize
|
14
|
-
@
|
11
|
+
# Heartbeat messages inform other nodes this node is healthy
|
12
|
+
class Heartbeat < Message
|
13
|
+
def initialize
|
14
|
+
@id = DCell.id
|
15
15
|
end
|
16
16
|
|
17
17
|
def dispatch
|
18
|
-
Node
|
18
|
+
node = DCell::Node[@id]
|
19
|
+
node.handle_heartbeat if node
|
19
20
|
end
|
20
21
|
end
|
21
22
|
|
@@ -57,21 +58,7 @@ module DCell
|
|
57
58
|
end
|
58
59
|
|
59
60
|
def dispatch
|
60
|
-
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
# Send a system event to the given recipient
|
65
|
-
class SystemEvent < Message
|
66
|
-
attr_reader :recipient, :event
|
67
|
-
|
68
|
-
def initialize(recipient, event)
|
69
|
-
super()
|
70
|
-
@recipient, @event = recipient, event
|
71
|
-
end
|
72
|
-
|
73
|
-
def dispatch
|
74
|
-
DCell::Router.route_system_event @recipient, @event
|
61
|
+
@recipient << @message
|
75
62
|
end
|
76
63
|
end
|
77
64
|
end
|