Better handling of background saving process killed or crashed

This commit is contained in:
antirez 2009-06-16 16:42:20 +02:00
parent c3cb078d46
commit a3b21203d2
2 changed files with 31 additions and 9 deletions

3
TODO
View File

@ -1,12 +1,11 @@
BEFORE REDIS 1.0.0-rc1
* Add number of keys for every DB in INFO
* Cover most of the source code with test-redis.tcl
* Remove tmp-.... files when saving child exits in the wrong way, to do so use tmp-pid.rdb as filename so that the parent can rebuild the file name just from the child pid.
AFTER 1.0 stable release
* Max command payload bytes configurable, with a pretty large default.
* Add a command to inspect the currently selected DB index
* Consistent hashing implemented in all the client libraries having an user base
* SORT: Don't copy the list into a vector when BY argument is constant.
* SORT ... STORE keyname. Instead to return the SORTed data set it into key.

37
redis.c
View File

@ -327,10 +327,11 @@ static int deleteIfVolatile(redisDb *db, robj *key);
static int deleteKey(redisDb *db, robj *key);
static time_t getExpire(redisDb *db, robj *key);
static int setExpire(redisDb *db, robj *key, time_t when);
static void updateSalvesWaitingBgsave(int bgsaveerr);
static void updateSlavesWaitingBgsave(int bgsaveerr);
static void freeMemoryIfNeeded(void);
static int processCommand(redisClient *c);
static void setupSigSegvAction(void);
static void rdbRemoveTempFile(pid_t childpid);
static void authCommand(redisClient *c);
static void pingCommand(redisClient *c);
@ -778,10 +779,11 @@ static int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientD
} else {
redisLog(REDIS_WARNING,
"Background saving terminated by signal");
rdbRemoveTempFile(server.bgsavechildpid);
}
server.bgsaveinprogress = 0;
server.bgsavechildpid = -1;
updateSalvesWaitingBgsave(exitcode == 0 ? REDIS_OK : REDIS_ERR);
updateSlavesWaitingBgsave(exitcode == 0 ? REDIS_OK : REDIS_ERR);
}
} else {
/* If there is not a background saving in progress check if
@ -1900,7 +1902,7 @@ static int rdbSave(char *filename) {
int j;
time_t now = time(NULL);
snprintf(tmpfile,256,"temp-%d.%ld.rdb",(int)time(NULL),(long int)random());
snprintf(tmpfile,256,"temp-%d.rdb", (int) getpid());
fp = fopen(tmpfile,"w");
if (!fp) {
redisLog(REDIS_WARNING, "Failed saving the DB: %s", strerror(errno));
@ -2027,6 +2029,13 @@ static int rdbSaveBackground(char *filename) {
return REDIS_OK; /* unreached */
}
static void rdbRemoveTempFile(pid_t childpid) {
char tmpfile[256];
snprintf(tmpfile,256,"temp-%d.rdb", (int) childpid);
unlink(tmpfile);
}
static int rdbLoadType(FILE *fp) {
unsigned char type;
if (fread(&type,1,1,fp) == 0) return -1;
@ -2544,11 +2553,15 @@ static void bgsaveCommand(redisClient *c) {
static void shutdownCommand(redisClient *c) {
redisLog(REDIS_WARNING,"User requested shutdown, saving DB...");
/* 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.bgsaveinprogress) {
redisLog(REDIS_WARNING,"There is a live saving child. Killing it!");
signal(SIGCHLD, SIG_IGN);
kill(server.bgsavechildpid,SIGKILL);
rdbRemoveTempFile(server.bgsavechildpid);
}
/* SYNC SAVE */
if (rdbSave(server.dbfilename) == REDIS_OK) {
if (server.daemonize)
unlink(server.pidfile);
@ -2556,7 +2569,10 @@ static void shutdownCommand(redisClient *c) {
redisLog(REDIS_WARNING,"Server exit now, bye bye...");
exit(1);
} else {
signal(SIGCHLD, SIG_DFL);
/* Ooops.. error saving! The best we can do is to continue operating.
* Note that if there was a background saving process, in the next
* cron() Redis will be notified that the background saving aborted,
* handling special stuff like slaves pending for synchronization... */
redisLog(REDIS_WARNING,"Error trying to save the DB, can't exit");
addReplySds(c,sdsnew("-ERR can't quit, problems saving the DB\r\n"));
}
@ -3939,7 +3955,13 @@ static void sendBulkToSlave(aeEventLoop *el, int fd, void *privdata, int mask) {
}
}
static void updateSalvesWaitingBgsave(int bgsaveerr) {
/* This function is called at the end of every backgrond saving.
* The argument bgsaveerr is REDIS_OK if the background saving succeeded
* otherwise REDIS_ERR is passed to the function.
*
* The goal of this function is to handle slaves waiting for a successful
* background saving in order to perform non-blocking synchronization. */
static void updateSlavesWaitingBgsave(int bgsaveerr) {
listNode *ln;
int startbgsave = 0;
@ -4183,7 +4205,7 @@ static struct redisFunctionSym symsTable[] = {
{"deleteKey", (unsigned long)deleteKey},
{"getExpire", (unsigned long)getExpire},
{"setExpire", (unsigned long)setExpire},
{"updateSalvesWaitingBgsave", (unsigned long)updateSalvesWaitingBgsave},
{"updateSlavesWaitingBgsave", (unsigned long)updateSlavesWaitingBgsave},
{"freeMemoryIfNeeded", (unsigned long)freeMemoryIfNeeded},
{"authCommand", (unsigned long)authCommand},
{"pingCommand", (unsigned long)pingCommand},
@ -4246,6 +4268,7 @@ static struct redisFunctionSym symsTable[] = {
{"processCommand", (unsigned long)processCommand},
{"setupSigSegvAction", (unsigned long)setupSigSegvAction},
{"readQueryFromClient", (unsigned long)readQueryFromClient},
{"rdbRemoveTempFile", (unsigned long)rdbRemoveTempFile},
{NULL,0}
};