Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions src/t_list.c
Original file line number Diff line number Diff line change
Expand Up @@ -604,12 +604,16 @@ void lsetCommand(client *c) {

if ((getLongFromObjectOrReply(c, c->argv[2], &index, NULL) != C_OK)) return;

listTypeTryConversionAppend(o, c->argv, 3, 3, NULL, NULL);
int old_encoding = o->encoding;
if (listTypeReplaceAtIndex(o, index, value)) {
/* We might replace a big item with a small one or vice versa, but we've
* already handled the growing case in listTypeTryConversionAppend()
* above, so here we just need to try the conversion for shrinking. */
listTypeTryConversion(o, LIST_CONV_SHRINKING, NULL, NULL);
/* LSET replaces an existing element, so conversion decisions must be
* based on the final list state rather than treating the new value as
* an appended element. A listpack may need to grow into a quicklist,
* while a quicklist may shrink into a listpack. */
if (old_encoding == OBJ_ENCODING_LISTPACK)
listTypeTryConversion(o, LIST_CONV_GROWING, NULL, NULL);
else
listTypeTryConversion(o, LIST_CONV_SHRINKING, NULL, NULL);
signalModifiedKey(c, c->db, c->argv[1]);
notifyKeyspaceEvent(NOTIFY_LIST, "lset", c->argv[1], c->db->id);
server.dirty++;
Expand Down
29 changes: 27 additions & 2 deletions tests/unit/type/list.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -2100,6 +2100,26 @@ foreach {pop} {BLPOP BLMPOP_RIGHT} {
}

foreach {max_lp_size large} "3 $largevalue(listpack) -1 $largevalue(quicklist)" {
test "List LSET keeps listpack encoding when replacement stays within limits - $max_lp_size" {
set origin_conf [config_get_set list-max-listpack-size $max_lp_size]

create_listpack lst "a b c"
r LSET lst 0 x
assert_encoding listpack lst

r config set list-max-listpack-size $origin_conf
}

test "List LSET converts listpack when replacement exceeds safety limit - $max_lp_size" {
set origin_conf [config_get_set list-max-listpack-size $max_lp_size]

create_listpack lst "a"
r LSET lst 0 [string repeat x 9000]
assert_encoding quicklist lst

r config set list-max-listpack-size $origin_conf
}

test "List listpack -> quicklist encoding conversion" {
set origin_conf [config_get_set list-max-listpack-size $max_lp_size]

Expand All @@ -2113,10 +2133,15 @@ foreach {pop} {BLPOP BLMPOP_RIGHT} {
r LINSERT lst after b $large
assert_encoding quicklist lst

# LSET
# LSET replaces an element, so it does not exceed count limits.
# Size-based limits can still force conversion for large values.
create_listpack lst "a b c"
r LSET lst 0 $large
assert_encoding quicklist lst
if {$max_lp_size == 3} {
assert_encoding listpack lst
} else {
assert_encoding quicklist lst
}

# LMOVE
create_quicklist lsrc{t} "a b c $large"
Expand Down
Loading