diff --git a/src/networking.c b/src/networking.c index a1948ce60..364654642 100644 --- a/src/networking.c +++ b/src/networking.c @@ -1037,14 +1037,25 @@ static void freeClientArgv(client *c) { /* Close all the slaves connections. This is useful in chained replication * when we resync with our own master and want to force all our slaves to - * resync with us as well. */ -void disconnectSlaves(void) { + * resync with us as well. + * + * If 'async' is non-zero we free the clients asynchronously. This is needed + * when we call this function from a context where in the chain of the + * callers somebody is iterating the list of clients. For instance when + * CLIENT KILL TYPE master is called, caching the master client may + * adjust the meaningful offset of replication, and in turn call + * discionectSlaves(). Since CLIENT KILL iterates the clients this is + * not safe. */ +void disconnectSlaves(int async) { listIter li; listNode *ln; listRewind(server.slaves,&li); while((ln = listNext(&li))) { listNode *ln = listFirst(server.slaves); - freeClientAsync((client*)ln->value); + if (async) + freeClientAsync((client*)ln->value); + else + freeClient((client*)ln->value); } } diff --git a/src/replication.c b/src/replication.c index 77422344a..e1c65d48b 100644 --- a/src/replication.c +++ b/src/replication.c @@ -2076,7 +2076,7 @@ int slaveTryPartialResynchronization(connection *conn, int read_reply) { memcpy(server.cached_master->replid,new,sizeof(server.replid)); /* Disconnect all the sub-slaves: they need to be notified. */ - disconnectSlaves(); + disconnectSlaves(0); } } @@ -2349,7 +2349,7 @@ void syncWithMaster(connection *conn) { * as well, if we have any sub-slaves. The master may transfer us an * entirely different data set and we have no way to incrementally feed * our slaves after that. */ - disconnectSlaves(); /* Force our slaves to resync with us as well. */ + disconnectSlaves(0); /* Force our slaves to resync with us as well. */ freeReplicationBacklog(); /* Don't allow our chained slaves to PSYNC. */ /* Fall back to SYNC if needed. Otherwise psync_result == PSYNC_FULLRESYNC @@ -2496,7 +2496,7 @@ void replicationSetMaster(char *ip, int port) { /* Force our slaves to resync with us as well. They may hopefully be able * to partially resync with us, but we can notify the replid change. */ - disconnectSlaves(); + disconnectSlaves(0); cancelReplicationHandshake(); /* Before destroying our master state, create a cached master using * our own parameters, to later PSYNC with the new master. */ @@ -2543,7 +2543,7 @@ void replicationUnsetMaster(void) { * of the replication ID change (see shiftReplicationId() call). However * the slaves will be able to partially resync with us, so it will be * a very fast reconnection. */ - disconnectSlaves(); + disconnectSlaves(0); server.repl_state = REPL_STATE_NONE; /* We need to make sure the new master will start the replication stream @@ -2778,7 +2778,7 @@ void replicationCacheMaster(client *c) { * from the stream and their offset would no longer match: upon * disconnection they will also trim the final PINGs and will be able * to incrementally sync without issues. */ - if (offset_adjusted) disconnectSlaves(); + if (offset_adjusted) disconnectSlaves(1); } /* If the "meaningful" offset, that is the offset without the final PINGs diff --git a/src/server.h b/src/server.h index f835bf5e9..2d17d69c8 100644 --- a/src/server.h +++ b/src/server.h @@ -1660,7 +1660,7 @@ int getClientType(client *c); int getClientTypeByName(char *name); char *getClientTypeName(int class); void flushSlavesOutputBuffers(void); -void disconnectSlaves(void); +void disconnectSlaves(int async); int listenToPort(int port, int *fds, int *count); void pauseClients(mstime_t duration); int clientsArePaused(void);