This is an automated email from the ASF dual-hosted git repository.

hulk pushed a commit to branch unstable
in repository https://gitbox.apache.org/repos/asf/kvrocks.git


The following commit(s) were added to refs/heads/unstable by this push:
     new a10b6e1e6 feat(rdb): add DUMP support for SortedInt type (#3366)
a10b6e1e6 is described below

commit a10b6e1e6c7f6917de3b12731f75eaeafab83018
Author: Zakir <[email protected]>
AuthorDate: Tue Feb 10 19:42:10 2026 +0530

    feat(rdb): add DUMP support for SortedInt type (#3366)
    
    - Serialize SortedInt as RDB Set for Redis compatibility
    - Use RangeByValue() to get all integers deterministically
    - No RESTORE changes (SortedInt dumps restore as Set, like
    Bitmap→String)
    - Resolves part of #3319
    
    Testing:
    - Manual test confirms DUMP no longer returns error
    - RESTORE successfully creates Set with preserved data
    - All integers maintained in restored Set
    
    Manuel test:
    root@codespaces-6e5713:/workspaces/kvrocks# # Connect to Kvrocks
    redis-cli -p 6666
    
    127.0.0.1:6666> SIADD testkey 100 200 300
    (integer) 0 // already exists
    
    127.0.0.1:6666> SICARD testkey
    (integer) 3
    
    127.0.0.1:6666> TYPE testkey
    sortedint
    
    127.0.0.1:6666> DUMP testkey
    
    "\x02\x03\xc0d\xc1\xc8\x00\xc1,\x01\x06\x00\xb2\x01\xaa\xe2\x06h\xba\x8d"
    
    127.0.0.1:6666> SIADD mykey 5 12 23 89 100
    (integer) 0
    127.0.0.1:6666> DUMP mykey
    
    "\x02\x05\xc0\x05\xc0\x0c\xc0\x17\xc0Y\xc0d\x06\x00\xa8\x19U\x90\x8f\x011o"
    
    127.0.0.1:6666> RESTORE newkey 0
    "\x02\x05\xc0\x05\xc0\x0c\xc0\x17\xc0Y\xc0d\x06\x00\xa8\x19U\x90\x8f\x011o"
    OK
    
    127.0.0.1:6666> TYPE newkey
    set
    
    127.0.0.1:6666> SMEMBERS newkey
    1) "100"
    2) "12"
    3) "23"
    4) "5"
    5) "89"
    127.0.0.1:6666> DUMP nonexistent
    (nil)
    127.0.0.1:6666> exit
    
    ---------
    
    Co-authored-by: hulk <[email protected]>
---
 src/storage/rdb/rdb.cc              | 36 ++++++++++++++++++++++++++++++++++++
 src/storage/rdb/rdb.h               |  3 +++
 tests/gocase/unit/dump/dump_test.go | 27 +++++++++++++++++++++++++++
 3 files changed, 66 insertions(+)

diff --git a/src/storage/rdb/rdb.cc b/src/storage/rdb/rdb.cc
index 1f646bd75..5adf48f05 100644
--- a/src/storage/rdb/rdb.cc
+++ b/src/storage/rdb/rdb.cc
@@ -20,6 +20,8 @@
 
 #include "rdb.h"
 
+#include <limits>
+
 #include "common/encoding.h"
 #include "common/rdb_stream.h"
 #include "common/time_util.h"
@@ -35,6 +37,7 @@
 #include "types/redis_hash.h"
 #include "types/redis_list.h"
 #include "types/redis_set.h"
+#include "types/redis_sortedint.h"
 #include "types/redis_string.h"
 #include "types/redis_zset.h"
 #include "vendor/crc64.h"
