Unverified Commit 959d6035 authored by Oran Agra's avatar Oran Agra Committed by GitHub
Browse files

Merge 6.2.2 release

Release 6.2.2
parents 92bde124 aa730ef1
...@@ -388,9 +388,8 @@ unsigned long zslDeleteRangeByScore(zskiplist *zsl, zrangespec *range, dict *dic ...@@ -388,9 +388,8 @@ unsigned long zslDeleteRangeByScore(zskiplist *zsl, zrangespec *range, dict *dic
x = zsl->header; x = zsl->header;
for (i = zsl->level-1; i >= 0; i--) { for (i = zsl->level-1; i >= 0; i--) {
while (x->level[i].forward && (range->minex ? while (x->level[i].forward &&
x->level[i].forward->score <= range->min : !zslValueGteMin(x->level[i].forward->score, range))
x->level[i].forward->score < range->min))
x = x->level[i].forward; x = x->level[i].forward;
update[i] = x; update[i] = x;
} }
...@@ -399,9 +398,7 @@ unsigned long zslDeleteRangeByScore(zskiplist *zsl, zrangespec *range, dict *dic ...@@ -399,9 +398,7 @@ unsigned long zslDeleteRangeByScore(zskiplist *zsl, zrangespec *range, dict *dic
x = x->level[0].forward; x = x->level[0].forward;
/* Delete nodes while in range. */ /* Delete nodes while in range. */
while (x && while (x && zslValueLteMax(x->score, range)) {
(range->maxex ? x->score < range->max : x->score <= range->max))
{
zskiplistNode *next = x->level[0].forward; zskiplistNode *next = x->level[0].forward;
zslDeleteNode(zsl,x,update); zslDeleteNode(zsl,x,update);
dictDelete(dict,x->ele); dictDelete(dict,x->ele);
...@@ -1279,9 +1276,7 @@ int zsetScore(robj *zobj, sds member, double *score) { ...@@ -1279,9 +1276,7 @@ int zsetScore(robj *zobj, sds member, double *score) {
/* Add a new element or update the score of an existing element in a sorted /* Add a new element or update the score of an existing element in a sorted
* set, regardless of its encoding. * set, regardless of its encoding.
* *
* The set of flags change the command behavior. They are passed with an integer * The set of flags change the command behavior.
* pointer since the function will clear the flags and populate them with
* other flags to indicate different conditions.
* *
* The input flags are the following: * The input flags are the following:
* *
...@@ -1323,19 +1318,19 @@ int zsetScore(robj *zobj, sds member, double *score) { ...@@ -1323,19 +1318,19 @@ int zsetScore(robj *zobj, sds member, double *score) {
* *
* The function does not take ownership of the 'ele' SDS string, but copies * The function does not take ownership of the 'ele' SDS string, but copies
* it if needed. */ * it if needed. */
int zsetAdd(robj *zobj, double score, sds ele, int *flags, double *newscore) { int zsetAdd(robj *zobj, double score, sds ele, int in_flags, int *out_flags, double *newscore) {
/* Turn options into simple to check vars. */ /* Turn options into simple to check vars. */
int incr = (*flags & ZADD_INCR) != 0; int incr = (in_flags & ZADD_IN_INCR) != 0;
int nx = (*flags & ZADD_NX) != 0; int nx = (in_flags & ZADD_IN_NX) != 0;
int xx = (*flags & ZADD_XX) != 0; int xx = (in_flags & ZADD_IN_XX) != 0;
int gt = (*flags & ZADD_GT) != 0; int gt = (in_flags & ZADD_IN_GT) != 0;
int lt = (*flags & ZADD_LT) != 0; int lt = (in_flags & ZADD_IN_LT) != 0;
*flags = 0; /* We'll return our response flags. */ *out_flags = 0; /* We'll return our response flags. */
double curscore; double curscore;
/* NaN as input is an error regardless of all the other parameters. */ /* NaN as input is an error regardless of all the other parameters. */
if (isnan(score)) { if (isnan(score)) {
*flags = ZADD_NAN; *out_flags = ZADD_OUT_NAN;
return 0; return 0;
} }
...@@ -1346,7 +1341,7 @@ int zsetAdd(robj *zobj, double score, sds ele, int *flags, double *newscore) { ...@@ -1346,7 +1341,7 @@ int zsetAdd(robj *zobj, double score, sds ele, int *flags, double *newscore) {
if ((eptr = zzlFind(zobj->ptr,ele,&curscore)) != NULL) { if ((eptr = zzlFind(zobj->ptr,ele,&curscore)) != NULL) {
/* NX? Return, same element already exists. */ /* NX? Return, same element already exists. */
if (nx) { if (nx) {
*flags |= ZADD_NOP; *out_flags |= ZADD_OUT_NOP;
return 1; return 1;
} }
...@@ -1354,22 +1349,24 @@ int zsetAdd(robj *zobj, double score, sds ele, int *flags, double *newscore) { ...@@ -1354,22 +1349,24 @@ int zsetAdd(robj *zobj, double score, sds ele, int *flags, double *newscore) {
if (incr) { if (incr) {
score += curscore; score += curscore;
if (isnan(score)) { if (isnan(score)) {
*flags |= ZADD_NAN; *out_flags |= ZADD_OUT_NAN;
return 0; return 0;
} }
if (newscore) *newscore = score;
} }
/* GT/LT? Only update if score is greater/less than current. */
if ((lt && score >= curscore) || (gt && score <= curscore)) {
*out_flags |= ZADD_OUT_NOP;
return 1;
}
if (newscore) *newscore = score;
/* Remove and re-insert when score changed. */ /* Remove and re-insert when score changed. */
if (score != curscore && if (score != curscore) {
/* LT? Only update if score is less than current. */
(!lt || score < curscore) &&
/* GT? Only update if score is greater than current. */
(!gt || score > curscore))
{
zobj->ptr = zzlDelete(zobj->ptr,eptr); zobj->ptr = zzlDelete(zobj->ptr,eptr);
zobj->ptr = zzlInsert(zobj->ptr,ele,score); zobj->ptr = zzlInsert(zobj->ptr,ele,score);
*flags |= ZADD_UPDATED; *out_flags |= ZADD_OUT_UPDATED;
} }
return 1; return 1;
} else if (!xx) { } else if (!xx) {
...@@ -1380,10 +1377,10 @@ int zsetAdd(robj *zobj, double score, sds ele, int *flags, double *newscore) { ...@@ -1380,10 +1377,10 @@ int zsetAdd(robj *zobj, double score, sds ele, int *flags, double *newscore) {
sdslen(ele) > server.zset_max_ziplist_value) sdslen(ele) > server.zset_max_ziplist_value)
zsetConvert(zobj,OBJ_ENCODING_SKIPLIST); zsetConvert(zobj,OBJ_ENCODING_SKIPLIST);
if (newscore) *newscore = score; if (newscore) *newscore = score;
*flags |= ZADD_ADDED; *out_flags |= ZADD_OUT_ADDED;
return 1; return 1;
} else { } else {
*flags |= ZADD_NOP; *out_flags |= ZADD_OUT_NOP;
return 1; return 1;
} }
} else if (zobj->encoding == OBJ_ENCODING_SKIPLIST) { } else if (zobj->encoding == OBJ_ENCODING_SKIPLIST) {
...@@ -1395,45 +1392,48 @@ int zsetAdd(robj *zobj, double score, sds ele, int *flags, double *newscore) { ...@@ -1395,45 +1392,48 @@ int zsetAdd(robj *zobj, double score, sds ele, int *flags, double *newscore) {
if (de != NULL) { if (de != NULL) {
/* NX? Return, same element already exists. */ /* NX? Return, same element already exists. */
if (nx) { if (nx) {
*flags |= ZADD_NOP; *out_flags |= ZADD_OUT_NOP;
return 1; return 1;
} }
curscore = *(double*)dictGetVal(de); curscore = *(double*)dictGetVal(de);
/* Prepare the score for the increment if needed. */ /* Prepare the score for the increment if needed. */
if (incr) { if (incr) {
score += curscore; score += curscore;
if (isnan(score)) { if (isnan(score)) {
*flags |= ZADD_NAN; *out_flags |= ZADD_OUT_NAN;
return 0; return 0;
} }
if (newscore) *newscore = score;
} }
/* GT/LT? Only update if score is greater/less than current. */
if ((lt && score >= curscore) || (gt && score <= curscore)) {
*out_flags |= ZADD_OUT_NOP;
return 1;
}
if (newscore) *newscore = score;
/* Remove and re-insert when score changes. */ /* Remove and re-insert when score changes. */
if (score != curscore && if (score != curscore) {
/* LT? Only update if score is less than current. */
(!lt || score < curscore) &&
/* GT? Only update if score is greater than current. */
(!gt || score > curscore))
{
znode = zslUpdateScore(zs->zsl,curscore,ele,score); znode = zslUpdateScore(zs->zsl,curscore,ele,score);
/* Note that we did not removed the original element from /* Note that we did not removed the original element from
* the hash table representing the sorted set, so we just * the hash table representing the sorted set, so we just
* update the score. */ * update the score. */
dictGetVal(de) = &znode->score; /* Update score ptr. */ dictGetVal(de) = &znode->score; /* Update score ptr. */
*flags |= ZADD_UPDATED; *out_flags |= ZADD_OUT_UPDATED;
} }
return 1; return 1;
} else if (!xx) { } else if (!xx) {
ele = sdsdup(ele); ele = sdsdup(ele);
znode = zslInsert(zs->zsl,score,ele); znode = zslInsert(zs->zsl,score,ele);
serverAssert(dictAdd(zs->dict,ele,&znode->score) == DICT_OK); serverAssert(dictAdd(zs->dict,ele,&znode->score) == DICT_OK);
*flags |= ZADD_ADDED; *out_flags |= ZADD_OUT_ADDED;
if (newscore) *newscore = score; if (newscore) *newscore = score;
return 1; return 1;
} else { } else {
*flags |= ZADD_NOP; *out_flags |= ZADD_OUT_NOP;
return 1; return 1;
} }
} else { } else {
...@@ -1636,7 +1636,7 @@ static int _zsetZiplistValidateIntegrity(unsigned char *p, void *userdata) { ...@@ -1636,7 +1636,7 @@ static int _zsetZiplistValidateIntegrity(unsigned char *p, void *userdata) {
return 1; return 1;
} }
/* 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 zsetZiplistValidateIntegrity(unsigned char *zl, size_t size, int deep) { int zsetZiplistValidateIntegrity(unsigned char *zl, size_t size, int deep) {
...@@ -1712,7 +1712,7 @@ void zaddGenericCommand(client *c, int flags) { ...@@ -1712,7 +1712,7 @@ void zaddGenericCommand(client *c, int flags) {
robj *zobj; robj *zobj;
sds ele; sds ele;
double score = 0, *scores = NULL; double score = 0, *scores = NULL;
int j, elements; int j, elements, ch = 0;
int scoreidx = 0; int scoreidx = 0;
/* The following vars are used in order to track what the command actually /* The following vars are used in order to track what the command actually
* did during the execution, to reply to the client and to trigger the * did during the execution, to reply to the client and to trigger the
...@@ -1727,23 +1727,22 @@ void zaddGenericCommand(client *c, int flags) { ...@@ -1727,23 +1727,22 @@ void zaddGenericCommand(client *c, int flags) {
scoreidx = 2; scoreidx = 2;
while(scoreidx < c->argc) { while(scoreidx < c->argc) {
char *opt = c->argv[scoreidx]->ptr; char *opt = c->argv[scoreidx]->ptr;
if (!strcasecmp(opt,"nx")) flags |= ZADD_NX; if (!strcasecmp(opt,"nx")) flags |= ZADD_IN_NX;
else if (!strcasecmp(opt,"xx")) flags |= ZADD_XX; else if (!strcasecmp(opt,"xx")) flags |= ZADD_IN_XX;
else if (!strcasecmp(opt,"ch")) flags |= ZADD_CH; else if (!strcasecmp(opt,"ch")) ch = 1; /* Return num of elements added or updated. */
else if (!strcasecmp(opt,"incr")) flags |= ZADD_INCR; else if (!strcasecmp(opt,"incr")) flags |= ZADD_IN_INCR;
else if (!strcasecmp(opt,"gt")) flags |= ZADD_GT; else if (!strcasecmp(opt,"gt")) flags |= ZADD_IN_GT;
else if (!strcasecmp(opt,"lt")) flags |= ZADD_LT; else if (!strcasecmp(opt,"lt")) flags |= ZADD_IN_LT;
else break; else break;
scoreidx++; scoreidx++;
} }
/* Turn options into simple to check vars. */ /* Turn options into simple to check vars. */
int incr = (flags & ZADD_INCR) != 0; int incr = (flags & ZADD_IN_INCR) != 0;
int nx = (flags & ZADD_NX) != 0; int nx = (flags & ZADD_IN_NX) != 0;
int xx = (flags & ZADD_XX) != 0; int xx = (flags & ZADD_IN_XX) != 0;
int ch = (flags & ZADD_CH) != 0; int gt = (flags & ZADD_IN_GT) != 0;
int gt = (flags & ZADD_GT) != 0; int lt = (flags & ZADD_IN_LT) != 0;
int lt = (flags & ZADD_LT) != 0;
/* After the options, we expect to have an even number of args, since /* After the options, we expect to have an even number of args, since
* we expect any number of score-element pairs. */ * we expect any number of score-element pairs. */
...@@ -1801,17 +1800,17 @@ void zaddGenericCommand(client *c, int flags) { ...@@ -1801,17 +1800,17 @@ void zaddGenericCommand(client *c, int flags) {
for (j = 0; j < elements; j++) { for (j = 0; j < elements; j++) {
double newscore; double newscore;
score = scores[j]; score = scores[j];
int retflags = flags; int retflags = 0;
ele = c->argv[scoreidx+1+j*2]->ptr; ele = c->argv[scoreidx+1+j*2]->ptr;
int retval = zsetAdd(zobj, score, ele, &retflags, &newscore); int retval = zsetAdd(zobj, score, ele, flags, &retflags, &newscore);
if (retval == 0) { if (retval == 0) {
addReplyError(c,nanerr); addReplyError(c,nanerr);
goto cleanup; goto cleanup;
} }
if (retflags & ZADD_ADDED) added++; if (retflags & ZADD_OUT_ADDED) added++;
if (retflags & ZADD_UPDATED) updated++; if (retflags & ZADD_OUT_UPDATED) updated++;
if (!(retflags & ZADD_NOP)) processed++; if (!(retflags & ZADD_OUT_NOP)) processed++;
score = newscore; score = newscore;
} }
server.dirty += (added+updated); server.dirty += (added+updated);
...@@ -1836,11 +1835,11 @@ cleanup: ...@@ -1836,11 +1835,11 @@ cleanup:
} }
void zaddCommand(client *c) { void zaddCommand(client *c) {
zaddGenericCommand(c,ZADD_NONE); zaddGenericCommand(c,ZADD_IN_NONE);
} }
void zincrbyCommand(client *c) { void zincrbyCommand(client *c) {
zaddGenericCommand(c,ZADD_INCR); zaddGenericCommand(c,ZADD_IN_INCR);
} }
void zremCommand(client *c) { void zremCommand(client *c) {
...@@ -2577,8 +2576,8 @@ void zunionInterDiffGenericCommand(client *c, robj *dstkey, int numkeysIndex, in ...@@ -2577,8 +2576,8 @@ void zunionInterDiffGenericCommand(client *c, robj *dstkey, int numkeysIndex, in
return; return;
if (setnum < 1) { if (setnum < 1) {
addReplyError(c, addReplyErrorFormat(c,
"at least 1 input key is needed for ZUNIONSTORE/ZINTERSTORE/ZDIFFSTORE"); "at least 1 input key is needed for %s", c->cmd->name);
return; return;
} }
...@@ -2941,7 +2940,7 @@ static void zrangeResultEmitCBufferForStore(zrange_result_handler *handler, ...@@ -2941,7 +2940,7 @@ static void zrangeResultEmitCBufferForStore(zrange_result_handler *handler,
double newscore; double newscore;
int retflags = 0; int retflags = 0;
sds ele = sdsnewlen(value, value_length_in_bytes); sds ele = sdsnewlen(value, value_length_in_bytes);
int retval = zsetAdd(handler->dstobj, score, ele, &retflags, &newscore); int retval = zsetAdd(handler->dstobj, score, ele, ZADD_IN_NONE, &retflags, &newscore);
sdsfree(ele); sdsfree(ele);
serverAssert(retval); serverAssert(retval);
} }
...@@ -2952,7 +2951,7 @@ static void zrangeResultEmitLongLongForStore(zrange_result_handler *handler, ...@@ -2952,7 +2951,7 @@ static void zrangeResultEmitLongLongForStore(zrange_result_handler *handler,
double newscore; double newscore;
int retflags = 0; int retflags = 0;
sds ele = sdsfromlonglong(value); sds ele = sdsfromlonglong(value);
int retval = zsetAdd(handler->dstobj, score, ele, &retflags, &newscore); int retval = zsetAdd(handler->dstobj, score, ele, ZADD_IN_NONE, &retflags, &newscore);
sdsfree(ele); sdsfree(ele);
serverAssert(retval); serverAssert(retval);
} }
......
...@@ -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
#define REDIS_VERSION "6.2.1" #define REDIS_VERSION "6.2.2"
#define REDIS_VERSION_NUM 0x00060201 #define REDIS_VERSION_NUM 0x00060202
...@@ -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
\ No newline at end of file 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]
} }
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