summaryrefslogtreecommitdiff
path: root/src/quicklist.c
diff options
context:
space:
mode:
authorsundb <sundbcn@gmail.com>2022-01-16 14:54:40 +0800
committerGitHub <noreply@github.com>2022-01-16 08:54:40 +0200
commit32e7b46a17601be33ea687ad5bafc6f01fcb8891 (patch)
treef3dfb9d3ff920cbd4d4de34b07767479a4b9f87f /src/quicklist.c
parent7da7d2aa8eb8f5e82bd6fae8f5dd1d83c9ead0a6 (diff)
downloadredis-32e7b46a17601be33ea687ad5bafc6f01fcb8891.tar.gz
Fix quicklist node not being recompressed correctly after inserting a new node before or after it (#10120)
### Describe Fix crash found by CI, Introduced by #9849. When we do any operation on the quicklist, we should make sure that all nodes of the quicklist should not be in the recompressed state. ### Issues This PR fixes two issues with incorrect recompression. 1. The current quicklist node is full and the previous node isn't full, the current node is not recompressed correctly after inserting elements into the previous node. 2. The current quicklist node is full and the next node isn't full, the current node is not recompressed correctly after inserting elements into the next node. ### Test Add two tests to cover incorrect compression issues. ### Other Fix unittest test failure caused by assertion introduced by #9849.
Diffstat (limited to 'src/quicklist.c')
-rw-r--r--src/quicklist.c16
1 files changed, 16 insertions, 0 deletions
diff --git a/src/quicklist.c b/src/quicklist.c
index b735d98e2..06e5034f3 100644
--- a/src/quicklist.c
+++ b/src/quicklist.c
@@ -1018,6 +1018,7 @@ REDIS_STATIC void _quicklistInsert(quicklistIter *iter, quicklistEntry *entry,
new_node->count++;
quicklistNodeUpdateSz(new_node);
quicklistRecompressOnly(new_node);
+ quicklistRecompressOnly(node);
} else if (full && at_head && avail_prev && !after) {
/* If we are: at head, previous has free space, and inserting before:
* - insert entry at tail of previous node. */
@@ -1028,6 +1029,7 @@ REDIS_STATIC void _quicklistInsert(quicklistIter *iter, quicklistEntry *entry,
new_node->count++;
quicklistNodeUpdateSz(new_node);
quicklistRecompressOnly(new_node);
+ quicklistRecompressOnly(node);
} else if (full && ((at_tail && !avail_next && after) ||
(at_head && !avail_prev && !after))) {
/* If we are: full, and our prev/next has no available space, then:
@@ -3166,6 +3168,11 @@ int quicklistTest(int argc, char *argv[], int flags) {
TEST("compress and decompress quicklist listpack node") {
quicklistNode *node = quicklistCreateNode();
node->entry = lpNew(0);
+
+ /* Just to avoid triggering the assertion in __quicklistCompressNode(),
+ * it disables the passing of quicklist head or tail node. */
+ node->prev = quicklistCreateNode();
+ node->next = quicklistCreateNode();
/* Create a rand string */
size_t sz = (1 << 25); /* 32MB per one entry */
@@ -3185,6 +3192,8 @@ int quicklistTest(int argc, char *argv[], int flags) {
}
zfree(s);
+ zfree(node->prev);
+ zfree(node->next);
zfree(node->entry);
zfree(node);
}
@@ -3199,6 +3208,11 @@ int quicklistTest(int argc, char *argv[], int flags) {
quicklistNode *node = __quicklistCreatePlainNode(s, sz);
+ /* Just to avoid triggering the assertion in __quicklistCompressNode(),
+ * it disables the passing of quicklist head or tail node. */
+ node->prev = quicklistCreateNode();
+ node->next = quicklistCreateNode();
+
long long start = mstime();
assert(__quicklistCompressNode(node));
assert(__quicklistDecompressNode(node));
@@ -3207,6 +3221,8 @@ int quicklistTest(int argc, char *argv[], int flags) {
assert(memcmp(node->entry, "helloworld", 10) == 0);
assert(memcmp(node->entry + sz - 10, "1234567890", 10) == 0);
+ zfree(node->prev);
+ zfree(node->next);
zfree(node->entry);
zfree(node);
}