From e7affd266c4884ce4fc60e567e3aae55cac49828 Mon Sep 17 00:00:00 2001 From: antirez Date: Mon, 16 Jun 2014 14:24:28 +0200 Subject: New features for CLIENT KILL. --- src/networking.c | 71 +++++++++++++++++++++++++++++++++++++++++++++----------- src/redis.h | 1 + 2 files changed, 59 insertions(+), 13 deletions(-) diff --git a/src/networking.c b/src/networking.c index 99e61de33..4d2b1054c 100644 --- a/src/networking.c +++ b/src/networking.c @@ -1346,27 +1346,72 @@ void clientCommand(redisClient *c) { redisClient *client; if (!strcasecmp(c->argv[1]->ptr,"list") && c->argc == 2) { + /* CLIENT LIST */ sds o = getAllClientsInfoString(); addReplyBulkCBuffer(c,o,sdslen(o)); sdsfree(o); - } else if (!strcasecmp(c->argv[1]->ptr,"kill") && c->argc == 3) { + } else if (!strcasecmp(c->argv[1]->ptr,"kill")) { + /* CLIENT KILL + * CLIENT KILL */ + char *addr = NULL; + int type = -1; + uint64_t id = 0; + int killed = 0; + + /* Parse arguments. */ + if (c->argc == 3) { + addr = c->argv[2]->ptr; + } else if (c->argc == 4) { + if (!strcasecmp(c->argv[2]->ptr,"id")) { + long long tmp; + + if (getLongLongFromObjectOrReply(c,c->argv[3],&tmp,NULL) + != REDIS_OK) return; + id = tmp; + } else if (!strcasecmp(c->argv[2]->ptr,"type")) { + type = getClientTypeByName(c->argv[3]->ptr); + if (type == -1) { + addReplyErrorFormat(c,"Unknown client type '%s'", + (char*) c->argv[3]->ptr); + return; + } + } else if (!strcasecmp(c->argv[2]->ptr,"addr")) { + addr = c->argv[3]->ptr; + } else { + addReply(c,shared.syntaxerr); + return; + } + } else { + addReply(c,shared.syntaxerr); + return; + } + + /* Iterate clients killing all the matching clients. */ listRewind(server.clients,&li); while ((ln = listNext(&li)) != NULL) { - char *peerid; - client = listNodeValue(ln); - peerid = getClientPeerId(client); - if (strcmp(peerid,c->argv[2]->ptr) == 0) { - addReply(c,shared.ok); - if (c == client) { - client->flags |= REDIS_CLOSE_AFTER_REPLY; - } else { - freeClient(client); - } - return; + if (addr && strcmp(getClientPeerId(client),addr) != 0) continue; + if (type != -1 && getClientType(client) != type) continue; + if (id != 0 && client->id != id) continue; + + /* Kill it. */ + if (c == client) { + client->flags |= REDIS_CLOSE_AFTER_REPLY; + } else { + freeClient(client); } + killed++; + } + + /* Reply according to old/new format. */ + if (c->argc == 3) { + if (killed == 0) + addReplyError(c,"No such client"); + else + addReply(c,shared.ok); + } else { + addReplyLongLong(c,killed); } - addReplyError(c,"No such client"); } else if (!strcasecmp(c->argv[1]->ptr,"setname") && c->argc == 3) { int j, len = sdslen(c->argv[2]->ptr); char *p = c->argv[2]->ptr; diff --git a/src/redis.h b/src/redis.h index d16933d59..02def27d7 100644 --- a/src/redis.h +++ b/src/redis.h @@ -1004,6 +1004,7 @@ void rewriteClientCommandArgument(redisClient *c, int i, robj *newval); unsigned long getClientOutputBufferMemoryUsage(redisClient *c); void freeClientsInAsyncFreeQueue(void); void asyncCloseClientOnOutputBufferLimitReached(redisClient *c); +int getClientType(redisClient *c); int getClientTypeByName(char *name); char *getClientTypeName(int class); void flushSlavesOutputBuffers(void); -- cgit v1.2.1