celluloid 0.16.0 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of celluloid might be problematic. Click here for more details.

Files changed (167) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +333 -0
  3. data/README.md +1 -1
  4. data/culture/CODE_OF_CONDUCT.md +28 -0
  5. data/culture/Gemfile +9 -0
  6. data/culture/README.md +22 -0
  7. data/culture/Rakefile +5 -0
  8. data/culture/SYNC.md +70 -0
  9. data/culture/celluloid-culture.gemspec +18 -0
  10. data/culture/gems/README.md +39 -0
  11. data/culture/gems/dependencies.yml +78 -0
  12. data/culture/gems/loader.rb +101 -0
  13. data/culture/rubocop/README.md +38 -0
  14. data/culture/rubocop/lint.yml +8 -0
  15. data/culture/rubocop/metrics.yml +15 -0
  16. data/culture/rubocop/rubocop.yml +4 -0
  17. data/culture/rubocop/style.yml +48 -0
  18. data/culture/spec/gems_spec.rb +2 -0
  19. data/culture/spec/spec_helper.rb +0 -0
  20. data/culture/spec/sync_spec.rb +2 -0
  21. data/culture/sync.rb +56 -0
  22. data/culture/tasks/rspec.rake +5 -0
  23. data/culture/tasks/rubocop.rake +2 -0
  24. data/examples/basic_usage.rb +49 -0
  25. data/examples/futures.rb +38 -0
  26. data/examples/ring.rb +61 -0
  27. data/examples/simple_pmap.rb +14 -0
  28. data/examples/timers.rb +72 -0
  29. data/lib/celluloid.rb +142 -127
  30. data/lib/celluloid/actor.rb +47 -41
  31. data/lib/celluloid/actor_system.rb +75 -22
  32. data/lib/celluloid/autostart.rb +1 -1
  33. data/lib/celluloid/backported.rb +2 -0
  34. data/lib/celluloid/call/async.rb +16 -0
  35. data/lib/celluloid/call/block.rb +22 -0
  36. data/lib/celluloid/call/sync.rb +70 -0
  37. data/lib/celluloid/calls.rb +25 -114
  38. data/lib/celluloid/cell.rb +32 -20
  39. data/lib/celluloid/condition.rb +3 -3
  40. data/lib/celluloid/core_ext.rb +1 -1
  41. data/lib/celluloid/current.rb +2 -0
  42. data/lib/celluloid/deprecate.rb +18 -0
  43. data/lib/celluloid/exceptions.rb +1 -1
  44. data/lib/celluloid/fiber.rb +3 -3
  45. data/lib/celluloid/future.rb +7 -6
  46. data/lib/celluloid/group.rb +65 -0
  47. data/lib/celluloid/group/manager.rb +27 -0
  48. data/lib/celluloid/group/pool.rb +125 -0
  49. data/lib/celluloid/group/spawner.rb +71 -0
  50. data/lib/celluloid/logging.rb +5 -5
  51. data/lib/celluloid/mailbox.rb +14 -13
  52. data/lib/celluloid/mailbox/evented.rb +76 -0
  53. data/lib/celluloid/notices.rb +15 -0
  54. data/lib/celluloid/proxies.rb +12 -0
  55. data/lib/celluloid/proxy/abstract.rb +24 -0
  56. data/lib/celluloid/proxy/actor.rb +46 -0
  57. data/lib/celluloid/proxy/async.rb +36 -0
  58. data/lib/celluloid/proxy/block.rb +31 -0
  59. data/lib/celluloid/proxy/cell.rb +76 -0
  60. data/lib/celluloid/proxy/future.rb +40 -0
  61. data/lib/celluloid/proxy/sync.rb +44 -0
  62. data/lib/celluloid/rspec.rb +9 -10
  63. data/lib/celluloid/system_events.rb +16 -15
  64. data/lib/celluloid/{tasks.rb → task.rb} +21 -21
  65. data/lib/celluloid/task/fibered.rb +45 -0
  66. data/lib/celluloid/task/threaded.rb +59 -0
  67. data/lib/celluloid/test.rb +1 -1
  68. data/lib/celluloid/thread.rb +6 -1
  69. data/lib/celluloid/version.rb +3 -0
  70. data/spec/celluloid/actor_spec.rb +2 -2
  71. data/spec/celluloid/actor_system_spec.rb +35 -21
  72. data/spec/celluloid/block_spec.rb +3 -5
  73. data/spec/celluloid/calls_spec.rb +33 -11
  74. data/spec/celluloid/condition_spec.rb +16 -13
  75. data/spec/celluloid/evented_mailbox_spec.rb +1 -31
  76. data/spec/celluloid/future_spec.rb +13 -10
  77. data/spec/celluloid/group/elastic_spec.rb +0 -0
  78. data/spec/celluloid/group/manager_spec.rb +0 -0
  79. data/spec/celluloid/group/pool_spec.rb +8 -0
  80. data/spec/celluloid/group/spawner_spec.rb +8 -0
  81. data/spec/celluloid/mailbox/evented_spec.rb +27 -0
  82. data/spec/celluloid/mailbox_spec.rb +1 -3
  83. data/spec/celluloid/misc/leak_spec.rb +73 -0
  84. data/spec/celluloid/task/fibered_spec.rb +5 -0
  85. data/spec/celluloid/task/threaded_spec.rb +5 -0
  86. data/spec/celluloid/timer_spec.rb +14 -16
  87. data/spec/deprecate/actor_system_spec.rb +72 -0
  88. data/spec/deprecate/block_spec.rb +52 -0
  89. data/spec/deprecate/calls_spec.rb +57 -0
  90. data/spec/deprecate/evented_mailbox_spec.rb +34 -0
  91. data/spec/deprecate/future_spec.rb +32 -0
  92. data/spec/deprecate/internal_pool_spec.rb +4 -0
  93. data/spec/shared/actor_examples.rb +1237 -0
  94. data/spec/shared/group_examples.rb +121 -0
  95. data/{lib/celluloid/rspec → spec/shared}/mailbox_examples.rb +20 -17
  96. data/{lib/celluloid/rspec → spec/shared}/task_examples.rb +9 -8
  97. data/spec/spec_helper.rb +72 -16
  98. data/spec/support/coverage.rb +4 -0
  99. data/spec/support/crash_checking.rb +68 -0
  100. data/spec/support/debugging.rb +31 -0
  101. data/spec/support/env.rb +16 -0
  102. data/{lib/celluloid/rspec/example_actor_class.rb → spec/support/examples/actor_class.rb} +21 -2
  103. data/spec/support/examples/evented_mailbox_class.rb +27 -0
  104. data/spec/support/includer.rb +9 -0
  105. data/spec/support/logging.rb +63 -0
  106. data/spec/support/loose_threads.rb +65 -0
  107. data/spec/support/reset_class_variables.rb +27 -0
  108. data/spec/support/sleep_and_wait.rb +14 -0
  109. data/spec/support/split_logs.rb +1 -0
  110. data/spec/support/stubbing.rb +14 -0
  111. metadata +255 -95
  112. data/lib/celluloid/call_chain.rb +0 -13
  113. data/lib/celluloid/cpu_counter.rb +0 -34
  114. data/lib/celluloid/evented_mailbox.rb +0 -73
  115. data/lib/celluloid/fsm.rb +0 -186
  116. data/lib/celluloid/handlers.rb +0 -41
  117. data/lib/celluloid/internal_pool.rb +0 -159
  118. data/lib/celluloid/legacy.rb +0 -9
  119. data/lib/celluloid/links.rb +0 -36
  120. data/lib/celluloid/logger.rb +0 -93
  121. data/lib/celluloid/logging/incident.rb +0 -21
  122. data/lib/celluloid/logging/incident_logger.rb +0 -129
  123. data/lib/celluloid/logging/incident_reporter.rb +0 -48
  124. data/lib/celluloid/logging/log_event.rb +0 -20
  125. data/lib/celluloid/logging/ring_buffer.rb +0 -65
  126. data/lib/celluloid/method.rb +0 -32
  127. data/lib/celluloid/notifications.rb +0 -83
  128. data/lib/celluloid/pool_manager.rb +0 -146
  129. data/lib/celluloid/probe.rb +0 -73
  130. data/lib/celluloid/properties.rb +0 -24
  131. data/lib/celluloid/proxies/abstract_proxy.rb +0 -20
  132. data/lib/celluloid/proxies/actor_proxy.rb +0 -38
  133. data/lib/celluloid/proxies/async_proxy.rb +0 -31
  134. data/lib/celluloid/proxies/block_proxy.rb +0 -29
  135. data/lib/celluloid/proxies/cell_proxy.rb +0 -68
  136. data/lib/celluloid/proxies/future_proxy.rb +0 -35
  137. data/lib/celluloid/proxies/sync_proxy.rb +0 -36
  138. data/lib/celluloid/receivers.rb +0 -63
  139. data/lib/celluloid/registry.rb +0 -57
  140. data/lib/celluloid/responses.rb +0 -44
  141. data/lib/celluloid/rspec/actor_examples.rb +0 -1054
  142. data/lib/celluloid/signals.rb +0 -23
  143. data/lib/celluloid/stack_dump.rb +0 -133
  144. data/lib/celluloid/supervision_group.rb +0 -169
  145. data/lib/celluloid/supervisor.rb +0 -22
  146. data/lib/celluloid/task_set.rb +0 -49
  147. data/lib/celluloid/tasks/task_fiber.rb +0 -43
  148. data/lib/celluloid/tasks/task_thread.rb +0 -53
  149. data/lib/celluloid/thread_handle.rb +0 -50
  150. data/lib/celluloid/uuid.rb +0 -38
  151. data/spec/celluloid/cpu_counter_spec.rb +0 -82
  152. data/spec/celluloid/fsm_spec.rb +0 -107
  153. data/spec/celluloid/internal_pool_spec.rb +0 -52
  154. data/spec/celluloid/links_spec.rb +0 -45
  155. data/spec/celluloid/logging/ring_buffer_spec.rb +0 -38
  156. data/spec/celluloid/notifications_spec.rb +0 -120
  157. data/spec/celluloid/pool_spec.rb +0 -92
  158. data/spec/celluloid/probe_spec.rb +0 -121
  159. data/spec/celluloid/properties_spec.rb +0 -42
  160. data/spec/celluloid/registry_spec.rb +0 -64
  161. data/spec/celluloid/stack_dump_spec.rb +0 -64
  162. data/spec/celluloid/supervision_group_spec.rb +0 -65
  163. data/spec/celluloid/supervisor_spec.rb +0 -103
  164. data/spec/celluloid/tasks/task_fiber_spec.rb +0 -5
  165. data/spec/celluloid/tasks/task_thread_spec.rb +0 -5
  166. data/spec/celluloid/thread_handle_spec.rb +0 -26
  167. data/spec/celluloid/uuid_spec.rb +0 -11
