diff options
-rw-r--r-- | redis.c | 32 | ||||
-rw-r--r-- | redis.conf | 17 |
2 files changed, 47 insertions, 2 deletions
@@ -190,6 +190,11 @@ #define ZSKIPLIST_MAXLEVEL 32 /* Should be enough for 2^32 elements */ #define ZSKIPLIST_P 0.25 /* Skiplist P = 1/4 */ +/* Append only defines */ +#define APPENDFSYNC_NO 0 +#define APPENDFSYNC_ALWAYS 1 +#define APPENDFSYNC_EVERYSEC 2 + /*================================= Data types ============================== */ /* A redis object, that is a type able to hold a string / list / set */ @@ -262,6 +267,8 @@ struct redisServer { int dbnum; int daemonize; int appendonly; + int appendfsync; + time_t lastfsync; int appendfd; int appendseldb; char *pidfile; @@ -1029,6 +1036,8 @@ static void initServerConfig() { server.glueoutputbuf = 1; server.daemonize = 0; server.appendonly = 0; + server.appendfsync = APPENDFSYNC_EVERYSEC; + server.lastfsync = time(NULL); server.appendfd = -1; server.appendseldb = -1; /* Make sure the first time will not match */ server.pidfile = "/var/run/redis.pid"; @@ -1245,6 +1254,17 @@ static void loadServerConfig(char *filename) { if ((server.appendonly = yesnotoi(argv[1])) == -1) { err = "argument must be 'yes' or 'no'"; goto loaderr; } + } else if (!strcasecmp(argv[0],"appendfsync") && argc == 2) { + if (strcasecmp(argv[1],"no")) { + server.appendfsync = APPENDFSYNC_NO; + } else if (strcasecmp(argv[1],"always")) { + server.appendfsync = APPENDFSYNC_ALWAYS; + } else if (strcasecmp(argv[1],"everysec")) { + server.appendfsync = APPENDFSYNC_EVERYSEC; + } else { + err = "argument must be 'no', 'always' or 'everysec'"; + goto loaderr; + } } else if (!strcasecmp(argv[0],"requirepass") && argc == 2) { server.requirepass = zstrdup(argv[1]); } else if (!strcasecmp(argv[0],"pidfile") && argc == 2) { @@ -1651,6 +1671,7 @@ static void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv sds buf = sdsempty(); int j; ssize_t nwritten; + time_t now; /* The DB this command was targetting is not the same as the last command * we appendend. To issue a SELECT command is needed. */ @@ -1691,8 +1712,15 @@ static void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv redisLog(REDIS_WARNING,"Aborting on short write while writing to the append-only file: %s",strerror(errno)); } abort(); - } - fsync(server.appendfd); /* Let's try to get this data on the disk */ + } + now = time(NULL); + if (server.appendfsync == APPENDFSYNC_ALWAYS || + (server.appendfsync == APPENDFSYNC_EVERYSEC && + now-server.lastfsync > 1)) + { + fsync(server.appendfd); /* Let's try to get this data on the disk */ + server.lastfsync = now; + } } static void processInputBuffer(redisClient *c) { diff --git a/redis.conf b/redis.conf index fac5ba605..610049ef9 100644 --- a/redis.conf +++ b/redis.conf @@ -124,6 +124,23 @@ databases 16 # appendonly yes +# The fsync() calls tells the Operating System to actually write data on disk +# instead to wait for more data in the output buffer. Some OS will really flush +# data on disk, some other OS will just try to do it ASAP. +# +# Redis supports three different modes: +# +# no: don't fsync, just let the OS flush the data when it wants. Faster. +# always: fsync after every write to the append only log . Slow, Safest. +# everysec: fsync only if one second passed since the last fsync. Compromise. +# +# The default is "no" since it's faster and anyway safer than snapshots from +# the point of view of durability of the latest records modified. + +appendfsync no +# appendfsync always +# appendfsync everysec + ############################### ADVANCED CONFIG ############################### # Glue small output buffers together in order to send small replies in a |