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)
......
...@@ -93,4 +93,4 @@ Community Impact Guidelines were inspired by Mozilla’s code of conduct ...@@ -93,4 +93,4 @@ Community Impact Guidelines were inspired by Mozilla’s code of conduct
enforcement ladder. enforcement ladder.
For answers to common questions about this code of conduct, see the FAQ at For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations. https://www.contributor-covenant.org/translations.
\ No newline at end of file
...@@ -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();
errors = sdscatprintf(errors, if (errno == ENOENT) {
"%s:%d: %s. ", /* For missing commands, we print out more information since
server.acl_filename, linenum, errmsg); * it shouldn't contain any sensitive information. */
continue; 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,
"%s:%d: %s. ",
server.acl_filename, linenum, errmsg);
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,10 +6740,16 @@ clusterNode *getNodeByQuery(client *c, struct redisCommand *cmd, robj **argv, in ...@@ -6742,10 +6740,16 @@ 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 (error_code) *error_code = CLUSTER_REDIR_ASK; /* If we have keys but we don't have all keys, we return TRYAGAIN */
return server.cluster->migrating_slots_to[slot]; if (existing_keys) {
if (error_code) *error_code = CLUSTER_REDIR_UNSTABLE;
return NULL;
} else {
if (error_code) *error_code = CLUSTER_REDIR_ASK;
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
......
...@@ -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