diff --git a/src/replication.c b/src/replication.c index e71b269d8..8a05b9696 100644 --- a/src/replication.c +++ b/src/replication.c @@ -79,6 +79,34 @@ char *replicationGetSlaveName(client *c) { return buf; } +/* Plain unlink() can block for quite some time in order to actually apply + * the file deletion to the filesystem. This call removes the file in a + * background thread instead. We actually just do close() in the thread, + * by using the fact that if there is another instance of the same file open, + * the foreground unlink() will not really do anything, and deleting the + * file will only happen once the last reference is lost. */ +int bg_unlink(const char *filename) { + int fd = open(filename,O_RDONLY|O_NONBLOCK); + if (fd == -1) { + /* Can't open the file? Fall back to unlinking in the main thread. */ + return unlink(filename); + } else { + /* The following unlink() will not do anything since file + * is still open. */ + int retval = unlink(filename); + if (retval == -1) { + /* If we got an unlink error, we just return it, closing the + * new reference we have to the file. */ + int old_errno = errno; + close(fd); /* This would overwrite our errno. So we saved it. */ + errno = old_errno; + return -1; + } + bioCreateBackgroundJob(BIO_CLOSE_FILE,(void*)(long)fd,NULL,NULL); + return 0; /* Success. */ + } +} + /* ---------------------------------- MASTER -------------------------------- */ void createReplicationBacklog(void) { @@ -917,7 +945,7 @@ void removeRDBUsedToSyncReplicas(void) { } if (delrdb) { RDBGeneratedByReplication = 0; - unlink(server.rdb_filename); + bg_unlink(server.rdb_filename); } } } @@ -1679,14 +1707,14 @@ void readSyncBulkPayload(connection *conn) { "Failed trying to load the MASTER synchronization " "DB from disk"); cancelReplicationHandshake(); - if (allPersistenceDisabled()) unlink(server.rdb_filename); + if (allPersistenceDisabled()) bg_unlink(server.rdb_filename); /* Note that there's no point in restarting the AOF on sync failure, it'll be restarted when sync succeeds or replica promoted. */ return; } /* Cleanup. */ - if (allPersistenceDisabled()) unlink(server.rdb_filename); + if (allPersistenceDisabled()) bg_unlink(server.rdb_filename); zfree(server.repl_transfer_tmpfile); close(server.repl_transfer_fd); server.repl_transfer_fd = -1;