Skip to content

Commit

Permalink
support additional filters like db, tot-net-out, tot-net-in, lib-name…
Browse files Browse the repository at this point in the history
…, lib-ver

Signed-off-by: Sarthak Aggarwal <[email protected]>
  • Loading branch information
sarthakaggarwal97 committed Jan 21, 2025
1 parent 3346867 commit 49c3a95
Show file tree
Hide file tree
Showing 5 changed files with 256 additions and 8 deletions.
18 changes: 14 additions & 4 deletions src/commands.def
Original file line number Diff line number Diff line change
Expand Up @@ -1289,7 +1289,7 @@ commandHistory CLIENT_KILL_History[] = {
{"6.2.0","`LADDR` option."},
{"8.0.0","`MAXAGE` option."},
{"8.0.0","Replaced `master` `TYPE` with `primary`. `master` still supported for backward compatibility."},
{"8.1.0","`ID` option accepts multiple IDs. Added filters NAME, MINIDLE, FLAGS, SUBSCRIBED-PATTERN, SUBSCRIBED-CHANNEL and SUBSCRIBED-SHARD-CHANNEL"},
{"8.1.0","`ID` option accepts multiple IDs. Added filters NAME, MINIDLE, FLAGS, SUBSCRIBED-PATTERN, SUBSCRIBED-CHANNEL, SUBSCRIBED-SHARD-CHANNEL, LIB-NAME, LIB-VER, DB, TOTAL-NET-IN and TOTAL-NET-OUT"},
};
#endif

Expand Down Expand Up @@ -1334,12 +1334,17 @@ struct COMMAND_ARG CLIENT_KILL_filter_new_format_Subargs[] = {
{MAKE_ARG("subscribed-pattern",ARG_TYPE_STRING,-1,"SUBSCRIBED-PATTERN",NULL,"8.1.0",CMD_ARG_OPTIONAL,0,NULL)},
{MAKE_ARG("subscribed-channel",ARG_TYPE_STRING,-1,"SUBSCRIBED-CHANNEL",NULL,"8.1.0",CMD_ARG_OPTIONAL,0,NULL)},
{MAKE_ARG("subscribed-shard-channel",ARG_TYPE_STRING,-1,"SUBSCRIBED-SHARD-CHANNEL",NULL,"8.1.0",CMD_ARG_OPTIONAL,0,NULL)},
{MAKE_ARG("lib-name",ARG_TYPE_STRING,-1,"LIB-NAME",NULL,"8.1.0",CMD_ARG_OPTIONAL,0,NULL)},
{MAKE_ARG("lib-ver",ARG_TYPE_STRING,-1,"LIB-VER",NULL,"8.1.0",CMD_ARG_OPTIONAL,0,NULL)},
{MAKE_ARG("db",ARG_TYPE_INTEGER,-1,"DB",NULL,"8.1.0",CMD_ARG_OPTIONAL,0,NULL)},
{MAKE_ARG("total-net-in",ARG_TYPE_INTEGER,-1,"TOTAL-NET-IN",NULL,"8.1.0",CMD_ARG_OPTIONAL,0,NULL)},
{MAKE_ARG("total-net-out",ARG_TYPE_INTEGER,-1,"TOTAL-NET-OUT",NULL,"8.1.0",CMD_ARG_OPTIONAL,0,NULL)},
};

/* CLIENT KILL filter argument table */
struct COMMAND_ARG CLIENT_KILL_filter_Subargs[] = {
{MAKE_ARG("old-format",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,"2.8.12"),.display_text="ip:port"},
{MAKE_ARG("new-format",ARG_TYPE_ONEOF,-1,NULL,NULL,NULL,CMD_ARG_MULTIPLE,13,NULL),.subargs=CLIENT_KILL_filter_new_format_Subargs},
{MAKE_ARG("new-format",ARG_TYPE_ONEOF,-1,NULL,NULL,NULL,CMD_ARG_MULTIPLE,18,NULL),.subargs=CLIENT_KILL_filter_new_format_Subargs},
};

/* CLIENT KILL argument table */
Expand All @@ -1359,7 +1364,7 @@ commandHistory CLIENT_LIST_History[] = {
{"7.0.0","Added `resp`, `multi-mem`, `rbs` and `rbp` fields."},
{"7.0.3","Added `ssub` field."},
{"8.0.0","Replaced `master` `TYPE` with `primary`. `master` still supported for backward compatibility."},
{"8.1.0","Added filters USER, ADDR, LADDR, SKIPME, MAXAGE, NAME, MINIDLE, FLAGS, SUBSCRIBED-PATTERN, SUBSCRIBED-CHANNEL and SUBSCRIBED-SHARD-CHANNEL."},
{"8.1.0","Added filters USER, ADDR, LADDR, SKIPME, MAXAGE, NAME, MINIDLE, FLAGS, SUBSCRIBED-PATTERN, SUBSCRIBED-CHANNEL, SUBSCRIBED-SHARD-CHANNEL, LIB-NAME, LIB-VER, DB, TOTAL-NET-IN and TOTAL-NET-OUT"},
};
#endif

Expand Down Expand Up @@ -1404,6 +1409,11 @@ struct COMMAND_ARG CLIENT_LIST_Args[] = {
{MAKE_ARG("subscribed-pattern",ARG_TYPE_STRING,-1,"SUBSCRIBED-PATTERN",NULL,"8.1.0",CMD_ARG_OPTIONAL,0,NULL)},
{MAKE_ARG("subscribed-channel",ARG_TYPE_STRING,-1,"SUBSCRIBED-CHANNEL",NULL,"8.1.0",CMD_ARG_OPTIONAL,0,NULL)},
{MAKE_ARG("subscribed-shard-channel",ARG_TYPE_STRING,-1,"SUBSCRIBED-SHARD-CHANNEL",NULL,"8.1.0",CMD_ARG_OPTIONAL,0,NULL)},
{MAKE_ARG("lib-name",ARG_TYPE_STRING,-1,"LIB-NAME",NULL,"8.1.0",CMD_ARG_OPTIONAL,0,NULL)},
{MAKE_ARG("lib-ver",ARG_TYPE_STRING,-1,"LIB-VER",NULL,"8.1.0",CMD_ARG_OPTIONAL,0,NULL)},
{MAKE_ARG("db",ARG_TYPE_INTEGER,-1,"DB",NULL,"8.1.0",CMD_ARG_OPTIONAL,0,NULL)},
{MAKE_ARG("total-net-in",ARG_TYPE_INTEGER,-1,"TOTAL-NET-IN",NULL,"8.1.0",CMD_ARG_OPTIONAL,0,NULL)},
{MAKE_ARG("total-net-out",ARG_TYPE_INTEGER,-1,"TOTAL-NET-OUT",NULL,"8.1.0",CMD_ARG_OPTIONAL,0,NULL)},
};