@@ -0,0 +1,65 @@
1
+ module Celluloid
2
+ class Group
3
+ class NotImplemented < StandardError; end
4
+ class StillActive < StandardError; end
5
+ class NotActive < StandardError; end
6
+
7
+ attr_accessor :group
8
+
9
+ def initialize
10
+ @mutex = Mutex.new
11
+ @group = []
12
+ @running = true
13
+ end
14
+
15
+ def assert_active
16
+ fail NotActive unless active?
17
+ end
18
+
19
+ def assert_inactive
20
+ return unless active?
21
+ if RUBY_PLATFORM == "java"
22
+ Celluloid.logger.warn "Group is still active"
23
+ else
24
+ fail StillActive
25
+ end
26
+ end
27
+
28
+ def each
29
+ to_a.each { |thread| yield thread }
30
+ end
31
+
32
+ def to_a
33
+ res = nil
34
+ @mutex.synchronize { res = @group.dup }
35
+ res
36
+ end
37
+
38
+ def purge(thread)
39
+ @mutex.synchronize do
40
+ @group.delete(thread)
41
+ thread.kill rescue nil
42
+ end
43
+ end
44
+
45
+ def each_actor(&block)
46
+ to_a.lazy.select { |t| t[:celluloid_role] == :actor }.each(&block)
47
+ end
48
+
49
+ def active?
50
+ @running
51
+ end
52
+
53
+ def get
54
+ fail NotImplemented
55
+ end
56
+
57
+ def create
58
+ fail NotImplemented
59
+ end
60
+
61
+ def shutdown
62
+ fail NotImplemented
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,27 @@
1
+ module Celluloid
2
+ class Group
3
+ class Manager
4
+ include Celluloid
5
+
6
+ def manage!(group)
7
+ @group = group
8
+ every(1.26) { garbage_collector }
9
+ end
10
+
11
+ def garbage_collector
12
+ @group.each do |t|
13
+ puts "running Group::Manager garbage_collector"
14
+ # case t[:celluloid_meta][:state]
15
+ # when :finished
16
+ # # puts "thread finished: #{t.inspect}"
17
+ # else
18
+ # # puts "thread state: #{t[:celluloid_meta]}"
19
+ # end
20
+ # # puts "thread: #{t[:celluloid_actor].name}"
21
+ end
22
+ rescue => ex
23
+ puts "#{ex.backtrace.first}"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,125 @@
1
+ require "thread"
2
+
3
+ module Celluloid
4
+ class Group
5
+ class Pool < Group
6
+ # You do not want to use this. Truly, you do not. There is no scenario when you will.
7
+ # But. If you somehow do.. `Celluloid.group_class = Celluloid::Group::Pool` and weep.
8
+
9
+ attr_accessor :max_idle
10
+
11
+ def initialize
12
+ super
13
+ @mutex = Mutex.new
14
+ @idle_threads = []
15
+ @group = []
16
+ @busy_size = 0
17
+ @idle_size = 0
18
+
19
+ # TODO: should really adjust this based on usage
20
+ @max_idle = 16
21
+ end
22
+
23
+ def idle?
24
+ busy_size.count == 0
25
+ end
26
+
27
+ def busy?
28
+ busy_size.count > 0
29
+ end
30
+
31
+ attr_reader :busy_size
32
+
33
+ attr_reader :idle_size
34
+
35
+ # Get a thread from the pool, running the given block
36
+ def get(&block)
37
+ @mutex.synchronize do
38
+ assert_active
39
+
40
+ begin
41
+ if @idle_threads.empty?
42
+ thread = create
43
+ else
44
+ thread = @idle_threads.pop
45
+ @idle_size = @idle_threads.length
46
+ end
47
+ end until thread.status # handle crashed threads
48
+
49
+ thread.busy = true
50
+ @busy_size += 1
51
+ thread[:celluloid_queue] << block
52
+ thread
53
+ end
54
+ end
55
+
56
+ # Return a thread to the pool
57
+ def put(thread)
58
+ @mutex.synchronize do
59
+ thread.busy = false
60
+ if idle_size + 1 >= @max_idle
61
+ thread[:celluloid_queue] << nil
62
+ @busy_size -= 1
63
+ @group.delete(thread)
64
+ else
65
+ @idle_threads.push thread
66
+ @busy_size -= 1
67
+ @idle_size = @idle_threads.length
68
+ clean_thread_locals(thread)
69
+ end
70
+ end
71
+ end
72
+
73
+ def shutdown
74
+ @running = false
75
+ @mutex.synchronize do
76
+ finalize
77
+ @group.each do |thread|
78
+ thread[:celluloid_queue] << nil
79
+ end
80
+ @group.shift.kill until @group.empty?
81
+ @idle_threads.clear
82
+ @busy_size = 0
83
+ @idle_size = 0
84
+ end
85
+ end
86
+
87
+ private
88
+
89
+ # Create a new thread with an associated queue of procs to run
90
+ def create
91
+ queue = Queue.new
92
+ thread = Thread.new do
93
+ while proc = queue.pop
94
+ begin
95
+ proc.call
96
+ rescue Exception => ex
97
+ Internals::Logger.crash("thread crashed", ex)
98
+ ensure
99
+ put thread
100
+ end
101
+ end
102
+ end
103
+
104
+ thread[:celluloid_queue] = queue
105
+ # @idle_threads << thread
106
+ @group << thread
107
+ thread
108
+ end
109
+
110
+ # Clean the thread locals of an incoming thread
111
+ def clean_thread_locals(thread)
112
+ thread.keys.each do |key|
113
+ next if key == :celluloid_queue
114
+
115
+ # Ruby seems to lack an API for deleting thread locals. WTF, Ruby?
116
+ thread[key] = nil
117
+ end
118
+ end
119
+
120
+ def finalize
121
+ @max_idle = 0
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,71 @@
1
+ require "thread"
2
+
3
+ module Celluloid
4
+ class Group
5
+ class Spawner < Group
6
+ attr_accessor :finalizer
7
+
8
+ def initialize
9
+ super
10
+ end
11
+
12
+ def get(&block)
13
+ assert_active
14
+ fail ArgumentError.new("No block sent to Spawner.get()") unless block_given?
15
+ instantiate block
16
+ end
17
+
18
+ def shutdown
19
+ @running = false
20
+ @mutex.synchronize do
21
+ queue = Queue.new
22
+ loop do
23
+ break if @group.empty?
24
+ th = @group.shift
25
+ th.kill
26
+ queue << th
27
+ end
28
+
29
+ loop do
30
+ break if queue.empty?
31
+ queue.pop.join
32
+ end
33
+ end
34
+ end
35
+
36
+ def idle?
37
+ to_a.select { |t| t[:celluloid_meta] && t[:celluloid_meta][:state] == :running }.empty?
38
+ end
39
+
40
+ def busy?
41
+ to_a.select { |t| t[:celluloid_meta] && t[:celluloid_meta][:state] == :running }.any?
42
+ end
43
+
44
+ private
45
+
46
+ def instantiate(proc)
47
+ thread = Thread.new do
48
+ Thread.current[:celluloid_meta] = {
49
+ started: Time.now,
50
+ state: :running,
51
+ }
52
+
53
+ begin
54
+ proc.call
55
+ rescue Exception => ex
56
+ Internals::Logger.crash("thread crashed", ex)
57
+ Thread.current[:celluloid_meta][:state] = :error
58
+ ensure
59
+ unless Thread.current[:celluloid_meta][:state] == :error
60
+ Thread.current[:celluloid_meta][:state] = :finished
61
+ end
62
+ Thread.current[:celluloid_meta][:finished] = Time.now
63
+ end
64
+ end
65
+
66
+ @mutex.synchronize { @group << thread }
67
+ thread
68
+ end
69
+ end
70
+ end
71
+ end
@@ -1,5 +1,5 @@
1
- require 'celluloid/logging/log_event'
2
- require 'celluloid/logging/incident'
3
- require 'celluloid/logging/ring_buffer'
4
- require 'celluloid/logging/incident_logger'
5
- require 'celluloid/logging/incident_reporter'
1
+ require "celluloid/logging/log_event"
2
+ require "celluloid/logging/incident"
3
+ require "celluloid/logging/ring_buffer"
4
+ require "celluloid/logging/incident_logger"
5
+ require "celluloid/logging/incident_reporter"
@@ -1,4 +1,4 @@
1
- require 'thread'
1
+ require "thread"
2
2
 
