Skip to content

Commit f3bf848

Browse files
authored
Fix resize hash table dictionary iterator (redis#12660)
Dictionary iterator logic in the `tryResizeHashTables` method is picking the next (incorrect) dictionary while the cursor is at a given slot. This could lead to some dictionary/slot getting skipped from resizing. Also stabilize the test. problem introduced recently in redis#11695
1 parent 03345dd commit f3bf848

File tree

3 files changed

+5
-17
lines changed

3 files changed

+5
-17
lines changed

src/server.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,8 +608,9 @@ void tryResizeHashTables(int dbid) {
608608
for (dbKeyType subdict = DB_MAIN; subdict <= DB_EXPIRES; subdict++) {
609609
dbIterator *dbit = dbIteratorInitFromSlot(db, subdict, db->sub_dict[subdict].resize_cursor);
610610
for (int i = 0; i < CRON_DBS_PER_CALL; i++) {
611-
dict *d = dbIteratorNextDict(dbit);
611+
dict *d = dbGetDictFromIterator(dbit);
612612
slot = dbIteratorGetCurrentSlot(dbit);
613+
dbIteratorNextDict(dbit);
613614
if (!d) break;
614615
if (htNeedsResize(d))
615616
dictResize(d);

src/server.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2428,6 +2428,7 @@ typedef struct dbIterator dbIterator;
24282428
dbIterator *dbIteratorInit(redisDb *db, dbKeyType keyType);
24292429
dbIterator *dbIteratorInitFromSlot(redisDb *db, dbKeyType keyType, int slot);
24302430
dict *dbIteratorNextDict(dbIterator *dbit);
2431+
dict *dbGetDictFromIterator(dbIterator *dbit);
24312432
int dbIteratorGetCurrentSlot(dbIterator *dbit);
24322433
dictEntry *dbIteratorNext(dbIterator *iter);
24332434

tests/unit/expire.tcl

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -834,7 +834,7 @@ start_server {tags {"expire"}} {
834834
} {} {needs:debug}
835835
}
836836

837-
start_cluster 1 0 {tags {"expire external:skip cluster"}} {
837+
start_cluster 1 0 {tags {"expire external:skip cluster slow"}} {
838838
test "expire scan should skip dictionaries with lot's of empty buckets" {
839839
# Collect two slots to help determine the expiry scan logic is able
840840
# to go past certain slots which aren't valid for scanning at the given point of time.
@@ -851,8 +851,6 @@ start_cluster 1 0 {tags {"expire external:skip cluster"}} {
851851
# hashslot(key) is 12539
852852
r psetex key 500 val
853853

854-
assert_equal 102 [r dbsize]
855-
856854
# disable resizing
857855
r config set rdb-key-save-delay 10000000
858856
r bgsave
@@ -882,23 +880,11 @@ start_cluster 1 0 {tags {"expire external:skip cluster"}} {
882880
fail "bgsave did not stop in time."
883881
}
884882

885-
# Verify dict is under rehashing
886-
set htstats [r debug HTSTATS 0]
887-
assert_match {*rehashing target*} $htstats
888-
889883
# put some data into slot 12182 and trigger the resize
890884
r psetex "{foo}0" 500 a
891885

892-
# Verify dict rehashing has completed
893-
set htstats [r debug HTSTATS 0]
894-
wait_for_condition 20 100 {
895-
![string match {*rehashing target*} $htstats]
896-
} else {
897-
fail "rehashing didn't complete"
898-
}
899-
900886
# Verify all keys have expired
901-
wait_for_condition 20 100 {
887+
wait_for_condition 200 100 {
902888
[r dbsize] eq 0
903889
} else {
904890
fail "Keys did not actively expire."

0 commit comments

Comments
 (0)