This bug is about a node should be compressed witch is not. The following code can create that node.
TEST("limit")
{
quicklist *ql = quicklistNew(2, 1);
quicklistPushHead(ql, "0", 1);
quicklistPushHead(ql, "1", 1);
quicklistPushHead(ql, "2", 1);
quicklistPushHead(ql, "3", 1);
quicklistPushHead(ql, "4", 1);
quicklistPushHead(ql, "5", 1);
assert(ql->len == 3);
assert(ql->head->next->encoding == QUICKLIST_NODE_ENCODING_RAW);
size_t sz = (1 << 12);
unsigned char *s = zmalloc(sz);
randstring(s, sz);
quicklistEntry entry;
quicklistIter *iter = quicklistGetIteratorEntryAtIdx(ql, 2, &entry);
quicklistDelEntry(iter, &entry);
quicklistInsertAfter(iter, &entry, s, sz);
quicklistReleaseIterator(iter);
assert(ql->len == 3);
/* ql->head->next is not compressed */
assert(ql->head->next->encoding == QUICKLIST_NODE_ENCODING_RAW);
/* ql->head->next should be compressed */
__quicklistCompress(ql, ql->head->next);
assert(ql->head->next->encoding == QUICKLIST_NODE_ENCODING_LZF);
zfree(s);
quicklistRelease(ql);
}
This bug is related with the member recompress in struct quicklistNode. A node will not be compressed if it's not compress small enough. And it will remain uncompressed after insert, because 'recompress' is 0 and will prevent compression。
Comment From: sundb
do you forget to release iterator which will compress the node?
Comment From: imchuncai
@sundb I have edited the code, release iterator won't work, cause quicklistInsertAfter() will reset the iterator .
Comment From: sundb
@imchuncai Thanks for pointing it out. This is a regression of #9849. The following cases are where we need to reset the iterator 1) node->entry was changed, whereas node->zi will be invalidated. 2) node changed, e.g. merges, deletes.
I was thinking that we could modify the way we reset the iterator. 1) When node->entry changed, we just reset node->zi. 2) When node changed, we will reset the whole iterator, and then the node compression will be handled by the business.