@@ -730,6 +733,8 @@ Status RDB::SaveObjectType(const RedisType type) {
     robj_type = RDBTypeSet;
   } else if (type == kRedisZSet) {
     robj_type = RDBTypeZSet2;
+  } else if (type == kRedisSortedint) {
+    robj_type = RDBTypeSet;
   } else {
     WARN("Invalid or Not supported object type: {}", (int)type);
     return {Status::NotOK, "Invalid or Not supported object type"};
@@ -793,6 +798,23 @@ Status RDB::SaveObject(const std::string &key, const 
RedisType type) {
       return {Status::RedisExecErr, s.ToString()};
     }
     return SaveStringObject(value);
+  } else if (type == kRedisSortedint) {
+    redis::Sortedint sortedint_db(storage_, ns_);
+    std::vector<uint64_t> ids;
+    SortedintRangeSpec spec;
+    spec.min = 0;
+    spec.max = std::numeric_limits<uint64_t>::max();
+    spec.minex = false;
+    spec.maxex = false;
+    spec.offset = 0;
+    spec.count = std::numeric_limits<int>::max();
+    spec.reversed = false;
+    int size = 0;
+    auto si_status = sortedint_db.RangeByValue(ctx, key, spec, &ids, &size);
+    if (!si_status.ok()) {
+      return {Status::RedisExecErr, si_status.ToString()};
+    }
+    return SaveSortedintObject(ids);
   } else {
     WARN("Invalid or Not supported object type: {}", (int)type);
     return {Status::NotOK, "Invalid or Not supported object type"};
@@ -930,6 +952,20 @@ Status RDB::SaveHashObject(const std::vector<FieldValue> 
&field_values) {
   }
   return Status::OK();
 }
+Status RDB::SaveSortedintObject(const std::vector<uint64_t> &ids) {
+  if (ids.size() > 0) {
+    auto status = RdbSaveLen(ids.size());
+    if (!status.IsOK()) return status;
+
+    for (const auto &id : ids) {
+      status = SaveStringObject(std::to_string(id));
+      if (!status.IsOK()) return status;
+    }
+  } else {
+    return {Status::NotOK, "the size of sortedint is zero"};
+  }
+  return Status::OK();
+}
 
 int RDB::rdbEncodeInteger(const long long value, unsigned char *enc) {
   if (value >= -(1 << 7) && value <= (1 << 7) - 1) {
diff --git a/src/storage/rdb/rdb.h b/src/storage/rdb/rdb.h
index 1a528540d..0b4ba7b3c 100644
--- a/src/storage/rdb/rdb.h
+++ b/src/storage/rdb/rdb.h
@@ -130,6 +130,9 @@ class RDB {
   // Hash
   Status SaveHashObject(const std::vector<FieldValue> &field_value);
 
+  // SortedInt
+  Status SaveSortedintObject(const std::vector<uint64_t> &ids);
+
  private:
   engine::Storage *storage_;
   std::string ns_;
diff --git a/tests/gocase/unit/dump/dump_test.go 
b/tests/gocase/unit/dump/dump_test.go
index ea2625f06..278467033 100644
--- a/tests/gocase/unit/dump/dump_test.go
+++ b/tests/gocase/unit/dump/dump_test.go
@@ -193,3 +193,30 @@ func TestDump_IntegerEncoding(t *testing.T) {
                require.Equal(t, v, got)
        }
 }
+
+func TestDump_SortedInt(t *testing.T) {
+       srv := util.StartServer(t, map[string]string{})
+       defer srv.Close()
+
+       ctx := context.Background()
+       rdb := srv.NewClient()
+       defer func() { require.NoError(t, rdb.Close()) }()
+
+       key := "test_sortedint_key"
+       require.NoError(t, rdb.Del(ctx, key).Err())
+
+       require.EqualValues(t, 5, rdb.Do(ctx, "SIADD", key, 5, 12, 23, 89, 
100).Val())
+       require.EqualValues(t, 5, rdb.Do(ctx, "SICARD", key).Val())
+       require.EqualValues(t, "sortedint", rdb.Type(ctx, key).Val())
+
+       serialized, err := rdb.Dump(ctx, key).Result()
+       require.NoError(t, err)
+
+       restoredKey := fmt.Sprintf("restore_%s", key)
+       require.NoError(t, rdb.RestoreReplace(ctx, restoredKey, 0, 
serialized).Err())
+
+       require.EqualValues(t, "set", rdb.Type(ctx, restoredKey).Val())
+       members := rdb.SMembers(ctx, restoredKey).Val()
+       expectedMembers := []string{"5", "12", "23", "89", "100"}
+       require.ElementsMatch(t, expectedMembers, members)
+}

Reply via email to