@@ -672,8 +672,9 @@ def resolve_with(state, raise_on_reassign = true)
672
672
# @!visibility private
673
673
# @return [Array<AbstractPromise>]
674
674
def blocks
675
- @Callbacks . each_with_object ( [ ] ) do |callback , promises |
676
- promises . push ( *( callback . select { |v | v . is_a? AbstractPromise } ) )
675
+ # TODO (pitr-ch 18-Dec-2016): add macro noting that debug methods may change api without warning
676
+ @Callbacks . each_with_object ( [ ] ) do |( method , *args ) , promises |
677
+ promises . push ( args [ 0 ] ) if method == :callback_notify_blocked
677
678
end
678
679
end
679
680
@@ -759,8 +760,8 @@ def async_callback_on_resolution(state, executor, args, callback)
759
760
end
760
761
end
761
762
762
- def callback_notify_blocked ( state , promise )
763
- promise . on_resolution self
763
+ def callback_notify_blocked ( state , promise , index )
764
+ promise . on_resolution self , index
764
765
end
765
766
end
766
767
@@ -985,7 +986,7 @@ def rescue_on(executor, *args, &task)
985
986
# @return [Future]
986
987
def zip ( other )
987
988
if other . is_a? ( Future )
988
- ZipFutureFuturePromise . new_blocked ( [ self , other ] , self , other , @DefaultExecutor ) . future
989
+ ZipFuturesPromise . new_blocked ( [ self , other ] , [ self , other ] , @DefaultExecutor ) . future
989
990
else
990
991
ZipFutureEventPromise . new_blocked ( [ self , other ] , self , other , @DefaultExecutor ) . future
991
992
end
@@ -1009,10 +1010,10 @@ def any(event_or_future)
1009
1010
#
1010
1011
# @return [Future]
1011
1012
def delay
1012
- future = DelayPromise . new ( @DefaultExecutor ) . future
1013
- ZipFutureEventPromise . new_blocked ( [ self , future ] ,
1013
+ event = DelayPromise . new ( @DefaultExecutor ) . event
1014
+ ZipFutureEventPromise . new_blocked ( [ self , event ] ,
1014
1015
self ,
1015
- future ,
1016
+ event ,
1016
1017
@DefaultExecutor ) . future
1017
1018
end
1018
1019
@@ -1373,7 +1374,7 @@ class BlockedPromise < InnerPromise
1373
1374
def self . new_blocked ( blockers , *args , &block )
1374
1375
promise = new ( *args , &block )
1375
1376
ensure
1376
- blockers . each { |f | f . add_callback :callback_notify_blocked , promise }
1377
+ blockers . each_with_index { |f , i | f . add_callback :callback_notify_blocked , promise , i }
1377
1378
end
1378
1379
1379
1380
def initialize ( future , blocked_by_futures , countdown )
@@ -1383,12 +1384,13 @@ def initialize(future, blocked_by_futures, countdown)
1383
1384
end
1384
1385
1385
1386
# @!visibility private
1386
- def on_resolution ( future )
1387
- countdown = process_on_resolution ( future )
1388
- resolvable = resolvable? ( countdown , future )
1387
+ def on_resolution ( future , index )
1388
+ # TODO (pitr-ch 18-Dec-2016): rename to on_blocker_resolution
1389
+ countdown = process_on_resolution ( future , index )
1390
+ resolvable = resolvable? ( countdown , future , index )
1389
1391
1390
1392
if resolvable
1391
- on_resolvable ( future )
1393
+ on_resolvable ( future , index )
1392
1394
# futures could be deleted from blocked_by one by one here, but that would be too expensive,
1393
1395
# it's done once when all are resolved to free their references
1394
1396
clear_blocked_by!
@@ -1428,15 +1430,15 @@ def clear_blocked_by!
1428
1430
end
1429
1431
1430
1432
# @return [true,false] if resolvable
1431
- def resolvable? ( countdown , future )
1433
+ def resolvable? ( countdown , future , index )
1432
1434
countdown . zero?
1433
1435
end
1434
1436
1435
- def process_on_resolution ( future )
1437
+ def process_on_resolution ( future , index )
1436
1438
@Countdown . decrement
1437
1439
end
1438
1440
1439
- def on_resolvable ( resolved_future )
1441
+ def on_resolvable ( resolved_future , index )
1440
1442
raise NotImplementedError
1441
1443
end
1442
1444
end
@@ -1465,7 +1467,7 @@ def initialize(blocked_by_future, default_executor, executor, args, &task)
1465
1467
super blocked_by_future , default_executor , executor , args , &task
1466
1468
end
1467
1469
1468
- def on_resolvable ( resolved_future )
1470
+ def on_resolvable ( resolved_future , index )
1469
1471
if resolved_future . fulfilled?
1470
1472
Concurrent . executor ( @Executor ) . post ( resolved_future , @Args , @Task ) do |future , args , task |
1471
1473
evaluate_to lambda { future . apply args , task }
@@ -1483,7 +1485,7 @@ def initialize(blocked_by_future, default_executor, executor, args, &task)
1483
1485
super blocked_by_future , default_executor , executor , args , &task
1484
1486
end
1485
1487
1486
- def on_resolvable ( resolved_future )
1488
+ def on_resolvable ( resolved_future , index )
1487
1489
if resolved_future . rejected?
1488
1490
Concurrent . executor ( @Executor ) . post ( resolved_future , @Args , @Task ) do |future , args , task |
1489
1491
evaluate_to lambda { future . apply args , task }
@@ -1497,7 +1499,7 @@ def on_resolvable(resolved_future)
1497
1499
class ChainPromise < BlockedTaskPromise
1498
1500
private
1499
1501
1500
- def on_resolvable ( resolved_future )
1502
+ def on_resolvable ( resolved_future , index )
1501
1503
if Future === resolved_future
1502
1504
Concurrent . executor ( @Executor ) . post ( resolved_future , @Args , @Task ) do |future , args , task |
1503
1505
evaluate_to ( *future . result , *args , task )
@@ -1536,7 +1538,7 @@ def initialize_blocked_by(blocked_by_future)
1536
1538
@BlockedBy = LockFreeStack . new . push ( blocked_by_future )
1537
1539
end
1538
1540
1539
- def on_resolvable ( resolved_future )
1541
+ def on_resolvable ( resolved_future , index )
1540
1542
resolve_with resolved_future . internal_state
1541
1543
end
1542
1544
@@ -1550,8 +1552,8 @@ def blocked_by_add(future)
1550
1552
future . touch if self . future . touched?
1551
1553
end
1552
1554
1553
- def resolvable? ( countdown , future )
1554
- !@Future . internal_state . resolved? && super ( countdown , future )
1555
+ def resolvable? ( countdown , future , index )
1556
+ !@Future . internal_state . resolved? && super ( countdown , future , index )
1555
1557
end
1556
1558
end
1557
1559
@@ -1563,8 +1565,8 @@ def initialize(blocked_by_future, default_executor)
1563
1565
super Event . new ( self , default_executor ) , blocked_by_future , 2
1564
1566
end
1565
1567
1566
- def process_on_resolution ( future )
1567
- countdown = super ( future )
1568
+ def process_on_resolution ( future , index )
1569
+ countdown = super ( future , index )
1568
1570
if countdown . nonzero?
1569
1571
internal_state = future . internal_state
1570
1572
@@ -1577,8 +1579,8 @@ def process_on_resolution(future)
1577
1579
case value
1578
1580
when Future , Event
1579
1581
blocked_by_add value
1580
- value . add_callback :callback_notify_blocked , self
1581
- @Countdown . value
1582
+ value . add_callback :callback_notify_blocked , self , nil
1583
+ countdown
1582
1584
else
1583
1585
resolve_with RESOLVED
1584
1586
end
@@ -1597,8 +1599,8 @@ def initialize(blocked_by_future, levels, default_executor)
1597
1599
super Future . new ( self , default_executor ) , blocked_by_future , 1 + levels
1598
1600
end
1599
1601
1600
- def process_on_resolution ( future )
1601
- countdown = super ( future )
1602
+ def process_on_resolution ( future , index )
1603
+ countdown = super ( future , index )
1602
1604
if countdown . nonzero?
1603
1605
internal_state = future . internal_state
1604
1606
@@ -1611,8 +1613,8 @@ def process_on_resolution(future)
1611
1613
case value
1612
1614
when Future
1613
1615
blocked_by_add value
1614
- value . add_callback :callback_notify_blocked , self
1615
- @Countdown . value
1616
+ value . add_callback :callback_notify_blocked , self , nil
1617
+ countdown
1616
1618
when Event
1617
1619
evaluate_to ( lambda { raise TypeError , 'cannot flatten to Event' } )
1618
1620
else
@@ -1632,7 +1634,7 @@ def initialize(blocked_by_future, default_executor)
1632
1634
super Future . new ( self , default_executor ) , blocked_by_future , 1
1633
1635
end
1634
1636
1635
- def process_on_resolution ( future )
1637
+ def process_on_resolution ( future , index )
1636
1638
internal_state = future . internal_state
1637
1639
1638
1640
unless internal_state . fulfilled?
@@ -1645,7 +1647,7 @@ def process_on_resolution(future)
1645
1647
when Future
1646
1648
# FIXME (pitr-ch 08-Dec-2016): will accumulate the completed futures
1647
1649
blocked_by_add value
1648
- value . add_callback :callback_notify_blocked , self
1650
+ value . add_callback :callback_notify_blocked , self , nil
1649
1651
else
1650
1652
resolve_with internal_state
1651
1653
end
@@ -1661,43 +1663,28 @@ def initialize(event1, event2, default_executor)
1661
1663
1662
1664
private
1663
1665
1664
- def on_resolvable ( resolved_future )
1666
+ def on_resolvable ( resolved_future , index )
1665
1667
resolve_with RESOLVED
1666
1668
end
1667
1669
end
1668
1670
1669
1671
class ZipFutureEventPromise < BlockedPromise
1670
1672
def initialize ( future , event , default_executor )
1671
1673
super Future . new ( self , default_executor ) , [ future , event ] , 2
1672
- @FutureResult = future
1674
+ @result = nil
1673
1675
end
1674
1676
1675
1677
private
1676
1678
1677
- def on_resolvable ( resolved_future )
1678
- resolve_with @FutureResult . internal_state
1679
- end
1680
- end
1681
-
1682
- class ZipFutureFuturePromise < BlockedPromise
1683
- def initialize ( future1 , future2 , default_executor )
1684
- super Future . new ( self , default_executor ) , [ future1 , future2 ] , 2
1685
- @Future1Result = future1
1686
- @Future2Result = future2
1679
+ def process_on_resolution ( future , index )
1680
+ # first blocking is future, take its result
1681
+ @result = future . internal_state if index == 0
1682
+ # super has to be called after above to piggyback on volatile @Countdown
1683
+ super future , index
1687
1684
end
1688
1685
1689
- private
1690
-
1691
- def on_resolvable ( resolved_future )
1692
- fulfilled1 , value1 , reason1 = @Future1Result . result
1693
- fulfilled2 , value2 , reason2 = @Future2Result . result
1694
- fulfilled = fulfilled1 && fulfilled2
1695
- new_state = if fulfilled
1696
- FulfilledArray . new ( [ value1 , value2 ] )
1697
- else
1698
- PartiallyRejected . new ( [ value1 , value2 ] , [ reason1 , reason2 ] )
1699
- end
1700
- resolve_with new_state
1686
+ def on_resolvable ( resolved_future , index )
1687
+ resolve_with @result
1701
1688
end
1702
1689
end
1703
1690
@@ -1708,7 +1695,7 @@ def initialize(event, default_executor)
1708
1695
1709
1696
private
1710
1697
1711
- def on_resolvable ( resolved_future )
1698
+ def on_resolvable ( resolved_future , index )
1712
1699
resolve_with RESOLVED
1713
1700
end
1714
1701
end
@@ -1720,7 +1707,7 @@ def initialize(future, default_executor)
1720
1707
1721
1708
private
1722
1709
1723
- def on_resolvable ( resolved_future )
1710
+ def on_resolvable ( resolved_future , index )
1724
1711
resolve_with resolved_future . internal_state
1725
1712
end
1726
1713
end
@@ -1730,23 +1717,28 @@ class ZipFuturesPromise < BlockedPromise
1730
1717
private
1731
1718
1732
1719
def initialize ( blocked_by_futures , default_executor )
1733
- super ( Future . new ( self , default_executor ) , blocked_by_futures , blocked_by_futures . size )
1720
+ size = blocked_by_futures . size
1721
+ super ( Future . new ( self , default_executor ) , blocked_by_futures , size )
1722
+ @Resolutions = ::Array . new ( size )
1723
+
1724
+ on_resolvable nil , -1 if blocked_by_futures . empty?
1725
+ end
1734
1726
1735
- on_resolvable nil if blocked_by_futures . empty?
1727
+ def process_on_resolution ( future , index )
1728
+ countdown = super future , index
1729
+ # TODO (pitr-ch 18-Dec-2016): Can we assume that array will never break under parallel access when never resized?
1730
+ @Resolutions [ index ] = future . internal_state
1731
+ countdown
1736
1732
end
1737
1733
1738
- def on_resolvable ( resolved_future )
1734
+ def on_resolvable ( resolved_future , index )
1739
1735
all_fulfilled = true
1740
- values = Array . new ( blocked_by . size )
1741
- reasons = Array . new ( blocked_by . size )
1736
+ values = Array . new ( @Resolutions . size )
1737
+ reasons = Array . new ( @Resolutions . size )
1742
1738
1743
- blocked_by . each_with_index do |future , i |
1744
- if future . is_a? ( Future )
1745
- fulfilled , values [ i ] , reasons [ i ] = future . result
1746
- all_fulfilled &&= fulfilled
1747
- else
1748
- values [ i ] = reasons [ i ] = nil
1749
- end
1739
+ @Resolutions . each_with_index do |internal_state , i |
1740
+ fulfilled , values [ i ] , reasons [ i ] = internal_state . result
1741
+ all_fulfilled &&= fulfilled
1750
1742
end
1751
1743
1752
1744
if all_fulfilled
@@ -1764,10 +1756,10 @@ class ZipEventsPromise < BlockedPromise
1764
1756
def initialize ( blocked_by_futures , default_executor )
1765
1757
super ( Event . new ( self , default_executor ) , blocked_by_futures , blocked_by_futures . size )
1766
1758
1767
- on_resolvable nil if blocked_by_futures . empty?
1759
+ on_resolvable nil , - 1 if blocked_by_futures . empty?
1768
1760
end
1769
1761
1770
- def on_resolvable ( resolved_future )
1762
+ def on_resolvable ( resolved_future , index )
1771
1763
resolve_with RESOLVED
1772
1764
end
1773
1765
end
@@ -1784,11 +1776,11 @@ def initialize(blocked_by_futures, default_executor)
1784
1776
super ( Future . new ( self , default_executor ) , blocked_by_futures , blocked_by_futures . size )
1785
1777
end
1786
1778
1787
- def resolvable? ( countdown , future )
1779
+ def resolvable? ( countdown , future , index )
1788
1780
true
1789
1781
end
1790
1782
1791
- def on_resolvable ( resolved_future )
1783
+ def on_resolvable ( resolved_future , index )
1792
1784
resolve_with resolved_future . internal_state , false
1793
1785
end
1794
1786
end
@@ -1801,11 +1793,11 @@ def initialize(blocked_by_futures, default_executor)
1801
1793
super ( Event . new ( self , default_executor ) , blocked_by_futures , blocked_by_futures . size )
1802
1794
end
1803
1795
1804
- def resolvable? ( countdown , future )
1796
+ def resolvable? ( countdown , future , index )
1805
1797
true
1806
1798
end
1807
1799
1808
- def on_resolvable ( resolved_future )
1800
+ def on_resolvable ( resolved_future , index )
1809
1801
resolve_with RESOLVED , false
1810
1802
end
1811
1803
end
@@ -1814,7 +1806,7 @@ class AnyFulfilledFuturePromise < AnyResolvedFuturePromise
1814
1806
1815
1807
private
1816
1808
1817
- def resolvable? ( countdown , future )
1809
+ def resolvable? ( countdown , future , index )
1818
1810
future . fulfilled? ||
1819
1811
# inlined super from BlockedPromise
1820
1812
countdown . zero?
@@ -1887,7 +1879,6 @@ def initialize(default_executor, intended_time)
1887
1879
:RunFuturePromise ,
1888
1880
:ZipEventEventPromise ,
1889
1881
:ZipFutureEventPromise ,
1890
- :ZipFutureFuturePromise ,
1891
1882
:EventWrapperPromise ,
1892
1883
:FutureWrapperPromise ,
1893
1884
:ZipFuturesPromise ,
0 commit comments