X-Git-Url: https://git.saurik.com/redis.git/blobdiff_plain/231d758eecf6e492c8b40cddf4bc9e3a4dbf39cb..ac945e2dcf8cf2890c5676cc26cbd6e6d2254b14:/redis.c diff --git a/redis.c b/redis.c index 302a2129..274dec7a 100644 --- a/redis.c +++ b/redis.c @@ -27,7 +27,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#define REDIS_VERSION "1.1.91" +#define REDIS_VERSION "1.1.93" #include "fmacros.h" #include "config.h" @@ -301,6 +301,7 @@ struct redisServer { char *appendfilename; char *requirepass; int shareobjects; + int rdbcompression; /* Replication related */ int isslave; char *masterauth; @@ -923,7 +924,7 @@ void backgroundRewriteDoneHandler(int statloc) { close(fd); goto cleanup; } - redisLog(REDIS_WARNING,"Parent diff flushed into the new append log file with success"); + redisLog(REDIS_NOTICE,"Parent diff flushed into the new append log file with success (%lu bytes)",sdslen(server.bgrewritebuf)); /* Now our work is to rename the temp file into the stable file. And * switch the file descriptor used by the server for append only. */ if (rename(tmpfile,server.appendfilename) == -1) { @@ -1141,6 +1142,7 @@ static void initServerConfig() { server.appendfilename = "appendonly.aof"; server.requirepass = NULL; server.shareobjects = 0; + server.rdbcompression = 1; server.sharingpoolsize = 1024; server.maxclients = 0; server.maxmemory = 0; @@ -1341,6 +1343,10 @@ static void loadServerConfig(char *filename) { if ((server.shareobjects = yesnotoi(argv[1])) == -1) { err = "argument must be 'yes' or 'no'"; goto loaderr; } + } else if (!strcasecmp(argv[0],"rdbcompression") && argc == 2) { + if ((server.rdbcompression = yesnotoi(argv[1])) == -1) { + err = "argument must be 'yes' or 'no'"; goto loaderr; + } } else if (!strcasecmp(argv[0],"shareobjectspoolsize") && argc == 2) { server.sharingpoolsize = atoi(argv[1]); if (server.sharingpoolsize < 1) { @@ -1713,7 +1719,10 @@ static int processCommand(redisClient *c) { return 1; } else if ((cmd->arity > 0 && cmd->arity != c->argc) || (c->argc < -cmd->arity)) { - addReplySds(c,sdsnew("-ERR wrong number of arguments\r\n")); + addReplySds(c, + sdscatprintf(sdsempty(), + "-ERR wrong number of arguments for '%s' command\r\n", + cmd->name)); resetClient(c); return 1; } else if (server.maxmemory && cmd->flags & REDIS_CMD_DENYOOM && zmalloc_used_memory() > server.maxmemory) { @@ -1874,11 +1883,6 @@ again: sdsupdatelen(query); /* Now we can split the query in arguments */ - if (sdslen(query) == 0) { - /* Ignore empty query */ - sdsfree(query); - return; - } argv = sdssplitlen(query,sdslen(query)," ",1,&argc); sdsfree(query); @@ -1894,10 +1898,16 @@ again: } } zfree(argv); - /* Execute the command. If the client is still valid - * after processCommand() return and there is something - * on the query buffer try to process the next command. */ - if (c->argc && processCommand(c) && sdslen(c->querybuf)) goto again; + if (c->argc) { + /* Execute the command. If the client is still valid + * after processCommand() return and there is something + * on the query buffer try to process the next command. */ + if (processCommand(c) && sdslen(c->querybuf)) goto again; + } else { + /* Nothing to process, argc == 0. Just process the query + * buffer if it's not empty or return to the caller */ + if (sdslen(c->querybuf)) goto again; + } return; } else if (sdslen(c->querybuf) >= REDIS_REQUEST_MAX_SIZE) { redisLog(REDIS_DEBUG, "Client protocol error"); @@ -2030,6 +2040,7 @@ static void addReplyBulkLen(redisClient *c, robj *obj) { } else { long n = (long)obj->ptr; + /* Compute how many bytes will take this integer as a radix 10 string */ len = 1; if (n < 0) { len++; @@ -2483,7 +2494,7 @@ static int rdbSaveStringObjectRaw(FILE *fp, robj *obj) { /* Try LZF compression - under 20 bytes it's unable to compress even * aaaaaaaaaaaaaaaaaa so skip it */ - if (len > 20) { + if (server.rdbcompression && len > 20) { int retval; retval = rdbSaveLzfStringObject(fp,obj); @@ -2979,7 +2990,7 @@ static void echoCommand(redisClient *c) { static void setGenericCommand(redisClient *c, int nx) { int retval; - deleteIfVolatile(c->db,c->argv[1]); + if (nx) deleteIfVolatile(c->db,c->argv[1]); retval = dictAdd(c->db->dict,c->argv[1],c->argv[2]); if (retval == DICT_ERR) { if (!nx) { @@ -3058,7 +3069,7 @@ static void msetGenericCommand(redisClient *c, int nx) { int j, busykeys = 0; if ((c->argc % 2) == 0) { - addReplySds(c,sdsnew("-ERR wrong number of arguments\r\n")); + addReplySds(c,sdsnew("-ERR wrong number of arguments for MSET\r\n")); return; } /* Handle the NX flag. The MSETNX semantic is to return zero and don't @@ -3292,7 +3303,8 @@ static void bgsaveCommand(redisClient *c) { return; } if (rdbSaveBackground(server.dbfilename) == REDIS_OK) { - addReply(c,shared.ok); + char *status = "+Background saving started\r\n"; + addReplySds(c,sdsnew(status)); } else { addReply(c,shared.err); } @@ -3308,20 +3320,26 @@ static void shutdownCommand(redisClient *c) { kill(server.bgsavechildpid,SIGKILL); rdbRemoveTempFile(server.bgsavechildpid); } - /* SYNC SAVE */ - if (rdbSave(server.dbfilename) == REDIS_OK) { - if (server.daemonize) - unlink(server.pidfile); - redisLog(REDIS_WARNING,"%zu bytes used at exit",zmalloc_used_memory()); - redisLog(REDIS_WARNING,"Server exit now, bye bye..."); - exit(1); + if (server.appendonly) { + /* Append only file: fsync() the AOF and exit */ + fsync(server.appendfd); + exit(0); } else { - /* 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")); + /* Snapshotting. Perform a SYNC SAVE and exit */ + if (rdbSave(server.dbfilename) == REDIS_OK) { + if (server.daemonize) + unlink(server.pidfile); + redisLog(REDIS_WARNING,"%zu bytes used at exit",zmalloc_used_memory()); + redisLog(REDIS_WARNING,"Server exit now, bye bye..."); + exit(0); + } else { + /* 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")); + } } } @@ -3619,7 +3637,7 @@ static void ltrimCommand(redisClient *c) { o = lookupKeyWrite(c->db,c->argv[1]); if (o == NULL) { - addReply(c,shared.nokeyerr); + addReply(c,shared.ok); } else { if (o->type != REDIS_LIST) { addReply(c,shared.wrongtypeerr); @@ -3956,8 +3974,9 @@ static void sinterGenericCommand(redisClient *c, robj **setskeys, unsigned long if (!setobj) { zfree(dv); if (dstkey) { - deleteKey(c->db,dstkey); - addReply(c,shared.ok); + if (deleteKey(c->db,dstkey)) + server.dirty++; + addReply(c,shared.czero); } else { addReply(c,shared.nullmultibulk); } @@ -4581,7 +4600,8 @@ static void zrangebyscoreCommand(redisClient *c) { int offset = 0, limit = -1; if (c->argc != 4 && c->argc != 7) { - addReplySds(c,sdsnew("-ERR wrong number of arguments\r\n")); + addReplySds(c, + sdsnew("-ERR wrong number of arguments for ZRANGEBYSCORE\r\n")); return; } else if (c->argc == 7 && strcasecmp(c->argv[4]->ptr,"limit")) { addReply(c,shared.syntaxerr); @@ -5080,6 +5100,7 @@ static sds genRedisInfoString(void) { "changes_since_last_save:%lld\r\n" "bgsave_in_progress:%d\r\n" "last_save_time:%ld\r\n" + "bgrewriteaof_in_progress:%d\r\n" "total_connections_received:%lld\r\n" "total_commands_processed:%lld\r\n" "role:%s\r\n" @@ -5094,6 +5115,7 @@ static sds genRedisInfoString(void) { server.dirty, server.bgsavechildpid != -1, server.lastsave, + server.bgrewritechildpid != -1, server.stat_numconnections, server.stat_numcommands, server.masterhost == NULL ? "master" : "slave" @@ -5576,6 +5598,7 @@ static int syncWithMaster(void) { } server.master = createClient(fd); server.master->flags |= REDIS_MASTER; + server.master->authenticated = 1; server.replstate = REDIS_REPL_CONNECTED; return REDIS_OK; } @@ -5858,7 +5881,8 @@ static int fwriteBulk(FILE *fp, robj *obj) { obj = getDecodedObject(obj); snprintf(buf,sizeof(buf),"$%ld\r\n",(long)sdslen(obj->ptr)); if (fwrite(buf,strlen(buf),1,fp) == 0) goto err; - if (fwrite(obj->ptr,sdslen(obj->ptr),1,fp) == 0) goto err; + if (sdslen(obj->ptr) && fwrite(obj->ptr,sdslen(obj->ptr),1,fp) == 0) + goto err; if (fwrite("\r\n",2,1,fp) == 0) goto err; decrRefCount(obj); return 1; @@ -5987,7 +6011,7 @@ static int rewriteAppendOnlyFile(char *filename) { } /* Save the expire time */ if (expiretime != -1) { - char cmd[]="*3\r\n$6\r\nEXPIRE\r\n"; + char cmd[]="*3\r\n$8\r\nEXPIREAT\r\n"; /* If this key is already expired skip it */ if (expiretime < now) continue; if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr; @@ -6016,7 +6040,7 @@ static int rewriteAppendOnlyFile(char *filename) { werr: fclose(fp); unlink(tmpfile); - redisLog(REDIS_WARNING,"Write error writing append only fileon disk: %s", strerror(errno)); + redisLog(REDIS_WARNING,"Write error writing append only file on disk: %s", strerror(errno)); if (di) dictReleaseIterator(di); return REDIS_ERR; } @@ -6075,7 +6099,8 @@ static void bgrewriteaofCommand(redisClient *c) { return; } if (rewriteAppendOnlyFileBackground() == REDIS_OK) { - addReply(c,shared.ok); + char *status = "+Background append only file rewriting started\r\n"; + addReplySds(c,sdsnew(status)); } else { addReply(c,shared.err); } @@ -6105,6 +6130,14 @@ static void debugCommand(redisClient *c) { } redisLog(REDIS_WARNING,"DB reloaded by DEBUG RELOAD"); addReply(c,shared.ok); + } else if (!strcasecmp(c->argv[1]->ptr,"loadaof")) { + emptyDb(); + if (loadAppendOnlyFile(server.appendfilename) != REDIS_OK) { + addReply(c,shared.err); + return; + } + redisLog(REDIS_WARNING,"Append Only File loaded by DEBUG LOADAOF"); + addReply(c,shared.ok); } else if (!strcasecmp(c->argv[1]->ptr,"object") && c->argc == 3) { dictEntry *de = dictFind(c->db->dict,c->argv[2]); robj *key, *val;