Unverified Commit 76b9c13d authored by Oran Agra's avatar Oran Agra Committed by GitHub
Browse files

Merge pull request #10962 from oranagra/release-7.0.3

Release 7.0.3
parents 05833959 85abb7cf
...@@ -12,6 +12,65 @@ SECURITY: There are security fixes in the release. ...@@ -12,6 +12,65 @@ SECURITY: There are security fixes in the release.
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
================================================================================
Redis 7.0.3 Released Monday Jul 11 12:00:00 IST 2022
================================================================================
Upgrade urgency: MODERATE, specifically if you're using a previous release of
Redis 7.0, contains fixes for bugs in previous 7.0 releases.
Performance and resource utilization improvements
=================================================
* Optimize zset conversion on large ZRANGESTORE (#10789)
* Optimize the performance of sending PING on large clusters (#10624)
* Allow for faster restart of Redis in cluster mode (#10912)
INFO fields and introspection changes
=====================================
* Add missing sharded pubsub keychannel count to CLIENT LIST (#10895)
* Add missing pubsubshard_channels field in INFO STATS (#10929)
Module API changes
==================
* Add RM_StringToULongLong and RM_CreateStringFromULongLong (#10889)
* Add RM_SetClientNameById and RM_GetClientNameById (#10839)
Changes in CLI tools
====================
* Add missing cluster-port support to redis-cli --cluster (#10344)
Other General Improvements
==========================
* Account sharded pubsub channels memory consumption (#10925)
* Allow ECHO in loading and stale modes (#10853)
* Cluster: Throw -TRYAGAIN instead of -ASK on migrating nodes for multi-key
commands when the node only has some of the keys (#9526)
Bug Fixes
=========
* TLS: Notify clients on connection shutdown (#10931)
* Fsync directory while persisting AOF manifest, RDB file, and config file (#10737)
* Script that made modification will not break with unexpected NOREPLICAS error (#10855)
* Cluster: Fix a bug where nodes may not acknowledge a CLUSTER FAILOVER TAKEOVER
after a replica reboots (#10798)
* Cluster: Fix crash during handshake and cluster shards call (#10942)
Fixes for issues in previous releases of Redis 7.0
--------------------------------------------------
* TLS: Fix issues with large replies (#10909)
* Correctly report the startup warning for vm.overcommit_memory (#10841)
* redis-server command line allow passing config name and value in the same argument (#10866)
* Support --save command line argument with no value for backwards compatibility (#10866)
* Fix CLUSTER RESET command regression requiring an argument (#10898)
================================================================================ ================================================================================
Redis 7.0.2 Released Sunday Jun 12 12:00:00 IST 2022 Redis 7.0.2 Released Sunday Jun 12 12:00:00 IST 2022
================================================================================ ================================================================================
...@@ -598,7 +657,7 @@ New configuration options ...@@ -598,7 +657,7 @@ New configuration options
* repl-diskless-sync-max-replicas, allows faster replication in some cases (#10092) * repl-diskless-sync-max-replicas, allows faster replication in some cases (#10092)
* latency-tracking, enabled by default, and latency-tracking-info-percentiles (#9462) * latency-tracking, enabled by default, and latency-tracking-info-percentiles (#9462)
* cluster-announce-hostnameand cluster-preferred-endpoint-type (#9530) * cluster-announce-hostnameand cluster-preferred-endpoint-type (#9530)
* cluster-allow-pubsublocal-when-down (#8621) * cluster-allow-pubsubshard-when-down (#8621)
* cluster-link-sendbuf-limit (#9774) * cluster-link-sendbuf-limit (#9774)
* list-max-listpack-*, hash-max-listpack-*, zset-max-listpack-* as aliases for * list-max-listpack-*, hash-max-listpack-*, zset-max-listpack-* as aliases for
the old ziplist configs (#8887, #9366, #9740) the old ziplist configs (#8887, #9366, #9740)
......
...@@ -223,11 +223,11 @@ public discussion groups, you agree to release your code under the terms ...@@ -223,11 +223,11 @@ public discussion groups, you agree to release your code under the terms
of the BSD license that you can find in the [COPYING][1] file included in the Redis of the BSD license that you can find in the [COPYING][1] file included in the Redis
source distribution. source distribution.
Please see the [CONTRIBUTING][2] file in this source distribution for more Please see the [CONTRIBUTING.md][2] file in this source distribution for more
information. For security bugs and vulnerabilities, please see [SECURITY.md][3]. information. For security bugs and vulnerabilities, please see [SECURITY.md][3].
[1]: https://github.com/redis/redis/blob/unstable/COPYING [1]: https://github.com/redis/redis/blob/unstable/COPYING
[2]: https://github.com/redis/redis/blob/unstable/CONTRIBUTING [2]: https://github.com/redis/redis/blob/unstable/CONTRIBUTING.md
[3]: https://github.com/redis/redis/blob/unstable/SECURITY.md [3]: https://github.com/redis/redis/blob/unstable/SECURITY.md
Redis internals Redis internals
......
...@@ -57,7 +57,7 @@ typedef enum { ...@@ -57,7 +57,7 @@ typedef enum {
REDIS_SSL_CTX_CA_CERT_LOAD_FAILED, /* Failed to load CA Certificate or CA Path */ REDIS_SSL_CTX_CA_CERT_LOAD_FAILED, /* Failed to load CA Certificate or CA Path */
REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED, /* Failed to load client certificate */ REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED, /* Failed to load client certificate */
REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED, /* Failed to load private key */ REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED, /* Failed to load private key */
REDIS_SSL_CTX_OS_CERTSTORE_OPEN_FAILED, /* Failed to open system certifcate store */ REDIS_SSL_CTX_OS_CERTSTORE_OPEN_FAILED, /* Failed to open system certificate store */
REDIS_SSL_CTX_OS_CERT_ADD_FAILED /* Failed to add CA certificates obtained from system to the SSL context */ REDIS_SSL_CTX_OS_CERT_ADD_FAILED /* Failed to add CA certificates obtained from system to the SSL context */
} redisSSLContextError; } redisSSLContextError;
......
...@@ -184,7 +184,7 @@ const char *redisSSLContextGetError(redisSSLContextError error) ...@@ -184,7 +184,7 @@ const char *redisSSLContextGetError(redisSSLContextError error)
case REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED: case REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED:
return "Failed to load private key"; return "Failed to load private key";
case REDIS_SSL_CTX_OS_CERTSTORE_OPEN_FAILED: case REDIS_SSL_CTX_OS_CERTSTORE_OPEN_FAILED:
return "Failed to open system certifcate store"; return "Failed to open system certificate store";
case REDIS_SSL_CTX_OS_CERT_ADD_FAILED: case REDIS_SSL_CTX_OS_CERT_ADD_FAILED:
return "Failed to add CA certificates obtained from system to the SSL context"; return "Failed to add CA certificates obtained from system to the SSL context";
default: default:
......
...@@ -1450,7 +1450,7 @@ appendfsync everysec ...@@ -1450,7 +1450,7 @@ appendfsync everysec
# BGSAVE or BGREWRITEAOF is in progress. # BGSAVE or BGREWRITEAOF is in progress.
# #
# This means that while another child is saving, the durability of Redis is # This means that while another child is saving, the durability of Redis is
# the same as "appendfsync none". In practical terms, this means that it is # the same as "appendfsync no". In practical terms, this means that it is
# possible to lose up to 30 seconds of log in the worst scenario (with the # possible to lose up to 30 seconds of log in the worst scenario (with the
# default Linux settings). # default Linux settings).
# #
......
...@@ -286,7 +286,9 @@ sentinel failover-timeout mymaster 180000 ...@@ -286,7 +286,9 @@ sentinel failover-timeout mymaster 180000
sentinel deny-scripts-reconfig yes sentinel deny-scripts-reconfig yes
# REDIS COMMANDS RENAMING # REDIS COMMANDS RENAMING (DEPRECATED)
#
# WARNING: avoid using this option if possible, instead use ACLs.
# #
# Sometimes the Redis server has certain commands, that are needed for Sentinel # Sometimes the Redis server has certain commands, that are needed for Sentinel
# to work correctly, renamed to unguessable strings. This is often the case # to work correctly, renamed to unguessable strings. This is often the case
......
...@@ -2169,15 +2169,25 @@ sds ACLLoadFromFile(const char *filename) { ...@@ -2169,15 +2169,25 @@ sds ACLLoadFromFile(const char *filename) {
server.acl_filename, linenum); server.acl_filename, linenum);
} }
int j; int syntax_error = 0;
for (j = 0; j < merged_argc; j++) { for (int j = 0; j < merged_argc; j++) {
acl_args[j] = sdstrim(acl_args[j],"\t\r\n"); acl_args[j] = sdstrim(acl_args[j],"\t\r\n");
if (ACLSetUser(u,acl_args[j],sdslen(acl_args[j])) != C_OK) { if (ACLSetUser(u,acl_args[j],sdslen(acl_args[j])) != C_OK) {
const char *errmsg = ACLSetUserStringError(); const char *errmsg = ACLSetUserStringError();
if (errno == ENOENT) {
/* For missing commands, we print out more information since
* it shouldn't contain any sensitive information. */
errors = sdscatprintf(errors,
"%s:%d: Error in applying operation '%s': %s. ",
server.acl_filename, linenum, acl_args[j], errmsg);
} else if (syntax_error == 0) {
/* For all other errors, only print out the first error encountered
* since it might affect future operations. */
errors = sdscatprintf(errors, errors = sdscatprintf(errors,
"%s:%d: %s. ", "%s:%d: %s. ",
server.acl_filename, linenum, errmsg); server.acl_filename, linenum, errmsg);
continue; syntax_error = 1;
}
} }
} }
......
...@@ -572,6 +572,16 @@ int writeAofManifestFile(sds buf) { ...@@ -572,6 +572,16 @@ int writeAofManifestFile(sds buf) {
tmp_am_name, am_name, strerror(errno)); tmp_am_name, am_name, strerror(errno));
ret = C_ERR; ret = C_ERR;
goto cleanup;
}
/* Also sync the AOF directory as new AOF files may be added in the directory */
if (fsyncFileDir(am_filepath) == -1) {
serverLog(LL_WARNING, "Fail to fsync AOF directory %s: %s.",
am_filepath, strerror(errno));
ret = C_ERR;
goto cleanup;
} }
cleanup: cleanup:
...@@ -1122,8 +1132,8 @@ void flushAppendOnlyFile(int force) { ...@@ -1122,8 +1132,8 @@ void flushAppendOnlyFile(int force) {
if (can_log) { if (can_log) {
serverLog(LL_WARNING,"Error writing to the AOF file: %s", serverLog(LL_WARNING,"Error writing to the AOF file: %s",
strerror(errno)); strerror(errno));
server.aof_last_write_errno = errno;
} }
server.aof_last_write_errno = errno;
} else { } else {
if (can_log) { if (can_log) {
serverLog(LL_WARNING,"Short write while writing to " serverLog(LL_WARNING,"Short write while writing to "
...@@ -2398,6 +2408,7 @@ int rewriteAppendOnlyFileBackground(void) { ...@@ -2398,6 +2408,7 @@ int rewriteAppendOnlyFileBackground(void) {
if (dirCreateIfMissing(server.aof_dirname) == -1) { if (dirCreateIfMissing(server.aof_dirname) == -1) {
serverLog(LL_WARNING, "Can't open or create append-only dir %s: %s", serverLog(LL_WARNING, "Can't open or create append-only dir %s: %s",
server.aof_dirname, strerror(errno)); server.aof_dirname, strerror(errno));
server.aof_lastbgrewrite_status = C_ERR;
return C_ERR; return C_ERR;
} }
...@@ -2405,7 +2416,10 @@ int rewriteAppendOnlyFileBackground(void) { ...@@ -2405,7 +2416,10 @@ int rewriteAppendOnlyFileBackground(void) {
* feedAppendOnlyFile() to issue a SELECT command. */ * feedAppendOnlyFile() to issue a SELECT command. */
server.aof_selected_db = -1; server.aof_selected_db = -1;
flushAppendOnlyFile(1); flushAppendOnlyFile(1);
if (openNewIncrAofForAppend() != C_OK) return C_ERR; if (openNewIncrAofForAppend() != C_OK) {
server.aof_lastbgrewrite_status = C_ERR;
return C_ERR;
}
server.stat_aof_rewrites++; server.stat_aof_rewrites++;
if ((childpid = redisFork(CHILD_TYPE_AOF)) == 0) { if ((childpid = redisFork(CHILD_TYPE_AOF)) == 0) {
char tmpfile[256]; char tmpfile[256];
...@@ -2563,6 +2577,8 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) { ...@@ -2563,6 +2577,8 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
strerror(errno)); strerror(errno));
aofManifestFree(temp_am); aofManifestFree(temp_am);
sdsfree(new_base_filepath); sdsfree(new_base_filepath);
server.aof_lastbgrewrite_status = C_ERR;
server.stat_aofrw_consecutive_failures++;
goto cleanup; goto cleanup;
} }
latencyEndMonitor(latency); latencyEndMonitor(latency);
...@@ -2591,6 +2607,8 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) { ...@@ -2591,6 +2607,8 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
sdsfree(temp_incr_filepath); sdsfree(temp_incr_filepath);
sdsfree(new_incr_filepath); sdsfree(new_incr_filepath);
sdsfree(temp_incr_aof_name); sdsfree(temp_incr_aof_name);
server.aof_lastbgrewrite_status = C_ERR;
server.stat_aofrw_consecutive_failures++;
goto cleanup; goto cleanup;
} }
latencyEndMonitor(latency); latencyEndMonitor(latency);
...@@ -2614,6 +2632,8 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) { ...@@ -2614,6 +2632,8 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
bg_unlink(new_incr_filepath); bg_unlink(new_incr_filepath);
sdsfree(new_incr_filepath); sdsfree(new_incr_filepath);
} }
server.aof_lastbgrewrite_status = C_ERR;
server.stat_aofrw_consecutive_failures++;
goto cleanup; goto cleanup;
} }
sdsfree(new_base_filepath); sdsfree(new_base_filepath);
......
...@@ -308,8 +308,10 @@ int clusterLoadConfig(char *filename) { ...@@ -308,8 +308,10 @@ int clusterLoadConfig(char *filename) {
if (atoi(argv[4])) n->ping_sent = mstime(); if (atoi(argv[4])) n->ping_sent = mstime();
if (atoi(argv[5])) n->pong_received = mstime(); if (atoi(argv[5])) n->pong_received = mstime();
/* Set configEpoch for this node. */ /* Set configEpoch for this node.
n->configEpoch = strtoull(argv[6],NULL,10); * If the node is a replica, set its config epoch to 0.
* If it's a primary, load the config epoch from the configuration file. */
n->configEpoch = (nodeIsSlave(n) && n->slaveof) ? 0 : strtoull(argv[6],NULL,10);
/* Populate hash slots served by this instance. */ /* Populate hash slots served by this instance. */
for (j = 8; j < argc; j++) { for (j = 8; j < argc; j++) {
...@@ -458,8 +460,8 @@ void clusterSaveConfigOrDie(int do_fsync) { ...@@ -458,8 +460,8 @@ void clusterSaveConfigOrDie(int do_fsync) {
} }
} }
/* Lock the cluster config using flock(), and leaks the file descriptor used to /* Lock the cluster config using flock(), and retain the file descriptor used to
* acquire the lock so that the file will be locked forever. * acquire the lock so that the file will be locked as long as the process is up.
* *
* This works because we always update nodes.conf with a new version * This works because we always update nodes.conf with a new version
* in-place, reopening the file, and writing to it in place (later adjusting * in-place, reopening the file, and writing to it in place (later adjusting
...@@ -498,8 +500,8 @@ int clusterLockConfig(char *filename) { ...@@ -498,8 +500,8 @@ int clusterLockConfig(char *filename) {
close(fd); close(fd);
return C_ERR; return C_ERR;
} }
/* Lock acquired: leak the 'fd' by not closing it, so that we'll retain the /* Lock acquired: leak the 'fd' by not closing it until shutdown time, so that
* lock to the file as long as the process exists. * we'll retain the lock to the file as long as the process exists.
* *
* After fork, the child process will get the fd opened by the parent process, * After fork, the child process will get the fd opened by the parent process,
* we need save `fd` to `cluster_config_file_lock_fd`, so that in redisFork(), * we need save `fd` to `cluster_config_file_lock_fd`, so that in redisFork(),
...@@ -964,6 +966,7 @@ clusterNode *createClusterNode(char *nodename, int flags) { ...@@ -964,6 +966,7 @@ clusterNode *createClusterNode(char *nodename, int flags) {
node->numslaves = 0; node->numslaves = 0;
node->slaves = NULL; node->slaves = NULL;
node->slaveof = NULL; node->slaveof = NULL;
node->last_in_ping_gossip = 0;
node->ping_sent = node->pong_received = 0; node->ping_sent = node->pong_received = 0;
node->data_received = 0; node->data_received = 0;
node->fail_time = 0; node->fail_time = 0;
...@@ -1217,10 +1220,14 @@ clusterNode *clusterLookupNode(const char *name, int length) { ...@@ -1217,10 +1220,14 @@ clusterNode *clusterLookupNode(const char *name, int length) {
return dictGetVal(de); return dictGetVal(de);
} }
/* Get all the nodes serving the same slots as myself. */ /* Get all the nodes serving the same slots as the given node. */
list *clusterGetNodesServingMySlots(clusterNode *node) { list *clusterGetNodesServingMySlots(clusterNode *node) {
list *nodes_for_slot = listCreate(); list *nodes_for_slot = listCreate();
clusterNode *my_primary = nodeIsMaster(node) ? node : node->slaveof; clusterNode *my_primary = nodeIsMaster(node) ? node : node->slaveof;
/* This function is only valid for fully connected nodes, so
* they should have a known primary. */
serverAssert(my_primary);
listAddNodeTail(nodes_for_slot, my_primary); listAddNodeTail(nodes_for_slot, my_primary);
for (int i=0; i < my_primary->numslaves; i++) { for (int i=0; i < my_primary->numslaves; i++) {
listAddNodeTail(nodes_for_slot, my_primary->slaves[i]); listAddNodeTail(nodes_for_slot, my_primary->slaves[i]);
...@@ -1999,7 +2006,7 @@ int writeHostnamePingExt(clusterMsgPingExt **cursor) { ...@@ -1999,7 +2006,7 @@ int writeHostnamePingExt(clusterMsgPingExt **cursor) {
uint32_t extension_size = getHostnamePingExtSize(); uint32_t extension_size = getHostnamePingExtSize();
/* Move the write cursor */ /* Move the write cursor */
(*cursor)->type = CLUSTERMSG_EXT_TYPE_HOSTNAME; (*cursor)->type = htons(CLUSTERMSG_EXT_TYPE_HOSTNAME);
(*cursor)->length = htonl(extension_size); (*cursor)->length = htonl(extension_size);
/* Make sure the string is NULL terminated by adding 1 */ /* Make sure the string is NULL terminated by adding 1 */
*cursor = (clusterMsgPingExt *) (ext->hostname + EIGHT_BYTE_ALIGN(sdslen(myself->hostname) + 1)); *cursor = (clusterMsgPingExt *) (ext->hostname + EIGHT_BYTE_ALIGN(sdslen(myself->hostname) + 1));
...@@ -2847,18 +2854,6 @@ void clusterBuildMessageHdr(clusterMsg *hdr, int type) { ...@@ -2847,18 +2854,6 @@ void clusterBuildMessageHdr(clusterMsg *hdr, int type) {
* totlen field is up to the caller. */ * totlen field is up to the caller. */
} }
/* Return non zero if the node is already present in the gossip section of the
* message pointed by 'hdr' and having 'count' gossip entries. Otherwise
* zero is returned. Helper for clusterSendPing(). */
int clusterNodeIsInGossipSection(clusterMsg *hdr, int count, clusterNode *n) {
int j;
for (j = 0; j < count; j++) {
if (memcmp(hdr->data.ping.gossip[j].nodename,n->name,
CLUSTER_NAMELEN) == 0) break;
}
return j != count;
}
/* Set the i-th entry of the gossip section in the message pointed by 'hdr' /* Set the i-th entry of the gossip section in the message pointed by 'hdr'
* to the info of the specified node 'n'. */ * to the info of the specified node 'n'. */
void clusterSetGossipEntry(clusterMsg *hdr, int i, clusterNode *n) { void clusterSetGossipEntry(clusterMsg *hdr, int i, clusterNode *n) {
...@@ -2878,6 +2873,8 @@ void clusterSetGossipEntry(clusterMsg *hdr, int i, clusterNode *n) { ...@@ -2878,6 +2873,8 @@ void clusterSetGossipEntry(clusterMsg *hdr, int i, clusterNode *n) {
/* Send a PING or PONG packet to the specified node, making sure to add enough /* Send a PING or PONG packet to the specified node, making sure to add enough
* gossip information. */ * gossip information. */
void clusterSendPing(clusterLink *link, int type) { void clusterSendPing(clusterLink *link, int type) {
static unsigned long long cluster_pings_sent = 0;
cluster_pings_sent++;
unsigned char *buf; unsigned char *buf;
clusterMsg *hdr; clusterMsg *hdr;
int gossipcount = 0; /* Number of gossip sections added so far. */ int gossipcount = 0; /* Number of gossip sections added so far. */
...@@ -2928,7 +2925,7 @@ void clusterSendPing(clusterLink *link, int type) { ...@@ -2928,7 +2925,7 @@ void clusterSendPing(clusterLink *link, int type) {
* to put inside the packet. */ * to put inside the packet. */
estlen = sizeof(clusterMsg) - sizeof(union clusterMsgData); estlen = sizeof(clusterMsg) - sizeof(union clusterMsgData);
estlen += (sizeof(clusterMsgDataGossip)*(wanted + pfail_wanted)); estlen += (sizeof(clusterMsgDataGossip)*(wanted + pfail_wanted));
estlen += sizeof(clusterMsgPingExt) + getHostnamePingExtSize(); estlen += getHostnamePingExtSize();
/* Note: clusterBuildMessageHdr() expects the buffer to be always at least /* Note: clusterBuildMessageHdr() expects the buffer to be always at least
* sizeof(clusterMsg) or more. */ * sizeof(clusterMsg) or more. */
...@@ -2967,10 +2964,11 @@ void clusterSendPing(clusterLink *link, int type) { ...@@ -2967,10 +2964,11 @@ void clusterSendPing(clusterLink *link, int type) {
} }
/* Do not add a node we already have. */ /* Do not add a node we already have. */
if (clusterNodeIsInGossipSection(hdr,gossipcount,this)) continue; if (this->last_in_ping_gossip == cluster_pings_sent) continue;
/* Add it */ /* Add it */
clusterSetGossipEntry(hdr,gossipcount,this); clusterSetGossipEntry(hdr,gossipcount,this);
this->last_in_ping_gossip = cluster_pings_sent;
freshnodes--; freshnodes--;
gossipcount++; gossipcount++;
} }
...@@ -2987,7 +2985,6 @@ void clusterSendPing(clusterLink *link, int type) { ...@@ -2987,7 +2985,6 @@ void clusterSendPing(clusterLink *link, int type) {
if (node->flags & CLUSTER_NODE_NOADDR) continue; if (node->flags & CLUSTER_NODE_NOADDR) continue;
if (!(node->flags & CLUSTER_NODE_PFAIL)) continue; if (!(node->flags & CLUSTER_NODE_PFAIL)) continue;
clusterSetGossipEntry(hdr,gossipcount,node); clusterSetGossipEntry(hdr,gossipcount,node);
freshnodes--;
gossipcount++; gossipcount++;
/* We take the count of the slots we allocated, since the /* We take the count of the slots we allocated, since the
* PFAIL stats may not match perfectly with the current number * PFAIL stats may not match perfectly with the current number
...@@ -5110,7 +5107,7 @@ void clusterReplyShards(client *c) { ...@@ -5110,7 +5107,7 @@ void clusterReplyShards(client *c) {
* information and an empty slots array. */ * information and an empty slots array. */
while((de = dictNext(di)) != NULL) { while((de = dictNext(di)) != NULL) {
clusterNode *n = dictGetVal(de); clusterNode *n = dictGetVal(de);
if (nodeIsSlave(n)) { if (!nodeIsMaster(n)) {
/* You can force a replica to own slots, even though it'll get reverted, /* You can force a replica to own slots, even though it'll get reverted,
* so freeing the slot pair here just in case. */ * so freeing the slot pair here just in case. */
clusterFreeNodesSlotsInfo(n); clusterFreeNodesSlotsInfo(n);
...@@ -6104,7 +6101,7 @@ migrateCachedSocket* migrateGetSocket(client *c, robj *host, robj *port, long ti ...@@ -6104,7 +6101,7 @@ migrateCachedSocket* migrateGetSocket(client *c, robj *host, robj *port, long ti
/* Create the socket */ /* Create the socket */
conn = server.tls_cluster ? connCreateTLS() : connCreateSocket(); conn = server.tls_cluster ? connCreateTLS() : connCreateSocket();
if (connBlockingConnect(conn, c->argv[1]->ptr, atoi(c->argv[2]->ptr), timeout) if (connBlockingConnect(conn, host->ptr, atoi(port->ptr), timeout)
!= C_OK) { != C_OK) {
addReplyError(c,"-IOERR error or timeout connecting to the client"); addReplyError(c,"-IOERR error or timeout connecting to the client");
connClose(conn); connClose(conn);
...@@ -6583,7 +6580,8 @@ clusterNode *getNodeByQuery(client *c, struct redisCommand *cmd, robj **argv, in ...@@ -6583,7 +6580,8 @@ clusterNode *getNodeByQuery(client *c, struct redisCommand *cmd, robj **argv, in
int multiple_keys = 0; int multiple_keys = 0;
multiState *ms, _ms; multiState *ms, _ms;
multiCmd mc; multiCmd mc;
int i, slot = 0, migrating_slot = 0, importing_slot = 0, missing_keys = 0; int i, slot = 0, migrating_slot = 0, importing_slot = 0, missing_keys = 0,
existing_keys = 0;
/* Allow any key to be set if a module disabled cluster redirections. */ /* Allow any key to be set if a module disabled cluster redirections. */
if (server.cluster_module_flags & CLUSTER_MODULE_FLAG_NO_REDIRECTION) if (server.cluster_module_flags & CLUSTER_MODULE_FLAG_NO_REDIRECTION)
...@@ -6695,10 +6693,10 @@ clusterNode *getNodeByQuery(client *c, struct redisCommand *cmd, robj **argv, in ...@@ -6695,10 +6693,10 @@ clusterNode *getNodeByQuery(client *c, struct redisCommand *cmd, robj **argv, in
* node until the migration completes with CLUSTER SETSLOT <slot> * node until the migration completes with CLUSTER SETSLOT <slot>
* NODE <node-id>. */ * NODE <node-id>. */
int flags = LOOKUP_NOTOUCH | LOOKUP_NOSTATS | LOOKUP_NONOTIFY; int flags = LOOKUP_NOTOUCH | LOOKUP_NOSTATS | LOOKUP_NONOTIFY;
if ((migrating_slot || importing_slot) && !is_pubsubshard && if ((migrating_slot || importing_slot) && !is_pubsubshard)
lookupKeyReadWithFlags(&server.db[0], thiskey, flags) == NULL)
{ {
missing_keys++; if (lookupKeyReadWithFlags(&server.db[0], thiskey, flags) == NULL) missing_keys++;
else existing_keys++;
} }
} }
getKeysFreeResult(&result); getKeysFreeResult(&result);
...@@ -6742,11 +6740,17 @@ clusterNode *getNodeByQuery(client *c, struct redisCommand *cmd, robj **argv, in ...@@ -6742,11 +6740,17 @@ clusterNode *getNodeByQuery(client *c, struct redisCommand *cmd, robj **argv, in
return myself; return myself;
/* If we don't have all the keys and we are migrating the slot, send /* If we don't have all the keys and we are migrating the slot, send
* an ASK redirection. */ * an ASK redirection or TRYAGAIN. */
if (migrating_slot && missing_keys) { if (migrating_slot && missing_keys) {
/* If we have keys but we don't have all keys, we return TRYAGAIN */
if (existing_keys) {
if (error_code) *error_code = CLUSTER_REDIR_UNSTABLE;
return NULL;
} else {
if (error_code) *error_code = CLUSTER_REDIR_ASK; if (error_code) *error_code = CLUSTER_REDIR_ASK;
return server.cluster->migrating_slots_to[slot]; return server.cluster->migrating_slots_to[slot];
} }
}
/* If we are receiving the slot, and the client correctly flagged the /* If we are receiving the slot, and the client correctly flagged the
* request as "ASKING", we can serve the request. However if the request * request as "ASKING", we can serve the request. However if the request
......
...@@ -127,6 +127,7 @@ typedef struct clusterNode { ...@@ -127,6 +127,7 @@ typedef struct clusterNode {
may be NULL even if the node is a slave may be NULL even if the node is a slave
if we don't have the master node in our if we don't have the master node in our
tables. */ tables. */
unsigned long long last_in_ping_gossip; /* The number of the last carried in the ping gossip section */
mstime_t ping_sent; /* Unix time we sent latest ping */ mstime_t ping_sent; /* Unix time we sent latest ping */
mstime_t pong_received; /* Unix time we received the pong */ mstime_t pong_received; /* Unix time we received the pong */
mstime_t data_received; /* Unix time we received any data */ mstime_t data_received; /* Unix time we received any data */
......
...@@ -470,7 +470,10 @@ NULL ...@@ -470,7 +470,10 @@ NULL
/********** CLUSTER MEET ********************/ /********** CLUSTER MEET ********************/
/* CLUSTER MEET history */ /* CLUSTER MEET history */
#define CLUSTER_MEET_History NULL commandHistory CLUSTER_MEET_History[] = {
{"4.0.0","Added the optional `cluster_bus_port` argument."},
{0}
};
/* CLUSTER MEET tips */ /* CLUSTER MEET tips */
const char *CLUSTER_MEET_tips[] = { const char *CLUSTER_MEET_tips[] = {
...@@ -482,6 +485,7 @@ NULL ...@@ -482,6 +485,7 @@ NULL
struct redisCommandArg CLUSTER_MEET_Args[] = { struct redisCommandArg CLUSTER_MEET_Args[] = {
{"ip",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE}, {"ip",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE},
{"port",ARG_TYPE_INTEGER,-1,NULL,NULL,NULL,CMD_ARG_NONE}, {"port",ARG_TYPE_INTEGER,-1,NULL,NULL,NULL,CMD_ARG_NONE},
{"cluster_bus_port",ARG_TYPE_INTEGER,-1,NULL,NULL,"4.0.0",CMD_ARG_OPTIONAL},
{0} {0}
}; };
...@@ -685,7 +689,7 @@ struct redisCommand CLUSTER_Subcommands[] = { ...@@ -685,7 +689,7 @@ struct redisCommand CLUSTER_Subcommands[] = {
{"nodes","Get Cluster config for the node","O(N) where N is the total number of Cluster nodes","3.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CLUSTER,CLUSTER_NODES_History,CLUSTER_NODES_tips,clusterCommand,2,CMD_STALE,0}, {"nodes","Get Cluster config for the node","O(N) where N is the total number of Cluster nodes","3.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CLUSTER,CLUSTER_NODES_History,CLUSTER_NODES_tips,clusterCommand,2,CMD_STALE,0},
{"replicas","List replica nodes of the specified master node","O(1)","5.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CLUSTER,CLUSTER_REPLICAS_History,CLUSTER_REPLICAS_tips,clusterCommand,3,CMD_ADMIN|CMD_STALE,0,.args=CLUSTER_REPLICAS_Args}, {"replicas","List replica nodes of the specified master node","O(1)","5.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CLUSTER,CLUSTER_REPLICAS_History,CLUSTER_REPLICAS_tips,clusterCommand,3,CMD_ADMIN|CMD_STALE,0,.args=CLUSTER_REPLICAS_Args},
{"replicate","Reconfigure a node as a replica of the specified master node","O(1)","3.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CLUSTER,CLUSTER_REPLICATE_History,CLUSTER_REPLICATE_tips,clusterCommand,3,CMD_NO_ASYNC_LOADING|CMD_ADMIN|CMD_STALE,0,.args=CLUSTER_REPLICATE_Args}, {"replicate","Reconfigure a node as a replica of the specified master node","O(1)","3.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CLUSTER,CLUSTER_REPLICATE_History,CLUSTER_REPLICATE_tips,clusterCommand,3,CMD_NO_ASYNC_LOADING|CMD_ADMIN|CMD_STALE,0,.args=CLUSTER_REPLICATE_Args},
{"reset","Reset a Redis Cluster node","O(N) where N is the number of known nodes. The command may execute a FLUSHALL as a side effect.","3.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CLUSTER,CLUSTER_RESET_History,CLUSTER_RESET_tips,clusterCommand,3,CMD_ADMIN|CMD_STALE|CMD_NOSCRIPT,0,.args=CLUSTER_RESET_Args}, {"reset","Reset a Redis Cluster node","O(N) where N is the number of known nodes. The command may execute a FLUSHALL as a side effect.","3.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CLUSTER,CLUSTER_RESET_History,CLUSTER_RESET_tips,clusterCommand,-2,CMD_ADMIN|CMD_STALE|CMD_NOSCRIPT,0,.args=CLUSTER_RESET_Args},
{"saveconfig","Forces the node to save cluster state on disk","O(1)","3.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CLUSTER,CLUSTER_SAVECONFIG_History,CLUSTER_SAVECONFIG_tips,clusterCommand,2,CMD_NO_ASYNC_LOADING|CMD_ADMIN|CMD_STALE,0}, {"saveconfig","Forces the node to save cluster state on disk","O(1)","3.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CLUSTER,CLUSTER_SAVECONFIG_History,CLUSTER_SAVECONFIG_tips,clusterCommand,2,CMD_NO_ASYNC_LOADING|CMD_ADMIN|CMD_STALE,0},
{"set-config-epoch","Set the configuration epoch in a new node","O(1)","3.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CLUSTER,CLUSTER_SET_CONFIG_EPOCH_History,CLUSTER_SET_CONFIG_EPOCH_tips,clusterCommand,3,CMD_NO_ASYNC_LOADING|CMD_ADMIN|CMD_STALE,0,.args=CLUSTER_SET_CONFIG_EPOCH_Args}, {"set-config-epoch","Set the configuration epoch in a new node","O(1)","3.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CLUSTER,CLUSTER_SET_CONFIG_EPOCH_History,CLUSTER_SET_CONFIG_EPOCH_tips,clusterCommand,3,CMD_NO_ASYNC_LOADING|CMD_ADMIN|CMD_STALE,0,.args=CLUSTER_SET_CONFIG_EPOCH_Args},
{"setslot","Bind a hash slot to a specific node","O(1)","3.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CLUSTER,CLUSTER_SETSLOT_History,CLUSTER_SETSLOT_tips,clusterCommand,-4,CMD_NO_ASYNC_LOADING|CMD_ADMIN|CMD_STALE,0,.args=CLUSTER_SETSLOT_Args}, {"setslot","Bind a hash slot to a specific node","O(1)","3.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CLUSTER,CLUSTER_SETSLOT_History,CLUSTER_SETSLOT_tips,clusterCommand,-4,CMD_NO_ASYNC_LOADING|CMD_ADMIN|CMD_STALE,0,.args=CLUSTER_SETSLOT_Args},
...@@ -1025,22 +1029,22 @@ struct redisCommandArg CLIENT_UNBLOCK_Args[] = { ...@@ -1025,22 +1029,22 @@ struct redisCommandArg CLIENT_UNBLOCK_Args[] = {
/* CLIENT command table */ /* CLIENT command table */
struct redisCommand CLIENT_Subcommands[] = { struct redisCommand CLIENT_Subcommands[] = {
{"caching","Instruct the server about tracking or not keys in the next request","O(1)","6.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_CACHING_History,CLIENT_CACHING_tips,clientCommand,3,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE,ACL_CATEGORY_CONNECTION,.args=CLIENT_CACHING_Args}, {"caching","Instruct the server about tracking or not keys in the next request","O(1)","6.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_CACHING_History,CLIENT_CACHING_tips,clientCommand,3,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,.args=CLIENT_CACHING_Args},
{"getname","Get the current connection name","O(1)","2.6.9",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_GETNAME_History,CLIENT_GETNAME_tips,clientCommand,2,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE,ACL_CATEGORY_CONNECTION}, {"getname","Get the current connection name","O(1)","2.6.9",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_GETNAME_History,CLIENT_GETNAME_tips,clientCommand,2,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION},
{"getredir","Get tracking notifications redirection client ID if any","O(1)","6.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_GETREDIR_History,CLIENT_GETREDIR_tips,clientCommand,2,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE,ACL_CATEGORY_CONNECTION}, {"getredir","Get tracking notifications redirection client ID if any","O(1)","6.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_GETREDIR_History,CLIENT_GETREDIR_tips,clientCommand,2,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION},
{"help","Show helpful text about the different subcommands","O(1)","5.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_HELP_History,CLIENT_HELP_tips,clientCommand,2,CMD_LOADING|CMD_STALE,ACL_CATEGORY_CONNECTION}, {"help","Show helpful text about the different subcommands","O(1)","5.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_HELP_History,CLIENT_HELP_tips,clientCommand,2,CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION},
{"id","Returns the client ID for the current connection","O(1)","5.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_ID_History,CLIENT_ID_tips,clientCommand,2,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE,ACL_CATEGORY_CONNECTION}, {"id","Returns the client ID for the current connection","O(1)","5.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_ID_History,CLIENT_ID_tips,clientCommand,2,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION},
{"info","Returns information about the current client connection.","O(1)","6.2.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_INFO_History,CLIENT_INFO_tips,clientCommand,2,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE,ACL_CATEGORY_CONNECTION}, {"info","Returns information about the current client connection.","O(1)","6.2.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_INFO_History,CLIENT_INFO_tips,clientCommand,2,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION},
{"kill","Kill the connection of a client","O(N) where N is the number of client connections","2.4.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_KILL_History,CLIENT_KILL_tips,clientCommand,-3,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE,ACL_CATEGORY_CONNECTION,.args=CLIENT_KILL_Args}, {"kill","Kill the connection of a client","O(N) where N is the number of client connections","2.4.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_KILL_History,CLIENT_KILL_tips,clientCommand,-3,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,.args=CLIENT_KILL_Args},
{"list","Get the list of client connections","O(N) where N is the number of client connections","2.4.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_LIST_History,CLIENT_LIST_tips,clientCommand,-2,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE,ACL_CATEGORY_CONNECTION,.args=CLIENT_LIST_Args}, {"list","Get the list of client connections","O(N) where N is the number of client connections","2.4.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_LIST_History,CLIENT_LIST_tips,clientCommand,-2,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,.args=CLIENT_LIST_Args},
{"no-evict","Set client eviction mode for the current connection","O(1)","7.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_NO_EVICT_History,CLIENT_NO_EVICT_tips,clientCommand,3,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE,ACL_CATEGORY_CONNECTION,.args=CLIENT_NO_EVICT_Args}, {"no-evict","Set client eviction mode for the current connection","O(1)","7.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_NO_EVICT_History,CLIENT_NO_EVICT_tips,clientCommand,3,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,.args=CLIENT_NO_EVICT_Args},
{"pause","Stop processing commands from clients for some time","O(1)","2.9.50",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_PAUSE_History,CLIENT_PAUSE_tips,clientCommand,-3,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE,ACL_CATEGORY_CONNECTION,.args=CLIENT_PAUSE_Args}, {"pause","Stop processing commands from clients for some time","O(1)","2.9.50",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,ACL_CATEGORY_CONNECTION,.args=CLIENT_REPLY_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},
{"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,ACL_CATEGORY_CONNECTION,.args=CLIENT_SETNAME_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,ACL_CATEGORY_CONNECTION,.args=CLIENT_TRACKING_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,ACL_CATEGORY_CONNECTION}, {"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},
{"unblock","Unblock a client blocked in 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,COMMAND_GROUP_CONNECTION,CLIENT_UNBLOCK_History,CLIENT_UNBLOCK_tips,clientCommand,-3,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE,ACL_CATEGORY_CONNECTION,.args=CLIENT_UNBLOCK_Args}, {"unblock","Unblock a client blocked in 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,COMMAND_GROUP_CONNECTION,CLIENT_UNBLOCK_History,CLIENT_UNBLOCK_tips,clientCommand,-3,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,.args=CLIENT_UNBLOCK_Args},
{"unpause","Resume processing of clients that were paused","O(N) Where N is the number of paused clients","6.2.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_UNPAUSE_History,CLIENT_UNPAUSE_tips,clientCommand,2,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE,ACL_CATEGORY_CONNECTION}, {"unpause","Resume processing of clients that were paused","O(N) Where N is the number of paused clients","6.2.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_UNPAUSE_History,CLIENT_UNPAUSE_tips,clientCommand,2,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION},
{0} {0}
}; };
...@@ -4317,13 +4321,13 @@ struct redisCommandArg COMMAND_LIST_Args[] = { ...@@ -4317,13 +4321,13 @@ struct redisCommandArg COMMAND_LIST_Args[] = {
/* COMMAND command table */ /* COMMAND command table */
struct redisCommand COMMAND_Subcommands[] = { struct redisCommand COMMAND_Subcommands[] = {
{"count","Get total number of Redis commands","O(1)","2.8.13",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SERVER,COMMAND_COUNT_History,COMMAND_COUNT_tips,commandCountCommand,2,CMD_LOADING|CMD_STALE,ACL_CATEGORY_CONNECTION}, {"count","Get total number of Redis commands","O(1)","2.8.13",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SERVER,COMMAND_COUNT_History,COMMAND_COUNT_tips,commandCountCommand,2,CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION},
{"docs","Get array of specific Redis command documentation","O(N) where N is the number of commands to look up","7.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SERVER,COMMAND_DOCS_History,COMMAND_DOCS_tips,commandDocsCommand,-2,CMD_LOADING|CMD_STALE,ACL_CATEGORY_CONNECTION,.args=COMMAND_DOCS_Args}, {"docs","Get array of specific Redis command documentation","O(N) where N is the number of commands to look up","7.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SERVER,COMMAND_DOCS_History,COMMAND_DOCS_tips,commandDocsCommand,-2,CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,.args=COMMAND_DOCS_Args},
{"getkeys","Extract keys given a full Redis command","O(N) where N is the number of arguments to the command","2.8.13",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SERVER,COMMAND_GETKEYS_History,COMMAND_GETKEYS_tips,commandGetKeysCommand,-4,CMD_LOADING|CMD_STALE,ACL_CATEGORY_CONNECTION}, {"getkeys","Extract keys given a full Redis command","O(N) where N is the number of arguments to the command","2.8.13",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SERVER,COMMAND_GETKEYS_History,COMMAND_GETKEYS_tips,commandGetKeysCommand,-4,CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION},
{"getkeysandflags","Extract keys and access flags given a full Redis command","O(N) where N is the number of arguments to the command","7.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SERVER,COMMAND_GETKEYSANDFLAGS_History,COMMAND_GETKEYSANDFLAGS_tips,commandGetKeysAndFlagsCommand,-4,CMD_LOADING|CMD_STALE,ACL_CATEGORY_CONNECTION}, {"getkeysandflags","Extract keys and access flags given a full Redis command","O(N) where N is the number of arguments to the command","7.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SERVER,COMMAND_GETKEYSANDFLAGS_History,COMMAND_GETKEYSANDFLAGS_tips,commandGetKeysAndFlagsCommand,-4,CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION},
{"help","Show helpful text about the different subcommands","O(1)","5.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SERVER,COMMAND_HELP_History,COMMAND_HELP_tips,commandHelpCommand,2,CMD_LOADING|CMD_STALE,ACL_CATEGORY_CONNECTION}, {"help","Show helpful text about the different subcommands","O(1)","5.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SERVER,COMMAND_HELP_History,COMMAND_HELP_tips,commandHelpCommand,2,CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION},
{"info","Get array of specific Redis command details, or all when no argument is given.","O(N) where N is the number of commands to look up","2.8.13",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SERVER,COMMAND_INFO_History,COMMAND_INFO_tips,commandInfoCommand,-2,CMD_LOADING|CMD_STALE,ACL_CATEGORY_CONNECTION,.args=COMMAND_INFO_Args}, {"info","Get array of specific Redis command details, or all when no argument is given.","O(N) where N is the number of commands to look up","2.8.13",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SERVER,COMMAND_INFO_History,COMMAND_INFO_tips,commandInfoCommand,-2,CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,.args=COMMAND_INFO_Args},
{"list","Get an array of Redis command names","O(N) where N is the total number of Redis commands","7.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SERVER,COMMAND_LIST_History,COMMAND_LIST_tips,commandListCommand,-2,CMD_LOADING|CMD_STALE,ACL_CATEGORY_CONNECTION,.args=COMMAND_LIST_Args}, {"list","Get an array of Redis command names","O(N) where N is the total number of Redis commands","7.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SERVER,COMMAND_LIST_History,COMMAND_LIST_tips,commandListCommand,-2,CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,.args=COMMAND_LIST_Args},
{0} {0}
}; };
...@@ -5808,8 +5812,8 @@ struct redisCommandArg ZRANGE_offset_count_Subargs[] = { ...@@ -5808,8 +5812,8 @@ struct redisCommandArg ZRANGE_offset_count_Subargs[] = {
/* ZRANGE argument table */ /* ZRANGE argument table */
struct redisCommandArg ZRANGE_Args[] = { struct redisCommandArg ZRANGE_Args[] = {
{"key",ARG_TYPE_KEY,0,NULL,NULL,NULL,CMD_ARG_NONE}, {"key",ARG_TYPE_KEY,0,NULL,NULL,NULL,CMD_ARG_NONE},
{"min",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE}, {"start",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE},
{"max",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE}, {"stop",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE},
{"sortby",ARG_TYPE_ONEOF,-1,NULL,NULL,"6.2.0",CMD_ARG_OPTIONAL,.subargs=ZRANGE_sortby_Subargs}, {"sortby",ARG_TYPE_ONEOF,-1,NULL,NULL,"6.2.0",CMD_ARG_OPTIONAL,.subargs=ZRANGE_sortby_Subargs},
{"rev",ARG_TYPE_PURE_TOKEN,-1,"REV",NULL,"6.2.0",CMD_ARG_OPTIONAL}, {"rev",ARG_TYPE_PURE_TOKEN,-1,"REV",NULL,"6.2.0",CMD_ARG_OPTIONAL},
{"offset_count",ARG_TYPE_BLOCK,-1,"LIMIT",NULL,"6.2.0",CMD_ARG_OPTIONAL,.subargs=ZRANGE_offset_count_Subargs}, {"offset_count",ARG_TYPE_BLOCK,-1,"LIMIT",NULL,"6.2.0",CMD_ARG_OPTIONAL,.subargs=ZRANGE_offset_count_Subargs},
...@@ -7175,7 +7179,7 @@ struct redisCommand redisCommandTable[] = { ...@@ -7175,7 +7179,7 @@ struct redisCommand redisCommandTable[] = {
/* connection */ /* connection */
{"auth","Authenticate to the server","O(N) where N is the number of passwords defined for the user","1.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,AUTH_History,AUTH_tips,authCommand,-2,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_FAST|CMD_NO_AUTH|CMD_SENTINEL|CMD_ALLOW_BUSY,ACL_CATEGORY_CONNECTION,.args=AUTH_Args}, {"auth","Authenticate to the server","O(N) where N is the number of passwords defined for the user","1.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,AUTH_History,AUTH_tips,authCommand,-2,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_FAST|CMD_NO_AUTH|CMD_SENTINEL|CMD_ALLOW_BUSY,ACL_CATEGORY_CONNECTION,.args=AUTH_Args},
{"client","A container for client connection commands","Depends on subcommand.","2.4.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_History,CLIENT_tips,NULL,-2,CMD_SENTINEL,0,.subcommands=CLIENT_Subcommands}, {"client","A container for client connection commands","Depends on subcommand.","2.4.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,CLIENT_History,CLIENT_tips,NULL,-2,CMD_SENTINEL,0,.subcommands=CLIENT_Subcommands},
{"echo","Echo the given string","O(1)","1.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,ECHO_History,ECHO_tips,echoCommand,2,CMD_FAST,ACL_CATEGORY_CONNECTION,.args=ECHO_Args}, {"echo","Echo the given string","O(1)","1.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,ECHO_History,ECHO_tips,echoCommand,2,CMD_LOADING|CMD_STALE|CMD_FAST,ACL_CATEGORY_CONNECTION,.args=ECHO_Args},
{"hello","Handshake with Redis","O(1)","6.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,HELLO_History,HELLO_tips,helloCommand,-1,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_FAST|CMD_NO_AUTH|CMD_SENTINEL|CMD_ALLOW_BUSY,ACL_CATEGORY_CONNECTION,.args=HELLO_Args}, {"hello","Handshake with Redis","O(1)","6.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,HELLO_History,HELLO_tips,helloCommand,-1,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_FAST|CMD_NO_AUTH|CMD_SENTINEL|CMD_ALLOW_BUSY,ACL_CATEGORY_CONNECTION,.args=HELLO_Args},
{"ping","Ping the server","O(1)","1.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,PING_History,PING_tips,pingCommand,-1,CMD_FAST|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,.args=PING_Args}, {"ping","Ping the server","O(1)","1.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,PING_History,PING_tips,pingCommand,-1,CMD_FAST|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,.args=PING_Args},
{"quit","Close the connection","O(1)","1.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,QUIT_History,QUIT_tips,quitCommand,-1,CMD_ALLOW_BUSY|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_FAST|CMD_NO_AUTH,ACL_CATEGORY_CONNECTION}, {"quit","Close the connection","O(1)","1.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_CONNECTION,QUIT_History,QUIT_tips,quitCommand,-1,CMD_ALLOW_BUSY|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_FAST|CMD_NO_AUTH,ACL_CATEGORY_CONNECTION},
......
...@@ -10,7 +10,8 @@ ...@@ -10,7 +10,8 @@
"command_flags": [ "command_flags": [
"NOSCRIPT", "NOSCRIPT",
"LOADING", "LOADING",
"STALE" "STALE",
"SENTINEL"
], ],
"acl_categories": [ "acl_categories": [
"CONNECTION" "CONNECTION"
......
...@@ -10,7 +10,8 @@ ...@@ -10,7 +10,8 @@
"command_flags": [ "command_flags": [
"NOSCRIPT", "NOSCRIPT",
"LOADING", "LOADING",
"STALE" "STALE",
"SENTINEL"
], ],
"acl_categories": [ "acl_categories": [
"CONNECTION" "CONNECTION"
......
...@@ -10,7 +10,8 @@ ...@@ -10,7 +10,8 @@
"command_flags": [ "command_flags": [
"NOSCRIPT", "NOSCRIPT",
"LOADING", "LOADING",
"STALE" "STALE",
"SENTINEL"
], ],
"acl_categories": [ "acl_categories": [
"CONNECTION" "CONNECTION"
......
...@@ -9,7 +9,8 @@ ...@@ -9,7 +9,8 @@
"function": "clientCommand", "function": "clientCommand",
"command_flags": [ "command_flags": [
"LOADING", "LOADING",
"STALE" "STALE",
"SENTINEL"
], ],
"acl_categories": [ "acl_categories": [
"CONNECTION" "CONNECTION"
......
...@@ -10,7 +10,8 @@ ...@@ -10,7 +10,8 @@
"command_flags": [ "command_flags": [
"NOSCRIPT", "NOSCRIPT",
"LOADING", "LOADING",
"STALE" "STALE",
"SENTINEL"
], ],
"acl_categories": [ "acl_categories": [
"CONNECTION" "CONNECTION"
......
...@@ -10,7 +10,8 @@ ...@@ -10,7 +10,8 @@
"command_flags": [ "command_flags": [
"NOSCRIPT", "NOSCRIPT",
"LOADING", "LOADING",
"STALE" "STALE",
"SENTINEL"
], ],
"acl_categories": [ "acl_categories": [
"CONNECTION" "CONNECTION"
......
...@@ -33,7 +33,8 @@ ...@@ -33,7 +33,8 @@
"ADMIN", "ADMIN",
"NOSCRIPT", "NOSCRIPT",
"LOADING", "LOADING",
"STALE" "STALE",
"SENTINEL"
], ],
"acl_categories": [ "acl_categories": [
"CONNECTION" "CONNECTION"
......
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