diff --git a/src/Win32_QFork.cpp b/src/Win32_QFork.cpp index fa631f32..152cf4c1 100644 --- a/src/Win32_QFork.cpp +++ b/src/Win32_QFork.cpp @@ -582,7 +582,7 @@ BOOL AbortForkOperation() BOOL EndForkOperation() { try { #ifdef _DEBUG - printf("sending termiation signal\n"); + printf("EndForkOperation: sending termination signal\n"); #endif SetEvent(g_pQForkControl->terminateForkedProcess); if( g_hForkedProcess != 0 ) diff --git a/src/networking.c b/src/networking.c index fd73b9f6..e91984e5 100644 --- a/src/networking.c +++ b/src/networking.c @@ -671,8 +671,13 @@ void freeClient(redisClient *c) { * Case 1: we lost the connection with a slave. */ if (c->flags & REDIS_SLAVE) { list *l; - if (c->replstate == REDIS_REPL_SEND_BULK && c->repldbfd != -1) + if (c->replstate == REDIS_REPL_SEND_BULK && c->repldbfd != -1) { close(c->repldbfd); +#ifdef _WIN32 + DeleteFileA(c->replFileCopy); + memset(c->replFileCopy, 0, MAX_PATH); +#endif + } l = (c->flags & REDIS_MONITOR) ? server.monitors : server.slaves; ln = listSearchKey(l,c); redisAssert(ln != NULL); diff --git a/src/redis.h b/src/redis.h index d5f92244..85762658 100644 --- a/src/redis.h +++ b/src/redis.h @@ -411,6 +411,7 @@ typedef struct redisClient { int replstate; /* replication state if this is a slave */ int repldbfd; /* replication DB file descriptor */ #ifdef _WIN32 + char replFileCopy[_MAX_PATH]; long long repldboff; /* replication DB file offset */ long long repldbsize; /* replication DB file size */ #else diff --git a/src/replication.c b/src/replication.c index 02b1f5ca..e183cf15 100644 --- a/src/replication.c +++ b/src/replication.c @@ -243,6 +243,10 @@ void sendBulkToSlaveDataDone(aeEventLoop *el, int fd, void *privdata, int nwritt slave->repldboff += nwritten; if (slave->repldboff == slave->repldbsize) { close(slave->repldbfd); +#ifdef _WIN32 + DeleteFileA(slave->replFileCopy); + memset(slave->replFileCopy, 0, MAX_PATH); +#endif slave->repldbfd = -1; aeDeleteFileEvent(server.el,slave->fd,AE_WRITABLE); slave->replstate = REDIS_REPL_ONLINE; @@ -343,6 +347,10 @@ void sendBulkToSlave(aeEventLoop *el, int fd, void *privdata, int mask) { slave->repldboff += nwritten; if (slave->repldboff == slave->repldbsize) { close(slave->repldbfd); +#ifdef _WIN32 + DeleteFileA(slave->replFileCopy); + memset(slave->replFileCopy, 0, MAX_PATH); +#endif slave->repldbfd = -1; aeDeleteFileEvent(server.el,slave->fd,AE_WRITABLE); slave->replstate = REDIS_REPL_ONLINE; @@ -383,7 +391,20 @@ void updateSlavesWaitingBgsave(int bgsaveerr) { continue; } #ifdef _WIN32 - if ((slave->repldbfd = open(server.rdb_filename,O_RDONLY|_O_BINARY,0)) == -1 || + /* As multiple slaves join asynchronously with the master, the synchronization process can launch multiple + RDB background saves before the first slaves are fully synchronized. This can cause a race condition + for the RDB file produced by the forked process with the RDB file being used to feed the slaves. + I don't think this patch totally eliminates the race condition, but it does eliminate the deadlock + that occurs when the forked process tries to copy the file it produces over the the RDB file being + held open by the slave feeding code. */ + sprintf(slave->replFileCopy,"%d_%s", slave->fd, server.rdb_filename); + if(CopyFileA( server.rdb_filename, slave->replFileCopy, FALSE) == FALSE) { + freeClient(slave); + redisLog(REDIS_WARNING,"Failed to duplicate RDB file. Failing SYNC: %d", GetLastError()); + continue; + } + + if ((slave->repldbfd = open(slave->replFileCopy,O_RDONLY|_O_BINARY,0)) == -1 || #else if ((slave->repldbfd = open(server.rdb_filename,O_RDONLY)) == -1 || #endif