diff options
author | sundb <sundbcn@gmail.com> | 2022-01-16 14:54:40 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-16 08:54:40 +0200 |
commit | 32e7b46a17601be33ea687ad5bafc6f01fcb8891 (patch) | |
tree | f3dfb9d3ff920cbd4d4de34b07767479a4b9f87f | |
parent | 7da7d2aa8eb8f5e82bd6fae8f5dd1d83c9ead0a6 (diff) | |
download | redis-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.
-rw-r--r-- | src/quicklist.c | 16 | ||||
-rw-r--r-- | tests/unit/type/list-3.tcl | 26 |
2 files changed, 42 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); } diff --git a/tests/unit/type/list-3.tcl b/tests/unit/type/list-3.tcl index d5e4088c5..45df5939d 100644 --- a/tests/unit/type/list-3.tcl +++ b/tests/unit/type/list-3.tcl @@ -93,6 +93,32 @@ start_server { r ping } + test {LINSERT correctly recompress full quicklistNode after inserting a element before it} { + r del key + config_set list-compress-depth 1 + r rpush key b + r rpush key c + r lset key -1 [string repeat x 8192]"969" + r lpush key a + r rpush key d + r linsert key before b f + r rpop key + r ping + } + + test {LINSERT correctly recompress full quicklistNode after inserting a element after it} { + r del key + config_set list-compress-depth 1 + r rpush key b + r rpush key c + r lset key 0 [string repeat x 8192]"969" + r lpush key a + r rpush key d + r linsert key after c f + r lpop key + r ping + } + foreach comp {2 1 0} { set cycles 1000 if {$::accurate} { set cycles 10000 } |