Commit f5ca1f9e authored by Oran Agra's avatar Oran Agra
Browse files

Merge unstable into 6.2

parents 92bde124 61d3fdb4
...@@ -147,7 +147,7 @@ void tlsInit(void) { ...@@ -147,7 +147,7 @@ void tlsInit(void) {
#if OPENSSL_VERSION_NUMBER < 0x10100000L #if OPENSSL_VERSION_NUMBER < 0x10100000L
OPENSSL_config(NULL); OPENSSL_config(NULL);
#else #else
OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL); OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG|OPENSSL_INIT_ATFORK, NULL);
#endif #endif
ERR_load_crypto_strings(); ERR_load_crypto_strings();
SSL_load_error_strings(); SSL_load_error_strings();
...@@ -164,11 +164,43 @@ void tlsInit(void) { ...@@ -164,11 +164,43 @@ void tlsInit(void) {
pending_list = listCreate(); pending_list = listCreate();
} }
void tlsCleanup(void) {
if (redis_tls_ctx) {
SSL_CTX_free(redis_tls_ctx);
redis_tls_ctx = NULL;
}
if (redis_tls_client_ctx) {
SSL_CTX_free(redis_tls_client_ctx);
redis_tls_client_ctx = NULL;
}
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
OPENSSL_cleanup();
#endif
}
/* Callback for passing a keyfile password stored as an sds to OpenSSL */
static int tlsPasswordCallback(char *buf, int size, int rwflag, void *u) {
UNUSED(rwflag);
const char *pass = u;
size_t pass_len;
if (!pass) return -1;
pass_len = strlen(pass);
if (pass_len > (size_t) size) return -1;
memcpy(buf, pass, pass_len);
return (int) pass_len;
}
/* Create a *base* SSL_CTX using the SSL configuration provided. The base context /* Create a *base* SSL_CTX using the SSL configuration provided. The base context
* includes everything that's common for both client-side and server-side connections. * includes everything that's common for both client-side and server-side connections.
*/ */
static SSL_CTX *createSSLContext(redisTLSContextConfig *ctx_config, int protocols, static SSL_CTX *createSSLContext(redisTLSContextConfig *ctx_config, int protocols, int client) {
const char *cert_file, const char *key_file) { const char *cert_file = client ? ctx_config->client_cert_file : ctx_config->cert_file;
const char *key_file = client ? ctx_config->client_key_file : ctx_config->key_file;
const char *key_file_pass = client ? ctx_config->client_key_file_pass : ctx_config->key_file_pass;
char errbuf[256]; char errbuf[256];
SSL_CTX *ctx = NULL; SSL_CTX *ctx = NULL;
...@@ -200,6 +232,9 @@ static SSL_CTX *createSSLContext(redisTLSContextConfig *ctx_config, int protocol ...@@ -200,6 +232,9 @@ static SSL_CTX *createSSLContext(redisTLSContextConfig *ctx_config, int protocol
SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE|SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE|SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
SSL_CTX_set_default_passwd_cb(ctx, tlsPasswordCallback);
SSL_CTX_set_default_passwd_cb_userdata(ctx, (void *) key_file_pass);
if (SSL_CTX_use_certificate_chain_file(ctx, cert_file) <= 0) { if (SSL_CTX_use_certificate_chain_file(ctx, cert_file) <= 0) {
ERR_error_string_n(ERR_get_error(), errbuf, sizeof(errbuf)); ERR_error_string_n(ERR_get_error(), errbuf, sizeof(errbuf));
serverLog(LL_WARNING, "Failed to load certificate: %s: %s", cert_file, errbuf); serverLog(LL_WARNING, "Failed to load certificate: %s: %s", cert_file, errbuf);
...@@ -266,7 +301,7 @@ int tlsConfigure(redisTLSContextConfig *ctx_config) { ...@@ -266,7 +301,7 @@ int tlsConfigure(redisTLSContextConfig *ctx_config) {
if (protocols == -1) goto error; if (protocols == -1) goto error;
/* Create server side/generla context */ /* Create server side/generla context */
ctx = createSSLContext(ctx_config, protocols, ctx_config->cert_file, ctx_config->key_file); ctx = createSSLContext(ctx_config, protocols, 0);
if (!ctx) goto error; if (!ctx) goto error;
if (ctx_config->session_caching) { if (ctx_config->session_caching) {
...@@ -317,7 +352,7 @@ int tlsConfigure(redisTLSContextConfig *ctx_config) { ...@@ -317,7 +352,7 @@ int tlsConfigure(redisTLSContextConfig *ctx_config) {
/* If a client-side certificate is configured, create an explicit client context */ /* If a client-side certificate is configured, create an explicit client context */
if (ctx_config->client_cert_file && ctx_config->client_key_file) { if (ctx_config->client_cert_file && ctx_config->client_key_file) {
client_ctx = createSSLContext(ctx_config, protocols, ctx_config->client_cert_file, ctx_config->client_key_file); client_ctx = createSSLContext(ctx_config, protocols, 1);
if (!client_ctx) goto error; if (!client_ctx) goto error;
} }
...@@ -948,6 +983,9 @@ sds connTLSGetPeerCert(connection *conn_) { ...@@ -948,6 +983,9 @@ sds connTLSGetPeerCert(connection *conn_) {
void tlsInit(void) { void tlsInit(void) {
} }
void tlsCleanup(void) {
}
int tlsConfigure(redisTLSContextConfig *ctx_config) { int tlsConfigure(redisTLSContextConfig *ctx_config) {
UNUSED(ctx_config); UNUSED(ctx_config);
return C_OK; return C_OK;
......
...@@ -946,9 +946,10 @@ static void test_ll2string(void) { ...@@ -946,9 +946,10 @@ static void test_ll2string(void) {
} }
#define UNUSED(x) (void)(x) #define UNUSED(x) (void)(x)
int utilTest(int argc, char **argv) { int utilTest(int argc, char **argv, int accurate) {
UNUSED(argc); UNUSED(argc);
UNUSED(argv); UNUSED(argv);
UNUSED(accurate);
test_string2ll(); test_string2ll();
test_string2l(); test_string2l();
......
...@@ -66,7 +66,7 @@ long getTimeZone(void); ...@@ -66,7 +66,7 @@ long getTimeZone(void);
int pathIsBaseName(char *path); int pathIsBaseName(char *path);
#ifdef REDIS_TEST #ifdef REDIS_TEST
int utilTest(int argc, char **argv); int utilTest(int argc, char **argv, int accurate);
#endif #endif
#endif #endif
...@@ -1472,7 +1472,7 @@ void ziplistRepr(unsigned char *zl) { ...@@ -1472,7 +1472,7 @@ void ziplistRepr(unsigned char *zl) {
printf("{end}\n\n"); printf("{end}\n\n");
} }
/* Validate the integrity of the data stracture. /* Validate the integrity of the data structure.
* when `deep` is 0, only the integrity of the header is validated. * when `deep` is 0, only the integrity of the header is validated.
* when `deep` is 1, we scan all the entries one by one. */ * when `deep` is 1, we scan all the entries one by one. */
int ziplistValidateIntegrity(unsigned char *zl, size_t size, int deep, int ziplistValidateIntegrity(unsigned char *zl, size_t size, int deep,
...@@ -1823,15 +1823,17 @@ static size_t strEntryBytesLarge(size_t slen) { ...@@ -1823,15 +1823,17 @@ static size_t strEntryBytesLarge(size_t slen) {
return slen + zipStorePrevEntryLength(NULL, ZIP_BIG_PREVLEN) + zipStoreEntryEncoding(NULL, 0, slen); return slen + zipStorePrevEntryLength(NULL, ZIP_BIG_PREVLEN) + zipStoreEntryEncoding(NULL, 0, slen);
} }
int ziplistTest(int argc, char **argv) { /* ./redis-server test ziplist <randomseed> --accurate */
int ziplistTest(int argc, char **argv, int accurate) {
unsigned char *zl, *p; unsigned char *zl, *p;
unsigned char *entry; unsigned char *entry;
unsigned int elen; unsigned int elen;
long long value; long long value;
int iteration;
/* If an argument is given, use it as the random seed. */ /* If an argument is given, use it as the random seed. */
if (argc == 2) if (argc >= 4)
srand(atoi(argv[1])); srand(atoi(argv[3]));
zl = createIntList(); zl = createIntList();
ziplistRepr(zl); ziplistRepr(zl);
...@@ -2339,7 +2341,8 @@ int ziplistTest(int argc, char **argv) { ...@@ -2339,7 +2341,8 @@ int ziplistTest(int argc, char **argv) {
unsigned int slen; unsigned int slen;
long long sval; long long sval;
for (i = 0; i < 20000; i++) { iteration = accurate ? 20000 : 20;
for (i = 0; i < iteration; i++) {
zl = ziplistNew(); zl = ziplistNew();
ref = listCreate(); ref = listCreate();
listSetFreeMethod(ref,(void (*)(void*))sdsfree); listSetFreeMethod(ref,(void (*)(void*))sdsfree);
...@@ -2405,15 +2408,17 @@ int ziplistTest(int argc, char **argv) { ...@@ -2405,15 +2408,17 @@ int ziplistTest(int argc, char **argv) {
printf("Stress with variable ziplist size:\n"); printf("Stress with variable ziplist size:\n");
{ {
unsigned long long start = usec(); unsigned long long start = usec();
stress(ZIPLIST_HEAD,100000,16384,256); int maxsize = accurate ? 16384 : 16;
stress(ZIPLIST_TAIL,100000,16384,256); stress(ZIPLIST_HEAD,100000,maxsize,256);
stress(ZIPLIST_TAIL,100000,maxsize,256);
printf("Done. usec=%lld\n\n", usec()-start); printf("Done. usec=%lld\n\n", usec()-start);
} }
/* Benchmarks */ /* Benchmarks */
{ {
zl = ziplistNew(); zl = ziplistNew();
for (int i=0; i<100000; i++) { iteration = accurate ? 100000 : 100;
for (int i=0; i<iteration; i++) {
char buf[4096] = "asdf"; char buf[4096] = "asdf";
zl = ziplistPush(zl, (unsigned char*)buf, 4, ZIPLIST_TAIL); zl = ziplistPush(zl, (unsigned char*)buf, 4, ZIPLIST_TAIL);
zl = ziplistPush(zl, (unsigned char*)buf, 40, ZIPLIST_TAIL); zl = ziplistPush(zl, (unsigned char*)buf, 40, ZIPLIST_TAIL);
...@@ -2462,7 +2467,8 @@ int ziplistTest(int argc, char **argv) { ...@@ -2462,7 +2467,8 @@ int ziplistTest(int argc, char **argv) {
{ {
char data[ZIP_BIG_PREVLEN]; char data[ZIP_BIG_PREVLEN];
zl = ziplistNew(); zl = ziplistNew();
for (int i = 0; i < 100000; i++) { iteration = accurate ? 100000 : 100;
for (int i = 0; i < iteration; i++) {
zl = ziplistPush(zl, (unsigned char*)data, ZIP_BIG_PREVLEN-4, ZIPLIST_TAIL); zl = ziplistPush(zl, (unsigned char*)data, ZIP_BIG_PREVLEN-4, ZIPLIST_TAIL);
} }
unsigned long long start = usec(); unsigned long long start = usec();
......
...@@ -67,7 +67,7 @@ void ziplistRandomPairs(unsigned char *zl, unsigned int count, ziplistEntry *key ...@@ -67,7 +67,7 @@ void ziplistRandomPairs(unsigned char *zl, unsigned int count, ziplistEntry *key
unsigned int ziplistRandomPairsUnique(unsigned char *zl, unsigned int count, ziplistEntry *keys, ziplistEntry *vals); unsigned int ziplistRandomPairsUnique(unsigned char *zl, unsigned int count, ziplistEntry *keys, ziplistEntry *vals);
#ifdef REDIS_TEST #ifdef REDIS_TEST
int ziplistTest(int argc, char *argv[]); int ziplistTest(int argc, char *argv[], int accurate);
#endif #endif
#endif /* _ZIPLIST_H */ #endif /* _ZIPLIST_H */
...@@ -374,7 +374,7 @@ size_t zipmapBlobLen(unsigned char *zm) { ...@@ -374,7 +374,7 @@ size_t zipmapBlobLen(unsigned char *zm) {
return totlen; return totlen;
} }
/* Validate the integrity of the data stracture. /* Validate the integrity of the data structure.
* when `deep` is 0, only the integrity of the header is validated. * when `deep` is 0, only the integrity of the header is validated.
* when `deep` is 1, we scan all the entries one by one. */ * when `deep` is 1, we scan all the entries one by one. */
int zipmapValidateIntegrity(unsigned char *zm, size_t size, int deep) { int zipmapValidateIntegrity(unsigned char *zm, size_t size, int deep) {
...@@ -473,11 +473,12 @@ static void zipmapRepr(unsigned char *p) { ...@@ -473,11 +473,12 @@ static void zipmapRepr(unsigned char *p) {
} }
#define UNUSED(x) (void)(x) #define UNUSED(x) (void)(x)
int zipmapTest(int argc, char *argv[]) { int zipmapTest(int argc, char *argv[], int accurate) {
unsigned char *zm; unsigned char *zm;
UNUSED(argc); UNUSED(argc);
UNUSED(argv); UNUSED(argv);
UNUSED(accurate);
zm = zipmapNew(); zm = zipmapNew();
...@@ -532,6 +533,7 @@ int zipmapTest(int argc, char *argv[]) { ...@@ -532,6 +533,7 @@ int zipmapTest(int argc, char *argv[]) {
printf(" %d:%.*s => %d:%.*s\n", klen, klen, key, vlen, vlen, value); printf(" %d:%.*s => %d:%.*s\n", klen, klen, key, vlen, vlen, value);
} }
} }
zfree(zm);
return 0; return 0;
} }
#endif #endif
...@@ -48,7 +48,7 @@ void zipmapRepr(unsigned char *p); ...@@ -48,7 +48,7 @@ void zipmapRepr(unsigned char *p);
int zipmapValidateIntegrity(unsigned char *zm, size_t size, int deep); int zipmapValidateIntegrity(unsigned char *zm, size_t size, int deep);
#ifdef REDIS_TEST #ifdef REDIS_TEST
int zipmapTest(int argc, char *argv[]); int zipmapTest(int argc, char *argv[], int accurate);
#endif #endif
#endif #endif
...@@ -414,9 +414,9 @@ size_t zmalloc_get_rss(void) { ...@@ -414,9 +414,9 @@ size_t zmalloc_get_rss(void) {
if (sysctl(mib, 4, &info, &infolen, NULL, 0) == 0) if (sysctl(mib, 4, &info, &infolen, NULL, 0) == 0)
#if defined(__FreeBSD__) #if defined(__FreeBSD__)
return (size_t)info.ki_rssize; return (size_t)info.ki_rssize * getpagesize();
#else #else
return (size_t)info.kp_vm_rssize; return (size_t)info.kp_vm_rssize * getpagesize();
#endif #endif
return 0L; return 0L;
...@@ -436,7 +436,7 @@ size_t zmalloc_get_rss(void) { ...@@ -436,7 +436,7 @@ size_t zmalloc_get_rss(void) {
mib[4] = sizeof(info); mib[4] = sizeof(info);
mib[5] = 1; mib[5] = 1;
if (sysctl(mib, 4, &info, &infolen, NULL, 0) == 0) if (sysctl(mib, 4, &info, &infolen, NULL, 0) == 0)
return (size_t)info.p_vm_rssize; return (size_t)info.p_vm_rssize * getpagesize();
return 0L; return 0L;
} }
...@@ -613,6 +613,11 @@ size_t zmalloc_get_smap_bytes_by_field(char *field, long pid) { ...@@ -613,6 +613,11 @@ size_t zmalloc_get_smap_bytes_by_field(char *field, long pid) {
} }
#endif #endif
/* Return the total number bytes in pages marked as Private Dirty.
*
* Note: depending on the platform and memory footprint of the process, this
* call can be slow, exceeding 1000ms!
*/
size_t zmalloc_get_private_dirty(long pid) { size_t zmalloc_get_private_dirty(long pid) {
return zmalloc_get_smap_bytes_by_field("Private_Dirty:",pid); return zmalloc_get_smap_bytes_by_field("Private_Dirty:",pid);
} }
...@@ -675,11 +680,12 @@ size_t zmalloc_get_memory_size(void) { ...@@ -675,11 +680,12 @@ size_t zmalloc_get_memory_size(void) {
#ifdef REDIS_TEST #ifdef REDIS_TEST
#define UNUSED(x) ((void)(x)) #define UNUSED(x) ((void)(x))
int zmalloc_test(int argc, char **argv) { int zmalloc_test(int argc, char **argv, int accurate) {
void *ptr; void *ptr;
UNUSED(argc); UNUSED(argc);
UNUSED(argv); UNUSED(argv);
UNUSED(accurate);
printf("Malloc prefix size: %d\n", (int) PREFIX_SIZE); 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);
......
...@@ -71,12 +71,21 @@ ...@@ -71,12 +71,21 @@
*/ */
#ifndef ZMALLOC_LIB #ifndef ZMALLOC_LIB
#define ZMALLOC_LIB "libc" #define ZMALLOC_LIB "libc"
#if !defined(NO_MALLOC_USABLE_SIZE) && \ #if !defined(NO_MALLOC_USABLE_SIZE) && \
(defined(__GLIBC__) || defined(__FreeBSD__) || \ (defined(__GLIBC__) || defined(__FreeBSD__) || \
defined(USE_MALLOC_USABLE_SIZE)) defined(USE_MALLOC_USABLE_SIZE))
/* Includes for malloc_usable_size() */
#ifdef __FreeBSD__
#include <malloc_np.h>
#else
#include <malloc.h> #include <malloc.h>
#endif
#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)
#endif #endif
#endif #endif
...@@ -126,7 +135,7 @@ size_t zmalloc_usable_size(void *ptr); ...@@ -126,7 +135,7 @@ size_t zmalloc_usable_size(void *ptr);
#endif #endif
#ifdef REDIS_TEST #ifdef REDIS_TEST
int zmalloc_test(int argc, char **argv); int zmalloc_test(int argc, char **argv, int accurate);
#endif #endif
#endif /* __ZMALLOC_H */ #endif /* __ZMALLOC_H */
user alice on nopass ~* +@all
user bob on nopass ~* &* +@all
\ No newline at end of file
user alice on allcommands allkeys >alice user alice on allcommands allkeys >alice
user bob on -@all +@set +acl ~set* >bob user bob on -@all +@set +acl ~set* >bob
user default on nopass ~* +@all
...@@ -4,6 +4,10 @@ ...@@ -4,6 +4,10 @@
# This software is released under the BSD License. See the COPYING file for # This software is released under the BSD License. See the COPYING file for
# more information. # more information.
# Track cluster configuration as created by create_cluster below
set ::cluster_master_nodes 0
set ::cluster_replica_nodes 0
# Returns a parsed CLUSTER NODES output as a list of dictionaries. # Returns a parsed CLUSTER NODES output as a list of dictionaries.
proc get_cluster_nodes id { proc get_cluster_nodes id {
set lines [split [R $id cluster nodes] "\r\n"] set lines [split [R $id cluster nodes] "\r\n"]
...@@ -120,6 +124,9 @@ proc create_cluster {masters slaves} { ...@@ -120,6 +124,9 @@ proc create_cluster {masters slaves} {
cluster_allocate_slaves $masters $slaves cluster_allocate_slaves $masters $slaves
} }
assert_cluster_state ok assert_cluster_state ok
set ::cluster_master_nodes $masters
set ::cluster_replica_nodes $slaves
} }
# Set the cluster node-timeout to all the reachalbe nodes. # Set the cluster node-timeout to all the reachalbe nodes.
...@@ -143,3 +150,28 @@ proc cluster_write_test {id} { ...@@ -143,3 +150,28 @@ proc cluster_write_test {id} {
} }
$cluster close $cluster close
} }
# Check if cluster configuration is consistent.
proc cluster_config_consistent {} {
for {set j 0} {$j < $::cluster_master_nodes + $::cluster_replica_nodes} {incr j} {
if {$j == 0} {
set base_cfg [R $j cluster slots]
} else {
set cfg [R $j cluster slots]
if {$cfg != $base_cfg} {
return 0
}
}
}
return 1
}
# Wait for cluster configuration to propagate and be consistent across nodes.
proc wait_for_cluster_propagation {} {
wait_for_condition 50 100 {
[cluster_config_consistent] eq 1
} else {
fail "cluster config did not reach a consistent state"
}
}
...@@ -54,7 +54,17 @@ proc process_is_running {pid} { ...@@ -54,7 +54,17 @@ proc process_is_running {pid} {
set numkeys 50000 set numkeys 50000
set numops 200000 set numops 200000
set cluster [redis_cluster 127.0.0.1:[get_instance_attrib redis 0 port]] set start_node_port [get_instance_attrib redis 0 port]
set cluster [redis_cluster 127.0.0.1:$start_node_port]
if {$::tls} {
# setup a non-TLS cluster client to the TLS cluster
set plaintext_port [get_instance_attrib redis 0 plaintext-port]
set cluster_plaintext [redis_cluster 127.0.0.1:$plaintext_port 0]
puts "Testing TLS cluster on start node 127.0.0.1:$start_node_port, plaintext port $plaintext_port"
} else {
set cluster_plaintext $cluster
puts "Testing using non-TLS cluster"
}
catch {unset content} catch {unset content}
array set content {} array set content {}
set tribpid {} set tribpid {}
...@@ -94,8 +104,11 @@ test "Cluster consistency during live resharding" { ...@@ -94,8 +104,11 @@ test "Cluster consistency during live resharding" {
# This way we are able to stress Lua -> Redis command invocation # This way we are able to stress Lua -> Redis command invocation
# as well, that has tests to prevent Lua to write into wrong # as well, that has tests to prevent Lua to write into wrong
# hash slots. # hash slots.
if {$listid % 2} { # We also use both TLS and plaintext connections.
if {$listid % 3 == 0} {
$cluster rpush $key $ele $cluster rpush $key $ele
} elseif {$listid % 3 == 1} {
$cluster_plaintext rpush $key $ele
} else { } else {
$cluster eval {redis.call("rpush",KEYS[1],ARGV[1])} 1 $key $ele $cluster eval {redis.call("rpush",KEYS[1],ARGV[1])} 1 $key $ele
} }
......
...@@ -29,6 +29,12 @@ test "Each master should have at least two replicas attached" { ...@@ -29,6 +29,12 @@ test "Each master should have at least two replicas attached" {
} }
} }
test "Set allow-replica-migration yes" {
foreach_redis_id id {
R $id CONFIG SET cluster-allow-replica-migration yes
}
}
set master0_id [dict get [get_myself 0] id] set master0_id [dict get [get_myself 0] id]
test "Resharding all the master #0 slots away from it" { test "Resharding all the master #0 slots away from it" {
set output [exec \ set output [exec \
......
# Replica migration test #2.
#
# Check that if 'cluster-allow-replica-migration' is set to 'no', slaves do not
# migrate when master becomes empty.
source "../tests/includes/init-tests.tcl"
# Create a cluster with 5 master and 15 slaves, to make sure there are no
# empty masters and make rebalancing simpler to handle during the test.
test "Create a 5 nodes cluster" {
create_cluster 5 15
}
test "Cluster is up" {
assert_cluster_state ok
}
test "Each master should have at least two replicas attached" {
foreach_redis_id id {
if {$id < 5} {
wait_for_condition 1000 50 {
[llength [lindex [R 0 role] 2]] >= 2
} else {
fail "Master #$id does not have 2 slaves as expected"
}
}
}
}
test "Set allow-replica-migration no" {
foreach_redis_id id {
R $id CONFIG SET cluster-allow-replica-migration no
}
}
set master0_id [dict get [get_myself 0] id]
test "Resharding all the master #0 slots away from it" {
set output [exec \
../../../src/redis-cli --cluster rebalance \
127.0.0.1:[get_instance_attrib redis 0 port] \
{*}[rediscli_tls_config "../../../tests"] \
--cluster-weight ${master0_id}=0 >@ stdout ]
}
test "Wait cluster to be stable" {
wait_for_condition 1000 50 {
[catch {exec ../../../src/redis-cli --cluster \
check 127.0.0.1:[get_instance_attrib redis 0 port] \
{*}[rediscli_tls_config "../../../tests"] \
}] == 0
} else {
fail "Cluster doesn't stabilize"
}
}
test "Master #0 stil should have its replicas" {
assert { [llength [lindex [R 0 role] 2]] >= 2 }
}
test "Each master should have at least two replicas attached" {
foreach_redis_id id {
if {$id < 5} {
wait_for_condition 1000 50 {
[llength [lindex [R 0 role] 2]] >= 2
} else {
fail "Master #$id does not have 2 slaves as expected"
}
}
}
}
...@@ -48,3 +48,16 @@ test "client can handle keys with hash tag" { ...@@ -48,3 +48,16 @@ test "client can handle keys with hash tag" {
$cluster set foo{tag} bar $cluster set foo{tag} bar
$cluster close $cluster close
} }
if {$::tls} {
test {CLUSTER SLOTS from non-TLS client in TLS cluster} {
set slots_tls [R 0 cluster slots]
set host [get_instance_attrib redis 0 host]
set plaintext_port [get_instance_attrib redis 0 plaintext-port]
set client_plain [redis $host $plaintext_port 0 0]
set slots_plain [$client_plain cluster slots]
$client_plain close
# Compare the ports in the first row
assert_no_match [lindex $slots_tls 0 3 1] [lindex $slots_plain 0 3 1]
}
}
...@@ -36,7 +36,7 @@ test "Right to restore backups when fail to diskless load " { ...@@ -36,7 +36,7 @@ test "Right to restore backups when fail to diskless load " {
# Write a key that belongs to slot 0 # Write a key that belongs to slot 0
set slot0_key "06S" set slot0_key "06S"
$master set $slot0_key 1 $master set $slot0_key 1
after 100 wait_for_ofs_sync $master $replica
assert_equal {1} [$replica get $slot0_key] assert_equal {1} [$replica get $slot0_key]
assert_equal $slot0_key [$replica CLUSTER GETKEYSINSLOT 0 1] assert_equal $slot0_key [$replica CLUSTER GETKEYSINSLOT 0 1]
...@@ -73,6 +73,13 @@ test "Right to restore backups when fail to diskless load " { ...@@ -73,6 +73,13 @@ test "Right to restore backups when fail to diskless load " {
# Kill master, abort full sync # Kill master, abort full sync
kill_instance redis $master_id kill_instance redis $master_id
# Start full sync, wait till the replica detects the disconnection
wait_for_condition 500 10 {
[s $replica_id loading] eq 0
} else {
fail "Fail to full sync"
}
# Replica keys and keys to slots map still both are right # Replica keys and keys to slots map still both are right
assert_equal {1} [$replica get $slot0_key] assert_equal {1} [$replica get $slot0_key]
assert_equal $slot0_key [$replica CLUSTER GETKEYSINSLOT 0 1] assert_equal $slot0_key [$replica CLUSTER GETKEYSINSLOT 0 1]
......
...@@ -37,26 +37,35 @@ set master2 [Rn 1] ...@@ -37,26 +37,35 @@ set master2 [Rn 1]
test "Continuous slots distribution" { test "Continuous slots distribution" {
assert_match "* 0-8191*" [$master1 CLUSTER NODES] assert_match "* 0-8191*" [$master1 CLUSTER NODES]
assert_match "* 8192-16383*" [$master2 CLUSTER NODES] assert_match "* 8192-16383*" [$master2 CLUSTER NODES]
assert_match "*0 8191*" [$master1 CLUSTER SLOTS]
assert_match "*8192 16383*" [$master2 CLUSTER SLOTS]
$master1 CLUSTER DELSLOTS 4096 $master1 CLUSTER DELSLOTS 4096
assert_match "* 0-4095 4097-8191*" [$master1 CLUSTER NODES] assert_match "* 0-4095 4097-8191*" [$master1 CLUSTER NODES]
assert_match "*0 4095*4097 8191*" [$master1 CLUSTER SLOTS]
$master2 CLUSTER DELSLOTS 12288 $master2 CLUSTER DELSLOTS 12288
assert_match "* 8192-12287 12289-16383*" [$master2 CLUSTER NODES] assert_match "* 8192-12287 12289-16383*" [$master2 CLUSTER NODES]
assert_match "*8192 12287*12289 16383*" [$master2 CLUSTER SLOTS]
} }
test "Discontinuous slots distribution" { test "Discontinuous slots distribution" {
# Remove middle slots # Remove middle slots
$master1 CLUSTER DELSLOTS 4092 4094 $master1 CLUSTER DELSLOTS 4092 4094
assert_match "* 0-4091 4093 4095 4097-8191*" [$master1 CLUSTER NODES] assert_match "* 0-4091 4093 4095 4097-8191*" [$master1 CLUSTER NODES]
assert_match "*0 4091*4093 4093*4095 4095*4097 8191*" [$master1 CLUSTER SLOTS]
$master2 CLUSTER DELSLOTS 12284 12286 $master2 CLUSTER DELSLOTS 12284 12286
assert_match "* 8192-12283 12285 12287 12289-16383*" [$master2 CLUSTER NODES] assert_match "* 8192-12283 12285 12287 12289-16383*" [$master2 CLUSTER NODES]
assert_match "*8192 12283*12285 12285*12287 12287*12289 16383*" [$master2 CLUSTER SLOTS]
# Remove head slots # Remove head slots
$master1 CLUSTER DELSLOTS 0 2 $master1 CLUSTER DELSLOTS 0 2
assert_match "* 1 3-4091 4093 4095 4097-8191*" [$master1 CLUSTER NODES] assert_match "* 1 3-4091 4093 4095 4097-8191*" [$master1 CLUSTER NODES]
assert_match "*1 1*3 4091*4093 4093*4095 4095*4097 8191*" [$master1 CLUSTER SLOTS]
# Remove tail slots # Remove tail slots
$master2 CLUSTER DELSLOTS 16380 16382 16383 $master2 CLUSTER DELSLOTS 16380 16382 16383
assert_match "* 8192-12283 12285 12287 12289-16379 16381*" [$master2 CLUSTER NODES] assert_match "* 8192-12283 12285 12287 12289-16379 16381*" [$master2 CLUSTER NODES]
assert_match "*8192 12283*12285 12285*12287 12287*12289 16379*16381 16381*" [$master2 CLUSTER SLOTS]
} }
# Tests for fixing migrating slot at all stages:
# 1. when migration is half inited on "migrating" node
# 2. when migration is half inited on "importing" node
# 3. migration inited, but not finished
# 4. migration is half finished on "migrating" node
# 5. migration is half finished on "importing" node
# TODO: Test is currently disabled until it is stabilized (fixing the test
# itself or real issues in Redis).
if {false} {
source "../tests/includes/init-tests.tcl"
source "../tests/includes/utils.tcl"
test "Create a 2 nodes cluster" {
create_cluster 2 0
config_set_all_nodes cluster-allow-replica-migration no
}
test "Cluster is up" {
assert_cluster_state ok
}
set cluster [redis_cluster 127.0.0.1:[get_instance_attrib redis 0 port]]
catch {unset nodefrom}
catch {unset nodeto}
proc reset_cluster {} {
uplevel 1 {
$cluster refresh_nodes_map
array set nodefrom [$cluster masternode_for_slot 609]
array set nodeto [$cluster masternode_notfor_slot 609]
}
}
reset_cluster
$cluster set aga xyz
test "Half init migration in 'migrating' is fixable" {
assert_equal {OK} [$nodefrom(link) cluster setslot 609 migrating $nodeto(id)]
fix_cluster $nodefrom(addr)
assert_equal "xyz" [$cluster get aga]
}
test "Half init migration in 'importing' is fixable" {
assert_equal {OK} [$nodeto(link) cluster setslot 609 importing $nodefrom(id)]
fix_cluster $nodefrom(addr)
assert_equal "xyz" [$cluster get aga]
}
test "Init migration and move key" {
assert_equal {OK} [$nodefrom(link) cluster setslot 609 migrating $nodeto(id)]
assert_equal {OK} [$nodeto(link) cluster setslot 609 importing $nodefrom(id)]
assert_equal {OK} [$nodefrom(link) migrate $nodeto(host) $nodeto(port) aga 0 10000]
wait_for_cluster_propagation
assert_equal "xyz" [$cluster get aga]
fix_cluster $nodefrom(addr)
assert_equal "xyz" [$cluster get aga]
}
reset_cluster
test "Move key again" {
wait_for_cluster_propagation
assert_equal {OK} [$nodefrom(link) cluster setslot 609 migrating $nodeto(id)]
assert_equal {OK} [$nodeto(link) cluster setslot 609 importing $nodefrom(id)]
assert_equal {OK} [$nodefrom(link) migrate $nodeto(host) $nodeto(port) aga 0 10000]
wait_for_cluster_propagation
assert_equal "xyz" [$cluster get aga]
}
test "Half-finish migration" {
# half finish migration on 'migrating' node
assert_equal {OK} [$nodefrom(link) cluster setslot 609 node $nodeto(id)]
fix_cluster $nodefrom(addr)
assert_equal "xyz" [$cluster get aga]
}
reset_cluster
test "Move key back" {
# 'aga' key is in 609 slot
assert_equal {OK} [$nodefrom(link) cluster setslot 609 migrating $nodeto(id)]
assert_equal {OK} [$nodeto(link) cluster setslot 609 importing $nodefrom(id)]
assert_equal {OK} [$nodefrom(link) migrate $nodeto(host) $nodeto(port) aga 0 10000]
assert_equal "xyz" [$cluster get aga]
}
test "Half-finish importing" {
# Now we half finish 'importing' node
assert_equal {OK} [$nodeto(link) cluster setslot 609 node $nodeto(id)]
fix_cluster $nodefrom(addr)
assert_equal "xyz" [$cluster get aga]
}
config_set_all_nodes cluster-allow-replica-migration yes
}
# Tests for many simlutaneous migrations.
# TODO: Test is currently disabled until it is stabilized (fixing the test
# itself or real issues in Redis).
if {false} {
source "../tests/includes/init-tests.tcl"
source "../tests/includes/utils.tcl"
# TODO: This test currently runs without replicas, as failovers (which may
# happen on lower-end CI platforms) are still not handled properly by the
# cluster during slot migration (related to #6339).
test "Create a 10 nodes cluster" {
create_cluster 10 0
config_set_all_nodes cluster-allow-replica-migration no
}
test "Cluster is up" {
assert_cluster_state ok
}
set cluster [redis_cluster 127.0.0.1:[get_instance_attrib redis 0 port]]
catch {unset nodefrom}
catch {unset nodeto}
$cluster refresh_nodes_map
test "Set many keys" {
for {set i 0} {$i < 40000} {incr i} {
$cluster set key:$i val:$i
}
}
test "Keys are accessible" {
for {set i 0} {$i < 40000} {incr i} {
assert { [$cluster get key:$i] eq "val:$i" }
}
}
test "Init migration of many slots" {
for {set slot 0} {$slot < 1000} {incr slot} {
array set nodefrom [$cluster masternode_for_slot $slot]
array set nodeto [$cluster masternode_notfor_slot $slot]
$nodefrom(link) cluster setslot $slot migrating $nodeto(id)
$nodeto(link) cluster setslot $slot importing $nodefrom(id)
}
}
test "Fix cluster" {
wait_for_cluster_propagation
fix_cluster $nodefrom(addr)
}
test "Keys are accessible" {
for {set i 0} {$i < 40000} {incr i} {
assert { [$cluster get key:$i] eq "val:$i" }
}
}
config_set_all_nodes cluster-allow-replica-migration yes
}
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