X-Git-Url: https://git.saurik.com/redis.git/blobdiff_plain/0d36ded040eba3b7b6e6ed1437f4f9c0bd44fbbe..81d456450ac42b7cf78367ae3a89af1a543c9ff1:/redis.c diff --git a/redis.c b/redis.c index f28b940a..07287605 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.94" #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; @@ -535,9 +536,9 @@ static struct redisCommand cmdTable[] = { {"zincrby",zincrbyCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM}, {"zrem",zremCommand,3,REDIS_CMD_BULK}, {"zremrangebyscore",zremrangebyscoreCommand,4,REDIS_CMD_INLINE}, - {"zrange",zrangeCommand,4,REDIS_CMD_INLINE}, + {"zrange",zrangeCommand,-4,REDIS_CMD_INLINE}, {"zrangebyscore",zrangebyscoreCommand,-4,REDIS_CMD_INLINE}, - {"zrevrange",zrevrangeCommand,4,REDIS_CMD_INLINE}, + {"zrevrange",zrevrangeCommand,-4,REDIS_CMD_INLINE}, {"zcard",zcardCommand,2,REDIS_CMD_INLINE}, {"zscore",zscoreCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM}, {"incrby",incrbyCommand,3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM}, @@ -1081,7 +1082,6 @@ static void createSharedObjects(void) { shared.nullbulk = createObject(REDIS_STRING,sdsnew("$-1\r\n")); shared.nullmultibulk = createObject(REDIS_STRING,sdsnew("*-1\r\n")); shared.emptymultibulk = createObject(REDIS_STRING,sdsnew("*0\r\n")); - /* no such key */ shared.pong = createObject(REDIS_STRING,sdsnew("+PONG\r\n")); shared.wrongtypeerr = createObject(REDIS_STRING,sdsnew( "-ERR Operation against a key holding the wrong kind of value\r\n")); @@ -1141,6 +1141,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 +1342,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) { @@ -1708,7 +1713,9 @@ static int processCommand(redisClient *c) { } cmd = lookupCommand(c->argv[0]->ptr); if (!cmd) { - addReplySds(c,sdsnew("-ERR unknown command\r\n")); + addReplySds(c, + sdscatprintf(sdsempty(), "-ERR unknown command '%s'\r\n", + (char*)c->argv[0]->ptr)); resetClient(c); return 1; } else if ((cmd->arity > 0 && cmd->arity != c->argc) || @@ -1877,11 +1884,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); @@ -1897,10 +1899,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"); @@ -2033,6 +2041,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++; @@ -2486,7 +2495,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); @@ -3312,20 +3321,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")); + } } } @@ -3623,7 +3638,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); @@ -3960,7 +3975,8 @@ static void sinterGenericCommand(redisClient *c, robj **setskeys, unsigned long if (!setobj) { zfree(dv); if (dstkey) { - deleteKey(c->db,dstkey); + if (deleteKey(c->db,dstkey)) + server.dirty++; addReply(c,shared.czero); } else { addReply(c,shared.nullmultibulk); @@ -4516,6 +4532,14 @@ static void zrangeGenericCommand(redisClient *c, int reverse) { robj *o; int start = atoi(c->argv[2]->ptr); int end = atoi(c->argv[3]->ptr); + int withscores = 0; + + if (c->argc == 5 && !strcasecmp(c->argv[4]->ptr,"withscores")) { + withscores = 1; + } else if (c->argc >= 5) { + addReply(c,shared.syntaxerr); + return; + } o = lookupKeyRead(c->db,c->argv[1]); if (o == NULL) { @@ -4558,12 +4582,15 @@ static void zrangeGenericCommand(redisClient *c, int reverse) { ln = ln->forward[0]; } - addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",rangelen)); + addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n", + withscores ? (rangelen*2) : rangelen)); for (j = 0; j < rangelen; j++) { ele = ln->obj; addReplyBulkLen(c,ele); addReply(c,ele); addReply(c,shared.crlf); + if (withscores) + addReplyDouble(c,ln->score); ln = reverse ? ln->backward : ln->forward[0]; } } @@ -4824,7 +4851,7 @@ static void sortCommand(redisClient *c) { /* Lookup the key to sort. It must be of the right types */ sortval = lookupKeyRead(c->db,c->argv[1]); if (sortval == NULL) { - addReply(c,shared.nokeyerr); + addReply(c,shared.nullmultibulk); return; } if (sortval->type != REDIS_SET && sortval->type != REDIS_LIST && @@ -5866,7 +5893,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; @@ -5995,7 +6023,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; @@ -6024,7 +6052,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; } @@ -6114,6 +6142,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;