Hello community, here is the log from the commit of package redis for openSUSE:Leap:15.2 checked in at 2020-04-28 20:11:06 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Leap:15.2/redis (Old) and /work/SRC/openSUSE:Leap:15.2/.redis.new.2738 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "redis" Tue Apr 28 20:11:06 2020 rev:43 rq:797725 version:5.0.9 Changes: -------- --- /work/SRC/openSUSE:Leap:15.2/redis/redis.changes 2020-03-26 05:42:17.935307401 +0100 +++ /work/SRC/openSUSE:Leap:15.2/.redis.new.2738/redis.changes 2020-04-28 20:11:07.132529482 +0200 @@ -1,0 +2,9 @@ +Sat Apr 18 07:57:40 UTC 2020 - Andreas Stieger <andreas.stie...@gmx.de> + +- redis 5.0.9: + * Critical fix when Streams with AOF ore replicas are used: + Prevent reprocesing some entries upon restart + * Speed improvement: Clients blocked on the same key are now + unblocked on O(1) time + +------------------------------------------------------------------- @@ -8,0 +18 @@ + Old: ---- redis-5.0.8.tar.gz New: ---- redis-5.0.9.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ redis.spec ++++++ --- /var/tmp/diff_new_pack.63eLna/_old 2020-04-28 20:11:07.748530761 +0200 +++ /var/tmp/diff_new_pack.63eLna/_new 2020-04-28 20:11:07.756530777 +0200 @@ -20,7 +20,7 @@ %define _log_dir %{_localstatedir}/log/%{name} %define _conf_dir %{_sysconfdir}/%{name} Name: redis -Version: 5.0.8 +Version: 5.0.9 Release: 0 Summary: Persistent key-value database License: BSD-3-Clause ++++++ redis-5.0.8.tar.gz -> redis-5.0.9.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-5.0.8/00-RELEASENOTES new/redis-5.0.9/00-RELEASENOTES --- old/redis-5.0.8/00-RELEASENOTES 2020-03-12 16:07:44.000000000 +0100 +++ new/redis-5.0.9/00-RELEASENOTES 2020-04-17 12:45:57.000000000 +0200 @@ -12,6 +12,27 @@ -------------------------------------------------------------------------------- ================================================================================ +Redis 5.0.9 Released Thu Apr 17 12:41:00 CET 2020 +================================================================================ + +Upgrade urgency:CRITICAL if you use Streams with AOF ore replicas. + Otherwise the upgrade urgency is LOW. + +This release has a speed improvement and a critical fix: + + * FIX: XREADGROUP when fetching data in a blocking way, would not + emit the XCLAIM in the AOF file and to replicas. This means + that the last ID is not updated, and that restarting the server + will have the effect of reprocessing some entries. + * NEW: Clients blocked on the same key are now unblocked on + O(1) time. Backported from Redis 6. + +Commits: + + 1fc8ef81a Fix XCLAIM propagation in AOF/replicas for blocking XREADGROUP. + a5e24eabc Speedup: unblock clients on keys in O(1). + +================================================================================ Redis 5.0.8 Released Thu Mar 12 16:05:41 CET 2020 ================================================================================ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-5.0.8/src/adlist.c new/redis-5.0.9/src/adlist.c --- old/redis-5.0.8/src/adlist.c 2020-03-12 16:07:44.000000000 +0100 +++ new/redis-5.0.9/src/adlist.c 2020-04-17 12:45:57.000000000 +0200 @@ -327,12 +327,11 @@ } /* Rotate the list removing the tail node and inserting it to the head. */ -void listRotate(list *list) { - listNode *tail = list->tail; - +void listRotateTailToHead(list *list) { if (listLength(list) <= 1) return; /* Detach current tail */ + listNode *tail = list->tail; list->tail = tail->prev; list->tail->next = NULL; /* Move it as head */ @@ -342,6 +341,21 @@ list->head = tail; } +/* Rotate the list removing the head node and inserting it to the tail. */ +void listRotateHeadToTail(list *list) { + if (listLength(list) <= 1) return; + + listNode *head = list->head; + /* Detach current head */ + list->head = head->next; + list->head->prev = NULL; + /* Move it as tail */ + list->tail->next = head; + head->next = NULL; + head->prev = list->tail; + list->tail = head; +} + /* Add all the elements of the list 'o' at the end of the * list 'l'. The list 'other' remains empty but otherwise valid. */ void listJoin(list *l, list *o) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-5.0.8/src/adlist.h new/redis-5.0.9/src/adlist.h --- old/redis-5.0.8/src/adlist.h 2020-03-12 16:07:44.000000000 +0100 +++ new/redis-5.0.9/src/adlist.h 2020-04-17 12:45:57.000000000 +0200 @@ -85,7 +85,8 @@ listNode *listIndex(list *list, long index); void listRewind(list *list, listIter *li); void listRewindTail(list *list, listIter *li); -void listRotate(list *list); +void listRotateTailToHead(list *list); +void listRotateHeadToTail(list *list); void listJoin(list *l, list *o); /* Directions for iterators */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-5.0.8/src/blocked.c new/redis-5.0.9/src/blocked.c --- old/redis-5.0.8/src/blocked.c 2020-03-12 16:07:44.000000000 +0100 +++ new/redis-5.0.9/src/blocked.c 2020-04-17 12:45:57.000000000 +0200 @@ -67,6 +67,21 @@ int serveClientBlockedOnList(client *receiver, robj *key, robj *dstkey, redisDb *db, robj *value, int where); +/* This structure represents the blocked key information that we store + * in the client structure. Each client blocked on keys, has a + * client->bpop.keys hash table. The keys of the hash table are Redis + * keys pointers to 'robj' structures. The value is this structure. + * The structure has two goals: firstly we store the list node that this + * client uses to be listed in the database "blocked clients for this key" + * list, so we can later unblock in O(1) without a list scan. + * Secondly for certain blocking types, we have additional info. Right now + * the only use for additional info we have is when clients are blocked + * on streams, as we have to remember the ID it blocked for. */ +typedef struct bkinfo { + listNode *listnode; /* List node for db->blocking_keys[key] list. */ + streamID stream_id; /* Stream ID if we blocked in a stream. */ +} bkinfo; + /* Get a timeout value from an object and store it into 'timeout'. * The final timeout is always stored as milliseconds as a time where the * timeout will expire, however the parsing is performed according to @@ -291,8 +306,7 @@ if (receiver->btype != BLOCKED_LIST) { /* Put at the tail, so that at the next call * we'll not run into it again. */ - listDelNode(clients,clientnode); - listAddNodeTail(clients,receiver); + listRotateHeadToTail(clients); continue; } @@ -353,8 +367,7 @@ if (receiver->btype != BLOCKED_ZSET) { /* Put at the tail, so that at the next call * we'll not run into it again. */ - listDelNode(clients,clientnode); - listAddNodeTail(clients,receiver); + listRotateHeadToTail(clients); continue; } @@ -398,8 +411,9 @@ while((ln = listNext(&li))) { client *receiver = listNodeValue(ln); if (receiver->btype != BLOCKED_STREAM) continue; - streamID *gt = dictFetchValue(receiver->bpop.keys, - rl->key); + bkinfo *bki = dictFetchValue(receiver->bpop.keys, + rl->key); + streamID *gt = &bki->stream_id; /* If we blocked in the context of a consumer * group, we need to resolve the group and update the @@ -516,17 +530,15 @@ if (target != NULL) incrRefCount(target); for (j = 0; j < numkeys; j++) { - /* The value associated with the key name in the bpop.keys dictionary - * is NULL for lists and sorted sets, or the stream ID for streams. */ - void *key_data = NULL; - if (btype == BLOCKED_STREAM) { - key_data = zmalloc(sizeof(streamID)); - memcpy(key_data,ids+j,sizeof(streamID)); - } + /* Allocate our bkinfo structure, associated to each key the client + * is blocked for. */ + bkinfo *bki = zmalloc(sizeof(*bki)); + if (btype == BLOCKED_STREAM) + bki->stream_id = ids[j]; /* If the key already exists in the dictionary ignore it. */ - if (dictAdd(c->bpop.keys,keys[j],key_data) != DICT_OK) { - zfree(key_data); + if (dictAdd(c->bpop.keys,keys[j],bki) != DICT_OK) { + zfree(bki); continue; } incrRefCount(keys[j]); @@ -545,6 +557,7 @@ l = dictGetVal(de); } listAddNodeTail(l,c); + bki->listnode = listLast(l); } blockClient(c,btype); } @@ -561,11 +574,12 @@ /* The client may wait for multiple keys, so unblock it for every key. */ while((de = dictNext(di)) != NULL) { robj *key = dictGetKey(de); + bkinfo *bki = dictGetVal(de); /* Remove this client from the list of clients waiting for this key. */ l = dictFetchValue(c->db->blocking_keys,key); serverAssertWithInfo(c,key,l != NULL); - listDelNode(l,listSearchKey(l,c)); + listDelNode(l,bki->listnode); /* If the list is empty we need to remove it to avoid wasting memory */ if (listLength(l) == 0) dictDelete(c->db->blocking_keys,key); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-5.0.8/src/server.c new/redis-5.0.9/src/server.c --- old/redis-5.0.8/src/server.c 2020-03-12 16:07:44.000000000 +0100 +++ new/redis-5.0.9/src/server.c 2020-04-17 12:45:57.000000000 +0200 @@ -987,7 +987,7 @@ /* Rotate the list, take the current head, process. * This way if the client must be removed from the list it's the * first element and we don't incur into O(N) computation. */ - listRotate(server.clients); + listRotateTailToHead(server.clients); head = listFirst(server.clients); c = listNodeValue(head); /* The following functions do different service checks on the client. @@ -2336,8 +2336,13 @@ * + PROPAGATE_AOF (propagate into the AOF file if is enabled) * + PROPAGATE_REPL (propagate into the replication link) * - * This should not be used inside commands implementation. Use instead - * alsoPropagate(), preventCommandPropagation(), forceCommandPropagation(). + * This should not be used inside commands implementation since it will not + * wrap the resulting commands in MULTI/EXEC. Use instead alsoPropagate(), + * preventCommandPropagation(), forceCommandPropagation(). + * + * However for functions that need to (also) propagate out of the context of a + * command execution, for example when serving a blocked client, you + * want to use propagate(). */ void propagate(struct redisCommand *cmd, int dbid, robj **argv, int argc, int flags) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-5.0.8/src/t_stream.c new/redis-5.0.9/src/t_stream.c --- old/redis-5.0.8/src/t_stream.c 2020-03-12 16:07:44.000000000 +0100 +++ new/redis-5.0.9/src/t_stream.c 2020-04-17 12:45:57.000000000 +0200 @@ -842,7 +842,7 @@ argv[11] = createStringObject("JUSTID",6); argv[12] = createStringObject("LASTID",6); argv[13] = createObjectFromStreamID(&group->last_id); - alsoPropagate(server.xclaimCommand,c->db->id,argv,14,PROPAGATE_AOF|PROPAGATE_REPL); + propagate(server.xclaimCommand,c->db->id,argv,14,PROPAGATE_AOF|PROPAGATE_REPL); decrRefCount(argv[0]); decrRefCount(argv[3]); decrRefCount(argv[4]); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-5.0.8/src/version.h new/redis-5.0.9/src/version.h --- old/redis-5.0.8/src/version.h 2020-03-12 16:07:44.000000000 +0100 +++ new/redis-5.0.9/src/version.h 2020-04-17 12:45:57.000000000 +0200 @@ -1 +1 @@ -#define REDIS_VERSION "5.0.8" +#define REDIS_VERSION "5.0.9"