3
3
  module Celluloid
4
4
  class MailboxDead < Celluloid::Error; end # you can't receive from the dead
@@ -52,37 +52,38 @@ module Celluloid
52
52
 
53
53
  @mutex.lock
54
54
  begin
55
- raise MailboxDead, "attempted to receive from a dead mailbox" if @dead
55
+ fail MailboxDead, "attempted to receive from a dead mailbox" if @dead
56
56
 
57
+ message = nil
57
58
  Timers::Wait.for(timeout) do |remaining|
58
59
  message = next_message(&block)
59
60
 
60
- break message if message
61
+ break if message
61
62
 
62
63
  @condition.wait(@mutex, remaining)
63
64
  end
64
65
  ensure
65
66
  @mutex.unlock rescue nil
66
67
  end
67
-
68
- return message
68
+
69
+ message
69
70
  end
70
71
 
71
72
  # Receive a letter from the mailbox. Guaranteed to return a message. If
72
73
  # timeout is exceeded, raise a TimeoutError.
73
74
  def receive(timeout = nil, &block)
75
+ message = nil
74
76
  Timers::Wait.for(timeout) do |remaining|
75
- if message = check(timeout, &block)
76
- return message
77
- end
77
+ message = check(timeout, &block)
78
+ break if message
78
79
  end
