concurrent-ruby-edge 0.3.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +552 -0
  3. data/LICENSE.txt +18 -18
  4. data/README.md +261 -103
  5. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/behaviour/abstract.rb +2 -0
  6. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/behaviour/awaits.rb +2 -0
  7. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/behaviour/buffer.rb +2 -0
  8. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/behaviour/errors_on_unknown_message.rb +2 -0
  9. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/behaviour/executes_context.rb +2 -0
  10. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/behaviour/linking.rb +2 -0
  11. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/behaviour/pausing.rb +2 -0
  12. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/behaviour/removes_child.rb +2 -0
  13. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/behaviour/sets_results.rb +2 -0
  14. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/behaviour/supervising.rb +2 -0
  15. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/behaviour/termination.rb +3 -1
  16. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/behaviour.rb +1 -1
  17. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/context.rb +3 -1
  18. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/core.rb +5 -4
  19. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/default_dead_letter_handler.rb +2 -0
  20. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/envelope.rb +2 -0
  21. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/errors.rb +2 -0
  22. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/internal_delegations.rb +3 -0
  23. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/reference.rb +9 -8
  24. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/root.rb +3 -0
  25. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/utils/ad_hoc.rb +2 -0
  26. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/utils/balancer.rb +2 -0
  27. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/utils/broadcast.rb +1 -0
  28. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/utils/pool.rb +1 -0
  29. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor.rb +11 -6
  30. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/buffer/base.rb +14 -14
  31. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/buffer/dropping.rb +1 -0
  32. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/buffer/sliding.rb +1 -0
  33. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/buffer/unbuffered.rb +1 -1
  34. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/tick.rb +1 -1
  35. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel.rb +3 -2
  36. data/lib/concurrent-ruby-edge/concurrent/edge/cancellation.rb +107 -0
  37. data/lib/concurrent-ruby-edge/concurrent/edge/channel.rb +453 -0
  38. data/lib/concurrent-ruby-edge/concurrent/edge/erlang_actor.rb +1549 -0
  39. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/edge/lock_free_linked_set/node.rb +2 -2
  40. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/edge/lock_free_linked_set.rb +8 -7
  41. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/edge/lock_free_queue.rb +2 -0
  42. data/lib/{concurrent → concurrent-ruby-edge/concurrent}/edge/old_channel_integration.rb +2 -0
  43. data/lib/concurrent-ruby-edge/concurrent/edge/processing_actor.rb +184 -0
  44. data/lib/concurrent-ruby-edge/concurrent/edge/promises.rb +174 -0
  45. data/lib/concurrent-ruby-edge/concurrent/edge/throttle.rb +229 -0
  46. data/lib/concurrent-ruby-edge/concurrent/edge/version.rb +3 -0
  47. data/lib/concurrent-ruby-edge/concurrent/edge.rb +21 -0
  48. data/lib/concurrent-ruby-edge/concurrent/executor/wrapping_executor.rb +50 -0
  49. data/lib/concurrent-ruby-edge/concurrent/lazy_register.rb +83 -0
  50. data/lib/{concurrent-edge.rb → concurrent-ruby-edge/concurrent-edge.rb} +5 -4
  51. metadata +71 -67
  52. data/lib/concurrent/edge/atomic_markable_reference.rb +0 -184
  53. data/lib/concurrent/edge/cancellation.rb +0 -138
  54. data/lib/concurrent/edge/lock_free_stack.rb +0 -126
  55. data/lib/concurrent/edge/processing_actor.rb +0 -161
  56. data/lib/concurrent/edge/promises.rb +0 -2111
  57. data/lib/concurrent/edge/throttle.rb +0 -192
  58. /data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/public_delegations.rb +0 -0
  59. /data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/type_check.rb +0 -0
  60. /data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/utils.rb +0 -0
  61. /data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/buffer/buffered.rb +0 -0
  62. /data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/buffer/ticker.rb +0 -0
  63. /data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/buffer/timer.rb +0 -0
  64. /data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/buffer.rb +0 -0
  65. /data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/selector/after_clause.rb +0 -0
  66. /data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/selector/default_clause.rb +0 -0
  67. /data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/selector/error_clause.rb +0 -0
  68. /data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/selector/put_clause.rb +0 -0
  69. /data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/selector/take_clause.rb +0 -0
  70. /data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/selector.rb +0 -0
  71. /data/lib/{concurrent → concurrent-ruby-edge/concurrent}/edge/lock_free_linked_set/window.rb +0 -0
