workaround for deadlocking on RDB file copy during multiple master/slave synchronizations
This commit is contained in:
+1
-1
@@ -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 )
|
||||
|
||||
+6
-1
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
+22
-1
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user