celluloid 0.13.0 → 0.14.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- 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
|