concurrent-ruby-edge 0.2.1 → 0.2.2

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 (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/concurrent/edge/future.rb +88 -73
  3. metadata +5 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 701e26cf927708495af961bdb3d74ecc9d19f674
4
- data.tar.gz: f0c8360bfa3bcd0d0ac9ffd6870a039e4f422e94
3
+ metadata.gz: 20739acc38b2038d536762dc5655b68b0cde737c
4
+ data.tar.gz: 5c133ef27aedb2505479213aeb3beae3eb3a7f68
5
5
  SHA512:
6
- metadata.gz: abe04d158a10d5d137dee2e2ca9b6612b4028ea505296d2e6892af3166443e648bdb0a0a7ca8e8a64a2d3870830e02fc61d471a53b6627ff612da7c13ea508da
7
- data.tar.gz: c645a675298541932bec282938cfac60d3b61c562eecd0383fd0224ff3ef794f038109eb064deb4535f70876a6ee40a90651a1a06ac67731f0bb08e149f4466f
6
+ metadata.gz: 30ad063a0289862764c7ae0ca71318b606ee8f09a8537d0362f17cf35adf1d47eef5dce46950895bb5def9286f3e52133ecc4c4fea1f03a5626c6281b0f44123
7
+ data.tar.gz: 5e3e8a5c3e700878ad6c457ef5d90c557a608762a7a2a1eeb8105c032505d4210586d7424aa78a1566119dbea6531ebfd5044abad86155b4468ba43d7c664ff3
@@ -66,7 +66,7 @@ module Concurrent
66
66
  # requested by calling `#wait`, `#value`, `#value!`, etc. on it or on any of the chained futures.
67
67
  # @return [Future]
68
68
  def delay(default_executor = :io, &task)
69
- Delay.new(default_executor).future.then(&task)
69
+ DelayPromise.new(default_executor).future.then(&task)
70
70
  end
71
71
 
72
72
  # Schedules the block to be executed on executor in given intended_time.
@@ -98,8 +98,18 @@ module Concurrent
98
98
  # Constructs new {Future} which is completed after first of the futures is complete.
99
99
  # @param [Event] futures
100
100
  # @return [Future]
101
- def any(*futures)
102
- AnyPromise.new(futures, :io).future
101
+ def any_complete(*futures)
102
+ AnyCompletePromise.new(futures, :io).future
103
+ end
104
+
105
+ alias_method :any, :any_complete
106
+
107
+ # Constructs new {Future} which becomes succeeded after first of the futures succeedes or
108
+ # failed if all futures fail (reason is last error).
109
+ # @param [Event] futures
110
+ # @return [Future]
111
+ def any_successful(*futures)
112
+ AnySuccessfulPromise.new(futures, :io).future
103
113
  end
104
114
 
105
115
  # only proof of concept
@@ -137,13 +147,11 @@ module Concurrent
137
147
  # TODO allow to to have a zip point for many futures and process them in batches by 10
138
148
  end
139
149
 
140
- extend FutureShortcuts
141
- include FutureShortcuts
142
-
143
150
  # Represents an event which will happen in future (will be completed). It has to always happen.
144
- class Event < Synchronization::LockableObject
151
+ class Event < Synchronization::Object
145
152
  safe_initialization!
146
153
  private(*attr_atomic(:internal_state))
154
+ # @!visibility private
147
155
  public :internal_state
148
156
  include Concern::Deprecation
149
157
  include Concern::Logging
@@ -188,13 +196,13 @@ module Concurrent
188
196
 
189
197
  def initialize(promise, default_executor)
190
198
  super()
199
+ @Lock = Mutex.new
200
+ @Condition = ConditionVariable.new
191
201
  @Promise = promise
192
202
  @DefaultExecutor = default_executor
193
- @Touched = AtomicBoolean.new(false)
203
+ @Touched = AtomicBoolean.new false
194
204
  @Callbacks = LockFreeStack.new
195
- # TODO (pitr 12-Sep-2015): replace with AtomicFixnum, avoid aba problem
196
- # TODO (pitr 12-Sep-2015): look at java.util.concurrent solution
197
- @Waiters = LockFreeStack.new
205
+ @Waiters = AtomicFixnum.new 0
198
206
  self.internal_state = PENDING
199
207
  end
200
208
 
@@ -276,7 +284,7 @@ module Concurrent
276
284
  # Inserts delay into the chain of Futures making rest of it lazy evaluated.
277
285
  # @return [Event]
278
286
  def delay
279
- ZipEventEventPromise.new(self, Delay.new(@DefaultExecutor).event, @DefaultExecutor).event
287
+ ZipEventEventPromise.new(self, DelayPromise.new(@DefaultExecutor).event, @DefaultExecutor).event
280
288
  end
281
289
 
282
290
  # # Schedules rest of the chain for execution with specified time or on specified time
@@ -298,13 +306,13 @@ module Concurrent
298
306
  # @yield [success, value, reason] executed async on `executor` when completed
299
307
  # @return self
300
308
  def on_completion(executor = nil, &callback)
301
- add_callback :pr_async_callback_on_completion, executor || @DefaultExecutor, callback
309
+ add_callback :async_callback_on_completion, executor || @DefaultExecutor, callback
302
310
  end
303
311
 
304
312
  # @yield [success, value, reason] executed sync when completed
305
313
  # @return self
306
314
  def on_completion!(&callback)
307
- add_callback :pr_callback_on_completion, callback
315
+ add_callback :callback_on_completion, callback
308
316
  end
309
317
 
310
318
  # Changes default executor for rest of the chain
@@ -329,9 +337,8 @@ module Concurrent
329
337
  # @!visibility private
330
338
  def complete_with(state, raise_on_reassign = true)
331
339
  if compare_and_set_internal_state(PENDING, state)
332
- #(state)
333
340
  # go to synchronized block only if there were waiting threads
334
- synchronize { ns_broadcast } if @Waiters.clear
341
+ @Lock.synchronize { @Condition.broadcast } unless @Waiters.value == 0
335
342
  call_callbacks
336
343
  else
337
344
  Concurrent::MultipleAssignmentError.new('Event can be completed only once') if raise_on_reassign
@@ -388,32 +395,31 @@ module Concurrent
388
395
 
389
396
  # @return [true, false]
390
397
  def wait_until_complete(timeout)
391
- while true
392
- last_waiter = @Waiters.peek # waiters' state before completion
393
- return true if completed?
394
-
395
- # synchronize so it cannot be signaled before it waits
396
- synchronize do
397
- # ok only if completing thread did not start signaling
398
- next unless @Waiters.compare_and_push last_waiter, Thread.current
399
- return ns_wait_until(timeout) { completed? }
398
+ return true if completed?
399
+
400
+ @Lock.synchronize do
401
+ @Waiters.increment
402
+ unless completed?
403
+ @Condition.wait @Lock, timeout
400
404
  end
405
+ @Waiters.decrement
401
406
  end
407
+ completed?
402
408
  end
403
409
 
404
- def pr_with_async(executor, *args, &block)
410
+ def with_async(executor, *args, &block)
405
411
  Concurrent.post_on(executor, *args, &block)
406
412
  end
407
413
 
408
- def pr_async_callback_on_completion(executor, callback)
409
- pr_with_async(executor) { pr_callback_on_completion callback }
414
+ def async_callback_on_completion(executor, callback)
415
+ with_async(executor) { callback_on_completion callback }
410
416
  end
411
417
 
412
- def pr_callback_on_completion(callback)
418
+ def callback_on_completion(callback)
413
419
  callback.call
414
420
  end
415
421
 
416
- def pr_callback_notify_blocked(promise)
422
+ def callback_notify_blocked(promise)
417
423
  promise.on_done self
418
424
  end
419
425
 
@@ -660,13 +666,13 @@ module Concurrent
660
666
 
661
667
  # @return [Future] which has first completed value from futures
662
668
  def any(*futures)
663
- AnyPromise.new([self, *futures], @DefaultExecutor).future
669
+ AnyCompletePromise.new([self, *futures], @DefaultExecutor).future
664
670
  end
665
671
 
666
672
  # Inserts delay into the chain of Futures making rest of it lazy evaluated.
667
673
  # @return [Future]
668
674
  def delay
669
- ZipFutureEventPromise.new(self, Delay.new(@DefaultExecutor).future, @DefaultExecutor).future
675
+ ZipFutureEventPromise.new(self, DelayPromise.new(@DefaultExecutor).future, @DefaultExecutor).future
670
676
  end
671
677
 
672
678
  # Schedules rest of the chain for execution with specified time or on specified time
@@ -714,32 +720,32 @@ module Concurrent
714
720
  # @yield [value] executed async on `executor` when success
715
721
  # @return self
716
722
  def on_success(executor = nil, &callback)
717
- add_callback :pr_async_callback_on_success, executor || @DefaultExecutor, callback
723
+ add_callback :async_callback_on_success, executor || @DefaultExecutor, callback
718
724
  end
719
725
 
720
726
  # @yield [reason] executed async on `executor` when failed?
721
727
  # @return self
722
728
  def on_failure(executor = nil, &callback)
723
- add_callback :pr_async_callback_on_failure, executor || @DefaultExecutor, callback
729
+ add_callback :async_callback_on_failure, executor || @DefaultExecutor, callback
724
730
  end
725
731
 
726
732
  # @yield [value] executed sync when success
727
733
  # @return self
728
734
  def on_success!(&callback)
729
- add_callback :pr_callback_on_success, callback
735
+ add_callback :callback_on_success, callback
730
736
  end
731
737
 
732
738
  # @yield [reason] executed sync when failed?
733
739
  # @return self
734
740
  def on_failure!(&callback)
735
- add_callback :pr_callback_on_failure, callback
741
+ add_callback :callback_on_failure, callback
736
742
  end
737
743
 
738
744
  # @!visibility private
739
745
  def complete_with(state, raise_on_reassign = true)
740
746
  if compare_and_set_internal_state(PENDING, state)
741
- @Waiters.clear
742
- synchronize { ns_broadcast }
747
+ # go to synchronized block only if there were waiting threads
748
+ @Lock.synchronize { @Condition.broadcast } unless @Waiters.value == 0
743
749
  call_callbacks state
744
750
  else
745
751
  if raise_on_reassign
@@ -792,37 +798,37 @@ module Concurrent
792
798
  self.send method, state, *args
793
799
  end
794
800
 
795
- def pr_async_callback_on_success(state, executor, callback)
796
- pr_with_async(executor, state, callback) do |st, cb|
797
- pr_callback_on_success st, cb
801
+ def async_callback_on_success(state, executor, callback)
802
+ with_async(executor, state, callback) do |st, cb|
803
+ callback_on_success st, cb
798
804
  end
799
805
  end
800
806
 
801
- def pr_async_callback_on_failure(state, executor, callback)
802
- pr_with_async(executor, state, callback) do |st, cb|
803
- pr_callback_on_failure st, cb
807
+ def async_callback_on_failure(state, executor, callback)
808
+ with_async(executor, state, callback) do |st, cb|
809
+ callback_on_failure st, cb
804
810
  end
805
811
  end
806
812
 
807
- def pr_callback_on_success(state, callback)
813
+ def callback_on_success(state, callback)
808
814
  state.apply callback if state.success?
809
815
  end
810
816
 
811
- def pr_callback_on_failure(state, callback)
817
+ def callback_on_failure(state, callback)
812
818
  state.apply callback unless state.success?
813
819
  end
814
820
 
815
- def pr_callback_on_completion(state, callback)
821
+ def callback_on_completion(state, callback)
816
822
  callback.call state.result
817
823
  end
818
824
 
819
- def pr_callback_notify_blocked(state, promise)
825
+ def callback_notify_blocked(state, promise)
820
826
  super(promise)
821
827
  end
822
828
 
823
- def pr_async_callback_on_completion(state, executor, callback)
824
- pr_with_async(executor, state, callback) do |st, cb|
825
- pr_callback_on_completion st, cb
829
+ def async_callback_on_completion(state, executor, callback)
830
+ with_async(executor, state, callback) do |st, cb|
831
+ callback_on_completion st, cb
826
832
  end
827
833
  end
828
834
 
@@ -1001,7 +1007,7 @@ module Concurrent
1001
1007
  class BlockedPromise < InnerPromise
1002
1008
  def self.new(*args, &block)
1003
1009
  promise = super(*args, &block)
1004
- promise.blocked_by.each { |f| f.add_callback :pr_callback_notify_blocked, promise }
1010
+ promise.blocked_by.each { |f| f.add_callback :callback_notify_blocked, promise }
1005
1011
  promise
1006
1012
  end
1007
1013
 
@@ -1014,7 +1020,7 @@ module Concurrent
1014
1020
  # @api private
1015
1021
  def on_done(future)
1016
1022
  countdown = process_on_done(future)
1017
- completable = completable?(countdown)
1023
+ completable = completable?(countdown, future)
1018
1024
 
1019
1025
  if completable
1020
1026
  on_completable(future)
@@ -1051,7 +1057,7 @@ module Concurrent
1051
1057
  end
1052
1058
 
1053
1059
  # @return [true,false] if completable
1054
- def completable?(countdown)
1060
+ def completable?(countdown, future)
1055
1061
  countdown.zero?
1056
1062
  end
1057
1063
 
@@ -1171,7 +1177,7 @@ module Concurrent
1171
1177
  case value
1172
1178
  when Future
1173
1179
  @BlockedBy.push value
1174
- value.add_callback :pr_callback_notify_blocked, self
1180
+ value.add_callback :callback_notify_blocked, self
1175
1181
  @Countdown.value
1176
1182
  when Event
1177
1183
  evaluate_to(lambda { raise TypeError, 'cannot flatten to Event' })
@@ -1200,8 +1206,8 @@ module Concurrent
1200
1206
  nil
1201
1207
  end
1202
1208
 
1203
- def completable?(countdown)
1204
- !@Future.internal_state.completed? && super(countdown)
1209
+ def completable?(countdown, future)
1210
+ !@Future.internal_state.completed? && super(countdown, future)
1205
1211
  end
1206
1212
  end
1207
1213
 
@@ -1321,7 +1327,7 @@ module Concurrent
1321
1327
  end
1322
1328
 
1323
1329
  # @!visibility private
1324
- class AnyPromise < BlockedPromise
1330
+ class AnyCompletePromise < BlockedPromise
1325
1331
 
1326
1332
  private
1327
1333
 
@@ -1331,7 +1337,7 @@ module Concurrent
1331
1337
  super(Future.new(self, default_executor), blocked_by_futures, blocked_by_futures.size)
1332
1338
  end
1333
1339
 
1334
- def completable?(countdown)
1340
+ def completable?(countdown, future)
1335
1341
  true
1336
1342
  end
1337
1343
 
@@ -1341,29 +1347,35 @@ module Concurrent
1341
1347
  end
1342
1348
 
1343
1349
  # @!visibility private
1344
- class Delay < InnerPromise
1345
- def touch
1346
- @Future.complete_with Event::COMPLETED
1347
- end
1350
+ class AnySuccessfulPromise < BlockedPromise
1348
1351
 
1349
1352
  private
1350
1353
 
1351
- def initialize(default_executor)
1352
- super Event.new(self, default_executor)
1354
+ def initialize(blocked_by_futures, default_executor)
1355
+ blocked_by_futures.all? { |f| f.is_a? Future } or
1356
+ raise ArgumentError, 'accepts only Futures not Events'
1357
+ super(Future.new(self, default_executor), blocked_by_futures, blocked_by_futures.size)
1358
+ end
1359
+
1360
+ def completable?(countdown, future)
1361
+ future.success? || super(countdown, future)
1362
+ end
1363
+
1364
+ def on_completable(done_future)
1365
+ complete_with done_future.internal_state, false
1353
1366
  end
1354
1367
  end
1355
1368
 
1356
1369
  # @!visibility private
1357
- class DelayValue < InnerPromise
1370
+ class DelayPromise < InnerPromise
1358
1371
  def touch
1359
- @Future.complete_with Future::Success.new(@Value)
1372
+ @Future.complete_with Event::COMPLETED
1360
1373
  end
1361
1374
 
1362
1375
  private
1363
1376
 
1364
- def initialize(default_executor, value)
1365
- super Future.new(self, default_executor)
1366
- @Value = value
1377
+ def initialize(default_executor)
1378
+ super Event.new(self, default_executor)
1367
1379
  end
1368
1380
  end
1369
1381
 
@@ -1401,7 +1413,10 @@ module Concurrent
1401
1413
  end
1402
1414
  end
1403
1415
  end
1404
-
1405
- extend Edge::FutureShortcuts
1406
- include Edge::FutureShortcuts
1407
1416
  end
1417
+
1418
+ Concurrent::Edge.send :extend, Concurrent::Edge::FutureShortcuts
1419
+ Concurrent::Edge.send :include, Concurrent::Edge::FutureShortcuts
1420
+
1421
+ Concurrent.send :extend, Concurrent::Edge::FutureShortcuts
1422
+ Concurrent.send :include, Concurrent::Edge::FutureShortcuts
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: concurrent-ruby-edge
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jerry D'Antonio
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2016-02-27 00:00:00.000000000 Z
13
+ date: 2016-05-02 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: concurrent-ruby
@@ -18,14 +18,14 @@ dependencies:
18
18
  requirements:
19
19
  - - "~>"
20
20
  - !ruby/object:Gem::Version
21
- version: 1.0.1
21
+ version: 1.0.2
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
26
  - - "~>"
27
27
  - !ruby/object:Gem::Version
28
- version: 1.0.1
28
+ version: 1.0.2
29
29
  description: |
30
30
  These features are under active development and may change frequently. They are expected not to
31
31
  keep backward compatibility (there may also lack tests and documentation). Semantic versions will
@@ -113,7 +113,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
113
113
  version: '0'
114
114
  requirements: []
115
115
  rubyforge_project:
116
- rubygems_version: 2.6.0
116
+ rubygems_version: 2.6.4
117
117
  signing_key:
118
118
  specification_version: 4
119
119
  summary: Edge features and additions to the concurrent-ruby gem.