Merge tag '6.0.5' into unstable
Redis 6.0.5 Former-commit-id: b736a95b0d23e4b73daa88c676b76d1d18e8bd17
This commit is contained in:
commit
d4dd336834
@ -11,6 +11,76 @@ CRITICAL: There is a critical bug affecting MOST USERS. Upgrade ASAP.
|
|||||||
SECURITY: There are security fixes in the release.
|
SECURITY: There are security fixes in the release.
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
Redis 6.0.5 Released Tue Jun 09 11:56:08 CEST 2020
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
Upgrade urgency MODERATE: several bugs with moderate impact are fixed here.
|
||||||
|
|
||||||
|
The most important issues are listed here:
|
||||||
|
|
||||||
|
* Fix handling of speical chars in ACL LOAD.
|
||||||
|
* Make Redis Cluster more robust about operation errors that may lead
|
||||||
|
to two clusters to mix together.
|
||||||
|
* Revert the sendfile() implementation of RDB transfer. It causes some delay.
|
||||||
|
* Fix TLS certificate loading for chained certificates.
|
||||||
|
* Fix AOF rewirting of KEEPTTL SET option.
|
||||||
|
* Fix MULTI/EXEC behavior during -BUSY script errors.
|
||||||
|
|
||||||
|
And this is the full list of commits:
|
||||||
|
|
||||||
|
antirez in commit ee8dd01bb:
|
||||||
|
Temporary fix for #7353 issue about EVAL during -BUSY.
|
||||||
|
1 file changed, 9 insertions(+)
|
||||||
|
|
||||||
|
xhe in commit a4a856d53:
|
||||||
|
return the correct proto version HELLO should return the current proto version, while the code hardcoded 3
|
||||||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||||
|
|
||||||
|
Oran Agra in commit e2046b300:
|
||||||
|
Don't queue commands in an already aborted MULTI state
|
||||||
|
1 file changed, 7 insertions(+)
|
||||||
|
|
||||||
|
Oran Agra in commit b35fdf1de:
|
||||||
|
Avoid rejecting WATCH / UNWATCH, like MULTI/EXEC/DISCARD
|
||||||
|
1 file changed, 4 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
zhaozhao.zz in commit 1d7bf208c:
|
||||||
|
AOF: append origin SET if no expire option
|
||||||
|
2 files changed, 23 insertions(+), 8 deletions(-)
|
||||||
|
|
||||||
|
Oran Agra in commit 676445ad9:
|
||||||
|
fix disconnectSlaves, to try to free each slave.
|
||||||
|
1 file changed, 1 deletion(-)
|
||||||
|
|
||||||
|
zhaozhao.zz in commit 4846c0c8a:
|
||||||
|
donot free protected client in freeClientsInAsyncFreeQueue
|
||||||
|
1 file changed, 9 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
Oran Agra in commit f33de403e:
|
||||||
|
fix pingoff test race
|
||||||
|
1 file changed, 1 insertion(+)
|
||||||
|
|
||||||
|
Kevin Fwu in commit 49af4d07e:
|
||||||
|
Fix TLS certificate loading for chained certificates.
|
||||||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||||
|
|
||||||
|
antirez in commit 329fddbda:
|
||||||
|
Revert "Implements sendfile for redis."
|
||||||
|
2 files changed, 2 insertions(+), 55 deletions(-)
|
||||||
|
|
||||||
|
antirez in commit 925a2cd5a:
|
||||||
|
Revert "avoid using sendfile if tls-replication is enabled"
|
||||||
|
1 file changed, 27 insertions(+), 34 deletions(-)
|
||||||
|
|
||||||
|
Liu Zhen in commit 84a7a9058:
|
||||||
|
fix clusters mixing accidentally by gossip
|
||||||
|
1 file changed, 10 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
antirez in commit cd63359a1:
|
||||||
|
Fix handling of special chars in ACL LOAD.
|
||||||
|
1 file changed, 8 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
================================================================================
|
================================================================================
|
||||||
Redis 6.0.4 Released Thu May 28 11:36:45 CEST 2020
|
Redis 6.0.4 Released Thu May 28 11:36:45 CEST 2020
|
||||||
================================================================================
|
================================================================================
|
||||||
|
10
src/acl.cpp
10
src/acl.cpp
@ -739,6 +739,7 @@ void ACLAddAllowedSubcommand(user *u, unsigned long id, const char *sub) {
|
|||||||
*/
|
*/
|
||||||
int ACLSetUser(user *u, const char *op, ssize_t oplen) {
|
int ACLSetUser(user *u, const char *op, ssize_t oplen) {
|
||||||
if (oplen == -1) oplen = strlen(op);
|
if (oplen == -1) oplen = strlen(op);
|
||||||
|
if (oplen == 0) return C_OK; /* Empty string is a no-operation. */
|
||||||
if (!strcasecmp(op,"on")) {
|
if (!strcasecmp(op,"on")) {
|
||||||
u->flags |= USER_FLAG_ENABLED;
|
u->flags |= USER_FLAG_ENABLED;
|
||||||
u->flags &= ~USER_FLAG_DISABLED;
|
u->flags &= ~USER_FLAG_DISABLED;
|
||||||
@ -1300,7 +1301,7 @@ sds ACLLoadFromFile(const char *filename) {
|
|||||||
if (lines[i][0] == '\0') continue;
|
if (lines[i][0] == '\0') continue;
|
||||||
|
|
||||||
/* Split into arguments */
|
/* Split into arguments */
|
||||||
argv = sdssplitargs(lines[i],&argc);
|
argv = sdssplitlen(lines[i],sdslen(lines[i])," ",1,&argc);
|
||||||
if (argv == NULL) {
|
if (argv == NULL) {
|
||||||
errors = sdscatprintf(errors,
|
errors = sdscatprintf(errors,
|
||||||
"%s:%d: unbalanced quotes in acl line. ",
|
"%s:%d: unbalanced quotes in acl line. ",
|
||||||
@ -1332,11 +1333,14 @@ sds ACLLoadFromFile(const char *filename) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try to process the line using the fake user to validate iif
|
/* Try to process the line using the fake user to validate if
|
||||||
* the rules are able to apply cleanly. */
|
* the rules are able to apply cleanly. At this stage we also
|
||||||
|
* trim trailing spaces, so that we don't have to handle that
|
||||||
|
* in ACLSetUser(). */
|
||||||
ACLSetUser(fakeuser,"reset",-1);
|
ACLSetUser(fakeuser,"reset",-1);
|
||||||
int j;
|
int j;
|
||||||
for (j = 2; j < argc; j++) {
|
for (j = 2; j < argc; j++) {
|
||||||
|
argv[j] = sdstrim(argv[j],"\t\r\n");
|
||||||
if (ACLSetUser(fakeuser,argv[j],sdslen(argv[j])) != C_OK) {
|
if (ACLSetUser(fakeuser,argv[j],sdslen(argv[j])) != C_OK) {
|
||||||
const char *errmsg = ACLSetUserStringError();
|
const char *errmsg = ACLSetUserStringError();
|
||||||
errors = sdscatprintf(errors,
|
errors = sdscatprintf(errors,
|
||||||
|
@ -671,19 +671,23 @@ sds catCommandForAofAndActiveReplication(sds buf, struct redisCommand *cmd, robj
|
|||||||
} else if (cmd->proc == setCommand && argc > 3) {
|
} else if (cmd->proc == setCommand && argc > 3) {
|
||||||
int i;
|
int i;
|
||||||
robj *exarg = NULL, *pxarg = NULL;
|
robj *exarg = NULL, *pxarg = NULL;
|
||||||
/* Translate SET [EX seconds][PX milliseconds] to SET and PEXPIREAT */
|
|
||||||
buf = catAppendOnlyGenericCommand(buf,3,argv);
|
|
||||||
for (i = 3; i < argc; i ++) {
|
for (i = 3; i < argc; i ++) {
|
||||||
if (!strcasecmp(szFromObj(argv[i]), "ex")) exarg = argv[i+1];
|
if (!strcasecmp(szFromObj(argv[i]), "ex")) exarg = argv[i+1];
|
||||||
if (!strcasecmp(szFromObj(argv[i]), "px")) pxarg = argv[i+1];
|
if (!strcasecmp(szFromObj(argv[i]), "px")) pxarg = argv[i+1];
|
||||||
}
|
}
|
||||||
serverAssert(!(exarg && pxarg));
|
serverAssert(!(exarg && pxarg));
|
||||||
|
if (exarg || pxarg) {
|
||||||
|
/* Translate SET [EX seconds][PX milliseconds] to SET and PEXPIREAT */
|
||||||
|
buf = catAppendOnlyGenericCommand(buf,3,argv);
|
||||||
if (exarg)
|
if (exarg)
|
||||||
buf = catAppendOnlyExpireAtCommand(buf,cserver.expireCommand,argv[1],
|
buf = catAppendOnlyExpireAtCommand(buf,cserver.expireCommand,argv[1],
|
||||||
exarg);
|
exarg);
|
||||||
if (pxarg)
|
if (pxarg)
|
||||||
buf = catAppendOnlyExpireAtCommand(buf,cserver.pexpireCommand,argv[1],
|
buf = catAppendOnlyExpireAtCommand(buf,cserver.pexpireCommand,argv[1],
|
||||||
pxarg);
|
pxarg);
|
||||||
|
} else {
|
||||||
|
buf = catAppendOnlyGenericCommand(buf,argc,argv);
|
||||||
|
}
|
||||||
} else if (cmd->proc == expireMemberCommand || cmd->proc == expireMemberAtCommand ||
|
} else if (cmd->proc == expireMemberCommand || cmd->proc == expireMemberAtCommand ||
|
||||||
cmd->proc == pexpireMemberAtCommand) {
|
cmd->proc == pexpireMemberAtCommand) {
|
||||||
/* Translate subkey expire commands to PEXPIREMEMBERAT */
|
/* Translate subkey expire commands to PEXPIREMEMBERAT */
|
||||||
|
@ -1501,7 +1501,10 @@ void clusterProcessGossipSection(clusterMsg *hdr, clusterLink *link) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* If it's not in NOADDR state and we don't have it, we
|
/* If it's not in NOADDR state and we don't have it, we
|
||||||
* start a handshake process against this IP/PORT pairs.
|
* add it to our trusted dict with exact nodeid and flag.
|
||||||
|
* Note that we cannot simply start a handshake against
|
||||||
|
* this IP/PORT pairs, since IP/PORT can be reused already,
|
||||||
|
* otherwise we risk joining another cluster.
|
||||||
*
|
*
|
||||||
* Note that we require that the sender of this gossip message
|
* Note that we require that the sender of this gossip message
|
||||||
* is a well known node in our cluster, otherwise we risk
|
* is a well known node in our cluster, otherwise we risk
|
||||||
@ -1510,7 +1513,12 @@ void clusterProcessGossipSection(clusterMsg *hdr, clusterLink *link) {
|
|||||||
!(flags & CLUSTER_NODE_NOADDR) &&
|
!(flags & CLUSTER_NODE_NOADDR) &&
|
||||||
!clusterBlacklistExists(g->nodename))
|
!clusterBlacklistExists(g->nodename))
|
||||||
{
|
{
|
||||||
clusterStartHandshake(g->ip,ntohs(g->port),ntohs(g->cport));
|
clusterNode *node;
|
||||||
|
node = createClusterNode(g->nodename, flags);
|
||||||
|
memcpy(node->ip,g->ip,NET_IP_STR_LEN);
|
||||||
|
node->port = ntohs(g->port);
|
||||||
|
node->cport = ntohs(g->cport);
|
||||||
|
clusterAddNode(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +59,13 @@ void queueMultiCommand(client *c) {
|
|||||||
multiCmd *mc;
|
multiCmd *mc;
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
|
/* No sense to waste memory if the transaction is already aborted.
|
||||||
|
* this is useful in case client sends these in a pipeline, or doesn't
|
||||||
|
* bother to read previous responses and didn't notice the multi was already
|
||||||
|
* aborted. */
|
||||||
|
if (c->flags & CLIENT_DIRTY_EXEC)
|
||||||
|
return;
|
||||||
|
|
||||||
c->mstate.commands = (multiCmd*)zrealloc(c->mstate.commands,
|
c->mstate.commands = (multiCmd*)zrealloc(c->mstate.commands,
|
||||||
sizeof(multiCmd)*(c->mstate.count+1), MALLOC_LOCAL);
|
sizeof(multiCmd)*(c->mstate.count+1), MALLOC_LOCAL);
|
||||||
mc = c->mstate.commands+c->mstate.count;
|
mc = c->mstate.commands+c->mstate.count;
|
||||||
@ -131,6 +138,15 @@ void execCommand(client *c) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If we are in -BUSY state, flag the transaction and return the
|
||||||
|
* -BUSY error, like Redis <= 5. This is a temporary fix, may be changed
|
||||||
|
* ASAP, see issue #7353 on Github. */
|
||||||
|
if (g_pserver->lua_timedout) {
|
||||||
|
flagTransaction(c);
|
||||||
|
addReply(c, shared.slowscripterr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check if we need to abort the EXEC because:
|
/* Check if we need to abort the EXEC because:
|
||||||
* 1) Some WATCHed key was touched.
|
* 1) Some WATCHed key was touched.
|
||||||
* 2) There was a previous error while queueing commands.
|
* 2) There was a previous error while queueing commands.
|
||||||
|
@ -1645,7 +1645,7 @@ int freeClientsInAsyncFreeQueue(int iel) {
|
|||||||
while((ln = listNext(&li)))
|
while((ln = listNext(&li)))
|
||||||
{
|
{
|
||||||
client *c = (client*)listNodeValue(ln);
|
client *c = (client*)listNodeValue(ln);
|
||||||
if (c->iel == iel)
|
if (c->iel == iel && !(c->flags & CLIENT_PROTECTED))
|
||||||
{
|
{
|
||||||
vecclientsFree.push_back(c);
|
vecclientsFree.push_back(c);
|
||||||
listDelNode(g_pserver->clients_to_close, ln);
|
listDelNode(g_pserver->clients_to_close, ln);
|
||||||
@ -3060,7 +3060,7 @@ void helloCommand(client *c) {
|
|||||||
addReplyBulkCString(c,KEYDB_SET_VERSION);
|
addReplyBulkCString(c,KEYDB_SET_VERSION);
|
||||||
|
|
||||||
addReplyBulkCString(c,"proto");
|
addReplyBulkCString(c,"proto");
|
||||||
addReplyLongLong(c,3);
|
addReplyLongLong(c,ver);
|
||||||
|
|
||||||
addReplyBulkCString(c,"id");
|
addReplyBulkCString(c,"id");
|
||||||
addReplyLongLong(c,c->id);
|
addReplyLongLong(c,c->id);
|
||||||
|
@ -1370,7 +1370,6 @@ void sendBulkToSlave(connection *conn) {
|
|||||||
* try to use sendfile system call if supported, unless tls is enabled.
|
* try to use sendfile system call if supported, unless tls is enabled.
|
||||||
* fallback to normal read+write otherwise. */
|
* fallback to normal read+write otherwise. */
|
||||||
nwritten = 0;
|
nwritten = 0;
|
||||||
if (!nwritten) {
|
|
||||||
ssize_t buflen;
|
ssize_t buflen;
|
||||||
char buf[PROTO_IOBUF_LEN];
|
char buf[PROTO_IOBUF_LEN];
|
||||||
|
|
||||||
@ -1394,7 +1393,6 @@ void sendBulkToSlave(connection *conn) {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
replica->repldboff += nwritten;
|
replica->repldboff += nwritten;
|
||||||
g_pserver->stat_net_output_bytes += nwritten;
|
g_pserver->stat_net_output_bytes += nwritten;
|
||||||
|
@ -813,11 +813,11 @@ struct redisCommand redisCommandTable[] = {
|
|||||||
0,NULL,0,0,0,0,0,0},
|
0,NULL,0,0,0,0,0,0},
|
||||||
|
|
||||||
{"watch",watchCommand,-2,
|
{"watch",watchCommand,-2,
|
||||||
"no-script fast @transaction",
|
"no-script fast ok-loading ok-stale @transaction",
|
||||||
0,NULL,1,-1,1,0,0,0},
|
0,NULL,1,-1,1,0,0,0},
|
||||||
|
|
||||||
{"unwatch",unwatchCommand,1,
|
{"unwatch",unwatchCommand,1,
|
||||||
"no-script fast @transaction",
|
"no-script fast ok-loading ok-stale @transaction",
|
||||||
0,NULL,0,0,0,0,0,0},
|
0,NULL,0,0,0,0,0,0},
|
||||||
|
|
||||||
{"cluster",clusterCommand,-2,
|
{"cluster",clusterCommand,-2,
|
||||||
@ -3870,6 +3870,8 @@ int processCommand(client *c, int callFlags, AeLocker &locker) {
|
|||||||
c->cmd->proc != multiCommand &&
|
c->cmd->proc != multiCommand &&
|
||||||
c->cmd->proc != execCommand &&
|
c->cmd->proc != execCommand &&
|
||||||
c->cmd->proc != discardCommand &&
|
c->cmd->proc != discardCommand &&
|
||||||
|
c->cmd->proc != watchCommand &&
|
||||||
|
c->cmd->proc != unwatchCommand &&
|
||||||
!(c->cmd->proc == shutdownCommand &&
|
!(c->cmd->proc == shutdownCommand &&
|
||||||
c->argc == 2 &&
|
c->argc == 2 &&
|
||||||
tolower(((char*)ptrFromObj(c->argv[1]))[0]) == 'n') &&
|
tolower(((char*)ptrFromObj(c->argv[1]))[0]) == 'n') &&
|
||||||
|
@ -226,7 +226,7 @@ int tlsConfigure(redisTLSContextConfig *ctx_config) {
|
|||||||
SSL_CTX_set_ecdh_auto(ctx, 1);
|
SSL_CTX_set_ecdh_auto(ctx, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (SSL_CTX_use_certificate_file(ctx, ctx_config->cert_file, SSL_FILETYPE_PEM) <= 0) {
|
if (SSL_CTX_use_certificate_chain_file(ctx, ctx_config->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", ctx_config->cert_file, errbuf);
|
serverLog(LL_WARNING, "Failed to load certificate: %s: %s", ctx_config->cert_file, errbuf);
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -101,8 +101,8 @@ void disableTracking(client *c) {
|
|||||||
|
|
||||||
/* Set the client 'c' to track the prefix 'prefix'. If the client 'c' is
|
/* Set the client 'c' to track the prefix 'prefix'. If the client 'c' is
|
||||||
* already registered for the specified prefix, no operation is performed. */
|
* already registered for the specified prefix, no operation is performed. */
|
||||||
void enableBcastTrackingForPrefix(client *c, const char *prefix, size_t plen) {
|
static void enableBcastTrackingForPrefix(client *c, const char *prefix, size_t plen) {
|
||||||
bcastState *bs = (bcastState*)raxFind(PrefixTable,(unsigned char*)prefix,sdslen(prefix));
|
bcastState *bs = (bcastState*)raxFind(PrefixTable,(unsigned char*)prefix,plen);
|
||||||
/* If this is the first client subscribing to such prefix, create
|
/* If this is the first client subscribing to such prefix, create
|
||||||
* the prefix in the table. */
|
* the prefix in the table. */
|
||||||
if (bs == raxNotFound) {
|
if (bs == raxNotFound) {
|
||||||
|
@ -64,6 +64,7 @@ start_server {} {
|
|||||||
# make sure replication is still alive and kicking
|
# make sure replication is still alive and kicking
|
||||||
$R(1) incr x
|
$R(1) incr x
|
||||||
wait_for_condition 50 1000 {
|
wait_for_condition 50 1000 {
|
||||||
|
[status $R(0) loading] == 0 &&
|
||||||
[$R(0) get x] == 1
|
[$R(0) get x] == 1
|
||||||
} else {
|
} else {
|
||||||
fail "replica didn't get incr"
|
fail "replica didn't get incr"
|
||||||
|
@ -313,4 +313,14 @@ start_server {tags {"expire"}} {
|
|||||||
after 3000
|
after 3000
|
||||||
assert_equal [r dbsize] 0
|
assert_equal [r dbsize] 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test {SET - use KEEPTTL option, TTL should not be removed after loadaof} {
|
||||||
|
r config set appendonly yes
|
||||||
|
r set foo bar EX 100
|
||||||
|
r set foo bar2 KEEPTTL
|
||||||
|
after 2000
|
||||||
|
r debug loadaof
|
||||||
|
set ttl [r ttl foo]
|
||||||
|
assert {$ttl <= 98 && $ttl > 90}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -363,6 +363,9 @@ start_server {tags {"multi"}} {
|
|||||||
set xx [r get xx]
|
set xx [r get xx]
|
||||||
# make sure that either the whole transcation passed or none of it (we actually expect none)
|
# make sure that either the whole transcation passed or none of it (we actually expect none)
|
||||||
assert { $xx == 1 || $xx == 3}
|
assert { $xx == 1 || $xx == 3}
|
||||||
|
# Discard the transaction since EXEC likely got -BUSY error
|
||||||
|
# so the client is still in MULTI state.
|
||||||
|
catch { $rd2 discard ;$rd2 read } e
|
||||||
# check that the connection is no longer in multi state
|
# check that the connection is no longer in multi state
|
||||||
$rd2 ping asdf
|
$rd2 ping asdf
|
||||||
set pong [$rd2 read]
|
set pong [$rd2 read]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user