79
-
80
- raise TimeoutError.new("receive timeout exceeded")
80
+ return message if message
81
+ fail TimeoutError.new("receive timeout exceeded")
81
82
  end
82
83
 
83
84
  # Shut down this mailbox and clean up its contents
84
85
  def shutdown
85
- raise MailboxDead, "mailbox already shutdown" if @dead
86
+ fail MailboxDead, "mailbox already shutdown" if @dead
86
87
 
87
88
  @mutex.lock
88
89
  begin
@@ -118,7 +119,7 @@ module Celluloid
118
119
 
119
120
  # Inspect the contents of the Mailbox
120
121
  def inspect
121
- "#<#{self.class}:#{object_id.to_s(16)} @messages=[#{map { |m| m.inspect }.join(', ')}]>"
122
+ "#<#{self.class}:#{object_id.to_s(16)} @messages=[#{map(&:inspect).join(', ')}]>"
122
123
  end
123
124
 
124
125
  # Number of messages in the Mailbox
@@ -146,7 +147,7 @@ module Celluloid
146
147
  end
147
148
 
148
149
  def dead_letter(message)
149
- Logger.debug "Discarded message (mailbox is dead): #{message}" if $CELLULOID_DEBUG
150
+ Internals::Logger.debug "Discarded message (mailbox is dead): #{message}" if $CELLULOID_DEBUG
150
151
  end
