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 CHANGED
@@ -1,3 +1,7 @@
1
+ HEAD
2
+ ----
3
+ * Switch default port to 7890 (7777 is heavily used by other programs)
4
+
1
5
  0.10.0
2
6
  ------
3
7
  * DCell::Explorer provides a web UI with Reel
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
- #gem 'reel', :git => 'git://github.com/celluloid/reel'
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
  ![DCell](https://github.com/celluloid/dcell/raw/master/logo.png)
2
2
  =====
3
- [![Build Status](http://travis-ci.org/celluloid/dcell.png)](http://travis-ci.org/celluloid/dcell)
3
+ [![Build Status](https://secure.travis-ci.org/celluloid/dcell.png?branch=master)](http://travis-ci.org/celluloid/dcell)
4
4
  [![Dependency Status](https://gemnasium.com/celluloid/dcell.png)](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 It Good?
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. See LICENSE.txt for further details.
146
+ Copyright (c) 2012 Tony Arcieri. Distributed under the MIT License.
147
+ See LICENSE.txt for further details.
@@ -10,7 +10,7 @@ require 'dcell'
10
10
  DCell.setup
11
11
  DCell.run!
12
12
 
13
- RECEIVER_PORT = 12345
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
 
@@ -3,7 +3,7 @@ require 'bundler'
3
3
  Bundler.setup
4
4
 
5
5
  require 'dcell'
6
- DCell.setup :id => 'benchmark_receiver', :addr => 'tcp://127.0.0.1:12345'
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::Group
33
- supervise DCell::Group
32
+ class BenchmarkApplication < Celluloid::SupervisionGroup
33
+ supervise DCell::SupervisionGroup
34
34
  supervise Progenator, :as => :progenator
35
35
  end
36
36
 
@@ -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.10.0"
20
- gem.add_runtime_dependency "celluloid-zmq", "~> 0.10.0"
21
- gem.add_runtime_dependency "reel", "~> 0.0.1"
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"
@@ -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>
@@ -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 = 7777 # Default DCell 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:7777)
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::Group.run
91
+ DCell::SupervisionGroup.run
105
92
  end
106
93
 
107
94
  # Run the DCell application in the background
108
95
  def run!
109
- DCell::Group.run!
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 Group < Celluloid::Group
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
@@ -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
- end
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
@@ -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::ActorProxy.new mailbox
36
- when Celluloid::Mailbox
37
- Celluloid::ActorProxy.new(mailbox)
38
- else raise "funny, I did not expect to see a #{mailbox.class} here"
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}@#{DCell.addr}"
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}@#{DCell.addr}"
84
+ "#{mailbox_id}@#{DCell.id}"
74
85
  end
75
86
 
76
87
  def self._load(string)
@@ -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
- @@directory_lock.synchronize do
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
- @@directory_lock.synchronize do
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
- @@directory_lock.synchronize { @@directory.keys }
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
@@ -38,7 +38,6 @@ module DCell
38
38
 
39
39
  def render_resource(connection, path)
40
40
  if node_id = path[%r{^nodes/(.*)$}, 1]
41
- p node_id
42
41
  node = DCell::Node[node_id]
43
42
  path = "index.html"
44
43
  else
@@ -4,12 +4,13 @@ module DCell
4
4
  class MailboxProxy
5
5
  class InvalidNodeError < StandardError; end
6
6
 
7
- def initialize(node_id, node_addr, mailbox_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
- @node = Node.new(node_id, node_addr) unless @node
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(@mailbox_id, message)
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}@#{@node_addr}"
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, node_addr = string.split("@")
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, node_addr, mailbox_id)
52
+ DCell::MailboxProxy.new(node_id, mailbox_id)
57
53
  end
58
54
  end
59
55
  end
@@ -8,14 +8,15 @@ module DCell
8
8
  @id = object_id
9
9
  end
10
10
 
11
- # Gossip messages contain health and membership information
12
- class Gossip < Message
13
- def initialize(peers, data)
14
- @peers, @data = peers, data
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.handle_gossip(@peers, @data)
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
- DCell::Router.route @recipient, @message
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