From a3a684d2c9bd7f113ae822b25c4c2730c9f12749 Mon Sep 17 00:00:00 2001
From: Mark McLoughlin <markmc@redhat.com>
Date: Fri, 2 Aug 2013 07:25:45 +0100
Subject: [PATCH] Fix race condition in ReplyWaiters.wake_all()

While we're iterating over the queues in ReplyWaiters.wake_all(), new
queues can be registered and we get:

  RuntimeError: dictionary changed size during iteration

Instead of using an iterator, take a snapshot list of message IDs and
operate on that.

We don't actually care about any new queues added after wake_all() is
called because the connection lock has already been dropped so one of
the other waiters must have picked it up.

We also don't need to worry about queues being removed - if we write to
a removed queue, that's not going to be a problem.

Change-Id: Ib572cbfd3a7346b76579f82b64aa85a03c1a4fb2
---
 oslo/messaging/_drivers/amqpdriver.py | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/oslo/messaging/_drivers/amqpdriver.py b/oslo/messaging/_drivers/amqpdriver.py
index 6cd35bb03..b68ae3e56 100644
--- a/oslo/messaging/_drivers/amqpdriver.py
+++ b/oslo/messaging/_drivers/amqpdriver.py
@@ -119,9 +119,8 @@ class ReplyWaiters(object):
             queue.put(message_data)
 
     def wake_all(self, except_id):
-        for msg_id in self._queues:
-            if msg_id == except_id:
-                continue
+        msg_ids = [i for i in self._queues if i != except_id]
+        for msg_id in msg_ids:
             self.put(msg_id, None)
 
     def add(self, msg_id, queue):