Skip to content

Commit

Permalink
Refuse writes if can't persist on disk.
Browse files Browse the repository at this point in the history
Redis now refuses accepting write queries if RDB persistence is
configured, but RDB snapshots can't be generated for some reason.
The status of the latest background save operation is now exposed
in the INFO output as well. This fixes issue redis#90.
  • Loading branch information
antirez committed Mar 7, 2012
1 parent e31b615 commit c25e7ea
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 4 deletions.
4 changes: 4 additions & 0 deletions src/rdb.c
Expand Up @@ -656,6 +656,7 @@ int rdbSave(char *filename) {
redisLog(REDIS_NOTICE,"DB saved on disk"); redisLog(REDIS_NOTICE,"DB saved on disk");
server.dirty = 0; server.dirty = 0;
server.lastsave = time(NULL); server.lastsave = time(NULL);
server.lastbgsave_status = REDIS_OK;
return REDIS_OK; return REDIS_OK;


werr: werr:
Expand Down Expand Up @@ -1061,12 +1062,15 @@ void backgroundSaveDoneHandler(int exitcode, int bysignal) {
"Background saving terminated with success"); "Background saving terminated with success");
server.dirty = server.dirty - server.dirty_before_bgsave; server.dirty = server.dirty - server.dirty_before_bgsave;
server.lastsave = time(NULL); server.lastsave = time(NULL);
server.lastbgsave_status = REDIS_OK;
} else if (!bysignal && exitcode != 0) { } else if (!bysignal && exitcode != 0) {
redisLog(REDIS_WARNING, "Background saving error"); redisLog(REDIS_WARNING, "Background saving error");
server.lastbgsave_status = REDIS_ERR;
} else { } else {
redisLog(REDIS_WARNING, redisLog(REDIS_WARNING,
"Background saving terminated by signal %d", bysignal); "Background saving terminated by signal %d", bysignal);
rdbRemoveTempFile(server.rdb_child_pid); rdbRemoveTempFile(server.rdb_child_pid);
server.lastbgsave_status = REDIS_ERR;
} }
server.rdb_child_pid = -1; server.rdb_child_pid = -1;
/* Possibly there are slaves waiting for a BGSAVE in order to be served /* Possibly there are slaves waiting for a BGSAVE in order to be served
Expand Down
13 changes: 13 additions & 0 deletions src/redis.c
Expand Up @@ -833,6 +833,8 @@ void createSharedObjects(void) {
"-LOADING Redis is loading the dataset in memory\r\n")); "-LOADING Redis is loading the dataset in memory\r\n"));
shared.slowscripterr = createObject(REDIS_STRING,sdsnew( shared.slowscripterr = createObject(REDIS_STRING,sdsnew(
"-BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE.\r\n")); "-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.space = createObject(REDIS_STRING,sdsnew(" "));
shared.colon = createObject(REDIS_STRING,sdsnew(":")); shared.colon = createObject(REDIS_STRING,sdsnew(":"));
shared.plus = createObject(REDIS_STRING,sdsnew("+")); shared.plus = createObject(REDIS_STRING,sdsnew("+"));
Expand Down Expand Up @@ -1088,6 +1090,7 @@ void initServer() {
server.stat_fork_time = 0; server.stat_fork_time = 0;
server.stat_rejected_conn = 0; server.stat_rejected_conn = 0;
server.unixtime = time(NULL); server.unixtime = time(NULL);
server.lastbgsave_status = REDIS_OK;
aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL); aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL);
if (server.ipfd > 0 && aeCreateFileEvent(server.el,server.ipfd,AE_READABLE, if (server.ipfd > 0 && aeCreateFileEvent(server.el,server.ipfd,AE_READABLE,
acceptTcpHandler,NULL) == AE_ERR) oom("creating file event"); acceptTcpHandler,NULL) == AE_ERR) oom("creating file event");
Expand Down Expand Up @@ -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 */ /* Only allow SUBSCRIBE and UNSUBSCRIBE in the context of Pub/Sub */
if ((dictSize(c->pubsub_channels) > 0 || listLength(c->pubsub_patterns) > 0) if ((dictSize(c->pubsub_channels) > 0 || listLength(c->pubsub_patterns) > 0)
&& &&
Expand Down Expand Up @@ -1645,12 +1656,14 @@ sds genRedisInfoString(char *section) {
"changes_since_last_save:%lld\r\n" "changes_since_last_save:%lld\r\n"
"bgsave_in_progress:%d\r\n" "bgsave_in_progress:%d\r\n"
"last_save_time:%ld\r\n" "last_save_time:%ld\r\n"
"last_bgsave_status:%s\r\n"
"bgrewriteaof_in_progress:%d\r\n", "bgrewriteaof_in_progress:%d\r\n",
server.loading, server.loading,
server.aof_state != REDIS_AOF_OFF, server.aof_state != REDIS_AOF_OFF,
server.dirty, server.dirty,
server.rdb_child_pid != -1, server.rdb_child_pid != -1,
server.lastsave, server.lastsave,
server.lastbgsave_status == REDIS_OK ? "ok" : "err",
server.aof_child_pid != -1); server.aof_child_pid != -1);


if (server.aof_state != REDIS_AOF_OFF) { if (server.aof_state != REDIS_AOF_OFF) {
Expand Down
9 changes: 5 additions & 4 deletions src/redis.h
Expand Up @@ -361,8 +361,8 @@ struct sharedObjectsStruct {
robj *crlf, *ok, *err, *emptybulk, *czero, *cone, *cnegone, *pong, *space, robj *crlf, *ok, *err, *emptybulk, *czero, *cone, *cnegone, *pong, *space,
*colon, *nullbulk, *nullmultibulk, *queued, *colon, *nullbulk, *nullmultibulk, *queued,
*emptymultibulk, *wrongtypeerr, *nokeyerr, *syntaxerr, *sameobjecterr, *emptymultibulk, *wrongtypeerr, *nokeyerr, *syntaxerr, *sameobjecterr,
*outofrangeerr, *noscripterr, *loadingerr, *slowscripterr, *plus, *outofrangeerr, *noscripterr, *loadingerr, *slowscripterr, *bgsaveerr,
*select0, *select1, *select2, *select3, *select4, *plus, *select0, *select1, *select2, *select3, *select4,
*select5, *select6, *select7, *select8, *select9, *select5, *select6, *select7, *select8, *select9,
*messagebulk, *pmessagebulk, *subscribebulk, *unsubscribebulk, *messagebulk, *pmessagebulk, *subscribebulk, *unsubscribebulk,
*psubscribebulk, *punsubscribebulk, *del, *rpop, *lpop, *psubscribebulk, *punsubscribebulk, *del, *rpop, *lpop,
Expand Down Expand Up @@ -567,6 +567,7 @@ struct redisServer {
char *requirepass; /* Pass for AUTH command, or NULL */ char *requirepass; /* Pass for AUTH command, or NULL */
char *pidfile; /* PID file path */ char *pidfile; /* PID file path */
int arch_bits; /* 32 or 64 depending on sizeof(long) */ int arch_bits; /* 32 or 64 depending on sizeof(long) */
int cronloops; /* Number of times the cron function run */
/* Networking */ /* Networking */
int port; /* TCP listening port */ int port; /* TCP listening port */
char *bindaddr; /* Bind address or NULL */ char *bindaddr; /* Bind address or NULL */
Expand All @@ -587,8 +588,6 @@ struct redisServer {
time_t loading_start_time; time_t loading_start_time;
/* Fast pointers to often looked up command */ /* Fast pointers to often looked up command */
struct redisCommand *delCommand, *multiCommand, *lpushCommand; 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 */ /* Fields used only for stats */
time_t stat_starttime; /* Server start time */ time_t stat_starttime; /* Server start time */
long long stat_numcommands; /* Number of processed commands */ long long stat_numcommands; /* Number of processed commands */
Expand Down Expand Up @@ -636,6 +635,8 @@ struct redisServer {
int saveparamslen; /* Number of saving points */ int saveparamslen; /* Number of saving points */
char *rdb_filename; /* Name of RDB file */ char *rdb_filename; /* Name of RDB file */
int rdb_compression; /* Use compression in RDB? */ 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 */ /* Propagation of commands in AOF / replication */
redisOpArray also_propagate; /* Additional command to propagate. */ redisOpArray also_propagate; /* Additional command to propagate. */
/* Logging */ /* Logging */
Expand Down

0 comments on commit c25e7ea

Please sign in to comment.