Merge unstable into 6.2

This commit is contained in:
Oran Agra 2021-03-01 20:54:02 +02:00
commit c83db6bf5a
34 changed files with 560 additions and 191 deletions

View File

@ -48,6 +48,25 @@ jobs:
- name: cluster tests - name: cluster tests
run: ./runtest-cluster run: ./runtest-cluster
test-ubuntu-no-malloc-usable-size:
runs-on: ubuntu-latest
if: github.repository == 'redis/redis'
timeout-minutes: 14400
steps:
- uses: actions/checkout@v2
- name: make
run: make MALLOC=libc CFLAGS=-DNO_MALLOC_USABLE_SIZE
- name: test
run: |
sudo apt-get install tcl8.6
./runtest --accurate --verbose --dump-logs
- name: module api test
run: ./runtest-moduleapi --verbose
- name: sentinel tests
run: ./runtest-sentinel
- name: cluster tests
run: ./runtest-cluster
test-ubuntu-32bit: test-ubuntu-32bit:
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: github.repository == 'redis/redis' if: github.repository == 'redis/redis'
@ -132,6 +151,22 @@ jobs:
- name: module api test - name: module api test
run: ./runtest-moduleapi --valgrind --no-latency --verbose --clients 1 run: ./runtest-moduleapi --valgrind --no-latency --verbose --clients 1
test-valgrind-no-malloc-usable-size:
runs-on: ubuntu-latest
if: github.repository == 'redis/redis'
timeout-minutes: 14400
steps:
- uses: actions/checkout@v2
- name: make
run: make valgrind CFLAGS="-DNO_MALLOC_USABLE_SIZE"
- name: test
run: |
sudo apt-get update
sudo apt-get install tcl8.6 valgrind -y
./runtest --valgrind --verbose --clients 1 --dump-logs
- name: module api test
run: ./runtest-moduleapi --valgrind --no-latency --verbose --clients 1
test-centos7-jemalloc: test-centos7-jemalloc:
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: github.repository == 'redis/redis' if: github.repository == 'redis/redis'
@ -221,3 +256,43 @@ jobs:
MAKE=gmake ./runtest-moduleapi --verbose && MAKE=gmake ./runtest-moduleapi --verbose &&
./runtest-sentinel && ./runtest-sentinel &&
./runtest-cluster ./runtest-cluster
test-alpine-jemalloc:
runs-on: ubuntu-latest
container: alpine:latest
steps:
- uses: actions/checkout@v2
- name: make
run: |
apk add build-base
make REDIS_CFLAGS='-Werror'
- name: test
run: |
apk add tcl procps
./runtest --accurate --verbose --dump-logs
- name: module api test
run: ./runtest-moduleapi --verbose
- name: sentinel tests
run: ./runtest-sentinel
- name: cluster tests
run: ./runtest-cluster
test-alpine-libc-malloc:
runs-on: ubuntu-latest
container: alpine:latest
steps:
- uses: actions/checkout@v2
- name: make
run: |
apk add build-base
make REDIS_CFLAGS='-Werror' USE_JEMALLOC=no CFLAGS=-DUSE_MALLOC_USABLE_SIZE
- name: test
run: |
apk add tcl procps
./runtest --accurate --verbose --dump-logs
- name: module api test
run: ./runtest-moduleapi --verbose
- name: sentinel tests
run: ./runtest-sentinel
- name: cluster tests
run: ./runtest-cluster

View File

@ -21,7 +21,12 @@ NODEPS:=clean distclean
# Default settings # Default settings
STD=-pedantic -DREDIS_STATIC='' STD=-pedantic -DREDIS_STATIC=''
# Use -Wno-c11-extensions on clang, either where explicitly used or on
# platforms we can assume it's being used.
ifneq (,$(findstring clang,$(CC))) ifneq (,$(findstring clang,$(CC)))
STD+=-Wno-c11-extensions
else
ifneq (,$(findstring FreeBSD,$(uname_S))) ifneq (,$(findstring FreeBSD,$(uname_S)))
STD+=-Wno-c11-extensions STD+=-Wno-c11-extensions
endif endif

View File

@ -1054,7 +1054,6 @@ void ACLInit(void) {
UsersToLoad = listCreate(); UsersToLoad = listCreate();
ACLLog = listCreate(); ACLLog = listCreate();
ACLInitDefaultUser(); ACLInitDefaultUser();
server.requirepass = NULL; /* Only used for backward compatibility. */
} }
/* Check the username and password pair and return C_OK if they are valid, /* Check the username and password pair and return C_OK if they are valid,
@ -2251,3 +2250,15 @@ void authCommand(client *c) {
} }
} }
/* Set the password for the "default" ACL user. This implements supports for
* requirepass config, so passing in NULL will set the user to be nopass. */
void ACLUpdateDefaultUserPassword(sds password) {
ACLSetUser(DefaultUser,"resetpass",-1);
if (password) {
sds aclop = sdscatlen(sdsnew(">"), password, sdslen(password));
ACLSetUser(DefaultUser,aclop,sdslen(aclop));
sdsfree(aclop);
} else {
ACLSetUser(DefaultUser,"nopass",-1);
}
}

View File

