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.
This commit is contained in:
antirez 2014-06-16 10:43:05 +02:00
parent aa19fd612b
commit 56d26c2380
5 changed files with 38 additions and 37 deletions

View File

@ -768,8 +768,8 @@ activerehashing yes
# #
# The limit can be set differently for the three different classes of clients: # The limit can be set differently for the three different classes of clients:
# #
# normal -> normal clients # normal -> normal clients including MONITOR clients
# slave -> slave clients and MONITOR clients # slave -> slave clients
# pubsub -> clients subscribed to at least one pubsub channel or pattern # pubsub -> clients subscribed to at least one pubsub channel or pattern
# #
# The syntax of every client-output-buffer-limit directive is the following: # The syntax of every client-output-buffer-limit directive is the following:

View File

@ -50,7 +50,7 @@ static struct {
{NULL, 0} {NULL, 0}
}; };
clientBufferLimitsConfig clientBufferLimitsDefaults[REDIS_CLIENT_LIMIT_NUM_CLASSES] = { clientBufferLimitsConfig clientBufferLimitsDefaults[REDIS_CLIENT_TYPE_COUNT] = {
{0, 0, 0}, /* normal */ {0, 0, 0}, /* normal */
{1024*1024*256, 1024*1024*64, 60}, /* slave */ {1024*1024*256, 1024*1024*64, 60}, /* slave */
{1024*1024*32, 1024*1024*8, 60} /* pubsub */ {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") && } else if (!strcasecmp(argv[0],"client-output-buffer-limit") &&
argc == 5) argc == 5)
{ {
int class = getClientLimitClassByName(argv[1]); int class = getClientTypeByName(argv[1]);
unsigned long long hard, soft; unsigned long long hard, soft;
int soft_seconds; int soft_seconds;
@ -817,7 +817,7 @@ void configSetCommand(redisClient *c) {
long val; long val;
if ((j % 4) == 0) { if ((j % 4) == 0) {
if (getClientLimitClassByName(v[j]) == -1) { if (getClientTypeByName(v[j]) == -1) {
sdsfreesplitres(v,vlen); sdsfreesplitres(v,vlen);
goto badfmt; goto badfmt;
} }
@ -835,7 +835,7 @@ void configSetCommand(redisClient *c) {
unsigned long long hard, soft; unsigned long long hard, soft;
int soft_seconds; int soft_seconds;
class = getClientLimitClassByName(v[j]); class = getClientTypeByName(v[j]);
hard = strtoll(v[j+1],NULL,10); hard = strtoll(v[j+1],NULL,10);
soft = strtoll(v[j+2],NULL,10); soft = strtoll(v[j+2],NULL,10);
soft_seconds = strtoll(v[j+3],NULL,10); soft_seconds = strtoll(v[j+3],NULL,10);
@ -1113,13 +1113,13 @@ void configGetCommand(redisClient *c) {
sds buf = sdsempty(); sds buf = sdsempty();
int j; 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", buf = sdscatprintf(buf,"%s %llu %llu %ld",
getClientLimitClassName(j), getClientTypeName(j),
server.client_obuf_limits[j].hard_limit_bytes, server.client_obuf_limits[j].hard_limit_bytes,
server.client_obuf_limits[j].soft_limit_bytes, server.client_obuf_limits[j].soft_limit_bytes,
(long) server.client_obuf_limits[j].soft_limit_seconds); (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); buf = sdscatlen(buf," ",1);
} }
addReplyBulkCString(c,"client-output-buffer-limit"); addReplyBulkCString(c,"client-output-buffer-limit");
@ -1535,7 +1535,7 @@ void rewriteConfigClientoutputbufferlimitOption(struct rewriteConfigState *state
int j; int j;
char *option = "client-output-buffer-limit"; 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 != int force = (server.client_obuf_limits[j].hard_limit_bytes !=
clientBufferLimitsDefaults[j].hard_limit_bytes) || clientBufferLimitsDefaults[j].hard_limit_bytes) ||
(server.client_obuf_limits[j].soft_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); server.client_obuf_limits[j].soft_limit_bytes);
line = sdscatprintf(sdsempty(),"%s %s %s %s %ld", 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); (long) server.client_obuf_limits[j].soft_limit_seconds);
rewriteConfigRewriteLine(state,option,line,force); rewriteConfigRewriteLine(state,option,line,force);
} }

View File

@ -1481,30 +1481,31 @@ unsigned long getClientOutputBufferMemoryUsage(redisClient *c) {
* classes of clients. * classes of clients.
* *
* The function will return one of the following: * The function will return one of the following:
* REDIS_CLIENT_LIMIT_CLASS_NORMAL -> Normal client * REDIS_CLIENT_TYPE_NORMAL -> Normal client
* REDIS_CLIENT_LIMIT_CLASS_SLAVE -> Slave or client executing MONITOR command * REDIS_CLIENT_TYPE_SLAVE -> Slave or client executing MONITOR command
* REDIS_CLIENT_LIMIT_CLASS_PUBSUB -> Client subscribed to Pub/Sub channels * REDIS_CLIENT_TYPE_PUBSUB -> Client subscribed to Pub/Sub channels
*/ */
int getClientLimitClass(redisClient *c) { int getClientType(redisClient *c) {
if (c->flags & REDIS_SLAVE) return REDIS_CLIENT_LIMIT_CLASS_SLAVE; if ((c->flags & REDIS_SLAVE) && !(c->flags & REDIS_MONITOR))
return REDIS_CLIENT_TYPE_SLAVE;
if (dictSize(c->pubsub_channels) || listLength(c->pubsub_patterns)) if (dictSize(c->pubsub_channels) || listLength(c->pubsub_patterns))
return REDIS_CLIENT_LIMIT_CLASS_PUBSUB; return REDIS_CLIENT_TYPE_PUBSUB;
return REDIS_CLIENT_LIMIT_CLASS_NORMAL; return REDIS_CLIENT_TYPE_NORMAL;
} }
int getClientLimitClassByName(char *name) { int getClientTypeByName(char *name) {
if (!strcasecmp(name,"normal")) return REDIS_CLIENT_LIMIT_CLASS_NORMAL; if (!strcasecmp(name,"normal")) return REDIS_CLIENT_TYPE_NORMAL;
else if (!strcasecmp(name,"slave")) return REDIS_CLIENT_LIMIT_CLASS_SLAVE; else if (!strcasecmp(name,"slave")) return REDIS_CLIENT_TYPE_SLAVE;
else if (!strcasecmp(name,"pubsub")) return REDIS_CLIENT_LIMIT_CLASS_PUBSUB; else if (!strcasecmp(name,"pubsub")) return REDIS_CLIENT_TYPE_PUBSUB;
else return -1; else return -1;
} }
char *getClientLimitClassName(int class) { char *getClientTypeName(int class) {
switch(class) { switch(class) {
case REDIS_CLIENT_LIMIT_CLASS_NORMAL: return "normal"; case REDIS_CLIENT_TYPE_NORMAL: return "normal";
case REDIS_CLIENT_LIMIT_CLASS_SLAVE: return "slave"; case REDIS_CLIENT_TYPE_SLAVE: return "slave";
case REDIS_CLIENT_LIMIT_CLASS_PUBSUB: return "pubsub"; case REDIS_CLIENT_TYPE_PUBSUB: return "pubsub";
default: return NULL; default: return NULL;
} }
} }
@ -1518,7 +1519,7 @@ int checkClientOutputBufferLimits(redisClient *c) {
int soft = 0, hard = 0, class; int soft = 0, hard = 0, class;
unsigned long used_mem = getClientOutputBufferMemoryUsage(c); unsigned long used_mem = getClientOutputBufferMemoryUsage(c);
class = getClientLimitClass(c); class = getClientType(c);
if (server.client_obuf_limits[class].hard_limit_bytes && if (server.client_obuf_limits[class].hard_limit_bytes &&
used_mem >= server.client_obuf_limits[class].hard_limit_bytes) used_mem >= server.client_obuf_limits[class].hard_limit_bytes)
hard = 1; hard = 1;

View File

@ -1485,7 +1485,7 @@ void initServerConfig() {
server.repl_no_slaves_since = time(NULL); server.repl_no_slaves_since = time(NULL);
/* Client output buffer limits */ /* 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]; server.client_obuf_limits[j] = clientBufferLimitsDefaults[j];
/* Double constants initialization */ /* Double constants initialization */

View File

@ -248,10 +248,10 @@
/* Client classes for client limits, currently used only for /* Client classes for client limits, currently used only for
* the max-client-output-buffer limit implementation. */ * the max-client-output-buffer limit implementation. */
#define REDIS_CLIENT_LIMIT_CLASS_NORMAL 0 #define REDIS_CLIENT_TYPE_NORMAL 0 /* Normal req-reply clients + MONITORs */
#define REDIS_CLIENT_LIMIT_CLASS_SLAVE 1 #define REDIS_CLIENT_TYPE_SLAVE 1 /* Slaves. */
#define REDIS_CLIENT_LIMIT_CLASS_PUBSUB 2 #define REDIS_CLIENT_TYPE_PUBSUB 2 /* Clients subscribed to PubSub channels. */
#define REDIS_CLIENT_LIMIT_NUM_CLASSES 3 #define REDIS_CLIENT_TYPE_COUNT 3
/* Slave replication state - from the point of view of the slave. */ /* Slave replication state - from the point of view of the slave. */
#define REDIS_REPL_NONE 0 /* No active replication */ #define REDIS_REPL_NONE 0 /* No active replication */
@ -585,7 +585,7 @@ typedef struct clientBufferLimitsConfig {
time_t soft_limit_seconds; time_t soft_limit_seconds;
} clientBufferLimitsConfig; } 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 /* The redisOp structure defines a Redis Operation, that is an instance of
* a command with an argument vector, database ID, propagation target * 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 */ size_t client_max_querybuf_len; /* Limit for client query buffer length */
int dbnum; /* Total number of configured DBs */ int dbnum; /* Total number of configured DBs */
int daemonize; /* True if running as a daemon */ 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 */ /* AOF persistence */
int aof_state; /* REDIS_AOF_(ON|OFF|WAIT_REWRITE) */ int aof_state; /* REDIS_AOF_(ON|OFF|WAIT_REWRITE) */
int aof_fsync; /* Kind of fsync() policy */ int aof_fsync; /* Kind of fsync() policy */
@ -1002,8 +1002,8 @@ void rewriteClientCommandArgument(redisClient *c, int i, robj *newval);
unsigned long getClientOutputBufferMemoryUsage(redisClient *c); unsigned long getClientOutputBufferMemoryUsage(redisClient *c);
void freeClientsInAsyncFreeQueue(void); void freeClientsInAsyncFreeQueue(void);
void asyncCloseClientOnOutputBufferLimitReached(redisClient *c); void asyncCloseClientOnOutputBufferLimitReached(redisClient *c);
int getClientLimitClassByName(char *name); int getClientTypeByName(char *name);
char *getClientLimitClassName(int class); char *getClientTypeName(int class);
void flushSlavesOutputBuffers(void); void flushSlavesOutputBuffers(void);
void disconnectSlaves(void); void disconnectSlaves(void);
int listenToPort(int port, int *fds, int *count); int listenToPort(int port, int *fds, int *count);