Skip to content

[Client Introspection] Client Count Command #1467

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: unstable
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions src/commands.def
Original file line number Diff line number Diff line change
Expand Up @@ -1176,6 +1176,62 @@ struct COMMAND_ARG CLIENT_CAPA_Args[] = {
{MAKE_ARG("capability",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_MULTIPLE,0,NULL)},
};

/********** CLIENT COUNT ********************/

#ifndef SKIP_CMD_HISTORY_TABLE
/* CLIENT COUNT history */
commandHistory CLIENT_COUNT_History[] = {
{"9.0.0","Introducing client count command with filters"},
};
#endif

#ifndef SKIP_CMD_TIPS_TABLE
/* CLIENT COUNT tips */
const char *CLIENT_COUNT_Tips[] = {
"nondeterministic_output",
};
#endif

#ifndef SKIP_CMD_KEY_SPECS_TABLE
/* CLIENT COUNT key specs */
#define CLIENT_COUNT_Keyspecs NULL
#endif

/* CLIENT COUNT type argument table */
struct COMMAND_ARG CLIENT_COUNT_type_Subargs[] = {
{MAKE_ARG("normal",ARG_TYPE_PURE_TOKEN,-1,"NORMAL",NULL,NULL,CMD_ARG_NONE,0,NULL)},
{MAKE_ARG("master",ARG_TYPE_PURE_TOKEN,-1,"MASTER",NULL,NULL,CMD_ARG_NONE,0,NULL)},
{MAKE_ARG("primary",ARG_TYPE_PURE_TOKEN,-1,"PRIMARY",NULL,NULL,CMD_ARG_NONE,0,NULL)},
{MAKE_ARG("slave",ARG_TYPE_PURE_TOKEN,-1,"SLAVE",NULL,NULL,CMD_ARG_NONE,0,NULL)},
{MAKE_ARG("replica",ARG_TYPE_PURE_TOKEN,-1,"REPLICA",NULL,NULL,CMD_ARG_NONE,0,NULL)},
{MAKE_ARG("pubsub",ARG_TYPE_PURE_TOKEN,-1,"PUBSUB",NULL,NULL,CMD_ARG_NONE,0,NULL)},
};

/* CLIENT COUNT skipme argument table */
struct COMMAND_ARG CLIENT_COUNT_skipme_Subargs[] = {
{MAKE_ARG("yes",ARG_TYPE_PURE_TOKEN,-1,"YES",NULL,NULL,CMD_ARG_NONE,0,NULL)},
{MAKE_ARG("no",ARG_TYPE_PURE_TOKEN,-1,"NO",NULL,NULL,CMD_ARG_NONE,0,NULL)},
};

/* CLIENT COUNT argument table */
struct COMMAND_ARG CLIENT_COUNT_Args[] = {
{MAKE_ARG("id",ARG_TYPE_INTEGER,-1,"ID",NULL,"9.0.0",CMD_ARG_OPTIONAL|CMD_ARG_MULTIPLE,0,NULL)},
{MAKE_ARG("type",ARG_TYPE_ONEOF,-1,"TYPE",NULL,"9.0.0",CMD_ARG_OPTIONAL,6,NULL),.subargs=CLIENT_COUNT_type_Subargs},
{MAKE_ARG("username",ARG_TYPE_STRING,-1,"USER",NULL,"9.0.0",CMD_ARG_OPTIONAL,0,NULL)},
{MAKE_ARG("addr",ARG_TYPE_STRING,-1,"ADDR",NULL,"9.0.0",CMD_ARG_OPTIONAL,0,NULL),.display_text="ip:port"},
{MAKE_ARG("laddr",ARG_TYPE_STRING,-1,"LADDR",NULL,"9.0.0",CMD_ARG_OPTIONAL,0,NULL),.display_text="ip:port"},
{MAKE_ARG("skipme",ARG_TYPE_ONEOF,-1,"SKIPME",NULL,"9.0.0",CMD_ARG_OPTIONAL,2,NULL),.subargs=CLIENT_COUNT_skipme_Subargs},
{MAKE_ARG("maxage",ARG_TYPE_INTEGER,-1,"MAXAGE",NULL,"9.0.0",CMD_ARG_OPTIONAL,0,NULL)},
{MAKE_ARG("name",ARG_TYPE_STRING,-1,"NAME",NULL,"9.0.0",CMD_ARG_OPTIONAL,0,NULL)},
{MAKE_ARG("idle",ARG_TYPE_INTEGER,-1,"IDLE",NULL,"9.0.0",CMD_ARG_OPTIONAL,0,NULL)},
{MAKE_ARG("flags",ARG_TYPE_STRING,-1,"FLAGS",NULL,"9.0.0",CMD_ARG_OPTIONAL,0,NULL)},
{MAKE_ARG("lib-name",ARG_TYPE_STRING,-1,"LIB-NAME",NULL,"9.0.0",CMD_ARG_OPTIONAL,0,NULL)},
{MAKE_ARG("lib-ver",ARG_TYPE_STRING,-1,"LIB-VER",NULL,"9.0.0",CMD_ARG_OPTIONAL,0,NULL)},
{MAKE_ARG("db",ARG_TYPE_INTEGER,-1,"DB",NULL,"9.0.0",CMD_ARG_OPTIONAL,0,NULL)},
{MAKE_ARG("capa",ARG_TYPE_STRING,-1,"CAPA",NULL,"9.0.0",CMD_ARG_OPTIONAL,0,NULL)},
{MAKE_ARG("ip",ARG_TYPE_STRING,-1,"IP",NULL,"9.0.0",CMD_ARG_OPTIONAL,0,NULL)},
};

