Hello community, here is the log from the commit of package redis for openSUSE:Factory checked in at 2018-02-09 15:52:42 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/redis (Old) and /work/SRC/openSUSE:Factory/.redis.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "redis" Fri Feb 9 15:52:42 2018 rev:39 rq:574511 version:4.0.8 Changes: -------- --- /work/SRC/openSUSE:Factory/redis/redis.changes 2018-01-28 20:33:44.833981955 +0100 +++ /work/SRC/openSUSE:Factory/.redis.new/redis.changes 2018-02-09 15:52:54.871822767 +0100 @@ -1,0 +2,7 @@ +Thu Feb 8 23:23:58 UTC 2018 - i...@ilya.pp.ua + +- Update to 4.0.8 + * Release notes: https://raw.githubusercontent.com/antirez/redis/4.0/00-RELEASENOTES + * Fix crash Redis Cluster instances during deletions. + +------------------------------------------------------------------- Old: ---- redis-4.0.7.tar.gz New: ---- redis-4.0.8.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ redis.spec ++++++ --- /var/tmp/diff_new_pack.4jMKDt/_old 2018-02-09 15:52:57.091743031 +0100 +++ /var/tmp/diff_new_pack.4jMKDt/_new 2018-02-09 15:52:57.091743031 +0100 @@ -19,7 +19,7 @@ %define _log_dir %{_localstatedir}/log/%{name} %define _conf_dir %{_sysconfdir}/%{name} Name: redis -Version: 4.0.7 +Version: 4.0.8 Release: 0 Summary: Persistent key-value database License: BSD-3-Clause ++++++ redis-4.0.7.tar.gz -> redis-4.0.8.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-4.0.7/00-RELEASENOTES new/redis-4.0.8/00-RELEASENOTES --- old/redis-4.0.7/00-RELEASENOTES 2018-01-24 11:16:18.000000000 +0100 +++ new/redis-4.0.8/00-RELEASENOTES 2018-02-02 17:39:14.000000000 +0100 @@ -11,6 +11,31 @@ -------------------------------------------------------------------------------- ================================================================================ +Redis 4.0.8 Released Fri Feb 2 11:17:40 CET 2018 +================================================================================ + +Upgrade urgency CRITICAL ONLY for Redis Cluster users. Otherwise no reason +to upgrade at all. + +Redis 4.0.8 fixes a single critical bug in the radix tree data structure +used for Redis Cluster keys slot tracking. The problem was actually fixed +10 months ago into unstable, but it was fixed in a commit related to Streams +so it was never backported (for error) into the 4.0 branch. + +The problem will crash Redis Cluster instances during deletions, but it is +very hard to trigger: only when the node removed is in the edge of a memory +mapped area there are the conditions to create an issue, because otherwise +the code just accesses an out of range word in read-only way in an allocated +structure: this is almost always harmless. + +The single commit in this release: + +f603940f Rax updated to latest antirez/rax commit. (Salvatore Sanfilippo) + +Cheers, +Salvatore + +================================================================================ Redis 4.0.7 Released Wed Jan 24 11:01:40 CET 2018 ================================================================================ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-4.0.7/src/rax.c new/redis-4.0.8/src/rax.c --- old/redis-4.0.7/src/rax.c 2018-01-24 11:16:18.000000000 +0100 +++ new/redis-4.0.8/src/rax.c 2018-02-02 17:39:14.000000000 +0100 @@ -131,7 +131,7 @@ } /* ---------------------------------------------------------------------------- - * Radis tree implementation + * Radix tree implementation * --------------------------------------------------------------------------*/ /* Allocate a new non compressed node with the specified number of children. @@ -186,10 +186,10 @@ void raxSetData(raxNode *n, void *data) { n->iskey = 1; if (data != NULL) { + n->isnull = 0; void **ndata = (void**) ((char*)n+raxNodeCurrentLength(n)-sizeof(void*)); memcpy(ndata,&data,sizeof(data)); - n->isnull = 0; } else { n->isnull = 1; } @@ -396,6 +396,7 @@ position to 0 to signal this node represents the searched key. */ } + debugnode("Lookup stop node is",h); if (stopnode) *stopnode = h; if (plink) *plink = parentlink; if (splitpos && h->iscompr) *splitpos = j; @@ -424,18 +425,21 @@ * our key. We have just to reallocate the node and make space for the * data pointer. */ if (i == len && (!h->iscompr || j == 0 /* not in the middle if j is 0 */)) { + debugf("### Insert: node representing key exists\n"); + if (!h->iskey || h->isnull) { + h = raxReallocForData(h,data); + if (h) memcpy(parentlink,&h,sizeof(h)); + } + if (h == NULL) { + errno = ENOMEM; + return 0; + } if (h->iskey) { if (old) *old = raxGetData(h); raxSetData(h,data); errno = 0; return 0; /* Element already exists. */ } - h = raxReallocForData(h,data); - if (h == NULL) { - errno = ENOMEM; - return 0; - } - memcpy(parentlink,&h,sizeof(h)); raxSetData(h,data); rax->numele++; return 1; /* Element inserted. */ @@ -734,9 +738,7 @@ } /* We walked the radix tree as far as we could, but still there are left - * chars in our string. We need to insert the missing nodes. - * Note: while loop never entered if the node was split by ALGO2, - * since i == len. */ + * chars in our string. We need to insert the missing nodes. */ while(i < len) { raxNode *child; @@ -871,7 +873,8 @@ memmove(((char*)cp)-1,cp,(parent->size-taillen-1)*sizeof(raxNode**)); /* Move the remaining "tail" pointer at the right position as well. */ - memmove(((char*)c)-1,c+1,taillen*sizeof(raxNode**)+parent->iskey*sizeof(void*)); + size_t valuelen = (parent->iskey && !parent->isnull) ? sizeof(void*) : 0; + memmove(((char*)c)-1,c+1,taillen*sizeof(raxNode**)+valuelen); /* 4. Update size. */ parent->size--; @@ -1090,27 +1093,36 @@ /* This is the core of raxFree(): performs a depth-first scan of the * tree and releases all the nodes found. */ -void raxRecursiveFree(rax *rax, raxNode *n) { +void raxRecursiveFree(rax *rax, raxNode *n, void (*free_callback)(void*)) { + debugnode("free traversing",n); int numchildren = n->iscompr ? 1 : n->size; raxNode **cp = raxNodeLastChildPtr(n); while(numchildren--) { raxNode *child; memcpy(&child,cp,sizeof(child)); - raxRecursiveFree(rax,child); + raxRecursiveFree(rax,child,free_callback); cp--; } debugnode("free depth-first",n); + if (free_callback && n->iskey && !n->isnull) + free_callback(raxGetData(n)); rax_free(n); rax->numnodes--; } -/* Free a whole radix tree. */ -void raxFree(rax *rax) { - raxRecursiveFree(rax,rax->head); +/* Free a whole radix tree, calling the specified callback in order to + * free the auxiliary data. */ +void raxFreeWithCallback(rax *rax, void (*free_callback)(void*)) { + raxRecursiveFree(rax,rax->head,free_callback); assert(rax->numnodes == 0); rax_free(rax); } +/* Free a whole radix tree. */ +void raxFree(rax *rax) { + raxFreeWithCallback(rax,NULL); +} + /* ------------------------------- Iterator --------------------------------- */ /* Initialize a Rax iterator. This call should be performed a single time @@ -1172,7 +1184,7 @@ * The function returns 1 on success or 0 on out of memory. */ int raxIteratorNextStep(raxIterator *it, int noup) { if (it->flags & RAX_ITER_EOF) { - return 0; + return 1; } else if (it->flags & RAX_ITER_JUST_SEEKED) { it->flags &= ~RAX_ITER_JUST_SEEKED; return 1; @@ -1184,10 +1196,6 @@ size_t orig_stack_items = it->stack.items; raxNode *orig_node = it->node; - /* Clear the EOF flag: it will be set again if the EOF condition - * is still valid. */ - it->flags &= ~RAX_ITER_EOF; - while(1) { int children = it->node->iscompr ? 1 : it->node->size; if (!noup && children) { @@ -1288,7 +1296,7 @@ * effect to the one of raxIteratorPrevSte(). */ int raxIteratorPrevStep(raxIterator *it, int noup) { if (it->flags & RAX_ITER_EOF) { - return 0; + return 1; } else if (it->flags & RAX_ITER_JUST_SEEKED) { it->flags &= ~RAX_ITER_JUST_SEEKED; return 1; @@ -1409,6 +1417,7 @@ it->node = it->rt->head; if (!raxSeekGreatest(it)) return 0; assert(it->node->iskey); + it->data = raxGetData(it->node); return 1; } @@ -1427,6 +1436,7 @@ /* We found our node, since the key matches and we have an * "equal" condition. */ if (!raxIteratorAddChars(it,ele,len)) return 0; /* OOM. */ + it->data = raxGetData(it->node); } else if (lt || gt) { /* Exact key not found or eq flag not set. We have to set as current * key the one represented by the node we stopped at, and perform @@ -1499,6 +1509,7 @@ * the previous sub-tree. */ if (nodechar < keychar) { if (!raxSeekGreatest(it)) return 0; + it->data = raxGetData(it->node); } else { if (!raxIteratorAddChars(it,it->node->data,it->node->size)) return 0; @@ -1615,8 +1626,8 @@ int eq = 0, lt = 0, gt = 0; if (op[0] == '=' || op[1] == '=') eq = 1; - if (op[1] == '>') gt = 1; - else if (op[1] == '<') lt = 1; + if (op[0] == '>') gt = 1; + else if (op[0] == '<') lt = 1; else if (op[1] != '=') return 0; /* Syntax error. */ size_t minlen = key_len < iter->key_len ? key_len : iter->key_len; @@ -1644,6 +1655,19 @@ raxStackFree(&it->stack); } +/* Return if the iterator is in an EOF state. This happens when raxSeek() + * failed to seek an appropriate element, so that raxNext() or raxPrev() + * will return zero, or when an EOF condition was reached while iterating + * with raxNext() and raxPrev(). */ +int raxEOF(raxIterator *it) { + return it->flags & RAX_ITER_EOF; +} + +/* Return the number of elements inside the radix tree. */ +uint64_t raxSize(rax *rax) { + return rax->numele; +} + /* ----------------------------- Introspection ------------------------------ */ /* This function is mostly used for debugging and learning purposes. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-4.0.7/src/rax.h new/redis-4.0.8/src/rax.h --- old/redis-4.0.7/src/rax.h 2018-01-24 11:16:18.000000000 +0100 +++ new/redis-4.0.8/src/rax.h 2018-02-02 17:39:14.000000000 +0100 @@ -148,6 +148,7 @@ int raxRemove(rax *rax, unsigned char *s, size_t len, void **old); void *raxFind(rax *rax, unsigned char *s, size_t len); void raxFree(rax *rax); +void raxFreeWithCallback(rax *rax, void (*free_callback)(void*)); void raxStart(raxIterator *it, rax *rt); int raxSeek(raxIterator *it, const char *op, unsigned char *ele, size_t len); int raxNext(raxIterator *it); @@ -155,6 +156,8 @@ int raxRandomWalk(raxIterator *it, size_t steps); int raxCompare(raxIterator *iter, const char *op, unsigned char *key, size_t key_len); void raxStop(raxIterator *it); +int raxEOF(raxIterator *it); void raxShow(rax *rax); +uint64_t raxSize(rax *rax); #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-4.0.7/src/version.h new/redis-4.0.8/src/version.h --- old/redis-4.0.7/src/version.h 2018-01-24 11:16:18.000000000 +0100 +++ new/redis-4.0.8/src/version.h 2018-02-02 17:39:14.000000000 +0100 @@ -1 +1 @@ -#define REDIS_VERSION "4.0.7" +#define REDIS_VERSION "4.0.8"