mirror of
https://github.com/fluencelabs/redis
synced 2025-03-30 22:31:03 +00:00
Initial implementation of append-only mode. Loading still not implemented.
This commit is contained in:
parent
43e5ccdf57
commit
44b38ef432
72
redis.c
72
redis.c
@ -261,6 +261,9 @@ struct redisServer {
|
|||||||
int maxidletime;
|
int maxidletime;
|
||||||
int dbnum;
|
int dbnum;
|
||||||
int daemonize;
|
int daemonize;
|
||||||
|
int appendonly;
|
||||||
|
int appendfd;
|
||||||
|
int appendseldb;
|
||||||
char *pidfile;
|
char *pidfile;
|
||||||
int bgsaveinprogress;
|
int bgsaveinprogress;
|
||||||
pid_t bgsavechildpid;
|
pid_t bgsavechildpid;
|
||||||
@ -269,6 +272,7 @@ struct redisServer {
|
|||||||
char *logfile;
|
char *logfile;
|
||||||
char *bindaddr;
|
char *bindaddr;
|
||||||
char *dbfilename;
|
char *dbfilename;
|
||||||
|
char *appendfilename;
|
||||||
char *requirepass;
|
char *requirepass;
|
||||||
int shareobjects;
|
int shareobjects;
|
||||||
/* Replication related */
|
/* Replication related */
|
||||||
@ -364,6 +368,7 @@ static void incrRefCount(robj *o);
|
|||||||
static int rdbSaveBackground(char *filename);
|
static int rdbSaveBackground(char *filename);
|
||||||
static robj *createStringObject(char *ptr, size_t len);
|
static robj *createStringObject(char *ptr, size_t len);
|
||||||
static void replicationFeedSlaves(list *slaves, struct redisCommand *cmd, int dictid, robj **argv, int argc);
|
static void replicationFeedSlaves(list *slaves, struct redisCommand *cmd, int dictid, robj **argv, int argc);
|
||||||
|
static void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int argc);
|
||||||
static int syncWithMaster(void);
|
static int syncWithMaster(void);
|
||||||
static robj *tryObjectSharing(robj *o);
|
static robj *tryObjectSharing(robj *o);
|
||||||
static int tryObjectEncoding(robj *o);
|
static int tryObjectEncoding(robj *o);
|
||||||
@ -1023,8 +1028,12 @@ static void initServerConfig() {
|
|||||||
server.bindaddr = NULL;
|
server.bindaddr = NULL;
|
||||||
server.glueoutputbuf = 1;
|
server.glueoutputbuf = 1;
|
||||||
server.daemonize = 0;
|
server.daemonize = 0;
|
||||||
|
server.appendonly = 0;
|
||||||
|
server.appendfd = -1;
|
||||||
|
server.appendseldb = -1; /* Make sure the first time will not match */
|
||||||
server.pidfile = "/var/run/redis.pid";
|
server.pidfile = "/var/run/redis.pid";
|
||||||
server.dbfilename = "dump.rdb";
|
server.dbfilename = "dump.rdb";
|
||||||
|
server.appendfilename = "appendonly.log";
|
||||||
server.requirepass = NULL;
|
server.requirepass = NULL;
|
||||||
server.shareobjects = 0;
|
server.shareobjects = 0;
|
||||||
server.sharingpoolsize = 1024;
|
server.sharingpoolsize = 1024;
|
||||||
@ -1084,6 +1093,15 @@ static void initServer() {
|
|||||||
server.stat_numconnections = 0;
|
server.stat_numconnections = 0;
|
||||||
server.stat_starttime = time(NULL);
|
server.stat_starttime = time(NULL);
|
||||||
aeCreateTimeEvent(server.el, 1000, serverCron, NULL, NULL);
|
aeCreateTimeEvent(server.el, 1000, serverCron, NULL, NULL);
|
||||||
|
|
||||||
|
if (server.appendonly) {
|
||||||
|
server.appendfd = open(server.appendfilename,O_WRONLY|O_APPEND|O_CREAT);
|
||||||
|
if (server.appendfd == -1) {
|
||||||
|
redisLog(REDIS_WARNING, "Can't open the append-only file: %s",
|
||||||
|
strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Empty the whole database */
|
/* Empty the whole database */
|
||||||
@ -1223,6 +1241,10 @@ static void loadServerConfig(char *filename) {
|
|||||||
if ((server.daemonize = yesnotoi(argv[1])) == -1) {
|
if ((server.daemonize = yesnotoi(argv[1])) == -1) {
|
||||||
err = "argument must be 'yes' or 'no'"; goto loaderr;
|
err = "argument must be 'yes' or 'no'"; goto loaderr;
|
||||||
}
|
}
|
||||||
|
} else if (!strcasecmp(argv[0],"appendonly") && argc == 2) {
|
||||||
|
if ((server.appendonly = yesnotoi(argv[1])) == -1) {
|
||||||
|
err = "argument must be 'yes' or 'no'"; goto loaderr;
|
||||||
|
}
|
||||||
} else if (!strcasecmp(argv[0],"requirepass") && argc == 2) {
|
} else if (!strcasecmp(argv[0],"requirepass") && argc == 2) {
|
||||||
server.requirepass = zstrdup(argv[1]);
|
server.requirepass = zstrdup(argv[1]);
|
||||||
} else if (!strcasecmp(argv[0],"pidfile") && argc == 2) {
|
} else if (!strcasecmp(argv[0],"pidfile") && argc == 2) {
|
||||||
@ -1538,6 +1560,8 @@ static int processCommand(redisClient *c) {
|
|||||||
/* Exec the command */
|
/* Exec the command */
|
||||||
dirty = server.dirty;
|
dirty = server.dirty;
|
||||||
cmd->proc(c);
|
cmd->proc(c);
|
||||||
|
if (server.appendonly != 0)
|
||||||
|
feedAppendOnlyFile(cmd,c->db->id,c->argv,c->argc);
|
||||||
if (server.dirty-dirty != 0 && listLength(server.slaves))
|
if (server.dirty-dirty != 0 && listLength(server.slaves))
|
||||||
replicationFeedSlaves(server.slaves,cmd,c->db->id,c->argv,c->argc);
|
replicationFeedSlaves(server.slaves,cmd,c->db->id,c->argv,c->argc);
|
||||||
if (listLength(server.monitors))
|
if (listLength(server.monitors))
|
||||||
@ -1622,6 +1646,54 @@ static void replicationFeedSlaves(list *slaves, struct redisCommand *cmd, int di
|
|||||||
if (outv != static_outv) zfree(outv);
|
if (outv != static_outv) zfree(outv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO: translate EXPIREs into EXPIRETOs */
|
||||||
|
static void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int argc) {
|
||||||
|
sds buf = sdsempty();
|
||||||
|
int j;
|
||||||
|
ssize_t nwritten;
|
||||||
|
|
||||||
|
/* The DB this command was targetting is not the same as the last command
|
||||||
|
* we appendend. To issue a SELECT command is needed. */
|
||||||
|
if (dictid != server.appendseldb) {
|
||||||
|
char seldb[64];
|
||||||
|
|
||||||
|
snprintf(seldb,sizeof(seldb),"%d",dictid);
|
||||||
|
buf = sdscatprintf(buf,"*2\r\n$6\r\nSELECT\r\n$%d\r\n%s\r\n",
|
||||||
|
strlen(seldb),seldb);
|
||||||
|
}
|
||||||
|
/* Append the actual command */
|
||||||
|
buf = sdscatprintf(buf,"*%d\r\n",argc);
|
||||||
|
for (j = 0; j < argc; j++) {
|
||||||
|
robj *o = argv[j];
|
||||||
|
|
||||||
|
if (o->encoding != REDIS_ENCODING_RAW)
|
||||||
|
o = getDecodedObject(o);
|
||||||
|
buf = sdscatprintf(buf,"$%d\r\n",sdslen(o->ptr));
|
||||||
|
buf = sdscatlen(buf,o->ptr,sdslen(o->ptr));
|
||||||
|
buf = sdscatlen(buf,"\r\n",2);
|
||||||
|
if (o != argv[j])
|
||||||
|
decrRefCount(o);
|
||||||
|
}
|
||||||
|
/* We want to perform a single write. This should be guaranteed atomic
|
||||||
|
* at least if the filesystem we are writing is a real physical one.
|
||||||
|
* While this will save us against the server being killed I don't think
|
||||||
|
* there is much to do about the whole server stopping for power problems
|
||||||
|
* or alike */
|
||||||
|
nwritten = write(server.appendfd,buf,sdslen(buf));
|
||||||
|
if (nwritten != (unsigned)sdslen(buf)) {
|
||||||
|
/* Ooops, we are in troubles. The best thing to do for now is
|
||||||
|
* to simply exit instead to give the illusion that everything is
|
||||||
|
* working as expected. */
|
||||||
|
if (nwritten == -1) {
|
||||||
|
redisLog(REDIS_WARNING,"Aborting on error writing to the append-only file: %s",strerror(errno));
|
||||||
|
} else {
|
||||||
|
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 */
|
||||||
|
}
|
||||||
|
|
||||||
static void processInputBuffer(redisClient *c) {
|
static void processInputBuffer(redisClient *c) {
|
||||||
again:
|
again:
|
||||||
if (c->bulklen == -1) {
|
if (c->bulklen == -1) {
|
||||||
|
17
redis.conf
17
redis.conf
@ -107,6 +107,23 @@ databases 16
|
|||||||
|
|
||||||
# maxmemory <bytes>
|
# maxmemory <bytes>
|
||||||
|
|
||||||
|
############################## APPEND ONLY MODE ###############################
|
||||||
|
|
||||||
|
# By default Redis asynchronously dumps the dataset on disk. If you can live
|
||||||
|
# with the idea that the latest records will be lost if something like a crash
|
||||||
|
# happens this is the preferred way to run Redis. If instead you care a lot
|
||||||
|
# about your data and don't want to that a single record can get lost you should
|
||||||
|
# enable the append only mode: when this mode is enabled Redis will append
|
||||||
|
# every write operation received in the file appendonly.log. This file will
|
||||||
|
# be read on startup in order to rebuild the full dataset in memory.
|
||||||
|
#
|
||||||
|
# Note that you can have both the async dumps and the append only file if you
|
||||||
|
# like (you have to comment the "save" statements above to disable the dumps).
|
||||||
|
# Still if append only mode is enabled Redis will load the data from the
|
||||||
|
# log file at startup ignoring the dump.rdb file.
|
||||||
|
|
||||||
|
# appendonly yes
|
||||||
|
|
||||||
############################### ADVANCED CONFIG ###############################
|
############################### ADVANCED CONFIG ###############################
|
||||||
|
|
||||||
# Glue small output buffers together in order to send small replies in a
|
# Glue small output buffers together in order to send small replies in a
|
||||||
|
Loading…
x
Reference in New Issue
Block a user