diff --git a/src/rdb.c b/src/rdb.c index 3a10e0cec012d9425b666a89d8201b251d43bd68..840e99137dc316df62eb3c9e6729d7fb797251e9 100644 --- a/src/rdb.c +++ b/src/rdb.c @@ -656,6 +656,7 @@ int rdbSave(char *filename) { redisLog(REDIS_NOTICE,"DB saved on disk"); server.dirty = 0; server.lastsave = time(NULL); + server.lastbgsave_status = REDIS_OK; return REDIS_OK; werr: @@ -1061,12 +1062,15 @@ void backgroundSaveDoneHandler(int exitcode, int bysignal) { "Background saving terminated with success"); server.dirty = server.dirty - server.dirty_before_bgsave; server.lastsave = time(NULL); + server.lastbgsave_status = REDIS_OK; } else if (!bysignal && exitcode != 0) { redisLog(REDIS_WARNING, "Background saving error"); + server.lastbgsave_status = REDIS_ERR; } else { redisLog(REDIS_WARNING, "Background saving terminated by signal %d", bysignal); rdbRemoveTempFile(server.rdb_child_pid); + server.lastbgsave_status = REDIS_ERR; } server.rdb_child_pid = -1; /* Possibly there are slaves waiting for a BGSAVE in order to be served diff --git a/src/redis.c b/src/redis.c index 6d5522e824c93b0ada93e823f7a3d80a174ff943..3dfef024f1083991a405f2312c7c5621a7abcb4f 100644 --- a/src/redis.c +++ b/src/redis.c @@ -833,6 +833,8 @@ void createSharedObjects(void) { "-LOADING Redis is loading the dataset in memory\r\n")); shared.slowscripterr = createObject(REDIS_STRING,sdsnew( "-BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE.\r\n")); + shared.bgsaveerr = createObject(REDIS_STRING,sdsnew( + "-MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Write commands are disabled. Please check Redis logs for details about the error.\r\n")); shared.space = createObject(REDIS_STRING,sdsnew(" ")); shared.colon = createObject(REDIS_STRING,sdsnew(":")); shared.plus = createObject(REDIS_STRING,sdsnew("+")); @@ -1088,6 +1090,7 @@ void initServer() { server.stat_fork_time = 0; server.stat_rejected_conn = 0; server.unixtime = time(NULL); + server.lastbgsave_status = REDIS_OK; aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL); if (server.ipfd > 0 && aeCreateFileEvent(server.el,server.ipfd,AE_READABLE, acceptTcpHandler,NULL) == AE_ERR) oom("creating file event"); @@ -1374,6 +1377,14 @@ int processCommand(redisClient *c) { } } + /* Don't accept write commands if there are problems persisting on disk. */ + if (server.saveparamslen > 0 && server.lastbgsave_status == REDIS_ERR && + c->cmd->flags & REDIS_CMD_WRITE) + { + addReply(c, shared.bgsaveerr); + return REDIS_OK; + } + /* Only allow SUBSCRIBE and UNSUBSCRIBE in the context of Pub/Sub */ if ((dictSize(c->pubsub_channels) > 0 || listLength(c->pubsub_patterns) > 0) && @@ -1645,12 +1656,14 @@ sds genRedisInfoString(char *section) { "changes_since_last_save:%lld\r\n" "bgsave_in_progress:%d\r\n" "last_save_time:%ld\r\n" + "last_bgsave_status:%s\r\n" "bgrewriteaof_in_progress:%d\r\n", server.loading, server.aof_state != REDIS_AOF_OFF, server.dirty, server.rdb_child_pid != -1, server.lastsave, + server.lastbgsave_status == REDIS_OK ? "ok" : "err", server.aof_child_pid != -1); if (server.aof_state != REDIS_AOF_OFF) { diff --git a/src/redis.h b/src/redis.h index c18e9170015988686c6fe1a82e3c5a5a3a5d17a7..daaf362fbed47e526007eda6a9d0e343b610bf06 100644 --- a/src/redis.h +++ b/src/redis.h @@ -361,8 +361,8 @@ struct sharedObjectsStruct { robj *crlf, *ok, *err, *emptybulk, *czero, *cone, *cnegone, *pong, *space, *colon, *nullbulk, *nullmultibulk, *queued, *emptymultibulk, *wrongtypeerr, *nokeyerr, *syntaxerr, *sameobjecterr, - *outofrangeerr, *noscripterr, *loadingerr, *slowscripterr, *plus, - *select0, *select1, *select2, *select3, *select4, + *outofrangeerr, *noscripterr, *loadingerr, *slowscripterr, *bgsaveerr, + *plus, *select0, *select1, *select2, *select3, *select4, *select5, *select6, *select7, *select8, *select9, *messagebulk, *pmessagebulk, *subscribebulk, *unsubscribebulk, *psubscribebulk, *punsubscribebulk, *del, *rpop, *lpop, @@ -567,6 +567,7 @@ struct redisServer { char *requirepass; /* Pass for AUTH command, or NULL */ char *pidfile; /* PID file path */ int arch_bits; /* 32 or 64 depending on sizeof(long) */ + int cronloops; /* Number of times the cron function run */ /* Networking */ int port; /* TCP listening port */ char *bindaddr; /* Bind address or NULL */ @@ -587,8 +588,6 @@ struct redisServer { time_t loading_start_time; /* Fast pointers to often looked up command */ struct redisCommand *delCommand, *multiCommand, *lpushCommand; - int cronloops; /* Number of times the cron function run */ - time_t lastsave; /* Unix time of last save succeeede */ /* Fields used only for stats */ time_t stat_starttime; /* Server start time */ long long stat_numcommands; /* Number of processed commands */ @@ -636,6 +635,8 @@ struct redisServer { int saveparamslen; /* Number of saving points */ char *rdb_filename; /* Name of RDB file */ int rdb_compression; /* Use compression in RDB? */ + time_t lastsave; /* Unix time of last save succeeede */ + int lastbgsave_status; /* REDIS_OK or REDIS_ERR */ /* Propagation of commands in AOF / replication */ redisOpArray also_propagate; /* Additional command to propagate. */ /* Logging */