diff --git a/src/commands.def b/src/commands.def index c5d766e3f8..cd919a80e1 100644 --- a/src/commands.def +++ b/src/commands.def @@ -1289,6 +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."}, }; #endif @@ -1320,7 +1321,7 @@ struct COMMAND_ARG CLIENT_KILL_filter_new_format_skipme_Subargs[] = { /* CLIENT KILL filter new_format argument table */ struct COMMAND_ARG CLIENT_KILL_filter_new_format_Subargs[] = { -{MAKE_ARG("client-id",ARG_TYPE_INTEGER,-1,"ID",NULL,"2.8.12",CMD_ARG_OPTIONAL,0,NULL)}, +{MAKE_ARG("client-id",ARG_TYPE_INTEGER,-1,"ID",NULL,"2.8.12",CMD_ARG_OPTIONAL|CMD_ARG_MULTIPLE,0,NULL)}, {MAKE_ARG("client-type",ARG_TYPE_ONEOF,-1,"TYPE",NULL,"2.8.12",CMD_ARG_OPTIONAL,6,NULL),.subargs=CLIENT_KILL_filter_new_format_client_type_Subargs}, {MAKE_ARG("username",ARG_TYPE_STRING,-1,"USER",NULL,NULL,CMD_ARG_OPTIONAL,0,NULL)}, {MAKE_ARG("addr",ARG_TYPE_STRING,-1,"ADDR",NULL,NULL,CMD_ARG_OPTIONAL,0,NULL),.display_text="ip:port"}, @@ -1352,6 +1353,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, and MAXAGE"}, }; #endif @@ -1375,10 +1377,21 @@ struct COMMAND_ARG CLIENT_LIST_client_type_Subargs[] = { {MAKE_ARG("pubsub",ARG_TYPE_PURE_TOKEN,-1,"PUBSUB",NULL,NULL,CMD_ARG_NONE,0,NULL)}, }; +/* CLIENT LIST skipme argument table */ +struct COMMAND_ARG CLIENT_LIST_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 LIST argument table */ struct COMMAND_ARG CLIENT_LIST_Args[] = { {MAKE_ARG("client-type",ARG_TYPE_ONEOF,-1,"TYPE",NULL,"5.0.0",CMD_ARG_OPTIONAL,4,NULL),.subargs=CLIENT_LIST_client_type_Subargs}, {MAKE_ARG("client-id",ARG_TYPE_INTEGER,-1,"ID",NULL,"6.2.0",CMD_ARG_OPTIONAL|CMD_ARG_MULTIPLE,0,NULL)}, +{MAKE_ARG("username",ARG_TYPE_STRING,-1,"USER",NULL,"8.1.0",CMD_ARG_OPTIONAL,0,NULL)}, +{MAKE_ARG("addr",ARG_TYPE_STRING,-1,"ADDR",NULL,"8.1.0",CMD_ARG_OPTIONAL,0,NULL),.display_text="ip:port"}, +{MAKE_ARG("laddr",ARG_TYPE_STRING,-1,"LADDR",NULL,"8.1.0",CMD_ARG_OPTIONAL,0,NULL),.display_text="ip:port"}, +{MAKE_ARG("skipme",ARG_TYPE_ONEOF,-1,"SKIPME",NULL,"8.1.0",CMD_ARG_OPTIONAL,2,NULL),.subargs=CLIENT_LIST_skipme_Subargs}, +{MAKE_ARG("maxage",ARG_TYPE_INTEGER,-1,"MAXAGE",NULL,"8.1.0",CMD_ARG_OPTIONAL,0,NULL)}, }; /********** CLIENT NO_EVICT ********************/ @@ -1652,26 +1665,26 @@ struct COMMAND_ARG CLIENT_UNBLOCK_Args[] = { /* CLIENT command table */ 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,clientCommand,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,clientCommand,-3,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE,ACL_CATEGORY_CONNECTION,CLIENT_CAPA_Keyspecs,0,NULL,1),.args=CLIENT_CAPA_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,clientCommand,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,clientCommand,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,clientCommand,2,CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_HELP_Keyspecs,0,NULL,0)}, -{MAKE_CMD("id","Returns the unique client ID of the connection.","O(1)","5.0.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_ID_History,0,CLIENT_ID_Tips,0,clientCommand,2,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_ID_Keyspecs,0,NULL,0)}, -{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,clientCommand,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,clientCommand,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,7,CLIENT_KILL_Tips,0,clientCommand,-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,7,CLIENT_LIST_Tips,1,clientCommand,-2,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_LIST_Keyspecs,0,NULL,2),.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,clientCommand,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,clientCommand,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,clientCommand,-3,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_PAUSE_Keyspecs,0,NULL,2),.args=CLIENT_PAUSE_Args}, -{MAKE_CMD("reply","Instructs the server whether to reply to commands.","O(1)","3.2.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_REPLY_History,0,CLIENT_REPLY_Tips,0,clientCommand,3,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_REPLY_Keyspecs,0,NULL,1),.args=CLIENT_REPLY_Args}, +{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("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)}, +{MAKE_CMD("id","Returns the unique client ID of the connection.","O(1)","5.0.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_ID_History,0,CLIENT_ID_Tips,0,clientIDCommand,2,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_ID_Keyspecs,0,NULL,0)}, +{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,7),.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}, +{MAKE_CMD("reply","Instructs the server whether to reply to commands.","O(1)","3.2.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_REPLY_History,0,CLIENT_REPLY_Tips,0,clientReplyCommand,3,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_REPLY_Keyspecs,0,NULL,1),.args=CLIENT_REPLY_Args}, {MAKE_CMD("setinfo","Sets information specific to the client or connection.","O(1)","7.2.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_SETINFO_History,0,CLIENT_SETINFO_Tips,2,clientSetinfoCommand,4,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_SETINFO_Keyspecs,0,NULL,1),.args=CLIENT_SETINFO_Args}, -{MAKE_CMD("setname","Sets the connection name.","O(1)","2.6.9",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_SETNAME_History,0,CLIENT_SETNAME_Tips,2,clientCommand,3,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_SETNAME_Keyspecs,0,NULL,1),.args=CLIENT_SETNAME_Args}, -{MAKE_CMD("tracking","Controls server-assisted client-side caching for the connection.","O(1). Some options may introduce additional complexity.","6.0.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_TRACKING_History,0,CLIENT_TRACKING_Tips,0,clientCommand,-3,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_TRACKING_Keyspecs,0,NULL,7),.args=CLIENT_TRACKING_Args}, -{MAKE_CMD("trackinginfo","Returns information about server-assisted client-side caching for the connection.","O(1)","6.2.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_TRACKINGINFO_History,0,CLIENT_TRACKINGINFO_Tips,0,clientCommand,2,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_TRACKINGINFO_Keyspecs,0,NULL,0)}, -{MAKE_CMD("unblock","Unblocks a client blocked by a blocking command from a different connection.","O(log N) where N is the number of client connections","5.0.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_UNBLOCK_History,0,CLIENT_UNBLOCK_Tips,0,clientCommand,-3,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_UNBLOCK_Keyspecs,0,NULL,2),.args=CLIENT_UNBLOCK_Args}, -{MAKE_CMD("unpause","Resumes processing commands from paused clients.","O(N) Where N is the number of paused clients","6.2.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_UNPAUSE_History,0,CLIENT_UNPAUSE_Tips,0,clientCommand,2,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_UNPAUSE_Keyspecs,0,NULL,0)}, +{MAKE_CMD("setname","Sets the connection name.","O(1)","2.6.9",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_SETNAME_History,0,CLIENT_SETNAME_Tips,2,clientSetNameCommand,3,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_SETNAME_Keyspecs,0,NULL,1),.args=CLIENT_SETNAME_Args}, +{MAKE_CMD("tracking","Controls server-assisted client-side caching for the connection.","O(1). Some options may introduce additional complexity.","6.0.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_TRACKING_History,0,CLIENT_TRACKING_Tips,0,clientTrackingCommand,-3,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_TRACKING_Keyspecs,0,NULL,7),.args=CLIENT_TRACKING_Args}, +{MAKE_CMD("trackinginfo","Returns information about server-assisted client-side caching for the connection.","O(1)","6.2.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_TRACKINGINFO_History,0,CLIENT_TRACKINGINFO_Tips,0,clientTrackingInfoCommand,2,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_TRACKINGINFO_Keyspecs,0,NULL,0)}, +{MAKE_CMD("unblock","Unblocks a client blocked by a blocking command from a different connection.","O(log N) where N is the number of client connections","5.0.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_UNBLOCK_History,0,CLIENT_UNBLOCK_Tips,0,clientUnblockCommand,-3,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_UNBLOCK_Keyspecs,0,NULL,2),.args=CLIENT_UNBLOCK_Args}, +{MAKE_CMD("unpause","Resumes processing commands from paused clients.","O(N) Where N is the number of paused clients","6.2.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_UNPAUSE_History,0,CLIENT_UNPAUSE_Tips,0,clientUnpauseCommand,2,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_UNPAUSE_Keyspecs,0,NULL,0)}, {0} }; @@ -10910,7 +10923,7 @@ struct COMMAND_STRUCT serverCommandTable[] = { {MAKE_CMD("readwrite","Enables read-write queries for a connection to a Valkey replica node.","O(1)","3.0.0",CMD_DOC_NONE,NULL,NULL,"cluster",COMMAND_GROUP_CLUSTER,READWRITE_History,0,READWRITE_Tips,0,readwriteCommand,1,CMD_FAST|CMD_LOADING|CMD_STALE,ACL_CATEGORY_CONNECTION,READWRITE_Keyspecs,0,NULL,0)}, /* connection */ {MAKE_CMD("auth","Authenticates the connection.","O(N) where N is the number of passwords defined for the user","1.0.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,AUTH_History,1,AUTH_Tips,0,authCommand,-2,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_FAST|CMD_NO_AUTH|CMD_SENTINEL|CMD_ALLOW_BUSY,ACL_CATEGORY_CONNECTION,AUTH_Keyspecs,0,NULL,2),.args=AUTH_Args}, -{MAKE_CMD("client","A container for client connection commands.","Depends on subcommand.","2.4.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_History,0,CLIENT_Tips,0,NULL,-2,CMD_SENTINEL,0,CLIENT_Keyspecs,0,NULL,0),.subcommands=CLIENT_Subcommands}, +{MAKE_CMD("client","A container for client connection commands.","Depends on subcommand.","2.4.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_History,0,CLIENT_Tips,0,clientCommand,-2,CMD_SENTINEL,0,CLIENT_Keyspecs,0,NULL,0),.subcommands=CLIENT_Subcommands}, {MAKE_CMD("echo","Returns the given string.","O(1)","1.0.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,ECHO_History,0,ECHO_Tips,0,echoCommand,2,CMD_LOADING|CMD_STALE|CMD_FAST,ACL_CATEGORY_CONNECTION,ECHO_Keyspecs,0,NULL,1),.args=ECHO_Args}, {MAKE_CMD("hello","Handshakes with the server.","O(1)","6.0.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,HELLO_History,2,HELLO_Tips,0,helloCommand,-1,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_FAST|CMD_NO_AUTH|CMD_SENTINEL|CMD_ALLOW_BUSY,ACL_CATEGORY_CONNECTION,HELLO_Keyspecs,0,NULL,1),.args=HELLO_Args}, {MAKE_CMD("ping","Returns the server's liveliness response.","O(1)","1.0.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,PING_History,0,PING_Tips,2,pingCommand,-1,CMD_FAST|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,PING_Keyspecs,0,NULL,1),.args=PING_Args}, diff --git a/src/commands/client-caching.json b/src/commands/client-caching.json index 2a4ae891db..d661492f45 100644 --- a/src/commands/client-caching.json +++ b/src/commands/client-caching.json @@ -6,7 +6,7 @@ "since": "6.0.0", "arity": 3, "container": "CLIENT", - "function": "clientCommand", + "function": "clientCachingCommand", "command_flags": [ "NOSCRIPT", "LOADING", diff --git a/src/commands/client-capa.json b/src/commands/client-capa.json index 3c16cd44f9..0d0f577f94 100644 --- a/src/commands/client-capa.json +++ b/src/commands/client-capa.json @@ -6,7 +6,7 @@ "since": "8.0.0", "arity": -3, "container": "CLIENT", - "function": "clientCommand", + "function": "clientCapaCommand", "command_flags": [ "NOSCRIPT", "LOADING", diff --git a/src/commands/client-getname.json b/src/commands/client-getname.json index 9e237af849..e13db064b7 100644 --- a/src/commands/client-getname.json +++ b/src/commands/client-getname.json @@ -6,7 +6,7 @@ "since": "2.6.9", "arity": 2, "container": "CLIENT", - "function": "clientCommand", + "function": "clientGetNameCommand", "command_flags": [ "NOSCRIPT", "LOADING", diff --git a/src/commands/client-getredir.json b/src/commands/client-getredir.json index 6fdb002dc8..3df1df6b6f 100644 --- a/src/commands/client-getredir.json +++ b/src/commands/client-getredir.json @@ -6,7 +6,7 @@ "since": "6.0.0", "arity": 2, "container": "CLIENT", - "function": "clientCommand", + "function": "clientGetredirCommand", "command_flags": [ "NOSCRIPT", "LOADING", diff --git a/src/commands/client-help.json b/src/commands/client-help.json index b49294c9ee..ae771d52ae 100644 --- a/src/commands/client-help.json +++ b/src/commands/client-help.json @@ -6,7 +6,7 @@ "since": "5.0.0", "arity": 2, "container": "CLIENT", - "function": "clientCommand", + "function": "clientHelpCommand", "command_flags": [ "LOADING", "STALE", diff --git a/src/commands/client-id.json b/src/commands/client-id.json index 7c2bf08200..f6131250dd 100644 --- a/src/commands/client-id.json +++ b/src/commands/client-id.json @@ -6,7 +6,7 @@ "since": "5.0.0", "arity": 2, "container": "CLIENT", - "function": "clientCommand", + "function": "clientIDCommand", "command_flags": [ "NOSCRIPT", "LOADING", diff --git a/src/commands/client-import-source.json b/src/commands/client-import-source.json index 113c07d70a..dd5ef65e77 100644 --- a/src/commands/client-import-source.json +++ b/src/commands/client-import-source.json @@ -6,7 +6,7 @@ "since": "8.1.0", "arity": 3, "container": "CLIENT", - "function": "clientCommand", + "function": "clientImportSourceCommand", "command_flags": [ "NOSCRIPT", "LOADING", diff --git a/src/commands/client-info.json b/src/commands/client-info.json index f974da437b..afda2ca967 100644 --- a/src/commands/client-info.json +++ b/src/commands/client-info.json @@ -6,7 +6,7 @@ "since": "6.2.0", "arity": 2, "container": "CLIENT", - "function": "clientCommand", + "function": "clientInfoCommand", "command_flags": [ "NOSCRIPT", "LOADING", diff --git a/src/commands/client-kill.json b/src/commands/client-kill.json index 97fa932cd8..0ae3579534 100644 --- a/src/commands/client-kill.json +++ b/src/commands/client-kill.json @@ -6,7 +6,7 @@ "since": "2.4.0", "arity": -3, "container": "CLIENT", - "function": "clientCommand", + "function": "clientKillCommand", "history": [ [ "2.8.12", @@ -35,6 +35,10 @@ [ "8.0.0", "Replaced `master` `TYPE` with `primary`. `master` still supported for backward compatibility." + ], + [ + "8.1.0", + "`ID` option accepts multiple IDs." ] ], "command_flags": [ @@ -68,6 +72,7 @@ "name": "client-id", "type": "integer", "optional": true, + "multiple": true, "since": "2.8.12" }, { diff --git a/src/commands/client-list.json b/src/commands/client-list.json index d9c0054e60..05e4de2419 100644 --- a/src/commands/client-list.json +++ b/src/commands/client-list.json @@ -6,7 +6,7 @@ "since": "2.4.0", "arity": -2, "container": "CLIENT", - "function": "clientCommand", + "function": "clientListCommand", "history": [ [ "2.8.12", @@ -35,6 +35,10 @@ [ "8.0.0", "Replaced `master` `TYPE` with `primary`. `master` still supported for backward compatibility." + ], + [ + "8.1.0", + "Added filters USER, ADDR, LADDR, SKIPME, and MAXAGE" ] ], "command_flags": [ @@ -91,6 +95,55 @@ "optional": true, "multiple": true, "since": "6.2.0" + }, + { + "token": "USER", + "name": "username", + "type": "string", + "optional": true, + "since": "8.1.0" + }, + { + "token": "ADDR", + "name": "addr", + "display": "ip:port", + "type": "string", + "optional": true, + "since": "8.1.0" + }, + { + "token": "LADDR", + "name": "laddr", + "display": "ip:port", + "type": "string", + "optional": true, + "since": "8.1.0" + }, + { + "token": "SKIPME", + "name": "skipme", + "type": "oneof", + "optional": true, + "since": "8.1.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": "8.1.0" } ] } diff --git a/src/commands/client-no-evict.json b/src/commands/client-no-evict.json index 9ed6718405..710f8a97f9 100644 --- a/src/commands/client-no-evict.json +++ b/src/commands/client-no-evict.json @@ -6,7 +6,7 @@ "since": "7.0.0", "arity": 3, "container": "CLIENT", - "function": "clientCommand", + "function": "clientNoEvictCommand", "command_flags": [ "ADMIN", "NOSCRIPT", diff --git a/src/commands/client-no-touch.json b/src/commands/client-no-touch.json index 4cf7b72416..4196770a2e 100644 --- a/src/commands/client-no-touch.json +++ b/src/commands/client-no-touch.json @@ -6,7 +6,7 @@ "since": "7.2.0", "arity": 3, "container": "CLIENT", - "function": "clientCommand", + "function": "clientNoTouchCommand", "command_flags": [ "NOSCRIPT", "LOADING", diff --git a/src/commands/client-pause.json b/src/commands/client-pause.json index b1dd7bc478..54faf796c2 100644 --- a/src/commands/client-pause.json +++ b/src/commands/client-pause.json @@ -6,7 +6,7 @@ "since": "3.0.0", "arity": -3, "container": "CLIENT", - "function": "clientCommand", + "function": "clientPauseCommand", "history": [ [ "6.2.0", diff --git a/src/commands/client-reply.json b/src/commands/client-reply.json index 9406de85cf..8d2b713a69 100644 --- a/src/commands/client-reply.json +++ b/src/commands/client-reply.json @@ -6,7 +6,7 @@ "since": "3.2.0", "arity": 3, "container": "CLIENT", - "function": "clientCommand", + "function": "clientReplyCommand", "command_flags": [ "NOSCRIPT", "LOADING", diff --git a/src/commands/client-setname.json b/src/commands/client-setname.json index b071bd18ff..f544dc6a0f 100644 --- a/src/commands/client-setname.json +++ b/src/commands/client-setname.json @@ -6,7 +6,7 @@ "since": "2.6.9", "arity": 3, "container": "CLIENT", - "function": "clientCommand", + "function": "clientSetNameCommand", "command_flags": [ "NOSCRIPT", "LOADING", diff --git a/src/commands/client-tracking.json b/src/commands/client-tracking.json index 2c3768c2fb..1acf84fafc 100644 --- a/src/commands/client-tracking.json +++ b/src/commands/client-tracking.json @@ -6,7 +6,7 @@ "since": "6.0.0", "arity": -3, "container": "CLIENT", - "function": "clientCommand", + "function": "clientTrackingCommand", "command_flags": [ "NOSCRIPT", "LOADING", diff --git a/src/commands/client-trackinginfo.json b/src/commands/client-trackinginfo.json index 270a3d5e6e..78ba8201d7 100644 --- a/src/commands/client-trackinginfo.json +++ b/src/commands/client-trackinginfo.json @@ -6,7 +6,7 @@ "since": "6.2.0", "arity": 2, "container": "CLIENT", - "function": "clientCommand", + "function": "clientTrackingInfoCommand", "command_flags": [ "NOSCRIPT", "LOADING", diff --git a/src/commands/client-unblock.json b/src/commands/client-unblock.json index d391ede9e9..2173173f40 100644 --- a/src/commands/client-unblock.json +++ b/src/commands/client-unblock.json @@ -6,7 +6,7 @@ "since": "5.0.0", "arity": -3, "container": "CLIENT", - "function": "clientCommand", + "function": "clientUnblockCommand", "command_flags": [ "ADMIN", "NOSCRIPT", diff --git a/src/commands/client-unpause.json b/src/commands/client-unpause.json index 6c55210d2a..bb78fb848b 100644 --- a/src/commands/client-unpause.json +++ b/src/commands/client-unpause.json @@ -6,7 +6,7 @@ "since": "6.2.0", "arity": 2, "container": "CLIENT", - "function": "clientCommand", + "function": "clientUnpauseCommand", "command_flags": [ "ADMIN", "NOSCRIPT", diff --git a/src/commands/client.json b/src/commands/client.json index b50996128e..116fb4d4a2 100644 --- a/src/commands/client.json +++ b/src/commands/client.json @@ -4,6 +4,7 @@ "complexity": "Depends on subcommand.", "group": "connection", "since": "2.4.0", + "function": "clientCommand", "arity": -2, "command_flags": [ "SENTINEL" diff --git a/src/networking.c b/src/networking.c index 48e397e6f4..0ff0fed4c0 100644 --- a/src/networking.c +++ b/src/networking.c @@ -31,6 +31,7 @@ #include "cluster.h" #include "cluster_slot_stats.h" #include "script.h" +#include "intset.h" #include "sds.h" #include "fpconv_dtoa.h" #include "fmtargs.h" @@ -43,10 +44,35 @@ #include #include +/* This struct is used to encapsulate filtering criteria for operations on clients + * such as identifying specific clients to kill or retrieve. Each field in the struct + * represents a filter that can be applied based on specific attributes of a client. */ +typedef struct { + /* A set of client IDs to filter. If NULL, no ID filtering is applied. */ + intset *ids; + /* Maximum age (in seconds) of a client connection for filtering. + * Connections younger than this value will not match. + * A value of 0 means no age filtering. */ + long long max_age; + /* Address/port of the client. If NULL, no address filtering is applied. */ + char *addr; + /* Remote address/port of the client. If NULL, no address filtering is applied. */ + char *laddr; + /* Filtering clients by authentication user. If NULL, no user-based filtering is applied. */ + user *user; + /* Client type to filter. If set to -1, no type filtering is applied. */ + int type; + /* Boolean flag to determine if the current client (`me`) should be filtered. 1 means "skip me", 0 means otherwise. */ + int skipme; +} clientFilter; + static void setProtocolError(const char *errstr, client *c); static void pauseClientsByClient(mstime_t end, int isPauseClientAll); int postponeClientRead(client *c); char *getClientSockname(client *c); +static int parseClientFiltersOrReply(client *c, int index, clientFilter *filter); +static int clientMatchesFilter(client *client, clientFilter client_filter); +static sds getAllFilteredClientsInfoString(clientFilter *client_filter, int hide_user_data); int ProcessingEventsWhileBlocked = 0; /* See processEventsWhileBlocked(). */ __thread sds thread_shared_qb = NULL; @@ -2451,6 +2477,7 @@ int handleClientsWithPendingWrites(void) { /* resetClient prepare the client to process the next command */ void resetClient(client *c) { serverCommandProc *prevcmd = c->cmd ? c->cmd->proc : NULL; + serverCommandProc *prevParentCmd = c->cmd && c->cmd->parent ? c->cmd->parent->proc : NULL; freeClientArgv(c); freeClientOriginalArgv(c); @@ -2480,7 +2507,7 @@ void resetClient(client *c) { /* We do the same for the CACHING command as well. It also affects * the next command or transaction executed, in a way very similar * to ASKING. */ - if (!c->flag.multi && prevcmd != clientCommand) c->flag.tracking_caching = 0; + if (!c->flag.multi && prevParentCmd != clientCommand) c->flag.tracking_caching = 0; /* Remove the CLIENT_REPLY_SKIP flag if any so that the reply * to the next command will be sent, but set the flag if the command @@ -3354,6 +3381,22 @@ sds getAllClientsInfoString(int type, int hide_user_data) { return o; } +static sds getAllFilteredClientsInfoString(clientFilter *client_filter, int hide_user_data) { + listNode *ln; + listIter li; + client *client; + sds o = sdsempty(); + sdsclear(o); + listRewind(server.clients, &li); + while ((ln = listNext(&li)) != NULL) { + client = listNodeValue(ln); + if (!clientMatchesFilter(client, *client_filter)) continue; + o = catClientInfoString(o, client, hide_user_data); + o = sdscatlen(o, "\n", 1); + } + return o; +} + /* Check validity of an attribute that's gonna be shown in CLIENT LIST. */ int validateClientAttr(const char *val) { /* Check if the charset is ok. We need to do this otherwise @@ -3473,570 +3516,648 @@ void quitCommand(client *c) { c->flag.close_after_reply = 1; } -void clientCommand(client *c) { - listNode *ln; - listIter li; +static int parseClientFiltersOrReply(client *c, int index, clientFilter *filter) { + while (index < c->argc) { + int moreargs = c->argc > index + 1; - if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr, "help")) { - const char *help[] = { - "CACHING (YES|NO)", - " Enable/disable tracking of the keys for next command in OPTIN/OPTOUT modes.", - "CAPA