151
152
 
152
153
  def mailbox_full
@@ -0,0 +1,76 @@
1
+ module Celluloid
2
+ class Mailbox
3
+ # An alternative implementation of Celluloid::Mailbox using Reactor
4
+ class Evented < Celluloid::Mailbox
5
+ attr_reader :reactor
6
+
7
+ def initialize(reactor_class)
8
+ super()
9
+ # @condition won't be used in the class.
10
+ @reactor = reactor_class.new
11
+ end
12
+
13
+ # Add a message to the Mailbox
14
+ def <<(message)
15
+ @mutex.lock
16
+ begin
17
+ if mailbox_full || @dead
18
+ dead_letter(message)
19
+ return
20
+ end
21
+ if message.is_a?(SystemEvent)
22
+ # SystemEvents are high priority messages so they get added to the
23
+ # head of our message queue instead of the end
24
+ @messages.unshift message
25
+ else
26
+ @messages << message
27
+ end
28
+ ensure
29
+ @mutex.unlock rescue nil
30
+ end
31
+ begin
32
+ current_actor = Thread.current[:celluloid_actor]
33
+ @reactor.wakeup unless current_actor && current_actor.mailbox == self
34
+ rescue IOError
35
+ Internals::Logger.crash "reactor crashed", $ERROR_INFO
36
+ dead_letter(message)
37
+ end
38
+ nil
39
+ end
40
+
41
+ # Receive a message from the Mailbox
42
+ def check(timeout = nil, &block)
43
+ # Get a message if it is available and process it immediately if possible:
44
+ if message = next_message(block)
45
+ return message
46
+ end
47
+
48
+ # ... otherwise, run the reactor once, either blocking or will return
49
+ # after the given timeout:
50
+ @reactor.run_once(timeout)
51
+
52
+ # No message was received:
53
+ return nil
54
+ rescue IOError
55
+ raise MailboxShutdown, "mailbox shutdown called during receive"
56
+ end
57
+
58
+ # Obtain the next message from the mailbox that matches the given block
59
+ def next_message(block)
60
+ @mutex.lock
61
+ begin
62
+ super(&block)
63
+ ensure
64
+ @mutex.unlock rescue nil
65
+ end
66
+ end
67
+
68
+ # Cleanup any IO objects this Mailbox may be using
69
+ def shutdown
70
+ super do
71
+ @reactor.shutdown
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end