dcell 0.9.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/.travis.yml +4 -1
  2. data/CHANGES.md +11 -0
  3. data/Gemfile +6 -3
  4. data/LICENSE.txt +1 -1
  5. data/README.md +27 -243
  6. data/benchmarks/receiver.rb +2 -2
  7. data/dcell.gemspec +7 -7
  8. data/explorer/css/bootstrap-responsive.css +686 -0
  9. data/explorer/css/bootstrap-responsive.min.css +12 -0
  10. data/explorer/css/bootstrap.css +3990 -0
  11. data/explorer/css/bootstrap.min.css +689 -0
  12. data/explorer/css/explorer.css +28 -0
  13. data/explorer/ico/favicon.ico +0 -0
  14. data/explorer/img/glyphicons-halflings-white.png +0 -0
  15. data/explorer/img/glyphicons-halflings.png +0 -0
  16. data/explorer/img/logo.png +0 -0
  17. data/explorer/index.html.erb +94 -0
  18. data/explorer/js/bootstrap.js +1726 -0
  19. data/explorer/js/bootstrap.min.js +6 -0
  20. data/lib/dcell.rb +27 -2
  21. data/lib/dcell/celluloid_ext.rb +14 -3
  22. data/lib/dcell/directory.rb +15 -3
  23. data/lib/dcell/explorer.rb +76 -0
  24. data/lib/dcell/future_proxy.rb +32 -0
  25. data/lib/dcell/info_service.rb +117 -0
  26. data/lib/dcell/mailbox_proxy.rb +6 -7
  27. data/lib/dcell/messages.rb +5 -6
  28. data/lib/dcell/node.rb +25 -55
  29. data/lib/dcell/node_manager.rb +81 -0
  30. data/lib/dcell/registries/cassandra_adapter.rb +86 -0
  31. data/lib/dcell/registries/gossip/core.rb +235 -0
  32. data/lib/dcell/registries/gossip_adapter.rb +26 -0
  33. data/lib/dcell/registries/moneta_adapter.rb +0 -7
  34. data/lib/dcell/registries/redis_adapter.rb +0 -31
  35. data/lib/dcell/registries/zk_adapter.rb +1 -39
  36. data/lib/dcell/router.rb +37 -30
  37. data/lib/dcell/rpc.rb +23 -23
  38. data/lib/dcell/server.rb +5 -2
  39. data/lib/dcell/version.rb +1 -1
  40. data/logo.png +0 -0
  41. data/spec/dcell/actor_proxy_spec.rb +4 -0
  42. data/spec/dcell/celluloid_ext_spec.rb +11 -0
  43. data/spec/dcell/directory_spec.rb +1 -1
  44. data/spec/dcell/explorer_spec.rb +17 -0
  45. data/spec/dcell/global_spec.rb +4 -0
  46. data/spec/dcell/registries/gossip_adapter_spec.rb +6 -0
  47. data/spec/spec_helper.rb +14 -7
  48. data/spec/support/registry_examples.rb +0 -18
  49. data/tasks/cassandra.task +84 -0
  50. metadata +55 -35
  51. data/celluloid-zmq/.gitignore +0 -17
  52. data/celluloid-zmq/.rspec +0 -4
  53. data/celluloid-zmq/CHANGES.md +0 -31
  54. data/celluloid-zmq/Gemfile +0 -7
  55. data/celluloid-zmq/README.md +0 -56
  56. data/celluloid-zmq/Rakefile +0 -7
  57. data/celluloid-zmq/celluloid-zmq.gemspec +0 -28
  58. data/celluloid-zmq/lib/celluloid/zmq.rb +0 -36
  59. data/celluloid-zmq/lib/celluloid/zmq/reactor.rb +0 -90
  60. data/celluloid-zmq/lib/celluloid/zmq/sockets.rb +0 -130
  61. data/celluloid-zmq/lib/celluloid/zmq/version.rb +0 -5
  62. data/celluloid-zmq/lib/celluloid/zmq/waker.rb +0 -55
  63. data/celluloid-zmq/spec/celluloid/zmq/actor_spec.rb +0 -6
  64. data/celluloid-zmq/spec/spec_helper.rb +0 -2
