Skip to content

Commit

Permalink
Client types generalized.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
antirez committed Jun 16, 2014
1 parent aa19fd6 commit 56d26c2
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 37 deletions.
4 changes: 2 additions & 2 deletions redis.conf
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
18 changes: 9 additions & 9 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
}
Expand All @@ -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);
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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 !=
Expand All @@ -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);
}
Expand Down
35 changes: 18 additions & 17 deletions src/networking.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}

Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/redis.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
16 changes: 8 additions & 8 deletions src/redis.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 56d26c2

Please sign in to comment.