summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Sackman <matthew@rabbitmq.com>2011-05-17 16:40:01 +0100
committerMatthew Sackman <matthew@rabbitmq.com>2011-05-17 16:40:01 +0100
commit7d783d1765e6c41c4d9377c8d321762ec86b3287 (patch)
treea165fed99d21531d16b8df2157df754387818ace
parent4dc16a43667afffc75a183bde8f67ecd5f56d9a5 (diff)
downloadrabbitmq-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.erl24
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).