summaryrefslogtreecommitdiff
path: root/src/replication.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/replication.c')
-rw-r--r--src/replication.c26
1 files changed, 26 insertions, 0 deletions
diff --git a/src/replication.c b/src/replication.c
index e6e477896..13938a1f3 100644
--- a/src/replication.c
+++ b/src/replication.c
@@ -1425,12 +1425,38 @@ int cancelReplicationHandshake(void) {
return 1;
}
+/* Mass-unblock clients because something changed in the instance that makes
+ * blocking no longer safe. For example clients blocked in list operations
+ * in an instance which turns from master to slave is unsafe, so this function
+ * is called when a master turns into a slave.
+ *
+ * The semantics is to send an -UNBLOCKED error to the client, disconnecting
+ * it at the same time. */
+void disconnectAllBlockedClients(void) {
+ listNode *ln;
+ listIter li;
+
+ listRewind(server.clients,&li);
+ while((ln = listNext(&li))) {
+ redisClient *c = listNodeValue(ln);
+
+ if (c->flags & REDIS_BLOCKED) {
+ addReplySds(c,sdsnew(
+ "-UNBLOCKED force unblock from blocking operation, "
+ "instance state changed (master -> slave?)\r\n"));
+ unblockClientWaitingData(c);
+ c->flags |= REDIS_CLOSE_AFTER_REPLY;
+ }
+ }
+}
+
/* Set replication to the specified master address and port. */
void replicationSetMaster(char *ip, int port) {
sdsfree(server.masterhost);
server.masterhost = sdsdup(ip);
server.masterport = port;
if (server.master) freeClient(server.master);
+ disconnectAllBlockedClients(); /* Clients blocked in master, now slave. */
disconnectSlaves(); /* Force our slaves to resync with us as well. */
replicationDiscardCachedMaster(); /* Don't try a PSYNC. */
freeReplicationBacklog(); /* Don't allow our chained slaves to PSYNC. */