@@ -1,3 +1,5 @@
1
+ require 'concurrent/actor/context'
2
+
1
3
  module Concurrent
2
4
  module Actor
3
5
  class DefaultDeadLetterHandler < RestartingContext
@@ -1,3 +1,5 @@
1
+ require 'concurrent/actor/type_check'
2
+
1
3
  module Concurrent
2
4
  module Actor
3
5
  class Envelope
@@ -1,3 +1,5 @@
1
+ require 'concurrent/actor/type_check'
2
+
1
3
  module Concurrent
2
4
  module Actor
3
5
  Error = Class.new(StandardError)
@@ -1,3 +1,6 @@
1
+ require 'logger'
2
+ require 'concurrent/actor/public_delegations'
3
+
1
4
  module Concurrent
2
5
  module Actor
3
6
  module InternalDelegations
@@ -1,3 +1,6 @@
1
+ require 'concurrent/actor/type_check'
2
+ require 'concurrent/actor/public_delegations'
3
+
1
4
  module Concurrent
2
5
  module Actor
3
6
 
@@ -35,12 +38,7 @@ module Concurrent
35
38
 
36
39
  alias_method :<<, :tell
37
40
 
38
- # @note it's a good practice to use tell whenever possible. Ask should be used only for
39
- # testing and when it returns very shortly. It can lead to deadlock if all threads in
40
- # global_io_executor will block on while asking. It's fine to use it form outside of actors and
41
- # global_io_executor.
42
- #
43
- # @note it's a good practice to use {#tell} whenever possible. Results can be send back with other messages.
41
+ # @note it's a good practice to use {#tell} whenever possible. Results can be sent back with other messages.
44
42
  # Ask should be used only for testing and when it returns very shortly. It can lead to deadlock if all threads in
45
43
  # global_io_executor will block on while asking. It's fine to use it form outside of actors and
46
44
  # global_io_executor.
@@ -55,10 +53,13 @@ module Concurrent
55
53
  message message, future
56
54
  end
57
55
 
56
+ # @!visibility privated
57
+ alias_method :ask_op, :ask
58
+
58
59
  # Sends the message synchronously and blocks until the message
59
60
  # is processed. Raises on error.
60
61
  #
61
- # @note it's a good practice to use {#tell} whenever possible. Results can be send back with other messages.
62
+ # @note it's a good practice to use {#tell} whenever possible. Results can be sent back with other messages.
62
63
  # Ask should be used only for testing and when it returns very shortly. It can lead to deadlock if all threads in
63
64
  # global_io_executor will block on while asking. It's fine to use it form outside of actors and
64
65
  # global_io_executor.
@@ -89,7 +90,7 @@ module Concurrent
89
90
  end
90
91
 
91
92
  def to_s
92
- "#<#{self.class}:0x#{'%x' % (object_id << 1)} #{path} (#{actor_class})>"
93
+ format '%s %s (%s)>', super[0..-2], path, actor_class
93
94
  end
94
95
 
95
96
  alias_method :inspect, :to_s
@@ -1,3 +1,6 @@
1
+ require 'concurrent/actor/context'
2
+ require 'concurrent/actor/core'
3
+
1
4
  module Concurrent
2
5
  module Actor
3
6
  # implements the root actor
@@ -1,3 +1,5 @@
1
+ require 'concurrent/actor/context'
2
+
1
3
  module Concurrent
2
4
  module Actor
3
5
  module Utils
@@ -1,3 +1,5 @@
1
+ require 'concurrent/actor/context'
2
+
1
3
  module Concurrent
2
4
  module Actor
3
5
  module Utils
@@ -1,4 +1,5 @@
1
1
  require 'set'
2
+ require 'concurrent/actor/context'
2
3
 
3
4
  module Concurrent
4
5
  module Actor
@@ -1,4 +1,5 @@
1
1
  require 'concurrent/actor/utils/balancer'
2
+ require 'concurrent/actor/context'
2
3
 