@@ -14,44 +14,13 @@ module DCell
14
14
  redis = Redis.new options
15
15
  @redis = Redis::Namespace.new @namespace, :redis => redis
16
16
 
17
- @node_registry = NodeRegistry.new(@redis)
18
17
  @global_registry = GlobalRegistry.new(@redis)
19
18
  end
20
19
 
21
- def clear_nodes
22
- @node_registry.clear
23
- end
24
-
25
20
  def clear_globals
26
21
  @global_registry.clear
27
22
  end
28
23
 
29
- class NodeRegistry
30
- def initialize(redis)
31
- @redis = redis
32
- end
33
-
34
- def get(node_id)
35
- @redis.hget 'nodes', node_id
36
- end
37
-
38
- def set(node_id, addr)
39
- @redis.hset 'nodes', node_id, addr
40
- end
41
-
42
- def nodes
43
- @redis.hkeys 'nodes'
44
- end
45
-
46
- def clear
47
- @redis.del 'nodes'
48
- end
49
- end
50
-
51
- def get_node(node_id); @node_registry.get(node_id) end
52
- def set_node(node_id, addr); @node_registry.set(node_id, addr) end
53
- def nodes; @node_registry.nodes end
54
-
55
24
  class GlobalRegistry
56
25
  def initialize(redis)
57
26
  @redis = redis
@@ -36,51 +36,13 @@ module DCell
36
36
  end
37
37
 
38
38
  @zk = ZK.new(*servers)
39
- @node_registry = NodeRegistry.new(@zk, @base_path)
40
39
  @global_registry = GlobalRegistry.new(@zk, @base_path)
41
40
  end
42
41
 
43
- def clear_nodes
44
- @node_registry.clear
45
- end
46
-
47
42
  def clear_globals
48
43
  @global_registry.clear
49
44
  end
50
45
 
51
- class NodeRegistry
52
- def initialize(zk, base_path)
53
- @zk, @base_path = zk, "#{base_path}/nodes"
54
- @zk.mkdir_p @base_path
55
- end
56
-
57
- def get(node_id)
58
- result, _ = @zk.get("#{@base_path}/#{node_id}")
59
- result
60
- rescue ZK::Exceptions::NoNode
61
- end
62
-
63
- def set(node_id, addr)
64
- path = "#{@base_path}/#{node_id}"
65
- @zk.set path, addr
66
- rescue ZK::Exceptions::NoNode
67
- @zk.create path, addr
68
- end
69
-
70
- def nodes
71
- @zk.children @base_path
72
- end
73
-
74
- def clear
75
- @zk.rm_rf @base_path
76
- @zk.mkdir_p @base_path
77
- end
78
- end
79
-
80
- def get_node(node_id); @node_registry.get(node_id) end
81
- def set_node(node_id, addr); @node_registry.set(node_id, addr) end
82
- def nodes; @node_registry.nodes end
83
-
84
46
  class GlobalRegistry
85
47
  def initialize(zk, base_path)
86
48
  @zk, @base_path = zk, "#{base_path}/globals"
@@ -119,4 +81,4 @@ module DCell
119
81
  def global_keys; @global_registry.global_keys end
120
82
  end
121
83
  end
122
- end
84
+ end
@@ -3,66 +3,73 @@ require 'weakref'
3
3
  module DCell
4
4
  # Route incoming messages to their recipient actors
5
5
  class Router
6
- @lock = Mutex.new
7
- @table = {}
6
+ @mutex = Mutex.new
7
+ @addresses = {}
8
+ @mailboxes = {}
8
9
 
9
10
  class << self
10
11
  # Enter a mailbox into the registry
11
12
  def register(mailbox)
