From 56d26c23801b53458dfe8ac614106a9ab71473f1 Mon Sep 17 00:00:00 2001 From: antirez Date: Mon, 16 Jun 2014 10:43:05 +0200 Subject: Client types generalized. Because of output buffer limits Redis internals had this idea of type of clients: normal, pubsub, slave. It is possible to set different output buffer limits for the three kinds of clients. However all the macros and API were named after output buffer limit classes, while the idea of a client type is a generic one that can be reused. This commit does two things: 1) Rename the API and defines with more general names. 2) Change the class of clients executing the MONITOR command from "slave" to "normal". "2" is a good idea because you want to have very special settings for slaves, that are not a good idea for MONITOR clients that are instead normal clients even if they are conceptually slave-alike (since it is a push protocol). The backward-compatibility breakage resulting from "2" is considered to be minimal to care, since MONITOR is a debugging command, and because anyway this change is not going to break the format or the behavior, but just when a connection is closed on big output buffer issues. --- redis.conf | 4 ++-- src/config.c | 18 +++++++++--------- src/networking.c | 35 ++++++++++++++++++----------------- src/redis.c | 2 +- src/redis.h | 16 ++++++++-------- 5 files changed, 38 insertions(+), 37 deletions(-) diff --git a/redis.conf b/redis.conf index fe259726e..1103d6152 100644 --- a/redis.conf +++ b/redis.conf @@ -768,8 +768,8 @@ activerehashing yes # # The limit can be set differently for the three different classes of clients: # -# normal -> normal clients -# slave -> slave clients and MONITOR clients +# normal -> normal clients including MONITOR clients +# slave -> slave clients # pubsub -> clients subscribed to at least one pubsub channel or pattern # # The syntax of every client-output-buffer-limit directive is the following: diff --git a/src/config.c b/src/config.c index f11120da4..a4e9c6c4e 100644 --- a/src/config.c +++ b/src/config.c @@ -50,7 +50,7 @@ static struct { {NULL, 0} }; -clientBufferLimitsConfig clientBufferLimitsDefaults[REDIS_CLIENT_LIMIT_NUM_CLASSES] = { +clientBufferLimitsConfig clientBufferLimitsDefaults[REDIS_CLIENT_TYPE_COUNT] = { {0, 0, 0}, /* normal */ {1024*1024*256, 1024*1024*64, 60}, /* slave */ {1024*1024*32, 1024*1024*8, 60} /* pubsub */ @@ -456,7 +456,7 @@ void loadServerConfigFromString(char *config) { } else if (!strcasecmp(argv[0],"client-output-buffer-limit") && argc == 5) { - int class = getClientLimitClassByName(argv[1]); + int class = getClientTypeByName(argv[1]); unsigned long long hard, soft; int soft_seconds; @@ -817,7 +817,7 @@ void configSetCommand(redisClient *c) { long val; if ((j % 4) == 0) { - if (getClientLimitClassByName(v[j]) == -1) { + if (getClientTypeByName(v[j]) == -1) { sdsfreesplitres(v,vlen); goto badfmt; } @@ -835,7 +835,7 @@ void configSetCommand(redisClient *c) { unsigned long long hard, soft; int soft_seconds; - class = getClientLimitClassByName(v[j]); + class = getClientTypeByName(v[j]); hard = strtoll(v[j+1],NULL,10); soft = strtoll(v[j+2],NULL,10); soft_seconds = strtoll(v[j+3],NULL,10); @@ -1113,13 +1113,13 @@ void configGetCommand(redisClient *c) { sds buf = sdsempty(); int j; - for (j = 0; j < REDIS_CLIENT_LIMIT_NUM_CLASSES; j++) { + for (j = 0; j < REDIS_CLIENT_TYPE_COUNT; j++) { buf = sdscatprintf(buf,"%s %llu %llu %ld", - getClientLimitClassName(j), + getClientTypeName(j), server.client_obuf_limits[j].hard_limit_bytes, server.client_obuf_limits[j].soft_limit_bytes, (long) server.client_obuf_limits[j].soft_limit_seconds); - if (j != REDIS_CLIENT_LIMIT_NUM_CLASSES-1) + if (j != REDIS_CLIENT_TYPE_COUNT-1) buf = sdscatlen(buf," ",1); } addReplyBulkCString(c,"client-output-buffer-limit"); @@ -1535,7 +1535,7 @@ void rewriteConfigClientoutputbufferlimitOption(struct rewriteConfigState *state int j; char *option = "client-output-buffer-limit"; - for (j = 0; j < REDIS_CLIENT_LIMIT_NUM_CLASSES; j++) { + for (j = 0; j < REDIS_CLIENT_TYPE_COUNT; j++) { int force = (server.client_obuf_limits[j].hard_limit_bytes != clientBufferLimitsDefaults[j].hard_limit_bytes) || (server.client_obuf_limits[j].soft_limit_bytes != @@ -1551,7 +1551,7 @@ void rewriteConfigClientoutputbufferlimitOption(struct rewriteConfigState *state server.client_obuf_limits[j].soft_limit_bytes); line = sdscatprintf(sdsempty(),"%s %s %s %s %ld", - option, getClientLimitClassName(j), hard, soft, + option, getClientTypeName(j), hard, soft, (long) server.client_obuf_limits[j].soft_limit_seconds); rewriteConfigRewriteLine(state,option,line,force); } diff --git a/src/networking.c b/src/networking.c index 06677d571..fa3e5ccce 100644 --- a/src/networking.c +++ b/src/networking.c @@ -1481,30 +1481,31 @@ unsigned long getClientOutputBufferMemoryUsage(redisClient *c) { * classes of clients. * * The function will return one of the following: - * REDIS_CLIENT_LIMIT_CLASS_NORMAL -> Normal client - * REDIS_CLIENT_LIMIT_CLASS_SLAVE -> Slave or client executing MONITOR command - * REDIS_CLIENT_LIMIT_CLASS_PUBSUB -> Client subscribed to Pub/Sub channels + * REDIS_CLIENT_TYPE_NORMAL -> Normal client + * REDIS_CLIENT_TYPE_SLAVE -> Slave or client executing MONITOR command + * REDIS_CLIENT_TYPE_PUBSUB -> Client subscribed to Pub/Sub channels */ -int getClientLimitClass(redisClient *c) { - if (c->flags & REDIS_SLAVE) return REDIS_CLIENT_LIMIT_CLASS_SLAVE; +int getClientType(redisClient *c) { + if ((c->flags & REDIS_SLAVE) && !(c->flags & REDIS_MONITOR)) + return REDIS_CLIENT_TYPE_SLAVE; if (dictSize(c->pubsub_channels) || listLength(c->pubsub_patterns)) - return REDIS_CLIENT_LIMIT_CLASS_PUBSUB; - return REDIS_CLIENT_LIMIT_CLASS_NORMAL; + return REDIS_CLIENT_TYPE_PUBSUB; + return REDIS_CLIENT_TYPE_NORMAL; } -int getClientLimitClassByName(char *name) { - if (!strcasecmp(name,"normal")) return REDIS_CLIENT_LIMIT_CLASS_NORMAL; - else if (!strcasecmp(name,"slave")) return REDIS_CLIENT_LIMIT_CLASS_SLAVE; - else if (!strcasecmp(name,"pubsub")) return REDIS_CLIENT_LIMIT_CLASS_PUBSUB; +int getClientTypeByName(char *name) { + if (!strcasecmp(name,"normal")) return REDIS_CLIENT_TYPE_NORMAL; + else if (!strcasecmp(name,"slave")) return REDIS_CLIENT_TYPE_SLAVE; + else if (!strcasecmp(name,"pubsub")) return REDIS_CLIENT_TYPE_PUBSUB; else return -1; } -char *getClientLimitClassName(int class) { +char *getClientTypeName(int class) { switch(class) { - case REDIS_CLIENT_LIMIT_CLASS_NORMAL: return "normal"; - case REDIS_CLIENT_LIMIT_CLASS_SLAVE: return "slave"; - case REDIS_CLIENT_LIMIT_CLASS_PUBSUB: return "pubsub"; - default: return NULL; + case REDIS_CLIENT_TYPE_NORMAL: return "normal"; + case REDIS_CLIENT_TYPE_SLAVE: return "slave"; + case REDIS_CLIENT_TYPE_PUBSUB: return "pubsub"; + default: return NULL; } } @@ -1518,7 +1519,7 @@ int checkClientOutputBufferLimits(redisClient *c) { int soft = 0, hard = 0, class; unsigned long used_mem = getClientOutputBufferMemoryUsage(c); - class = getClientLimitClass(c); + class = getClientType(c); if (server.client_obuf_limits[class].hard_limit_bytes && used_mem >= server.client_obuf_limits[class].hard_limit_bytes) hard = 1; diff --git a/src/redis.c b/src/redis.c index 89eaf4368..ca4fd7d1a 100644 --- a/src/redis.c +++ b/src/redis.c @@ -1485,7 +1485,7 @@ void initServerConfig() { server.repl_no_slaves_since = time(NULL); /* Client output buffer limits */ - for (j = 0; j < REDIS_CLIENT_LIMIT_NUM_CLASSES; j++) + for (j = 0; j < REDIS_CLIENT_TYPE_COUNT; j++) server.client_obuf_limits[j] = clientBufferLimitsDefaults[j]; /* Double constants initialization */ diff --git a/src/redis.h b/src/redis.h index 96b6cd04d..4d987d879 100644 --- a/src/redis.h +++ b/src/redis.h @@ -248,10 +248,10 @@ /* Client classes for client limits, currently used only for * the max-client-output-buffer limit implementation. */ -#define REDIS_CLIENT_LIMIT_CLASS_NORMAL 0 -#define REDIS_CLIENT_LIMIT_CLASS_SLAVE 1 -#define REDIS_CLIENT_LIMIT_CLASS_PUBSUB 2 -#define REDIS_CLIENT_LIMIT_NUM_CLASSES 3 +#define REDIS_CLIENT_TYPE_NORMAL 0 /* Normal req-reply clients + MONITORs */ +#define REDIS_CLIENT_TYPE_SLAVE 1 /* Slaves. */ +#define REDIS_CLIENT_TYPE_PUBSUB 2 /* Clients subscribed to PubSub channels. */ +#define REDIS_CLIENT_TYPE_COUNT 3 /* Slave replication state - from the point of view of the slave. */ #define REDIS_REPL_NONE 0 /* No active replication */ @@ -585,7 +585,7 @@ typedef struct clientBufferLimitsConfig { time_t soft_limit_seconds; } clientBufferLimitsConfig; -extern clientBufferLimitsConfig clientBufferLimitsDefaults[REDIS_CLIENT_LIMIT_NUM_CLASSES]; +extern clientBufferLimitsConfig clientBufferLimitsDefaults[REDIS_CLIENT_TYPE_COUNT]; /* The redisOp structure defines a Redis Operation, that is an instance of * a command with an argument vector, database ID, propagation target @@ -697,7 +697,7 @@ struct redisServer { size_t client_max_querybuf_len; /* Limit for client query buffer length */ int dbnum; /* Total number of configured DBs */ int daemonize; /* True if running as a daemon */ - clientBufferLimitsConfig client_obuf_limits[REDIS_CLIENT_LIMIT_NUM_CLASSES]; + clientBufferLimitsConfig client_obuf_limits[REDIS_CLIENT_TYPE_COUNT]; /* AOF persistence */ int aof_state; /* REDIS_AOF_(ON|OFF|WAIT_REWRITE) */ int aof_fsync; /* Kind of fsync() policy */ @@ -1002,8 +1002,8 @@ void rewriteClientCommandArgument(redisClient *c, int i, robj *newval); unsigned long getClientOutputBufferMemoryUsage(redisClient *c); void freeClientsInAsyncFreeQueue(void); void asyncCloseClientOnOutputBufferLimitReached(redisClient *c); -int getClientLimitClassByName(char *name); -char *getClientLimitClassName(int class); +int getClientTypeByName(char *name); +char *getClientTypeName(int class); void flushSlavesOutputBuffers(void); void disconnectSlaves(void); int listenToPort(int port, int *fds, int *count); -- cgit v1.2.1