3
4
  module Concurrent
4
5
  module Actor
@@ -1,6 +1,7 @@
1
+ # NOTE: finer grained than require 'concurrent/actor' not supported
2
+
1
3
  require 'concurrent/configuration'
2
4
  require 'concurrent/executor/serialized_execution'
3
- require 'concurrent/synchronization'
4
5
  require 'concurrent/edge/promises'
5
6
 
6
7
  module Concurrent
@@ -10,9 +11,9 @@ module Concurrent
10
11
  # TODO supervision tree, pause children on error in parent, pause may need higher priority
11
12
  # TODO more effective executor
12
13
 
13
- # {include:file:doc/actor/main.md}
14
+ # {include:file:docs-source/actor/main.md}
14
15
  # @api Actor
15
- # @!macro edge_warning
16
+ # @!macro warn.edge
16
17
  module Actor
17
18
 
18
19
  require 'concurrent/actor/type_check'
@@ -35,9 +36,13 @@ module Concurrent
35
36
  end
36
37
 
37
38
  @root = Concurrent::Promises.delay do
38
- Core.new(parent: nil, name: '/', class: Root, initialized: future = Concurrent::Promises.resolvable_future).reference.tap do
39
- future.wait!
40
- end
39
+ Core.
40
+ new(parent: nil,
41
+ name: '/',
42
+ class: Root,
43
+ initialized: future = Concurrent::Promises.resolvable_future).
44
+ reference.
45
+ tap { future.wait! }
41
46
  end
42
47
 
43
48
  # A root actor, a default parent of all actors spawned outside an actor
@@ -15,13 +15,13 @@ module Concurrent
15
15
  # used as a channel buffer should extend this class.
16
16
  class Base < Synchronization::LockableObject
17
17
 
18
- # @!macro [attach] channel_buffer_capacity_reader
18
+ # @!macro channel_buffer_capacity_reader
19
19
  #
20
20
  # The maximum number of values which can be {#put} onto the buffer
21
21
  # it becomes full.
22
22
  attr_reader :capacity
23
23
 
24
- # @!macro [attach] channel_buffer_initialize
24
+ # @!macro channel_buffer_initialize
25
25
  #
26
26
  # Creates a new buffer.
27
27
  def initialize(*args)
@@ -35,7 +35,7 @@ module Concurrent
35
35
  end
36
36
  end
37
37
 
38
- # @!macro [attach] channel_buffer_blocking_question
38
+ # @!macro channel_buffer_blocking_question
39
39
  #
40
40
  # Predicate indicating if this buffer will block {#put} operations
41
41
  # once it reaches its maximum capacity.
@@ -45,14 +45,14 @@ module Concurrent
45
45
  true
46
46
  end
47
47
 
48
- # @!macro [attach] channel_buffer_size_reader
48
+ # @!macro channel_buffer_size_reader
49
49
  #
50
50
  # The number of items currently in the buffer.
51
51
  def size
52
52
  synchronize { ns_size }
53
53
  end
54
54
 
55
- # @!macro [attach] channel_buffer_empty_question
55
+ # @!macro channel_buffer_empty_question
56
56
  #
57
57
  # Predicate indicating if the buffer is empty.
58
58
  #
@@ -63,7 +63,7 @@ module Concurrent
63
63
  synchronize { ns_empty? }
64
64
  end
65
65
 
66
- # @!macro [attach] channel_buffer_full_question
66
+ # @!macro channel_buffer_full_question
67
67
  #
68
68
  # Predicate indicating if the buffer is full.
69
69
  #
@@ -74,7 +74,7 @@ module Concurrent
74
74
  synchronize { ns_full? }
75
75
  end
76
76
 
77
- # @!macro [attach] channel_buffer_put
77
+ # @!macro channel_buffer_put
78
78
  #
79
79
  # Put an item onto the buffer if possible. If the buffer is open
80
80
  # but not able to accept the item the calling thread will block
@@ -89,9 +89,9 @@ module Concurrent
89
89
  raise NotImplementedError
90
90
  end
91
91
 
92
- # @!macro [attach] channel_buffer_offer
92
+ # @!macro channel_buffer_offer
93
93
  #
