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" {

Reply via email to