@ -499,7 +499,7 @@ void clusterInit(void) {
if (saveconf) clusterSaveConfigOrDie(1); if (saveconf) clusterSaveConfigOrDie(1);
/* We need a listening TCP port for our cluster messaging needs. */ /* We need a listening TCP port for our cluster messaging needs. */
server.cfd_count = 0; server.cfd.count = 0;
/* Port sanity check II /* Port sanity check II
* The other handshake port check is triggered too late to stop * The other handshake port check is triggered too late to stop
@ -512,19 +512,11 @@ void clusterInit(void) {
"Your Redis port number must be 55535 or less."); "Your Redis port number must be 55535 or less.");
exit(1); exit(1);
} }
if (listenToPort(port+CLUSTER_PORT_INCR, if (listenToPort(port+CLUSTER_PORT_INCR, &server.cfd) == C_ERR) {
server.cfd,&server.cfd_count) == C_ERR)
{
exit(1); exit(1);
} else {
int j;
for (j = 0; j < server.cfd_count; j++) {
if (aeCreateFileEvent(server.el, server.cfd[j], AE_READABLE,
clusterAcceptHandler, NULL) == AE_ERR)
serverPanic("Unrecoverable error creating Redis Cluster "
"file event.");
} }
if (createSocketAcceptHandler(&server.cfd, clusterAcceptHandler) != C_OK) {
serverPanic("Unrecoverable error creating Redis Cluster socket accept handler.");
} }
/* The slots -> keys map is a radix tree. Initialize it here. */ /* The slots -> keys map is a radix tree. Initialize it here. */

View File

@ -504,8 +504,6 @@ void loadServerConfigFromString(char *config) {
} }
} else if (!strcasecmp(argv[0],"include") && argc == 2) { } else if (!strcasecmp(argv[0],"include") && argc == 2) {
loadServerConfig(argv[1], 0, NULL); loadServerConfig(argv[1], 0, NULL);
} else if ((!strcasecmp(argv[0],"client-query-buffer-limit")) && argc == 2) {
server.client_max_querybuf_len = memtoll(argv[1],NULL);
} else if ((!strcasecmp(argv[0],"slaveof") || } else if ((!strcasecmp(argv[0],"slaveof") ||
!strcasecmp(argv[0],"replicaof")) && argc == 3) { !strcasecmp(argv[0],"replicaof")) && argc == 3) {
slaveof_linenum = linenum; slaveof_linenum = linenum;
@ -521,26 +519,6 @@ void loadServerConfigFromString(char *config) {
err = "Invalid master port"; goto loaderr; err = "Invalid master port"; goto loaderr;
} }
server.repl_state = REPL_STATE_CONNECT; server.repl_state = REPL_STATE_CONNECT;
} else if (!strcasecmp(argv[0],"requirepass") && argc == 2) {
if (sdslen(argv[1]) > CONFIG_AUTHPASS_MAX_LEN) {
err = "Password is longer than CONFIG_AUTHPASS_MAX_LEN";
goto loaderr;
}
/* The old "requirepass" directive just translates to setting
* a password to the default user. The only thing we do
* additionally is to remember the cleartext password in this
* case, for backward compatibility with Redis <= 5. */
ACLSetUser(DefaultUser,"resetpass",-1);
sdsfree(server.requirepass);
server.requirepass = NULL;
if (sdslen(argv[1])) {
sds aclop = sdscatlen(sdsnew(">"), argv[1], sdslen(argv[1]));
ACLSetUser(DefaultUser,aclop,sdslen(aclop));
sdsfree(aclop);
server.requirepass = sdsdup(argv[1]);
} else {
ACLSetUser(DefaultUser,"nopass",-1);
}
} else if (!strcasecmp(argv[0],"list-max-ziplist-entries") && argc == 2){ } else if (!strcasecmp(argv[0],"list-max-ziplist-entries") && argc == 2){
/* DEAD OPTION */ /* DEAD OPTION */
} else if (!strcasecmp(argv[0],"list-max-ziplist-value") && argc == 2) { } else if (!strcasecmp(argv[0],"list-max-ziplist-value") && argc == 2) {
@ -750,23 +728,22 @@ void configSetCommand(client *c) {
if (0) { /* this starts the config_set macros else-if chain. */ if (0) { /* this starts the config_set macros else-if chain. */
/* Special fields that can't be handled with general macros. */ /* Special fields that can't be handled with general macros. */
config_set_special_field("requirepass") { config_set_special_field("bind") {
if (sdslen(o->ptr) > CONFIG_AUTHPASS_MAX_LEN) goto badfmt; int vlen;
/* The old "requirepass" directive just translates to setting sds *v = sdssplitlen(o->ptr,sdslen(o->ptr)," ",1,&vlen);
* a password to the default user. The only thing we do
* additionally is to remember the cleartext password in this if (vlen < 1 || vlen > CONFIG_BINDADDR_MAX) {
* case, for backward compatibility with Redis <= 5. */ addReplyError(c, "Too many bind addresses specified.");
ACLSetUser(DefaultUser,"resetpass",-1); sdsfreesplitres(v, vlen);
sdsfree(server.requirepass); return;
server.requirepass = NULL;
if (sdslen(o->ptr)) {
sds aclop = sdscatlen(sdsnew(">"), o->ptr, sdslen(o->ptr));
ACLSetUser(DefaultUser,aclop,sdslen(aclop));
sdsfree(aclop);
server.requirepass = sdsdup(o->ptr);
} else {
ACLSetUser(DefaultUser,"nopass",-1);
} }
if (changeBindAddr(v, vlen) == C_ERR) {
addReplyError(c, "Failed to bind to specified addresses.");
sdsfreesplitres(v, vlen);
return;
}
sdsfreesplitres(v, vlen);
} config_set_special_field("save") { } config_set_special_field("save") {
int vlen, j; int vlen, j;
sds *v = sdssplitlen(o->ptr,sdslen(o->ptr)," ",1,&vlen); sds *v = sdssplitlen(o->ptr,sdslen(o->ptr)," ",1,&vlen);
@ -876,10 +853,6 @@ void configSetCommand(client *c) {
enableWatchdog(ll); enableWatchdog(ll);
else else
disableWatchdog(); disableWatchdog();
/* Memory fields.
* config_set_memory_field(name,var) */
} config_set_memory_field(
"client-query-buffer-limit",server.client_max_querybuf_len) {
/* Everything else is an error... */ /* Everything else is an error... */
} config_set_else { } config_set_else {
addReplyErrorFormat(c,"Unsupported CONFIG parameter: %s", addReplyErrorFormat(c,"Unsupported CONFIG parameter: %s",
@ -959,7 +932,6 @@ void configGetCommand(client *c) {
config_get_string_field("logfile",server.logfile); config_get_string_field("logfile",server.logfile);
/* Numerical values */ /* Numerical values */
config_get_numerical_field("client-query-buffer-limit",server.client_max_querybuf_len);
config_get_numerical_field("watchdog-period",server.watchdog_period); config_get_numerical_field("watchdog-period",server.watchdog_period);
/* Everything we can't handle with macros follows. */ /* Everything we can't handle with macros follows. */
@ -1046,16 +1018,6 @@ void configGetCommand(client *c) {
sdsfree(aux); sdsfree(aux);
matches++; matches++;
} }
if (stringmatch(pattern,"requirepass",1)) {
addReplyBulkCString(c,"requirepass");
sds password = server.requirepass;
if (password) {
addReplyBulkCBuffer(c,password,sdslen(password));
} else {
addReplyBulkCString(c,"");
}
matches++;
}
if (stringmatch(pattern,"oom-score-adj-values",0)) { if (stringmatch(pattern,"oom-score-adj-values",0)) {
sds buf = sdsempty(); sds buf = sdsempty();
@ -1564,26 +1526,6 @@ void rewriteConfigBindOption(struct rewriteConfigState *state) {
rewriteConfigRewriteLine(state,option,line,force); rewriteConfigRewriteLine(state,option,line,force);
} }
/* Rewrite the requirepass option. */
void rewriteConfigRequirepassOption(struct rewriteConfigState *state, char *option) {
int force = 1;
sds line;
sds password = server.requirepass;
/* If there is no password set, we don't want the requirepass option
* to be present in the configuration at all. */
if (password == NULL) {
rewriteConfigMarkAsProcessed(state,option);
return;
}
line = sdsnew(option);
line = sdscatlen(line, " ", 1);
line = sdscatsds(line, password);
rewriteConfigRewriteLine(state,option,line,force);
}
/* Glue together the configuration lines in the current configuration /* Glue together the configuration lines in the current configuration
* rewrite state into a single string, stripping multiple empty lines. */ * rewrite state into a single string, stripping multiple empty lines. */
sds rewriteConfigGetContentFromState(struct rewriteConfigState *state) { sds rewriteConfigGetContentFromState(struct rewriteConfigState *state) {
@ -1740,8 +1682,6 @@ int rewriteConfig(char *path, int force_all) {
rewriteConfigUserOption(state); rewriteConfigUserOption(state);
rewriteConfigDirOption(state); rewriteConfigDirOption(state);
rewriteConfigSlaveofOption(state,"replicaof"); rewriteConfigSlaveofOption(state,"replicaof");
rewriteConfigRequirepassOption(state,"requirepass");
rewriteConfigBytesOption(state,"client-query-buffer-limit",server.client_max_querybuf_len,PROTO_MAX_QUERYBUF_LEN);
rewriteConfigStringOption(state,"cluster-config-file",server.cluster_configfile,CONFIG_DEFAULT_CLUSTER_CONFIG_FILE); rewriteConfigStringOption(state,"cluster-config-file",server.cluster_configfile,CONFIG_DEFAULT_CLUSTER_CONFIG_FILE);
rewriteConfigNotifykeyspaceeventsOption(state); rewriteConfigNotifykeyspaceeventsOption(state);
rewriteConfigClientoutputbufferlimitOption(state); rewriteConfigClientoutputbufferlimitOption(state);
@ -2267,6 +2207,20 @@ static int updateHZ(long long val, long long prev, const char **err) {
return 1; return 1;
} }
static int updatePort(long long val, long long prev, const char **err) {
/* Do nothing if port is unchanged */
if (val == prev) {
return 1;
}
if (changeListenPort(val, &server.ipfd, acceptTcpHandler) == C_ERR) {
*err = "Unable to listen on this port. Check server logs.";
return 0;
}
return 1;
}
static int updateJemallocBgThread(int val, int prev, const char **err) { static int updateJemallocBgThread(int val, int prev, const char **err) {
UNUSED(prev); UNUSED(prev);
UNUSED(err); UNUSED(err);
@ -2368,6 +2322,18 @@ static int updateOOMScoreAdj(int val, int prev, const char **err) {
return 1; return 1;
} }
int updateRequirePass(sds val, sds prev, const char **err) {
UNUSED(prev);
UNUSED(err);
/* The old "requirepass" directive just translates to setting
* a password to the default user. The only thing we do
* additionally is to remember the cleartext password in this
* case, for backward compatibility with Redis <= 5. */
ACLUpdateDefaultUserPassword(val);
return 1;
}
#ifdef USE_OPENSSL #ifdef USE_OPENSSL
static int updateTlsCfg(char *val, char *prev, const char **err) { static int updateTlsCfg(char *val, char *prev, const char **err) {
UNUSED(val); UNUSED(val);
@ -2393,6 +2359,27 @@ static int updateTlsCfgInt(long long val, long long prev, const char **err) {
UNUSED(prev); UNUSED(prev);
return updateTlsCfg(NULL, NULL, err); return updateTlsCfg(NULL, NULL, err);
} }
static int updateTLSPort(long long val, long long prev, const char **err) {
/* Do nothing if port is unchanged */
if (val == prev) {
return 1;
}
/* Configure TLS if tls is enabled */
if (prev == 0 && tlsConfigure(&server.tls_ctx_config) == C_ERR) {
*err = "Unable to update TLS configuration. Check server logs.";
return 0;
}
if (changeListenPort(val, &server.tlsfd, acceptTLSHandler) == C_ERR) {
*err = "Unable to listen on this port. Check server logs.";
return 0;
}
return 1;
}
#endif /* USE_OPENSSL */ #endif /* USE_OPENSSL */
standardConfig configs[] = { standardConfig configs[] = {
@ -2458,6 +2445,7 @@ standardConfig configs[] = {
/* SDS Configs */ /* SDS Configs */
createSDSConfig("masterauth", NULL, MODIFIABLE_CONFIG, EMPTY_STRING_IS_NULL, server.masterauth, NULL, NULL, NULL), createSDSConfig("masterauth", NULL, MODIFIABLE_CONFIG, EMPTY_STRING_IS_NULL, server.masterauth, NULL, NULL, NULL),
createSDSConfig("requirepass", NULL, MODIFIABLE_CONFIG, EMPTY_STRING_IS_NULL, server.requirepass, NULL, NULL, updateRequirePass),
/* Enum Configs */ /* Enum Configs */
createEnumConfig("supervised", NULL, IMMUTABLE_CONFIG, supervised_mode_enum, server.supervised_mode, SUPERVISED_NONE, NULL, NULL), createEnumConfig("supervised", NULL, IMMUTABLE_CONFIG, supervised_mode_enum, server.supervised_mode, SUPERVISED_NONE, NULL, NULL),
@ -2472,7 +2460,7 @@ standardConfig configs[] = {
/* Integer configs */ /* Integer configs */
createIntConfig("databases", NULL, IMMUTABLE_CONFIG, 1, INT_MAX, server.dbnum, 16, INTEGER_CONFIG, NULL, NULL), createIntConfig("databases", NULL, IMMUTABLE_CONFIG, 1, INT_MAX, server.dbnum, 16, INTEGER_CONFIG, NULL, NULL),
createIntConfig("port", NULL, IMMUTABLE_CONFIG, 0, 65535, server.port, 6379, INTEGER_CONFIG, NULL, NULL), /* TCP port. */ createIntConfig("port", NULL, MODIFIABLE_CONFIG, 0, 65535, server.port, 6379, INTEGER_CONFIG, NULL, updatePort), /* TCP port. */
createIntConfig("io-threads", NULL, IMMUTABLE_CONFIG, 1, 128, server.io_threads_num, 1, INTEGER_CONFIG, NULL, NULL), /* Single threaded by default */ createIntConfig("io-threads", NULL, IMMUTABLE_CONFIG, 1, 128, server.io_threads_num, 1, INTEGER_CONFIG, NULL, NULL), /* Single threaded by default */
createIntConfig("auto-aof-rewrite-percentage", NULL, MODIFIABLE_CONFIG, 0, INT_MAX, server.aof_rewrite_perc, 100, INTEGER_CONFIG, NULL, NULL), createIntConfig("auto-aof-rewrite-percentage", NULL, MODIFIABLE_CONFIG, 0, INT_MAX, server.aof_rewrite_perc, 100, INTEGER_CONFIG, NULL, NULL),
createIntConfig("cluster-replica-validity-factor", "cluster-slave-validity-factor", MODIFIABLE_CONFIG, 0, INT_MAX, server.cluster_slave_validity_factor, 10, INTEGER_CONFIG, NULL, NULL), /* Slave max data age factor. */ createIntConfig("cluster-replica-validity-factor", "cluster-slave-validity-factor", MODIFIABLE_CONFIG, 0, INT_MAX, server.cluster_slave_validity_factor, 10, INTEGER_CONFIG, NULL, NULL), /* Slave max data age factor. */
@ -2534,13 +2522,14 @@ standardConfig configs[] = {
createSizeTConfig("zset-max-ziplist-value", NULL, MODIFIABLE_CONFIG, 0, LONG_MAX, server.zset_max_ziplist_value, 64, MEMORY_CONFIG, NULL, NULL), createSizeTConfig("zset-max-ziplist-value", NULL, MODIFIABLE_CONFIG, 0, LONG_MAX, server.zset_max_ziplist_value, 64, MEMORY_CONFIG, NULL, NULL),
createSizeTConfig("hll-sparse-max-bytes", NULL, MODIFIABLE_CONFIG, 0, LONG_MAX, server.hll_sparse_max_bytes, 3000, MEMORY_CONFIG, NULL, NULL), createSizeTConfig("hll-sparse-max-bytes", NULL, MODIFIABLE_CONFIG, 0, LONG_MAX, server.hll_sparse_max_bytes, 3000, MEMORY_CONFIG, NULL, NULL),
createSizeTConfig("tracking-table-max-keys", NULL, MODIFIABLE_CONFIG, 0, LONG_MAX, server.tracking_table_max_keys, 1000000, INTEGER_CONFIG, NULL, NULL), /* Default: 1 million keys max. */ createSizeTConfig("tracking-table-max-keys", NULL, MODIFIABLE_CONFIG, 0, LONG_MAX, server.tracking_table_max_keys, 1000000, INTEGER_CONFIG, NULL, NULL), /* Default: 1 million keys max. */
createSizeTConfig("client-query-buffer-limit", NULL, MODIFIABLE_CONFIG, 1024*1024, LONG_MAX, server.client_max_querybuf_len, 1024*1024*1024, MEMORY_CONFIG, NULL, NULL), /* Default: 1GB max query buffer. */
/* Other configs */ /* Other configs */
createTimeTConfig("repl-backlog-ttl", NULL, MODIFIABLE_CONFIG, 0, LONG_MAX, server.repl_backlog_time_limit, 60*60, INTEGER_CONFIG, NULL, NULL), /* Default: 1 hour */ createTimeTConfig("repl-backlog-ttl", NULL, MODIFIABLE_CONFIG, 0, LONG_MAX, server.repl_backlog_time_limit, 60*60, INTEGER_CONFIG, NULL, NULL), /* Default: 1 hour */
createOffTConfig("auto-aof-rewrite-min-size", NULL, MODIFIABLE_CONFIG, 0, LLONG_MAX, server.aof_rewrite_min_size, 64*1024*1024, MEMORY_CONFIG, NULL, NULL), createOffTConfig("auto-aof-rewrite-min-size", NULL, MODIFIABLE_CONFIG, 0, LLONG_MAX, server.aof_rewrite_min_size, 64*1024*1024, MEMORY_CONFIG, NULL, NULL),
#ifdef USE_OPENSSL #ifdef USE_OPENSSL
createIntConfig("tls-port", NULL, IMMUTABLE_CONFIG, 0, 65535, server.tls_port, 0, INTEGER_CONFIG, NULL, updateTlsCfgInt), /* TCP port. */ createIntConfig("tls-port", NULL, MODIFIABLE_CONFIG, 0, 65535, server.tls_port, 0, INTEGER_CONFIG, NULL, updateTLSPort), /* TCP port. */
createIntConfig("tls-session-cache-size", NULL, MODIFIABLE_CONFIG, 0, INT_MAX, server.tls_ctx_config.session_cache_size, 20*1024, INTEGER_CONFIG, NULL, updateTlsCfgInt), createIntConfig("tls-session-cache-size", NULL, MODIFIABLE_CONFIG, 0, INT_MAX, server.tls_ctx_config.session_cache_size, 20*1024, INTEGER_CONFIG, NULL, updateTlsCfgInt),
createIntConfig("tls-session-cache-timeout", NULL, MODIFIABLE_CONFIG, 0, INT_MAX, server.tls_ctx_config.session_cache_timeout, 300, INTEGER_CONFIG, NULL, updateTlsCfgInt), createIntConfig("tls-session-cache-timeout", NULL, MODIFIABLE_CONFIG, 0, INT_MAX, server.tls_ctx_config.session_cache_timeout, 300, INTEGER_CONFIG, NULL, updateTlsCfgInt),
createBoolConfig("tls-cluster", NULL, MODIFIABLE_CONFIG, server.tls_cluster, 0, NULL, updateTlsCfgBool), createBoolConfig("tls-cluster", NULL, MODIFIABLE_CONFIG, server.tls_cluster, 0, NULL, updateTlsCfgBool),

View File

@ -35,7 +35,6 @@
#endif #endif
#ifdef __linux__ #ifdef __linux__
#include <linux/version.h>
#include <features.h> #include <features.h>
#endif #endif
@ -114,19 +113,7 @@
/* Define rdb_fsync_range to sync_file_range() on Linux, otherwise we use /* Define rdb_fsync_range to sync_file_range() on Linux, otherwise we use
* the plain fsync() call. */ * the plain fsync() call. */
#ifdef __linux__ #if (defined(__linux__) && defined(SYNC_FILE_RANGE_WAIT_BEFORE))
#if defined(__GLIBC__) && defined(__GLIBC_PREREQ)
#if (LINUX_VERSION_CODE >= 0x020611 && __GLIBC_PREREQ(2, 6))
#define HAVE_SYNC_FILE_RANGE 1
#endif
#else
#if (LINUX_VERSION_CODE >= 0x020611)
#define HAVE_SYNC_FILE_RANGE 1
#endif
#endif
#endif
#ifdef HAVE_SYNC_FILE_RANGE
#define rdb_fsync_range(fd,off,size) sync_file_range(fd,off,size,SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE) #define rdb_fsync_range(fd,off,size) sync_file_range(fd,off,size,SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE)
#else #else
#define rdb_fsync_range(fd,off,size) fsync(fd) #define rdb_fsync_range(fd,off,size) fsync(fd)
@ -143,7 +130,7 @@
#define ESOCKTNOSUPPORT 0 #define ESOCKTNOSUPPORT 0
#endif #endif
#if ((defined __linux && defined(__GLIBC__)) || defined __APPLE__) #if (defined __linux || defined __APPLE__)
#define USE_SETPROCTITLE #define USE_SETPROCTITLE
#define INIT_SETPROCTITLE_REPLACEMENT #define INIT_SETPROCTITLE_REPLACEMENT
void spt_init(int argc, char *argv[]); void spt_init(int argc, char *argv[]);

View File

@ -427,7 +427,7 @@ int connGetState(connection *conn) {
* For sockets, we always return "fd=<fdnum>" to maintain compatibility. * For sockets, we always return "fd=<fdnum>" to maintain compatibility.
*/ */
const char *connGetInfo(connection *conn, char *buf, size_t buf_len) { const char *connGetInfo(connection *conn, char *buf, size_t buf_len) {
snprintf(buf, buf_len-1, "fd=%i", conn->fd); snprintf(buf, buf_len-1, "fd=%i", conn == NULL ? -1 : conn->fd);
return buf; return buf;
} }

View File

@ -1315,7 +1315,7 @@ void scanDatabaseForReadyLists(redisDb *db) {
* *
* Returns C_ERR if at least one of the DB ids are out of range, otherwise * Returns C_ERR if at least one of the DB ids are out of range, otherwise
* C_OK is returned. */ * C_OK is returned. */
int dbSwapDatabases(long id1, long id2) { int dbSwapDatabases(int id1, int id2) {
if (id1 < 0 || id1 >= server.dbnum || if (id1 < 0 || id1 >= server.dbnum ||
id2 < 0 || id2 >= server.dbnum) return C_ERR; id2 < 0 || id2 >= server.dbnum) return C_ERR;
if (id1 == id2) return C_OK; if (id1 == id2) return C_OK;
@ -1356,7 +1356,7 @@ int dbSwapDatabases(long id1, long id2) {
/* SWAPDB db1 db2 */ /* SWAPDB db1 db2 */
void swapdbCommand(client *c) { void swapdbCommand(client *c) {
long id1, id2; int id1, id2;
/* Not allowed in cluster mode: we have just DB 0 there. */ /* Not allowed in cluster mode: we have just DB 0 there. */
if (server.cluster_enabled) { if (server.cluster_enabled) {
@ -1365,11 +1365,11 @@ void swapdbCommand(client *c) {
} }
/* Get the two DBs indexes. */ /* Get the two DBs indexes. */
if (getLongFromObjectOrReply(c, c->argv[1], &id1, if (getIntFromObjectOrReply(c, c->argv[1], &id1,
"invalid first DB index") != C_OK) "invalid first DB index") != C_OK)
return; return;
if (getLongFromObjectOrReply(c, c->argv[2], &id2, if (getIntFromObjectOrReply(c, c->argv[2], &id2,
"invalid second DB index") != C_OK) "invalid second DB index") != C_OK)
return; return;

View File

@ -54,6 +54,10 @@ typedef ucontext_t sigcontext_t;
#endif #endif
#endif #endif
#if defined(__APPLE__) && defined(__arm64__)
#include <mach/mach.h>
#endif
/* Globals */ /* Globals */
static int bug_report_start = 0; /* True if bug report header was already logged. */ static int bug_report_start = 0; /* True if bug report header was already logged. */
static pthread_mutex_t bug_report_start_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t bug_report_start_mutex = PTHREAD_MUTEX_INITIALIZER;

View File

@ -60,7 +60,6 @@
#ifdef __linux__ #ifdef __linux__
/* features.h uses the defines above to set feature specific defines. */ /* features.h uses the defines above to set feature specific defines. */
#include <linux/version.h>
#include <features.h> #include <features.h>
#endif #endif

View File

@ -84,9 +84,9 @@ lwCanvas *lwDrawSchotter(int console_cols, int squares_per_row, int squares_per_
* rows. */ * rows. */
float angle = 0; float angle = 0;
if (y > 1) { if (y > 1) {
float r1 = (float)rand() / RAND_MAX / squares_per_col * y; float r1 = (float)rand() / (float) RAND_MAX / squares_per_col * y;
float r2 = (float)rand() / RAND_MAX / squares_per_col * y; float r2 = (float)rand() / (float) RAND_MAX / squares_per_col * y;
float r3 = (float)rand() / RAND_MAX / squares_per_col * y; float r3 = (float)rand() / (float) RAND_MAX / squares_per_col * y;
if (rand() % 2) r1 = -r1; if (rand() % 2) r1 = -r1;
if (rand() % 2) r2 = -r2; if (rand() % 2) r2 = -r2;
if (rand() % 2) r3 = -r3; if (rand() % 2) r3 = -r3;

View File

@ -1837,6 +1837,28 @@ unsigned long long RM_GetClientId(RedisModuleCtx *ctx) {
return ctx->client->id; return ctx->client->id;
} }
/* Return the ACL user name used by the client with the specified client ID.
* Client ID can be obtained with RM_GetClientId() API. If the client does not
* exist, NULL is returned and errno is set to ENOENT. If the client isn't
* using an ACL user, NULL is returned and errno is set to ENOTSUP */
RedisModuleString *RM_GetClientUserNameById(RedisModuleCtx *ctx, uint64_t id) {
client *client = lookupClientByID(id);
if (client == NULL) {
errno = ENOENT;
return NULL;
}
if (client->user == NULL) {
errno = ENOTSUP;
return NULL;
}
sds name = sdsnew(client->user->name);
robj *str = createObject(OBJ_STRING, name);
autoMemoryAdd(ctx, REDISMODULE_AM_STRING, str);
return str;
}
/* This is an helper for RM_GetClientInfoById() and other functions: given /* This is an helper for RM_GetClientInfoById() and other functions: given
* a client, it populates the client info structure with the appropriate * a client, it populates the client info structure with the appropriate
* fields depending on the version provided. If the version is not valid * fields depending on the version provided. If the version is not valid
@ -3969,16 +3991,26 @@ RedisModuleCallReply *RM_Call(RedisModuleCtx *ctx, const char *cmdname, const ch
RedisModuleCallReply *reply = NULL; RedisModuleCallReply *reply = NULL;
int replicate = 0; /* Replicate this command? */ int replicate = 0; /* Replicate this command? */
/* Create the client and dispatch the command. */ /* Handle arguments. */
va_start(ap, fmt); va_start(ap, fmt);
c = createClient(NULL);
c->user = NULL; /* Root user. */
argv = moduleCreateArgvFromUserFormat(cmdname,fmt,&argc,&flags,ap); argv = moduleCreateArgvFromUserFormat(cmdname,fmt,&argc,&flags,ap);
replicate = flags & REDISMODULE_ARGV_REPLICATE; replicate = flags & REDISMODULE_ARGV_REPLICATE;
va_end(ap); va_end(ap);
/* Setup our fake client for command execution. */ /* Setup our fake client for command execution. */
c->flags |= CLIENT_MODULE; if (server.module_client == NULL) {
/* This is the first RM_Call() ever. Create reusable client. */
c = server.module_client = createClient(NULL);
} else if (server.module_client->argv == NULL) {
/* The reusable module client is not busy with a command. Use it. */
c = server.module_client;
} else {
/* The reusable module client is busy. (It is probably used in a
* recursive call to this module.) */
c = createClient(NULL);
}
c->user = NULL; /* Root user. */
c->flags = CLIENT_MODULE;
/* We do not want to allow block, the module do not expect it */ /* We do not want to allow block, the module do not expect it */
c->flags |= CLIENT_DENY_BLOCKING; c->flags |= CLIENT_DENY_BLOCKING;
@ -4066,7 +4098,18 @@ RedisModuleCallReply *RM_Call(RedisModuleCtx *ctx, const char *cmdname, const ch
cleanup: cleanup:
if (ctx->module) ctx->module->in_call--; if (ctx->module) ctx->module->in_call--;
freeClient(c); if (c == server.module_client) {
/* reset shared client so it can be reused */
discardTransaction(c);
pubsubUnsubscribeAllChannels(c,0);
pubsubUnsubscribeAllPatterns(c,0);
resetClient(c); /* frees the contents of argv */
zfree(c->argv);
c->argv = NULL;
c->resp = 2;
} else {
freeClient(c); /* temporary client */
}
return reply; return reply;
} }
@ -8269,6 +8312,9 @@ void moduleInitModulesSystem(void) {
/* Set up filter list */ /* Set up filter list */
moduleCommandFilters = listCreate(); moduleCommandFilters = listCreate();
/* Reusable client for RM_Call() is created on first use */
server.module_client = NULL;
moduleRegisterCoreAPI(); moduleRegisterCoreAPI();
if (pipe(server.module_blocked_pipe) == -1) { if (pipe(server.module_blocked_pipe) == -1) {
serverLog(LL_WARNING, serverLog(LL_WARNING,
@ -9133,6 +9179,7 @@ void moduleRegisterCoreAPI(void) {
REGISTER_API(IsKeysPositionRequest); REGISTER_API(IsKeysPositionRequest);
REGISTER_API(KeyAtPos); REGISTER_API(KeyAtPos);
REGISTER_API(GetClientId); REGISTER_API(GetClientId);
REGISTER_API(GetClientUserNameById);
REGISTER_API(GetContextFlags); REGISTER_API(GetContextFlags);
REGISTER_API(AvoidReplicaTraffic); REGISTER_API(AvoidReplicaTraffic);
REGISTER_API(PoolAlloc); REGISTER_API(PoolAlloc);

View File

@ -250,18 +250,20 @@ int pubsubUnsubscribePattern(client *c, robj *pattern, int notify) {
/* Unsubscribe from all the channels. Return the number of channels the /* Unsubscribe from all the channels. Return the number of channels the
* client was subscribed to. */ * client was subscribed to. */
int pubsubUnsubscribeAllChannels(client *c, int notify) { int pubsubUnsubscribeAllChannels(client *c, int notify) {
int count = 0;
if (dictSize(c->pubsub_channels) > 0) {
dictIterator *di = dictGetSafeIterator(c->pubsub_channels); dictIterator *di = dictGetSafeIterator(c->pubsub_channels);
dictEntry *de; dictEntry *de;
int count = 0;
while((de = dictNext(di)) != NULL) { while((de = dictNext(di)) != NULL) {
robj *channel = dictGetKey(de); robj *channel = dictGetKey(de);
count += pubsubUnsubscribeChannel(c,channel,notify); count += pubsubUnsubscribeChannel(c,channel,notify);
} }
dictReleaseIterator(di);
}
/* We were subscribed to nothing? Still reply to the client. */ /* We were subscribed to nothing? Still reply to the client. */
if (notify && count == 0) addReplyPubsubUnsubscribed(c,NULL); if (notify && count == 0) addReplyPubsubUnsubscribed(c,NULL);
dictReleaseIterator(di);
return count; return count;
} }

View File

@ -999,7 +999,7 @@ int quicklistDelRange(quicklist *quicklist, const long start,
* can just delete the entire node without ziplist math. */ * can just delete the entire node without ziplist math. */
delete_entire_node = 1; delete_entire_node = 1;
del = node->count; del = node->count;
} else if (entry.offset >= 0 && extent >= node->count) { } else if (entry.offset >= 0 && extent + entry.offset >= node->count) {
/* If deleting more nodes after this one, calculate delete based /* If deleting more nodes after this one, calculate delete based
* on size of current node. */ * on size of current node. */
del = node->count - entry.offset; del = node->count - entry.offset;
@ -2238,6 +2238,17 @@ int quicklistTest(int argc, char *argv[]) {
quicklistRelease(ql); quicklistRelease(ql);
} }
TEST("delete less than fill but across nodes") {
quicklist *ql = quicklistNew(-2, options[_i]);
quicklistSetFill(ql, 32);
for (int i = 0; i < 500; i++)
quicklistPushTail(ql, genstr("hello", i + 1), 32);
ql_verify(ql, 16, 500, 32, 20);
quicklistDelRange(ql, 60, 10);
ql_verify(ql, 16, 490, 32, 20);
quicklistRelease(ql);
}
TEST("delete negative 1 from 500 list") { TEST("delete negative 1 from 500 list") {
quicklist *ql = quicklistNew(-2, options[_i]); quicklist *ql = quicklistNew(-2, options[_i]);
quicklistSetFill(ql, 32); quicklistSetFill(ql, 32);

View File

@ -819,6 +819,9 @@ static int cliConnect(int flags) {
if (context == NULL || flags & CC_FORCE) { if (context == NULL || flags & CC_FORCE) {
if (context != NULL) { if (context != NULL) {
redisFree(context); redisFree(context);
config.dbnum = 0;
config.in_multi = 0;
cliRefreshPrompt();
} }
if (config.hostsocket == NULL) { if (config.hostsocket == NULL) {
@ -2969,7 +2972,7 @@ static void clusterManagerOptimizeAntiAffinity(clusterManagerNodeArray *ipnodes,
ip_count, ip_count,
&offenders, &offenders,
&offending_len); &offending_len);
if (score == 0) break; // Optimal anti affinity reached if (score == 0 || offending_len == 0) break; // Optimal anti affinity reached
/* We'll try to randomly swap a slave's assigned master causing /* We'll try to randomly swap a slave's assigned master causing
* an affinity problem with another random slave, to see if we * an affinity problem with another random slave, to see if we
* can improve the affinity. */ * can improve the affinity. */

View File

@ -665,6 +665,7 @@ REDISMODULE_API long long (*RedisModule_StreamTrimByID)(RedisModuleKey *key, int
REDISMODULE_API int (*RedisModule_IsKeysPositionRequest)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_IsKeysPositionRequest)(RedisModuleCtx *ctx) REDISMODULE_ATTR;
REDISMODULE_API void (*RedisModule_KeyAtPos)(RedisModuleCtx *ctx, int pos) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_KeyAtPos)(RedisModuleCtx *ctx, int pos) REDISMODULE_ATTR;
REDISMODULE_API unsigned long long (*RedisModule_GetClientId)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API unsigned long long (*RedisModule_GetClientId)(RedisModuleCtx *ctx) REDISMODULE_ATTR;
REDISMODULE_API RedisModuleString * (*RedisModule_GetClientUserNameById)(RedisModuleCtx *ctx, uint64_t id) REDISMODULE_ATTR;
REDISMODULE_API int (*RedisModule_GetClientInfoById)(void *ci, uint64_t id) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_GetClientInfoById)(void *ci, uint64_t id) REDISMODULE_ATTR;
REDISMODULE_API int (*RedisModule_PublishMessage)(RedisModuleCtx *ctx, RedisModuleString *channel, RedisModuleString *message) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_PublishMessage)(RedisModuleCtx *ctx, RedisModuleString *channel, RedisModuleString *message) REDISMODULE_ATTR;
REDISMODULE_API int (*RedisModule_GetContextFlags)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_GetContextFlags)(RedisModuleCtx *ctx) REDISMODULE_ATTR;
@ -936,6 +937,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
REDISMODULE_GET_API(IsKeysPositionRequest); REDISMODULE_GET_API(IsKeysPositionRequest);
REDISMODULE_GET_API(KeyAtPos); REDISMODULE_GET_API(KeyAtPos);
REDISMODULE_GET_API(GetClientId); REDISMODULE_GET_API(GetClientId);
REDISMODULE_GET_API(GetClientUserNameById);
REDISMODULE_GET_API(GetContextFlags); REDISMODULE_GET_API(GetContextFlags);
REDISMODULE_GET_API(AvoidReplicaTraffic); REDISMODULE_GET_API(AvoidReplicaTraffic);
REDISMODULE_GET_API(PoolAlloc); REDISMODULE_GET_API(PoolAlloc);

View File

@ -619,7 +619,7 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
"at least one of the keys mentioned in the " "at least one of the keys mentioned in the "
"command arguments"); "command arguments");
break; break;
case ACL_DENIED_AUTH: case ACL_DENIED_CHANNEL:
luaPushError(lua, "The user executing the script can't publish " luaPushError(lua, "The user executing the script can't publish "
"to the channel mentioned in the command"); "to the channel mentioned in the command");
break; break;
@ -1544,7 +1544,7 @@ void evalGenericCommand(client *c, int evalsha) {
* return an error. */ * return an error. */
if (evalsha) { if (evalsha) {
lua_pop(lua,1); /* remove the error handler from the stack. */ lua_pop(lua,1); /* remove the error handler from the stack. */
addReply(c, shared.noscripterr); addReplyErrorObject(c, shared.noscripterr);
return; return;
} }
if (luaCreateFunction(c,lua,c->argv[1]) == NULL) { if (luaCreateFunction(c,lua,c->argv[1]) == NULL) {
@ -1695,7 +1695,7 @@ void evalShaCommand(client *c) {
* not the right length. So we return an error ASAP, this way * not the right length. So we return an error ASAP, this way
* evalGenericCommand() can be implemented without string length * evalGenericCommand() can be implemented without string length
* sanity check */ * sanity check */
addReply(c, shared.noscripterr); addReplyErrorObject(c, shared.noscripterr);
return; return;
} }
if (!(c->flags & CLIENT_LUA_DEBUG)) if (!(c->flags & CLIENT_LUA_DEBUG))

View File

@ -1070,7 +1070,7 @@ struct redisCommand redisCommandTable[] = {
"write fast @stream", "write fast @stream",
0,NULL,1,1,1,0,0,0}, 0,NULL,1,1,1,0,0,0},
{"xtrim",xtrimCommand,-2, {"xtrim",xtrimCommand,-4,
"write random @stream", "write random @stream",
0,NULL,1,1,1,0,0,0}, 0,NULL,1,1,1,0,0,0},
@ -2648,12 +2648,11 @@ void initServerConfig(void) {
server.arch_bits = (sizeof(long) == 8) ? 64 : 32; server.arch_bits = (sizeof(long) == 8) ? 64 : 32;
server.bindaddr_count = 0; server.bindaddr_count = 0;
server.unixsocketperm = CONFIG_DEFAULT_UNIX_SOCKET_PERM; server.unixsocketperm = CONFIG_DEFAULT_UNIX_SOCKET_PERM;
server.ipfd_count = 0; server.ipfd.count = 0;
server.tlsfd_count = 0; server.tlsfd.count = 0;
server.sofd = -1; server.sofd = -1;
server.active_expire_enabled = 1; server.active_expire_enabled = 1;
server.skip_checksum_validation = 0; server.skip_checksum_validation = 0;
server.client_max_querybuf_len = PROTO_MAX_QUERYBUF_LEN;
server.saveparams = NULL; server.saveparams = NULL;
server.loading = 0; server.loading = 0;
server.loading_rdb_used_mem = 0; server.loading_rdb_used_mem = 0;
@ -2989,6 +2988,34 @@ void checkTcpBacklogSettings(void) {
#endif #endif
} }
void closeSocketListeners(socketFds *sfd) {
int j;
for (j = 0; j < sfd->count; j++) {
if (sfd->fd[j] == -1) continue;
aeDeleteFileEvent(server.el, sfd->fd[j], AE_READABLE);
close(sfd->fd[j]);
}
sfd->count = 0;
}
/* Create an event handler for accepting new connections in TCP or TLS domain sockets.
* This works atomically for all socket fds */
int createSocketAcceptHandler(socketFds *sfd, aeFileProc *accept_handler) {
int j;
for (j = 0; j < sfd->count; j++) {
if (aeCreateFileEvent(server.el, sfd->fd[j], AE_READABLE, accept_handler,NULL) == AE_ERR) {
/* Rollback */
for (j = j-1; j >= 0; j--) aeDeleteFileEvent(server.el, sfd->fd[j], AE_READABLE);
return C_ERR;
}
}
return C_OK;
}
/* Initialize a set of file descriptors to listen to the specified 'port' /* Initialize a set of file descriptors to listen to the specified 'port'
* binding the addresses specified in the Redis server configuration. * binding the addresses specified in the Redis server configuration.
* *
@ -3007,7 +3034,7 @@ void checkTcpBacklogSettings(void) {
* impossible to bind, or no bind addresses were specified in the server * impossible to bind, or no bind addresses were specified in the server
* configuration but the function is not able to bind * for at least * configuration but the function is not able to bind * for at least
* one of the IPv4 or IPv6 protocols. */ * one of the IPv4 or IPv6 protocols. */
int listenToPort(int port, int *fds, int *count) { int listenToPort(int port, socketFds *sfd) {
int j; int j;
char **bindaddr = server.bindaddr; char **bindaddr = server.bindaddr;
int bindaddr_count = server.bindaddr_count; int bindaddr_count = server.bindaddr_count;
@ -3025,12 +3052,12 @@ int listenToPort(int port, int *fds, int *count) {
if (optional) addr++; if (optional) addr++;
if (strchr(addr,':')) { if (strchr(addr,':')) {
/* Bind IPv6 address. */ /* Bind IPv6 address. */
fds[*count] = anetTcp6Server(server.neterr,port,addr,server.tcp_backlog); sfd->fd[sfd->count] = anetTcp6Server(server.neterr,port,addr,server.tcp_backlog);
} else { } else {
/* Bind IPv4 address. */ /* Bind IPv4 address. */
fds[*count] = anetTcpServer(server.neterr,port,addr,server.tcp_backlog); sfd->fd[sfd->count] = anetTcpServer(server.neterr,port,addr,server.tcp_backlog);
} }
if (fds[*count] == ANET_ERR) { if (sfd->fd[sfd->count] == ANET_ERR) {
serverLog(LL_WARNING, serverLog(LL_WARNING,
"Could not create server TCP listening socket %s:%d: %s", "Could not create server TCP listening socket %s:%d: %s",
addr, port, server.neterr); addr, port, server.neterr);
@ -3040,11 +3067,14 @@ int listenToPort(int port, int *fds, int *count) {
errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT || errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
errno == EAFNOSUPPORT) errno == EAFNOSUPPORT)
continue; continue;
/* Rollback successful listens before exiting */
closeSocketListeners(sfd);
return C_ERR; return C_ERR;
} }
anetNonBlock(NULL,fds[*count]); anetNonBlock(NULL,sfd->fd[sfd->count]);
anetCloexec(fds[*count]); anetCloexec(sfd->fd[sfd->count]);
(*count)++; sfd->count++;
} }
return C_OK; return C_OK;
} }
@ -3166,10 +3196,10 @@ void initServer(void) {
/* Open the TCP listening socket for the user commands. */ /* Open the TCP listening socket for the user commands. */
if (server.port != 0 && if (server.port != 0 &&
listenToPort(server.port,server.ipfd,&server.ipfd_count) == C_ERR) listenToPort(server.port,&server.ipfd) == C_ERR)
exit(1); exit(1);
if (server.tls_port != 0 && if (server.tls_port != 0 &&
listenToPort(server.tls_port,server.tlsfd,&server.tlsfd_count) == C_ERR) listenToPort(server.tls_port,&server.tlsfd) == C_ERR)
exit(1); exit(1);
/* Open the listening Unix domain socket. */ /* Open the listening Unix domain socket. */
@ -3186,7 +3216,7 @@ void initServer(void) {
} }
/* Abort if there are no listening sockets at all. */ /* Abort if there are no listening sockets at all. */
if (server.ipfd_count == 0 && server.tlsfd_count == 0 && server.sofd < 0) { if (server.ipfd.count == 0 && server.tlsfd.count == 0 && server.sofd < 0) {
serverLog(LL_WARNING, "Configured to not listen anywhere, exiting."); serverLog(LL_WARNING, "Configured to not listen anywhere, exiting.");
exit(1); exit(1);
} }
@ -3264,21 +3294,11 @@ void initServer(void) {
/* Create an event handler for accepting new connections in TCP and Unix /* Create an event handler for accepting new connections in TCP and Unix
* domain sockets. */ * domain sockets. */
for (j = 0; j < server.ipfd_count; j++) { if (createSocketAcceptHandler(&server.ipfd, acceptTcpHandler) != C_OK) {
if (aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE, serverPanic("Unrecoverable error creating TCP socket accept handler.");
acceptTcpHandler,NULL) == AE_ERR)
{
serverPanic(
"Unrecoverable error creating server.ipfd file event.");
}
}
for (j = 0; j < server.tlsfd_count; j++) {
if (aeCreateFileEvent(server.el, server.tlsfd[j], AE_READABLE,
acceptTLSHandler,NULL) == AE_ERR)
{
serverPanic(
"Unrecoverable error creating server.tlsfd file event.");
} }
if (createSocketAcceptHandler(&server.tlsfd, acceptTLSHandler) != C_OK) {
serverPanic("Unrecoverable error creating TLS socket accept handler.");
} }
if (server.sofd > 0 && aeCreateFileEvent(server.el,server.sofd,AE_READABLE, if (server.sofd > 0 && aeCreateFileEvent(server.el,server.sofd,AE_READABLE,
acceptUnixHandler,NULL) == AE_ERR) serverPanic("Unrecoverable error creating server.sofd file event."); acceptUnixHandler,NULL) == AE_ERR) serverPanic("Unrecoverable error creating server.sofd file event.");
@ -3324,6 +3344,9 @@ void initServer(void) {
scriptingInit(1); scriptingInit(1);
slowlogInit(); slowlogInit();
latencyMonitorInit(); latencyMonitorInit();
/* Initialize ACL default password if it exists */
ACLUpdateDefaultUserPassword(server.requirepass);
} }
/* Some steps in server initialization need to be done last (after modules /* Some steps in server initialization need to be done last (after modules
@ -4180,11 +4203,11 @@ void incrementErrorCount(const char *fullerr, size_t namelen) {
void closeListeningSockets(int unlink_unix_socket) { void closeListeningSockets(int unlink_unix_socket) {
int j; int j;
for (j = 0; j < server.ipfd_count; j++) close(server.ipfd[j]); for (j = 0; j < server.ipfd.count; j++) close(server.ipfd.fd[j]);
for (j = 0; j < server.tlsfd_count; j++) close(server.tlsfd[j]); for (j = 0; j < server.tlsfd.count; j++) close(server.tlsfd.fd[j]);
if (server.sofd != -1) close(server.sofd); if (server.sofd != -1) close(server.sofd);
if (server.cluster_enabled) if (server.cluster_enabled)
for (j = 0; j < server.cfd_count; j++) close(server.cfd[j]); for (j = 0; j < server.cfd.count; j++) close(server.cfd.fd[j]);
if (unlink_unix_socket && server.unixsocket) { if (unlink_unix_socket && server.unixsocket) {
serverLog(LL_NOTICE,"Removing the unix socket file."); serverLog(LL_NOTICE,"Removing the unix socket file.");
unlink(server.unixsocket); /* don't care if this fails */ unlink(server.unixsocket); /* don't care if this fails */
@ -5534,6 +5557,105 @@ void redisAsciiArt(void) {
zfree(buf); zfree(buf);
} }
int changeBindAddr(sds *addrlist, int addrlist_len) {
int i;
int result = C_OK;
char *prev_bindaddr[CONFIG_BINDADDR_MAX];
int prev_bindaddr_count;
/* Close old TCP and TLS servers */
closeSocketListeners(&server.ipfd);
closeSocketListeners(&server.tlsfd);
/* Keep previous settings */
prev_bindaddr_count = server.bindaddr_count;
memcpy(prev_bindaddr, server.bindaddr, sizeof(server.bindaddr));
/* Copy new settings */
memset(server.bindaddr, 0, sizeof(server.bindaddr));
for (i = 0; i < addrlist_len; i++) {
server.bindaddr[i] = zstrdup(addrlist[i]);
}
server.bindaddr_count = addrlist_len;
/* Bind to the new port */
if ((server.port != 0 && listenToPort(server.port, &server.ipfd) != C_OK) ||
(server.tls_port != 0 && listenToPort(server.tls_port, &server.tlsfd) != C_OK)) {
serverLog(LL_WARNING, "Failed to bind, trying to restore old listening sockets.");
/* Restore old bind addresses */
for (i = 0; i < addrlist_len; i++) {
zfree(server.bindaddr[i]);
}
memcpy(server.bindaddr, prev_bindaddr, sizeof(server.bindaddr));
server.bindaddr_count = prev_bindaddr_count;
/* Re-Listen TCP and TLS */
server.ipfd.count = 0;
if (server.port != 0 && listenToPort(server.port, &server.ipfd) != C_OK) {
serverPanic("Failed to restore old listening sockets.");
}
server.tlsfd.count = 0;
if (server.tls_port != 0 && listenToPort(server.tls_port, &server.tlsfd) != C_OK) {
serverPanic("Failed to restore old listening sockets.");
}
result = C_ERR;
} else {
/* Free old bind addresses */
for (i = 0; i < prev_bindaddr_count; i++) {
zfree(prev_bindaddr[i]);
}
}
/* Create TCP and TLS event handlers */
if (createSocketAcceptHandler(&server.ipfd, acceptTcpHandler) != C_OK) {
serverPanic("Unrecoverable error creating TCP socket accept handler.");
}
if (createSocketAcceptHandler(&server.tlsfd, acceptTLSHandler) != C_OK) {
serverPanic("Unrecoverable error creating TLS socket accept handler.");
}
if (server.set_proc_title) redisSetProcTitle(NULL);
return result;
}
int changeListenPort(int port, socketFds *sfd, aeFileProc *accept_handler) {
socketFds new_sfd = {{0}};
/* Just close the server if port disabled */
if (port == 0) {
closeSocketListeners(sfd);
if (server.set_proc_title) redisSetProcTitle(NULL);
return C_OK;
}
/* Bind to the new port */
if (listenToPort(port, &new_sfd) != C_OK) {
return C_ERR;
}
/* Create event handlers */
if (createSocketAcceptHandler(&new_sfd, accept_handler) != C_OK) {
closeSocketListeners(&new_sfd);
return C_ERR;
}
/* Close old servers */
closeSocketListeners(sfd);
/* Copy new descriptors */
sfd->count = new_sfd.count;
memcpy(sfd->fd, new_sfd.fd, sizeof(new_sfd.fd));
if (server.set_proc_title) redisSetProcTitle(NULL);
return C_OK;
}
static void sigShutdownHandler(int sig) { static void sigShutdownHandler(int sig) {
char *msg; char *msg;
@ -6122,7 +6244,7 @@ int main(int argc, char **argv) {
exit(1); exit(1);
} }
} }
if (server.ipfd_count > 0 || server.tlsfd_count > 0) if (server.ipfd.count > 0 || server.tlsfd.count > 0)
serverLog(LL_NOTICE,"Ready to accept connections"); serverLog(LL_NOTICE,"Ready to accept connections");
if (server.sofd > 0) if (server.sofd > 0)
serverLog(LL_NOTICE,"The server is now ready to accept connections at %s", server.unixsocket); serverLog(LL_NOTICE,"The server is now ready to accept connections at %s", server.unixsocket);

View File

@ -138,7 +138,6 @@ typedef long long ustime_t; /* microsecond time type. */
#define STATS_METRIC_COUNT 3 #define STATS_METRIC_COUNT 3
/* Protocol and I/O related defines */ /* Protocol and I/O related defines */
#define PROTO_MAX_QUERYBUF_LEN (1024*1024*1024) /* 1GB max query buffer. */
#define PROTO_IOBUF_LEN (1024*16) /* Generic I/O buffer size */ #define PROTO_IOBUF_LEN (1024*16) /* Generic I/O buffer size */
#define PROTO_REPLY_CHUNK_BYTES (16*1024) /* 16k output buffer */ #define PROTO_REPLY_CHUNK_BYTES (16*1024) /* 16k output buffer */
#define PROTO_INLINE_MAX_SIZE (1024*64) /* Max size of inline reads */ #define PROTO_INLINE_MAX_SIZE (1024*64) /* Max size of inline reads */
@ -1105,6 +1104,11 @@ struct malloc_stats {
size_t allocator_resident; size_t allocator_resident;
}; };
typedef struct socketFds {
int fd[CONFIG_BINDADDR_MAX];
int count;
} socketFds;
/*----------------------------------------------------------------------------- /*-----------------------------------------------------------------------------
* TLS Context Configuration * TLS Context Configuration
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
@ -1196,6 +1200,7 @@ struct redisServer {
to be processed. */ to be processed. */
pid_t child_pid; /* PID of current child */ pid_t child_pid; /* PID of current child */
int child_type; /* Type of current child */ int child_type; /* Type of current child */
client *module_client; /* "Fake" client to call Redis from modules */
/* Networking */ /* Networking */
int port; /* TCP listening port */ int port; /* TCP listening port */
int tls_port; /* TLS listening port */ int tls_port; /* TLS listening port */
@ -1204,13 +1209,10 @@ struct redisServer {
int bindaddr_count; /* Number of addresses in server.bindaddr[] */ int bindaddr_count; /* Number of addresses in server.bindaddr[] */
char *unixsocket; /* UNIX socket path */ char *unixsocket; /* UNIX socket path */
mode_t unixsocketperm; /* UNIX socket permission */ mode_t unixsocketperm; /* UNIX socket permission */
int ipfd[CONFIG_BINDADDR_MAX]; /* TCP socket file descriptors */ socketFds ipfd; /* TCP socket file descriptors */
int ipfd_count; /* Used slots in ipfd[] */ socketFds tlsfd; /* TLS socket file descriptors */
int tlsfd[CONFIG_BINDADDR_MAX]; /* TLS socket file descriptors */
int tlsfd_count; /* Used slots in tlsfd[] */
int sofd; /* Unix socket file descriptor */ int sofd; /* Unix socket file descriptor */
int cfd[CONFIG_BINDADDR_MAX];/* Cluster bus listening socket */ socketFds cfd; /* Cluster bus listening socket */
int cfd_count; /* Used slots in cfd[] */
list *clients; /* List of active clients */ list *clients; /* List of active clients */
list *clients_to_close; /* Clients to close asynchronously */ list *clients_to_close; /* Clients to close asynchronously */
list *clients_pending_write; /* There is to write or install handler. */ list *clients_pending_write; /* There is to write or install handler. */
@ -1855,7 +1857,7 @@ int getClientTypeByName(char *name);
char *getClientTypeName(int class); char *getClientTypeName(int class);
void flushSlavesOutputBuffers(void); void flushSlavesOutputBuffers(void);
void disconnectSlaves(void); void disconnectSlaves(void);
int listenToPort(int port, int *fds, int *count); int listenToPort(int port, socketFds *fds);
void pauseClients(mstime_t duration, pause_type type); void pauseClients(mstime_t duration, pause_type type);
void unpauseClients(void); void unpauseClients(void);
int areClientsPaused(void); int areClientsPaused(void);
@ -2106,6 +2108,7 @@ void addReplyCommandCategories(client *c, struct redisCommand *cmd);
user *ACLCreateUnlinkedUser(); user *ACLCreateUnlinkedUser();
void ACLFreeUserAndKillClients(user *u); void ACLFreeUserAndKillClients(user *u);
void addACLLogEntry(client *c, int reason, int keypos, sds username); void addACLLogEntry(client *c, int reason, int keypos, sds username);
void ACLUpdateDefaultUserPassword(sds password);
/* Sorted sets data type */ /* Sorted sets data type */
@ -2183,6 +2186,9 @@ int processCommand(client *c);
int processPendingCommandsAndResetClient(client *c); int processPendingCommandsAndResetClient(client *c);
void setupSignalHandlers(void); void setupSignalHandlers(void);
void removeSignalHandlers(void); void removeSignalHandlers(void);
int createSocketAcceptHandler(socketFds *sfd, aeFileProc *accept_handler);
int changeListenPort(int port, socketFds *sfd, aeFileProc *accept_handler);
int changeBindAddr(sds *addrlist, int addrlist_len);
struct redisCommand *lookupCommand(sds name); struct redisCommand *lookupCommand(sds name);
struct redisCommand *lookupCommandByCString(const char *s); struct redisCommand *lookupCommandByCString(const char *s);
struct redisCommand *lookupCommandOrOriginal(sds name); struct redisCommand *lookupCommandOrOriginal(sds name);

View File

@ -232,7 +232,7 @@ void spt_init(int argc, char *argv[]) {
if (!(SPT.arg0 = strdup(argv[0]))) if (!(SPT.arg0 = strdup(argv[0])))
goto syerr; goto syerr;
#if __GLIBC__ #if __linux__
if (!(tmp = strdup(program_invocation_name))) if (!(tmp = strdup(program_invocation_name)))
goto syerr; goto syerr;

View File

@ -3229,17 +3229,17 @@ cleanup:
void xtrimCommand(client *c) { void xtrimCommand(client *c) {
robj *o; robj *o;
/* Argument parsing. */
streamAddTrimArgs parsed_args;
if (streamParseAddOrTrimArgsOrReply(c, &parsed_args, 1) < 0)
return; /* streamParseAddOrTrimArgsOrReply already replied. */
/* If the key does not exist, we are ok returning zero, that is, the /* If the key does not exist, we are ok returning zero, that is, the
* number of elements removed from the stream. */ * number of elements removed from the stream. */
if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL
|| checkType(c,o,OBJ_STREAM)) return; || checkType(c,o,OBJ_STREAM)) return;
stream *s = o->ptr; stream *s = o->ptr;
/* Argument parsing. */
streamAddTrimArgs parsed_args;
if (streamParseAddOrTrimArgsOrReply(c, &parsed_args, 1) < 0)
return; /* streamParseAddOrTrimArgsOrReply already replied. */
/* Perform the trimming. */ /* Perform the trimming. */
int64_t deleted = streamTrim(s, &parsed_args); int64_t deleted = streamTrim(s, &parsed_args);
if (deleted) { if (deleted) {
@ -3570,7 +3570,7 @@ int streamValidateListpackIntegrity(unsigned char *lp, size_t size, int deep) {
p = next; if (!lpValidateNext(lp, &next, size)) return 0; p = next; if (!lpValidateNext(lp, &next, size)) return 0;
/* deleted */ /* deleted */
lpGetIntegerIfValid(p, &valid_record); int64_t deleted_count = lpGetIntegerIfValid(p, &valid_record);
if (!valid_record) return 0; if (!valid_record) return 0;
p = next; if (!lpValidateNext(lp, &next, size)) return 0; p = next; if (!lpValidateNext(lp, &next, size)) return 0;
@ -3589,6 +3589,7 @@ int streamValidateListpackIntegrity(unsigned char *lp, size_t size, int deep) {
if (!valid_record || zero != 0) return 0; if (!valid_record || zero != 0) return 0;
p = next; if (!lpValidateNext(lp, &next, size)) return 0; p = next; if (!lpValidateNext(lp, &next, size)) return 0;
entry_count += deleted_count;
while (entry_count--) { while (entry_count--) {
if (!p) return 0; if (!p) return 0;
int64_t fields = master_fields, extra_fields = 3; int64_t fields = master_fields, extra_fields = 3;

View File

@ -32,6 +32,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <unistd.h> #include <unistd.h>
#include <assert.h>
/* This function provide us access to the original libc free(). This is useful /* This function provide us access to the original libc free(). This is useful
* for instance to free results obtained by backtrace_symbols(). We need * for instance to free results obtained by backtrace_symbols(). We need
@ -49,19 +50,20 @@ void zlibc_free(void *ptr) {
#ifdef HAVE_MALLOC_SIZE #ifdef HAVE_MALLOC_SIZE
#define PREFIX_SIZE (0) #define PREFIX_SIZE (0)
#define ASSERT_NO_SIZE_OVERFLOW(sz)
#else #else
#if defined(__sun) || defined(__sparc) || defined(__sparc__) #if defined(__sun) || defined(__sparc) || defined(__sparc__)
#define PREFIX_SIZE (sizeof(long long)) #define PREFIX_SIZE (sizeof(long long))
#else #else
#define PREFIX_SIZE (sizeof(size_t)) #define PREFIX_SIZE (sizeof(size_t))
#endif #endif
#define ASSERT_NO_SIZE_OVERFLOW(sz) assert((sz) + PREFIX_SIZE > (sz))
#endif #endif
#if PREFIX_SIZE > 0 /* When using the libc allocator, use a minimum allocation size to match the
#define ASSERT_NO_SIZE_OVERFLOW(sz) assert((sz) + PREFIX_SIZE > (sz)) * jemalloc behavior that doesn't return NULL in this case.
#else */
#define ASSERT_NO_SIZE_OVERFLOW(sz) #define MALLOC_MIN_SIZE(x) ((x) > 0 ? (x) : sizeof(long))
#endif
/* Explicitly override malloc/free etc when using tcmalloc. */ /* Explicitly override malloc/free etc when using tcmalloc. */
#if defined(USE_TCMALLOC) #if defined(USE_TCMALLOC)
@ -96,7 +98,7 @@ static void (*zmalloc_oom_handler)(size_t) = zmalloc_default_oom;
* '*usable' is set to the usable size if non NULL. */ * '*usable' is set to the usable size if non NULL. */
void *ztrymalloc_usable(size_t size, size_t *usable) { void *ztrymalloc_usable(size_t size, size_t *usable) {
ASSERT_NO_SIZE_OVERFLOW(size); ASSERT_NO_SIZE_OVERFLOW(size);
void *ptr = malloc(size+PREFIX_SIZE); void *ptr = malloc(MALLOC_MIN_SIZE(size)+PREFIX_SIZE);
if (!ptr) return NULL; if (!ptr) return NULL;
#ifdef HAVE_MALLOC_SIZE #ifdef HAVE_MALLOC_SIZE
@ -156,7 +158,7 @@ void zfree_no_tcache(void *ptr) {
* '*usable' is set to the usable size if non NULL. */ * '*usable' is set to the usable size if non NULL. */
void *ztrycalloc_usable(size_t size, size_t *usable) { void *ztrycalloc_usable(size_t size, size_t *usable) {
ASSERT_NO_SIZE_OVERFLOW(size); ASSERT_NO_SIZE_OVERFLOW(size);
void *ptr = calloc(1, size+PREFIX_SIZE); void *ptr = calloc(1, MALLOC_MIN_SIZE(size)+PREFIX_SIZE);
if (ptr == NULL) return NULL; if (ptr == NULL) return NULL;
#ifdef HAVE_MALLOC_SIZE #ifdef HAVE_MALLOC_SIZE
@ -678,6 +680,7 @@ int zmalloc_test(int argc, char **argv) {
UNUSED(argc); UNUSED(argc);
UNUSED(argv); UNUSED(argv);
printf("Malloc prefix size: %d\n", (int) PREFIX_SIZE);
printf("Initial used memory: %zu\n", zmalloc_used_memory()); printf("Initial used memory: %zu\n", zmalloc_used_memory());
ptr = zmalloc(123); ptr = zmalloc(123);
printf("Allocated 123 bytes; used: %zu\n", zmalloc_used_memory()); printf("Allocated 123 bytes; used: %zu\n", zmalloc_used_memory());

View File

@ -61,9 +61,19 @@
#define zmalloc_size(p) malloc_size(p) #define zmalloc_size(p) malloc_size(p)
#endif #endif
/* On native libc implementations, we should still do our best to provide a
* HAVE_MALLOC_SIZE capability. This can be set explicitly as well:
*
* NO_MALLOC_USABLE_SIZE disables it on all platforms, even if they are
* known to support it.
* USE_MALLOC_USABLE_SIZE forces use of malloc_usable_size() regardless
* of platform.
*/
#ifndef ZMALLOC_LIB #ifndef ZMALLOC_LIB
#define ZMALLOC_LIB "libc" #define ZMALLOC_LIB "libc"
#ifdef __GLIBC__ #if !defined(NO_MALLOC_USABLE_SIZE) && \
(defined(__GLIBC__) || defined(__FreeBSD__) || \
defined(USE_MALLOC_USABLE_SIZE))
#include <malloc.h> #include <malloc.h>
#define HAVE_MALLOC_SIZE 1 #define HAVE_MALLOC_SIZE 1
#define zmalloc_size(p) malloc_usable_size(p) #define zmalloc_size(p) malloc_usable_size(p)

View File

@ -186,6 +186,8 @@ proc is_alive pid {
proc stop_instance pid { proc stop_instance pid {
catch {exec kill $pid} catch {exec kill $pid}
# Node might have been stopped in the test
catch {exec kill -SIGCONT $pid}
if {$::valgrind} { if {$::valgrind} {
set max_wait 60000 set max_wait 60000
} else { } else {

View File

@ -32,6 +32,7 @@ proc generate_types {} {
# add some metadata to the stream # add some metadata to the stream
r xgroup create stream mygroup 0 r xgroup create stream mygroup 0
set records [r xreadgroup GROUP mygroup Alice COUNT 2 STREAMS stream >] set records [r xreadgroup GROUP mygroup Alice COUNT 2 STREAMS stream >]
r xdel stream [lindex [lindex [lindex [lindex $records 0] 1] 1] 0]
r xack stream mygroup [lindex [lindex [lindex [lindex $records 0] 1] 0] 0] r xack stream mygroup [lindex [lindex [lindex [lindex $records 0] 1] 0] 0]
# create other non-collection types # create other non-collection types

View File

@ -1,6 +1,18 @@
set system_name [string tolower [exec uname -s]] set system_name [string tolower [exec uname -s]]
set system_supported 0
if {$system_name eq {linux} || $system_name eq {darwin}} { # We only support darwin or Linux with glibc
if {$system_name eq {darwin}} {
set system_supported 1
} elseif {$system_name eq {linux}} {
# Avoid the test on libmusl, which does not support backtrace
set ldd [exec ldd src/redis-server]
if {![string match {*libc.musl*} $ldd]} {
set system_supported 1
}
}
if {$system_supported} {
set server_path [tmpdir server.log] set server_path [tmpdir server.log]
start_server [list overrides [list dir $server_path]] { start_server [list overrides [list dir $server_path]] {
test "Server is able to generate a stack trace on selected systems" { test "Server is able to generate a stack trace on selected systems" {

View File

@ -52,6 +52,7 @@ start_server [list overrides [list "dir" $server_path] keep_persistence true] {
} }
r xgroup create stream mygroup 0 r xgroup create stream mygroup 0
set records [r xreadgroup GROUP mygroup Alice COUNT 2 STREAMS stream >] set records [r xreadgroup GROUP mygroup Alice COUNT 2 STREAMS stream >]
r xdel stream [lindex [lindex [lindex [lindex $records 0] 1] 1] 0]
r xack stream mygroup [lindex [lindex [lindex [lindex $records 0] 1] 0] 0] r xack stream mygroup [lindex [lindex [lindex [lindex $records 0] 1] 0] 0]
set digest [r debug digest] set digest [r debug digest]
r config set sanitize-dump-payload no r config set sanitize-dump-payload no

View File

@ -72,6 +72,8 @@ proc kill_server config {
# kill server and wait for the process to be totally exited # kill server and wait for the process to be totally exited
send_data_packet $::test_server_fd server-killing $pid send_data_packet $::test_server_fd server-killing $pid
catch {exec kill $pid} catch {exec kill $pid}
# Node might have been stopped in the test
catch {exec kill -SIGCONT $pid}
if {$::valgrind} { if {$::valgrind} {
set max_wait 60000 set max_wait 60000
} else { } else {

View File

@ -75,6 +75,7 @@ set ::all_tests {
unit/tracking unit/tracking
unit/oom-score-adj unit/oom-score-adj
unit/shutdown unit/shutdown
unit/networking
} }
# Index to the next test to run in the ::all_tests list. # Index to the next test to run in the ::all_tests list.
set ::next_test 0 set ::next_test 0

View File

@ -62,6 +62,19 @@ start_server {tags {"info"}} {
assert_equal [s total_error_replies] 2 assert_equal [s total_error_replies] 2
} }
test {errorstats: failed call NOSCRIPT error} {
r config resetstat
assert_equal [s total_error_replies] 0
assert_match {} [errorstat NOSCRIPT]
catch {r evalsha NotValidShaSUM 0} e
assert_match {NOSCRIPT*} $e
assert_match {*count=1*} [errorstat NOSCRIPT]
assert_match {*calls=1,*,rejected_calls=0,failed_calls=1} [cmdstat evalsha]
assert_equal [s total_error_replies] 1
r config resetstat
assert_match {} [errorstat NOSCRIPT]
}
test {errorstats: failed call NOGROUP error} { test {errorstats: failed call NOGROUP error} {
r config resetstat r config resetstat
assert_match {} [errorstat NOGROUP] assert_match {} [errorstat NOGROUP]

View File

@ -100,13 +100,10 @@ start_server {tags {"introspection"}} {
supervised supervised
syslog-facility syslog-facility
databases databases
port
tls-port
io-threads io-threads
logfile logfile
unixsocketperm unixsocketperm
slaveof slaveof
bind
requirepass requirepass
server_cpulist server_cpulist
bio_cpulist bio_cpulist
@ -131,6 +128,7 @@ start_server {tags {"introspection"}} {
tls-protocols tls-protocols
tls-ciphers tls-ciphers
tls-ciphersuites tls-ciphersuites
tls-port
} }
} }
@ -173,7 +171,7 @@ start_server {tags {"introspection"}} {
# Rewrite entire configuration, restart and confirm the # Rewrite entire configuration, restart and confirm the
# server is able to parse it and start. # server is able to parse it and start.
assert_equal [r debug config-rewrite-force-all] "OK" assert_equal [r debug config-rewrite-force-all] "OK"
restart_server 0 false false restart_server 0 true false
assert_equal [r ping] "PONG" assert_equal [r ping] "PONG"
# Verify no changes were introduced # Verify no changes were introduced

View File

@ -16,6 +16,11 @@ start_server {tags {"modules"}} {
assert { [string match "*cmdstat_module*" $info] } assert { [string match "*cmdstat_module*" $info] }
} }
test {test RM_Call recursive} {
set info [r test.call_generic test.call_generic info commandstats]
assert { [string match "*cmdstat_module*" $info] }
}
test {test redis version} { test {test redis version} {
set version [s redis_version] set version [s redis_version]
assert_equal $version [r test.redisversion] assert_equal $version [r test.redisversion]
@ -106,4 +111,8 @@ start_server {tags {"modules"}} {
r test.log_tsctx "info" "Test message" r test.log_tsctx "info" "Test message"
verify_log_message 0 "*<misc> Test message*" 0 verify_log_message 0 "*<misc> Test message*" 0
} }
test {test RM_Call CLIENT INFO} {
assert_match "*fd=-1*" [r test.call_generic client info]
}
} }

36
tests/unit/networking.tcl Normal file
View File

@ -0,0 +1,36 @@
test {CONFIG SET port number} {
start_server {} {
if {$::tls} { set port_cfg tls-port} else { set port_cfg port }
# available port
set avail_port [find_available_port $::baseport $::portcount]
set rd [redis [srv 0 host] [srv 0 port] 0 $::tls]
$rd CONFIG SET $port_cfg $avail_port
$rd close
set rd [redis [srv 0 host] $avail_port 0 $::tls]
$rd PING
# already inuse port
catch {$rd CONFIG SET $port_cfg $::test_server_port} e
assert_match {*Unable to listen on this port*} $e
$rd close
# make sure server still listening on the previous port
set rd [redis [srv 0 host] $avail_port 0 $::tls]
$rd PING
$rd close
}
}
test {CONFIG SET bind address} {
start_server {} {
# non-valid address
catch {r CONFIG SET bind "some.wrong.bind.address"} e
assert_match {*Failed to bind to specified addresses*} $e
# make sure server still bound to the previous address
set rd [redis [srv 0 host] [srv 0 port] 0 $::tls]
$rd PING
$rd close
}
}

View File

@ -114,5 +114,30 @@ start_server {tags {"tls"}} {
} }
} }
} }
test {TLS: switch between tcp and tls ports} {
set srv_port [srv 0 port]
# TLS
set rd [redis [srv 0 host] $srv_port 0 1]
$rd PING
# TCP
$rd CONFIG SET tls-port 0
$rd CONFIG SET port $srv_port
$rd close
set rd [redis [srv 0 host] $srv_port 0 0]
$rd PING
# TLS
$rd CONFIG SET port 0
$rd CONFIG SET tls-port $srv_port
$rd close
set rd [redis [srv 0 host] $srv_port 0 1]
$rd PING
$rd close
}
} }
} }