celluloid 0.13.0 → 0.14.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.
- checksums.yaml +7 -0
- data/README.md +1 -2
- data/lib/celluloid.rb +84 -32
- data/lib/celluloid/actor.rb +35 -30
- data/lib/celluloid/autostart.rb +0 -13
- data/lib/celluloid/calls.rb +71 -23
- data/lib/celluloid/core_ext.rb +3 -14
- data/lib/celluloid/cpu_counter.rb +1 -1
- data/lib/celluloid/evented_mailbox.rb +82 -0
- data/lib/celluloid/fsm.rb +2 -0
- data/lib/celluloid/future.rb +4 -4
- data/lib/celluloid/internal_pool.rb +11 -8
- data/lib/celluloid/legacy.rb +14 -13
- data/lib/celluloid/logging/incident_logger.rb +2 -2
- data/lib/celluloid/mailbox.rb +16 -0
- data/lib/celluloid/method.rb +7 -7
- data/lib/celluloid/notifications.rb +1 -1
- data/lib/celluloid/proxies/abstract_proxy.rb +1 -1
- data/lib/celluloid/proxies/actor_proxy.rb +23 -27
- data/lib/celluloid/proxies/async_proxy.rb +18 -6
- data/lib/celluloid/proxies/block_proxy.rb +29 -0
- data/lib/celluloid/proxies/future_proxy.rb +9 -3
- data/lib/celluloid/proxies/sync_proxy.rb +31 -0
- data/lib/celluloid/receivers.rb +1 -1
- data/lib/celluloid/responses.rb +13 -1
- data/lib/celluloid/stack_dump.rb +8 -5
- data/lib/celluloid/supervision_group.rb +6 -4
- data/lib/celluloid/tasks.rb +63 -2
- data/lib/celluloid/tasks/task_fiber.rb +6 -46
- data/lib/celluloid/tasks/task_thread.rb +8 -44
- data/lib/celluloid/thread.rb +82 -0
- data/lib/celluloid/thread_handle.rb +3 -2
- data/lib/celluloid/version.rb +1 -1
- data/spec/support/actor_examples.rb +116 -53
- data/spec/support/example_actor_class.rb +7 -1
- data/spec/support/mailbox_examples.rb +29 -3
- data/spec/support/task_examples.rb +11 -9
- metadata +21 -29
data/lib/celluloid/core_ext.rb
CHANGED
@@ -1,20 +1,9 @@
|
|
1
1
|
require 'celluloid/fiber'
|
2
2
|
|
3
|
-
# Monkeypatch Thread to allow lazy access to its Celluloid::Mailbox
|
4
3
|
class Thread
|
5
4
|
attr_accessor :uuid_counter, :uuid_limit
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
current[:celluloid_mailbox] ||= Celluloid::Mailbox.new
|
6
|
+
def celluloid?
|
7
|
+
false
|
10
8
|
end
|
11
|
-
|
12
|
-
# Receive a message either as an actor or through the local mailbox
|
13
|
-
def self.receive(timeout = nil, &block)
|
14
|
-
if Celluloid.actor?
|
15
|
-
Celluloid.receive(timeout, &block)
|
16
|
-
else
|
17
|
-
mailbox.receive(timeout, &block)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
9
|
+
end
|
@@ -12,7 +12,7 @@ module Celluloid
|
|
12
12
|
Dir["/sys/devices/system/cpu/cpu*"].select { |n| n=~/cpu\d+/ }.count
|
13
13
|
end
|
14
14
|
when 'mingw', 'mswin'
|
15
|
-
@cores = Integer(
|
15
|
+
@cores = Integer(ENV["NUMBER_OF_PROCESSORS"][/\d+/])
|
16
16
|
else
|
17
17
|
@cores = nil
|
18
18
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Celluloid
|
2
|
+
# An alternative implementation of Celluloid::Mailbox using Reactor
|
3
|
+
class EventedMailbox < Celluloid::Mailbox
|
4
|
+
attr_reader :reactor
|
5
|
+
|
6
|
+
def initialize(reactor_class)
|
7
|
+
super()
|
8
|
+
# @condition won't be used in the class.
|
9
|
+
@reactor = reactor_class.new
|
10
|
+
end
|
11
|
+
|
12
|
+
# Add a message to the Mailbox
|
13
|
+
def <<(message)
|
14
|
+
@mutex.lock
|
15
|
+
begin
|
16
|
+
if mailbox_full
|
17
|
+
Logger.debug "Discarded message: #{message}"
|
18
|
+
return
|
19
|
+
end
|
20
|
+
if message.is_a?(SystemEvent)
|
21
|
+
# Silently swallow system events sent to dead actors
|
22
|
+
return if @dead
|
23
|
+
|
24
|
+
# SystemEvents are high priority messages so they get added to the
|
25
|
+
# head of our message queue instead of the end
|
26
|
+
@messages.unshift message
|
27
|
+
else
|
28
|
+
raise MailboxError, "dead recipient" if @dead
|
29
|
+
@messages << message
|
30
|
+
end
|
31
|
+
|
32
|
+
current_actor = Thread.current[:celluloid_actor]
|
33
|
+
@reactor.wakeup unless current_actor && current_actor.mailbox == self
|
34
|
+
rescue IOError
|
35
|
+
raise MailboxError, "dead recipient"
|
36
|
+
ensure
|
37
|
+
@mutex.unlock rescue nil
|
38
|
+
end
|
39
|
+
nil
|
40
|
+
end
|
41
|
+
|
42
|
+
# Receive a message from the Mailbox
|
43
|
+
def receive(timeout = nil, &block)
|
44
|
+
message = next_message(block)
|
45
|
+
|
46
|
+
until message
|
47
|
+
if timeout
|
48
|
+
now = Time.now
|
49
|
+
wait_until ||= now + timeout
|
50
|
+
wait_interval = wait_until - now
|
51
|
+
return if wait_interval < 0
|
52
|
+
else
|
53
|
+
wait_interval = nil
|
54
|
+
end
|
55
|
+
|
56
|
+
@reactor.run_once(wait_interval)
|
57
|
+
message = next_message(block)
|
58
|
+
end
|
59
|
+
|
60
|
+
message
|
61
|
+
rescue IOError
|
62
|
+
shutdown # force shutdown of the mailbox
|
63
|
+
raise MailboxShutdown, "mailbox shutdown called during receive"
|
64
|
+
end
|
65
|
+
|
66
|
+
# Obtain the next message from the mailbox that matches the given block
|
67
|
+
def next_message(block)
|
68
|
+
@mutex.lock
|
69
|
+
begin
|
70
|
+
super(&block)
|
71
|
+
ensure
|
72
|
+
@mutex.unlock rescue nil
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Cleanup any IO objects this Mailbox may be using
|
77
|
+
def shutdown
|
78
|
+
@reactor.shutdown
|
79
|
+
super
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/lib/celluloid/fsm.rb
CHANGED
@@ -62,6 +62,7 @@ module Celluloid
|
|
62
62
|
# Be kind and call super if you must redefine initialize
|
63
63
|
def initialize(actor = nil)
|
64
64
|
@state = self.class.default_state
|
65
|
+
@delayed_transition = nil
|
65
66
|
@actor = actor
|
66
67
|
@actor ||= Celluloid.current_actor if Celluloid.actor?
|
67
68
|
end
|
@@ -166,6 +167,7 @@ module Celluloid
|
|
166
167
|
|
167
168
|
def initialize(name, transitions = nil, &block)
|
168
169
|
@name, @block = name, block
|
170
|
+
@transitions = nil
|
169
171
|
@transitions = Array(transitions).map { |t| t.to_sym } if transitions
|
170
172
|
end
|
171
173
|
|
data/lib/celluloid/future.rb
CHANGED
@@ -57,11 +57,11 @@ module Celluloid
|
|
57
57
|
else
|
58
58
|
case @forwards
|
59
59
|
when Array
|
60
|
-
@forwards <<
|
60
|
+
@forwards << Celluloid.mailbox
|
61
61
|
when NilClass
|
62
|
-
@forwards =
|
62
|
+
@forwards = Celluloid.mailbox
|
63
63
|
else
|
64
|
-
@forwards = [@forwards,
|
64
|
+
@forwards = [@forwards, Celluloid.mailbox]
|
65
65
|
end
|
66
66
|
end
|
67
67
|
ensure
|
@@ -69,7 +69,7 @@ module Celluloid
|
|
69
69
|
end
|
70
70
|
|
71
71
|
unless ready
|
72
|
-
result =
|
72
|
+
result = Celluloid.receive(timeout) do |msg|
|
73
73
|
msg.is_a?(Future::Result) && msg.future == self
|
74
74
|
end
|
75
75
|
end
|
@@ -10,6 +10,10 @@ module Celluloid
|
|
10
10
|
@mutex = Mutex.new
|
11
11
|
@busy_size = @idle_size = 0
|
12
12
|
|
13
|
+
reset
|
14
|
+
end
|
15
|
+
|
16
|
+
def reset
|
13
17
|
# TODO: should really adjust this based on usage
|
14
18
|
@max_idle = 16
|
15
19
|
end
|
@@ -38,7 +42,7 @@ module Celluloid
|
|
38
42
|
if @pool.size >= @max_idle
|
39
43
|
thread[:celluloid_queue] << nil
|
40
44
|
else
|
41
|
-
|
45
|
+
thread.recycle
|
42
46
|
@pool << thread
|
43
47
|
@idle_size += 1
|
44
48
|
@busy_size -= 1
|
@@ -65,13 +69,12 @@ module Celluloid
|
|
65
69
|
thread
|
66
70
|
end
|
67
71
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
thread[key] = nil
|
72
|
+
def shutdown
|
73
|
+
@mutex.synchronize do
|
74
|
+
@max_idle = 0
|
75
|
+
@pool.each do |thread|
|
76
|
+
thread[:celluloid_queue] << nil
|
77
|
+
end
|
75
78
|
end
|
76
79
|
end
|
77
80
|
end
|
data/lib/celluloid/legacy.rb
CHANGED
@@ -9,9 +9,9 @@ module Celluloid
|
|
9
9
|
|
10
10
|
unbanged_meth = meth.to_s
|
11
11
|
unbanged_meth.slice!(-1, 1)
|
12
|
-
|
12
|
+
async unbanged_meth, *args, &block
|
13
13
|
else
|
14
|
-
|
14
|
+
super
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
@@ -27,20 +27,21 @@ module Celluloid
|
|
27
27
|
unbanged_meth = meth.to_s.sub(/!$/, '')
|
28
28
|
args.unshift unbanged_meth
|
29
29
|
|
30
|
-
|
31
|
-
begin
|
32
|
-
Thread.current[:celluloid_actor].mailbox << call
|
33
|
-
rescue MailboxError
|
34
|
-
# Silently swallow asynchronous calls to dead actors. There's no way
|
35
|
-
# to reliably generate DeadActorErrors for async calls, so users of
|
36
|
-
# async calls should find other ways to deal with actors dying
|
37
|
-
# during an async call (i.e. linking/supervisors)
|
38
|
-
end
|
39
|
-
|
30
|
+
async :__send__, *args, &block
|
40
31
|
return
|
41
32
|
end
|
42
33
|
|
43
34
|
super
|
44
35
|
end
|
45
36
|
end
|
46
|
-
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class Thread
|
40
|
+
def self.mailbox
|
41
|
+
Celluloid.mailbox
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.receive(timeout = nil, &block)
|
45
|
+
Celluloid.receive(timeout, &block)
|
46
|
+
end
|
47
|
+
end
|
@@ -49,9 +49,9 @@ module Celluloid
|
|
49
49
|
@sizelimit = options[:sizelimit] || 100
|
50
50
|
|
51
51
|
@buffer_mutex = Mutex.new
|
52
|
-
@buffers = Hash.new do |progname_hash,
|
52
|
+
@buffers = Hash.new do |progname_hash, _progname|
|
53
53
|
@buffer_mutex.synchronize do
|
54
|
-
progname_hash[
|
54
|
+
progname_hash[_progname] = Hash.new do |severity_hash, severity|
|
55
55
|
severity_hash[severity] = RingBuffer.new(@sizelimit)
|
56
56
|
end
|
57
57
|
end
|
data/lib/celluloid/mailbox.rb
CHANGED
@@ -11,6 +11,7 @@ module Celluloid
|
|
11
11
|
|
12
12
|
# A unique address at which this mailbox can be found
|
13
13
|
attr_reader :address
|
14
|
+
attr_accessor :max_size
|
14
15
|
|
15
16
|
def initialize
|
16
17
|
@address = Celluloid.uuid
|
@@ -18,12 +19,17 @@ module Celluloid
|
|
18
19
|
@mutex = Mutex.new
|
19
20
|
@dead = false
|
20
21
|
@condition = ConditionVariable.new
|
22
|
+
@max_size = nil
|
21
23
|
end
|
22
24
|
|
23
25
|
# Add a message to the Mailbox
|
24
26
|
def <<(message)
|
25
27
|
@mutex.lock
|
26
28
|
begin
|
29
|
+
if mailbox_full
|
30
|
+
Logger.debug "Discarded message: #{message}"
|
31
|
+
return
|
32
|
+
end
|
27
33
|
if message.is_a?(SystemEvent)
|
28
34
|
# Silently swallow system events sent to dead actors
|
29
35
|
return if @dead
|
@@ -125,5 +131,15 @@ module Celluloid
|
|
125
131
|
def inspect
|
126
132
|
"#<#{self.class}:#{object_id.to_s(16)} @messages=[#{map { |m| m.inspect }.join(', ')}]>"
|
127
133
|
end
|
134
|
+
|
135
|
+
# Number of messages in the Mailbox
|
136
|
+
def size
|
137
|
+
@mutex.synchronize { @messages.size }
|
138
|
+
end
|
139
|
+
|
140
|
+
private
|
141
|
+
def mailbox_full
|
142
|
+
@max_size && @messages.size >= @max_size
|
143
|
+
end
|
128
144
|
end
|
129
145
|
end
|
data/lib/celluloid/method.rb
CHANGED
@@ -2,23 +2,23 @@ module Celluloid
|
|
2
2
|
# Method handles that route through an actor proxy
|
3
3
|
class Method
|
4
4
|
|
5
|
-
def initialize(
|
6
|
-
raise NameError, "undefined method `#{name}'" unless
|
5
|
+
def initialize(proxy, name)
|
6
|
+
raise NameError, "undefined method `#{name}'" unless proxy.respond_to? name
|
7
7
|
|
8
|
-
@
|
9
|
-
@klass = @
|
8
|
+
@proxy, @name = proxy, name
|
9
|
+
@klass = @proxy.class
|
10
10
|
end
|
11
11
|
|
12
12
|
def arity
|
13
|
-
@
|
13
|
+
@proxy.method_missing(:method, @name).arity
|
14
14
|
end
|
15
15
|
|
16
16
|
def call(*args, &block)
|
17
|
-
@
|
17
|
+
@proxy.__send__(@name, *args, &block)
|
18
18
|
end
|
19
19
|
|
20
20
|
def inspect
|
21
|
-
"#<Celluloid::Method #{@klass}
|
21
|
+
"#<Celluloid::Method #{@klass}##{@name}>"
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
@@ -1,55 +1,54 @@
|
|
1
1
|
module Celluloid
|
2
2
|
# A proxy object returned from Celluloid::Actor.new/new_link which converts
|
3
3
|
# the normal Ruby method protocol into an inter-actor message protocol
|
4
|
-
class ActorProxy
|
5
|
-
attr_reader :
|
4
|
+
class ActorProxy < SyncProxy
|
5
|
+
attr_reader :thread
|
6
6
|
|
7
7
|
def initialize(actor)
|
8
|
-
@
|
8
|
+
@thread = actor.thread
|
9
9
|
|
10
|
-
|
11
|
-
@
|
10
|
+
super(actor.mailbox, actor.subject.class.to_s)
|
11
|
+
@sync_proxy = SyncProxy.new(@mailbox, @klass)
|
12
|
+
@async_proxy = AsyncProxy.new(@mailbox, @klass)
|
13
|
+
@future_proxy = FutureProxy.new(@mailbox, @klass)
|
12
14
|
end
|
13
|
-
|
14
|
-
# allow querying the real class
|
15
|
-
alias :__class__ :class
|
16
|
-
|
15
|
+
|
17
16
|
def class
|
18
|
-
|
17
|
+
method_missing :__send__, :class
|
19
18
|
end
|
20
19
|
|
21
20
|
def send(meth, *args, &block)
|
22
|
-
|
21
|
+
method_missing :send, meth, *args, &block
|
23
22
|
end
|
24
23
|
|
25
24
|
def _send_(meth, *args, &block)
|
26
|
-
|
25
|
+
method_missing :__send__, meth, *args, &block
|
27
26
|
end
|
28
27
|
|
29
28
|
def inspect
|
30
|
-
|
29
|
+
method_missing :inspect
|
31
30
|
rescue DeadActorError
|
32
|
-
"#<Celluloid::
|
31
|
+
"#<Celluloid::ActorProxy(#{@klass}) dead>"
|
33
32
|
end
|
34
33
|
|
35
34
|
def name
|
36
|
-
|
35
|
+
method_missing :name
|
37
36
|
end
|
38
37
|
|
39
38
|
def is_a?(klass)
|
40
|
-
|
39
|
+
method_missing :is_a?, klass
|
41
40
|
end
|
42
41
|
|
43
42
|
def kind_of?(klass)
|
44
|
-
|
43
|
+
method_missing :kind_of?, klass
|
45
44
|
end
|
46
45
|
|
47
46
|
def respond_to?(meth, include_private = false)
|
48
|
-
|
47
|
+
method_missing :respond_to?, meth, include_private
|
49
48
|
end
|
50
49
|
|
51
50
|
def methods(include_ancestors = true)
|
52
|
-
|
51
|
+
method_missing :methods, include_ancestors
|
53
52
|
end
|
54
53
|
|
55
54
|
def method(name)
|
@@ -61,13 +60,15 @@ module Celluloid
|
|
61
60
|
end
|
62
61
|
|
63
62
|
def to_s
|
64
|
-
|
63
|
+
method_missing :to_s
|
65
64
|
end
|
66
65
|
|
66
|
+
alias_method :sync, :method_missing
|
67
|
+
|
67
68
|
# Obtain an async proxy or explicitly invoke a named async method
|
68
69
|
def async(method_name = nil, *args, &block)
|
69
70
|
if method_name
|
70
|
-
|
71
|
+
@async_proxy.method_missing method_name, *args, &block
|
71
72
|
else
|
72
73
|
@async_proxy
|
73
74
|
end
|
@@ -76,7 +77,7 @@ module Celluloid
|
|
76
77
|
# Obtain a future proxy or explicitly invoke a named future method
|
77
78
|
def future(method_name = nil, *args, &block)
|
78
79
|
if method_name
|
79
|
-
|
80
|
+
@future_proxy.method_missing method_name, *args, &block
|
80
81
|
else
|
81
82
|
@future_proxy
|
82
83
|
end
|
@@ -94,10 +95,5 @@ module Celluloid
|
|
94
95
|
::Kernel.raise DeadActorError, "actor already terminated" unless alive?
|
95
96
|
@mailbox << TerminationRequest.new
|
96
97
|
end
|
97
|
-
|
98
|
-
# method_missing black magic to call bang predicate methods asynchronously
|
99
|
-
def method_missing(meth, *args, &block)
|
100
|
-
Actor.call @mailbox, meth, *args, &block
|
101
|
-
end
|
102
98
|
end
|
103
99
|
end
|