Hello community, here is the log from the commit of package redis for openSUSE:Factory checked in at 2020-06-11 14:47:27 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/redis (Old) and /work/SRC/openSUSE:Factory/.redis.new.3606 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "redis" Thu Jun 11 14:47:27 2020 rev:58 rq:813302 version:6.0.5 Changes: -------- --- /work/SRC/openSUSE:Factory/redis/redis.changes 2020-06-08 23:43:27.245257504 +0200 +++ /work/SRC/openSUSE:Factory/.redis.new.3606/redis.changes 2020-06-11 14:47:47.913923752 +0200 @@ -1,0 +2,12 @@ +Wed Jun 10 15:18:18 UTC 2020 - Andreas Stieger <[email protected]> + +- redis 6.0.5: + * 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 + * Fix TLS certificate loading for chained certificates + * Fix AOF rewirting of KEEPTTL SET option + * Fix MULTI/EXEC behavior during -BUSY script errors + +------------------------------------------------------------------- Old: ---- redis-6.0.4.tar.gz New: ---- redis-6.0.5.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ redis.spec ++++++ --- /var/tmp/diff_new_pack.jy8cH8/_old 2020-06-11 14:47:49.037927026 +0200 +++ /var/tmp/diff_new_pack.jy8cH8/_new 2020-06-11 14:47:49.041927039 +0200 @@ -19,10 +19,10 @@ %define _data_dir %{_localstatedir}/lib/%{name} %define _log_dir %{_localstatedir}/log/%{name} %define _conf_dir %{_sysconfdir}/%{name} -%define redis_hashes_tree 6132305b4e7b98a88e6526d36190251960b6fc38 +%define redis_hashes_tree f898aabb30ab0655dc08f8f5cf900f1a8de8a803 Name: redis -Version: 6.0.4 +Version: 6.0.5 Release: 0 Summary: Persistent key-value database License: BSD-3-Clause ++++++ redis-6.0.4.tar.gz -> redis-6.0.5.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.0.4/00-RELEASENOTES new/redis-6.0.5/00-RELEASENOTES --- old/redis-6.0.4/00-RELEASENOTES 2020-05-28 12:18:38.000000000 +0200 +++ new/redis-6.0.5/00-RELEASENOTES 2020-06-09 12:19:30.000000000 +0200 @@ -12,6 +12,76 @@ -------------------------------------------------------------------------------- ================================================================================ +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 ================================================================================ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.0.4/src/acl.c new/redis-6.0.5/src/acl.c --- old/redis-6.0.4/src/acl.c 2020-05-28 12:18:38.000000000 +0200 +++ new/redis-6.0.5/src/acl.c 2020-06-09 12:19:30.000000000 +0200 @@ -732,10 +732,11 @@ * EEXIST: You are adding a key pattern after "*" was already added. This is * almost surely an error on the user side. * ENODEV: The password you are trying to remove from the user does not exist. - * EBADMSG: The hash you are trying to add is not a valid hash. + * EBADMSG: The hash you are trying to add is not a valid hash. */ int ACLSetUser(user *u, const char *op, ssize_t oplen) { if (oplen == -1) oplen = strlen(op); + if (oplen == 0) return C_OK; /* Empty string is a no-operation. */ if (!strcasecmp(op,"on")) { u->flags |= USER_FLAG_ENABLED; u->flags &= ~USER_FLAG_DISABLED; @@ -1297,7 +1298,7 @@ if (lines[i][0] == '\0') continue; /* Split into arguments */ - argv = sdssplitargs(lines[i],&argc); + argv = sdssplitlen(lines[i],sdslen(lines[i])," ",1,&argc); if (argv == NULL) { errors = sdscatprintf(errors, "%s:%d: unbalanced quotes in acl line. ", @@ -1329,11 +1330,14 @@ continue; } - /* Try to process the line using the fake user to validate iif - * the rules are able to apply cleanly. */ + /* Try to process the line using the fake user to validate if + * 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); int 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) { char *errmsg = ACLSetUserStringError(); errors = sdscatprintf(errors, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.0.4/src/aof.c new/redis-6.0.5/src/aof.c --- old/redis-6.0.4/src/aof.c 2020-05-28 12:18:38.000000000 +0200 +++ new/redis-6.0.5/src/aof.c 2020-06-09 12:19:30.000000000 +0200 @@ -611,19 +611,24 @@ } else if (cmd->proc == setCommand && argc > 3) { int i; 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 ++) { if (!strcasecmp(argv[i]->ptr, "ex")) exarg = argv[i+1]; if (!strcasecmp(argv[i]->ptr, "px")) pxarg = argv[i+1]; } serverAssert(!(exarg && pxarg)); - if (exarg) - buf = catAppendOnlyExpireAtCommand(buf,server.expireCommand,argv[1], - exarg); - if (pxarg) - buf = catAppendOnlyExpireAtCommand(buf,server.pexpireCommand,argv[1], - pxarg); + + if (exarg || pxarg) { + /* Translate SET [EX seconds][PX milliseconds] to SET and PEXPIREAT */ + buf = catAppendOnlyGenericCommand(buf,3,argv); + if (exarg) + buf = catAppendOnlyExpireAtCommand(buf,server.expireCommand,argv[1], + exarg); + if (pxarg) + buf = catAppendOnlyExpireAtCommand(buf,server.pexpireCommand,argv[1], + pxarg); + } else { + buf = catAppendOnlyGenericCommand(buf,argc,argv); + } } else { /* All the other commands don't need translation or need the * same translation already operated in the command vector diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.0.4/src/cluster.c new/redis-6.0.5/src/cluster.c --- old/redis-6.0.4/src/cluster.c 2020-05-28 12:18:38.000000000 +0200 +++ new/redis-6.0.5/src/cluster.c 2020-06-09 12:19:30.000000000 +0200 @@ -1463,7 +1463,10 @@ } } else { /* 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 * is a well known node in our cluster, otherwise we risk @@ -1472,7 +1475,12 @@ !(flags & CLUSTER_NODE_NOADDR) && !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); } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.0.4/src/config.h new/redis-6.0.5/src/config.h --- old/redis-6.0.4/src/config.h 2020-05-28 12:18:38.000000000 +0200 +++ new/redis-6.0.5/src/config.h 2020-06-09 12:19:30.000000000 +0200 @@ -133,12 +133,6 @@ /* Byte ordering detection */ #include <sys/types.h> /* This will likely define BYTE_ORDER */ -/* Define redis_sendfile. */ -#if defined(__linux__) || (defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_5)) -#define HAVE_SENDFILE 1 -ssize_t redis_sendfile(int out_fd, int in_fd, off_t offset, size_t count); -#endif - #ifndef BYTE_ORDER #if (BSD >= 199103) # include <machine/endian.h> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.0.4/src/multi.c new/redis-6.0.5/src/multi.c --- old/redis-6.0.4/src/multi.c 2020-05-28 12:18:38.000000000 +0200 +++ new/redis-6.0.5/src/multi.c 2020-06-09 12:19:30.000000000 +0200 @@ -58,6 +58,13 @@ multiCmd *mc; 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 = zrealloc(c->mstate.commands, sizeof(multiCmd)*(c->mstate.count+1)); mc = c->mstate.commands+c->mstate.count; @@ -128,6 +135,15 @@ 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 (server.lua_timedout) { + flagTransaction(c); + addReply(c, shared.slowscripterr); + return; + } + /* Check if we need to abort the EXEC because: * 1) Some WATCHed key was touched. * 2) There was a previous error while queueing commands. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.0.4/src/networking.c new/redis-6.0.5/src/networking.c --- old/redis-6.0.4/src/networking.c 2020-05-28 12:18:38.000000000 +0200 +++ new/redis-6.0.5/src/networking.c 2020-06-09 12:19:30.000000000 +0200 @@ -1019,7 +1019,6 @@ listNode *ln; listRewind(server.slaves,&li); while((ln = listNext(&li))) { - listNode *ln = listFirst(server.slaves); freeClient((client*)ln->value); } } @@ -1239,14 +1238,20 @@ /* Free the clietns marked as CLOSE_ASAP, return the number of clients * freed. */ int freeClientsInAsyncFreeQueue(void) { - int freed = listLength(server.clients_to_close); - while (listLength(server.clients_to_close)) { - listNode *ln = listFirst(server.clients_to_close); + int freed = 0; + listIter li; + listNode *ln; + + listRewind(server.clients_to_close,&li); + while ((ln = listNext(&li)) != NULL) { client *c = listNodeValue(ln); + if (c->flags & CLIENT_PROTECTED) continue; + c->flags &= ~CLIENT_CLOSE_ASAP; freeClient(c); listDelNode(server.clients_to_close,ln); + freed++; } return freed; } @@ -2522,7 +2527,7 @@ addReplyBulkCString(c,REDIS_VERSION); addReplyBulkCString(c,"proto"); - addReplyLongLong(c,3); + addReplyLongLong(c,ver); addReplyBulkCString(c,"id"); addReplyLongLong(c,c->id); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.0.4/src/replication.c new/redis-6.0.5/src/replication.c --- old/redis-6.0.4/src/replication.c 2020-05-28 12:18:38.000000000 +0200 +++ new/redis-6.0.5/src/replication.c 2020-06-09 12:19:30.000000000 +0200 @@ -1008,41 +1008,10 @@ } } -#if HAVE_SENDFILE -/* Implements redis_sendfile to transfer data between file descriptors and - * avoid transferring data to and from user space. - * - * The function prototype is just like sendfile(2) on Linux. in_fd is a file - * descriptor opened for reading and out_fd is a descriptor opened for writing. - * offset specifies where to start reading data from in_fd. count is the number - * of bytes to copy between the file descriptors. - * - * The return value is the number of bytes written to out_fd, if the transfer - * was successful. On error, -1 is returned, and errno is set appropriately. */ -ssize_t redis_sendfile(int out_fd, int in_fd, off_t offset, size_t count) { -#if defined(__linux__) - #include <sys/sendfile.h> - return sendfile(out_fd, in_fd, &offset, count); - -#elif defined(__APPLE__) - off_t len = count; - /* Notice that it may return -1 and errno is set to EAGAIN even if some - * bytes have been sent successfully and the len argument is set correctly - * when using a socket marked for non-blocking I/O. */ - if (sendfile(in_fd, out_fd, offset, &len, NULL, 0) == -1 && - errno != EAGAIN) return -1; - else - return (ssize_t)len; - -#endif - errno = ENOSYS; - return -1; -} -#endif - void sendBulkToSlave(connection *conn) { client *slave = connGetPrivateData(conn); - ssize_t nwritten; + char buf[PROTO_IOBUF_LEN]; + ssize_t nwritten, buflen; /* Before sending the RDB file, we send the preamble as configured by the * replication process. Currently the preamble is just the bulk count of @@ -1067,46 +1036,23 @@ } } - /* If the preamble was already transferred, send the RDB bulk data. - * try to use sendfile system call if supported, unless tls is enabled. - * fallback to normal read+write otherwise. */ - nwritten = 0; -#if HAVE_SENDFILE - if (!server.tls_replication) { - if ((nwritten = redis_sendfile(conn->fd,slave->repldbfd, - slave->repldboff,PROTO_IOBUF_LEN)) == -1) - { - if (errno != EAGAIN) { - serverLog(LL_WARNING,"Sendfile error sending DB to replica: %s", - strerror(errno)); - freeClient(slave); - } - return; - } + /* If the preamble was already transferred, send the RDB bulk data. */ + lseek(slave->repldbfd,slave->repldboff,SEEK_SET); + buflen = read(slave->repldbfd,buf,PROTO_IOBUF_LEN); + if (buflen <= 0) { + serverLog(LL_WARNING,"Read error sending DB to replica: %s", + (buflen == 0) ? "premature EOF" : strerror(errno)); + freeClient(slave); + return; } -#endif - if (!nwritten) { - ssize_t buflen; - char buf[PROTO_IOBUF_LEN]; - - lseek(slave->repldbfd,slave->repldboff,SEEK_SET); - buflen = read(slave->repldbfd,buf,PROTO_IOBUF_LEN); - if (buflen <= 0) { - serverLog(LL_WARNING,"Read error sending DB to replica: %s", - (buflen == 0) ? "premature EOF" : strerror(errno)); + if ((nwritten = connWrite(conn,buf,buflen)) == -1) { + if (connGetState(conn) != CONN_STATE_CONNECTED) { + serverLog(LL_WARNING,"Write error sending DB to replica: %s", + connGetLastError(conn)); freeClient(slave); - return; - } - if ((nwritten = connWrite(conn,buf,buflen)) == -1) { - if (connGetState(conn) != CONN_STATE_CONNECTED) { - serverLog(LL_WARNING,"Write error sending DB to replica: %s", - connGetLastError(conn)); - freeClient(slave); - } - return; } + return; } - slave->repldboff += nwritten; server.stat_net_output_bytes += nwritten; if (slave->repldboff == slave->repldbsize) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.0.4/src/server.c new/redis-6.0.5/src/server.c --- old/redis-6.0.4/src/server.c 2020-05-28 12:18:38.000000000 +0200 +++ new/redis-6.0.5/src/server.c 2020-06-09 12:19:30.000000000 +0200 @@ -776,11 +776,11 @@ 0,NULL,0,0,0,0,0,0}, {"watch",watchCommand,-2, - "no-script fast @transaction", + "no-script fast ok-loading ok-stale @transaction", 0,NULL,1,-1,1,0,0,0}, {"unwatch",unwatchCommand,1, - "no-script fast @transaction", + "no-script fast ok-loading ok-stale @transaction", 0,NULL,0,0,0,0,0,0}, {"cluster",clusterCommand,-2, @@ -3627,6 +3627,8 @@ c->cmd->proc != multiCommand && c->cmd->proc != execCommand && c->cmd->proc != discardCommand && + c->cmd->proc != watchCommand && + c->cmd->proc != unwatchCommand && !(c->cmd->proc == shutdownCommand && c->argc == 2 && tolower(((char*)c->argv[1]->ptr)[0]) == 'n') && diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.0.4/src/tls.c new/redis-6.0.5/src/tls.c --- old/redis-6.0.4/src/tls.c 2020-05-28 12:18:38.000000000 +0200 +++ new/redis-6.0.5/src/tls.c 2020-06-09 12:19:30.000000000 +0200 @@ -217,7 +217,7 @@ SSL_CTX_set_ecdh_auto(ctx, 1); #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)); serverLog(LL_WARNING, "Failed to load certificate: %s: %s", ctx_config->cert_file, errbuf); goto error; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.0.4/src/version.h new/redis-6.0.5/src/version.h --- old/redis-6.0.4/src/version.h 2020-05-28 12:18:38.000000000 +0200 +++ new/redis-6.0.5/src/version.h 2020-06-09 12:19:30.000000000 +0200 @@ -1 +1 @@ -#define REDIS_VERSION "6.0.4" +#define REDIS_VERSION "6.0.5" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.0.4/tests/integration/psync2-pingoff.tcl new/redis-6.0.5/tests/integration/psync2-pingoff.tcl --- old/redis-6.0.4/tests/integration/psync2-pingoff.tcl 2020-05-28 12:18:38.000000000 +0200 +++ new/redis-6.0.5/tests/integration/psync2-pingoff.tcl 2020-06-09 12:19:30.000000000 +0200 @@ -64,6 +64,7 @@ # make sure replication is still alive and kicking $R(1) incr x wait_for_condition 50 1000 { + [status $R(0) loading] == 0 && [$R(0) get x] == 1 } else { fail "replica didn't get incr" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.0.4/tests/unit/expire.tcl new/redis-6.0.5/tests/unit/expire.tcl --- old/redis-6.0.4/tests/unit/expire.tcl 2020-05-28 12:18:38.000000000 +0200 +++ new/redis-6.0.5/tests/unit/expire.tcl 2020-06-09 12:19:30.000000000 +0200 @@ -232,4 +232,14 @@ set ttl [r ttl foo] assert {$ttl <= 100 && $ttl > 90} } + + 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} + } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.0.4/tests/unit/multi.tcl new/redis-6.0.5/tests/unit/multi.tcl --- old/redis-6.0.4/tests/unit/multi.tcl 2020-05-28 12:18:38.000000000 +0200 +++ new/redis-6.0.5/tests/unit/multi.tcl 2020-06-09 12:19:30.000000000 +0200 @@ -363,6 +363,9 @@ set xx [r get xx] # make sure that either the whole transcation passed or none of it (we actually expect none) 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 $rd2 ping asdf set pong [$rd2 read] ++++++ redis.hashes ++++++ --- /var/tmp/diff_new_pack.jy8cH8/_old 2020-06-11 14:47:49.485928332 +0200 +++ /var/tmp/diff_new_pack.jy8cH8/_new 2020-06-11 14:47:49.489928344 +0200 @@ -106,3 +106,4 @@ hash redis-6.0.2.tar.gz sha256 9c37cd4228a57e82e7037094751c63349302b0b86c5e30b778a63a802dfd0109 http://download.redis.io/releases/redis-6.0.2.tar.gz hash redis-6.0.3.tar.gz sha256 bca46dce81fe92f7b2de4cf8ae41fbc4b94fbd5674def7f12c87e7f9165cbb3a http://download.redis.io/releases/redis-6.0.3.tar.gz hash redis-6.0.4.tar.gz sha256 3337005a1e0c3aa293c87c313467ea8ac11984921fab08807998ba765c9943de http://download.redis.io/releases/redis-6.0.4.tar.gz +hash redis-6.0.5.tar.gz sha256 42cf86a114d2a451b898fcda96acd4d01062a7dbaaad2801d9164a36f898f596 http://download.redis.io/releases/redis-6.0.5.tar.gz
