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 d6ea22a69 fix(bloom): crash due to pinnable slice in bloom filter 
(#2843)
d6ea22a69 is described below

commit d6ea22a69fd86ddb0fedd297a550ce02433d4f83
Author: mwish <[email protected]>
AuthorDate: Tue Mar 25 11:43:13 2025 +0800

    fix(bloom): crash due to pinnable slice in bloom filter (#2843)
---
 src/types/redis_bloom_chain.cc          | 25 +++++++++++++++------
 tests/cppunit/types/bloom_chain_test.cc | 40 ++++++++++++++++++++++++++++-----
 2 files changed, 53 insertions(+), 12 deletions(-)

diff --git a/src/types/redis_bloom_chain.cc b/src/types/redis_bloom_chain.cc
index 7dea8189b..cc2e45a23 100644
--- a/src/types/redis_bloom_chain.cc
+++ b/src/types/redis_bloom_chain.cc
@@ -195,6 +195,20 @@ rocksdb::Status BloomChain::InsertCommon(engine::Context 
&ctx, const Slice &user
     if (exist) {
       (*rets)[i] = BloomFilterAddResult::kExist;
     } else {
+      auto pinnable_slice_from_string = [](std::string data) -> 
rocksdb::PinnableSlice {
+        // This is a workaround for the issue that PinnableSlice does not 
support
+        // constructing from a temporary string.
+        rocksdb::PinnableSlice slice;
+        *slice.GetSelf() = std::move(data);
+        slice.PinSelf();
+        return slice;
+      };
+      auto strip_string_from_pinnable_slice = [](rocksdb::PinnableSlice 
&slice) -> std::string {
+        if (slice.GetSelf() != nullptr) {
+          return std::move(*slice.GetSelf());
+        }
+        return slice.ToString();
+      };
       if (metadata.size + 1 > metadata.GetCapacity()) {
         if (metadata.IsScaling()) {
           s = batch->Put(bf_key_list.back(), 
bf_data_list.back().ToStringView());
@@ -202,20 +216,17 @@ rocksdb::Status BloomChain::InsertCommon(engine::Context 
&ctx, const Slice &user
           std::string bf_data;
           s = createBloomFilterInBatch(ns_key, &metadata, batch, &bf_data);
           if (!s.ok()) return s;
-          rocksdb::PinnableSlice pin_slice;
-          *pin_slice.GetSelf() = std::move(bf_data);
-          pin_slice.PinSelf();
-          bf_data_list.push_back(std::move(pin_slice));
+          
bf_data_list.push_back(pinnable_slice_from_string(std::move(bf_data)));
           bf_key_list.push_back(getBFKey(ns_key, metadata, metadata.n_filters 
- 1));
         } else {
           (*rets)[i] = BloomFilterAddResult::kFull;
           continue;
         }
       }
-      std::string data = bf_data_list.back().ToString();
+      auto &bf_data = bf_data_list.back();
+      std::string data = strip_string_from_pinnable_slice(bf_data);
       bloomAdd(item_hash_list[i], data);
-      *bf_data_list.back().GetSelf() = std::move(data);
-      bf_data_list.back().PinSelf();
+      bf_data = pinnable_slice_from_string(std::move(data));
       (*rets)[i] = BloomFilterAddResult::kOk;
       metadata.size += 1;
     }
diff --git a/tests/cppunit/types/bloom_chain_test.cc 
b/tests/cppunit/types/bloom_chain_test.cc
index bf8048014..cace78d45 100644
--- a/tests/cppunit/types/bloom_chain_test.cc
+++ b/tests/cppunit/types/bloom_chain_test.cc
@@ -27,10 +27,13 @@
 
 class RedisBloomChainTest : public TestBase {
  protected:
-  explicit RedisBloomChainTest() { sb_chain_ = 
std::make_unique<redis::BloomChain>(storage_.get(), "sb_chain_ns"); }
+  explicit RedisBloomChainTest() = default;
   ~RedisBloomChainTest() override = default;
 
-  void SetUp() override { key_ = "test_sb_chain_key"; }
+  void SetUp() override {
+    key_ = "test_sb_chain_key";
+    sb_chain_ = std::make_unique<redis::BloomChain>(storage_.get(), 
"sb_chain_ns");
+  }
   void TearDown() override {}
 
   std::unique_ptr<redis::BloomChain> sb_chain_;
@@ -48,8 +51,6 @@ TEST_F(RedisBloomChainTest, Reserve) {
   s = sb_chain_->Reserve(*ctx_, key_, capacity, error_rate, expansion);
   EXPECT_FALSE(s.ok());
   EXPECT_EQ(s.ToString(), "Invalid argument: the key already exists");
-
-  s = sb_chain_->Del(*ctx_, key_);
 }
 
 TEST_F(RedisBloomChainTest, BasicAddAndTest) {
@@ -79,5 +80,34 @@ TEST_F(RedisBloomChainTest, BasicAddAndTest) {
     EXPECT_TRUE(s.ok());
     EXPECT_EQ(exist, false);
   }
-  s = sb_chain_->Del(*ctx_, key_);
+}
+
+TEST_F(RedisBloomChainTest, DuplicateInsert) {
+  std::string insert_items[] = {"item1", "item2", "item3", "item101", 
"item202", "303"};
+  for (const auto& insert_item : insert_items) {
+    redis::BloomFilterAddResult ret = redis::BloomFilterAddResult::kOk;
+    auto s = sb_chain_->Add(*ctx_, key_, insert_item, &ret);
+    EXPECT_TRUE(s.ok());
+    EXPECT_EQ(ret, redis::BloomFilterAddResult::kOk);
+  }
+  std::vector<std::string> arrays;
+  for (int64_t idx = 0; idx < 1000; ++idx) {
+    arrays.push_back("itemx" + std::to_string(idx));
+  }
+  std::vector<redis::BloomFilterAddResult> results;
+  results.resize(arrays.size());
+  auto s = sb_chain_->MAdd(*ctx_, key_, arrays, &results);
+  EXPECT_TRUE(s.ok());
+  arrays.clear();
+  for (int64_t idx = 1000; idx < 2000; ++idx) {
+    arrays.push_back("itemx" + std::to_string(idx));
+  }
+  s = sb_chain_->MAdd(*ctx_, key_, arrays, &results);
+  EXPECT_TRUE(s.ok());
+  arrays.clear();
+  for (int64_t idx = 2000; idx < 3000; ++idx) {
+    arrays.push_back("itemx" + std::to_string(idx));
+  }
+  s = sb_chain_->MAdd(*ctx_, key_, arrays, &results);
+  EXPECT_TRUE(s.ok());
 }

Reply via email to