12
- id = mailbox.object_id.to_s(16)
13
-
14
- @lock.synchronize do
15
- ref = @table[id]
16
- unless ref && ref.weakref_alive?
17
- @table[id] = WeakRef.new(mailbox)
13
+ @mutex.lock
14
+ begin
15
+ address = @addresses[mailbox.object_id]
16
+ unless address
17
+ address = Celluloid.uuid
18
+ @addresses[mailbox.object_id] = address
18
19
  end
19
- end
20
20
 
21
- id
21
+ ref = @mailboxes[address]
22
+ @mailboxes[address] = WeakRef.new(mailbox) unless ref && ref.weakref_alive?
23
+
24
+ address
25
+ ensure
26
+ @mutex.unlock rescue nil
27
+ end
22
28
  end
23
29
 
24
- # Find a mailbox by its ID
25
- def find(mailbox_id)
26
- @lock.synchronize do
27
- ref = @table[mailbox_id]
30
+ # Find a mailbox by its address
31
+ def find(mailbox_address)
32
+ @mutex.lock
33
+ begin
34
+ ref = @mailboxes[mailbox_address]
28
35
  return unless ref
29
- begin
30
- ref.__getobj__
31
- rescue WeakRef::RefError
32
- # The referenced actor is dead, so prune the registry
33
- @table.delete mailbox_id
34
- nil
35
- end
36
+ ref.__getobj__
37
+ rescue WeakRef::RefError
38
+ # The referenced actor is dead, so prune the registry
39
+ @mailboxes.delete mailbox_address
40
+ nil
41
+ ensure
42
+ @mutex.unlock rescue nil
36
43
  end
37
44
  end
38
45
 
39
46
  # Route a message to a given mailbox ID
40
- def route(mailbox_id, message)
41
- recipient = find mailbox_id
47
+ def route(recipient, message)
48
+ recipient = find(recipient) if recipient.is_a? String
42
49
 
43
50
  if recipient
44
51
  recipient << message
45
52
  else
46
- Celluloid::Logger.debug("received message for invalid actor: #{mailbox_id.inspect}")
53
+ Celluloid::Logger.debug("received message for invalid actor: #{mailbox_address.inspect}")
47
54
  end
48
55
  end
49
56
 
50
57
  # Route a system event to a given mailbox ID
51
- def route_system_event(mailbox_id, event)
52
- recipient = find mailbox_id
58
+ def route_system_event(mailbox_address, event)
59
+ recipient = find mailbox_address
53
60
 
54
61
  if recipient
55
62
  recipient.system_event event
56
63
  else
57
- Celluloid::Logger.debug("received message for invalid actor: #{mailbox_id.inspect}")
64
+ Celluloid::Logger.debug("received message for invalid actor: #{mailbox_address.inspect}")
58
65
  end
59
66
  end
60
67
 
61
68
  # Prune all entries that point to dead objects
62
69
  def gc
63
- @lock.synchronize do
64
- @table.each do |id, ref|
65
- @table.delete id unless ref.weakref_alive?
70
+ @mutex.synchronize do
71
+ @mailboxes.each do |id, ref|
72
+ @mailboxes.delete id unless ref.weakref_alive?
66
73
  end
67
74
  end
68
75
  end
@@ -1,8 +1,6 @@
1
1
  require 'weakref'
2
2
 
3
3
  module DCell
4
- EPOCH = Time.gm(2012) # All things begin in 2012
5
-
6
4
  class RPC < Celluloid::SyncCall
7
5
  def initialize(id, caller, method, arguments, block)
8
6
  @id, @caller, @method, @arguments, @block = id, caller, method, arguments, block
@@ -17,16 +15,16 @@ module DCell
17
15
  # Loader for custom marshal format
18
16
  def self._load(string)
19
17
  id = string.slice!(0, string.index(":") + 1)
20
- match = id.match(/^([0-9a-fA-F]+)@(.+?):$/)
18
+ match = id.match(/^([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})@(.+?):$/)
21
19
  raise ArgumentError, "couldn't parse call ID" unless match
