- l = dictGetEntryVal(de);
- ln = listFirst(l);
- redisAssert(ln != NULL);
- receiver = ln->value;
-
- if (receiver->bstate.target == NULL) {
- /* BRPOP/BLPOP return a multi-bulk with the name
- * of the popped list */
- addReplyMultiBulkLen(receiver,2);
- addReplyBulk(receiver,key);
- addReplyBulk(receiver,ele);
- }
- else {
- /* BRPOPLPUSH */
- robj *dobj = lookupKeyWrite(receiver->db,receiver->bstate.target);
- if (dobj && checkType(receiver,dobj,REDIS_LIST)) return 0;
-
- addReplyBulk(receiver,ele);
-
- if (!handleClientsWaitingListPush(receiver, receiver->bstate.target, ele)) {
- /* Create the list if the key does not exist */
- if (!dobj) {
- dobj = createZiplistObject();
- dbAdd(receiver->db, receiver->bstate.target, dobj);
+ clients = dictGetEntryVal(de);
+ numclients = listLength(clients);
+
+ /* Try to handle the push as long as there are clients waiting for a push.
+ * Note that "numclients" is used because the list of clients waiting for a
+ * push on "key" is deleted by unblockClient() when empty.
+ *
+ * This loop will have more than 1 iteration when there is a BRPOPLPUSH
+ * that cannot push the target list because it does not contain a list. If
+ * this happens, it simply tries the next client waiting for a push. */
+ while (numclients--) {
+ ln = listFirst(clients);
+ redisAssert(ln != NULL);
+ receiver = ln->value;
+ dstkey = receiver->bpop.target;
+
+ /* This should remove the first element of the "clients" list. */
+ unblockClientWaitingData(receiver);
+
+ if (dstkey == NULL) {
+ /* BRPOP/BLPOP */
+ addReplyMultiBulkLen(receiver,2);
+ addReplyBulk(receiver,key);
+ addReplyBulk(receiver,ele);
+ return 1;
+ } else {
+ /* BRPOPLPUSH, note that receiver->db is always equal to c->db. */
+ dstobj = lookupKeyWrite(receiver->db,dstkey);
+ if (dstobj && checkType(receiver,dstobj,REDIS_LIST)) {
+ decrRefCount(dstkey);
+ } else {
+ rpoplpushHandlePush(receiver,dstkey,dstobj,ele);
+ decrRefCount(dstkey);
+ return 1;