Hello community, here is the log from the commit of package redis for openSUSE:Factory checked in at 2020-03-25 23:43:34 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/redis (Old) and /work/SRC/openSUSE:Factory/.redis.new.3160 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "redis" Wed Mar 25 23:43:34 2020 rev:52 rq:788015 version:5.0.8 Changes: -------- --- /work/SRC/openSUSE:Factory/redis/redis.changes 2020-02-14 16:27:43.167267019 +0100 +++ /work/SRC/openSUSE:Factory/.redis.new.3160/redis.changes 2020-03-25 23:43:45.432002645 +0100 @@ -1,0 +2,36 @@ +Tue Mar 24 19:04:42 UTC 2020 - Thorsten Kukuk <ku...@suse.com> + +- Use the tmpfiles macros instead of calling systemd-tempfiles + direct and build wrong macro paths. + +------------------------------------------------------------------- +Wed Mar 18 02:18:24 UTC 2020 - Илья Индиго <i...@ilya.pp.ua> +- Refresh spec-file with spec-cleaner and manual optimizations + * Remove Group tag. + * Replace make by %make_build macros. +- Update to 5.0.8 + * https://raw.githubusercontent.com/antirez/redis/5.0.8/00-RELEASENOTES + * Fix Pi building needing -latomic, backport. + * Fix impl of aof-child whitelist SIGUSR1 feature. + * Fix ThreadSafeContext lock/unlock function names. + * XREADGROUP should propagate XCALIM/SETID in MULTI/EXEC. + * Fix client flags to be int64 in module.c. + * Fix small bugs related to replica and monitor ambiguity. + * Fix lua related memory leak. + * Simplify #6379 changes. + * Free allocated sds in pfdebugCommand() to avoid memory leak. + * Jump to right label on AOF parsing error. + * Free fakeclient argv on AOF error. + * Fix potential memory leak of rioWriteBulkStreamID(). + * Fix potential memory leak of clusterLoadConfig(). + * Fix bug on KEYS command where pattern starts with * followed by \x00. + * Blocking XREAD[GROUP] should always reply with valid data. + * XCLAIM: Create the consumer only on successful claims. + * Stream: Handle streamID-related edge cases. + * Fix ip and missing mode in RM_GetClusterNodeInfo(). + * Inline protocol: handle empty strings well. + * Mark extern definition of SDS_NOINIT in sds.h. + * Fix revisit CVE-2015-8080 vulnerability. + * Avoid sentinel changes promoted_slave to be its own replica. + +------------------------------------------------------------------- @@ -1252 +1287,0 @@ - Old: ---- redis-5.0.7.tar.gz New: ---- redis-5.0.8.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ redis.spec ++++++ --- /var/tmp/diff_new_pack.hQeQSZ/_old 2020-03-25 23:43:46.076002856 +0100 +++ /var/tmp/diff_new_pack.hQeQSZ/_new 2020-03-25 23:43:46.076002856 +0100 @@ -20,11 +20,10 @@ %define _log_dir %{_localstatedir}/log/%{name} %define _conf_dir %{_sysconfdir}/%{name} Name: redis -Version: 5.0.7 +Version: 5.0.8 Release: 0 Summary: Persistent key-value database License: BSD-3-Clause -Group: Productivity/Databases/Servers URL: https://redis.io Source0: http://download.redis.io/releases/redis-%{version}.tar.gz Source1: %{name}.logrotate @@ -68,7 +67,7 @@ %build export HOST=OBS # for reproducible builds -make %{?_smp_mflags} CFLAGS="%{optflags}" V=1 +%make_build CFLAGS="%{optflags}" %sysusers_generate_pre %{SOURCE9} redis %install @@ -100,7 +99,7 @@ install -Dm 0644 %{SOURCE1} %{buildroot}%{_sysconfdir}/logrotate.d/%{name} install -Dm 0644 %{SOURCE2} %{buildroot}%{_unitdir}/%{name}.target install -Dm 0644 %{SOURCE3} %{buildroot}%{_unitdir}/%{name}@.service -install -Dm 0644 %{SOURCE4} %{buildroot}%{_libexecdir}/tmpfiles.d/%{name}.conf +install -Dm 0644 %{SOURCE4} %{buildroot}%{_tmpfilesdir}/%{name}.conf install -Dm 0644 %{SOURCE7} %{buildroot}%{_unitdir}/%{name}-sentinel@.service install -Dm 0644 %{SOURCE8} %{buildroot}%{_unitdir}/%{name}-sentinel.target @@ -118,14 +117,14 @@ 'child process exited abnormally' -- sometimes it works. --------------------------------------------------- EOF -make %{?_smp_mflags} test || true +%make_build test || true %endif %pre -f redis.pre %service_add_pre redis.target redis@.service redis-sentinel.target redis-sentinel@.service %post -systemd-tmpfiles --create %{_libexecdir}/tmpfiles.d/%{name}.conf || true +%tmpfiles_create %{_tmpfilesdir}/%{name}.conf %service_add_post redis.target redis@.service redis-sentinel.target redis-sentinel@.service echo "See %{_docdir}/%{name}/README.SUSE to continue" @@ -143,7 +142,7 @@ %{_bindir}/%{name}-* %{_sbindir}/%{name}-* %{_sbindir}/rc%{name} -%{_libexecdir}/tmpfiles.d/%{name}.conf +%{_tmpfilesdir}/%{name}.conf %{_sysusersdir}/redis-user.conf %{_unitdir}/%{name}@.service %{_unitdir}/%{name}.target ++++++ redis-5.0.7.tar.gz -> redis-5.0.8.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-5.0.7/00-RELEASENOTES new/redis-5.0.8/00-RELEASENOTES --- old/redis-5.0.7/00-RELEASENOTES 2019-11-19 18:05:52.000000000 +0100 +++ new/redis-5.0.8/00-RELEASENOTES 2020-03-12 16:07:44.000000000 +0100 @@ -12,6 +12,104 @@ -------------------------------------------------------------------------------- ================================================================================ +Redis 5.0.8 Released Thu Mar 12 16:05:41 CET 2020 +================================================================================ + +Upgrade urgency HIGH: This release fixes security issues. + +This is a list of fixes in this release: + +Salvatore Sanfilippo in commit 2bea502d: + Merge pull request #6975 from dustinmm80/add-arm-latomic-linking +Dustin Collins in commit b5931405: + Fix Pi building needing -latomic, backport + 1 file changed, 9 insertions(+) + +srzhao in commit fd441300: + fix impl of aof-child whitelist SIGUSR1 feature. + 1 file changed, 5 insertions(+), 4 deletions(-) + +Ariel in commit 77ff332b: + fix ThreadSafeContext lock/unlock function names + 1 file changed, 2 insertions(+), 2 deletions(-) + +Guy Benoish in commit 4f0f799c: + XREADGROUP should propagate XCALIM/SETID in MULTI/EXEC + 1 file changed, 2 insertions(+), 2 deletions(-) + +Oran Agra in commit 0c1273c3: + Fix client flags to be int64 in module.c + 1 file changed, 3 insertions(+), 3 deletions(-) + +Guy Benoish in commit 708a4e8a: + Fix small bugs related to replica and monitor ambiguity + 2 files changed, 8 insertions(+), 6 deletions(-) + +WuYunlong in commit eac4115d: + Fix lua related memory leak. + 1 file changed, 1 insertion(+) + +antirez in commit d075df17: + Simplify #6379 changes. + 2 files changed, 4 insertions(+), 9 deletions(-) + +WuYunlong in commit 80a49c37: + Free allocated sds in pfdebugCommand() to avoid memory leak. + 1 file changed, 1 insertion(+) + +antirez in commit 60870d3a: + Jump to right label on AOF parsing error. + 1 file changed, 6 insertions(+), 4 deletions(-) + +antirez in commit d90f599b: + Free fakeclient argv on AOF error. + 1 file changed, 11 insertions(+), 3 deletions(-) + +WuYunlong in commit 8ee3bddf: + Fix potential memory leak of rioWriteBulkStreamID(). + 1 file changed, 4 insertions(+), 1 deletion(-) + +WuYunlong in commit 4780fe78: + Fix potential memory leak of clusterLoadConfig(). + 1 file changed, 20 insertions(+), 5 deletions(-) + +Leo Murillo in commit f3b77510: + Fix bug on KEYS command where pattern starts with * followed by \x00 (null char). + 1 file changed, 1 insertion(+), 1 deletion(-) + +Guy Benoish in commit 7f3fcedb: + Blocking XREAD[GROUP] should always reply with valid data (or timeout) + 3 files changed, 44 insertions(+), 10 deletions(-) + +antirez in commit f93b2fa5: + XCLAIM: Create the consumer only on successful claims. + 1 file changed, 4 insertions(+), 2 deletions(-) + +Guy Benoish in commit 89682d96: + Stream: Handle streamID-related edge cases + 4 files changed, 54 insertions(+), 4 deletions(-) + +antirez in commit 920e108f: + Fix ip and missing mode in RM_GetClusterNodeInfo(). + 1 file changed, 5 insertions(+), 2 deletions(-) + +antirez in commit 7569b210: + Inline protocol: handle empty strings well. + 1 file changed, 2 insertions(+), 6 deletions(-) + +Khem Raj in commit 3c610b4e: + Mark extern definition of SDS_NOINIT in sds.h + 1 file changed, 1 insertion(+), 1 deletion(-) + +Seunghoon Woo in commit 16b2d07f: + [FIX] revisit CVE-2015-8080 vulnerability + 1 file changed, 6 insertions(+), 4 deletions(-) + +yz1509 in commit 19f33585: + avoid sentinel changes promoted_slave to be its own replica. + 1 file changed, 1 insertion(+), 1 deletion(-) + +================================================================================ Redis 5.0.7 Released Tue Nov 19 17:52:44 CET 2019 ================================================================================ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-5.0.7/deps/lua/src/lua_struct.c new/redis-5.0.8/deps/lua/src/lua_struct.c --- old/redis-5.0.7/deps/lua/src/lua_struct.c 2019-11-19 18:05:52.000000000 +0100 +++ new/redis-5.0.8/deps/lua/src/lua_struct.c 2020-03-12 16:07:44.000000000 +0100 @@ -89,12 +89,14 @@ } Header; -static int getnum (const char **fmt, int df) { +static int getnum (lua_State *L, const char **fmt, int df) { if (!isdigit(**fmt)) /* no number? */ return df; /* return default value */ else { int a = 0; do { + if (a > (INT_MAX / 10) || a * 10 > (INT_MAX - (**fmt - '0'))) + luaL_error(L, "integral size overflow"); a = a*10 + *((*fmt)++) - '0'; } while (isdigit(**fmt)); return a; @@ -115,9 +117,9 @@ case 'f': return sizeof(float); case 'd': return sizeof(double); case 'x': return 1; - case 'c': return getnum(fmt, 1); + case 'c': return getnum(L, fmt, 1); case 'i': case 'I': { - int sz = getnum(fmt, sizeof(int)); + int sz = getnum(L, fmt, sizeof(int)); if (sz > MAXINTSIZE) luaL_error(L, "integral size %d is larger than limit of %d", sz, MAXINTSIZE); @@ -150,7 +152,7 @@ case '>': h->endian = BIG; return; case '<': h->endian = LITTLE; return; case '!': { - int a = getnum(fmt, MAXALIGN); + int a = getnum(L, fmt, MAXALIGN); if (!isp2(a)) luaL_error(L, "alignment %d is not a power of 2", a); h->align = a; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-5.0.7/src/Makefile new/redis-5.0.8/src/Makefile --- old/redis-5.0.7/src/Makefile 2019-11-19 18:05:52.000000000 +0100 +++ new/redis-5.0.8/src/Makefile 2020-03-12 16:07:44.000000000 +0100 @@ -77,6 +77,15 @@ FINAL_LIBS=-lm DEBUG=-g -ggdb +# Linux ARM needs -latomic at linking time +ifneq (,$(filter aarch64 armv,$(uname_M))) + FINAL_LIBS+=-latomic +else +ifneq (,$(findstring armv,$(uname_M))) + FINAL_LIBS+=-latomic +endif +endif + ifeq ($(uname_S),SunOS) # SunOS ifneq ($(@@),32bit) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-5.0.7/src/aof.c new/redis-5.0.8/src/aof.c --- old/redis-5.0.7/src/aof.c 2019-11-19 18:05:52.000000000 +0100 +++ new/redis-5.0.8/src/aof.c 2020-03-12 16:07:44.000000000 +0100 @@ -774,18 +774,26 @@ argc = atoi(buf+1); if (argc < 1) goto fmterr; + /* Load the next command in the AOF as our fake client + * argv. */ argv = zmalloc(sizeof(robj*)*argc); fakeClient->argc = argc; fakeClient->argv = argv; for (j = 0; j < argc; j++) { - if (fgets(buf,sizeof(buf),fp) == NULL) { + /* Parse the argument len. */ + char *readres = fgets(buf,sizeof(buf),fp); + if (readres == NULL || buf[0] != '$') { fakeClient->argc = j; /* Free up to j-1. */ freeFakeClientArgv(fakeClient); - goto readerr; + if (readres == NULL) + goto readerr; + else + goto fmterr; } - if (buf[0] != '$') goto fmterr; len = strtol(buf+1,NULL,10); + + /* Read it into a string object. */ argsds = sdsnewlen(SDS_NOINIT,len); if (len && fread(argsds,len,1,fp) == 0) { sdsfree(argsds); @@ -794,10 +802,12 @@ goto readerr; } argv[j] = createObject(OBJ_STRING,argsds); + + /* Discard CRLF. */ if (fread(buf,2,1,fp) == 0) { fakeClient->argc = j+1; /* Free up to j. */ freeFakeClientArgv(fakeClient); - goto readerr; /* discard CRLF */ + goto readerr; } } @@ -1127,7 +1137,7 @@ int retval; sds replyid = sdscatfmt(sdsempty(),"%U-%U",id->ms,id->seq); - if ((retval = rioWriteBulkString(r,replyid,sdslen(replyid))) == 0) return 0; + retval = rioWriteBulkString(r,replyid,sdslen(replyid)); sdsfree(replyid); return retval; } @@ -1782,14 +1792,15 @@ serverLog(LL_VERBOSE, "Background AOF rewrite signal handler took %lldus", ustime()-now); } else if (!bysignal && exitcode != 0) { + server.aof_lastbgrewrite_status = C_ERR; + + serverLog(LL_WARNING, + "Background AOF rewrite terminated with error"); + } else { /* SIGUSR1 is whitelisted, so we have a way to kill a child without * tirggering an error condition. */ if (bysignal != SIGUSR1) server.aof_lastbgrewrite_status = C_ERR; - serverLog(LL_WARNING, - "Background AOF rewrite terminated with error"); - } else { - server.aof_lastbgrewrite_status = C_ERR; serverLog(LL_WARNING, "Background AOF rewrite terminated by signal %d", bysignal); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-5.0.7/src/blocked.c new/redis-5.0.8/src/blocked.c --- old/redis-5.0.7/src/blocked.c 2019-11-19 18:05:52.000000000 +0100 +++ new/redis-5.0.8/src/blocked.c 2020-03-12 16:07:44.000000000 +0100 @@ -429,7 +429,7 @@ if (streamCompareID(&s->last_id, gt) > 0) { streamID start = *gt; - start.seq++; /* Can't overflow, it's an uint64_t */ + streamIncrID(&start); /* Lookup the consumer for the group, if any. */ streamConsumer *consumer = NULL; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-5.0.7/src/cluster.c new/redis-5.0.8/src/cluster.c --- old/redis-5.0.7/src/cluster.c 2019-11-19 18:05:52.000000000 +0100 +++ new/redis-5.0.8/src/cluster.c 2020-03-12 16:07:44.000000000 +0100 @@ -157,7 +157,10 @@ } /* Regular config lines have at least eight fields */ - if (argc < 8) goto fmterr; + if (argc < 8) { + sdsfreesplitres(argv,argc); + goto fmterr; + } /* Create this node if it does not exist */ n = clusterLookupNode(argv[0]); @@ -166,7 +169,10 @@ clusterAddNode(n); } /* Address and port */ - if ((p = strrchr(argv[1],':')) == NULL) goto fmterr; + if ((p = strrchr(argv[1],':')) == NULL) { + sdsfreesplitres(argv,argc); + goto fmterr; + } *p = '\0'; memcpy(n->ip,argv[1],strlen(argv[1])+1); char *port = p+1; @@ -247,7 +253,10 @@ *p = '\0'; direction = p[1]; /* Either '>' or '<' */ slot = atoi(argv[j]+1); - if (slot < 0 || slot >= CLUSTER_SLOTS) goto fmterr; + if (slot < 0 || slot >= CLUSTER_SLOTS) { + sdsfreesplitres(argv,argc); + goto fmterr; + } p += 3; cn = clusterLookupNode(p); if (!cn) { @@ -267,8 +276,12 @@ } else { start = stop = atoi(argv[j]); } - if (start < 0 || start >= CLUSTER_SLOTS) goto fmterr; - if (stop < 0 || stop >= CLUSTER_SLOTS) goto fmterr; + if (start < 0 || start >= CLUSTER_SLOTS || + stop < 0 || stop >= CLUSTER_SLOTS) + { + sdsfreesplitres(argv,argc); + goto fmterr; + } while(start <= stop) clusterAddSlot(n, start++); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-5.0.7/src/db.c new/redis-5.0.8/src/db.c --- old/redis-5.0.7/src/db.c 2019-11-19 18:05:52.000000000 +0100 +++ new/redis-5.0.8/src/db.c 2020-03-12 16:07:44.000000000 +0100 @@ -542,7 +542,7 @@ void *replylen = addDeferredMultiBulkLength(c); di = dictGetSafeIterator(c->db->dict); - allkeys = (pattern[0] == '*' && pattern[1] == '\0'); + allkeys = (pattern[0] == '*' && plen == 1); while((de = dictNext(di)) != NULL) { sds key = dictGetKey(de); robj *keyobj; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-5.0.7/src/hyperloglog.c new/redis-5.0.8/src/hyperloglog.c --- old/redis-5.0.7/src/hyperloglog.c 2019-11-19 18:05:52.000000000 +0100 +++ new/redis-5.0.8/src/hyperloglog.c 2020-03-12 16:07:44.000000000 +0100 @@ -1535,6 +1535,7 @@ sds decoded = sdsempty(); if (hdr->encoding != HLL_SPARSE) { + sdsfree(decoded); addReplyError(c,"HLL encoding is not sparse"); return; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-5.0.7/src/module.c new/redis-5.0.8/src/module.c --- old/redis-5.0.7/src/module.c 2019-11-19 18:05:52.000000000 +0100 +++ new/redis-5.0.8/src/module.c 2020-03-12 16:07:44.000000000 +0100 @@ -647,9 +647,9 @@ * flags into the command flags used by the Redis core. * * It returns the set of flags, or -1 if unknown flags are found. */ -int commandFlagsFromString(char *s) { +int64_t commandFlagsFromString(char *s) { int count, j; - int flags = 0; + int64_t flags = 0; sds *tokens = sdssplitlen(s,strlen(s)," ",1,&count); for (j = 0; j < count; j++) { char *t = tokens[j]; @@ -727,7 +727,7 @@ * other reason. */ int RM_CreateCommand(RedisModuleCtx *ctx, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep) { - int flags = strflags ? commandFlagsFromString((char*)strflags) : 0; + int64_t flags = strflags ? commandFlagsFromString((char*)strflags) : 0; if (flags == -1) return REDISMODULE_ERR; if ((flags & CMD_MODULE_NO_CLUSTER) && server.cluster_enabled) return REDISMODULE_ERR; @@ -4008,9 +4008,9 @@ * * To call non-reply APIs, the thread safe context must be prepared with: * - * RedisModule_ThreadSafeCallStart(ctx); + * RedisModule_ThreadSafeContextLock(ctx); * ... make your call here ... - * RedisModule_ThreadSafeCallStop(ctx); + * RedisModule_ThreadSafeContextUnlock(ctx); * * This is not needed when using `RedisModule_Reply*` functions, assuming * that a blocked client was used when the context was created, otherwise @@ -4378,10 +4378,13 @@ UNUSED(ctx); clusterNode *node = clusterLookupNode(id); - if (node->flags & (CLUSTER_NODE_NOADDR|CLUSTER_NODE_HANDSHAKE)) + if (node == NULL || + node->flags & (CLUSTER_NODE_NOADDR|CLUSTER_NODE_HANDSHAKE)) + { return REDISMODULE_ERR; + } - if (ip) memcpy(ip,node->name,REDISMODULE_NODE_ID_LEN); + if (ip) strncpy(ip,node->ip,NET_IP_STR_LEN); if (master_id) { /* If the information is not available, the function will set the diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-5.0.7/src/networking.c new/redis-5.0.8/src/networking.c --- old/redis-5.0.7/src/networking.c 2019-11-19 18:05:52.000000000 +0100 +++ new/redis-5.0.8/src/networking.c 2020-03-12 16:07:44.000000000 +0100 @@ -918,7 +918,7 @@ /* We need to remember the time when we started to have zero * attached slaves, as after some time we'll free the replication * backlog. */ - if (c->flags & CLIENT_SLAVE && listLength(server.slaves) == 0) + if (getClientType(c) == CLIENT_TYPE_SLAVE && listLength(server.slaves) == 0) server.repl_no_slaves_since = server.unixtime; refreshGoodSlavesCount(); } @@ -1030,8 +1030,8 @@ * just deliver as much data as it is possible to deliver. * * Moreover, we also send as much as possible if the client is - * a slave (otherwise, on high-speed traffic, the replication - * buffer will grow indefinitely) */ + * a slave or a monitor (otherwise, on high-speed traffic, the + * replication/output buffer will grow indefinitely) */ if (totwritten > NET_MAX_WRITES_PER_EVENT && (server.maxmemory == 0 || zmalloc_used_memory() < server.maxmemory) && @@ -1216,7 +1216,7 @@ /* Newline from slaves can be used to refresh the last ACK time. * This is useful for a slave to ping back while loading a big * RDB file. */ - if (querylen == 0 && c->flags & CLIENT_SLAVE) + if (querylen == 0 && getClientType(c) == CLIENT_TYPE_SLAVE) c->repl_ack_time = server.unixtime; /* Move querybuffer position to the next query in the buffer. */ @@ -1230,12 +1230,8 @@ /* Create redis objects for all arguments. */ for (c->argc = 0, j = 0; j < argc; j++) { - if (sdslen(argv[j])) { - c->argv[c->argc] = createObject(OBJ_STRING,argv[j]); - c->argc++; - } else { - sdsfree(argv[j]); - } + c->argv[c->argc] = createObject(OBJ_STRING,argv[j]); + c->argc++; } zfree(argv); return C_OK; @@ -2037,12 +2033,14 @@ * * The function will return one of the following: * CLIENT_TYPE_NORMAL -> Normal client - * CLIENT_TYPE_SLAVE -> Slave or client executing MONITOR command + * CLIENT_TYPE_SLAVE -> Slave * CLIENT_TYPE_PUBSUB -> Client subscribed to Pub/Sub channels * CLIENT_TYPE_MASTER -> The client representing our replication master. */ int getClientType(client *c) { if (c->flags & CLIENT_MASTER) return CLIENT_TYPE_MASTER; + /* Even though MONITOR clients are marked as replicas, we + * want the expose them as normal clients. */ if ((c->flags & CLIENT_SLAVE) && !(c->flags & CLIENT_MONITOR)) return CLIENT_TYPE_SLAVE; if (c->flags & CLIENT_PUBSUB) return CLIENT_TYPE_PUBSUB; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-5.0.7/src/scripting.c new/redis-5.0.8/src/scripting.c --- old/redis-5.0.7/src/scripting.c 2019-11-19 18:05:52.000000000 +0100 +++ new/redis-5.0.8/src/scripting.c 2020-03-12 16:07:44.000000000 +0100 @@ -2213,6 +2213,7 @@ ldbLog(sdscatfmt(sdsempty(),"<error> %s",lua_tostring(lua,-1))); lua_pop(lua,1); sdsfree(code); + sdsfree(expr); return; } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-5.0.7/src/sds.h new/redis-5.0.8/src/sds.h --- old/redis-5.0.7/src/sds.h 2019-11-19 18:05:52.000000000 +0100 +++ new/redis-5.0.8/src/sds.h 2020-03-12 16:07:44.000000000 +0100 @@ -34,7 +34,7 @@ #define __SDS_H #define SDS_MAX_PREALLOC (1024*1024) -const char *SDS_NOINIT; +extern const char *SDS_NOINIT; #include <sys/types.h> #include <stdarg.h> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-5.0.7/src/sentinel.c new/redis-5.0.8/src/sentinel.c --- old/redis-5.0.7/src/sentinel.c 2019-11-19 18:05:52.000000000 +0100 +++ new/redis-5.0.8/src/sentinel.c 2020-03-12 16:07:44.000000000 +0100 @@ -4270,7 +4270,7 @@ sentinelRedisInstance *slave = dictGetVal(de); int retval; - if (slave->flags & (SRI_RECONF_DONE|SRI_RECONF_SENT)) continue; + if (slave->flags & (SRI_PROMOTED|SRI_RECONF_DONE|SRI_RECONF_SENT)) continue; if (slave->link->disconnected) continue; retval = sentinelSendSlaveOf(slave, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-5.0.7/src/server.c new/redis-5.0.8/src/server.c --- old/redis-5.0.7/src/server.c 2019-11-19 18:05:52.000000000 +0100 +++ new/redis-5.0.8/src/server.c 2020-03-12 16:07:44.000000000 +0100 @@ -821,7 +821,7 @@ time_t now = now_ms/1000; if (server.maxidletime && - !(c->flags & CLIENT_SLAVE) && /* no timeout for slaves */ + !(c->flags & CLIENT_SLAVE) && /* no timeout for slaves and monitors */ !(c->flags & CLIENT_MASTER) && /* no timeout for masters */ !(c->flags & CLIENT_BLOCKED) && /* no timeout for BLPOP */ !(c->flags & CLIENT_PUBSUB) && /* no timeout for Pub/Sub clients */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-5.0.7/src/stream.h new/redis-5.0.8/src/stream.h --- old/redis-5.0.7/src/stream.h 2019-11-19 18:05:52.000000000 +0100 +++ new/redis-5.0.8/src/stream.h 2020-03-12 16:07:44.000000000 +0100 @@ -109,5 +109,6 @@ streamNACK *streamCreateNACK(streamConsumer *consumer); void streamDecodeID(void *buf, streamID *id); int streamCompareID(streamID *a, streamID *b); +void streamIncrID(streamID *id); #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-5.0.7/src/t_stream.c new/redis-5.0.8/src/t_stream.c --- old/redis-5.0.7/src/t_stream.c 2019-11-19 18:05:52.000000000 +0100 +++ new/redis-5.0.8/src/t_stream.c 2020-03-12 16:07:44.000000000 +0100 @@ -67,6 +67,21 @@ zfree(s); } +/* Set 'id' to be its successor streamID */ +void streamIncrID(streamID *id) { + if (id->seq == UINT64_MAX) { + if (id->ms == UINT64_MAX) { + /* Special case where 'id' is the last possible streamID... */ + id->ms = id->seq = 0; + } else { + id->ms++; + id->seq = 0; + } + } else { + id->seq++; + } +} + /* Generate the next stream item ID given the previous one. If the current * milliseconds Unix time is greater than the previous one, just use this * as time part and start with sequence part of zero. Otherwise we use the @@ -77,8 +92,8 @@ new_id->ms = ms; new_id->seq = 0; } else { - new_id->ms = last_id->ms; - new_id->seq = last_id->seq+1; + *new_id = *last_id; + streamIncrID(new_id); } } @@ -776,6 +791,16 @@ return deleted; } +/* Get the last valid (non-tombstone) streamID of 's'. */ +void streamLastValidID(stream *s, streamID *maxid) +{ + streamIterator si; + streamIteratorStart(&si,s,NULL,NULL,1); + int64_t numfields; + streamIteratorGetID(&si,maxid,&numfields); + streamIteratorStop(&si); +} + /* Emit a reply in the client output buffer by formatting a Stream ID * in the standard <ms>-<seq> format, using the simple string protocol * of REPL. */ @@ -817,7 +842,7 @@ argv[11] = createStringObject("JUSTID",6); argv[12] = createStringObject("LASTID",6); argv[13] = createObjectFromStreamID(&group->last_id); - propagate(server.xclaimCommand,c->db->id,argv,14,PROPAGATE_AOF|PROPAGATE_REPL); + alsoPropagate(server.xclaimCommand,c->db->id,argv,14,PROPAGATE_AOF|PROPAGATE_REPL); decrRefCount(argv[0]); decrRefCount(argv[3]); decrRefCount(argv[4]); @@ -844,7 +869,7 @@ argv[2] = key; argv[3] = groupname; argv[4] = createObjectFromStreamID(&group->last_id); - propagate(server.xgroupCommand,c->db->id,argv,5,PROPAGATE_AOF|PROPAGATE_REPL); + alsoPropagate(server.xgroupCommand,c->db->id,argv,5,PROPAGATE_AOF|PROPAGATE_REPL); decrRefCount(argv[0]); decrRefCount(argv[1]); decrRefCount(argv[4]); @@ -1233,6 +1258,13 @@ if ((o = streamTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return; s = o->ptr; + /* Return ASAP if the stream has reached the last possible ID */ + if (s->last_id.ms == UINT64_MAX && s->last_id.seq == UINT64_MAX) { + addReplyError(c,"The stream has exhausted the last possible ID, " + "unable to add more items"); + return; + } + /* Append using the low level function and return the ID. */ if (streamAppendItem(s,c->argv+field_pos,(c->argc-field_pos)/2, &id, id_given ? &id : NULL) @@ -1496,20 +1528,23 @@ { serve_synchronously = 1; serve_history = 1; - } else { + } else if (s->length) { /* We also want to serve a consumer in a consumer group * synchronously in case the group top item delivered is smaller * than what the stream has inside. */ - streamID *last = &groups[i]->last_id; - if (s->length && (streamCompareID(&s->last_id, last) > 0)) { + streamID maxid, *last = &groups[i]->last_id; + streamLastValidID(s, &maxid); + if (streamCompareID(&maxid, last) > 0) { serve_synchronously = 1; *gt = *last; } } - } else { + } else if (s->length) { /* For consumers without a group, we serve synchronously if we can * actually provide at least one item from the stream. */ - if (s->length && (streamCompareID(&s->last_id, gt) > 0)) { + streamID maxid; + streamLastValidID(s, &maxid); + if (streamCompareID(&maxid, gt) > 0) { serve_synchronously = 1; } } @@ -1521,7 +1556,7 @@ * so start from the next ID, since we want only messages with * IDs greater than start. */ streamID start = *gt; - start.seq++; /* uint64_t can't overflow in this context. */ + streamIncrID(&start); /* Emit the two elements sub-array consisting of the name * of the stream and the data we extracted from it. */ @@ -1858,11 +1893,7 @@ * item, otherwise the fundamental ID monotonicity assumption is violated. */ if (s->length > 0) { streamID maxid; - streamIterator si; - streamIteratorStart(&si,s,NULL,NULL,1); - int64_t numfields; - streamIteratorGetID(&si,&maxid,&numfields); - streamIteratorStop(&si); + streamLastValidID(s,&maxid); if (streamCompareID(&id,&maxid) < 0) { addReplyError(c,"The ID specified in XSETID is smaller than the " @@ -2233,7 +2264,7 @@ } /* Do the actual claiming. */ - streamConsumer *consumer = streamLookupConsumer(group,c->argv[3]->ptr,1); + streamConsumer *consumer = NULL; void *arraylenptr = addDeferredMultiBulkLength(c); size_t arraylen = 0; for (int j = 5; j <= last_id_arg; j++) { @@ -2285,9 +2316,11 @@ if (nack->consumer) raxRemove(nack->consumer->pel,buf,sizeof(buf),NULL); /* Update the consumer and idle time. */ + if (consumer == NULL) + consumer = streamLookupConsumer(group,c->argv[3]->ptr,1); nack->consumer = consumer; nack->delivery_time = deliverytime; - /* Set the delivery attempts counter if given, otherwise + /* Set the delivery attempts counter if given, otherwise * autoincrement unless JUSTID option provided */ if (retrycount >= 0) { nack->delivery_count = retrycount; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-5.0.7/src/version.h new/redis-5.0.8/src/version.h --- old/redis-5.0.7/src/version.h 2019-11-19 18:05:52.000000000 +0100 +++ new/redis-5.0.8/src/version.h 2020-03-12 16:07:44.000000000 +0100 @@ -1 +1 @@ -#define REDIS_VERSION "5.0.7" +#define REDIS_VERSION "5.0.8" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-5.0.7/tests/unit/type/stream-cgroups.tcl new/redis-5.0.8/tests/unit/type/stream-cgroups.tcl --- old/redis-5.0.7/tests/unit/type/stream-cgroups.tcl 2019-11-19 18:05:52.000000000 +0100 +++ new/redis-5.0.8/tests/unit/type/stream-cgroups.tcl 2020-03-12 16:07:44.000000000 +0100 @@ -147,6 +147,20 @@ assert {[lindex $res 0 1 1] == {2-0 {field1 B}}} } + test {Blocking XREADGROUP will not reply with an empty array} { + r del mystream + r XGROUP CREATE mystream mygroup $ MKSTREAM + r XADD mystream 666 f v + set res [r XREADGROUP GROUP mygroup Alice BLOCK 10 STREAMS mystream ">"] + assert {[lindex $res 0 1 0] == {666-0 {f v}}} + r XADD mystream 667 f2 v2 + r XDEL mystream 667 + set rd [redis_deferring_client] + $rd XREADGROUP GROUP mygroup Alice BLOCK 10 STREAMS mystream ">" + after 20 + assert {[$rd read] == {}} ;# before the fix, client didn't even block, but was served synchronously with {mystream {}} + } + test {XCLAIM can claim PEL items from another consumer} { # Add 3 items into the stream, and create a consumer group r del mystream diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-5.0.7/tests/unit/type/stream.tcl new/redis-5.0.8/tests/unit/type/stream.tcl --- old/redis-5.0.7/tests/unit/type/stream.tcl 2019-11-19 18:05:52.000000000 +0100 +++ new/redis-5.0.8/tests/unit/type/stream.tcl 2020-03-12 16:07:44.000000000 +0100 @@ -191,6 +191,17 @@ assert {[lindex $res 0 1 0 1] eq {old abcd1234}} } + test {Blocking XREAD will not reply with an empty array} { + r del s1 + r XADD s1 666 f v + r XADD s1 667 f2 v2 + r XDEL s1 667 + set rd [redis_deferring_client] + $rd XREAD BLOCK 10 STREAMS s1 666 + after 20 + assert {[$rd read] == {}} ;# before the fix, client didn't even block, but was served synchronously with {s1 {}} + } + test "XREAD: XADD + DEL should not awake client" { set rd [redis_deferring_client] r del s1 @@ -328,6 +339,33 @@ assert_equal [r xrevrange teststream2 1234567891245 -] {{1234567891240-0 {key1 value2}} {1234567891230-0 {key1 value1}}} } + + test {XREAD streamID edge (no-blocking)} { + r del x + r XADD x 1-1 f v + r XADD x 1-18446744073709551615 f v + r XADD x 2-1 f v + set res [r XREAD BLOCK 0 STREAMS x 1-18446744073709551615] + assert {[lindex $res 0 1 0] == {2-1 {f v}}} + } + + test {XREAD streamID edge (blocking)} { + r del x + set rd [redis_deferring_client] + $rd XREAD BLOCK 0 STREAMS x 1-18446744073709551615 + r XADD x 1-1 f v + r XADD x 1-18446744073709551615 f v + r XADD x 2-1 f v + set res [$rd read] + assert {[lindex $res 0 1 0] == {2-1 {f v}}} + } + + test {XADD streamID edge} { + r del x + r XADD x 2577343934890-18446744073709551615 f v ;# we need the timestamp to be in the future + r XADD x * f2 v2 + assert_equal [r XRANGE x - +] {{2577343934890-18446744073709551615 {f v}} {2577343934891-0 {f2 v2}}} + } } start_server {tags {"stream"} overrides {appendonly yes}} {