22
20
 
23
- call_id, node_id = match[1], match[2]
21
+ uuid, node_id = match[1], match[2]
24
22
 
25
23
  if DCell.id == node_id
26
- Manager.claim Integer("0x#{call_id}")
24
+ Manager.claim uuid
27
25
  else
28
26
  caller, method, arguments, block = Marshal.load(string)
29
- RPC.new("#{call_id}@#{node_id}", caller, method, arguments, block)
27
+ RPC.new("#{uuid}@#{node_id}", caller, method, arguments, block)
30
28
  end
31
29
  end
32
30
 
@@ -35,31 +33,33 @@ module DCell
35
33
  @mutex = Mutex.new
36
34
  @ids = {}
37
35
  @calls = {}
38
- @serial = Integer(Time.now - EPOCH) * 0x100000
39
36
 
40
37
  def self.register(call)
41
38
  @mutex.lock
42
- call_id = @ids[call.object_id]
43
- unless call_id
44
- call_id = @serial
45
- @serial += 1
46
- @ids[call.object_id] = call_id
47
- end
39
+ begin
40
+ call_id = @ids[call.object_id]
41
+ unless call_id
42
+ call_id = Celluloid.uuid
43
+ @ids[call.object_id] = call_id
44
+ end
48
45
 
49
- @calls[call_id] = WeakRef.new(call)
50
- call_id
51
- ensure
52
- @mutex.unlock
46
+ @calls[call_id] = WeakRef.new(call)
47
+ call_id
48
+ ensure
49
+ @mutex.unlock rescue nil
50
+ end
53
51
  end
54
52
 
55
53
  def self.claim(call_id)
56
54
  @mutex.lock
57
- ref = @calls.delete(call_id)
58
- ref.__getobj__ if ref
59
- rescue WeakRef::RefError
60
- # Nothing to see here, folks
61
- ensure
62
- @mutex.unlock
55
+ begin
56
+ ref = @calls.delete(call_id)
57
+ ref.__getobj__ if ref
58
+ rescue WeakRef::RefError
59
+ # Nothing to see here, folks
60
+ ensure
61
+ @mutex.unlock rescue nil
62
+ end
63
63
  end
64
64
  end
65
65
  end
@@ -5,6 +5,9 @@ module DCell
5
5
 
6
6
  # Bind to the given 0MQ address (in URL form ala tcp://host:port)
7
7
  def initialize
8
+ # The gossip protocol is dependent on the node manager
9
+ link Actor[:node_manager]
10
+
8
11
  @addr = DCell.addr
9
12
  @socket = PullSocket.new
10
13
 
@@ -20,7 +23,7 @@ module DCell
20
23
 
21
24
  # Wait for incoming 0MQ messages
22
25
  def run
23
- while true; handle_message @socket.read; end
26
+ while true; handle_message! @socket.read; end
24
27
  end
25
28
 
26
29
  # Shut down the server
@@ -39,7 +42,7 @@ module DCell
39
42
 
40
43
  begin
41
44
  message.dispatch
42
- rescue Exception => ex
45
+ rescue => ex
43
46
  Celluloid::Logger.crash("DCell::Server: message dispatch failed", ex)
44
47
  end
45
48
  end
@@ -1,3 +1,3 @@
1
1
  module DCell
2
- VERSION = "0.9.0"
2
+ VERSION = "0.10.0"
3
3
  end
data/logo.png CHANGED
Binary file
@@ -26,6 +26,10 @@ describe DCell::ActorProxy do
26
26
  @remote_actor.value.should == 42
27
27
  end
28
28
 
29
+ it "makes future calls to remote actors" do
30
+ @remote_actor.future(:value).value.should == 42
31
+ end
32
+
29
33
  context :linking do
30
34
  before :each do
31
35
  @local_actor = LocalActor.new
