__quicklistCompress may compress more node than required (#8311)
When a quicklist has quicklist->compress * 2 nodes, then call __quicklistCompress, all nodes will be decompressed and the middle two nodes will be recompressed again. This violates the fact that quicklist->compress * 2 nodes are uncompressed. It's harmless because when visit a node, we always try to uncompress node first. This only happened when a quicklist has quicklist->compress * 2 + 1 nodes, then delete a node. For other scenarios like insert node and iterate this will not happen.
This commit is contained in:
parent
817894c012
commit
9b4edfdf08
@ -315,7 +315,9 @@ REDIS_STATIC void __quicklistCompress(const quicklist *quicklist,
|
|||||||
if (forward == node || reverse == node)
|
if (forward == node || reverse == node)
|
||||||
in_depth = 1;
|
in_depth = 1;
|
||||||
|
|
||||||
if (forward == reverse)
|
/* We passed into compress depth of opposite side of the quicklist
|
||||||
|
* so there's no need to compress anything and we can exit. */
|
||||||
|
if (forward == reverse || forward->next == reverse)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
forward = forward->next;
|
forward = forward->next;
|
||||||
@ -325,11 +327,9 @@ REDIS_STATIC void __quicklistCompress(const quicklist *quicklist,
|
|||||||
if (!in_depth)
|
if (!in_depth)
|
||||||
quicklistCompressNode(node);
|
quicklistCompressNode(node);
|
||||||
|
|
||||||
if (depth > 2) {
|
|
||||||
/* At this point, forward and reverse are one node beyond depth */
|
/* At this point, forward and reverse are one node beyond depth */
|
||||||
quicklistCompressNode(forward);
|
quicklistCompressNode(forward);
|
||||||
quicklistCompressNode(reverse);
|
quicklistCompressNode(reverse);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define quicklistCompress(_ql, _node) \
|
#define quicklistCompress(_ql, _node) \
|
||||||
@ -380,10 +380,11 @@ REDIS_STATIC void __quicklistInsertNode(quicklist *quicklist,
|
|||||||
quicklist->head = quicklist->tail = new_node;
|
quicklist->head = quicklist->tail = new_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Update len first, so in __quicklistCompress we know exactly len */
|
||||||
|
quicklist->len++;
|
||||||
|
|
||||||
if (old_node)
|
if (old_node)
|
||||||
quicklistCompress(quicklist, old_node);
|
quicklistCompress(quicklist, old_node);
|
||||||
|
|
||||||
quicklist->len++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wrappers for node inserting around existing node. */
|
/* Wrappers for node inserting around existing node. */
|
||||||
@ -602,15 +603,16 @@ REDIS_STATIC void __quicklistDelNode(quicklist *quicklist,
|
|||||||
quicklist->head = node->next;
|
quicklist->head = node->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Update len first, so in __quicklistCompress we know exactly len */
|
||||||
|
quicklist->len--;
|
||||||
|
quicklist->count -= node->count;
|
||||||
|
|
||||||
/* If we deleted a node within our compress depth, we
|
/* If we deleted a node within our compress depth, we
|
||||||
* now have compressed nodes needing to be decompressed. */
|
* now have compressed nodes needing to be decompressed. */
|
||||||
__quicklistCompress(quicklist, NULL);
|
__quicklistCompress(quicklist, NULL);
|
||||||
|
|
||||||
quicklist->count -= node->count;
|
|
||||||
|
|
||||||
zfree(node->zl);
|
zfree(node->zl);
|
||||||
zfree(node);
|
zfree(node);
|
||||||
quicklist->len--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Delete one entry from list given the node for the entry and a pointer
|
/* Delete one entry from list given the node for the entry and a pointer
|
||||||
@ -2706,6 +2708,14 @@ int quicklistTest(int argc, char *argv[]) {
|
|||||||
quicklistPushHead(ql, genstr("hello HEAD", i + 1), 64);
|
quicklistPushHead(ql, genstr("hello HEAD", i + 1), 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int step = 0; step < 2; step++) {
|
||||||
|
/* test remove node */
|
||||||
|
if (step == 1) {
|
||||||
|
for (int i = 0; i < list_sizes[list] / 2; i++) {
|
||||||
|
quicklistPop(ql, QUICKLIST_HEAD, NULL, NULL, NULL);
|
||||||
|
quicklistPop(ql, QUICKLIST_TAIL, NULL, NULL, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
quicklistNode *node = ql->head;
|
quicklistNode *node = ql->head;
|
||||||
unsigned int low_raw = ql->compress;
|
unsigned int low_raw = ql->compress;
|
||||||
unsigned int high_raw = ql->len - ql->compress;
|
unsigned int high_raw = ql->len - ql->compress;
|
||||||
@ -2730,6 +2740,8 @@ int quicklistTest(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
quicklistRelease(ql);
|
quicklistRelease(ql);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user