94
- # Put an item onto the buffer is possible. If the buffer is open but
94
+ # Put an item onto the buffer if possible. If the buffer is open but
95
95
  # unable to add an item, probably due to being full, the method will
96
96
  # return immediately. Similarly, the method will return immediately
97
97
  # when the buffer is closed. A return value of `false` does not
@@ -107,7 +107,7 @@ module Concurrent
107
107
  raise NotImplementedError
108
108
  end
109
109
 
110
- # @!macro [attach] channel_buffer_take
110
+ # @!macro channel_buffer_take
111
111
  #
112
112
  # Take an item from the buffer if one is available. If the buffer
113
113
  # is open and no item is available the calling thread will block
@@ -123,7 +123,7 @@ module Concurrent
123
123
  raise NotImplementedError
124
124
  end
125
125
 
126
- # @!macro [attach] channel_buffer_next
126
+ # @!macro channel_buffer_next
127
127
  #
128
128
  # Take the next "item" from the buffer and also return a boolean
129
129
  # indicating if "more" items can be taken. Used for iterating
@@ -152,7 +152,7 @@ module Concurrent
152
152
  raise NotImplementedError
153
153
  end
154
154
 
155
- # @!macro [attach] channel_buffer_poll
155
+ # @!macro channel_buffer_poll
156
156
  #
157
157
  # Take the next item from the buffer if one is available else return
158
158
  # immediately. Failing to return a value does not necessarily
@@ -166,7 +166,7 @@ module Concurrent
166
166
  raise NotImplementedError
167
167
  end
168
168
 
169
- # @!macro [attach] channel_buffer_close
169
+ # @!macro channel_buffer_close
170
170
  #
171
171
  # Close the buffer, preventing new items from being added. Once a
172
172
  # buffer is closed it cannot be opened again.
@@ -179,7 +179,7 @@ module Concurrent
179
179
  end
180
180
  end
181
181
 
182
- # @!macro [attach] channel_buffer_closed_question
182
+ # @!macro channel_buffer_closed_question
183
183
  #
184
184
  # Predicate indicating is this buffer closed.
185
185
  #
@@ -1,4 +1,5 @@
1
1
  require 'concurrent/channel/buffer/base'
2
+ require 'concurrent/channel/buffer/buffered'
2
3
 
3
4
  module Concurrent
4
5
  class Channel
@@ -1,4 +1,5 @@
1
1
  require 'concurrent/channel/buffer/base'
2
+ require 'concurrent/channel/buffer/buffered'
2
3
 
3
4
  module Concurrent
4
5
  class Channel
@@ -131,7 +131,7 @@ module Concurrent
131
131
  # waiting to {#put} items onto the buffer. This method exhibits the
132
132
  # same blocking behavior as {#take}.
133
133
  #
134
- # @see {#take}
134
+ # @see #take
135
135
  def next
136
136
  item = take
137
137
  more = (item != Concurrent::NULL)
@@ -1,4 +1,4 @@
1
- require 'concurrent/synchronization'
1
+ require 'concurrent/synchronization/object'
2
2
  require 'concurrent/utility/monotonic_time'
3
3
 
4
4
  module Concurrent
@@ -8,13 +8,14 @@ require 'concurrent/executor/cached_thread_pool'
8
8
 
9
9
  module Concurrent
10
10
 
11
- # {include:file:doc/channel.md}
11
+ # {include:file:docs-source/channel.md}
12
+ # @!macro warn.edge
12
13
  class Channel
13
14
  extend Forwardable
14
15
  include Enumerable
15
16
 
16
17
  # NOTE: Move to global IO pool once stable
17
- GOROUTINES = Concurrent::CachedThreadPool.new(auto_terminate: true)
18
+ GOROUTINES = Concurrent::CachedThreadPool.new
18
19
  private_constant :GOROUTINES
19
20
 
