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/incubator-kvrocks.git
The following commit(s) were added to refs/heads/unstable by this push:
new 1bcb7db Add the new command SMISMEMBER (#778)
1bcb7db is described below
commit 1bcb7dbe39af5ad16a39743420976a841c38fa14
Author: mathspanda <[email protected]>
AuthorDate: Tue Aug 16 09:51:46 2022 +0800
Add the new command SMISMEMBER (#778)
---
src/redis_cmd.cc | 26 ++++++++++++++++++++++++++
src/redis_set.cc | 28 ++++++++++++++++++++--------
src/redis_set.h | 1 +
tests/cppunit/t_set_test.cc | 20 ++++++++++++++++++++
tests/tcl/tests/unit/command.tcl | 4 ++--
tests/tcl/tests/unit/type/set.tcl | 34 ++++++++++++++++++++++++++++++++--
6 files changed, 101 insertions(+), 12 deletions(-)
diff --git a/src/redis_cmd.cc b/src/redis_cmd.cc
index 0e0ae25..7437635 100644
--- a/src/redis_cmd.cc
+++ b/src/redis_cmd.cc
@@ -1990,6 +1990,31 @@ class CommandSIsMember : public Commander {
}
};
+class CommandSMIsMember : public Commander {
+ public:
+ Status Execute(Server *svr, Connection *conn, std::string *output) override {
+ Redis::Set set_db(svr->storage_, conn->GetNamespace());
+ std::vector<Slice> members;
+ for (size_t i = 2; i < args_.size(); i++) {
+ members.emplace_back(Slice(args_[i]));
+ }
+
+ std::vector<int> exists;
+ rocksdb::Status s = set_db.MIsMember(args_[1], members, &exists);
+ if (!s.ok() && !s.IsNotFound()) {
+ return Status(Status::RedisExecErr, s.ToString());
+ }
+ if (s.IsNotFound()) {
+ exists.resize(members.size(), 0);
+ }
+ output->append(Redis::MultiLen(exists.size()));
+ for (const auto &exist : exists) {
+ output->append(Redis::Integer(exist));
+ }
+ return Status::OK();
+ }
+};
+
class CommandSPop : public Commander {
public:
Status Parse(const std::vector<std::string> &args) override {
@@ -4864,6 +4889,7 @@ CommandAttributes redisCommandTable[] = {
ADD_CMD("scard", 2, "read-only", 1, 1, 1, CommandSCard),
ADD_CMD("smembers", 2, "read-only", 1, 1, 1, CommandSMembers),
ADD_CMD("sismember", 3, "read-only", 1, 1, 1, CommandSIsMember),
+ ADD_CMD("smismember", -3, "read-only", 1, 1, 1, CommandSMIsMember),
ADD_CMD("spop", -2, "write", 1, 1, 1, CommandSPop),
ADD_CMD("srandmember", -2, "read-only", 1, 1, 1, CommandSRandMember),
ADD_CMD("smove", 4, "write", 1, 2, 1, CommandSMove),
diff --git a/src/redis_set.cc b/src/redis_set.cc
index f0aef9f..923a01b 100644
--- a/src/redis_set.cc
+++ b/src/redis_set.cc
@@ -165,24 +165,36 @@ rocksdb::Status Set::Members(const Slice &user_key,
std::vector<std::string> *me
}
rocksdb::Status Set::IsMember(const Slice &user_key, const Slice &member, int
*ret) {
- *ret = 0;
+ std::vector<int> exists;
+ rocksdb::Status s = MIsMember(user_key, {member}, &exists);
+ if (!s.ok()) return s;
+ *ret = exists[0];
+ return s;
+}
+
+rocksdb::Status Set::MIsMember(const Slice &user_key, const std::vector<Slice>
&members, std::vector<int> *exists) {
+ exists->clear();
std::string ns_key;
AppendNamespacePrefix(user_key, &ns_key);
SetMetadata metadata(false);
rocksdb::Status s = GetMetadata(ns_key, &metadata);
- if (!s.ok()) return s.IsNotFound() ? rocksdb::Status::OK() : s;
+ if (!s.ok()) return s;
rocksdb::ReadOptions read_options;
LatestSnapShot ss(db_);
read_options.snapshot = ss.GetSnapShot();
- std::string sub_key;
- InternalKey(ns_key, member, metadata.version,
storage_->IsSlotIdEncoded()).Encode(&sub_key);
- std::string value;
- s = db_->Get(read_options, sub_key, &value);
- if (s.ok()) {
- *ret = 1;
+ std::string sub_key, value;
+ for (const auto &member : members) {
+ InternalKey(ns_key, member, metadata.version,
storage_->IsSlotIdEncoded()).Encode(&sub_key);
+ s = db_->Get(read_options, sub_key, &value);
+ if (!s.ok() && !s.IsNotFound()) return s;
+ if (s.IsNotFound()) {
+ exists->emplace_back(0);
+ } else {
+ exists->emplace_back(1);
+ }
}
return rocksdb::Status::OK();
}
diff --git a/src/redis_set.h b/src/redis_set.h
index e36a7a8..63a01bf 100644
--- a/src/redis_set.h
+++ b/src/redis_set.h
@@ -35,6 +35,7 @@ class Set : public SubKeyScanner {
rocksdb::Status Card(const Slice &user_key, int *ret);
rocksdb::Status IsMember(const Slice &user_key, const Slice &member, int
*ret);
+ rocksdb::Status MIsMember(const Slice &user_key, const std::vector<Slice>
&members, std::vector<int> *exists);
rocksdb::Status Add(const Slice &user_key, const std::vector<Slice>
&members, int *ret);
rocksdb::Status Remove(const Slice &user_key, const std::vector<Slice>
&members, int *ret);
rocksdb::Status Members(const Slice &user_key, std::vector<std::string>
*members);
diff --git a/tests/cppunit/t_set_test.cc b/tests/cppunit/t_set_test.cc
index 4f6228a..50535f2 100644
--- a/tests/cppunit/t_set_test.cc
+++ b/tests/cppunit/t_set_test.cc
@@ -82,6 +82,26 @@ TEST_F(RedisSetTest, IsMember) {
set->Del(key_);
}
+TEST_F(RedisSetTest, MIsMember) {
+ int ret;
+ std::vector<int> exists;
+ rocksdb::Status s = set->Add(key_, fields_, &ret);
+ EXPECT_TRUE(s.ok() && static_cast<int>(fields_.size()) == ret);
+ s = set->MIsMember(key_, fields_, &exists);
+ EXPECT_TRUE(s.ok());
+ for (size_t i = 0; i < fields_.size(); i++) {
+ EXPECT_TRUE(exists[i] == 1);
+ }
+ s = set->Remove(key_, {fields_[0]}, &ret);
+ EXPECT_TRUE(s.ok() && ret == 1);
+ s = set->MIsMember(key_, fields_, &exists);
+ EXPECT_TRUE(s.ok() && exists[0] == 0);
+ for (size_t i = 1; i < fields_.size(); i++) {
+ EXPECT_TRUE(exists[i] == 1);
+ }
+ set->Del(key_);
+}
+
TEST_F(RedisSetTest, Move) {
int ret;
rocksdb::Status s = set->Add(key_, fields_, &ret);
diff --git a/tests/tcl/tests/unit/command.tcl b/tests/tcl/tests/unit/command.tcl
index 70f20e0..8579ac9 100644
--- a/tests/tcl/tests/unit/command.tcl
+++ b/tests/tcl/tests/unit/command.tcl
@@ -16,9 +16,9 @@
# under the License.
start_server {tags {"command"}} {
- test {kvrocks has 171 commands currently} {
+ test {kvrocks has 172 commands currently} {
r command count
- } {171}
+ } {172}
test {acquire GET command info by COMMAND INFO} {
set e [lindex [r command info get] 0]
diff --git a/tests/tcl/tests/unit/type/set.tcl
b/tests/tcl/tests/unit/type/set.tcl
index 3608961..e4bc9fa 100644
--- a/tests/tcl/tests/unit/type/set.tcl
+++ b/tests/tcl/tests/unit/type/set.tcl
@@ -29,7 +29,7 @@ start_server {
foreach entry $entries { r sadd $key $entry }
}
- test {SADD, SCARD, SISMEMBER, SMEMBERS basics - regular set} {
+ test {SADD, SCARD, SISMEMBER, SMISMEMBER, SMEMBERS basics - regular set} {
create_set myset {foo}
#assert_encoding hashtable myset
assert_equal 1 [r sadd myset bar]
@@ -38,10 +38,15 @@ start_server {
assert_equal 1 [r sismember myset foo]
assert_equal 1 [r sismember myset bar]
assert_equal 0 [r sismember myset bla]
+ assert_equal {1} [r smismember myset foo]
+ assert_equal {1 1} [r smismember myset foo bar]
+ assert_equal {1 0} [r smismember myset foo bla]
+ assert_equal {0 1} [r smismember myset bla foo]
+ assert_equal {0} [r smismember myset bla]
assert_equal {bar foo} [lsort [r smembers myset]]
}
- test {SADD, SCARD, SISMEMBER, SMEMBERS basics - intset} {
+ test {SADD, SCARD, SISMEMBER, SMISMEMBER, SMEMBERS basics - intset} {
create_set myset {17}
#assert_encoding intset myset
assert_equal 1 [r sadd myset 16]
@@ -50,9 +55,33 @@ start_server {
assert_equal 1 [r sismember myset 16]
assert_equal 1 [r sismember myset 17]
assert_equal 0 [r sismember myset 18]
+ assert_equal {1} [r smismember myset 16]
+ assert_equal {1 1} [r smismember myset 16 17]
+ assert_equal {1 0} [r smismember myset 16 18]
+ assert_equal {0 1} [r smismember myset 18 16]
+ assert_equal {0} [r smismember myset 18]
assert_equal {16 17} [lsort [r smembers myset]]
}
+ test {SMISMEMBER against non set} {
+ r lpush mylist foo
+ assert_error *WRONGTYPE* {r smismember mylist bar}
+ }
+
+ test {SMISMEMBER non existing key} {
+ assert_equal {0} [r smismember myset1 foo]
+ assert_equal {0 0} [r smismember myset1 foo bar]
+ }
+
+ test {SMISMEMBER requires one or more members} {
+ r del zmscoretest
+ r zadd zmscoretest 10 x
+ r zadd zmscoretest 20 y
+
+ catch {r smismember zmscoretest} e
+ assert_match {*ERR*wrong*number*arg*} $e
+ }
+
test {SADD against non set} {
r lpush mylist foo
assert_error *WRONGTYPE* {r sadd mylist bar}
@@ -69,6 +98,7 @@ start_server {
create_set myset {213244124402402314402033402}
#assert_encoding hashtable myset
assert_equal 1 [r sismember myset 213244124402402314402033402]
+ assert_equal {1} [r smismember myset 213244124402402314402033402]
}
test "SADD overflows the maximum allowed integers in an intset" {