@@ -33,9 +33,11 @@ defmodule GenStage.BroadcastDispatcher do
33
33
34
34
@ behaviour GenStage.Dispatcher
35
35
36
+ require Logger
37
+
36
38
@ doc false
37
39
def init ( _opts ) do
38
- { :ok , { [ ] , 0 } }
40
+ { :ok , { [ ] , 0 , MapSet . new ( ) } }
39
41
end
40
42
41
43
@ doc false
@@ -45,36 +47,48 @@ defmodule GenStage.BroadcastDispatcher do
45
47
end
46
48
47
49
@ doc false
48
- def subscribe ( opts , { pid , ref } , { demands , waiting } ) do
50
+ def subscribe ( opts , { pid , ref } , { demands , waiting , subscribed_processes } ) do
49
51
selector = validate_selector ( opts )
50
- { :ok , 0 , { add_demand ( - waiting , pid , ref , selector , demands ) , waiting } }
52
+
53
+ if subscribed? ( subscribed_processes , pid ) do
54
+ Logger . error ( fn ->
55
+ "#{ inspect ( pid ) } is already registered with #{ inspect ( self ( ) ) } . " <>
56
+ "This subscription has been discared."
57
+ end )
58
+
59
+ { :error , :already_subscribed }
60
+ else
61
+ subscribed_processes = add_subscriber ( subscribed_processes , pid )
62
+ { :ok , 0 , { add_demand ( - waiting , pid , ref , selector , demands ) , waiting , subscribed_processes } }
63
+ end
51
64
end
52
65
53
66
@ doc false
54
- def cancel ( { _ , ref } , { demands , waiting } ) do
67
+ def cancel ( { pid , ref } , { demands , waiting , subscribed_processes } ) do
55
68
# Since we may have removed the process we were waiting on,
56
69
# cancellation may actually generate demand!
57
70
demands = delete_demand ( ref , demands )
58
71
new_min = get_min ( demands )
59
72
demands = adjust_demand ( new_min , demands )
60
- { :ok , new_min , { demands , waiting + new_min } }
73
+ subscribed_processes = delete_subscriber ( subscribed_processes , pid )
74
+ { :ok , new_min , { demands , waiting + new_min , subscribed_processes } }
61
75
end
62
76
63
77
@ doc false
64
- def ask ( counter , { pid , ref } , { demands , waiting } ) do
78
+ def ask ( counter , { pid , ref } , { demands , waiting , subscribed_processes } ) do
65
79
{ current , selector , demands } = pop_demand ( ref , demands )
66
80
demands = add_demand ( current + counter , pid , ref , selector , demands )
67
81
new_min = get_min ( demands )
68
82
demands = adjust_demand ( new_min , demands )
69
- { :ok , new_min , { demands , waiting + new_min } }
83
+ { :ok , new_min , { demands , waiting + new_min , subscribed_processes } }
70
84
end
71
85
72
86
@ doc false
73
- def dispatch ( events , _length , { demands , 0 } ) do
74
- { :ok , events , { demands , 0 } }
87
+ def dispatch ( events , _length , { demands , 0 , subscribed_processes } ) do
88
+ { :ok , events , { demands , 0 , subscribed_processes } }
75
89
end
76
90
77
- def dispatch ( events , length , { demands , waiting } ) do
91
+ def dispatch ( events , length , { demands , waiting , subscribed_processes } ) do
78
92
{ deliver_now , deliver_later , waiting } = split_events ( events , length , waiting )
79
93
80
94
for { _ , pid , ref , selector } <- demands do
@@ -92,7 +106,7 @@ defmodule GenStage.BroadcastDispatcher do
92
106
:ok
93
107
end
94
108
95
- { :ok , deliver_later , { demands , waiting } }
109
+ { :ok , deliver_later , { demands , waiting , subscribed_processes } }
96
110
end
97
111
98
112
defp filter_and_count ( messages , nil ) do
@@ -168,4 +182,16 @@ defmodule GenStage.BroadcastDispatcher do
168
182
defp delete_demand ( ref , demands ) do
169
183
List . keydelete ( demands , ref , 2 )
170
184
end
185
+
186
+ defp add_subscriber ( subscribed_processes , pid ) do
187
+ MapSet . put ( subscribed_processes , pid )
188
+ end
189
+
190
+ defp delete_subscriber ( subscribed_processes , pid ) do
191
+ MapSet . delete ( subscribed_processes , pid )
192
+ end
193
+
194
+ defp subscribed? ( subscribed_processes , pid ) do
195
+ MapSet . member? ( subscribed_processes , pid )
196
+ end
171
197
end
0 commit comments