/********** CLIENT NO_EVICT ********************/
Expand Down Expand Up @@ -1686,7 +1696,7 @@ struct COMMAND_STRUCT CLIENT_Subcommands[] = {
{MAKE_CMD("import-source","Mark this client as an import source when server is in import mode.","O(1)","8.1.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_IMPORT_SOURCE_History,0,CLIENT_IMPORT_SOURCE_Tips,0,clientImportSourceCommand,3,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE,ACL_CATEGORY_CONNECTION,CLIENT_IMPORT_SOURCE_Keyspecs,0,NULL,1),.args=CLIENT_IMPORT_SOURCE_Args},
{MAKE_CMD("info","Returns information about the connection.","O(1)","6.2.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_INFO_History,0,CLIENT_INFO_Tips,1,clientInfoCommand,2,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_INFO_Keyspecs,0,NULL,0)},
{MAKE_CMD("kill","Terminates open connections.","O(N) where N is the number of client connections","2.4.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_KILL_History,8,CLIENT_KILL_Tips,0,clientKillCommand,-3,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_KILL_Keyspecs,0,NULL,1),.args=CLIENT_KILL_Args},
{MAKE_CMD("list","Lists open connections.","O(N) where N is the number of client connections","2.4.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_LIST_History,8,CLIENT_LIST_Tips,1,clientListCommand,-2,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_LIST_Keyspecs,0,NULL,13),.args=CLIENT_LIST_Args},
{MAKE_CMD("list","Lists open connections.","O(N) where N is the number of client connections","2.4.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_LIST_History,8,CLIENT_LIST_Tips,1,clientListCommand,-2,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_LIST_Keyspecs,0,NULL,18),.args=CLIENT_LIST_Args},
{MAKE_CMD("no-evict","Sets the client eviction mode of the connection.","O(1)","7.0.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_NO_EVICT_History,0,CLIENT_NO_EVICT_Tips,0,clientNoEvictCommand,3,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_NO_EVICT_Keyspecs,0,NULL,1),.args=CLIENT_NO_EVICT_Args},
{MAKE_CMD("no-touch","Controls whether commands sent by the client affect the LRU/LFU of accessed keys.","O(1)","7.2.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_NO_TOUCH_History,0,CLIENT_NO_TOUCH_Tips,0,clientNoTouchCommand,3,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE,ACL_CATEGORY_CONNECTION,CLIENT_NO_TOUCH_Keyspecs,0,NULL,1),.args=CLIENT_NO_TOUCH_Args},
{MAKE_CMD("pause","Suspends commands processing.","O(1)","3.0.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_PAUSE_History,1,CLIENT_PAUSE_Tips,0,clientPauseCommand,-3,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_PAUSE_Keyspecs,0,NULL,2),.args=CLIENT_PAUSE_Args},
Expand Down
37 changes: 36 additions & 1 deletion src/commands/client-kill.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
],
[
"8.1.0",
"`ID` option accepts multiple IDs. Added filters NAME, MINIDLE, FLAGS, SUBSCRIBED-PATTERN, SUBSCRIBED-CHANNEL and SUBSCRIBED-SHARD-CHANNEL"
"`ID` option accepts multiple IDs. Added filters NAME, MINIDLE, FLAGS, SUBSCRIBED-PATTERN, SUBSCRIBED-CHANNEL, SUBSCRIBED-SHARD-CHANNEL, LIB-NAME, LIB-VER, DB, TOTAL-NET-IN and TOTAL-NET-OUT"
]
],
"command_flags": [
Expand Down Expand Up @@ -204,6 +204,41 @@
"type": "string",
"optional": true,
"since": "8.1.0"
},
{
"token": "LIB-NAME",
"name": "lib-name",
"type": "string",
"optional": true,
"since": "8.1.0"
},
{
"token": "LIB-VER",
"name": "lib-ver",
"type": "string",
"optional": true,
"since": "8.1.0"
},
{
"token": "DB",
"name": "db",
"type": "integer",
"optional": true,
"since": "8.1.0"
},
{
"token": "TOTAL-NET-IN",
"name": "total-net-in",
"type": "integer",
"optional": true,
"since": "8.1.0"
},
{
"token": "TOTAL-NET-OUT",
"name": "total-net-out",
"type": "integer",
"optional": true,
"since": "8.1.0"
}
]
}
Expand Down
37 changes: 36 additions & 1 deletion src/commands/client-list.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
],
[
"8.1.0",
"Added filters USER, ADDR, LADDR, SKIPME, MAXAGE, NAME, MINIDLE, FLAGS, SUBSCRIBED-PATTERN, SUBSCRIBED-CHANNEL and SUBSCRIBED-SHARD-CHANNEL."
"Added filters USER, ADDR, LADDR, SKIPME, MAXAGE, NAME, MINIDLE, FLAGS, SUBSCRIBED-PATTERN, SUBSCRIBED-CHANNEL, SUBSCRIBED-SHARD-CHANNEL, LIB-NAME, LIB-VER, DB, TOTAL-NET-IN and TOTAL-NET-OUT"
]
],
"command_flags": [
Expand Down Expand Up @@ -186,6 +186,41 @@
"type": "string",
"optional": true,
"since": "8.1.0"
},
{
"token": "LIB-NAME",
"name": "lib-name",
"type": "string",
"optional": true,
"since": "8.1.0"
},
{
"token": "LIB-VER",
"name": "lib-ver",
"type": "string",
"optional": true,
"since": "8.1.0"
},
{
"token": "DB",
"name": "db",
"type": "integer",
"optional": true,
"since": "8.1.0"
},
{
"token": "TOTAL-NET-IN",
"name": "total-net-in",
"type": "integer",
"optional": true,
"since": "8.1.0"
},
{
"token": "TOTAL-NET-OUT",
"name": "total-net-out",
"type": "integer",
"optional": true,
"since": "8.1.0"
}
]
}
Expand Down
67 changes: 65 additions & 2 deletions src/networking.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,16 @@ typedef struct {
robj *subscribed_channel;
/* Client subscribed shard channel for filtering. If NULL, no filtering is applied. */
robj *subscribed_shard_channel;
/* Library name to filter. If NULL, no library name filtering is applied. */
robj *lib_name;
/* Library version to filter. If NULL, no library version filtering is applied. */
robj *lib_ver;
/* Database index to filter. If set to -1, no DB number filtering is applied. */
int db_number;
/* Total network input bytes to filter. If set to -1, no filtering is applied. */
unsigned long long tot_net_in;
/* Total network output bytes to filter. If set to -1, no filtering is applied. */
unsigned long long tot_net_out;
} clientFilter;

static void setProtocolError(const char *errstr, client *c);
Expand Down Expand Up @@ -3632,6 +3642,45 @@ static int parseClientFiltersOrReply(client *c, int index, clientFilter *filter)
} else if (!strcasecmp(c->argv[index]->ptr, "subscribed-shard-channel") && moreargs) {
filter->subscribed_shard_channel = createObject(OBJ_STRING, sdsnew(c->argv[index + 1]->ptr));
index += 2;
} else if (!strcasecmp(c->argv[index]->ptr, "lib-name") && moreargs) {
filter->lib_name = createObject(OBJ_STRING, sdsnew(c->argv[index + 1]->ptr));
index += 2;
} else if (!strcasecmp(c->argv[index]->ptr, "lib-ver") && moreargs) {
filter->lib_ver = createObject(OBJ_STRING, sdsnew(c->argv[index + 1]->ptr));
index += 2;
} else if (!strcasecmp(c->argv[index]->ptr, "db") && moreargs) {
int tmp;
if (getIntFromObjectOrReply(c, c->argv[index + 1], &tmp,
"db is not an integer or out of range") != C_OK)
return C_ERR;
if (tmp < 0 || tmp >= server.dbnum) {
addReplyErrorFormat(c, "db number should be between 0 and %d", server.dbnum - 1);
return C_ERR;
}
filter->db_number = tmp;
index += 2;
} else if (!strcasecmp(c->argv[index]->ptr, "tot-net-in") && moreargs) {
long long tmp;
if (getLongLongFromObjectOrReply(c, c->argv[index + 1], &tmp,
"tot-net-in is not an integer or out of range") != C_OK)
return C_ERR;
if (tmp < 0) {
addReplyError(c, "tot-net-in should be non-negative");
return C_ERR;
}
filter->tot_net_in = tmp;
index += 2;
} else if (!strcasecmp(c->argv[index]->ptr, "tot-net-out") && moreargs) {
long long tmp;
if (getLongLongFromObjectOrReply(c, c->argv[index + 1], &tmp,
"tot-net-out is not an integer or out of range") != C_OK)
return C_ERR;
if (tmp < 0) {
addReplyError(c, "tot-net-out should be non-negative");
return C_ERR;
}
filter->tot_net_out = tmp;
index += 2;
} else {
addReplyErrorObject(c, shared.syntaxerr);
return C_ERR;
Expand Down Expand Up @@ -3659,6 +3708,11 @@ static int clientMatchesFilter(client *client, clientFilter client_filter) {
if (client_filter.subscribed_pattern && !clientSubscribedToPattern(client, client_filter.subscribed_pattern)) return 0;
if (client_filter.subscribed_channel && !clientSubscribedToChannel(client, client_filter.subscribed_channel)) return 0;
if (client_filter.subscribed_shard_channel && !clientSubscribedToShardChannel(client, client_filter.subscribed_shard_channel)) return 0;
if (client_filter.lib_name && (!client->lib_name || compareStringObjects(client->lib_name, client_filter.lib_name) != 0)) return 0;
if (client_filter.lib_ver && (!client->lib_ver || compareStringObjects(client->lib_ver, client_filter.lib_ver) != 0)) return 0;
if (client_filter.db_number != -1 && client->db->id != client_filter.db_number) return 0;
if (client->net_input_bytes < client_filter.tot_net_in) return 0;
if (client->net_output_bytes < client_filter.tot_net_out) return 0;

/* If all conditions are satisfied, the client matches the filter. */
return 1;
Expand Down Expand Up @@ -3887,7 +3941,7 @@ void clientListCommand(client *c) {
sds response = NULL;

if (c->argc > 3) {
clientFilter filter = {.ids = NULL, .max_age = 0, .addr = NULL, .laddr = NULL, .user = NULL, .type = -1, .skipme = 0};
clientFilter filter = {.ids = NULL, .max_age = 0, .addr = NULL, .laddr = NULL, .user = NULL, .type = -1, .skipme = 0, .db_number = -1};
int i = 2;

if (parseClientFiltersOrReply(c, i, &filter) != C_OK) {
Expand Down Expand Up @@ -3951,7 +4005,8 @@ void clientKillCommand(client *c) {
.laddr = NULL,
.user = NULL,
.type = -1,
.skipme = 1};
.skipme = 1,
.db_number = -1};

int killed = 0, close_this_client = 0;

Expand Down Expand Up @@ -4019,6 +4074,14 @@ static void freeClientFilter(clientFilter *filter) {
decrRefCount(filter->subscribed_channel);
filter->subscribed_channel = NULL;
}
if (filter->lib_name) {
decrRefCount(filter->lib_name);
filter->lib_name = NULL;
}
if (filter->lib_ver) {
decrRefCount(filter->lib_ver);
filter->lib_ver = NULL;
}
}


Expand Down
105 changes: 105 additions & 0 deletions tests/unit/introspection.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -1313,6 +1313,111 @@ start_server {tags {"introspection"}} {
}
} {} {external:skip}


test {CLIENT LIST can filter by LIB-NAME} {
r CLIENT SETINFO lib-name mylib
set result [r client list lib-name mylib]
assert_match {*lib-name=mylib*} $result
}

test {CLIENT LIST can filter by LIB-VER} {
r CLIENT SETINFO lib-ver 1.2.3
set result [r client list lib-ver 1.2.3]
assert_match {*lib-ver=1.2.3*} $result
}

test {CLIENT LIST can filter by DB number} {
r select 2
set result [r client list db 2]
assert_match {*db=2*} $result
}

test {CLIENT LIST can filter by TOT-NET-IN} {
r ping
set result [r client list tot-net-in 1]
assert_match {*tot-net-in=*} $result
}

test {CLIENT LIST can filter by TOT-NET-OUT} {
r ping
set result [r client list tot-net-out 1]
assert_match {*tot-net-out=*} $result
}

test {CLIENT KILL can filter by LIB-NAME} {
set c1 [valkey_client]
set c2 [valkey_client]

$c1 client setinfo lib-name mylib
$c2 client kill lib-name mylib

set result [$c2 client list]
assert {[string match {*lib-name=mylib*} $result] == 0}

catch {$c2 close}
}

test {CLIENT KILL can filter by LIB-VER} {
set c1 [valkey_client]
set c2 [valkey_client]

$c1 client setinfo lib-ver 1.2.3
$c2 client kill lib-ver 1.2.3

set result [$c2 client list]
assert {[string match {*lib-ver=1.2.3*} $result] == 0}

catch {$c2 close}
}

test {CLIENT KILL can filter by DB} {
set c1 [valkey_client]
set c2 [valkey_client]

$c1 select 2
$c2 client kill db 2

set result [$c2 client list]
assert {[string match {*db=2*} $result] == 0}

catch {$c2 close}
}

test {CLIENT KILL can filter by TOT-NET-IN} {
set c1 [valkey_client]
set c2 [valkey_client]

# Generate some network input by sending commands
for {set i 0} {$i < 20} {incr i} {
$c1 ping
}

# Kill clients with a `TOT-NET-IN` greater than 100 bytes
$c2 client kill tot-net-in 100

set result [$c2 client list]
assert {[string match "*tot-net-in=*" $result] == 1}

catch {$c2 close}
}

test {CLIENT KILL can filter by TOT-NET-OUT} {
set c1 [valkey_client]
set c2 [valkey_client]

# Generate some network output by receiving replies
for {set i 0} {$i < 10} {incr i} {
$c1 ping
}

# Kill clients with a `TOT-NET-OUT` greater than 100 bytes
$c2 client kill tot-net-out 50

set result [$c2 client list]
assert {[string match "*tot-net-out=*" $result] == 1}

}

test {valkey-server command line arguments - allow passing option name and option value in the same arg} {
start_server {config "default.conf" args {"--maxmemory 700mb" "--maxmemory-policy volatile-lru"}} {
assert_match [r config get maxmemory] {maxmemory 734003200}
Expand Down

0 comments on commit 49c3a95

Please sign in to comment.