Commit 1cf48a34 authored by Vitaly Arbuzov's avatar Vitaly Arbuzov
Browse files

Merge branch 'unstable' into dict-split-by-slot

parents 8b723d2d 557ca05d
......@@ -922,10 +922,10 @@ jobs:
run: sudo apt-get install tcl8.6 tclx
- name: test
if: true && !contains(github.event.inputs.skiptests, 'redis')
run: ./runtest --log-req-res --dont-clean --force-resp3 --tags -slow --verbose --dump-logs ${{github.event.inputs.test_args}}
run: ./runtest --log-req-res --no-latency --dont-clean --force-resp3 --tags -slow --verbose --dump-logs ${{github.event.inputs.test_args}}
- name: module api test
if: true && !contains(github.event.inputs.skiptests, 'modules')
run: ./runtest-moduleapi --log-req-res --dont-clean --force-resp3 --dont-pre-clean --verbose --dump-logs ${{github.event.inputs.test_args}}
run: ./runtest-moduleapi --log-req-res --no-latency --dont-clean --force-resp3 --dont-pre-clean --verbose --dump-logs ${{github.event.inputs.test_args}}
- name: sentinel tests
if: true && !contains(github.event.inputs.skiptests, 'sentinel')
run: ./runtest-sentinel --log-req-res --dont-clean --force-resp3 ${{github.event.inputs.cluster_test_args}}
......
......@@ -15,9 +15,14 @@
release_hdr := $(shell sh -c './mkreleasehdr.sh')
uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
uname_M := $(shell sh -c 'uname -m 2>/dev/null || echo not')
CLANG := $(findstring clang,$(shell sh -c '$(CC) --version | head -1'))
OPTIMIZATION?=-O3
ifeq ($(OPTIMIZATION),-O3)
REDIS_CFLAGS+=-flto=auto
ifeq (clang,$(CLANG))
REDIS_CFLAGS+=-flto
else
REDIS_CFLAGS+=-flto=auto
endif
REDIS_LDFLAGS+=-flto
endif
DEPENDENCY_TARGETS=hiredis linenoise lua hdr_histogram fpconv
......@@ -28,7 +33,7 @@ STD=-pedantic -DREDIS_STATIC=''
# Use -Wno-c11-extensions on clang, either where explicitly used or on
# platforms we can assume it's being used.
ifneq (,$(findstring clang,$(CC)))
ifeq (clang,$(CLANG))
STD+=-Wno-c11-extensions
else
ifneq (,$(findstring FreeBSD,$(uname_S)))
......
......@@ -958,6 +958,27 @@ struct redisCommandArg CLIENT_REPLY_Args[] = {
{0}
};
/********** CLIENT SETINFO ********************/
/* CLIENT SETINFO history */
#define CLIENT_SETINFO_History NULL
/* CLIENT SETINFO tips */
#define CLIENT_SETINFO_tips NULL
/* CLIENT SETINFO attr argument table */
struct redisCommandArg CLIENT_SETINFO_attr_Subargs[] = {
{"libname",ARG_TYPE_STRING,-1,"LIB-NAME",NULL,NULL,CMD_ARG_NONE},
{"libver",ARG_TYPE_STRING,-1,"LIB-VER",NULL,NULL,CMD_ARG_NONE},
{0}
};
/* CLIENT SETINFO argument table */
struct redisCommandArg CLIENT_SETINFO_Args[] = {
{"attr",ARG_TYPE_ONEOF,-1,NULL,NULL,NULL,CMD_ARG_NONE,.subargs=CLIENT_SETINFO_attr_Subargs},
{0}
};
/********** CLIENT SETNAME ********************/
/* CLIENT SETNAME history */
......@@ -1051,6 +1072,7 @@ struct redisCommand CLIENT_Subcommands[] = {
{"no-touch","Controls whether commands sent by the client will alter the LRU/LFU of the keys they access.","O(1)","7.2.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_NO_TOUCH_History,CLIENT_NO_TOUCH_tips,clientCommand,3,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE,ACL_CATEGORY_CONNECTION,.args=CLIENT_NO_TOUCH_Args},
{"pause","Stop processing commands from clients for some time","O(1)","3.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_PAUSE_History,CLIENT_PAUSE_tips,clientCommand,-3,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,.args=CLIENT_PAUSE_Args},
{"reply","Instruct the server whether to reply to commands","O(1)","3.2.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_REPLY_History,CLIENT_REPLY_tips,clientCommand,3,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,.args=CLIENT_REPLY_Args},
{"setinfo","Set client or connection specific info","O(1)","7.2.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_SETINFO_History,CLIENT_SETINFO_tips,clientSetinfoCommand,4,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,.args=CLIENT_SETINFO_Args},
{"setname","Set the current connection name","O(1)","2.6.9",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_SETNAME_History,CLIENT_SETNAME_tips,clientCommand,3,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,.args=CLIENT_SETNAME_Args},
{"tracking","Enable or disable server assisted client side caching support","O(1). Some options may introduce additional complexity.","6.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_TRACKING_History,CLIENT_TRACKING_tips,clientCommand,-3,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,.args=CLIENT_TRACKING_Args},
{"trackinginfo","Return information about server assisted client side caching for the current connection","O(1)","6.2.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_TRACKINGINFO_History,CLIENT_TRACKINGINFO_tips,clientCommand,2,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION},
......@@ -6485,7 +6507,10 @@ struct redisCommand XGROUP_Subcommands[] = {
/********** XINFO CONSUMERS ********************/
/* XINFO CONSUMERS history */
#define XINFO_CONSUMERS_History NULL
commandHistory XINFO_CONSUMERS_History[] = {
{"7.2.0","Added the `inactive` field."},
{0}
};
/* XINFO CONSUMERS tips */
const char *XINFO_CONSUMERS_tips[] = {
......@@ -6531,6 +6556,7 @@ struct redisCommandArg XINFO_GROUPS_Args[] = {
commandHistory XINFO_STREAM_History[] = {
{"6.0.0","Added the `FULL` modifier."},
{"7.0.0","Added the `max-deleted-entry-id`, `entries-added`, `recorded-first-entry-id`, `entries-read` and `lag` fields"},
{"7.2.0","Added the `active-time` field, and changed the meaning of `seen-time`."},
{0}
};
......
{
"SETINFO": {
"summary": "Set client or connection specific info",
"complexity": "O(1)",
"group": "connection",
"since": "7.2.0",
"arity": 4,
"container": "CLIENT",
"function": "clientSetinfoCommand",
"command_flags": [
"NOSCRIPT",
"LOADING",
"STALE",
"SENTINEL"
],
"acl_categories": [
"CONNECTION"
],
"reply_schema": {
"const": "OK"
},
"arguments": [
{
"name": "attr",
"type": "oneof",
"arguments": [
{
"token": "lib-name",
"name": "libname",
"type": "string"
},
{
"token": "lib-ver",
"name": "libver",
"type": "string"
}
]
}
]
}
}
......@@ -7,6 +7,12 @@
"arity": 4,
"container": "XINFO",
"function": "xinfoCommand",
"history": [
[
"7.2.0",
"Added the `inactive` field."
]
],
"command_flags": [
"READONLY"
],
......
......@@ -14,6 +14,10 @@
[
"7.0.0",
"Added the `max-deleted-entry-id`, `entries-added`, `recorded-first-entry-id`, `entries-read` and `lag` fields"
],
[
"7.2.0",
"Added the `active-time` field, and changed the meaning of `seen-time`."
]
],
"function": "xinfoCommand",
......
......@@ -130,17 +130,17 @@ struct commandHelp {
15,
"2.6.0" },
{ "BITFIELD",
"key GET encoding offset|[OVERFLOW WRAP|SAT|FAIL] SET encoding offset value|INCRBY encoding offset increment [GET encoding offset|[OVERFLOW WRAP|SAT|FAIL] SET encoding offset value|INCRBY encoding offset increment ...]",
"key [GET encoding offset|[OVERFLOW WRAP|SAT|FAIL] SET encoding offset value|INCRBY encoding offset increment [GET encoding offset|[OVERFLOW WRAP|SAT|FAIL] SET encoding offset value|INCRBY encoding offset increment ...]]",
"Perform arbitrary bitfield integer operations on strings",
15,
"3.2.0" },
{ "BITFIELD_RO",
"key GET encoding offset [GET encoding offset ...]",
"key [GET encoding offset [GET encoding offset ...]]",
"Perform arbitrary bitfield integer operations on strings. Read-only variant of BITFIELD",
15,
"6.0.0" },
{ "BITOP",
"operation destkey key [key ...]",
"AND|OR|XOR|NOT destkey key [key ...]",
"Perform bitwise operations between strings",
15,
"2.6.0" },
......@@ -225,7 +225,7 @@ struct commandHelp {
8,
"6.2.0" },
{ "CLIENT KILL",
"[ip:port] [ID client-id] [TYPE NORMAL|MASTER|SLAVE|REPLICA|PUBSUB] [USER username] [ADDR ip:port] [LADDR ip:port] [SKIPME yes/no]",
"old-format|[ID client-id]|[TYPE NORMAL|MASTER|SLAVE|REPLICA|PUBSUB]|[USER username]|[ADDR addr]|[LADDR laddr]|[SKIPME YES|NO] [[ID client-id]|[TYPE NORMAL|MASTER|SLAVE|REPLICA|PUBSUB]|[USER username]|[ADDR addr]|[LADDR laddr]|[SKIPME YES|NO] ...]",
"Kill the connection of a client",
8,
"2.4.0" },
......@@ -239,16 +239,26 @@ struct commandHelp {
"Set client eviction mode for the current connection",
8,
"7.0.0" },
{ "CLIENT NO-TOUCH",
"ON|OFF",
"Controls whether commands sent by the client will alter the LRU/LFU of the keys they access.",
8,
"7.2.0" },
{ "CLIENT PAUSE",
"timeout [WRITE|ALL]",
"Stop processing commands from clients for some time",
8,
"2.9.50" },
"3.0.0" },
{ "CLIENT REPLY",
"ON|OFF|SKIP",
"Instruct the server whether to reply to commands",
8,
"3.2.0" },
{ "CLIENT SETINFO",
"LIB-NAME libname|LIB-VER libver",
"Set client or connection specific info",
8,
"7.2.0" },
{ "CLIENT SETNAME",
"connection-name",
"Set the current connection name",
......@@ -355,7 +365,7 @@ struct commandHelp {
12,
"7.0.0" },
{ "CLUSTER MEET",
"ip port [cluster_bus_port]",
"ip port [cluster-bus-port]",
"Force a node cluster to handshake with another node",
12,
"3.0.0" },
......@@ -364,6 +374,11 @@ struct commandHelp {
"Return the node id",
12,
"3.0.0" },
{ "CLUSTER MYSHARDID",
"",
"Return the node shard id",
12,
"7.2.0" },
{ "CLUSTER NODES",
"",
"Get Cluster config for the node",
......@@ -395,7 +410,7 @@ struct commandHelp {
12,
"3.0.0" },
{ "CLUSTER SETSLOT",
"slot IMPORTING node-id|MIGRATING node-id|NODE node-id|STABLE",
"slot IMPORTING importing|MIGRATING migrating|NODE node|STABLE",
"Bind a hash slot to a specific node",
12,
"3.0.0" },
......@@ -430,12 +445,12 @@ struct commandHelp {
9,
"7.0.0" },
{ "COMMAND GETKEYS",
"",
"command [arg [arg ...]]",
"Extract keys given a full Redis command",
9,
"2.8.13" },
{ "COMMAND GETKEYSANDFLAGS",
"",
"command [arg [arg ...]]",
"Extract keys and access flags given a full Redis command",
9,
"7.0.0" },
......@@ -540,12 +555,12 @@ struct commandHelp {
10,
"2.6.0" },
{ "EVALSHA_RO",
"sha1 numkeys key [key ...] arg [arg ...]",
"sha1 numkeys [key [key ...]] [arg [arg ...]]",
"Execute a read-only Lua script server side",
10,
"7.0.0" },
{ "EVAL_RO",
"script numkeys key [key ...] arg [arg ...]",
"script numkeys [key [key ...]] [arg [arg ...]]",
"Execute a read-only Lua script server side",
10,
"7.0.0" },
......@@ -580,12 +595,12 @@ struct commandHelp {
9,
"6.2.0" },
{ "FCALL",
"function numkeys key [key ...] arg [arg ...]",
"function numkeys [key [key ...]] [arg [arg ...]]",
"Invoke a function",
10,
"7.0.0" },
{ "FCALL_RO",
"function numkeys key [key ...] arg [arg ...]",
"function numkeys [key [key ...]] [arg [arg ...]]",
"Invoke a read-only function",
10,
"7.0.0" },
......@@ -660,22 +675,22 @@ struct commandHelp {
13,
"3.2.0" },
{ "GEOHASH",
"key member [member ...]",
"key [member [member ...]]",
"Returns members of a geospatial index as standard geohash strings",
13,
"3.2.0" },
{ "GEOPOS",
"key member [member ...]",
"key [member [member ...]]",
"Returns longitude and latitude of members of a geospatial index",
13,
"3.2.0" },
{ "GEORADIUS",
"key longitude latitude radius M|KM|FT|MI [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]] [ASC|DESC] [STORE key] [STOREDIST key]",
"key longitude latitude radius M|KM|FT|MI [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]] [ASC|DESC] [STORE storekey] [STOREDIST storedistkey]",
"Query a sorted set representing a geospatial index to fetch members matching a given maximum distance from a point",
13,
"3.2.0" },
{ "GEORADIUSBYMEMBER",
"key member radius M|KM|FT|MI [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]] [ASC|DESC] [STORE key] [STOREDIST key]",
"key member radius M|KM|FT|MI [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]] [ASC|DESC] [STORE storekey] [STOREDIST storedistkey]",
"Query a sorted set representing a geospatial index to fetch members matching a given maximum distance from a member",
13,
"3.2.0" },
......@@ -885,7 +900,7 @@ struct commandHelp {
9,
"2.8.13" },
{ "LCS",
"key1 key2 [LEN] [IDX] [MINMATCHLEN len] [WITHMATCHLEN]",
"key1 key2 [LEN] [IDX] [MINMATCHLEN min-match-len] [WITHMATCHLEN]",
"Find longest common substring",
1,
"7.0.0" },
......@@ -1000,7 +1015,7 @@ struct commandHelp {
1,
"1.0.0" },
{ "MIGRATE",
"host port key| destination-db timeout [COPY] [REPLACE] [[AUTH password]|[AUTH2 username password]] [KEYS key [key ...]]",
"host port key| destination-db timeout [COPY] [REPLACE] [AUTH auth|AUTH2 username password] [KEYS keys [keys ...]]",
"Atomically transfer a key from a Redis instance to another one.",
0,
"2.6.0" },
......@@ -1025,7 +1040,7 @@ struct commandHelp {
9,
"4.0.0" },
{ "MODULE LOADEX",
"path [CONFIG name value [CONFIG name value ...]] [ARGS arg [arg ...]]",
"path [CONFIG name value [CONFIG name value ...]] [ARGS args [args ...]]",
"Load a module with extended parameters",
9,
"7.0.0" },
......@@ -1450,12 +1465,12 @@ struct commandHelp {
3,
"1.0.0" },
{ "SORT",
"key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]",
"key [BY by-pattern] [LIMIT offset count] [GET get-pattern [GET get-pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]",
"Sort the elements in a list, set or sorted set",
0,
"1.0.0" },
{ "SORT_RO",
"key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA]",
"key [BY by-pattern] [LIMIT offset count] [GET get-pattern [GET get-pattern ...]] [ASC|DESC] [ALPHA]",
"Sort the elements in a list, set or sorted set. Read-only variant of SORT.",
0,
"7.0.0" },
......@@ -1569,6 +1584,11 @@ struct commandHelp {
"Wait for the synchronous replication of all the write commands sent in the context of the current connection",
0,
"3.0.0" },
{ "WAITAOF",
"numlocal numreplicas timeout",
"Wait for all write commands sent in the context of the current connection to be synced to AOF of local host and/or replicas",
0,
"7.2.0" },
{ "WATCH",
"key [key ...]",
"Watch the given keys to determine execution of the MULTI/EXEC block",
......@@ -1590,7 +1610,7 @@ struct commandHelp {
14,
"6.2.0" },
{ "XCLAIM",
"key group consumer min-idle-time id [id ...] [IDLE ms] [TIME unix-time-milliseconds] [RETRYCOUNT count] [FORCE] [JUSTID]",
"key group consumer min-idle-time id [id ...] [IDLE ms] [TIME unix-time-milliseconds] [RETRYCOUNT count] [FORCE] [JUSTID] [LASTID lastid]",
"Changes (or acquires) ownership of a message in a consumer group, as if the message was delivered to the specified consumer.",
14,
"5.0.0" },
......@@ -1605,22 +1625,22 @@ struct commandHelp {
14,
"5.0.0" },
{ "XGROUP CREATE",
"key groupname id|$ [MKSTREAM] [ENTRIESREAD entries_read]",
"key group id|$ [MKSTREAM] [ENTRIESREAD entries-read]",
"Create a consumer group.",
14,
"5.0.0" },
{ "XGROUP CREATECONSUMER",
"key groupname consumername",
"key group consumer",
"Create a consumer in a consumer group.",
14,
"6.2.0" },
{ "XGROUP DELCONSUMER",
"key groupname consumername",
"key group consumer",
"Delete a consumer from a consumer group.",
14,
"5.0.0" },
{ "XGROUP DESTROY",
"key groupname",
"key group",
"Destroy a consumer group.",
14,
"5.0.0" },
......@@ -1630,7 +1650,7 @@ struct commandHelp {
14,
"5.0.0" },
{ "XGROUP SETID",
"key groupname id|$ [ENTRIESREAD entries_read]",
"key group id|$ [ENTRIESREAD entriesread]",
"Set a consumer group to an arbitrary last delivered ID value.",
14,
"5.0.0" },
......@@ -1640,7 +1660,7 @@ struct commandHelp {
14,
"5.0.0" },
{ "XINFO CONSUMERS",
"key groupname",
"key group",
"List the consumers in a consumer group",
14,
"5.0.0" },
......@@ -1690,7 +1710,7 @@ struct commandHelp {
14,
"5.0.0" },
{ "XSETID",
"key last-id [ENTRIESADDED entries_added] [MAXDELETEDID max_deleted_entry_id]",
"key last-id [ENTRIESADDED entries-added] [MAXDELETEDID max-deleted-id]",
"An internal command for replicating stream values",
14,
"5.0.0" },
......@@ -1795,7 +1815,7 @@ struct commandHelp {
4,
"6.2.0" },
{ "ZRANK",
"key member",
"key member [WITHSCORE]",
"Determine the index of a member in a sorted set",
4,
"2.0.0" },
......@@ -1835,7 +1855,7 @@ struct commandHelp {
4,
"2.2.0" },
{ "ZREVRANK",
"key member",
"key member [WITHSCORE]",
"Determine the index of a member in a sorted set, with scores ordered from high to low",
4,
"2.0.0" },
......
......@@ -147,6 +147,8 @@ client *createClient(connection *conn) {
#endif
c->conn = conn;
c->name = NULL;
c->lib_name = NULL;
c->lib_ver = NULL;
c->bufpos = 0;
c->buf_usable_size = zmalloc_usable_size(c->buf);
c->buf_peak = c->buf_usable_size;
......@@ -1496,7 +1498,11 @@ void clearClientConnectionState(client *c) {
if (c->flags & CLIENT_TRACKING) disableTracking(c);
selectDb(c,0);
#ifdef LOG_REQ_RES
c->resp = server.client_default_resp;
#else
c->resp = 2;
#endif
clientSetDefaultAuth(c);
moduleNotifyUserChanged(c);
......@@ -1511,6 +1517,9 @@ void clearClientConnectionState(client *c) {
c->name = NULL;
}
/* Note: lib_name and lib_ver are not reset since they still
* represent the client library behind the connection. */
/* Selectively clear state flags not covered above */
c->flags &= ~(CLIENT_ASKING|CLIENT_READONLY|CLIENT_PUBSUB|CLIENT_REPLY_OFF|
CLIENT_REPLY_SKIP_NEXT|CLIENT_NO_TOUCH|CLIENT_NO_EVICT);
......@@ -1662,6 +1671,8 @@ void freeClient(client *c) {
/* Release other dynamically allocated client structure fields,
* and finally release the client structure itself. */
if (c->name) decrRefCount(c->name);
if (c->lib_name) decrRefCount(c->lib_name);
if (c->lib_ver) decrRefCount(c->lib_ver);
freeClientMultiState(c);
sdsfree(c->peerid);
sdsfree(c->sockname);
......@@ -2775,7 +2786,7 @@ sds catClientInfoString(sds s, client *client) {
}
sds ret = sdscatfmt(s,
"id=%U addr=%s laddr=%s %s name=%s age=%I idle=%I flags=%s db=%i sub=%i psub=%i ssub=%i multi=%i qbuf=%U qbuf-free=%U argv-mem=%U multi-mem=%U rbs=%U rbp=%U obl=%U oll=%U omem=%U tot-mem=%U events=%s cmd=%s user=%s redir=%I resp=%i",
"id=%U addr=%s laddr=%s %s name=%s age=%I idle=%I flags=%s db=%i sub=%i psub=%i ssub=%i multi=%i qbuf=%U qbuf-free=%U argv-mem=%U multi-mem=%U rbs=%U rbp=%U obl=%U oll=%U omem=%U tot-mem=%U events=%s cmd=%s user=%s redir=%I resp=%i lib-name=%s lib-ver=%s",
(unsigned long long) client->id,
getClientPeerId(client),
getClientSockname(client),
......@@ -2803,7 +2814,10 @@ sds catClientInfoString(sds s, client *client) {
client->lastcmd ? client->lastcmd->fullname : "NULL",
client->user ? client->user->name : "(superuser)",
(client->flags & CLIENT_TRACKING) ? (long long) client->client_tracking_redirection : -1,
client->resp);
client->resp,
client->lib_name ? (char*)client->lib_name->ptr : "",
client->lib_ver ? (char*)client->lib_ver->ptr : ""
);
return ret;
}
......@@ -2823,6 +2837,20 @@ sds getAllClientsInfoString(int type) {
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
* CLIENT LIST format will break. You should always be able to
* split by space to get the different fields. */
while (*val) {
if (*val < '!' || *val > '~') { /* ASCII is assumed. */
return C_ERR;
}
val++;
}
return C_OK;
}
/* Returns C_OK if the name is valid. Returns C_ERR & sets `err` (when provided) otherwise. */
int validateClientName(robj *name, const char **err) {
const char *err_msg = "Client names cannot contain spaces, newlines or special characters.";
......@@ -2830,15 +2858,9 @@ int validateClientName(robj *name, const char **err) {
/* We allow setting the client name to an empty string. */
if (len == 0)
return C_OK;
/* Otherwise check if the charset is ok. We need to do this otherwise
* CLIENT LIST format will break. You should always be able to
* split by space to get the different fields. */
char *p = name->ptr;
for (int j = 0; j < len; j++) {
if (p[j] < '!' || p[j] > '~') { /* ASCII is assumed. */
if (err) *err = err_msg;
return C_ERR;
}
if (validateClientAttr(name->ptr) == C_ERR) {
if (err) *err = err_msg;
return C_ERR;
}
return C_OK;
}
......@@ -2880,6 +2902,35 @@ int clientSetNameOrReply(client *c, robj *name) {
return result;
}
/* Set client or connection related info */
void clientSetinfoCommand(client *c) {
sds attr = c->argv[2]->ptr;
robj *valob = c->argv[3];
sds val = valob->ptr;
robj **destvar = NULL;
if (!strcasecmp(attr,"lib-name")) {
destvar = &c->lib_name;
} else if (!strcasecmp(attr,"lib-ver")) {
destvar = &c->lib_ver;
} else {
addReplyErrorFormat(c,"Unrecognized option '%s'", attr);
return;
}
if (validateClientAttr(val)==C_ERR) {
addReplyErrorFormat(c,
"%s cannot contain spaces, newlines or special characters.", attr);
return;
}
if (*destvar) decrRefCount(*destvar);
if (sdslen(val)) {
*destvar = valob;
incrRefCount(valob);
} else
*destvar = NULL;
addReply(c,shared.ok);
}
/* Reset the client state to resemble a newly connected client.
*/
void resetCommand(client *c) {
......
......@@ -1155,6 +1155,8 @@ typedef struct client {
int resp; /* RESP protocol version. Can be 2 or 3. */
redisDb *db; /* Pointer to currently SELECTed DB. */
robj *name; /* As set by CLIENT SETNAME. */
robj *lib_name; /* The client library name as set by CLIENT SETINFO. */
robj *lib_ver; /* The client library version as set by CLIENT SETINFO. */
sds querybuf; /* Buffer we use to accumulate client queries. */
size_t qb_pos; /* The position we have read in querybuf. */
size_t querybuf_peak; /* Recent (100ms or more) peak of querybuf size. */
......@@ -3668,6 +3670,7 @@ void objectCommand(client *c);
void memoryCommand(client *c);
void clientCommand(client *c);
void helloCommand(client *c);
void clientSetinfoCommand(client *c);
void evalCommand(client *c);
void evalRoCommand(client *c);
void evalShaCommand(client *c);
......
......@@ -12,10 +12,22 @@ if {$::simulate_error} {
}
}
test "Sentinel commands sanity check" {
test "Sentinel command flag infrastructure works correctly" {
foreach_sentinel_id id {
assert_equal {72} [llength [S $id command list]]
assert_equal {15} [S $id command count]
set command_list [S $id command list]
foreach cmd {ping info subscribe client|setinfo} {
assert_not_equal [S $id command docs $cmd] {}
assert_not_equal [lsearch $command_list $cmd] -1
}
foreach cmd {save bgrewriteaof blpop replicaof} {
assert_equal [S $id command docs $cmd] {}
assert_equal [lsearch $command_list $cmd] -1
assert_error {ERR unknown command*} {S $id $cmd}
}
assert_error {ERR unknown subcommand*} {S $id client no-touch}
}
}
......
......@@ -36,7 +36,7 @@ proc wait_for_cluster_propagation {} {
# Wait for cluster size to be consistent across nodes.
proc wait_for_cluster_size {cluster_size} {
wait_for_condition 50 100 {
wait_for_condition 1000 50 {
[cluster_size_consistent $cluster_size] eq 1
} else {
fail "cluster size did not reach a consistent size $cluster_size"
......
......@@ -118,6 +118,10 @@ start_server {tags {"introspection"}} {
assert_match {*calls=1,*} [cmdstat geoadd]
} {} {needs:config-resetstat}
test {COMMAND COUNT get total number of Redis commands} {
assert_morethan [r command count] 0
}
test {COMMAND GETKEYS GET} {
assert_equal {key} [r command getkeys get key]
}
......
......@@ -325,6 +325,31 @@ start_server {tags {"introspection"}} {
}
}
test {CLIENT SETINFO can set a library name to this connection} {
r CLIENT SETINFO lib-name redis.py
r CLIENT SETINFO lib-ver 1.2.3
r client info
} {*lib-name=redis.py lib-ver=1.2.3*}
test {CLIENT SETINFO invalid args} {
assert_error {*wrong number of arguments*} {r CLIENT SETINFO lib-name}
assert_error {*cannot contain spaces*} {r CLIENT SETINFO lib-name "redis py"}
assert_error {*newlines*} {r CLIENT SETINFO lib-name "redis.py\n"}
assert_error {*Unrecognized*} {r CLIENT SETINFO badger hamster}
# test that all of these didn't affect the previously set values
r client info
} {*lib-name=redis.py lib-ver=1.2.3*}
test {RESET does NOT clean library name} {
r reset
r client info
} {*lib-name=redis.py*} {needs:reset}
test {CLIENT SETINFO can clear library name} {
r CLIENT SETINFO lib-name ""
r client info
} {*lib-name= *}
test {CONFIG save params special case handled properly} {
# No "save" keyword - defaults should apply
start_server {config "minimal.conf"} {
......
......@@ -12,7 +12,6 @@ import argparse
import multiprocessing
import collections
import io
import signal
import traceback
from datetime import timedelta
from functools import partial
......@@ -169,7 +168,7 @@ class Response(object):
value = Response(f, line_counter)
self.json[field] = value.json
if line[0] == '|':
# We don't care abou the attributes, read the real response
# We don't care about the attributes, read the real response
real_res = Response(f, line_counter)
self.__dict__.update(real_res.__dict__)
......@@ -180,7 +179,7 @@ class Response(object):
def process_file(docs, path):
"""
This function processes a single filegenerated by logreqres.c
This function processes a single file generated by logreqres.c
"""
line_counter = [0] # A list with one integer: to force python to pass it by reference
command_counter = dict()
......@@ -190,7 +189,7 @@ def process_file(docs, path):
# Convert file to StringIO in order to minimize IO operations
with open(path, "r", newline="\r\n", encoding="latin-1") as f:
content = f.read()
with io.StringIO(content) as fakefile:
while True:
try:
......@@ -244,7 +243,7 @@ def fetch_schemas(cli, port, args, docs):
break
except Exception as e:
time.sleep(0.1)
pass
print('Connected')
cli_proc = subprocess.Popen([cli, '-p', str(port), '--json', 'command', 'docs'], stdout=subprocess.PIPE)
......@@ -310,7 +309,7 @@ if __name__ == '__main__':
start = time.time()
# Obtain all the files toprocesses
# Obtain all the files to processes
paths = []
for path in glob.glob('%s/tmp/*/*.reqres' % testdir):
paths.append(path)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment