This is an automated email from the ASF dual-hosted git repository.
twice 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 963861d5f feat(hash): support NOVALUES in HSCAN (#3109)
963861d5f is described below
commit 963861d5fe378ac4d8b22336fc509ae3593e21ab
Author: Qiang-Liu <[email protected]>
AuthorDate: Wed Aug 13 09:55:02 2025 +0800
feat(hash): support NOVALUES in HSCAN (#3109)
---
src/commands/cmd_hash.cc | 12 +++++++++---
src/commands/scan_base.h | 3 +++
tests/gocase/unit/type/hash/hash_test.go | 17 +++++++++++++++++
3 files changed, 29 insertions(+), 3 deletions(-)
diff --git a/src/commands/cmd_hash.cc b/src/commands/cmd_hash.cc
index 13d13de8a..35e7c9856 100644
--- a/src/commands/cmd_hash.cc
+++ b/src/commands/cmd_hash.cc
@@ -408,17 +408,23 @@ class CommandHScan : public CommandSubkeyScanBase {
std::vector<std::string> values;
auto key_name = srv->GetKeyNameFromCursor(cursor_, CursorType::kTypeHash);
- auto s = hash_db.Scan(ctx, key_, key_name, limit_, prefix_, &fields,
&values);
+ auto s = hash_db.Scan(ctx, key_, key_name, limit_, prefix_, &fields,
no_values_ ? nullptr : &values);
if (!s.ok() && !s.IsNotFound()) {
return {Status::RedisExecErr, s.ToString()};
}
auto cursor = GetNextCursor(srv, fields, CursorType::kTypeHash);
std::vector<std::string> entries;
- entries.reserve(2 * fields.size());
+ if (no_values_) {
+ entries.reserve(fields.size());
+ } else {
+ entries.reserve(2 * fields.size());
+ }
for (size_t i = 0; i < fields.size(); i++) {
entries.emplace_back(redis::BulkString(fields[i]));
- entries.emplace_back(redis::BulkString(values[i]));
+ if (!no_values_) {
+ entries.emplace_back(redis::BulkString(values[i]));
+ }
}
*output = redis::Array({redis::BulkString(cursor), redis::Array(entries)});
return Status::OK();
diff --git a/src/commands/scan_base.h b/src/commands/scan_base.h
index 5a0d4ca17..d80c1e4e1 100644
--- a/src/commands/scan_base.h
+++ b/src/commands/scan_base.h
@@ -64,6 +64,8 @@ class CommandScanBase : public Commander {
} else {
return {Status::RedisExecErr, "Invalid type"};
}
+ } else if (parser.EatEqICase("novalues")) {
+ no_values_ = true;
} else {
return parser.InvalidSyntax();
}
@@ -102,6 +104,7 @@ class CommandScanBase : public Commander {
std::string suffix_glob_ = "*";
int limit_ = 20;
RedisType type_ = kRedisNone;
+ bool no_values_ = false;
};
class CommandSubkeyScanBase : public CommandScanBase {
diff --git a/tests/gocase/unit/type/hash/hash_test.go
b/tests/gocase/unit/type/hash/hash_test.go
index 8d1536796..eb568b257 100644
--- a/tests/gocase/unit/type/hash/hash_test.go
+++ b/tests/gocase/unit/type/hash/hash_test.go
@@ -775,6 +775,23 @@ var testHash = func(t *testing.T, configs
util.KvrocksServerConfigs) {
require.Equal(t, "b", rdb.HGet(ctx, "hash", strings.Repeat("k",
336)).Val())
})
+ t.Run("HSCAN without NOVALUES", func(t *testing.T) {
+ rdb.Del(ctx, "langhash")
+ rdb.HMSet(ctx, "langhash", []string{"lang1", "C++", "lang2",
"JavaScript", "lang3", "Python", "lang4", "GoLanguage"})
+ res, _, _ := rdb.HScan(ctx, "langhash", 0, "lang1", 0).Result()
+ require.Equal(t, 2, len(res))
+ require.Equal(t, "lang1", res[0])
+ require.Equal(t, "C++", res[1])
+ })
+
+ t.Run("HSCAN with NOVALUES", func(t *testing.T) {
+ rdb.Del(ctx, "langhash")
+ rdb.HMSet(ctx, "langhash", []string{"lang1", "C++", "lang2",
"JavaScript", "lang3", "Python", "lang4", "GoLanguage"})
+ res, _, _ := rdb.HScanNoValues(ctx, "langhash", 0, "lang1",
0).Result()
+ require.Equal(t, 1, len(res))
+ require.Equal(t, "lang1", res[0])
+ })
+
for _, size := range []int64{10, 512} {
t.Run(fmt.Sprintf("Hash fuzzing #1 - %d fields", size), func(t
*testing.T) {
for times := 0; times < 10; times++ {