X-Git-Url: https://git.saurik.com/redis.git/blobdiff_plain/7b72272790268942b5f4f751c78ea6ed227b2bba..093433c16ddf432e5005a6b45825febf448fc6a9:/src/networking.c diff --git a/src/networking.c b/src/networking.c index 976b472a..f14b4ef8 100644 --- a/src/networking.c +++ b/src/networking.c @@ -36,6 +36,7 @@ redisClient *createClient(int fd) { c->reqtype = 0; c->argc = 0; c->argv = NULL; + c->cmd = NULL; c->multibulklen = 0; c->bulklen = -1; c->sentlen = 0; @@ -246,10 +247,17 @@ void addReplyError(redisClient *c, char *err) { } void addReplyErrorFormat(redisClient *c, const char *fmt, ...) { + size_t l, j; va_list ap; va_start(ap,fmt); sds s = sdscatvprintf(sdsempty(),fmt,ap); va_end(ap); + /* Make sure there are no newlines in the string, otherwise invalid protocol + * is emitted. */ + l = sdslen(s); + for (j = 0; j < l; j++) { + if (s[j] == '\r' || s[j] == '\n') s[j] = ' '; + } _addReplyError(c,s,sdslen(s)); sdsfree(s); } @@ -454,6 +462,7 @@ static void freeClientArgv(redisClient *c) { for (j = 0; j < c->argc; j++) decrRefCount(c->argv[j]); c->argc = 0; + c->cmd = NULL; } void freeClient(redisClient *c) { @@ -494,25 +503,6 @@ void freeClient(redisClient *c) { redisAssert(ln != NULL); listDelNode(server.unblocked_clients,ln); } - /* Remove from the list of clients waiting for swapped keys, or ready - * to be restarted, but not yet woken up again. */ - if (c->flags & REDIS_IO_WAIT) { - redisAssert(server.ds_enabled); - if (listLength(c->io_keys) == 0) { - ln = listSearchKey(server.io_ready_clients,c); - - /* When this client is waiting to be woken up (REDIS_IO_WAIT), - * it should be present in the list io_ready_clients */ - redisAssert(ln != NULL); - listDelNode(server.io_ready_clients,ln); - } else { - while (listLength(c->io_keys)) { - ln = listFirst(c->io_keys); - dontWaitForSwappedKey(c,ln->value); - } - } - server.cache_blocked_clients--; - } listRelease(c->io_keys); /* Master/slave cleanup. * Case 1: we lost the connection with a slave. */ @@ -529,6 +519,7 @@ void freeClient(redisClient *c) { if (c->flags & REDIS_MASTER) { server.master = NULL; server.replstate = REDIS_REPL_CONNECT; + server.repl_down_since = time(NULL); /* Since we lost the connection with the master, we should also * close the connection with all our slaves if we have any, so * when we'll resync with the master the other slaves will sync again @@ -619,7 +610,7 @@ void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) { } } if (totwritten > 0) c->lastinteraction = time(NULL); - if (listLength(c->reply) == 0) { + if (c->bufpos == 0 && listLength(c->reply) == 0) { c->sentlen = 0; aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE); @@ -712,7 +703,7 @@ int processMultibulkBuffer(redisClient *c) { if (c->multibulklen == 0) { /* The client should have been reset */ - redisAssert(c->argc == 0); + redisAssertWithInfo(c,NULL,c->argc == 0); /* Multi bulk length cannot be read without a \r\n */ newline = strchr(c->querybuf,'\r'); @@ -725,7 +716,7 @@ int processMultibulkBuffer(redisClient *c) { /* 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] == '*'); + redisAssertWithInfo(c,NULL,c->querybuf[0] == '*'); ok = string2ll(c->querybuf+1,newline-(c->querybuf+1),&ll); if (!ok || ll > 1024*1024) { addReplyError(c,"Protocol error: invalid multibulk length"); @@ -746,7 +737,7 @@ int processMultibulkBuffer(redisClient *c) { c->argv = zmalloc(sizeof(robj*)*c->multibulklen); } - redisAssert(c->multibulklen > 0); + redisAssertWithInfo(c,NULL,c->multibulklen > 0); while(c->multibulklen) { /* Read bulk length if unknown */ if (c->bulklen == -1) { @@ -803,7 +794,7 @@ 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; + if (c->flags & REDIS_BLOCKED) 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 @@ -913,7 +904,6 @@ void clientCommand(redisClient *c) { if (p == flags) *p++ = 'N'; if (client->flags & REDIS_MULTI) *p++ = 'x'; if (client->flags & REDIS_BLOCKED) *p++ = 'b'; - if (client->flags & REDIS_IO_WAIT) *p++ = 'i'; if (client->flags & REDIS_DIRTY_CAS) *p++ = 'd'; if (client->flags & REDIS_CLOSE_AFTER_REPLY) *p++ = 'c'; if (client->flags & REDIS_UNBLOCKED) *p++ = 'u'; @@ -953,3 +943,51 @@ void clientCommand(redisClient *c) { addReplyError(c, "Syntax error, try CLIENT (LIST | KILL ip:port)"); } } + +/* Rewrite the command vector of the client. All the new objects ref count + * is incremented. The old command vector is freed, and the old objects + * ref count is decremented. */ +void rewriteClientCommandVector(redisClient *c, int argc, ...) { + va_list ap; + int j; + robj **argv; /* The new argument vector */ + + argv = zmalloc(sizeof(robj*)*argc); + va_start(ap,argc); + for (j = 0; j < argc; j++) { + robj *a; + + a = va_arg(ap, robj*); + argv[j] = a; + incrRefCount(a); + } + /* We free the objects in the original vector at the end, so we are + * sure that if the same objects are reused in the new vector the + * refcount gets incremented before it gets decremented. */ + for (j = 0; j < c->argc; j++) decrRefCount(c->argv[j]); + zfree(c->argv); + /* Replace argv and argc with our new versions. */ + c->argv = argv; + c->argc = argc; + c->cmd = lookupCommand(c->argv[0]->ptr); + redisAssertWithInfo(c,NULL,c->cmd != NULL); + va_end(ap); +} + +/* Rewrite a single item in the command vector. + * The new val ref count is incremented, and the old decremented. */ +void rewriteClientCommandArgument(redisClient *c, int i, robj *newval) { + robj *oldval; + + redisAssertWithInfo(c,NULL,i < c->argc); + oldval = c->argv[i]; + c->argv[i] = newval; + incrRefCount(newval); + decrRefCount(oldval); + + /* If this is the command name make sure to fix c->cmd. */ + if (i == 0) { + c->cmd = lookupCommand(c->argv[0]->ptr); + redisAssertWithInfo(c,NULL,c->cmd != NULL); + } +}