concurrent-ruby-edge 0.3.1 → 0.7.0

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.
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