@@ -1986,7 +1986,7 @@ defmodule GenStage do
1986
1986
type: :producer_consumer ,
1987
1987
buffer: { :queue . new ( ) , 0 , init_wheel ( buffer_size ) } ,
1988
1988
buffer_config: { buffer_size , buffer_keep } ,
1989
- events: 0 ,
1989
+ events: { :queue . new ( ) , 0 } ,
1990
1990
dispatcher_mod: dispatcher_mod ,
1991
1991
dispatcher_state: dispatcher_state
1992
1992
}
@@ -2200,17 +2200,11 @@ defmodule GenStage do
2200
2200
2201
2201
def handle_info (
2202
2202
{ :"$gen_consumer" , { producer_pid , ref } , events } ,
2203
- % { type: :producer_consumer , events: demand_or_queue , producers: producers } = stage
2203
+ % { type: :producer_consumer , events: { queue , counter } , producers: producers } = stage
2204
2204
)
2205
2205
when is_list ( events ) do
2206
2206
case producers do
2207
2207
% { ^ ref => _entry } ->
2208
- { counter , queue } =
2209
- case demand_or_queue do
2210
- demand when is_integer ( demand ) -> { demand , :queue . new ( ) }
2211
- queue -> { 0 , queue }
2212
- end
2213
-
2214
2208
queue = put_pc_events ( events , ref , queue )
2215
2209
take_pc_events ( queue , counter , stage )
2216
2210
@@ -2229,8 +2223,7 @@ defmodule GenStage do
2229
2223
case producers do
2230
2224
% { ^ ref => entry } ->
2231
2225
{ batches , stage } = consumer_receive ( from , entry , events , stage )
2232
- { _ , reply } = consumer_dispatch ( batches , from , mod , state , stage , 0 , false )
2233
- reply
2226
+ consumer_dispatch ( batches , from , mod , state , stage , false )
2234
2227
2235
2228
_ ->
2236
2229
msg = { :"$gen_producer" , { self ( ) , ref } , { :cancel , :unknown_subscription } }
@@ -2489,27 +2482,25 @@ defmodule GenStage do
2489
2482
2490
2483
defp dispatcher_callback ( callback , args , % { dispatcher_mod: dispatcher_mod } = stage ) do
2491
2484
{ :ok , counter , dispatcher_state } = apply ( dispatcher_mod , callback , args )
2492
- stage = % { stage | dispatcher_state: dispatcher_state }
2493
2485
2494
- case take_from_buffer ( counter , stage ) do
2495
- { :ok , 0 , stage } ->
2496
- { :noreply , stage }
2486
+ case stage do
2487
+ % { type: :producer_consumer , events: { queue , demand } } ->
2488
+ counter = demand + counter
2489
+ stage = % { stage | dispatcher_state: dispatcher_state , events: { queue , counter } }
2490
+ { :ok , _ , stage } = take_from_buffer ( counter , stage )
2491
+ % { events: { queue , counter } } = stage
2492
+ take_pc_events ( queue , counter , stage )
2497
2493
2498
- { :ok , counter , stage } when is_integer ( counter ) and counter > 0 ->
2499
- case stage do
2500
- # producer
2501
- % { events: :forward , state: state } ->
2494
+ % { } ->
2495
+ case take_from_buffer ( counter , % { stage | dispatcher_state: dispatcher_state } ) do
2496
+ { :ok , 0 , stage } ->
2497
+ { :noreply , stage }
2498
+
2499
+ { :ok , counter , % { events: :forward , state: state } = stage } ->
2502
2500
noreply_callback ( :handle_demand , [ counter , state ] , stage )
2503
2501
2504
- % { events: events } when is_list ( events ) ->
2502
+ { :ok , counter , % { events: events } = stage } when is_list ( events ) ->
2505
2503
{ :noreply , % { stage | events: [ counter | events ] } }
2506
-
2507
- # producer_consumer
2508
- % { events: events } when is_integer ( events ) ->
2509
- { :noreply , % { stage | events: counter + events } }
2510
-
2511
- % { events: queue } ->
2512
- take_pc_events ( queue , counter , stage )
2513
2504
end
2514
2505
end
2515
2506
end
@@ -2534,7 +2525,24 @@ defmodule GenStage do
2534
2525
defp dispatch_events ( events , length , stage ) do
2535
2526
% { dispatcher_mod: dispatcher_mod , dispatcher_state: dispatcher_state } = stage
2536
2527
{ :ok , events , dispatcher_state } = dispatcher_mod . dispatch ( events , length , dispatcher_state )
2537
- buffer_events ( events , % { stage | dispatcher_state: dispatcher_state } )
2528
+
2529
+ stage =
2530
+ case stage do
2531
+ % { type: :producer_consumer , events: { queue , demand } } ->
2532
+ if demand < length - length ( events ) do
2533
+ IO . puts ( Exception . format_stacktrace ( ) )
2534
+ IO . inspect ( { demand , length , length ( events ) } )
2535
+ end
2536
+
2537
+ demand = demand - ( length - length ( events ) )
2538
+
2539
+ % { stage | dispatcher_state: dispatcher_state , events: { queue , max ( demand , 0 ) } }
2540
+
2541
+ % { } ->
2542
+ % { stage | dispatcher_state: dispatcher_state }
2543
+ end
2544
+
2545
+ buffer_events ( events , stage )
2538
2546
end
2539
2547
2540
2548
defp take_from_buffer ( counter , % { buffer: { _ , buffer , _ } } = stage )
@@ -2669,14 +2677,12 @@ defmodule GenStage do
2669
2677
{ :reply , :ok , stage }
2670
2678
end
2671
2679
2672
- defp producer_info ( msg , % { type: :producer_consumer , events: demand_or_queue } = stage ) do
2680
+ defp producer_info ( msg , % { type: :producer_consumer , events: { queue , demand } } = stage ) do
2673
2681
stage =
2674
- case demand_or_queue do
2675
- demand when is_integer ( demand ) ->
2676
- buffer_or_dispatch_info ( msg , stage )
2677
-
2678
- queue ->
2679
- % { stage | events: :queue . in ( { :info , msg } , queue ) }
2682
+ if :queue . is_empty ( queue ) do
2683
+ buffer_or_dispatch_info ( msg , stage )
2684
+ else
2685
+ % { stage | events: { :queue . in ( { :info , msg } , queue ) , demand } }
2680
2686
end
2681
2687
2682
2688
{ :reply , :ok , stage }
@@ -2798,32 +2804,32 @@ defmodule GenStage do
2798
2804
defp split_events ( [ event | events ] , limit , counter , acc ) ,
2799
2805
do: split_events ( events , limit , counter + 1 , [ event | acc ] )
2800
2806
2801
- defp consumer_dispatch ( [ { batch , ask } | batches ] , from , mod , state , stage , count , _hibernate? ) do
2807
+ defp consumer_dispatch ( [ { batch , ask } | batches ] , from , mod , state , stage , _hibernate? ) do
2802
2808
case mod . handle_events ( batch , from , state ) do
2803
2809
{ :noreply , events , state } when is_list ( events ) ->
2804
2810
stage = dispatch_events ( events , length ( events ) , stage )
2805
2811
ask ( from , ask , [ :noconnect ] )
2806
- consumer_dispatch ( batches , from , mod , state , stage , count + length ( events ) , false )
2812
+ consumer_dispatch ( batches , from , mod , state , stage , false )
2807
2813
2808
2814
{ :noreply , events , state , :hibernate } when is_list ( events ) ->
2809
2815
stage = dispatch_events ( events , length ( events ) , stage )
2810
2816
ask ( from , ask , [ :noconnect ] )
2811
- consumer_dispatch ( batches , from , mod , state , stage , count + length ( events ) , true )
2817
+ consumer_dispatch ( batches , from , mod , state , stage , true )
2812
2818
2813
2819
{ :stop , reason , state } ->
2814
- { count , { :stop , reason , % { stage | state: state } } }
2820
+ { :stop , reason , % { stage | state: state } }
2815
2821
2816
2822
other ->
2817
- { count , { :stop , { :bad_return_value , other } , % { stage | state: state } } }
2823
+ { :stop , { :bad_return_value , other } , % { stage | state: state } }
2818
2824
end
2819
2825
end
2820
2826
2821
- defp consumer_dispatch ( [ ] , _from , _mod , state , stage , count , false ) do
2822
- { count , { :noreply , % { stage | state: state } } }
2827
+ defp consumer_dispatch ( [ ] , _from , _mod , state , stage , false ) do
2828
+ { :noreply , % { stage | state: state } }
2823
2829
end
2824
2830
2825
- defp consumer_dispatch ( [ ] , _from , _mod , state , stage , count , true ) do
2826
- { count , { :noreply , % { stage | state: state } , :hibernate } }
2831
+ defp consumer_dispatch ( [ ] , _from , _mod , state , stage , true ) do
2832
+ { :noreply , % { stage | state: state } , :hibernate }
2827
2833
end
2828
2834
2829
2835
defp consumer_subscribe ( { to , opts } , stage ) when is_list ( opts ) ,
@@ -2903,14 +2909,13 @@ defmodule GenStage do
2903
2909
mode ,
2904
2910
kind_reason ,
2905
2911
pid_ref ,
2906
- % { type: :producer_consumer , events: demand_or_queue } = stage
2912
+ % { type: :producer_consumer , events: { queue , demand } } = stage
2907
2913
) do
2908
- case demand_or_queue do
2909
- demand when is_integer ( demand ) ->
2910
- invoke_cancel ( mode , kind_reason , pid_ref , stage )
2911
-
2912
- queue ->
2913
- { :noreply , % { stage | events: :queue . in ( { :cancel , mode , kind_reason , pid_ref } , queue ) } }
2914
+ if :queue . is_empty ( queue ) do
2915
+ invoke_cancel ( mode , kind_reason , pid_ref , stage )
2916
+ else
2917
+ queue = :queue . in ( { :cancel , mode , kind_reason , pid_ref } , queue )
2918
+ { :noreply , % { stage | events: { queue , demand } } }
2914
2919
end
2915
2920
end
2916
2921
@@ -2946,11 +2951,11 @@ defmodule GenStage do
2946
2951
{ producer_id , _ , _ } = entry
2947
2952
from = { producer_id , ref }
2948
2953
{ batches , stage } = consumer_receive ( from , entry , events , stage )
2949
- consumer_dispatch ( batches , from , mod , state , stage , 0 , false )
2954
+ consumer_dispatch ( batches , from , mod , state , stage , false )
2950
2955
2951
2956
% { } ->
2952
2957
# We queued but producer was removed
2953
- consumer_dispatch ( [ { events , 0 } ] , { :pid , ref } , mod , state , stage , 0 , false )
2958
+ consumer_dispatch ( [ { events , 0 } ] , { :pid , ref } , mod , state , stage , false )
2954
2959
end
2955
2960
end
2956
2961
@@ -2972,27 +2977,27 @@ defmodule GenStage do
2972
2977
end
2973
2978
2974
2979
{ { :value , { events , ref } } , queue } ->
2975
- case send_pc_events ( events , ref , stage ) do
2976
- { sent , { :noreply , stage } } ->
2977
- take_pc_events ( queue , counter - sent , stage )
2980
+ case send_pc_events ( events , ref , % { stage | events: { queue , counter } } ) do
2981
+ { :noreply , % { events: { queue , counter } } = stage } ->
2982
+ take_pc_events ( queue , counter , stage )
2978
2983
2979
- { sent , { :noreply , stage , :hibernate } } ->
2980
- take_pc_events ( queue , counter - sent , stage )
2984
+ { :noreply , % { events: { queue , counter } } = stage , :hibernate } ->
2985
+ take_pc_events ( queue , counter , stage )
2981
2986
2982
- { _ , { :stop , _ , _ } = stop } ->
2987
+ { :stop , _ , _ } = stop ->
2983
2988
stop
2984
2989
end
2985
2990
2986
- { :empty , _queue } ->
2987
- { :noreply , % { stage | events: counter } }
2991
+ { :empty , queue } ->
2992
+ { :noreply , % { stage | events: { queue , counter } } }
2988
2993
end
2989
2994
end
2990
2995
2991
2996
# It is OK to send more events than the consumer has
2992
- # asked because those will always be buffered. Once
2993
- # we have taken from the buffer, the event queue will
2997
+ # asked (counter < 0) because those will always be buffered.
2998
+ # Once we have taken from the buffer, the event queue will
2994
2999
# be adjusted again.
2995
- defp take_pc_events ( queue , _counter , stage ) do
2996
- { :noreply , % { stage | events: queue } }
3000
+ defp take_pc_events ( queue , counter , stage ) do
3001
+ { :noreply , % { stage | events: { queue , counter } } }
2997
3002
end
2998
3003
end
0 commit comments