diff --git a/src/aof.c b/src/aof.c index 2accc781e..928e1c4d1 100644 --- a/src/aof.c +++ b/src/aof.c @@ -213,22 +213,20 @@ void aof_background_fsync(int fd) { void killAppendOnlyChild(void) { int statloc; /* No AOFRW child? return. */ - if (server.aof_child_pid == -1) return; + if (server.child_type != CHILD_TYPE_AOF) return; /* Kill AOFRW child, wait for child exit. */ serverLog(LL_NOTICE,"Killing running AOF rewrite child: %ld", - (long) server.aof_child_pid); - if (kill(server.aof_child_pid,SIGUSR1) != -1) { - while(wait3(&statloc,0,NULL) != server.aof_child_pid); + (long) server.child_pid); + if (kill(server.child_pid,SIGUSR1) != -1) { + while(wait3(&statloc,0,NULL) != server.child_pid); } /* Reset the buffer accumulating changes while the child saves. */ aofRewriteBufferReset(); - aofRemoveTempFile(server.aof_child_pid); - server.aof_child_pid = -1; + aofRemoveTempFile(server.child_pid); + resetChildState(); server.aof_rewrite_time_start = -1; /* Close pipes used for IPC between the two processes. */ aofClosePipes(); - closeChildInfoPipe(); - updateDictResizePolicy(); } /* Called when the user switches from "appendonly yes" to "appendonly no" @@ -265,14 +263,14 @@ int startAppendOnly(void) { strerror(errno)); return C_ERR; } - if (hasActiveChildProcess() && server.aof_child_pid == -1) { + if (hasActiveChildProcess() && server.child_type != CHILD_TYPE_AOF) { server.aof_rewrite_scheduled = 1; serverLog(LL_WARNING,"AOF was enabled but there is already another background operation. An AOF background was scheduled to start when possible."); } else { /* If there is a pending AOF rewrite, we need to switch it off and * start a new one: the old one cannot be reused because it is not * accumulating the AOF buffer. */ - if (server.aof_child_pid != -1) { + if (server.child_type == CHILD_TYPE_AOF) { serverLog(LL_WARNING,"AOF was enabled but there is already an AOF rewriting in background. Stopping background AOF and starting a rewrite now."); killAppendOnlyChild(); } @@ -646,7 +644,7 @@ void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int a * accumulate the differences between the child DB and the current one * in a buffer, so that when the child process will do its work we * can append the differences to the new append only file. */ - if (server.aof_child_pid != -1) + if (server.child_type == CHILD_TYPE_AOF) aofRewriteBufferAppend((unsigned char*)buf,sdslen(buf)); sdsfree(buf); @@ -1703,7 +1701,6 @@ int rewriteAppendOnlyFileBackground(void) { if (hasActiveChildProcess()) return C_ERR; if (aofCreatePipes() != C_OK) return C_ERR; - openChildInfoPipe(); if ((childpid = redisFork(CHILD_TYPE_AOF)) == 0) { char tmpfile[256]; @@ -1720,7 +1717,6 @@ int rewriteAppendOnlyFileBackground(void) { } else { /* Parent */ if (childpid == -1) { - closeChildInfoPipe(); serverLog(LL_WARNING, "Can't rewrite append only file in background: fork: %s", strerror(errno)); @@ -1731,8 +1727,7 @@ int rewriteAppendOnlyFileBackground(void) { "Background append only file rewriting started by pid %ld",(long) childpid); server.aof_rewrite_scheduled = 0; server.aof_rewrite_time_start = time(NULL); - server.aof_child_pid = childpid; - updateDictResizePolicy(); + /* We set appendseldb to -1 in order to force the next call to the * feedAppendOnlyFile() to issue a SELECT command, so the differences * accumulated by the parent into server.aof_rewrite_buf will start @@ -1745,7 +1740,7 @@ int rewriteAppendOnlyFileBackground(void) { } void bgrewriteaofCommand(client *c) { - if (server.aof_child_pid != -1) { + if (server.child_type == CHILD_TYPE_AOF) { addReplyError(c,"Background append only file rewriting already in progress"); } else if (hasActiveChildProcess()) { server.aof_rewrite_scheduled = 1; @@ -1803,7 +1798,7 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) { * rewritten AOF. */ latencyStartMonitor(latency); snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof", - (int)server.aof_child_pid); + (int)server.child_pid); newfd = open(tmpfile,O_WRONLY|O_APPEND); if (newfd == -1) { serverLog(LL_WARNING, @@ -1931,8 +1926,7 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) { cleanup: aofClosePipes(); aofRewriteBufferReset(); - aofRemoveTempFile(server.aof_child_pid); - server.aof_child_pid = -1; + aofRemoveTempFile(server.child_pid); server.aof_rewrite_time_last = time(NULL)-server.aof_rewrite_time_start; server.aof_rewrite_time_start = -1; /* Schedule a new rewrite if we are waiting for it to switch the AOF ON. */ diff --git a/src/db.c b/src/db.c index 62ffda101..c4b48fb0e 100644 --- a/src/db.c +++ b/src/db.c @@ -617,7 +617,7 @@ int getFlushCommandFlags(client *c, int *flags) { /* Flushes the whole server data set. */ void flushAllDataAndResetRDB(int flags) { server.dirty += emptyDb(-1,flags,NULL); - if (server.rdb_child_pid != -1) killRDBChild(); + if (server.child_type == CHILD_TYPE_RDB) killRDBChild(); if (server.saveparamslen > 0) { /* Normally rdbSave() will reset dirty, but we don't want this here * as otherwise FLUSHALL will not be replicated nor put into the AOF. */ diff --git a/src/module.c b/src/module.c index 56ff63869..2de6bee2f 100644 --- a/src/module.c +++ b/src/module.c @@ -7065,23 +7065,16 @@ int RM_ScanKey(RedisModuleKey *key, RedisModuleScanCursor *cursor, RedisModuleSc */ int RM_Fork(RedisModuleForkDoneHandler cb, void *user_data) { pid_t childpid; - if (hasActiveChildProcess()) { - return -1; - } - openChildInfoPipe(); if ((childpid = redisFork(CHILD_TYPE_MODULE)) == 0) { /* Child */ redisSetProcTitle("redis-module-fork"); } else if (childpid == -1) { - closeChildInfoPipe(); serverLog(LL_WARNING,"Can't fork for module: %s", strerror(errno)); } else { /* Parent */ - server.module_child_pid = childpid; moduleForkInfo.done_handler = cb; moduleForkInfo.done_handler_user_data = user_data; - updateDictResizePolicy(); serverLog(LL_VERBOSE, "Module fork started pid: %ld ", (long) childpid); } return childpid; @@ -7101,22 +7094,20 @@ int RM_ExitFromChild(int retcode) { * child or the pid does not match, return C_ERR without doing anything. */ int TerminateModuleForkChild(int child_pid, int wait) { /* Module child should be active and pid should match. */ - if (server.module_child_pid == -1 || - server.module_child_pid != child_pid) return C_ERR; + if (server.child_type != CHILD_TYPE_MODULE || + server.child_pid != child_pid) return C_ERR; int statloc; serverLog(LL_VERBOSE,"Killing running module fork child: %ld", - (long) server.module_child_pid); - if (kill(server.module_child_pid,SIGUSR1) != -1 && wait) { - while(wait4(server.module_child_pid,&statloc,0,NULL) != - server.module_child_pid); + (long) server.child_pid); + if (kill(server.child_pid,SIGUSR1) != -1 && wait) { + while(wait4(server.child_pid,&statloc,0,NULL) != + server.child_pid); } /* Reset the buffer accumulating changes while the child saves. */ - server.module_child_pid = -1; + resetChildState(); moduleForkInfo.done_handler = NULL; moduleForkInfo.done_handler_user_data = NULL; - closeChildInfoPipe(); - updateDictResizePolicy(); return C_OK; } @@ -7133,12 +7124,12 @@ int RM_KillForkChild(int child_pid) { void ModuleForkDoneHandler(int exitcode, int bysignal) { serverLog(LL_NOTICE, "Module fork exited pid: %ld, retcode: %d, bysignal: %d", - (long) server.module_child_pid, exitcode, bysignal); + (long) server.child_pid, exitcode, bysignal); if (moduleForkInfo.done_handler) { moduleForkInfo.done_handler(exitcode, bysignal, moduleForkInfo.done_handler_user_data); } - server.module_child_pid = -1; + moduleForkInfo.done_handler = NULL; moduleForkInfo.done_handler_user_data = NULL; } diff --git a/src/networking.c b/src/networking.c index acb1b27cb..e71e39624 100644 --- a/src/networking.c +++ b/src/networking.c @@ -1358,7 +1358,7 @@ void freeClient(client *c) { * to keep data safe and we may delay configured 'save' for full sync. */ if (server.saveparamslen == 0 && c->replstate == SLAVE_STATE_WAIT_BGSAVE_END && - server.rdb_child_pid != -1 && + server.child_type == CHILD_TYPE_RDB && server.rdb_child_type == RDB_CHILD_TYPE_DISK && anyOtherSlaveWaitRdb(c) == 0) { diff --git a/src/rdb.c b/src/rdb.c index abcfeadd7..1281948d1 100644 --- a/src/rdb.c +++ b/src/rdb.c @@ -1410,7 +1410,6 @@ int rdbSaveBackground(char *filename, rdbSaveInfo *rsi) { server.dirty_before_bgsave = server.dirty; server.lastbgsave_try = time(NULL); - openChildInfoPipe(); if ((childpid = redisFork(CHILD_TYPE_RDB)) == 0) { int retval; @@ -1426,7 +1425,6 @@ int rdbSaveBackground(char *filename, rdbSaveInfo *rsi) { } else { /* Parent */ if (childpid == -1) { - closeChildInfoPipe(); server.lastbgsave_status = C_ERR; serverLog(LL_WARNING,"Can't save in background: fork: %s", strerror(errno)); @@ -1434,9 +1432,7 @@ int rdbSaveBackground(char *filename, rdbSaveInfo *rsi) { } serverLog(LL_NOTICE,"Background saving started by pid %ld",(long) childpid); server.rdb_save_time_start = time(NULL); - server.rdb_child_pid = childpid; server.rdb_child_type = RDB_CHILD_TYPE_DISK; - updateDictResizePolicy(); return C_OK; } return C_OK; /* unreached */ @@ -2654,7 +2650,7 @@ static void backgroundSaveDoneHandlerDisk(int exitcode, int bysignal) { serverLog(LL_WARNING, "Background saving terminated by signal %d", bysignal); latencyStartMonitor(latency); - rdbRemoveTempFile(server.rdb_child_pid, 0); + rdbRemoveTempFile(server.child_pid, 0); latencyEndMonitor(latency); latencyAddSampleIfNeeded("rdb-unlink-temp-file",latency); /* SIGUSR1 is whitelisted, so we have a way to kill a child without @@ -2706,7 +2702,6 @@ void backgroundSaveDoneHandler(int exitcode, int bysignal) { break; } - server.rdb_child_pid = -1; server.rdb_child_type = RDB_CHILD_TYPE_NONE; server.rdb_save_time_last = time(NULL)-server.rdb_save_time_start; server.rdb_save_time_start = -1; @@ -2719,10 +2714,13 @@ void backgroundSaveDoneHandler(int exitcode, int bysignal) { * the child did not exit for an error, but because we wanted), and performs * the cleanup needed. */ void killRDBChild(void) { - kill(server.rdb_child_pid,SIGUSR1); - rdbRemoveTempFile(server.rdb_child_pid, 0); - closeChildInfoPipe(); - updateDictResizePolicy(); + kill(server.child_pid, SIGUSR1); + /* Because we are not using here wait4 (like we have in killAppendOnlyChild + * and TerminateModuleForkChild), all the cleanup operations is done by + * checkChildrenDone, that later will find that the process killed. + * This includes: + * - resetChildState + * - rdbRemoveTempFile */ } /* Spawn an RDB child that writes the RDB to the sockets of the slaves @@ -2773,7 +2771,6 @@ int rdbSaveToSlavesSockets(rdbSaveInfo *rsi) { } /* Create the child process. */ - openChildInfoPipe(); if ((childpid = redisFork(CHILD_TYPE_RDB)) == 0) { /* Child */ int retval, dummy; @@ -2824,14 +2821,11 @@ int rdbSaveToSlavesSockets(rdbSaveInfo *rsi) { server.rdb_pipe_conns = NULL; server.rdb_pipe_numconns = 0; server.rdb_pipe_numconns_writing = 0; - closeChildInfoPipe(); } else { serverLog(LL_NOTICE,"Background RDB transfer started by pid %ld", (long) childpid); server.rdb_save_time_start = time(NULL); - server.rdb_child_pid = childpid; server.rdb_child_type = RDB_CHILD_TYPE_SOCKET; - updateDictResizePolicy(); close(rdb_pipe_write); /* close write in parent so that it can detect the close on the child. */ if (aeCreateFileEvent(server.el, server.rdb_pipe_read, AE_READABLE, rdbPipeReadHandler,NULL) == AE_ERR) { serverPanic("Unrecoverable error creating server.rdb_pipe_read file event."); @@ -2843,7 +2837,7 @@ int rdbSaveToSlavesSockets(rdbSaveInfo *rsi) { } void saveCommand(client *c) { - if (server.rdb_child_pid != -1) { + if (server.child_type == CHILD_TYPE_RDB) { addReplyError(c,"Background save already in progress"); return; } @@ -2874,7 +2868,7 @@ void bgsaveCommand(client *c) { rdbSaveInfo rsi, *rsiptr; rsiptr = rdbPopulateSaveInfo(&rsi); - if (server.rdb_child_pid != -1) { + if (server.child_type == CHILD_TYPE_RDB) { addReplyError(c,"Background save already in progress"); } else if (hasActiveChildProcess()) { if (schedule) { diff --git a/src/replication.c b/src/replication.c index 20eb83e72..361bdb626 100644 --- a/src/replication.c +++ b/src/replication.c @@ -786,7 +786,7 @@ void syncCommand(client *c) { } /* CASE 1: BGSAVE is in progress, with disk target. */ - if (server.rdb_child_pid != -1 && + if (server.child_type == CHILD_TYPE_RDB && server.rdb_child_type == RDB_CHILD_TYPE_DISK) { /* Ok a background save is in progress. Let's check if it is a good @@ -816,7 +816,7 @@ void syncCommand(client *c) { } /* CASE 2: BGSAVE is in progress, with socket target. */ - } else if (server.rdb_child_pid != -1 && + } else if (server.child_type == CHILD_TYPE_RDB && server.rdb_child_type == RDB_CHILD_TYPE_SOCKET) { /* There is an RDB child process but it is writing directly to @@ -914,7 +914,7 @@ void replconfCommand(client *c) { * There's a chance the ACK got to us before we detected that the * bgsave is done (since that depends on cron ticks), so run a * quick check first (instead of waiting for the next ACK. */ - if (server.rdb_child_pid != -1 && c->replstate == SLAVE_STATE_WAIT_BGSAVE_END) + if (server.child_type == CHILD_TYPE_RDB && c->replstate == SLAVE_STATE_WAIT_BGSAVE_END) checkChildrenDone(); if (c->repl_put_online_on_ack && c->replstate == SLAVE_STATE_ONLINE) putSlaveOnline(c); @@ -1721,13 +1721,13 @@ void readSyncBulkPayload(connection *conn) { connRecvTimeout(conn,0); } else { /* Ensure background save doesn't overwrite synced data */ - if (server.rdb_child_pid != -1) { + if (server.child_type == CHILD_TYPE_RDB) { serverLog(LL_NOTICE, "Replica is about to load the RDB file received from the " "master, but there is a pending RDB child running. " "Killing process %ld and removing its temp file to avoid " "any race", - (long) server.rdb_child_pid); + (long) server.child_pid); killRDBChild(); } diff --git a/src/server.c b/src/server.c index 6140b21ac..ee2a00986 100644 --- a/src/server.c +++ b/src/server.c @@ -1559,12 +1559,32 @@ void updateDictResizePolicy(void) { dictDisableResize(); } +const char *strChildType(int type) { + switch(type) { + case CHILD_TYPE_RDB: return "RDB"; + case CHILD_TYPE_AOF: return "AOF"; + case CHILD_TYPE_LDB: return "LDB"; + case CHILD_TYPE_MODULE: return "MODULE"; + default: return "Unknown"; + } +} + /* Return true if there are active children processes doing RDB saving, * AOF rewriting, or some side process spawned by a loaded module. */ int hasActiveChildProcess() { - return server.rdb_child_pid != -1 || - server.aof_child_pid != -1 || - server.module_child_pid != -1; + return server.child_pid != -1; +} + +void resetChildState() { + server.child_type = CHILD_TYPE_NONE; + server.child_pid = -1; + updateDictResizePolicy(); + closeChildInfoPipe(); +} + +/* Return if child type is mutual exclusive with other fork children */ +int isMutuallyExclusiveChildType(int type) { + return type == CHILD_TYPE_RDB || type == CHILD_TYPE_AOF || type == CHILD_TYPE_MODULE; } /* Return true if this instance has persistence completely turned off: @@ -1886,29 +1906,30 @@ void checkChildrenDone(void) { if (pid == -1) { serverLog(LL_WARNING,"wait3() returned an error: %s. " - "rdb_child_pid = %d, aof_child_pid = %d, module_child_pid = %d", + "child_type: %s, child_pid = %d", strerror(errno), - (int) server.rdb_child_pid, - (int) server.aof_child_pid, - (int) server.module_child_pid); - } else if (pid == server.rdb_child_pid) { - backgroundSaveDoneHandler(exitcode,bysignal); - if (!bysignal && exitcode == 0) receiveChildInfo(); - } else if (pid == server.aof_child_pid) { - backgroundRewriteDoneHandler(exitcode,bysignal); - if (!bysignal && exitcode == 0) receiveChildInfo(); - } else if (pid == server.module_child_pid) { - ModuleForkDoneHandler(exitcode,bysignal); + strChildType(server.child_type), + (int) server.child_pid); + } else if (pid == server.child_pid) { + if (server.child_type == CHILD_TYPE_RDB) { + backgroundSaveDoneHandler(exitcode, bysignal); + } else if (server.child_type == CHILD_TYPE_AOF) { + backgroundRewriteDoneHandler(exitcode, bysignal); + } else if (server.child_type == CHILD_TYPE_MODULE) { + ModuleForkDoneHandler(exitcode, bysignal); + } else { + serverPanic("Unknown child type %d for child pid %d", server.child_type, server.child_pid); + exit(1); + } if (!bysignal && exitcode == 0) receiveChildInfo(); + resetChildState(); } else { if (!ldbRemoveChild(pid)) { serverLog(LL_WARNING, - "Warning, detected child with unmatched pid: %ld", - (long)pid); + "Warning, detected child with unmatched pid: %ld", + (long) pid); } } - updateDictResizePolicy(); - closeChildInfoPipe(); /* start any pending forks immediately. */ replicationStartPendingFork(); @@ -3087,9 +3108,8 @@ void initServer(void) { server.in_eval = 0; server.in_exec = 0; server.propagate_in_transaction = 0; - server.rdb_child_pid = -1; - server.aof_child_pid = -1; - server.module_child_pid = -1; + server.child_pid = -1; + server.child_type = CHILD_TYPE_NONE; server.rdb_child_type = RDB_CHILD_TYPE_NONE; server.rdb_pipe_conns = NULL; server.rdb_pipe_numconns = 0; @@ -4056,25 +4076,28 @@ int prepareForShutdown(int flags) { /* Kill the saving child if there is a background saving in progress. We want to avoid race conditions, for instance our saving child may overwrite the synchronous saving did by SHUTDOWN. */ - if (server.rdb_child_pid != -1) { + if (server.child_type == CHILD_TYPE_RDB) { serverLog(LL_WARNING,"There is a child saving an .rdb. Killing it!"); - /* Note that, in killRDBChild, we call rdbRemoveTempFile that will - * do close fd(in order to unlink file actully) in background thread. + killRDBChild(); + /* Note that, in killRDBChild normally has backgroundSaveDoneHandler + * doing it's cleanup, but in this case this code will not be reached, + * so we need to call rdbRemoveTempFile which will close fd(in order + * to unlink file actully) in background thread. * The temp rdb file fd may won't be closed when redis exits quickly, * but OS will close this fd when process exits. */ - killRDBChild(); + rdbRemoveTempFile(server.child_pid, 0); } /* Kill module child if there is one. */ - if (server.module_child_pid != -1) { + if (server.child_type == CHILD_TYPE_MODULE) { serverLog(LL_WARNING,"There is a module fork child. Killing it!"); - TerminateModuleForkChild(server.module_child_pid,0); + TerminateModuleForkChild(server.child_pid,0); } if (server.aof_state != AOF_OFF) { /* Kill the AOF saving child as the AOF we already have may be longer * but contains the full dataset anyway. */ - if (server.aof_child_pid != -1) { + if (server.child_type == CHILD_TYPE_AOF) { /* If we have AOF enabled but haven't written the AOF yet, don't * shutdown or else the dataset will be lost. */ if (server.aof_state == AOF_WAIT_REWRITE) { @@ -4613,23 +4636,23 @@ sds genRedisInfoString(const char *section) { "module_fork_last_cow_size:%zu\r\n", server.loading, server.dirty, - server.rdb_child_pid != -1, + server.child_type == CHILD_TYPE_RDB, (intmax_t)server.lastsave, (server.lastbgsave_status == C_OK) ? "ok" : "err", (intmax_t)server.rdb_save_time_last, - (intmax_t)((server.rdb_child_pid == -1) ? + (intmax_t)((server.child_type != CHILD_TYPE_RDB) ? -1 : time(NULL)-server.rdb_save_time_start), server.stat_rdb_cow_bytes, server.aof_state != AOF_OFF, - server.aof_child_pid != -1, + server.child_type == CHILD_TYPE_AOF, server.aof_rewrite_scheduled, (intmax_t)server.aof_rewrite_time_last, - (intmax_t)((server.aof_child_pid == -1) ? + (intmax_t)((server.child_type != CHILD_TYPE_AOF) ? -1 : time(NULL)-server.aof_rewrite_time_start), (server.aof_lastbgrewrite_status == C_OK) ? "ok" : "err", (server.aof_last_write_status == C_OK) ? "ok" : "err", server.stat_aof_cow_bytes, - server.module_child_pid != -1, + server.child_type == CHILD_TYPE_MODULE, server.stat_module_cow_bytes); if (server.aof_enabled) { @@ -5289,6 +5312,13 @@ void closeClildUnusedResourceAfterFork() { /* purpose is one of CHILD_TYPE_ types */ int redisFork(int purpose) { + if (isMutuallyExclusiveChildType(purpose)) { + if (hasActiveChildProcess()) + return -1; + + openChildInfoPipe(); + } + int childpid; long long start = ustime(); if ((childpid = fork()) == 0) { @@ -5304,8 +5334,23 @@ int redisFork(int purpose) { server.stat_fork_rate = (double) zmalloc_used_memory() * 1000000 / server.stat_fork_time / (1024*1024*1024); /* GB per second. */ latencyAddSampleIfNeeded("fork",server.stat_fork_time/1000); if (childpid == -1) { + if (isMutuallyExclusiveChildType(purpose)) closeChildInfoPipe(); return -1; } + + /* The child_pid and child_type are only for mutual exclusive children. + * other child types should handle and store their pid's in dedicated variables. + * + * Today, we allows CHILD_TYPE_LDB to run in parallel with the other fork types: + * - it isn't used for production, so it will not make the server to be less efficient + * - used for debugging, and we don't want to block it from running while other + * forks are running (like RDB and AOF) */ + if (isMutuallyExclusiveChildType(purpose)) { + server.child_pid = childpid; + server.child_type = purpose; + } + + updateDictResizePolicy(); } return childpid; } diff --git a/src/server.h b/src/server.h index b5610432c..9d383cc37 100644 --- a/src/server.h +++ b/src/server.h @@ -1145,7 +1145,8 @@ struct redisServer { int module_blocked_pipe[2]; /* Pipe used to awake the event loop if a client blocked on a module command needs to be processed. */ - pid_t module_child_pid; /* PID of module child */ + pid_t child_pid; /* PID of current child */ + int child_type; /* Type of current child */ /* Networking */ int port; /* TCP listening port */ int tls_port; /* TLS listening port */ @@ -1281,7 +1282,6 @@ struct redisServer { off_t aof_fsync_offset; /* AOF offset which is already synced to disk. */ int aof_flush_sleep; /* Micros to sleep before flush. (used by tests) */ int aof_rewrite_scheduled; /* Rewrite once BGSAVE terminates. */ - pid_t aof_child_pid; /* PID if rewriting process */ list *aof_rewrite_buf_blocks; /* Hold changes during an AOF rewrite. */ sds aof_buf; /* AOF buffer, written before entering the event loop */ int aof_fd; /* File descriptor of currently selected AOF file */ @@ -1311,7 +1311,6 @@ struct redisServer { /* RDB persistence */ long long dirty; /* Changes to DB from the last save */ long long dirty_before_bgsave; /* Used to restore dirty on failed BGSAVE */ - pid_t rdb_child_pid; /* PID of RDB saving child */ struct saveparam *saveparams; /* Save points array for RDB */ int saveparamslen; /* Number of saving points */ char *rdb_filename; /* Name of RDB file */ @@ -2007,6 +2006,8 @@ void receiveChildInfo(void); /* Fork helpers */ int redisFork(int type); int hasActiveChildProcess(); +void resetChildState(); +int isMutuallyExclusiveChildType(int type); void sendChildCOWInfo(int ptype, char *pname); /* acl.c -- Authentication related prototypes. */