41
41
-export ([replay /1 ]).
42
42
43
43
% % for testing and debugging
44
- -export ([eval_listeners /2 ,
44
+ -export ([eval_listeners /3 ,
45
45
state /0 ]).
46
46
47
47
-rabbit_boot_step ({? MODULE ,
@@ -339,7 +339,7 @@ all_coord_members() ->
339
339
Nodes = rabbit_mnesia :cluster_nodes (running ) -- [node ()],
340
340
[{? MODULE , Node } || Node <- [node () | Nodes ]].
341
341
342
- version () -> 1 .
342
+ version () -> 2 .
343
343
344
344
which_module (_ ) ->
345
345
? MODULE .
@@ -349,7 +349,8 @@ init(_Conf) ->
349
349
350
350
-spec apply (map (), command (), state ()) ->
351
351
{state (), term (), ra_machine :effects ()}.
352
- apply (#{index := _Idx } = Meta0 , {_CmdTag , StreamId , #{}} = Cmd ,
352
+ apply (#{index := _Idx , machine_version := MachineVersion } = Meta0 ,
353
+ {_CmdTag , StreamId , #{}} = Cmd ,
353
354
#? MODULE {streams = Streams0 ,
354
355
monitors = Monitors0 } = State0 ) ->
355
356
Stream0 = maps :get (StreamId , Streams0 , undefined ),
@@ -367,10 +368,10 @@ apply(#{index := _Idx} = Meta0, {_CmdTag, StreamId, #{}} = Cmd,
367
368
case Stream1 of
368
369
undefined ->
369
370
return (Meta , State0 #? MODULE {streams = maps :remove (StreamId , Streams0 )},
370
- Reply , inform_listeners_eol (Stream0 ));
371
+ Reply , inform_listeners_eol (MachineVersion , Stream0 ));
371
372
_ ->
372
373
{Stream2 , Effects0 } = evaluate_stream (Meta , Stream1 , []),
373
- {Stream3 , Effects1 } = eval_listeners (Stream2 , Effects0 ),
374
+ {Stream3 , Effects1 } = eval_listeners (MachineVersion , Stream2 , Effects0 ),
374
375
{Stream , Effects2 } = eval_retention (Meta , Stream3 , Effects1 ),
375
376
{Monitors , Effects } = ensure_monitors (Stream , Monitors0 , Effects2 ),
376
377
return (Meta ,
@@ -380,9 +381,10 @@ apply(#{index := _Idx} = Meta0, {_CmdTag, StreamId, #{}} = Cmd,
380
381
Reply ->
381
382
return (Meta , State0 , Reply , [])
382
383
end ;
383
- apply (Meta , {down , Pid , Reason } = Cmd ,
384
+ apply (#{ machine_version : = MachineVersion } = Meta , {down , Pid , Reason } = Cmd ,
384
385
#? MODULE {streams = Streams0 ,
385
- monitors = Monitors0 } = State ) ->
386
+ monitors = Monitors0 ,
387
+ listeners = StateListeners0 } = State ) ->
386
388
387
389
Effects0 = case Reason of
388
390
noconnection ->
@@ -391,7 +393,21 @@ apply(Meta, {down, Pid, Reason} = Cmd,
391
393
[]
392
394
end ,
393
395
case maps :take (Pid , Monitors0 ) of
394
- {{PidStreams , listener }, Monitors } ->
396
+ {{StreamId , listener }, Monitors } when MachineVersion =< 1 ->
397
+ Listeners = case maps :take (StreamId , StateListeners0 ) of
398
+ error ->
399
+ StateListeners0 ;
400
+ {Pids0 , Listeners1 } ->
401
+ case maps :remove (Pid , Pids0 ) of
402
+ Pids when map_size (Pids ) == 0 ->
403
+ Listeners1 ;
404
+ Pids ->
405
+ Listeners1 #{StreamId => Pids }
406
+ end
407
+ end ,
408
+ return (Meta , State #? MODULE {listeners = Listeners ,
409
+ monitors = Monitors }, ok , Effects0 );
410
+ {{PidStreams , listener }, Monitors } when MachineVersion >= 2 ->
395
411
Streams = maps :fold (fun (StreamId , _ , Acc ) ->
396
412
case Acc of
397
413
#{StreamId := Stream = # stream {listeners = Listeners0 }} ->
@@ -426,12 +442,31 @@ apply(Meta, {down, Pid, Reason} = Cmd,
426
442
error ->
427
443
return (Meta , State , ok , Effects0 )
428
444
end ;
429
- apply (Meta , {register_listener , #{pid := Pid ,
430
- node := Node ,
431
- stream_id := StreamId ,
432
- type := Type }},
445
+ apply (#{machine_version := MachineVersion } = Meta ,
446
+ {register_listener , #{pid := Pid ,
447
+ stream_id := StreamId }},
433
448
#? MODULE {streams = Streams ,
434
- monitors = Monitors0 } = State0 ) ->
449
+ monitors = Monitors0 } = State0 ) when MachineVersion =< 1 ->
450
+ case Streams of
451
+ #{StreamId := # stream {listeners = Listeners0 } = Stream0 } ->
452
+ Stream1 = Stream0 # stream {listeners = maps :put (Pid , undefined , Listeners0 )},
453
+ {Stream , Effects } = eval_listeners (MachineVersion , Stream1 , []),
454
+ Monitors = maps :put (Pid , {StreamId , listener }, Monitors0 ),
455
+ return (Meta ,
456
+ State0 #? MODULE {streams = maps :put (StreamId , Stream , Streams ),
457
+ monitors = Monitors }, ok ,
458
+ [{monitor , process , Pid } | Effects ]);
459
+ _ ->
460
+ return (Meta , State0 , stream_not_found , [])
461
+ end ;
462
+
463
+ apply (#{machine_version := MachineVersion } = Meta ,
464
+ {register_listener , #{pid := Pid ,
465
+ node := Node ,
466
+ stream_id := StreamId ,
467
+ type := Type }},
468
+ #? MODULE {streams = Streams ,
469
+ monitors = Monitors0 } = State0 ) when MachineVersion >= 2 ->
435
470
case Streams of
436
471
#{StreamId := # stream {listeners = Listeners0 } = Stream0 } ->
437
472
{LKey , LValue } =
@@ -442,7 +477,7 @@ apply(Meta, {register_listener, #{pid := Pid,
442
477
{{Pid , member }, {Node , undefined }}
443
478
end ,
444
479
Stream1 = Stream0 # stream {listeners = maps :put (LKey , LValue , Listeners0 )},
445
- {Stream , Effects } = eval_listeners (Stream1 , []),
480
+ {Stream , Effects } = eval_listeners (MachineVersion , Stream1 , []),
446
481
{PidStreams , listener } = maps :get (Pid , Monitors0 , {#{}, listener }),
447
482
Monitors = maps :put (Pid , {PidStreams #{StreamId => ok }, listener }, Monitors0 ),
448
483
return (Meta ,
@@ -476,6 +511,12 @@ apply(Meta, {nodeup, Node} = Cmd,
476
511
end , {Streams0 , Effects0 }, Streams0 ),
477
512
return (Meta , State #? MODULE {monitors = Monitors ,
478
513
streams = Streams }, ok , Effects );
514
+ apply (Meta , {machine_version , 1 , 2 }, State = #? MODULE {streams = Streams0 }) ->
515
+ Streams1 = maps :fold (fun (ListPid , LeaderPid , Acc ) ->
516
+ Acc #{{ListPid , leader } => LeaderPid }
517
+ end , #{}, Streams0 ),
518
+ return (Meta , State #? MODULE {streams = Streams1 ,
519
+ listeners = undefined }, ok , []);
479
520
apply (Meta , {machine_version , _From , _To }, State ) ->
480
521
return (Meta , State , ok , []);
481
522
apply (Meta , UnkCmd , State ) ->
@@ -1278,10 +1319,19 @@ update_stream0(#{system_time := _Ts},
1278
1319
update_stream0 (_Meta , _Cmd , undefined ) ->
1279
1320
undefined .
1280
1321
1281
- inform_listeners_eol (# stream {target = deleted ,
1322
+ inform_listeners_eol (MachineVersion , # stream {target = deleted ,
1282
1323
listeners = Listeners ,
1283
1324
queue_ref = QRef
1284
- }) ->
1325
+ }) when MachineVersion =< 1 ->
1326
+ lists :map (fun (Pid ) ->
1327
+ {send_msg , Pid ,
1328
+ {queue_event , QRef , eol },
1329
+ cast }
1330
+ end , maps :keys (Listeners ));
1331
+ inform_listeners_eol (MachineVersion , # stream {target = deleted ,
1332
+ listeners = Listeners ,
1333
+ queue_ref = QRef
1334
+ }) when MachineVersion >= 2 ->
1285
1335
LPidsMap = maps :fold (fun ({P , _ }, _V , Acc ) ->
1286
1336
Acc #{P => ok }
1287
1337
end , #{}, Listeners ),
@@ -1290,12 +1340,35 @@ inform_listeners_eol(#stream{target = deleted,
1290
1340
{queue_event , QRef , eol },
1291
1341
cast }
1292
1342
end , maps :keys (LPidsMap ));
1293
- inform_listeners_eol (_ ) ->
1343
+ inform_listeners_eol (_ , _ ) ->
1294
1344
[].
1295
1345
1296
- eval_listeners (# stream {listeners = Listeners0 ,
1297
- queue_ref = QRef ,
1298
- members = Members } = Stream0 , Effects0 ) ->
1346
+ eval_listeners (MachineVersion , # stream {listeners = Listeners0 ,
1347
+ queue_ref = QRef ,
1348
+ members = Members } = Stream , Effects0 )
1349
+ when MachineVersion =< 1 ->
1350
+ case find_leader (Members ) of
1351
+ {# member {state = {running , _ , LeaderPid }}, _ } ->
1352
+ % % a leader is running, check all listeners to see if any of them
1353
+ % % has not been notified of the current leader pid
1354
+ {Listeners , Effects } =
1355
+ maps :fold (
1356
+ fun (_ , P , Acc ) when P == LeaderPid ->
1357
+ Acc ;
1358
+ (LPid , _ , {L , Acc }) ->
1359
+ {L #{LPid => LeaderPid },
1360
+ [{send_msg , LPid ,
1361
+ {queue_event , QRef ,
1362
+ {stream_leader_change , LeaderPid }},
1363
+ cast } | Acc ]}
1364
+ end , {Listeners0 , Effects0 }, Listeners0 ),
1365
+ {Stream # stream {listeners = Listeners }, Effects };
1366
+ _ ->
1367
+ {Stream , Effects0 }
1368
+ end ;
1369
+ eval_listeners (MachineVersion , # stream {listeners = Listeners0 ,
1370
+ queue_ref = QRef ,
1371
+ members = Members } = Stream0 , Effects0 ) when MachineVersion >= 2 ->
1299
1372
% % Iterating over stream listeners.
1300
1373
% % Returning the new map of listeners and the effects (notification of changes)
1301
1374
{Listeners1 , Effects1 } =
0 commit comments