merge conflict resolved

This commit is contained in:
antirez
2010-10-28 22:59:47 +02:00
21 changed files with 539 additions and 473 deletions

View File

@ -132,7 +132,7 @@ dep:
$(CC) -MM *.c
test:
(cd ..; tclsh8.5 tests/test_helper.tcl --tags "${TAGS}")
(cd ..; tclsh8.5 tests/test_helper.tcl --tags "${TAGS}" --file "${FILE}")
bench:
./redis-benchmark

View File

@ -266,9 +266,6 @@ int loadAppendOnlyFile(char *filename) {
redisLog(REDIS_WARNING,"Unknown command '%s' reading the append only file", argv[0]->ptr);
exit(1);
}
/* Try object encoding */
if (cmd->flags & REDIS_CMD_BULK)
argv[argc-1] = tryObjectEncoding(argv[argc-1]);
/* Run the command in the context of a fake client */
fakeClient->argc = argc;
fakeClient->argv = argv;

View File

@ -246,8 +246,11 @@ loaderr:
*----------------------------------------------------------------------------*/
void configSetCommand(redisClient *c) {
robj *o = getDecodedObject(c->argv[3]);
robj *o;
long long ll;
redisAssert(c->argv[2]->encoding == REDIS_ENCODING_RAW);
redisAssert(c->argv[3]->encoding == REDIS_ENCODING_RAW);
o = c->argv[3];
if (!strcasecmp(c->argv[2]->ptr,"dbfilename")) {
zfree(server.dbfilename);
@ -312,7 +315,6 @@ void configSetCommand(redisClient *c) {
if (startAppendOnly() == REDIS_ERR) {
addReplyError(c,
"Unable to turn on AOF. Check server logs.");
decrRefCount(o);
return;
}
}
@ -354,10 +356,8 @@ void configSetCommand(redisClient *c) {
} else {
addReplyErrorFormat(c,"Unsupported CONFIG parameter: %s",
(char*)c->argv[2]->ptr);
decrRefCount(o);
return;
}
decrRefCount(o);
addReply(c,shared.ok);
return;
@ -365,15 +365,15 @@ badfmt: /* Bad format errors */
addReplyErrorFormat(c,"Invalid argument '%s' for CONFIG SET '%s'",
(char*)o->ptr,
(char*)c->argv[2]->ptr);
decrRefCount(o);
}
void configGetCommand(redisClient *c) {
robj *o = getDecodedObject(c->argv[2]);
robj *o = c->argv[2];
void *replylen = addDeferredMultiBulkLength(c);
char *pattern = o->ptr;
char buf[128];
int matches = 0;
redisAssert(o->encoding == REDIS_ENCODING_RAW);
if (stringmatch(pattern,"dbfilename",0)) {
addReplyBulkCString(c,"dbfilename");
@ -462,7 +462,6 @@ void configGetCommand(redisClient *c) {
sdsfree(buf);
matches++;
}
decrRefCount(o);
setDeferredMultiBulkLength(c,replylen,matches*2);
}

View File

@ -28,13 +28,11 @@ redisClient *createClient(int fd) {
selectDb(c,0);
c->fd = fd;
c->querybuf = sdsempty();
c->newline = NULL;
c->reqtype = 0;
c->argc = 0;
c->argv = NULL;
c->multibulklen = 0;
c->bulklen = -1;
c->multibulk = 0;
c->mbargc = 0;
c->mbargv = NULL;
c->sentlen = 0;
c->flags = 0;
c->lastinteraction = time(NULL);
@ -57,7 +55,12 @@ redisClient *createClient(int fd) {
return c;
}
/* Set the event loop to listen for write events on the client's socket.
* Typically gets called every time a reply is built. */
int _installWriteEvent(redisClient *c) {
/* When CLOSE_AFTER_REPLY is set, no more replies may be added! */
redisAssert(!(c->flags & REDIS_CLOSE_AFTER_REPLY));
if (c->fd <= 0) return REDIS_ERR;
if (c->bufpos == 0 && listLength(c->reply) == 0 &&
(c->replstate == REDIS_REPL_NONE ||
@ -374,13 +377,9 @@ void acceptHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
static void freeClientArgv(redisClient *c) {
int j;
for (j = 0; j < c->argc; j++)
decrRefCount(c->argv[j]);
for (j = 0; j < c->mbargc; j++)
decrRefCount(c->mbargv[j]);
c->argc = 0;
c->mbargc = 0;
}
void freeClient(redisClient *c) {
@ -461,7 +460,6 @@ void freeClient(redisClient *c) {
}
/* Release memory */
zfree(c->argv);
zfree(c->mbargv);
freeClientMultiState(c);
zfree(c);
}
@ -546,6 +544,9 @@ void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) {
if (listLength(c->reply) == 0) {
c->sentlen = 0;
aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
/* Close connection after entire reply has been sent. */
if (c->flags & REDIS_CLOSE_AFTER_REPLY) freeClient(c);
}
}
@ -630,9 +631,9 @@ void sendReplyToClientWritev(aeEventLoop *el, int fd, void *privdata, int mask)
/* resetClient prepare the client to process the next command */
void resetClient(redisClient *c) {
freeClientArgv(c);
c->reqtype = 0;
c->multibulklen = 0;
c->bulklen = -1;
c->multibulk = 0;
c->newline = NULL;
}
void closeTimedoutClients(void) {
@ -663,90 +664,172 @@ void closeTimedoutClients(void) {
}
}
void processInputBuffer(redisClient *c) {
int seeknewline = 0;
int processInlineBuffer(redisClient *c) {
char *newline = strstr(c->querybuf,"\r\n");
int argc, j;
sds *argv;
size_t querylen;
again:
/* Before to process the input buffer, make sure the client is not
* waitig for a blocking operation such as BLPOP. Note that the first
* iteration the client is never blocked, otherwise the processInputBuffer
* would not be called at all, but after the execution of the first commands
* in the input buffer the client may be blocked, and the "goto again"
* will try to reiterate. The following line will make it return asap. */
if (c->flags & REDIS_BLOCKED || c->flags & REDIS_IO_WAIT) return;
/* Nothing to do without a \r\n */
if (newline == NULL)
return REDIS_ERR;
if (seeknewline && c->bulklen == -1) c->newline = strchr(c->querybuf,'\n');
seeknewline = 1;
if (c->bulklen == -1) {
/* Read the first line of the query */
size_t querylen;
/* Split the input buffer up to the \r\n */
querylen = newline-(c->querybuf);
argv = sdssplitlen(c->querybuf,querylen," ",1,&argc);
if (c->newline) {
char *p = c->newline;
sds query, *argv;
int argc, j;
/* Leave data after the first line of the query in the buffer */
c->querybuf = sdsrange(c->querybuf,querylen+2,-1);
c->newline = NULL;
query = c->querybuf;
c->querybuf = sdsempty();
querylen = 1+(p-(query));
if (sdslen(query) > querylen) {
/* leave data after the first line of the query in the buffer */
c->querybuf = sdscatlen(c->querybuf,query+querylen,sdslen(query)-querylen);
}
*p = '\0'; /* remove "\n" */
if (*(p-1) == '\r') *(p-1) = '\0'; /* and "\r" if any */
sdsupdatelen(query);
/* Setup argv array on client structure */
if (c->argv) zfree(c->argv);
c->argv = zmalloc(sizeof(robj*)*argc);
/* Now we can split the query in arguments */
argv = sdssplitlen(query,sdslen(query)," ",1,&argc);
sdsfree(query);
if (c->argv) zfree(c->argv);
c->argv = zmalloc(sizeof(robj*)*argc);
for (j = 0; j < argc; j++) {
if (sdslen(argv[j])) {
c->argv[c->argc] = createObject(REDIS_STRING,argv[j]);
c->argc++;
} else {
sdsfree(argv[j]);
}
}
zfree(argv);
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_VERBOSE, "Client protocol error");
freeClient(c);
return;
}
} else {
/* Bulk read handling. Note that if we are at this point
the client already sent a command terminated with a newline,
we are reading the bulk data that is actually the last
argument of the command. */
int qbl = sdslen(c->querybuf);
if (c->bulklen <= qbl) {
/* Copy everything but the final CRLF as final argument */
c->argv[c->argc] = createStringObject(c->querybuf,c->bulklen-2);
/* Create redis objects for all arguments. */
for (c->argc = 0, j = 0; j < argc; j++) {
if (sdslen(argv[j])) {
c->argv[c->argc] = createObject(REDIS_STRING,argv[j]);
c->argc++;
c->querybuf = sdsrange(c->querybuf,c->bulklen,-1);
/* Process the command. If the client is still valid after
* the processing and there is more data in the buffer
* try to parse it. */
if (processCommand(c) && sdslen(c->querybuf)) goto again;
return;
} else {
sdsfree(argv[j]);
}
}
zfree(argv);
return REDIS_OK;
}
/* Helper function. Trims query buffer to make the function that processes
* multi bulk requests idempotent. */
static void setProtocolError(redisClient *c, int pos) {
c->flags |= REDIS_CLOSE_AFTER_REPLY;
c->querybuf = sdsrange(c->querybuf,pos,-1);
}
int processMultibulkBuffer(redisClient *c) {
char *newline = NULL;
char *eptr;
int pos = 0, tolerr;
long bulklen;
if (c->multibulklen == 0) {
/* The client should have been reset */
redisAssert(c->argc == 0);
/* Multi bulk length cannot be read without a \r\n */
newline = strstr(c->querybuf,"\r\n");
if (newline == NULL)
return REDIS_ERR;
/* We know for sure there is a whole line since newline != NULL,
* so go ahead and find out the multi bulk length. */
redisAssert(c->querybuf[0] == '*');
c->multibulklen = strtol(c->querybuf+1,&eptr,10);
pos = (newline-c->querybuf)+2;
if (c->multibulklen <= 0) {
c->querybuf = sdsrange(c->querybuf,pos,-1);
return REDIS_OK;
} else if (c->multibulklen > 1024*1024) {
addReplyError(c,"Protocol error: invalid multibulk length");
setProtocolError(c,pos);
return REDIS_ERR;
}
/* Setup argv array on client structure */
if (c->argv) zfree(c->argv);
c->argv = zmalloc(sizeof(robj*)*c->multibulklen);
/* Search new newline */
newline = strstr(c->querybuf+pos,"\r\n");
}
redisAssert(c->multibulklen > 0);
while(c->multibulklen) {
/* Read bulk length if unknown */
if (c->bulklen == -1) {
newline = strstr(c->querybuf+pos,"\r\n");
if (newline != NULL) {
if (c->querybuf[pos] != '$') {
addReplyErrorFormat(c,
"Protocol error: expected '$', got '%c'",
c->querybuf[pos]);
setProtocolError(c,pos);
return REDIS_ERR;
}
bulklen = strtol(c->querybuf+pos+1,&eptr,10);
tolerr = (eptr[0] != '\r');
if (tolerr || bulklen == LONG_MIN || bulklen == LONG_MAX ||
bulklen < 0 || bulklen > 1024*1024*1024)
{
addReplyError(c,"Protocol error: invalid bulk length");
setProtocolError(c,pos);
return REDIS_ERR;
}
pos += eptr-(c->querybuf+pos)+2;
c->bulklen = bulklen;
} else {
/* No newline in current buffer, so wait for more data */
break;
}
}
/* Read bulk argument */
if (sdslen(c->querybuf)-pos < (unsigned)(c->bulklen+2)) {
/* Not enough data (+2 == trailing \r\n) */
break;
} else {
c->argv[c->argc++] = createStringObject(c->querybuf+pos,c->bulklen);
pos += c->bulklen+2;
c->bulklen = -1;
c->multibulklen--;
}
}
/* Trim to pos */
c->querybuf = sdsrange(c->querybuf,pos,-1);
/* We're done when c->multibulk == 0 */
if (c->multibulklen == 0) {
return REDIS_OK;
}
return REDIS_ERR;
}
void processInputBuffer(redisClient *c) {
/* Keep processing while there is something in the input buffer */
while(sdslen(c->querybuf)) {
/* Immediately abort if the client is in the middle of something. */
if (c->flags & REDIS_BLOCKED || c->flags & REDIS_IO_WAIT) return;
/* REDIS_CLOSE_AFTER_REPLY closes the connection once the reply is
* written to the client. Make sure to not let the reply grow after
* this flag has been set (i.e. don't process more commands). */
if (c->flags & REDIS_CLOSE_AFTER_REPLY) return;
/* Determine request type when unknown. */
if (!c->reqtype) {
if (c->querybuf[0] == '*') {
c->reqtype = REDIS_REQ_MULTIBULK;
} else {
c->reqtype = REDIS_REQ_INLINE;
}
}
if (c->reqtype == REDIS_REQ_INLINE) {
if (processInlineBuffer(c) != REDIS_OK) break;
} else if (c->reqtype == REDIS_REQ_MULTIBULK) {
if (processMultibulkBuffer(c) != REDIS_OK) break;
} else {
redisPanic("Unknown request type");
}
/* Multibulk processing could see a <= 0 length. */
if (c->argc == 0) {
resetClient(c);
} else {
/* Only reset the client when the command was executed. */
if (processCommand(c) == REDIS_OK)
resetClient(c);
}
}
}
@ -773,14 +856,8 @@ void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
return;
}
if (nread) {
size_t oldlen = sdslen(c->querybuf);
c->querybuf = sdscatlen(c->querybuf, buf, nread);
c->querybuf = sdscatlen(c->querybuf,buf,nread);
c->lastinteraction = time(NULL);
/* Scan this new piece of the query for the newline. We do this
* here in order to make sure we perform this scan just one time
* per piece of buffer, leading to an O(N) scan instead of O(N*N) */
if (c->bulklen == -1 && c->newline == NULL)
c->newline = strchr(c->querybuf+oldlen,'\n');
} else {
return;
}

View File

@ -575,10 +575,28 @@ int main(int argc, char **argv) {
aeMain(config.el);
endBenchmark();
prepareForBenchmark("MSET (10 keys, multi bulk)");
c = createClient();
if (!c) exit(1);
c->obuf = sdscatprintf(c->obuf,"*%d\r\n$4\r\nMSET\r\n", 11);
{
int i;
char *data = zmalloc(config.datasize+2);
memset(data,'x',config.datasize);
for (i = 0; i < 10; i++) {
c->obuf = sdscatprintf(c->obuf,"$%d\r\n%s\r\n",config.datasize,data);
}
zfree(data);
}
prepareClientForReply(c,REPLY_RETCODE);
createMissingClients(c);
aeMain(config.el);
endBenchmark();
prepareForBenchmark("SET");
c = createClient();
if (!c) exit(1);
c->obuf = sdscatprintf(c->obuf,"SET foo_rand000000000000 %d\r\n",config.datasize);
c->obuf = sdscat(c->obuf,"SET foo_rand000000000000 ");
{
char *data = zmalloc(config.datasize+2);
memset(data,'x',config.datasize);
@ -612,7 +630,7 @@ int main(int argc, char **argv) {
prepareForBenchmark("LPUSH");
c = createClient();
if (!c) exit(1);
c->obuf = sdscat(c->obuf,"LPUSH mylist 3\r\nbar\r\n");
c->obuf = sdscat(c->obuf,"LPUSH mylist bar\r\n");
prepareClientForReply(c,REPLY_INT);
createMissingClients(c);
aeMain(config.el);
@ -630,7 +648,7 @@ int main(int argc, char **argv) {
prepareForBenchmark("SADD");
c = createClient();
if (!c) exit(1);
c->obuf = sdscat(c->obuf,"SADD myset 24\r\ncounter_rand000000000000\r\n");
c->obuf = sdscat(c->obuf,"SADD myset counter_rand000000000000\r\n");
prepareClientForReply(c,REPLY_RETCODE);
createMissingClients(c);
aeMain(config.el);
@ -648,7 +666,7 @@ int main(int argc, char **argv) {
prepareForBenchmark("LPUSH (again, in order to bench LRANGE)");
c = createClient();
if (!c) exit(1);
c->obuf = sdscat(c->obuf,"LPUSH mylist 3\r\nbar\r\n");
c->obuf = sdscat(c->obuf,"LPUSH mylist bar\r\n");
prepareClientForReply(c,REPLY_RETCODE);
createMissingClients(c);
aeMain(config.el);

View File

@ -45,10 +45,6 @@
#include "zmalloc.h"
#include "linenoise.h"
#define REDIS_CMD_INLINE 1
#define REDIS_CMD_BULK 2
#define REDIS_CMD_MULTIBULK 4
#define REDIS_NOTUSED(V) ((void) V)
static struct config {

View File

@ -69,120 +69,120 @@ double R_Zero, R_PosInf, R_NegInf, R_Nan;
struct redisServer server; /* server global state */
struct redisCommand *commandTable;
struct redisCommand readonlyCommandTable[] = {
{"get",getCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
{"set",setCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,0,0,0},
{"setnx",setnxCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,0,0,0},
{"setex",setexCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,0,0,0},
{"append",appendCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
{"substr",substrCommand,4,REDIS_CMD_INLINE,NULL,1,1,1},
{"strlen",strlenCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
{"del",delCommand,-2,REDIS_CMD_INLINE,NULL,0,0,0},
{"exists",existsCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
{"incr",incrCommand,2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,1,1},
{"decr",decrCommand,2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,1,1},
{"mget",mgetCommand,-2,REDIS_CMD_INLINE,NULL,1,-1,1},
{"rpush",rpushCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
{"lpush",lpushCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
{"rpushx",rpushxCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
{"lpushx",lpushxCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
{"linsert",linsertCommand,5,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
{"rpop",rpopCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
{"lpop",lpopCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
{"brpop",brpopCommand,-3,REDIS_CMD_INLINE,NULL,1,1,1},
{"blpop",blpopCommand,-3,REDIS_CMD_INLINE,NULL,1,1,1},
{"llen",llenCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
{"lindex",lindexCommand,3,REDIS_CMD_INLINE,NULL,1,1,1},
{"lset",lsetCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
{"lrange",lrangeCommand,4,REDIS_CMD_INLINE,NULL,1,1,1},
{"ltrim",ltrimCommand,4,REDIS_CMD_INLINE,NULL,1,1,1},
{"lrem",lremCommand,4,REDIS_CMD_BULK,NULL,1,1,1},
{"rpoplpush",rpoplpushcommand,3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,2,1},
{"sadd",saddCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
{"srem",sremCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
{"smove",smoveCommand,4,REDIS_CMD_BULK,NULL,1,2,1},
{"sismember",sismemberCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
{"scard",scardCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
{"spop",spopCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
{"srandmember",srandmemberCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
{"sinter",sinterCommand,-2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,-1,1},
{"sinterstore",sinterstoreCommand,-3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,2,-1,1},
{"sunion",sunionCommand,-2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,-1,1},
{"sunionstore",sunionstoreCommand,-3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,2,-1,1},
{"sdiff",sdiffCommand,-2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,-1,1},
{"sdiffstore",sdiffstoreCommand,-3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,2,-1,1},
{"smembers",sinterCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
{"zadd",zaddCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
{"zincrby",zincrbyCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
{"zrem",zremCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
{"zremrangebyscore",zremrangebyscoreCommand,4,REDIS_CMD_INLINE,NULL,1,1,1},
{"zremrangebyrank",zremrangebyrankCommand,4,REDIS_CMD_INLINE,NULL,1,1,1},
{"zunionstore",zunionstoreCommand,-4,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,zunionInterBlockClientOnSwappedKeys,0,0,0},
{"zinterstore",zinterstoreCommand,-4,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,zunionInterBlockClientOnSwappedKeys,0,0,0},
{"zrange",zrangeCommand,-4,REDIS_CMD_INLINE,NULL,1,1,1},
{"zrangebyscore",zrangebyscoreCommand,-4,REDIS_CMD_INLINE,NULL,1,1,1},
{"zrevrangebyscore",zrevrangebyscoreCommand,-4,REDIS_CMD_INLINE,NULL,1,1,1},
{"zcount",zcountCommand,4,REDIS_CMD_INLINE,NULL,1,1,1},
{"zrevrange",zrevrangeCommand,-4,REDIS_CMD_INLINE,NULL,1,1,1},
{"zcard",zcardCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
{"zscore",zscoreCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
{"zrank",zrankCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
{"zrevrank",zrevrankCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
{"hset",hsetCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
{"hsetnx",hsetnxCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
{"hget",hgetCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
{"hmset",hmsetCommand,-4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
{"hmget",hmgetCommand,-3,REDIS_CMD_BULK,NULL,1,1,1},
{"hincrby",hincrbyCommand,4,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,1,1},
{"hdel",hdelCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
{"hlen",hlenCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
{"hkeys",hkeysCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
{"hvals",hvalsCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
{"hgetall",hgetallCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
{"hexists",hexistsCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
{"incrby",incrbyCommand,3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,1,1},
{"decrby",decrbyCommand,3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,1,1},
{"getset",getsetCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
{"mset",msetCommand,-3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,-1,2},
{"msetnx",msetnxCommand,-3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,-1,2},
{"randomkey",randomkeyCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
{"select",selectCommand,2,REDIS_CMD_INLINE,NULL,0,0,0},
{"move",moveCommand,3,REDIS_CMD_INLINE,NULL,1,1,1},
{"rename",renameCommand,3,REDIS_CMD_INLINE,NULL,1,1,1},
{"renamenx",renamenxCommand,3,REDIS_CMD_INLINE,NULL,1,1,1},
{"expire",expireCommand,3,REDIS_CMD_INLINE,NULL,0,0,0},
{"expireat",expireatCommand,3,REDIS_CMD_INLINE,NULL,0,0,0},
{"keys",keysCommand,2,REDIS_CMD_INLINE,NULL,0,0,0},
{"dbsize",dbsizeCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
{"auth",authCommand,2,REDIS_CMD_INLINE,NULL,0,0,0},
{"ping",pingCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
{"echo",echoCommand,2,REDIS_CMD_BULK,NULL,0,0,0},
{"save",saveCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
{"bgsave",bgsaveCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
{"bgrewriteaof",bgrewriteaofCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
{"shutdown",shutdownCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
{"lastsave",lastsaveCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
{"type",typeCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
{"multi",multiCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
{"exec",execCommand,1,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,execBlockClientOnSwappedKeys,0,0,0},
{"discard",discardCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
{"sync",syncCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
{"flushdb",flushdbCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
{"flushall",flushallCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
{"sort",sortCommand,-2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,1,1},
{"info",infoCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
{"monitor",monitorCommand,1,REDIS_CMD_INLINE,NULL,0,0,0},
{"ttl",ttlCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
{"persist",persistCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
{"slaveof",slaveofCommand,3,REDIS_CMD_INLINE,NULL,0,0,0},
{"debug",debugCommand,-2,REDIS_CMD_INLINE,NULL,0,0,0},
{"config",configCommand,-2,REDIS_CMD_BULK,NULL,0,0,0},
{"subscribe",subscribeCommand,-2,REDIS_CMD_INLINE,NULL,0,0,0},
{"unsubscribe",unsubscribeCommand,-1,REDIS_CMD_INLINE,NULL,0,0,0},
{"psubscribe",psubscribeCommand,-2,REDIS_CMD_INLINE,NULL,0,0,0},
{"punsubscribe",punsubscribeCommand,-1,REDIS_CMD_INLINE,NULL,0,0,0},
{"publish",publishCommand,3,REDIS_CMD_BULK|REDIS_CMD_FORCE_REPLICATION,NULL,0,0,0},
{"watch",watchCommand,-2,REDIS_CMD_INLINE,NULL,0,0,0},
{"unwatch",unwatchCommand,1,REDIS_CMD_INLINE,NULL,0,0,0}
{"get",getCommand,2,0,NULL,1,1,1},
{"set",setCommand,3,REDIS_CMD_DENYOOM,NULL,0,0,0},
{"setnx",setnxCommand,3,REDIS_CMD_DENYOOM,NULL,0,0,0},
{"setex",setexCommand,4,REDIS_CMD_DENYOOM,NULL,0,0,0},
{"append",appendCommand,3,REDIS_CMD_DENYOOM,NULL,1,1,1},
{"substr",substrCommand,4,0,NULL,1,1,1},
{"strlen",strlenCommand,2,0,NULL,1,1,1},
{"del",delCommand,-2,0,NULL,0,0,0},
{"exists",existsCommand,2,0,NULL,1,1,1},
{"incr",incrCommand,2,REDIS_CMD_DENYOOM,NULL,1,1,1},
{"decr",decrCommand,2,REDIS_CMD_DENYOOM,NULL,1,1,1},
{"mget",mgetCommand,-2,0,NULL,1,-1,1},
{"rpush",rpushCommand,3,REDIS_CMD_DENYOOM,NULL,1,1,1},
{"lpush",lpushCommand,3,REDIS_CMD_DENYOOM,NULL,1,1,1},
{"rpushx",rpushxCommand,3,REDIS_CMD_DENYOOM,NULL,1,1,1},
{"lpushx",lpushxCommand,3,REDIS_CMD_DENYOOM,NULL,1,1,1},
{"linsert",linsertCommand,5,REDIS_CMD_DENYOOM,NULL,1,1,1},
{"rpop",rpopCommand,2,0,NULL,1,1,1},
{"lpop",lpopCommand,2,0,NULL,1,1,1},
{"brpop",brpopCommand,-3,0,NULL,1,1,1},
{"blpop",blpopCommand,-3,0,NULL,1,1,1},
{"llen",llenCommand,2,0,NULL,1,1,1},
{"lindex",lindexCommand,3,0,NULL,1,1,1},
{"lset",lsetCommand,4,REDIS_CMD_DENYOOM,NULL,1,1,1},
{"lrange",lrangeCommand,4,0,NULL,1,1,1},
{"ltrim",ltrimCommand,4,0,NULL,1,1,1},
{"lrem",lremCommand,4,0,NULL,1,1,1},
{"rpoplpush",rpoplpushcommand,3,REDIS_CMD_DENYOOM,NULL,1,2,1},
{"sadd",saddCommand,3,REDIS_CMD_DENYOOM,NULL,1,1,1},
{"srem",sremCommand,3,0,NULL,1,1,1},
{"smove",smoveCommand,4,0,NULL,1,2,1},
{"sismember",sismemberCommand,3,0,NULL,1,1,1},
{"scard",scardCommand,2,0,NULL,1,1,1},
{"spop",spopCommand,2,0,NULL,1,1,1},
{"srandmember",srandmemberCommand,2,0,NULL,1,1,1},
{"sinter",sinterCommand,-2,REDIS_CMD_DENYOOM,NULL,1,-1,1},
{"sinterstore",sinterstoreCommand,-3,REDIS_CMD_DENYOOM,NULL,2,-1,1},
{"sunion",sunionCommand,-2,REDIS_CMD_DENYOOM,NULL,1,-1,1},
{"sunionstore",sunionstoreCommand,-3,REDIS_CMD_DENYOOM,NULL,2,-1,1},
{"sdiff",sdiffCommand,-2,REDIS_CMD_DENYOOM,NULL,1,-1,1},
{"sdiffstore",sdiffstoreCommand,-3,REDIS_CMD_DENYOOM,NULL,2,-1,1},
{"smembers",sinterCommand,2,0,NULL,1,1,1},
{"zadd",zaddCommand,4,REDIS_CMD_DENYOOM,NULL,1,1,1},
{"zincrby",zincrbyCommand,4,REDIS_CMD_DENYOOM,NULL,1,1,1},
{"zrem",zremCommand,3,0,NULL,1,1,1},
{"zremrangebyscore",zremrangebyscoreCommand,4,0,NULL,1,1,1},
{"zremrangebyrank",zremrangebyrankCommand,4,0,NULL,1,1,1},
{"zunionstore",zunionstoreCommand,-4,REDIS_CMD_DENYOOM,zunionInterBlockClientOnSwappedKeys,0,0,0},
{"zinterstore",zinterstoreCommand,-4,REDIS_CMD_DENYOOM,zunionInterBlockClientOnSwappedKeys,0,0,0},
{"zrange",zrangeCommand,-4,0,NULL,1,1,1},
{"zrangebyscore",zrangebyscoreCommand,-4,0,NULL,1,1,1},
{"zrevrangebyscore",zrevrangebyscoreCommand,-4,0,NULL,1,1,1},
{"zcount",zcountCommand,4,0,NULL,1,1,1},
{"zrevrange",zrevrangeCommand,-4,0,NULL,1,1,1},
{"zcard",zcardCommand,2,0,NULL,1,1,1},
{"zscore",zscoreCommand,3,REDIS_CMD_DENYOOM,NULL,1,1,1},
{"zrank",zrankCommand,3,0,NULL,1,1,1},
{"zrevrank",zrevrankCommand,3,0,NULL,1,1,1},
{"hset",hsetCommand,4,REDIS_CMD_DENYOOM,NULL,1,1,1},
{"hsetnx",hsetnxCommand,4,REDIS_CMD_DENYOOM,NULL,1,1,1},
{"hget",hgetCommand,3,0,NULL,1,1,1},
{"hmset",hmsetCommand,-4,REDIS_CMD_DENYOOM,NULL,1,1,1},
{"hmget",hmgetCommand,-3,0,NULL,1,1,1},
{"hincrby",hincrbyCommand,4,REDIS_CMD_DENYOOM,NULL,1,1,1},
{"hdel",hdelCommand,3,0,NULL,1,1,1},
{"hlen",hlenCommand,2,0,NULL,1,1,1},
{"hkeys",hkeysCommand,2,0,NULL,1,1,1},
{"hvals",hvalsCommand,2,0,NULL,1,1,1},
{"hgetall",hgetallCommand,2,0,NULL,1,1,1},
{"hexists",hexistsCommand,3,0,NULL,1,1,1},
{"incrby",incrbyCommand,3,REDIS_CMD_DENYOOM,NULL,1,1,1},
{"decrby",decrbyCommand,3,REDIS_CMD_DENYOOM,NULL,1,1,1},
{"getset",getsetCommand,3,REDIS_CMD_DENYOOM,NULL,1,1,1},
{"mset",msetCommand,-3,REDIS_CMD_DENYOOM,NULL,1,-1,2},
{"msetnx",msetnxCommand,-3,REDIS_CMD_DENYOOM,NULL,1,-1,2},
{"randomkey",randomkeyCommand,1,0,NULL,0,0,0},
{"select",selectCommand,2,0,NULL,0,0,0},
{"move",moveCommand,3,0,NULL,1,1,1},
{"rename",renameCommand,3,0,NULL,1,1,1},
{"renamenx",renamenxCommand,3,0,NULL,1,1,1},
{"expire",expireCommand,3,0,NULL,0,0,0},
{"expireat",expireatCommand,3,0,NULL,0,0,0},
{"keys",keysCommand,2,0,NULL,0,0,0},
{"dbsize",dbsizeCommand,1,0,NULL,0,0,0},
{"auth",authCommand,2,0,NULL,0,0,0},
{"ping",pingCommand,1,0,NULL,0,0,0},
{"echo",echoCommand,2,0,NULL,0,0,0},
{"save",saveCommand,1,0,NULL,0,0,0},
{"bgsave",bgsaveCommand,1,0,NULL,0,0,0},
{"bgrewriteaof",bgrewriteaofCommand,1,0,NULL,0,0,0},
{"shutdown",shutdownCommand,1,0,NULL,0,0,0},
{"lastsave",lastsaveCommand,1,0,NULL,0,0,0},
{"type",typeCommand,2,0,NULL,1,1,1},
{"multi",multiCommand,1,0,NULL,0,0,0},
{"exec",execCommand,1,REDIS_CMD_DENYOOM,execBlockClientOnSwappedKeys,0,0,0},
{"discard",discardCommand,1,0,NULL,0,0,0},
{"sync",syncCommand,1,0,NULL,0,0,0},
{"flushdb",flushdbCommand,1,0,NULL,0,0,0},
{"flushall",flushallCommand,1,0,NULL,0,0,0},
{"sort",sortCommand,-2,REDIS_CMD_DENYOOM,NULL,1,1,1},
{"info",infoCommand,1,0,NULL,0,0,0},
{"monitor",monitorCommand,1,0,NULL,0,0,0},
{"ttl",ttlCommand,2,0,NULL,1,1,1},
{"persist",persistCommand,2,0,NULL,1,1,1},
{"slaveof",slaveofCommand,3,0,NULL,0,0,0},
{"debug",debugCommand,-2,0,NULL,0,0,0},
{"config",configCommand,-2,0,NULL,0,0,0},
{"subscribe",subscribeCommand,-2,0,NULL,0,0,0},
{"unsubscribe",unsubscribeCommand,-1,0,NULL,0,0,0},
{"psubscribe",psubscribeCommand,-2,0,NULL,0,0,0},
{"punsubscribe",punsubscribeCommand,-1,0,NULL,0,0,0},
{"publish",publishCommand,3,REDIS_CMD_FORCE_REPLICATION,NULL,0,0,0},
{"watch",watchCommand,-2,0,NULL,0,0,0},
{"unwatch",unwatchCommand,1,0,NULL,0,0,0}
};
/*============================ Utility functions ============================ */
@ -899,84 +899,14 @@ void call(redisClient *c, struct redisCommand *cmd) {
int processCommand(redisClient *c) {
struct redisCommand *cmd;
/* Handle the multi bulk command type. This is an alternative protocol
* supported by Redis in order to receive commands that are composed of
* multiple binary-safe "bulk" arguments. The latency of processing is
* a bit higher but this allows things like multi-sets, so if this
* protocol is used only for MSET and similar commands this is a big win. */
if (c->multibulk == 0 && c->argc == 1 && ((char*)(c->argv[0]->ptr))[0] == '*') {
c->multibulk = atoi(((char*)c->argv[0]->ptr)+1);
if (c->multibulk <= 0) {
resetClient(c);
return 1;
} else {
decrRefCount(c->argv[c->argc-1]);
c->argc--;
return 1;
}
} else if (c->multibulk) {
if (c->bulklen == -1) {
if (((char*)c->argv[0]->ptr)[0] != '$') {
addReplyError(c,"multi bulk protocol error");
resetClient(c);
return 1;
} else {
char *eptr;
long bulklen = strtol(((char*)c->argv[0]->ptr)+1,&eptr,10);
int perr = eptr[0] != '\0';
decrRefCount(c->argv[0]);
if (perr || bulklen == LONG_MIN || bulklen == LONG_MAX ||
bulklen < 0 || bulklen > 1024*1024*1024)
{
c->argc--;
addReplyError(c,"invalid bulk write count");
resetClient(c);
return 1;
}
c->argc--;
c->bulklen = bulklen+2; /* add two bytes for CR+LF */
return 1;
}
} else {
c->mbargv = zrealloc(c->mbargv,(sizeof(robj*))*(c->mbargc+1));
c->mbargv[c->mbargc] = c->argv[0];
c->mbargc++;
c->argc--;
c->multibulk--;
if (c->multibulk == 0) {
robj **auxargv;
int auxargc;
/* Here we need to swap the multi-bulk argc/argv with the
* normal argc/argv of the client structure. */
auxargv = c->argv;
c->argv = c->mbargv;
c->mbargv = auxargv;
auxargc = c->argc;
c->argc = c->mbargc;
c->mbargc = auxargc;
/* We need to set bulklen to something different than -1
* in order for the code below to process the command without
* to try to read the last argument of a bulk command as
* a special argument. */
c->bulklen = 0;
/* continue below and process the command */
} else {
c->bulklen = -1;
return 1;
}
}
}
/* -- end of multi bulk commands processing -- */
/* The QUIT command is handled as a special case. Normal command
* procs are unable to close the client connection safely */
/* The QUIT command is handled separately. Normal command procs will
* go through checking for replication and QUIT will cause trouble
* when FORCE_REPLICATION is enabled and would be implemented in
* a regular command proc. */
if (!strcasecmp(c->argv[0]->ptr,"quit")) {
freeClient(c);
return 0;
addReply(c,shared.ok);
c->flags |= REDIS_CLOSE_AFTER_REPLY;
return REDIS_ERR;
}
/* Now lookup the command and check ASAP about trivial error conditions
@ -985,55 +915,18 @@ int processCommand(redisClient *c) {
if (!cmd) {
addReplyErrorFormat(c,"unknown command '%s'",
(char*)c->argv[0]->ptr);
resetClient(c);
return 1;
return REDIS_OK;
} else if ((cmd->arity > 0 && cmd->arity != c->argc) ||
(c->argc < -cmd->arity)) {
addReplyErrorFormat(c,"wrong number of arguments for '%s' command",
cmd->name);
resetClient(c);
return 1;
} else if (cmd->flags & REDIS_CMD_BULK && c->bulklen == -1) {
/* This is a bulk command, we have to read the last argument yet. */
char *eptr;
long bulklen = strtol(c->argv[c->argc-1]->ptr,&eptr,10);
int perr = eptr[0] != '\0';
decrRefCount(c->argv[c->argc-1]);
if (perr || bulklen == LONG_MAX || bulklen == LONG_MIN ||
bulklen < 0 || bulklen > 1024*1024*1024)
{
c->argc--;
addReplyError(c,"invalid bulk write count");
resetClient(c);
return 1;
}
c->argc--;
c->bulklen = bulklen+2; /* add two bytes for CR+LF */
/* It is possible that the bulk read is already in the
* buffer. Check this condition and handle it accordingly.
* This is just a fast path, alternative to call processInputBuffer().
* It's a good idea since the code is small and this condition
* happens most of the times. */
if ((signed)sdslen(c->querybuf) >= c->bulklen) {
c->argv[c->argc] = createStringObject(c->querybuf,c->bulklen-2);
c->argc++;
c->querybuf = sdsrange(c->querybuf,c->bulklen,-1);
} else {
/* Otherwise return... there is to read the last argument
* from the socket. */
return 1;
}
return REDIS_OK;
}
/* Let's try to encode the bulk object to save space. */
if (cmd->flags & REDIS_CMD_BULK)
c->argv[c->argc-1] = tryObjectEncoding(c->argv[c->argc-1]);
/* Check if the user is authenticated */
if (server.requirepass && !c->authenticated && cmd->proc != authCommand) {
addReplyError(c,"operation not permitted");
resetClient(c);
return 1;
return REDIS_OK;
}
/* Handle the maxmemory directive.
@ -1046,8 +939,7 @@ int processCommand(redisClient *c) {
zmalloc_used_memory() > server.maxmemory)
{
addReplyError(c,"command not allowed when used memory > 'maxmemory'");
resetClient(c);
return 1;
return REDIS_OK;
}
/* Only allow SUBSCRIBE and UNSUBSCRIBE in the context of Pub/Sub */
@ -1056,8 +948,7 @@ int processCommand(redisClient *c) {
cmd->proc != subscribeCommand && cmd->proc != unsubscribeCommand &&
cmd->proc != psubscribeCommand && cmd->proc != punsubscribeCommand) {
addReplyError(c,"only (P)SUBSCRIBE / (P)UNSUBSCRIBE / QUIT allowed in this context");
resetClient(c);
return 1;
return REDIS_OK;
}
/* Exec the command */
@ -1069,13 +960,10 @@ int processCommand(redisClient *c) {
addReply(c,shared.queued);
} else {
if (server.vm_enabled && server.vm_max_threads > 0 &&
blockClientOnSwappedKeys(c,cmd)) return 1;
blockClientOnSwappedKeys(c,cmd)) return REDIS_ERR;
call(c,cmd);
}
/* Prepare the client for the next command */
resetClient(c);
return 1;
return REDIS_OK;
}
/*================================== Shutdown =============================== */

View File

@ -57,15 +57,15 @@
/* Hash table parameters */
#define REDIS_HT_MINFILL 10 /* Minimal hash table fill 10% */
/* Command flags */
#define REDIS_CMD_BULK 1 /* Bulk write command */
#define REDIS_CMD_INLINE 2 /* Inline command */
/* REDIS_CMD_DENYOOM reserves a longer comment: all the commands marked with
this flags will return an error when the 'maxmemory' option is set in the
config file and the server is using more than maxmemory bytes of memory.
In short this commands are denied on low memory conditions. */
#define REDIS_CMD_DENYOOM 4
#define REDIS_CMD_FORCE_REPLICATION 8 /* Force replication even if dirty is 0 */
/* Command flags:
* REDIS_CMD_DENYOOM:
* Commands marked with this flag will return an error when 'maxmemory' is
* set and the server is using more than 'maxmemory' bytes of memory.
* In short: commands with this flag are denied on low memory conditions.
* REDIS_CMD_FORCE_REPLICATION:
* Force replication even if dirty is 0. */
#define REDIS_CMD_DENYOOM 4
#define REDIS_CMD_FORCE_REPLICATION 8
/* Object types */
#define REDIS_STRING 0
@ -144,6 +144,11 @@
#define REDIS_BLOCKED 16 /* The client is waiting in a blocking operation */
#define REDIS_IO_WAIT 32 /* The client is waiting for Virtual Memory I/O */
#define REDIS_DIRTY_CAS 64 /* Watched keys modified. EXEC will fail. */
#define REDIS_CLOSE_AFTER_REPLY 128 /* Close after writing entire reply. */
/* Client request types */
#define REDIS_REQ_INLINE 1
#define REDIS_REQ_MULTIBULK 2
/* Slave replication state - slave side */
#define REDIS_REPL_NONE 0 /* No active replication */
@ -294,11 +299,11 @@ typedef struct redisClient {
redisDb *db;
int dictid;
sds querybuf;
robj **argv, **mbargv;
char *newline; /* pointing to the detected newline in querybuf */
int argc, mbargc;
long bulklen; /* bulk read len. -1 if not in bulk read mode */
int multibulk; /* multi bulk command format active */
int argc;
robj **argv;
int reqtype;
int multibulklen; /* number of multi bulk arguments left to read */
long bulklen; /* length of bulk argument in multi bulk request */
list *reply;
int sentlen;
time_t lastinteraction; /* time of the last interaction, used for timeout */

View File

@ -260,6 +260,7 @@ void listTypeConvert(robj *subject, int enc) {
void pushGenericCommand(redisClient *c, int where) {
robj *lobj = lookupKeyWrite(c->db,c->argv[1]);
c->argv[2] = tryObjectEncoding(c->argv[2]);
if (lobj == NULL) {
if (handleClientsWaitingListPush(c,c->argv[1],c->argv[2])) {
addReply(c,shared.cone);
@ -346,14 +347,17 @@ void pushxGenericCommand(redisClient *c, robj *refval, robj *val, int where) {
}
void lpushxCommand(redisClient *c) {
c->argv[2] = tryObjectEncoding(c->argv[2]);
pushxGenericCommand(c,NULL,c->argv[2],REDIS_HEAD);
}
void rpushxCommand(redisClient *c) {
c->argv[2] = tryObjectEncoding(c->argv[2]);
pushxGenericCommand(c,NULL,c->argv[2],REDIS_TAIL);
}
void linsertCommand(redisClient *c) {
c->argv[4] = tryObjectEncoding(c->argv[4]);
if (strcasecmp(c->argv[2]->ptr,"after") == 0) {
pushxGenericCommand(c,c->argv[3],c->argv[4],REDIS_TAIL);
} else if (strcasecmp(c->argv[2]->ptr,"before") == 0) {
@ -409,7 +413,7 @@ void lsetCommand(redisClient *c) {
robj *o = lookupKeyWriteOrReply(c,c->argv[1],shared.nokeyerr);
if (o == NULL || checkType(c,o,REDIS_LIST)) return;
int index = atoi(c->argv[2]->ptr);
robj *value = c->argv[3];
robj *value = (c->argv[3] = tryObjectEncoding(c->argv[3]));
listTypeTryConversion(o,value);
if (o->encoding == REDIS_ENCODING_ZIPLIST) {
@ -559,7 +563,8 @@ void ltrimCommand(redisClient *c) {
}
void lremCommand(redisClient *c) {
robj *subject, *obj = c->argv[3];
robj *subject, *obj;
obj = c->argv[3] = tryObjectEncoding(c->argv[3]);
int toremove = atoi(c->argv[2]->ptr);
int removed = 0;
listTypeEntry entry;

View File

@ -178,6 +178,7 @@ void saddCommand(redisClient *c) {
robj *set;
set = lookupKeyWrite(c->db,c->argv[1]);
c->argv[2] = tryObjectEncoding(c->argv[2]);
if (set == NULL) {
set = setTypeCreate(c->argv[2]);
dbAdd(c->db,c->argv[1],set);
@ -202,6 +203,7 @@ void sremCommand(redisClient *c) {
if ((set = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
checkType(c,set,REDIS_SET)) return;
c->argv[2] = tryObjectEncoding(c->argv[2]);
if (setTypeRemove(set,c->argv[2])) {
if (setTypeSize(set) == 0) dbDelete(c->db,c->argv[1]);
touchWatchedKey(c->db,c->argv[1]);
@ -216,7 +218,7 @@ void smoveCommand(redisClient *c) {
robj *srcset, *dstset, *ele;
srcset = lookupKeyWrite(c->db,c->argv[1]);
dstset = lookupKeyWrite(c->db,c->argv[2]);
ele = c->argv[3];
ele = c->argv[3] = tryObjectEncoding(c->argv[3]);
/* If the source key does not exist return 0 */
if (srcset == NULL) {
@ -264,6 +266,7 @@ void sismemberCommand(redisClient *c) {
if ((set = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
checkType(c,set,REDIS_SET)) return;
c->argv[2] = tryObjectEncoding(c->argv[2]);
if (setTypeIsMember(set,c->argv[2]))
addReply(c,shared.cone);
else

View File

@ -37,14 +37,17 @@ void setGenericCommand(redisClient *c, int nx, robj *key, robj *val, robj *expir
}
void setCommand(redisClient *c) {
c->argv[2] = tryObjectEncoding(c->argv[2]);
setGenericCommand(c,0,c->argv[1],c->argv[2],NULL);
}
void setnxCommand(redisClient *c) {
c->argv[2] = tryObjectEncoding(c->argv[2]);
setGenericCommand(c,1,c->argv[1],c->argv[2],NULL);
}
void setexCommand(redisClient *c) {
c->argv[3] = tryObjectEncoding(c->argv[3]);
setGenericCommand(c,0,c->argv[1],c->argv[3],c->argv[2]);
}
@ -69,6 +72,7 @@ void getCommand(redisClient *c) {
void getsetCommand(redisClient *c) {
if (getGenericCommand(c) == REDIS_ERR) return;
c->argv[2] = tryObjectEncoding(c->argv[2]);
dbReplace(c->db,c->argv[1],c->argv[2]);
incrRefCount(c->argv[2]);
touchWatchedKey(c->db,c->argv[1]);
@ -180,6 +184,7 @@ void appendCommand(redisClient *c) {
robj *o;
o = lookupKeyWrite(c->db,c->argv[1]);
c->argv[2] = tryObjectEncoding(c->argv[2]);
if (o == NULL) {
/* Create the key */
retval = dbAdd(c->db,c->argv[1],c->argv[2]);

View File

@ -440,12 +440,14 @@ void zaddGenericCommand(redisClient *c, robj *key, robj *ele, double score, int
void zaddCommand(redisClient *c) {
double scoreval;
if (getDoubleFromObjectOrReply(c,c->argv[2],&scoreval,NULL) != REDIS_OK) return;
c->argv[3] = tryObjectEncoding(c->argv[3]);
zaddGenericCommand(c,c->argv[1],c->argv[3],scoreval,0);
}
void zincrbyCommand(redisClient *c) {
double scoreval;
if (getDoubleFromObjectOrReply(c,c->argv[2],&scoreval,NULL) != REDIS_OK) return;
c->argv[3] = tryObjectEncoding(c->argv[3]);
zaddGenericCommand(c,c->argv[1],c->argv[3],scoreval,1);
}
@ -460,6 +462,7 @@ void zremCommand(redisClient *c) {
checkType(c,zsetobj,REDIS_ZSET)) return;
zs = zsetobj->ptr;
c->argv[2] = tryObjectEncoding(c->argv[2]);
de = dictFind(zs->dict,c->argv[2]);
if (de == NULL) {
addReply(c,shared.czero);
@ -1004,6 +1007,7 @@ void zscoreCommand(redisClient *c) {
checkType(c,o,REDIS_ZSET)) return;
zs = o->ptr;
c->argv[2] = tryObjectEncoding(c->argv[2]);
de = dictFind(zs->dict,c->argv[2]);
if (!de) {
addReply(c,shared.nullbulk);
@ -1027,6 +1031,7 @@ void zrankGenericCommand(redisClient *c, int reverse) {
zs = o->ptr;
zsl = zs->zsl;
c->argv[2] = tryObjectEncoding(c->argv[2]);
de = dictFind(zs->dict,c->argv[2]);
if (!de) {
addReply(c,shared.nullbulk);