From 69040d75888eb4b0d5f988b0b9e58c7937448eaf Mon Sep 17 00:00:00 2001 From: Warrick <1016weicheng@gmail.com> Date: Wed, 19 Aug 2026 12:31:47 +0800 Subject: [PATCH] [fix] add ziplist->listpack data conversion during loading rordb --- src/rdb.c | 22 ++++----------- tests/assets/swap/rordb-ziplist.rordb | Bin 0 -> 15936 bytes tests/swap/unit/rordb_ziplist_load.tcl | 36 +++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 17 deletions(-) create mode 100644 tests/assets/swap/rordb-ziplist.rordb create mode 100644 tests/swap/unit/rordb_ziplist_load.tcl diff --git a/src/rdb.c b/src/rdb.c index 6665467e7cd..7b8e0969244 100644 --- a/src/rdb.c +++ b/src/rdb.c @@ -2729,11 +2729,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb, sds key, int dbid, int *error) { quicklist *ql = quicklistNew(server.list_max_listpack_size, server.list_compress_depth); - if ( -#ifdef ENABLE_SWAP - !rdbLoadObjectGetSkipEmptyCheckFlag() && -#endif - !ziplistValidateIntegrity(encoded, encoded_len, 1, + if (!ziplistValidateIntegrity(encoded, encoded_len, 1, _listZiplistEntryConvertAndValidate, ql)) { @@ -2746,9 +2742,9 @@ robj *rdbLoadObject(int rdbtype, rio *rdb, sds key, int dbid, int *error) } if ( #ifdef ENABLE_SWAP - !rdbLoadObjectGetSkipEmptyCheckFlag() && + !rdbLoadObjectGetSkipEmptyCheckFlag() && #endif - ql->len == 0) { + ql->len == 0) { zfree(encoded); o->ptr = NULL; @@ -2810,11 +2806,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb, sds key, int dbid, int *error) case RDB_TYPE_ZSET_ZIPLIST: { unsigned char *lp = lpNew(encoded_len); - if ( -#ifdef ENABLE_SWAP - !rdbLoadObjectGetSkipEmptyCheckFlag() && -#endif - !ziplistPairsConvertAndValidateIntegrity(encoded, encoded_len, &lp)) { + if (!ziplistPairsConvertAndValidateIntegrity(encoded, encoded_len, &lp)) { rdbReportCorruptRDB("Zset ziplist integrity check failed."); zfree(lp); zfree(encoded); @@ -2872,11 +2864,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb, sds key, int dbid, int *error) case RDB_TYPE_HASH_ZIPLIST: { unsigned char *lp = lpNew(encoded_len); - if ( -#ifdef ENABLE_SWAP - !rdbLoadObjectGetSkipEmptyCheckFlag() && -#endif - !ziplistPairsConvertAndValidateIntegrity(encoded, encoded_len, &lp)) { + if (!ziplistPairsConvertAndValidateIntegrity(encoded, encoded_len, &lp)) { rdbReportCorruptRDB("Hash ziplist integrity check failed."); zfree(lp); zfree(encoded); diff --git a/tests/assets/swap/rordb-ziplist.rordb b/tests/assets/swap/rordb-ziplist.rordb new file mode 100644 index 0000000000000000000000000000000000000000..1f5bacca9f59737950755dc13713b8f8963479e7 GIT binary patch literal 15936 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 data conversion(ziplistPairsConvertAndValidateIntegrity), + # leaving an empty object and silently dropping every field. + # + # With the fix, the conversion always runs, so the fields survive the load. + + set server_path [tmpdir "server.rordb-ziplist-load"] + + test "load rordb with legacy ziplist-encoded hash/zset preserves all fields" { + exec cp tests/assets/swap/rordb-ziplist.rordb $server_path + start_server [list overrides [list "dir" $server_path "dbfilename" "rordb-ziplist.rordb"]] { + assert_equal [r dbsize] 2 + + # hash: 3 fields must survive the ziplist->listpack conversion + assert_equal [r hlen ziphash] 3 + assert_equal [lsort [r hgetall ziphash]] [lsort {f1 v1 f2 v2 f3 v3}] + assert_equal [r hget ziphash f1] v1 + assert_equal [r hget ziphash f2] v2 + assert_equal [r hget ziphash f3] v3 + + # zset: 3 members must survive the ziplist->listpack conversion + assert_equal [r zcard zipzset] 3 + assert_equal [r zrange zipzset 0 -1 withscores] {a 1 b 2 c 3} + + # full read triggers swap-in merge; must not crash / underflow + assert_equal [r ping] {PONG} + } + } +}