From c937aa89b5835d12a1b5900beaa471908f3a236d Mon Sep 17 00:00:00 2001 From: antirez Date: Tue, 24 Mar 2009 13:37:32 +0100 Subject: [PATCH] Server replies now in the new format, test-redis.tcl and redis-cli modified accordingly --- redis-cli.c | 165 +++++++++++++++++++++--------------------- redis.c | 193 ++++++++++++++++++++++++------------------------- test-redis.tcl | 149 +++++++++++++++++++------------------- 3 files changed, 252 insertions(+), 255 deletions(-) diff --git a/redis-cli.c b/redis-cli.c index cd106684..6ced5abc 100644 --- a/redis-cli.c +++ b/redis-cli.c @@ -40,11 +40,6 @@ #define REDIS_CMD_INLINE 1 #define REDIS_CMD_BULK 2 -#define REDIS_CMD_INTREPLY 4 -#define REDIS_CMD_RETCODEREPLY 8 -#define REDIS_CMD_BULKREPLY 16 -#define REDIS_CMD_MULTIBULKREPLY 32 -#define REDIS_CMD_SINGLELINEREPLY 64 #define REDIS_NOTUSED(V) ((void) V) @@ -60,54 +55,56 @@ struct redisCommand { }; static struct redisCommand cmdTable[] = { - {"get",2,REDIS_CMD_INLINE|REDIS_CMD_BULKREPLY}, - {"set",3,REDIS_CMD_BULK|REDIS_CMD_RETCODEREPLY}, - {"setnx",3,REDIS_CMD_BULK|REDIS_CMD_INTREPLY}, - {"del",2,REDIS_CMD_INLINE|REDIS_CMD_INTREPLY}, - {"exists",2,REDIS_CMD_INLINE|REDIS_CMD_INTREPLY}, - {"incr",2,REDIS_CMD_INLINE|REDIS_CMD_INTREPLY}, - {"decr",2,REDIS_CMD_INLINE|REDIS_CMD_INTREPLY}, - {"rpush",3,REDIS_CMD_BULK|REDIS_CMD_RETCODEREPLY}, - {"lpush",3,REDIS_CMD_BULK|REDIS_CMD_RETCODEREPLY}, - {"rpop",2,REDIS_CMD_INLINE|REDIS_CMD_BULKREPLY}, - {"lpop",2,REDIS_CMD_INLINE|REDIS_CMD_BULKREPLY}, - {"llen",2,REDIS_CMD_INLINE|REDIS_CMD_INTREPLY}, - {"lindex",3,REDIS_CMD_INLINE|REDIS_CMD_BULKREPLY}, - {"lset",4,REDIS_CMD_BULK|REDIS_CMD_RETCODEREPLY}, - {"lrange",4,REDIS_CMD_INLINE|REDIS_CMD_MULTIBULKREPLY}, - {"ltrim",4,REDIS_CMD_INLINE|REDIS_CMD_RETCODEREPLY}, - {"lrem",4,REDIS_CMD_BULK|REDIS_CMD_INTREPLY}, - {"sadd",3,REDIS_CMD_BULK|REDIS_CMD_INTREPLY}, - {"srem",3,REDIS_CMD_BULK|REDIS_CMD_INTREPLY}, - {"sismember",3,REDIS_CMD_BULK|REDIS_CMD_INTREPLY}, - {"scard",2,REDIS_CMD_INLINE|REDIS_CMD_INTREPLY}, - {"sinter",-2,REDIS_CMD_INLINE|REDIS_CMD_MULTIBULKREPLY}, - {"sinterstore",-3,REDIS_CMD_INLINE|REDIS_CMD_RETCODEREPLY}, - {"smembers",2,REDIS_CMD_INLINE|REDIS_CMD_MULTIBULKREPLY}, - {"incrby",3,REDIS_CMD_INLINE|REDIS_CMD_INTREPLY}, - {"decrby",3,REDIS_CMD_INLINE|REDIS_CMD_INTREPLY}, - {"randomkey",1,REDIS_CMD_INLINE|REDIS_CMD_SINGLELINEREPLY}, - {"select",2,REDIS_CMD_INLINE|REDIS_CMD_RETCODEREPLY}, - {"move",3,REDIS_CMD_INLINE|REDIS_CMD_INTREPLY}, - {"rename",3,REDIS_CMD_INLINE|REDIS_CMD_RETCODEREPLY}, - {"renamenx",3,REDIS_CMD_INLINE|REDIS_CMD_INTREPLY}, - {"keys",2,REDIS_CMD_INLINE|REDIS_CMD_BULKREPLY}, - {"dbsize",1,REDIS_CMD_INLINE|REDIS_CMD_INTREPLY}, - {"ping",1,REDIS_CMD_INLINE|REDIS_CMD_RETCODEREPLY}, - {"echo",2,REDIS_CMD_BULK|REDIS_CMD_BULKREPLY}, - {"save",1,REDIS_CMD_INLINE|REDIS_CMD_RETCODEREPLY}, - {"bgsave",1,REDIS_CMD_INLINE|REDIS_CMD_RETCODEREPLY}, - {"shutdown",1,REDIS_CMD_INLINE|REDIS_CMD_RETCODEREPLY}, - {"lastsave",1,REDIS_CMD_INLINE|REDIS_CMD_INTREPLY}, - {"type",2,REDIS_CMD_INLINE|REDIS_CMD_SINGLELINEREPLY}, - {"flushdb",1,REDIS_CMD_INLINE|REDIS_CMD_RETCODEREPLY}, - {"flushall",1,REDIS_CMD_INLINE|REDIS_CMD_RETCODEREPLY}, - {"sort",-2,REDIS_CMD_INLINE|REDIS_CMD_MULTIBULKREPLY}, - {"info",1,REDIS_CMD_INLINE|REDIS_CMD_BULKREPLY}, - {"mget",-2,REDIS_CMD_INLINE|REDIS_CMD_MULTIBULKREPLY}, + {"get",2,REDIS_CMD_INLINE}, + {"set",3,REDIS_CMD_BULK}, + {"setnx",3,REDIS_CMD_BULK}, + {"del",2,REDIS_CMD_INLINE}, + {"exists",2,REDIS_CMD_INLINE}, + {"incr",2,REDIS_CMD_INLINE}, + {"decr",2,REDIS_CMD_INLINE}, + {"rpush",3,REDIS_CMD_BULK}, + {"lpush",3,REDIS_CMD_BULK}, + {"rpop",2,REDIS_CMD_INLINE}, + {"lpop",2,REDIS_CMD_INLINE}, + {"llen",2,REDIS_CMD_INLINE}, + {"lindex",3,REDIS_CMD_INLINE}, + {"lset",4,REDIS_CMD_BULK}, + {"lrange",4,REDIS_CMD_INLINE}, + {"ltrim",4,REDIS_CMD_INLINE}, + {"lrem",4,REDIS_CMD_BULK}, + {"sadd",3,REDIS_CMD_BULK}, + {"srem",3,REDIS_CMD_BULK}, + {"sismember",3,REDIS_CMD_BULK}, + {"scard",2,REDIS_CMD_INLINE}, + {"sinter",-2,REDIS_CMD_INLINE}, + {"sinterstore",-3,REDIS_CMD_INLINE}, + {"smembers",2,REDIS_CMD_INLINE}, + {"incrby",3,REDIS_CMD_INLINE}, + {"decrby",3,REDIS_CMD_INLINE}, + {"randomkey",1,REDIS_CMD_INLINE}, + {"select",2,REDIS_CMD_INLINE}, + {"move",3,REDIS_CMD_INLINE}, + {"rename",3,REDIS_CMD_INLINE}, + {"renamenx",3,REDIS_CMD_INLINE}, + {"keys",2,REDIS_CMD_INLINE}, + {"dbsize",1,REDIS_CMD_INLINE}, + {"ping",1,REDIS_CMD_INLINE}, + {"echo",2,REDIS_CMD_BULK}, + {"save",1,REDIS_CMD_INLINE}, + {"bgsave",1,REDIS_CMD_INLINE}, + {"shutdown",1,REDIS_CMD_INLINE}, + {"lastsave",1,REDIS_CMD_INLINE}, + {"type",2,REDIS_CMD_INLINE}, + {"flushdb",1,REDIS_CMD_INLINE}, + {"flushall",1,REDIS_CMD_INLINE}, + {"sort",-2,REDIS_CMD_INLINE}, + {"info",1,REDIS_CMD_INLINE}, + {"mget",-2,REDIS_CMD_INLINE}, {NULL,0,0} }; +static int cliReadReply(int fd); + static struct redisCommand *lookupCommand(char *name) { int j = 0; while(cmdTable[j].name != NULL) { @@ -150,38 +147,26 @@ static sds cliReadLine(int fd) { return sdstrim(line,"\r\n"); } -static int cliReadInlineReply(int fd, int type) { +static int cliReadSingleLineReply(int fd) { sds reply = cliReadLine(fd); if (reply == NULL) return 1; printf("%s\n", reply); - if (type == REDIS_CMD_SINGLELINEREPLY) return 0; - if (type == REDIS_CMD_INTREPLY) return atoi(reply) < 0; - if (type == REDIS_CMD_RETCODEREPLY) return reply[0] == '-'; return 0; } -static int cliReadBulkReply(int fd, int multibulk) { +static int cliReadBulkReply(int fd) { sds replylen = cliReadLine(fd); char *reply, crlf[2]; - int bulklen, error = 0; + int bulklen; if (replylen == NULL) return 1; - if (strcmp(replylen,"nil") == 0) { - sdsfree(replylen); - printf("(nil)\n"); - return 0; - } bulklen = atoi(replylen); - if (multibulk && bulklen == -1) { + if (bulklen == -1) { sdsfree(replylen); printf("(nil)"); return 0; } - if (bulklen < 0) { - bulklen = -bulklen; - error = 1; - } reply = zmalloc(bulklen); anetRead(fd,reply,bulklen); anetRead(fd,crlf,2); @@ -189,10 +174,10 @@ static int cliReadBulkReply(int fd, int multibulk) { zfree(reply); return 1; } - if (!multibulk && isatty(fileno(stdout)) && reply[bulklen-1] != '\n') + if (isatty(fileno(stdout)) && reply[bulklen-1] != '\n') printf("\n"); zfree(reply); - return error; + return 0; } static int cliReadMultiBulkReply(int fd) { @@ -200,21 +185,45 @@ static int cliReadMultiBulkReply(int fd) { int elements, c = 1; if (replylen == NULL) return 1; - if (strcmp(replylen,"nil") == 0) { + elements = atoi(replylen); + if (elements == -1) { sdsfree(replylen); printf("(nil)\n"); return 0; } - elements = atoi(replylen); + if (elements == 0) { + printf("(empty list or set)\n"); + } while(elements--) { printf("%d. ", c); - if (cliReadBulkReply(fd,1)) return 1; - printf("\n"); + if (cliReadReply(fd)) return 1; c++; } return 0; } +static int cliReadReply(int fd) { + char type; + + if (anetRead(fd,&type,1) <= 0) exit(1); + switch(type) { + case '-': + printf("(error) "); + cliReadSingleLineReply(fd); + return 1; + case '+': + case ':': + return cliReadSingleLineReply(fd); + case '$': + return cliReadBulkReply(fd); + case '*': + return cliReadMultiBulkReply(fd); + default: + printf("protocol error, got '%c' as reply type byte\n", type); + return 1; + } +} + static int cliSendCommand(int argc, char **argv) { struct redisCommand *rc = lookupCommand(argv[0]); int fd, j, retval = 0; @@ -247,17 +256,7 @@ static int cliSendCommand(int argc, char **argv) { cmd = sdscat(cmd,"\r\n"); } anetWrite(fd,cmd,sdslen(cmd)); - if (rc->flags & REDIS_CMD_INTREPLY) { - retval = cliReadInlineReply(fd,REDIS_CMD_INTREPLY); - } else if (rc->flags & REDIS_CMD_RETCODEREPLY) { - retval = cliReadInlineReply(fd,REDIS_CMD_RETCODEREPLY); - } else if (rc->flags & REDIS_CMD_SINGLELINEREPLY) { - retval = cliReadInlineReply(fd,REDIS_CMD_SINGLELINEREPLY); - } else if (rc->flags & REDIS_CMD_BULKREPLY) { - retval = cliReadBulkReply(fd,0); - } else if (rc->flags & REDIS_CMD_MULTIBULKREPLY) { - retval = cliReadMultiBulkReply(fd); - } + retval = cliReadReply(fd); if (retval) { close(fd); return retval; diff --git a/redis.c b/redis.c index 58b85606..5174b333 100644 --- a/redis.c +++ b/redis.c @@ -214,10 +214,10 @@ typedef struct _redisSortOperation { } redisSortOperation; struct sharedObjectsStruct { - robj *crlf, *ok, *err, *zerobulk, *nil, *zero, *one, *pong, *space, - *minus1, *minus2, *minus3, *minus4, - *wrongtypeerr, *nokeyerr, *wrongtypeerrbulk, *nokeyerrbulk, - *syntaxerr, *syntaxerrbulk, + robj *crlf, *ok, *err, *emptybulk, *czero, *cone, *pong, *space, + *colon, *minus1, *nullbulk, *nullmultibulk, + *emptymultibulk, *wrongtypeerr, *nokeyerr, *syntaxerr, *sameobjecterr, + *outofrangeerr, *plus, *select0, *select1, *select2, *select3, *select4, *select5, *select6, *select7, *select8, *select9; } shared; @@ -660,29 +660,28 @@ static void createSharedObjects(void) { shared.crlf = createObject(REDIS_STRING,sdsnew("\r\n")); shared.ok = createObject(REDIS_STRING,sdsnew("+OK\r\n")); shared.err = createObject(REDIS_STRING,sdsnew("-ERR\r\n")); - shared.zerobulk = createObject(REDIS_STRING,sdsnew("0\r\n\r\n")); - shared.nil = createObject(REDIS_STRING,sdsnew("nil\r\n")); - shared.zero = createObject(REDIS_STRING,sdsnew("0\r\n")); - shared.one = createObject(REDIS_STRING,sdsnew("1\r\n")); + shared.emptybulk = createObject(REDIS_STRING,sdsnew("$0\r\n\r\n")); + shared.czero = createObject(REDIS_STRING,sdsnew(":0\r\n")); + shared.cone = createObject(REDIS_STRING,sdsnew(":1\r\n")); + 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.minus1 = createObject(REDIS_STRING,sdsnew("-1\r\n")); - /* operation against key holding a value of the wrong type */ - shared.minus2 = createObject(REDIS_STRING,sdsnew("-2\r\n")); - /* src and dest objects are the same */ - shared.minus3 = createObject(REDIS_STRING,sdsnew("-3\r\n")); - /* out of range argument */ - shared.minus4 = createObject(REDIS_STRING,sdsnew("-4\r\n")); 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")); - shared.wrongtypeerrbulk = createObject(REDIS_STRING,sdscatprintf(sdsempty(),"%d\r\n%s",-sdslen(shared.wrongtypeerr->ptr)+2,shared.wrongtypeerr->ptr)); shared.nokeyerr = createObject(REDIS_STRING,sdsnew( "-ERR no such key\r\n")); - shared.nokeyerrbulk = createObject(REDIS_STRING,sdscatprintf(sdsempty(),"%d\r\n%s",-sdslen(shared.nokeyerr->ptr)+2,shared.nokeyerr->ptr)); shared.syntaxerr = createObject(REDIS_STRING,sdsnew( "-ERR syntax error\r\n")); - shared.syntaxerrbulk = createObject(REDIS_STRING,sdscatprintf(sdsempty(),"%d\r\n%s",-sdslen(shared.syntaxerr->ptr)+2,shared.syntaxerr->ptr)); + shared.sameobjecterr = createObject(REDIS_STRING,sdsnew( + "-ERR source and destination objects are the same\r\n")); + shared.outofrangeerr = createObject(REDIS_STRING,sdsnew( + "-ERR index out of range\r\n")); shared.space = createObject(REDIS_STRING,sdsnew(" ")); + shared.colon = createObject(REDIS_STRING,sdsnew(":")); + shared.plus = createObject(REDIS_STRING,sdsnew("+")); shared.select0 = createStringObject("select 0\r\n",10); shared.select1 = createStringObject("select 1\r\n",10); shared.select2 = createStringObject("select 2\r\n",10); @@ -1654,7 +1653,7 @@ static void pingCommand(redisClient *c) { } static void echoCommand(redisClient *c) { - addReplySds(c,sdscatprintf(sdsempty(),"%d\r\n", + addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n", (int)sdslen(c->argv[1]->ptr))); addReply(c,c->argv[1]); addReply(c,shared.crlf); @@ -1671,7 +1670,7 @@ static void setGenericCommand(redisClient *c, int nx) { dictReplace(c->dict,c->argv[1],c->argv[2]); incrRefCount(c->argv[2]); } else { - addReply(c,shared.zero); + addReply(c,shared.czero); return; } } else { @@ -1679,7 +1678,7 @@ static void setGenericCommand(redisClient *c, int nx) { incrRefCount(c->argv[2]); } server.dirty++; - addReply(c, nx ? shared.one : shared.ok); + addReply(c, nx ? shared.cone : shared.ok); } static void setCommand(redisClient *c) { @@ -1695,14 +1694,14 @@ static void getCommand(redisClient *c) { de = dictFind(c->dict,c->argv[1]); if (de == NULL) { - addReply(c,shared.nil); + addReply(c,shared.nullbulk); } else { robj *o = dictGetEntryVal(de); if (o->type != REDIS_STRING) { - addReply(c,shared.wrongtypeerrbulk); + addReply(c,shared.wrongtypeerr); } else { - addReplySds(c,sdscatprintf(sdsempty(),"%d\r\n",(int)sdslen(o->ptr))); + addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n",(int)sdslen(o->ptr))); addReply(c,o); addReply(c,shared.crlf); } @@ -1713,18 +1712,18 @@ static void mgetCommand(redisClient *c) { dictEntry *de; int j; - addReplySds(c,sdscatprintf(sdsempty(),"%d\r\n",c->argc-1)); + addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",c->argc-1)); for (j = 1; j < c->argc; j++) { de = dictFind(c->dict,c->argv[j]); if (de == NULL) { - addReply(c,shared.minus1); + addReply(c,shared.nullbulk); } else { robj *o = dictGetEntryVal(de); if (o->type != REDIS_STRING) { - addReply(c,shared.minus1); + addReply(c,shared.nullbulk); } else { - addReplySds(c,sdscatprintf(sdsempty(),"%d\r\n",(int)sdslen(o->ptr))); + addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n",(int)sdslen(o->ptr))); addReply(c,o); addReply(c,shared.crlf); } @@ -1762,6 +1761,7 @@ static void incrDecrCommand(redisClient *c, int incr) { incrRefCount(c->argv[1]); } server.dirty++; + addReply(c,shared.colon); addReply(c,o); addReply(c,shared.crlf); } @@ -1789,9 +1789,9 @@ static void decrbyCommand(redisClient *c) { static void delCommand(redisClient *c) { if (dictDelete(c->dict,c->argv[1]) == DICT_OK) { server.dirty++; - addReply(c,shared.one); + addReply(c,shared.cone); } else { - addReply(c,shared.zero); + addReply(c,shared.czero); } } @@ -1800,9 +1800,9 @@ static void existsCommand(redisClient *c) { de = dictFind(c->dict,c->argv[1]); if (de == NULL) - addReply(c,shared.zero); + addReply(c,shared.czero); else - addReply(c,shared.one); + addReply(c,shared.cone); } static void selectCommand(redisClient *c) { @@ -1822,6 +1822,7 @@ static void randomkeyCommand(redisClient *c) { if (de == NULL) { addReply(c,shared.crlf); } else { + addReply(c,shared.plus); addReply(c,dictGetEntryKey(de)); addReply(c,shared.crlf); } @@ -1852,18 +1853,18 @@ static void keysCommand(redisClient *c) { } } dictReleaseIterator(di); - lenobj->ptr = sdscatprintf(sdsempty(),"%lu\r\n",keyslen+(numkeys ? (numkeys-1) : 0)); + lenobj->ptr = sdscatprintf(sdsempty(),"$%lu\r\n",keyslen+(numkeys ? (numkeys-1) : 0)); addReply(c,shared.crlf); } static void dbsizeCommand(redisClient *c) { addReplySds(c, - sdscatprintf(sdsempty(),"%lu\r\n",dictGetHashTableUsed(c->dict))); + sdscatprintf(sdsempty(),":%lu\r\n",dictGetHashTableUsed(c->dict))); } static void lastsaveCommand(redisClient *c) { addReplySds(c, - sdscatprintf(sdsempty(),"%lu\r\n",server.lastsave)); + sdscatprintf(sdsempty(),":%lu\r\n",server.lastsave)); } static void typeCommand(redisClient *c) { @@ -1872,14 +1873,14 @@ static void typeCommand(redisClient *c) { de = dictFind(c->dict,c->argv[1]); if (de == NULL) { - type = "none"; + type = "+none"; } else { robj *o = dictGetEntryVal(de); switch(o->type) { - case REDIS_STRING: type = "string"; break; - case REDIS_LIST: type = "list"; break; - case REDIS_SET: type = "set"; break; + case REDIS_STRING: type = "+string"; break; + case REDIS_LIST: type = "+list"; break; + case REDIS_SET: type = "+set"; break; default: type = "unknown"; break; } } @@ -1927,19 +1928,13 @@ static void renameGenericCommand(redisClient *c, int nx) { /* To use the same key as src and dst is probably an error */ if (sdscmp(c->argv[1]->ptr,c->argv[2]->ptr) == 0) { - if (nx) - addReply(c,shared.minus3); - else - addReplySds(c,sdsnew("-ERR src and dest key are the same\r\n")); + addReply(c,shared.sameobjecterr); return; } de = dictFind(c->dict,c->argv[1]); if (de == NULL) { - if (nx) - addReply(c,shared.minus1); - else - addReply(c,shared.nokeyerr); + addReply(c,shared.nokeyerr); return; } o = dictGetEntryVal(de); @@ -1947,7 +1942,7 @@ static void renameGenericCommand(redisClient *c, int nx) { if (dictAdd(c->dict,c->argv[2],o) == DICT_ERR) { if (nx) { decrRefCount(o); - addReply(c,shared.zero); + addReply(c,shared.czero); return; } dictReplace(c->dict,c->argv[2],o); @@ -1956,7 +1951,7 @@ static void renameGenericCommand(redisClient *c, int nx) { } dictDelete(c->dict,c->argv[1]); server.dirty++; - addReply(c,nx ? shared.one : shared.ok); + addReply(c,nx ? shared.cone : shared.ok); } static void renameCommand(redisClient *c) { @@ -1977,7 +1972,7 @@ static void moveCommand(redisClient *c) { src = c->dict; srcid = c->dictid; if (selectDb(c,atoi(c->argv[2]->ptr)) == REDIS_ERR) { - addReply(c,shared.minus4); + addReply(c,shared.outofrangeerr); return; } dst = c->dict; @@ -1987,14 +1982,14 @@ static void moveCommand(redisClient *c) { /* If the user is moving using as target the same * DB as the source DB it is probably an error. */ if (src == dst) { - addReply(c,shared.minus3); + addReply(c,shared.sameobjecterr); return; } /* Check if the element exists and get a reference */ de = dictFind(c->dict,c->argv[1]); if (!de) { - addReply(c,shared.zero); + addReply(c,shared.czero); return; } @@ -2002,7 +1997,7 @@ static void moveCommand(redisClient *c) { key = dictGetEntryKey(de); o = dictGetEntryVal(de); if (dictAdd(dst,key,o) == DICT_ERR) { - addReply(c,shared.zero); + addReply(c,shared.czero); return; } incrRefCount(key); @@ -2011,7 +2006,7 @@ static void moveCommand(redisClient *c) { /* OK! key moved, free the entry in the source DB */ dictDelete(src,c->argv[1]); server.dirty++; - addReply(c,shared.one); + addReply(c,shared.cone); } /* =================================== Lists ================================ */ @@ -2064,15 +2059,15 @@ static void llenCommand(redisClient *c) { de = dictFind(c->dict,c->argv[1]); if (de == NULL) { - addReply(c,shared.zero); + addReply(c,shared.czero); return; } else { robj *o = dictGetEntryVal(de); if (o->type != REDIS_LIST) { - addReply(c,shared.minus2); + addReply(c,shared.wrongtypeerr); } else { l = o->ptr; - addReplySds(c,sdscatprintf(sdsempty(),"%d\r\n",listLength(l))); + addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",listLength(l))); } } } @@ -2083,22 +2078,22 @@ static void lindexCommand(redisClient *c) { de = dictFind(c->dict,c->argv[1]); if (de == NULL) { - addReply(c,shared.nil); + addReply(c,shared.nullbulk); } else { robj *o = dictGetEntryVal(de); if (o->type != REDIS_LIST) { - addReply(c,shared.wrongtypeerrbulk); + addReply(c,shared.wrongtypeerr); } else { list *list = o->ptr; listNode *ln; ln = listIndex(list, index); if (ln == NULL) { - addReply(c,shared.nil); + addReply(c,shared.nullbulk); } else { robj *ele = listNodeValue(ln); - addReplySds(c,sdscatprintf(sdsempty(),"%d\r\n",(int)sdslen(ele->ptr))); + addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n",(int)sdslen(ele->ptr))); addReply(c,ele); addReply(c,shared.crlf); } @@ -2124,7 +2119,7 @@ static void lsetCommand(redisClient *c) { ln = listIndex(list, index); if (ln == NULL) { - addReplySds(c,sdsnew("-ERR index out of range\r\n")); + addReply(c,shared.outofrangeerr); } else { robj *ele = listNodeValue(ln); @@ -2143,12 +2138,12 @@ static void popGenericCommand(redisClient *c, int where) { de = dictFind(c->dict,c->argv[1]); if (de == NULL) { - addReply(c,shared.nil); + addReply(c,shared.nullbulk); } else { robj *o = dictGetEntryVal(de); if (o->type != REDIS_LIST) { - addReply(c,shared.wrongtypeerrbulk); + addReply(c,shared.wrongtypeerr); } else { list *list = o->ptr; listNode *ln; @@ -2159,10 +2154,10 @@ static void popGenericCommand(redisClient *c, int where) { ln = listLast(list); if (ln == NULL) { - addReply(c,shared.nil); + addReply(c,shared.nullbulk); } else { robj *ele = listNodeValue(ln); - addReplySds(c,sdscatprintf(sdsempty(),"%d\r\n",(int)sdslen(ele->ptr))); + addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n",(int)sdslen(ele->ptr))); addReply(c,ele); addReply(c,shared.crlf); listDelNode(list,ln); @@ -2187,12 +2182,12 @@ static void lrangeCommand(redisClient *c) { de = dictFind(c->dict,c->argv[1]); if (de == NULL) { - addReply(c,shared.nil); + addReply(c,shared.nullmultibulk); } else { robj *o = dictGetEntryVal(de); if (o->type != REDIS_LIST) { - addReply(c,shared.wrongtypeerrbulk); + addReply(c,shared.wrongtypeerr); } else { list *list = o->ptr; listNode *ln; @@ -2209,7 +2204,7 @@ static void lrangeCommand(redisClient *c) { /* indexes sanity checks */ if (start > end || start >= llen) { /* Out of range start or start > end result in empty list */ - addReply(c,shared.zero); + addReply(c,shared.emptymultibulk); return; } if (end >= llen) end = llen-1; @@ -2217,10 +2212,10 @@ static void lrangeCommand(redisClient *c) { /* Return the result in form of a multi-bulk reply */ ln = listIndex(list, start); - addReplySds(c,sdscatprintf(sdsempty(),"%d\r\n",rangelen)); + addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",rangelen)); for (j = 0; j < rangelen; j++) { ele = listNodeValue(ln); - addReplySds(c,sdscatprintf(sdsempty(),"%d\r\n",(int)sdslen(ele->ptr))); + addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n",(int)sdslen(ele->ptr))); addReply(c,ele); addReply(c,shared.crlf); ln = ln->next; @@ -2290,7 +2285,7 @@ static void lremCommand(redisClient *c) { robj *o = dictGetEntryVal(de); if (o->type != REDIS_LIST) { - addReply(c,shared.minus2); + addReply(c,shared.wrongtypeerr); } else { list *list = o->ptr; listNode *ln, *next; @@ -2314,7 +2309,7 @@ static void lremCommand(redisClient *c) { } ln = next; } - addReplySds(c,sdscatprintf(sdsempty(),"%d\r\n",removed)); + addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",removed)); } } } @@ -2333,16 +2328,16 @@ static void saddCommand(redisClient *c) { } else { set = dictGetEntryVal(de); if (set->type != REDIS_SET) { - addReply(c,shared.minus2); + addReply(c,shared.wrongtypeerr); return; } } if (dictAdd(set->ptr,c->argv[2],NULL) == DICT_OK) { incrRefCount(c->argv[2]); server.dirty++; - addReply(c,shared.one); + addReply(c,shared.cone); } else { - addReply(c,shared.zero); + addReply(c,shared.czero); } } @@ -2351,20 +2346,20 @@ static void sremCommand(redisClient *c) { de = dictFind(c->dict,c->argv[1]); if (de == NULL) { - addReply(c,shared.zero); + addReply(c,shared.czero); } else { robj *set; set = dictGetEntryVal(de); if (set->type != REDIS_SET) { - addReply(c,shared.minus2); + addReply(c,shared.wrongtypeerr); return; } if (dictDelete(set->ptr,c->argv[2]) == DICT_OK) { server.dirty++; - addReply(c,shared.one); + addReply(c,shared.cone); } else { - addReply(c,shared.zero); + addReply(c,shared.czero); } } } @@ -2374,19 +2369,19 @@ static void sismemberCommand(redisClient *c) { de = dictFind(c->dict,c->argv[1]); if (de == NULL) { - addReply(c,shared.zero); + addReply(c,shared.czero); } else { robj *set; set = dictGetEntryVal(de); if (set->type != REDIS_SET) { - addReply(c,shared.minus2); + addReply(c,shared.wrongtypeerr); return; } if (dictFind(set->ptr,c->argv[2])) - addReply(c,shared.one); + addReply(c,shared.cone); else - addReply(c,shared.zero); + addReply(c,shared.czero); } } @@ -2396,15 +2391,15 @@ static void scardCommand(redisClient *c) { de = dictFind(c->dict,c->argv[1]); if (de == NULL) { - addReply(c,shared.zero); + addReply(c,shared.czero); return; } else { robj *o = dictGetEntryVal(de); if (o->type != REDIS_SET) { - addReply(c,shared.minus2); + addReply(c,shared.wrongtypeerr); } else { s = o->ptr; - addReplySds(c,sdscatprintf(sdsempty(),"%d\r\n", + addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n", dictGetHashTableUsed(s))); } } @@ -2431,13 +2426,13 @@ static void sinterGenericCommand(redisClient *c, robj **setskeys, int setsnum, r de = dictFind(c->dict,setskeys[j]); if (!de) { zfree(dv); - addReply(c,dstkey ? shared.nokeyerr : shared.nil); + addReply(c,shared.nokeyerr); return; } setobj = dictGetEntryVal(de); if (setobj->type != REDIS_SET) { zfree(dv); - addReply(c,dstkey ? shared.wrongtypeerr : shared.wrongtypeerrbulk); + addReply(c,shared.wrongtypeerr); return; } dv[j] = setobj->ptr; @@ -2479,7 +2474,7 @@ static void sinterGenericCommand(redisClient *c, robj **setskeys, int setsnum, r continue; /* at least one set does not contain the member */ ele = dictGetEntryKey(de); if (!dstkey) { - addReplySds(c,sdscatprintf(sdsempty(),"%d\r\n",sdslen(ele->ptr))); + addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n",sdslen(ele->ptr))); addReply(c,ele); addReply(c,shared.crlf); cardinality++; @@ -2491,7 +2486,7 @@ static void sinterGenericCommand(redisClient *c, robj **setskeys, int setsnum, r dictReleaseIterator(di); if (!dstkey) - lenobj->ptr = sdscatprintf(sdsempty(),"%d\r\n",cardinality); + lenobj->ptr = sdscatprintf(sdsempty(),"*%d\r\n",cardinality); else addReply(c,shared.ok); zfree(dv); @@ -2621,12 +2616,12 @@ static void sortCommand(redisClient *c) { /* Lookup the key to sort. It must be of the right types */ de = dictFind(c->dict,c->argv[1]); if (de == NULL) { - addReply(c,shared.nokeyerrbulk); + addReply(c,shared.nokeyerr); return; } sortval = dictGetEntryVal(de); if (sortval->type != REDIS_SET && sortval->type != REDIS_LIST) { - addReply(c,shared.wrongtypeerrbulk); + addReply(c,shared.wrongtypeerr); return; } @@ -2680,7 +2675,7 @@ static void sortCommand(redisClient *c) { } else { decrRefCount(sortval); listRelease(operations); - addReply(c,shared.syntaxerrbulk); + addReply(c,shared.syntaxerr); return; } j++; @@ -2761,11 +2756,11 @@ static void sortCommand(redisClient *c) { /* Send command output to the output buffer, performing the specified * GET/DEL/INCR/DECR operations if any. */ outputlen = getop ? getop*(end-start+1) : end-start+1; - addReplySds(c,sdscatprintf(sdsempty(),"%d\r\n",outputlen)); + addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",outputlen)); for (j = start; j <= end; j++) { listNode *ln = operations->head; if (!getop) { - addReplySds(c,sdscatprintf(sdsempty(),"%d\r\n", + addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n", sdslen(vector[j].obj->ptr))); addReply(c,vector[j].obj); addReply(c,shared.crlf); @@ -2779,7 +2774,7 @@ static void sortCommand(redisClient *c) { if (!val || val->type != REDIS_STRING) { addReply(c,shared.minus1); } else { - addReplySds(c,sdscatprintf(sdsempty(),"%d\r\n", + addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n", sdslen(val->ptr))); addReply(c,val); addReply(c,shared.crlf); @@ -2827,7 +2822,7 @@ static void infoCommand(redisClient *c) { uptime, uptime/(3600*24) ); - addReplySds(c,sdscatprintf(sdsempty(),"%d\r\n",sdslen(info))); + addReplySds(c,sdscatprintf(sdsempty(),"$%d\r\n",sdslen(info))); addReplySds(c,info); addReply(c,shared.crlf); } @@ -2930,7 +2925,7 @@ static void syncCommand(redisClient *c) { if (fd == -1 || fstat(fd,&sb) == -1) goto closeconn; len = sb.st_size; - snprintf(sizebuf,32,"%d\r\n",len); + snprintf(sizebuf,32,"$%d\r\n",len); if (syncWrite(c->fd,sizebuf,strlen(sizebuf),5) == -1) goto closeconn; while(len) { char buf[1024]; @@ -2982,7 +2977,7 @@ static int syncWithMaster(void) { strerror(errno)); return REDIS_ERR; } - dumpsize = atoi(buf); + dumpsize = atoi(buf+1); redisLog(REDIS_NOTICE,"Receiving %d bytes data dump from MASTER",dumpsize); /* Read the bulk write data on a temp file */ snprintf(tmpfile,256,"temp-%d.%ld.rdb",(int)time(NULL),(long int)random()); diff --git a/test-redis.tcl b/test-redis.tcl index 9bfab204..bc39f85d 100644 --- a/test-redis.tcl +++ b/test-redis.tcl @@ -124,16 +124,16 @@ proc main {server port} { puts -nonewline $fd "SET k1 4\r\nxyzk\r\nGET k1\r\nPING\r\n" flush $fd set res {} - append res [string match +OK* [redis_read_retcode $fd]] - append res [redis_bulk_read $fd] - append res [string match +PONG* [redis_read_retcode $fd]] + append res [string match OK* [redis_read_reply $fd]] + append res [redis_read_reply $fd] + append res [string match PONG* [redis_read_reply $fd]] format $res } {1xyzk1} test {Non existing command} { puts -nonewline $fd "foo\r\n" flush $fd - string match -ERR* [redis_read_retcode $fd] + string match ERR* [redis_read_reply $fd] } {1} test {Basic LPUSH, RPUSH, LLENGTH, LINDEX} { @@ -181,19 +181,19 @@ proc main {server port} { redis_del $fd mylist redis_set $fd mylist foobar redis_llen $fd mylist - } {-2} + } {ERR*} test {LINDEX against non-list value error} { redis_lindex $fd mylist 0 - } {*ERROR*} + } {ERR*} test {LPUSH against non-list value error} { redis_lpush $fd mylist 0 - } {-ERR*} + } {ERR*} test {RPUSH against non-list value error} { redis_rpush $fd mylist 0 - } {-ERR*} + } {ERR*} test {RENAME basic usage} { redis_set $fd mykey hello @@ -236,11 +236,11 @@ proc main {server port} { test {RENAME against non existing source key} { redis_rename $fd nokey foobar - } {-ERR*} + } {ERR*} test {RENAME where source and dest key is the same} { redis_rename $fd mykey mykey - } {-ERR*} + } {ERR*} test {DEL all keys again (DB 0)} { foreach key [redis_keys $fd *] { @@ -309,7 +309,7 @@ proc main {server port} { test {LPOP against non list value} { redis_set $fd notalist foo redis_lpop $fd notalist - } {*ERROR*against*} + } {ERR*kind*} test {Mass LPUSH/LPOP} { set sum 0 @@ -363,16 +363,16 @@ proc main {server port} { test {LSET out of range index} { redis_lset $fd mylist 10 foo - } {-ERR*range*} + } {ERR*range*} test {LSET against non existing key} { redis_lset $fd nosuchkey 10 foo - } {-ERR*key*} + } {ERR*key*} test {LSET against non list value} { redis_set $fd nolist foobar redis_lset $fd nolist 0 foo - } {-ERR*value*} + } {ERR*value*} test {SADD, SCARD, SISMEMBER, SMEMBERS basics} { redis_sadd $fd myset foo @@ -391,7 +391,7 @@ proc main {server port} { test {SADD against non set} { redis_sadd $fd mylist foo - } {-2} + } {ERR*kind*} test {SREM basics} { redis_sadd $fd myset ciao @@ -431,7 +431,7 @@ proc main {server port} { redis_set $fd myemptykey {} redis_set $fd mynormalkey {blablablba} redis_save $fd - } {+OK} + } {OK} test {Create a random list} { set tosort {} @@ -606,221 +606,224 @@ proc redis_readnl {fd len} { return $buf } -proc redis_bulk_read {fd {multi 0}} { - set count [redis_read_integer $fd] - if {$count eq {nil}} return {} - if {$multi && $count == -1} return {} - set len [expr {abs($count)}] - set buf [redis_readnl $fd $len] - if {$count < 0} {return "***ERROR*** $buf"} +proc redis_bulk_read {fd} { + set count [redis_read_line $fd] + if {$count == -1} return {} + set buf [redis_readnl $fd $count] return $buf } proc redis_multi_bulk_read fd { - set count [redis_read_integer $fd] - if {$count eq {nil}} return {} - if {$count < 0} { - set len [expr {abs($count)}] - set buf [redis_readnl $fd $len] - return "***ERROR*** $buf" - } + set count [redis_read_line $fd] + if {$count == -1} return {} set l {} for {set i 0} {$i < $count} {incr i} { - lappend l [redis_bulk_read $fd 1] + lappend l [redis_read_reply $fd] } return $l } -proc redis_read_retcode fd { - set retcode [string trim [gets $fd]] - # puts "S: $retcode" - return $retcode +proc redis_read_line fd { + string trim [gets $fd] } -proc redis_read_integer fd { - string trim [gets $fd] +proc redis_read_reply fd { + set type [read $fd 1] + if {$type eq {:}} { + redis_read_line $fd + } elseif {$type eq {-}} { + redis_read_line $fd + } elseif {$type eq {+}} { + redis_read_line $fd + } elseif {$type eq {$}} { + redis_bulk_read $fd + } elseif {$type eq {*}} { + redis_multi_bulk_read $fd + } else { + error "Bad protocol: $type as initial reply byte" + } } ### Actual API ### proc redis_set {fd key val} { redis_writenl $fd "set $key [string length $val]\r\n$val" - redis_read_retcode $fd + redis_read_reply $fd } proc redis_setnx {fd key val} { redis_writenl $fd "setnx $key [string length $val]\r\n$val" - redis_read_integer $fd + redis_read_reply $fd } proc redis_get {fd key} { redis_writenl $fd "get $key" - redis_bulk_read $fd + redis_read_reply $fd } proc redis_select {fd id} { redis_writenl $fd "select $id" - redis_read_retcode $fd + redis_read_reply $fd } proc redis_move {fd key id} { redis_writenl $fd "move $key $id" - redis_read_integer $fd + redis_read_reply $fd } proc redis_del {fd key} { redis_writenl $fd "del $key" - redis_read_integer $fd + redis_read_reply $fd } proc redis_keys {fd pattern} { redis_writenl $fd "keys $pattern" - split [redis_bulk_read $fd] + split [redis_read_reply $fd] } proc redis_dbsize {fd} { redis_writenl $fd "dbsize" - redis_read_integer $fd + redis_read_reply $fd } proc redis_incr {fd key} { redis_writenl $fd "incr $key" - redis_read_integer $fd + redis_read_reply $fd } proc redis_decr {fd key} { redis_writenl $fd "decr $key" - redis_read_integer $fd + redis_read_reply $fd } proc redis_exists {fd key} { redis_writenl $fd "exists $key" - redis_read_integer $fd + redis_read_reply $fd } proc redis_lpush {fd key val} { redis_writenl $fd "lpush $key [string length $val]\r\n$val" - redis_read_retcode $fd + redis_read_reply $fd } proc redis_rpush {fd key val} { redis_writenl $fd "rpush $key [string length $val]\r\n$val" - redis_read_retcode $fd + redis_read_reply $fd } proc redis_llen {fd key} { redis_writenl $fd "llen $key" - redis_read_integer $fd + redis_read_reply $fd } proc redis_scard {fd key} { redis_writenl $fd "scard $key" - redis_read_integer $fd + redis_read_reply $fd } proc redis_lindex {fd key index} { redis_writenl $fd "lindex $key $index" - redis_bulk_read $fd + redis_read_reply $fd } proc redis_lrange {fd key first last} { redis_writenl $fd "lrange $key $first $last" - redis_multi_bulk_read $fd + redis_read_reply $fd } proc redis_mget {fd args} { redis_writenl $fd "mget [join $args]" - redis_multi_bulk_read $fd + redis_read_reply $fd } proc redis_sort {fd key {params {}}} { redis_writenl $fd "sort $key $params" - redis_multi_bulk_read $fd + redis_read_reply $fd } proc redis_ltrim {fd key first last} { redis_writenl $fd "ltrim $key $first $last" - redis_read_retcode $fd + redis_read_reply $fd } proc redis_rename {fd key1 key2} { redis_writenl $fd "rename $key1 $key2" - redis_read_retcode $fd + redis_read_reply $fd } proc redis_renamenx {fd key1 key2} { redis_writenl $fd "renamenx $key1 $key2" - redis_read_integer $fd + redis_read_reply $fd } proc redis_lpop {fd key} { redis_writenl $fd "lpop $key" - redis_bulk_read $fd + redis_read_reply $fd } proc redis_rpop {fd key} { redis_writenl $fd "rpop $key" - redis_bulk_read $fd + redis_read_reply $fd } proc redis_lset {fd key index val} { redis_writenl $fd "lset $key $index [string length $val]\r\n$val" - redis_read_retcode $fd + redis_read_reply $fd } proc redis_sadd {fd key val} { redis_writenl $fd "sadd $key [string length $val]\r\n$val" - redis_read_integer $fd + redis_read_reply $fd } proc redis_srem {fd key val} { redis_writenl $fd "srem $key [string length $val]\r\n$val" - redis_read_integer $fd + redis_read_reply $fd } proc redis_sismember {fd key val} { redis_writenl $fd "sismember $key [string length $val]\r\n$val" - redis_read_integer $fd + redis_read_reply $fd } proc redis_sinter {fd args} { redis_writenl $fd "sinter [join $args]" - redis_multi_bulk_read $fd + redis_read_reply $fd } proc redis_sinterstore {fd args} { redis_writenl $fd "sinterstore [join $args]" - redis_read_retcode $fd + redis_read_reply $fd } proc redis_smembers {fd key} { redis_writenl $fd "smembers $key" - redis_multi_bulk_read $fd + redis_read_reply $fd } proc redis_echo {fd str} { redis_writenl $fd "echo [string length $str]\r\n$str" - redis_writenl $fd "smembers $key" + redis_read_reply $fd } proc redis_save {fd} { redis_writenl $fd "save" - redis_read_retcode $fd + redis_read_reply $fd } proc redis_flushall {fd} { redis_writenl $fd "flushall" - redis_read_retcode $fd + redis_read_reply $fd } proc redis_flushdb {fd} { redis_writenl $fd "flushdb" - redis_read_retcode $fd + redis_read_reply $fd } proc redis_lrem {fd key count val} { redis_writenl $fd "lrem $key $count [string length $val]\r\n$val" - redis_read_integer $fd + redis_read_reply $fd } proc stress {} { -- 2.45.2