@@ -4,6 +4,10 @@ describe Celluloid, "extensions" do
4
4
  before do
5
5
  class WillKane
6
6
  include Celluloid
7
+
8
+ def speak
9
+ "Don't shove me Harv."
10
+ end
7
11
  end
8
12
  @marshal = WillKane.new
9
13
  end
@@ -18,4 +22,11 @@ describe Celluloid, "extensions" do
18
22
  string = Marshal.dump(@marshal.mailbox)
19
23
  Marshal.load(string).should be_alive
20
24
  end
25
+
26
+ it "marshals Celluloid::Future objects" do
27
+ future = @marshal.future(:speak)
28
+ future.should be_a(Celluloid::Future)
29
+ string = Marshal.dump(future)
30
+ Marshal.load(string).value.should == "Don't shove me Harv."
31
+ end
21
32
  end
@@ -5,4 +5,4 @@ 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
- end
8
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+ require 'dcell/explorer'
3
+
4
+ describe DCell::Explorer do
5
+ EXPLORER_HOST = 'localhost'
6
+ EXPLORER_PORT = 7778
7
+ EXPLORER_BASE = "http://#{EXPLORER_HOST}:#{EXPLORER_PORT}"
8
+
9
+ before do
10
+ @explorer = DCell::Explorer.new(EXPLORER_HOST, EXPLORER_PORT)
11
+ end
12
+
13
+ it "reports the current node's status" do
14
+ response = Net::HTTP.get URI(EXPLORER_BASE)
15
+ response[%r{<h1><.*?> ([\w\.\-]+)<\/h1>}, 1].should == DCell.id
16
+ end
17
+ end
@@ -11,6 +11,10 @@ describe DCell::Global do
11
11
 
12
12
  # Double check the global value is available on all nodes
13
13
  node = DCell::Node['test_node']
14
+ 20.downto(0) do |i|
15
+ break if node[:test_actor].the_answer
16
+ sleep 1
17
+ end
14
18
  node[:test_actor].the_answer.should == 42
15
19
  end
16
20
 
@@ -0,0 +1,6 @@
1
+ require 'spec_helper'
2
+
3
+ describe DCell::Registry::GossipAdapter do
4
+ subject { DCell::Registry::GossipAdapter.new :env => "test" }
5
+ it_behaves_like "a DCell registry"
6
+ end
@@ -5,12 +5,19 @@ Bundler.setup
5
5
  require 'dcell'
6
6
  Dir['./spec/support/*.rb'].map { |f| require f }
7
7
 
8
- DCell.setup
9
- DCell.run!
8
+ RSpec.configure do |config|
9
+ config.before(:suite) do
10
+ DCell.setup :directory => { :id => 'test_node', :addr => "tcp://127.0.0.1:#{TestNode::PORT}" }
11
+ @supervisor = DCell.run!
10
12
 
11
- TestNode.start
12
- TestNode.wait_until_ready
13
+ TestNode.start
14
+ TestNode.wait_until_ready
15
+ end
13
16
 
14
- at_exit do
15
- TestNode.stop
16
- end
17
+ config.after(:suite) do
18
+ TestNode.stop
19
+ end
20
+ end
21
+
22
+ # FIXME: this is hax to bypass the other at_exit handlers
23
+ at_exit { exit! $!.status }
@@ -1,22 +1,4 @@
1
1
  shared_context "a DCell registry" do
2
- context "node registry" do
3
- before :each do
4
- subject.clear_nodes
5
- end
6
-
7
- it "stores node addresses" do
8
- address = "tcp://localhost:7777"
9
-
10
- subject.set_node("foobar", address)
11
- subject.get_node("foobar").should == address
12
- end
13
-
14
- it "stores the IDs of all nodes" do
15
- subject.set_node("foobar", "tcp://localhost:7777")
16
- subject.nodes.should include "foobar"
17
- end
18
- end
19
-
20
2
  context "global registry" do
21
3
  before :each do
22
4
  subject.clear_globals