20
21
  BUFFER_TYPES = {
@@ -0,0 +1,107 @@
1
+ require 'concurrent/concern/deprecation'
2
+ require 'concurrent/synchronization/object'
3
+ require 'concurrent/promises'
4
+
5
+ module Concurrent
6
+
7
+ # TODO (pitr-ch 27-Mar-2016): cooperation with mutex, condition, select etc?
8
+ # TODO (pitr-ch 10-Dec-2018): integrate with enumerator?
9
+ # token.cancelable(array.each_with_index).each do |v, i|
10
+ # # stops iterating when cancelled
11
+ # end
12
+ # token.cancelable(array).each_with_index do |v, i|
13
+ # # stops iterating when cancelled
14
+ # end
15
+
16
+ # The Cancellation abstraction provides cooperative cancellation.
17
+ #
18
+ # The standard methods `Thread#raise` of `Thread#kill` available in Ruby
19
+ # are very dangerous (see linked the blog posts bellow).
20
+ # Therefore concurrent-ruby provides an alternative.
21
+ # * <https://jvns.ca/blog/2015/11/27/why-rubys-timeout-is-dangerous-and-thread-dot-raise-is-terrifying/>
22
+ # * <http://www.mikeperham.com/2015/05/08/timeout-rubys-most-dangerous-api/>
23
+ # * <http://blog.headius.com/2008/02/rubys-threadraise-threadkill-timeoutrb.html>
24
+ #
25
+ # It provides an object which represents a task which can be executed,
26
+ # the task has to get the reference to the object and periodically cooperatively check that it is not cancelled.
27
+ # Good practices to make tasks cancellable:
28
+ # * check cancellation every cycle of a loop which does significant work,
29
+ # * do all blocking actions in a loop with a timeout then on timeout check cancellation
30
+ # and if ok block again with the timeout
31
+ #
32
+ # The idea was inspired by <https://msdn.microsoft.com/en-us/library/dd537607(v=vs.110).aspx>
33
+ # @!macro warn.edge
34
+ #
35
+ # {include:file:docs-source/cancellation.out.md}
36
+ class Cancellation < Synchronization::Object
37
+ safe_initialization!
38
+
39
+ # Create Cancellation which will cancel itself in given time
40
+ #
41
+ # @!macro promises.param.intended_time
42
+ # @return [Cancellation]
43
+ def self.timeout(intended_time)
44
+ new Concurrent::Promises.schedule(intended_time)
45
+ end
46
+
47
+ # Creates the cancellation object.
48
+ #
49
+ # @param [Promises::Future, Promises::Event] origin of the cancellation.
50
+ # When it is resolved the cancellation is canceled.
51
+ # @example
52
+ # cancellation, origin = Concurrent::Cancellation.new
53
+ # @see #to_ary
54
+ def initialize(origin = Promises.resolvable_event)
55
+ super()
56
+ @Origin = origin
57
+ end
58
+
59
+ # Allow to multi-assign the Cancellation object
60
+ # @return [Array(Cancellation, Promises::Future), Array(Cancellation, Promises::Event)]
61
+ # @example
62
+ # cancellation = Concurrent::Cancellation.new
63
+ # cancellation, origin = Concurrent::Cancellation.new
64
+ def to_ary
65
+ [self, @Origin]
66
+ end
67
+
68
+ # The event or future which is the origin of the cancellation
69
+ # @return [Promises::Future, Promises::Event]
70
+ def origin
71
+ @Origin
72
+ end
73
+
74
+ # Is the cancellation cancelled?
75
+ # Respective, was the origin of the cancellation resolved.
76
+ # @return [true, false]
77
+ def canceled?
78
+ @Origin.resolved?
79
+ end
80
+
81
+ # Raise error when cancelled
82
+ # @param [#exception] error to be risen
83
+ # @raise the error
84
+ # @return [self]
85
+ def check!(error = CancelledOperationError)
86
+ raise error if canceled?
87
+ self
88
+ end
89
+
90
+ # Creates a new Cancellation which is cancelled when first
91
+ # of the supplied cancellations or self is cancelled.
92
+ #
93
+ # @param [Cancellation] cancellations to combine
94
+ # @return [Cancellation] new cancellation
95
+ def join(*cancellations)
96
+ Cancellation.new Promises.any_event(*[@Origin, *cancellations.map(&:origin)])
97
+ end
98
+
99
+ # Short string representation.
100
+ # @return [String]
101
+ def to_s
102
+ format '%s %s>', super[0..-2], canceled? ? 'canceled' : 'pending'
103
+ end
104
+
105
+ alias_method :inspect, :to_s
106
+ end
107
+ end