diff options
| author | Matthew Sackman <matthew@rabbitmq.com> | 2011-05-17 16:40:01 +0100 |
|---|---|---|
| committer | Matthew Sackman <matthew@rabbitmq.com> | 2011-05-17 16:40:01 +0100 |
| commit | 7d783d1765e6c41c4d9377c8d321762ec86b3287 (patch) | |
| tree | a165fed99d21531d16b8df2157df754387818ace | |
| parent | 4dc16a43667afffc75a183bde8f67ecd5f56d9a5 (diff) | |
| download | rabbitmq-server-git-7d783d1765e6c41c4d9377c8d321762ec86b3287.tar.gz | |
Eliminate a race which was found to allow promotion to be non-atomic
| -rw-r--r-- | src/rabbit_mirror_queue_misc.erl | 24 |
1 files changed, 19 insertions, 5 deletions
diff --git a/src/rabbit_mirror_queue_misc.erl b/src/rabbit_mirror_queue_misc.erl index bf341c74e8..5f180c5eae 100644 --- a/src/rabbit_mirror_queue_misc.erl +++ b/src/rabbit_mirror_queue_misc.erl @@ -20,6 +20,11 @@ -include("rabbit.hrl"). +%% If the dead pids include the queue pid (i.e. the master has died) +%% then only remove that if we are about to be promoted. Otherwise we +%% can have the situation where a slave updates the mnesia record for +%% a queue, promoting another slave before that slave realises it has +%% become the new master. remove_from_queue(QueueName, DeadPids) -> DeadNodes = [node(DeadPid) || DeadPid <- DeadPids], rabbit_misc:execute_mnesia_transaction( @@ -35,13 +40,22 @@ remove_from_queue(QueueName, DeadPids) -> not lists:member(node(Pid), DeadNodes)], case {{QPid, MPids}, {QPid1, MPids1}} of {Same, Same} -> - {ok, QPid}; - _ -> + ok; + _ when QPid =:= QPid1 orelse node(QPid1) =:= node() -> + %% Either master hasn't changed, so + %% we're ok to update mnesia; or master + %% has changed to become us! Q1 = Q #amqqueue { pid = QPid1, mirror_pids = MPids1 }, - ok = rabbit_amqqueue:store_queue(Q1), - {ok, QPid1} - end + ok = rabbit_amqqueue:store_queue(Q1); + _ -> + %% Master has changed, and we're not it, + %% so leave alone to allow the promoted + %% slave to find it and make its + %% promotion atomic. + ok + end, + {ok, QPid1} end end). |