/********** CLIENT GETNAME ********************/

#ifndef SKIP_CMD_HISTORY_TABLE
Expand Down Expand Up @@ -1699,6 +1755,7 @@ struct COMMAND_ARG CLIENT_UNBLOCK_Args[] = {
struct COMMAND_STRUCT CLIENT_Subcommands[] = {
{MAKE_CMD("caching","Instructs the server whether to track the keys in the next request.","O(1)","6.0.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_CACHING_History,0,CLIENT_CACHING_Tips,0,clientCachingCommand,3,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_CACHING_Keyspecs,0,NULL,1),.args=CLIENT_CACHING_Args},
{MAKE_CMD("capa","A client claims its capability.","O(1)","8.0.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_CAPA_History,0,CLIENT_CAPA_Tips,0,clientCapaCommand,-3,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE,ACL_CATEGORY_CONNECTION,CLIENT_CAPA_Keyspecs,0,NULL,1),.args=CLIENT_CAPA_Args},
{MAKE_CMD("count","Counts open connections.","O(N) where N is the number of client connections","9.0.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_COUNT_History,1,CLIENT_COUNT_Tips,1,clientCountCommand,-2,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_COUNT_Keyspecs,0,NULL,15),.args=CLIENT_COUNT_Args},
{MAKE_CMD("getname","Returns the name of the connection.","O(1)","2.6.9",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_GETNAME_History,0,CLIENT_GETNAME_Tips,0,clientGetNameCommand,2,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_GETNAME_Keyspecs,0,NULL,0)},
{MAKE_CMD("getredir","Returns the client ID to which the connection's tracking notifications are redirected.","O(1)","6.0.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_GETREDIR_History,0,CLIENT_GETREDIR_Tips,0,clientGetredirCommand,2,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_GETREDIR_Keyspecs,0,NULL,0)},
{MAKE_CMD("help","Returns helpful text about the different subcommands.","O(1)","5.0.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_HELP_History,0,CLIENT_HELP_Tips,0,clientHelpCommand,2,CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_HELP_Keyspecs,0,NULL,0)},
Expand Down
188 changes: 188 additions & 0 deletions src/commands/client-count.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
{
"COUNT": {
"summary": "Counts open connections.",
"complexity": "O(N) where N is the number of client connections",
"group": "connection",
"since": "9.0.0",
"arity": -2,
"container": "CLIENT",
"function": "clientCountCommand",
"history": [
[
"9.0.0",
"Introducing client count command with filters"
]
],
"command_flags": [
"ADMIN",
"NOSCRIPT",
"LOADING",
"STALE",
"SENTINEL"
],
"acl_categories": [
"CONNECTION"
],
"command_tips": [
"NONDETERMINISTIC_OUTPUT"
],
"reply_schema": {
"type": "string",
"description": "Information and statistics about client connections"
},
"arguments": [
{
"token": "ID",
"name": "id",
"type": "integer",
"optional": true,
"multiple": true,
"since": "9.0.0"
},
{
"token": "TYPE",
"name": "type",
"type": "oneof",
"optional": true,
"since": "9.0.0",
"arguments": [
{
"name": "normal",
"type": "pure-token",
"token": "normal"
},
{
"name": "master",
"type": "pure-token",
"token": "master"
},
{
"name": "primary",
"type": "pure-token",
"token": "primary"
},
{
"name": "slave",
"type": "pure-token",
"token": "slave"
},
{
"name": "replica",
"type": "pure-token",
"token": "replica"
},
{
"name": "pubsub",
"type": "pure-token",
"token": "pubsub"
}
]
},
{
"token": "USER",
"name": "username",
"type": "string",
"optional": true,
"since": "9.0.0"
},
{
"token": "ADDR",
"name": "addr",
"display": "ip:port",
"type": "string",
"optional": true,
"since": "9.0.0"
},
{
"token": "LADDR",
"name": "laddr",
"display": "ip:port",
"type": "string",
"optional": true,
"since": "9.0.0"
},
{
"token": "SKIPME",
"name": "skipme",
"type": "oneof",
"optional": true,
"since": "9.0.0",
"arguments": [
{
"name": "yes",
"type": "pure-token",
"token": "YES"
},
{
"name": "no",
"type": "pure-token",
"token": "NO"
}
]
},
{
"token": "MAXAGE",
"name": "maxage",
"type": "integer",
"optional": true,
"since": "9.0.0"
},
{
"token": "NAME",
"name": "name",
"type": "string",
"optional": true,
"since": "9.0.0"
},
{
"token": "IDLE",
"name": "idle",
"type": "integer",
"optional": true,
"since": "9.0.0"
},
{
"token": "FLAGS",
"name": "flags",
"type": "string",
"optional": true,
"since": "9.0.0"
},
{
"token": "LIB-NAME",
"name": "lib-name",
"type": "string",
"optional": true,
"since": "9.0.0"
},
{
"token": "LIB-VER",
"name": "lib-ver",
"type": "string",
"optional": true,
"since": "9.0.0"
},
{
"token": "DB",
"name": "db",
"type": "integer",
"optional": true,
"since": "9.0.0"
},
{
"token": "CAPA",
"name": "capa",
"type": "string",
"optional": true,
"since": "9.0.0"
},
{
"token": "IP",
"name": "ip",
"type": "string",
"optional": true,
"since": "9.0.0"
}
]
}
}
51 changes: 51 additions & 0 deletions src/networking.c
Original file line number Diff line number Diff line change
Expand Up @@ -4622,6 +4622,57 @@ void clientImportSourceCommand(client *c) {
}
}

void clientCountCommand(client *c) {
/* If there are additional arguments */
if (c->argc > 2) {
clientFilter filter = {.ids = NULL, .max_age = 0, .idle = 0, .addr = NULL, .laddr = NULL, .user = NULL, .type = -1, .skipme = 0, .db_number = -1};
const int i = 2; // Start parsing filters from the third argument

if (parseClientFiltersOrReply(c, i, &filter) != C_OK) {
/* Free filter resources on failure */
freeClientFilter(&filter);
return;
}

long long count = 0;
listIter li;
listNode *ln;
listRewind(server.clients, &li);

/* Count clients that match the filter */
while ((ln = listNext(&li)) != NULL) {
client *cl = listNodeValue(ln);
if (clientMatchesFilter(cl, &filter)) {
count++;
}
}

/* Free filter resources after use */
freeClientFilter(&filter);
/* Return the count to the client */
addReplyLongLong(c, count);

} else if (c->argc == 2) {
/* No filters, just "CLIENT COUNT" */
long long count = 0;
listIter li;
listNode *ln;
listRewind(server.clients, &li);

/* Count all clients */
while ((ln = listNext(&li)) != NULL) {
count++;
}

/* Return the total count to the client */
addReplyLongLong(c, count);
} else {
/* Invalid syntax */
addReplyErrorObject(c, shared.syntaxerr);
return;
}
}

void clientCommand(client *c) {
addReplySubcommandSyntaxError(c);
}
Expand Down
1 change: 1 addition & 0 deletions src/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -3818,6 +3818,7 @@ void clientTrackingInfoCommand(client *c);
void clientNoTouchCommand(client *c);
void clientCapaCommand(client *c);
void clientImportSourceCommand(client *c);
void clientCountCommand(client *c);
void helloCommand(client *c);
void clientSetinfoCommand(client *c);
void evalCommand(client *c);
Expand Down
Loading
Loading