Skip to content

Commit 5363779

Browse files
authored
fix: circular dependency in qlist (#4302)
* fix: circular dependency in qlist fixes #4294 Signed-off-by: Roman Gershman <roman@dragonflydb.io> * chore: fixes Signed-off-by: Roman Gershman <roman@dragonflydb.io> --------- Signed-off-by: Roman Gershman <roman@dragonflydb.io>
1 parent f564513 commit 5363779

File tree

3 files changed

+20
-7
lines changed

3 files changed

+20
-7
lines changed

src/core/qlist.cc

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,7 @@ string QList::Pop(Where where) {
371371

372372
/* The head and tail should never be compressed */
373373
DCHECK(node->encoding != QUICKLIST_NODE_ENCODING_LZF);
374+
DCHECK(head_->prev->next == nullptr);
374375

375376
string res;
376377
if (ABSL_PREDICT_FALSE(QL_NODE_IS_PLAIN(node))) {
@@ -390,6 +391,7 @@ string QList::Pop(Where where) {
390391
}
391392
DelPackedIndex(node, pos);
392393
}
394+
DCHECK(head_ == nullptr || head_->prev->next == nullptr);
393395
return res;
394396
}
395397

@@ -479,11 +481,13 @@ bool QList::PushSentinel(string_view value, Where where) {
479481
if (len_ == 1) { // sanity check
480482
DCHECK_EQ(malloc_size_, orig->sz);
481483
}
484+
DCHECK(head_->prev->next == nullptr);
482485
return false;
483486
}
484487

485488
quicklistNode* node = CreateFromSV(QUICKLIST_NODE_CONTAINER_PACKED, value);
486489
InsertNode(orig, node, opt);
490+
DCHECK(head_->prev->next == nullptr);
487491
return true;
488492
}
489493

@@ -837,13 +841,15 @@ quicklistNode* QList::ListpackMerge(quicklistNode* a, quicklistNode* b) {
837841
void QList::DelNode(quicklistNode* node) {
838842
if (node->next)
839843
node->next->prev = node->prev;
840-
if (node->prev)
841-
node->prev->next = node->next;
842844

843845
if (node == head_) {
844846
head_ = node->next;
845-
} else if (node == head_->prev) { // tail
846-
head_->prev = node->prev;
847+
} else {
848+
// for non-head nodes, update prev->next to point to node->next
849+
// (If node==head, prev is tail and should always point to NULL).
850+
node->prev->next = node->next;
851+
if (node == head_->prev) // tail
852+
head_->prev = node->prev;
847853
}
848854

849855
/* Update len first, so in Compress we know exactly len */

src/core/qlist_test.cc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,15 @@ TEST_F(QListTest, CompressionPlain) {
282282
EXPECT_EQ(500, i);
283283
}
284284

285+
TEST_F(QListTest, LargeValues) {
286+
string val(100000, 'a');
287+
ql_.Push(val, QList::HEAD);
288+
ql_.Push(val, QList::HEAD);
289+
ql_.Pop(QList::HEAD);
290+
auto items = ToItems();
291+
EXPECT_THAT(items, ElementsAre(val));
292+
}
293+
285294
using FillCompress = tuple<int, unsigned>;
286295

287296
class PrintToFillCompress {

tests/dragonfly/seeder/script-genlib.lua

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,7 @@ end
5656

5757
function LG_funcs.add_list(key, keys)
5858
local is_huge = keys[key]
59-
--- TODO -- investigate why second case of replication_test_all fails
60-
--- we somehow create a quicklist that is circular and we deadlock
61-
redis.apcall('LPUSH', key, unpack(randstr_sequence(false)))
59+
redis.apcall('LPUSH', key, unpack(randstr_sequence(is_huge)))
6260
end
6361

6462
function LG_funcs.mod_list(key, keys)

0 commit comments

Comments
 (0)