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:
parent
aa19fd612b
commit
56d26c2380
@ -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:
|
||||||
|
18
src/config.c
18
src/config.c
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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 */
|
||||||
|
16
src/redis.h
16
src/redis.h
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user