diff --git a/CMakeLists.txt b/CMakeLists.txt index 41b2d897f0..4fe49879c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -659,7 +659,6 @@ ExternalProject_Add(rediscache set(REDISCACHE_INCLUDE_DIR ${INSTALL_INCLUDEDIR}) set(REDISCACHE_LIBRARY ${INSTALL_LIBDIR}/librediscache.a) - option(USE_PIKA_TOOLS "compile pika-tools" OFF) if (USE_PIKA_TOOLS) ExternalProject_Add(hiredis diff --git a/include/pika_admin.h b/include/pika_admin.h index 67a1969820..3613c38289 100644 --- a/include/pika_admin.h +++ b/include/pika_admin.h @@ -466,13 +466,18 @@ class PKPatternMatchDelCmd : public Cmd { PKPatternMatchDelCmd(const std::string& name, int arity, uint32_t flag) : Cmd(name, arity, flag, static_cast(AclCategory::ADMIN)) {} void Do() override; + void DoThroughDB() override; + void DoUpdateCache() override; void Split(const HintKeys& hint_keys) override {}; void Merge() override {}; Cmd* Clone() override { return new PKPatternMatchDelCmd(*this); } + void DoBinlog() override; private: - storage::DataType type_ = storage::DataType::kAll; + storage::DataType type_; + std::vector remove_keys_; std::string pattern_; + int64_t max_count_; void DoInitial() override; }; diff --git a/src/pika_admin.cc b/src/pika_admin.cc index 870aaf965a..963ae489f1 100644 --- a/src/pika_admin.cc +++ b/src/pika_admin.cc @@ -3136,16 +3136,53 @@ void PKPatternMatchDelCmd::DoInitial() { return; } pattern_ = argv_[1]; + max_count_ = storage::BATCH_DELETE_LIMIT; + if (argv_.size() > 2) { + if (pstd::string2int(argv_[2].data(), argv_[2].size(), &max_count_) == 0 || max_count_ < 1 || max_count_ > storage::BATCH_DELETE_LIMIT) { + res_.SetRes(CmdRes::kInvalidInt); + return; + } + } } -//TODO: may lead to inconsistent between rediscache and db, because currently it only cleans db void PKPatternMatchDelCmd::Do() { - int ret = 0; - rocksdb::Status s = db_->storage()->PKPatternMatchDel(type_, pattern_, &ret); - if (s.ok()) { - res_.AppendInteger(ret); + int64_t count = 0; + rocksdb::Status s = db_->storage()->PKPatternMatchDelWithRemoveKeys(pattern_, &count, &remove_keys_, max_count_); + + if(s.ok()) { + res_.AppendInteger(count); + s_ = rocksdb::Status::OK(); + for (const auto& key : remove_keys_) { + RemSlotKey(key, db_); + } } else { res_.SetRes(CmdRes::kErrOther, s.ToString()); + if (count >= 0) { + s_ = rocksdb::Status::OK(); + for (const auto& key : remove_keys_) { + RemSlotKey(key, db_); + } + } + } +} + +void PKPatternMatchDelCmd::DoThroughDB() { + Do(); +} + +void PKPatternMatchDelCmd::DoUpdateCache() { + if(s_.ok()) { + db_->cache()->Del(remove_keys_); + } +} + +void PKPatternMatchDelCmd::DoBinlog() { + std::string opt = "del"; + for(auto& key: remove_keys_) { + argv_.clear(); + argv_.emplace_back(opt); + argv_.emplace_back(key); + Cmd::DoBinlog(); } } diff --git a/src/pika_command.cc b/src/pika_command.cc index b374218cb6..b86b0483c4 100644 --- a/src/pika_command.cc +++ b/src/pika_command.cc @@ -130,7 +130,7 @@ void InitCmdTable(CmdTable* cmd_table) { cmd_table->insert(std::pair>(kCmdNamePadding, std::move(paddingptr))); std::unique_ptr pkpatternmatchdelptr = - std::make_unique(kCmdNamePKPatternMatchDel, 2, kCmdFlagsWrite | kCmdFlagsAdmin); + std::make_unique(kCmdNamePKPatternMatchDel, -2, kCmdFlagsWrite | kCmdFlagsAdmin); cmd_table->insert( std::pair>(kCmdNamePKPatternMatchDel, std::move(pkpatternmatchdelptr))); std::unique_ptr dummyptr = std::make_unique(kCmdDummy, 0, kCmdFlagsWrite); diff --git a/src/storage/include/storage/storage.h b/src/storage/include/storage/storage.h index 0b520f5800..5dd638a990 100644 --- a/src/storage/include/storage/storage.h +++ b/src/storage/include/storage/storage.h @@ -985,7 +985,7 @@ class Storage { // Traverses the database of the specified type, removing the Key that matches // the pattern - Status PKPatternMatchDel(const DataType& data_type, const std::string& pattern, int32_t* ret); + Status PKPatternMatchDelWithRemoveKeys(const std::string& pattern, int64_t* ret, std::vector* remove_keys, const int64_t& max_count); // Iterate over a collection of elements // return next_key that the user need to use as the start_key argument diff --git a/src/storage/src/redis.h b/src/storage/src/redis.h index ccad635263..1164aba1af 100644 --- a/src/storage/src/redis.h +++ b/src/storage/src/redis.h @@ -189,7 +189,7 @@ class Redis { Status Expireat(const Slice& key, int64_t timestamp); Status Persist(const Slice& key); Status TTL(const Slice& key, int64_t* timestamp); - Status PKPatternMatchDel(const std::string& pattern, int32_t* ret); + Status PKPatternMatchDelWithRemoveKeys(const std::string& pattern, int64_t* ret, std::vector* remove_keys, const int64_t& max_count); Status GetType(const Slice& key, enum DataType& type); Status IsExist(const Slice& key); diff --git a/src/storage/src/redis_strings.cc b/src/storage/src/redis_strings.cc index f282142e2f..a71128e4dc 100644 --- a/src/storage/src/redis_strings.cc +++ b/src/storage/src/redis_strings.cc @@ -1689,7 +1689,7 @@ rocksdb::Status Redis::IsExist(const storage::Slice& key) { /* * Example Delete the specified prefix key */ -rocksdb::Status Redis::PKPatternMatchDel(const std::string& pattern, int32_t* ret) { +rocksdb::Status Redis::PKPatternMatchDelWithRemoveKeys(const std::string& pattern, int64_t* ret, std::vector* remove_keys, const int64_t& max_count) { rocksdb::ReadOptions iterator_options; const rocksdb::Snapshot* snapshot; ScopeSnapshot ss(db_, &snapshot); @@ -1698,12 +1698,12 @@ rocksdb::Status Redis::PKPatternMatchDel(const std::string& pattern, int32_t* re std::string key; std::string meta_value; - int32_t total_delete = 0; + int64_t total_delete = 0; rocksdb::Status s; rocksdb::WriteBatch batch; rocksdb::Iterator* iter = db_->NewIterator(iterator_options, handles_[kMetaCF]); iter->SeekToFirst(); - while (iter->Valid()) { + while (iter->Valid() && static_cast(batch.Count()) < max_count) { auto meta_type = static_cast(static_cast(iter->value()[0])); ParsedBaseMetaKey parsed_meta_key(iter->key().ToString()); key = iter->key().ToString(); @@ -1714,6 +1714,7 @@ rocksdb::Status Redis::PKPatternMatchDel(const std::string& pattern, int32_t* re if (!parsed_strings_value.IsStale() && (StringMatch(pattern.data(), pattern.size(), parsed_meta_key.Key().data(), parsed_meta_key.Key().size(), 0) != 0)) { batch.Delete(key); + remove_keys->push_back(parsed_meta_key.Key().data()); } } else if (meta_type == DataType::kLists) { ParsedListsMetaValue parsed_lists_meta_value(&meta_value); @@ -1722,6 +1723,7 @@ rocksdb::Status Redis::PKPatternMatchDel(const std::string& pattern, int32_t* re 0)) { parsed_lists_meta_value.InitialMetaValue(); batch.Put(handles_[kMetaCF], iter->key(), meta_value); + remove_keys->push_back(parsed_meta_key.Key().data()); } } else if (meta_type == DataType::kStreams) { StreamMetaValue stream_meta_value; @@ -1730,6 +1732,7 @@ rocksdb::Status Redis::PKPatternMatchDel(const std::string& pattern, int32_t* re (StringMatch(pattern.data(), pattern.size(), parsed_meta_key.Key().data(), parsed_meta_key.Key().size(), 0) != 0)) { stream_meta_value.InitMetaValue(); batch.Put(handles_[kMetaCF], key, stream_meta_value.value()); + remove_keys->push_back(parsed_meta_key.Key().data()); } } else { ParsedBaseMetaValue parsed_meta_value(&meta_value); @@ -1738,18 +1741,7 @@ rocksdb::Status Redis::PKPatternMatchDel(const std::string& pattern, int32_t* re 0)) { parsed_meta_value.InitialMetaValue(); batch.Put(handles_[kMetaCF], iter->key(), meta_value); - } - } - - if (static_cast(batch.Count()) >= BATCH_DELETE_LIMIT) { - s = db_->Write(default_write_options_, &batch); - if (s.ok()) { - total_delete += static_cast(batch.Count()); - batch.Clear(); - } else { - *ret = total_delete; - delete iter; - return s; + remove_keys->push_back(parsed_meta_key.Key().data()); } } iter->Next(); @@ -1757,13 +1749,16 @@ rocksdb::Status Redis::PKPatternMatchDel(const std::string& pattern, int32_t* re if (batch.Count() != 0U) { s = db_->Write(default_write_options_, &batch); if (s.ok()) { - total_delete += static_cast(batch.Count()); + total_delete += static_cast(batch.Count()); batch.Clear(); + } else { + remove_keys->erase(remove_keys->end() - batch.Count(), remove_keys->end()); } } - delete iter; *ret = total_delete; + delete iter; return s; } + } // namespace storage diff --git a/src/storage/src/storage.cc b/src/storage/src/storage.cc index a264783927..8002026ab7 100644 --- a/src/storage/src/storage.cc +++ b/src/storage/src/storage.cc @@ -1399,16 +1399,20 @@ Status Storage::PKRScanRange(const DataType& data_type, const Slice& key_start, return Status::OK(); } -Status Storage::PKPatternMatchDel(const DataType& data_type, const std::string& pattern, int32_t* ret) { +Status Storage::PKPatternMatchDelWithRemoveKeys(const std::string& pattern, int64_t* ret, + std::vector* remove_keys, const int64_t& max_count) { Status s; *ret = 0; for (const auto& inst : insts_) { - int32_t tmp_ret = 0; - s = inst->PKPatternMatchDel(pattern, &tmp_ret); + int64_t tmp_ret = 0; + s = inst->PKPatternMatchDelWithRemoveKeys(pattern, &tmp_ret, remove_keys, max_count - *ret); if (!s.ok()) { return s; - } + } *ret += tmp_ret; + if (*ret == max_count) { + return s; + } } return s; } diff --git a/src/storage/tests/keys_test.cc b/src/storage/tests/keys_test.cc index 4609da95f2..09292872f0 100644 --- a/src/storage/tests/keys_test.cc +++ b/src/storage/tests/keys_test.cc @@ -2098,8 +2098,10 @@ for (const auto& kv : kvs) { TEST_F(KeysTest, PKPatternMatchDel) { int32_t ret; uint64_t ret64; - int32_t delete_count = 0; + int64_t delete_count = 0; std::vector keys; + std::vector remove_keys; + const int64_t max_count = storage::BATCH_DELETE_LIMIT; std::map type_status; //=============================== Strings =============================== @@ -2111,10 +2113,12 @@ TEST_F(KeysTest, PKPatternMatchDel) { db.Set("GP1_PKPATTERNMATCHDEL_STRING_KEY4", "VALUE"); db.Set("GP1_PKPATTERNMATCHDEL_STRING_KEY5", "VALUE"); db.Set("GP1_PKPATTERNMATCHDEL_STRING_KEY6", "VALUE"); - s = db.PKPatternMatchDel(DataType::kStrings, "*", &delete_count); + s = db.PKPatternMatchDelWithRemoveKeys("*", &delete_count, &remove_keys, max_count); ASSERT_TRUE(s.ok()); ASSERT_EQ(delete_count, 6); + ASSERT_EQ(remove_keys.size(), 6); keys.clear(); + remove_keys.clear(); db.Keys(DataType::kStrings, "*", &keys); ASSERT_EQ(keys.size(), 0); @@ -2128,10 +2132,13 @@ TEST_F(KeysTest, PKPatternMatchDel) { ASSERT_TRUE(make_expired(&db, "GP2_PKPATTERNMATCHDEL_STRING_KEY1")); ASSERT_TRUE(make_expired(&db, "GP2_PKPATTERNMATCHDEL_STRING_KEY3")); ASSERT_TRUE(make_expired(&db, "GP2_PKPATTERNMATCHDEL_STRING_KEY5")); - s = db.PKPatternMatchDel(DataType::kStrings, "*", &delete_count); + s = db.PKPatternMatchDelWithRemoveKeys("*", &delete_count, &remove_keys, max_count); ASSERT_TRUE(s.ok()); ASSERT_EQ(delete_count, 3); + ASSERT_EQ(remove_keys.size(), 3); keys.clear(); + remove_keys.clear(); + db.Keys(DataType::kStrings, "*", &keys); db.Keys(DataType::kStrings, "*", &keys); ASSERT_EQ(keys.size(), 0); @@ -2142,10 +2149,12 @@ TEST_F(KeysTest, PKPatternMatchDel) { db.Set("GP3_PKPATTERNMATCHDEL_STRING_KEY4_0ooo0", "VALUE"); db.Set("GP3_PKPATTERNMATCHDEL_STRING_KEY5_0xxx0", "VALUE"); db.Set("GP3_PKPATTERNMATCHDEL_STRING_KEY6_0ooo0", "VALUE"); - s = db.PKPatternMatchDel(DataType::kStrings, "*0xxx0", &delete_count); + s = db.PKPatternMatchDelWithRemoveKeys("*0xxx0", &delete_count, &remove_keys, max_count); ASSERT_TRUE(s.ok()); ASSERT_EQ(delete_count, 3); + ASSERT_EQ(remove_keys.size(), 3); keys.clear(); + remove_keys.clear(); db.Keys(DataType::kStrings, "*", &keys); ASSERT_EQ(keys.size(), 3); ASSERT_EQ(keys[0], "GP3_PKPATTERNMATCHDEL_STRING_KEY2_0ooo0"); @@ -2164,10 +2173,12 @@ TEST_F(KeysTest, PKPatternMatchDel) { ASSERT_TRUE(make_expired(&db, "GP4_PKPATTERNMATCHDEL_STRING_KEY1")); ASSERT_TRUE(make_expired(&db, "GP4_PKPATTERNMATCHDEL_STRING_KEY3")); ASSERT_TRUE(make_expired(&db, "GP4_PKPATTERNMATCHDEL_STRING_KEY5")); - s = db.PKPatternMatchDel(DataType::kStrings, "*0ooo0", &delete_count); + s = db.PKPatternMatchDelWithRemoveKeys("*0ooo0", &delete_count, &remove_keys, max_count); ASSERT_TRUE(s.ok()); ASSERT_EQ(delete_count, 3); + ASSERT_EQ(remove_keys.size(), 3); keys.clear(); + remove_keys.clear(); db.Keys(DataType::kStrings, "*", &keys); ASSERT_EQ(keys.size(), 0); @@ -2176,12 +2187,15 @@ TEST_F(KeysTest, PKPatternMatchDel) { for (size_t idx = 0; idx < gp5_total_kv; ++idx) { db.Set("GP5_PKPATTERNMATCHDEL_STRING_KEY" + std::to_string(idx), "VALUE"); } - s = db.PKPatternMatchDel(DataType::kStrings, "*", &delete_count); + s = db.PKPatternMatchDelWithRemoveKeys("*", &delete_count, &remove_keys, max_count); ASSERT_TRUE(s.ok()); - ASSERT_EQ(delete_count, gp5_total_kv); + ASSERT_EQ(delete_count, max_count); + ASSERT_EQ(remove_keys.size(), max_count); keys.clear(); + remove_keys.clear(); db.Keys(DataType::kStrings, "*", &keys); - ASSERT_EQ(keys.size(), 0); + ASSERT_EQ(keys.size(), gp5_total_kv - max_count); + db.Del(keys); //=============================== Set =============================== @@ -2192,10 +2206,12 @@ TEST_F(KeysTest, PKPatternMatchDel) { db.SAdd("GP1_PKPATTERNMATCHDEL_SET_KEY4", {"M1"}, &ret); db.SAdd("GP1_PKPATTERNMATCHDEL_SET_KEY5", {"M1"}, &ret); db.SAdd("GP1_PKPATTERNMATCHDEL_SET_KEY6", {"M1"}, &ret); - s = db.PKPatternMatchDel(DataType::kSets, "*", &delete_count); + s = db.PKPatternMatchDelWithRemoveKeys("*", &delete_count, &remove_keys, max_count); ASSERT_TRUE(s.ok()); ASSERT_EQ(delete_count, 6); + ASSERT_EQ(remove_keys.size(), 6); keys.clear(); + remove_keys.clear(); db.Keys(DataType::kSets, "*", &keys); ASSERT_EQ(keys.size(), 0); @@ -2209,10 +2225,12 @@ TEST_F(KeysTest, PKPatternMatchDel) { ASSERT_TRUE(make_expired(&db, "GP2_PKPATTERNMATCHDEL_SET_KEY1")); ASSERT_TRUE(make_expired(&db, "GP2_PKPATTERNMATCHDEL_SET_KEY3")); ASSERT_TRUE(make_expired(&db, "GP2_PKPATTERNMATCHDEL_SET_KEY5")); - s = db.PKPatternMatchDel(DataType::kSets, "*", &delete_count); + s = db.PKPatternMatchDelWithRemoveKeys("*", &delete_count, &remove_keys, max_count); ASSERT_TRUE(s.ok()); ASSERT_EQ(delete_count, 3); + ASSERT_EQ(remove_keys.size(), 3); keys.clear(); + remove_keys.clear(); db.Keys(DataType::kSets, "*", &keys); ASSERT_EQ(keys.size(), 0); @@ -2223,10 +2241,12 @@ TEST_F(KeysTest, PKPatternMatchDel) { db.SAdd("GP3_PKPATTERNMATCHDEL_SET_KEY4_0ooo0", {"M1"}, &ret); db.SAdd("GP3_PKPATTERNMATCHDEL_SET_KEY5_0xxx0", {"M1"}, &ret); db.SAdd("GP3_PKPATTERNMATCHDEL_SET_KEY6_0ooo0", {"M1"}, &ret); - s = db.PKPatternMatchDel(DataType::kSets, "*0ooo0", &delete_count); + s = db.PKPatternMatchDelWithRemoveKeys("*0ooo0", &delete_count, &remove_keys, max_count); ASSERT_TRUE(s.ok()); ASSERT_EQ(delete_count, 3); + ASSERT_EQ(remove_keys.size(), 3); keys.clear(); + remove_keys.clear(); db.Keys(DataType::kSets, "*", &keys); ASSERT_EQ(keys.size(), 3); ASSERT_EQ("GP3_PKPATTERNMATCHDEL_SET_KEY1_0xxx0", keys[0]); @@ -2245,10 +2265,12 @@ TEST_F(KeysTest, PKPatternMatchDel) { db.SRem("GP4_PKPATTERNMATCHDEL_SET_KEY1", {"M1"}, &ret); db.SRem("GP4_PKPATTERNMATCHDEL_SET_KEY3", {"M1"}, &ret); db.SRem("GP4_PKPATTERNMATCHDEL_SET_KEY5", {"M1"}, &ret); - s = db.PKPatternMatchDel(DataType::kSets, "*", &delete_count); + s = db.PKPatternMatchDelWithRemoveKeys("*", &delete_count, &remove_keys, max_count); ASSERT_TRUE(s.ok()); ASSERT_EQ(delete_count, 3); + ASSERT_EQ(remove_keys.size(), 3); keys.clear(); + remove_keys.clear(); db.Keys(DataType::kSets, "*", &keys); ASSERT_EQ(keys.size(), 0); @@ -2265,10 +2287,12 @@ TEST_F(KeysTest, PKPatternMatchDel) { ASSERT_TRUE(make_expired(&db, "GP5_PKPATTERNMATCHDEL_SET_KEY2_0xxx0")); db.SRem("GP5_PKPATTERNMATCHDEL_SET_KEY3_0ooo0", {"M1"}, &ret); db.SRem("GP5_PKPATTERNMATCHDEL_SET_KEY4_0xxx0", {"M1"}, &ret); - s = db.PKPatternMatchDel(DataType::kSets, "*0ooo0", &delete_count); + s = db.PKPatternMatchDelWithRemoveKeys("*0ooo0", &delete_count, &remove_keys, max_count); ASSERT_TRUE(s.ok()); ASSERT_EQ(delete_count, 2); + ASSERT_EQ(remove_keys.size(), 2); keys.clear(); + remove_keys.clear(); db.Keys(DataType::kSets, "*", &keys); ASSERT_EQ(keys.size(), 2); ASSERT_EQ(keys[0], "GP5_PKPATTERNMATCHDEL_SET_KEY6_0xxx0"); @@ -2281,12 +2305,15 @@ TEST_F(KeysTest, PKPatternMatchDel) { for (size_t idx = 0; idx < gp6_total_set; ++idx) { db.SAdd("GP6_PKPATTERNMATCHDEL_SET_KEY" + std::to_string(idx), {"M1"}, &ret); } - s = db.PKPatternMatchDel(DataType::kSets, "*", &delete_count); + s = db.PKPatternMatchDelWithRemoveKeys("*", &delete_count, &remove_keys, max_count); ASSERT_TRUE(s.ok()); - ASSERT_EQ(delete_count, gp6_total_set); + ASSERT_EQ(delete_count, max_count); + ASSERT_EQ(remove_keys.size(), max_count); keys.clear(); + remove_keys.clear(); db.Keys(DataType::kSets, "*", &keys); - ASSERT_EQ(keys.size(), 0); + ASSERT_EQ(keys.size(), gp6_total_set - max_count); + db.Del(keys); //=============================== Hashes =============================== @@ -2297,10 +2324,12 @@ TEST_F(KeysTest, PKPatternMatchDel) { db.HSet("GP1_PKPATTERNMATCHDEL_HASH_KEY4", "FIELD", "VALUE", &ret); db.HSet("GP1_PKPATTERNMATCHDEL_HASH_KEY5", "FIELD", "VALUE", &ret); db.HSet("GP1_PKPATTERNMATCHDEL_HASH_KEY6", "FIELD", "VALUE", &ret); - s = db.PKPatternMatchDel(DataType::kHashes, "*", &delete_count); + s = db.PKPatternMatchDelWithRemoveKeys("*", &delete_count, &remove_keys, max_count); ASSERT_TRUE(s.ok()); ASSERT_EQ(delete_count, 6); + ASSERT_EQ(remove_keys.size(), 6); keys.clear(); + remove_keys.clear(); db.Keys(DataType::kHashes, "*", &keys); ASSERT_EQ(keys.size(), 0); @@ -2314,10 +2343,12 @@ TEST_F(KeysTest, PKPatternMatchDel) { ASSERT_TRUE(make_expired(&db, "GP2_PKPATTERNMATCHDEL_HASH_KEY1")); ASSERT_TRUE(make_expired(&db, "GP2_PKPATTERNMATCHDEL_HASH_KEY3")); ASSERT_TRUE(make_expired(&db, "GP2_PKPATTERNMATCHDEL_HASH_KEY5")); - s = db.PKPatternMatchDel(DataType::kHashes, "*", &delete_count); + s = db.PKPatternMatchDelWithRemoveKeys("*", &delete_count, &remove_keys, max_count); ASSERT_TRUE(s.ok()); ASSERT_EQ(delete_count, 3); + ASSERT_EQ(remove_keys.size(), 3); keys.clear(); + remove_keys.clear(); db.Keys(DataType::kHashes, "*", &keys); ASSERT_EQ(keys.size(), 0); @@ -2328,10 +2359,12 @@ TEST_F(KeysTest, PKPatternMatchDel) { db.HSet("GP3_PKPATTERNMATCHDEL_HASH_KEY4_0ooo0", "FIELD", "VALUE", &ret); db.HSet("GP3_PKPATTERNMATCHDEL_HASH_KEY5_0xxx0", "FIELD", "VALUE", &ret); db.HSet("GP3_PKPATTERNMATCHDEL_HASH_KEY6_0ooo0", "FIELD", "VALUE", &ret); - s = db.PKPatternMatchDel(DataType::kHashes, "*0ooo0", &delete_count); + s = db.PKPatternMatchDelWithRemoveKeys("*0ooo0", &delete_count, &remove_keys, max_count); ASSERT_TRUE(s.ok()); ASSERT_EQ(delete_count, 3); + ASSERT_EQ(remove_keys.size(), 3); keys.clear(); + remove_keys.clear(); db.Keys(DataType::kHashes, "*", &keys); ASSERT_EQ(keys.size(), 3); ASSERT_EQ("GP3_PKPATTERNMATCHDEL_HASH_KEY1_0xxx0", keys[0]); @@ -2350,10 +2383,12 @@ TEST_F(KeysTest, PKPatternMatchDel) { db.HDel("GP4_PKPATTERNMATCHDEL_HASH_KEY1", {"FIELD"}, &ret); db.HDel("GP4_PKPATTERNMATCHDEL_HASH_KEY3", {"FIELD"}, &ret); db.HDel("GP4_PKPATTERNMATCHDEL_HASH_KEY5", {"FIELD"}, &ret); - s = db.PKPatternMatchDel(DataType::kHashes, "*", &delete_count); + s = db.PKPatternMatchDelWithRemoveKeys("*", &delete_count, &remove_keys, max_count); ASSERT_TRUE(s.ok()); ASSERT_EQ(delete_count, 3); + ASSERT_EQ(remove_keys.size(), 3); keys.clear(); + remove_keys.clear(); db.Keys(DataType::kHashes, "*", &keys); ASSERT_EQ(keys.size(), 0); @@ -2370,10 +2405,12 @@ TEST_F(KeysTest, PKPatternMatchDel) { ASSERT_TRUE(make_expired(&db, "GP5_PKPATTERNMATCHDEL_HASH_KEY2_0xxx0")); db.HDel("GP5_PKPATTERNMATCHDEL_HASH_KEY3_0ooo0", {"FIELD"}, &ret); db.HDel("GP5_PKPATTERNMATCHDEL_HASH_KEY4_0xxx0", {"FIELD"}, &ret); - s = db.PKPatternMatchDel(DataType::kHashes, "*0ooo0", &delete_count); + s = db.PKPatternMatchDelWithRemoveKeys("*0ooo0", &delete_count, &remove_keys, max_count); ASSERT_TRUE(s.ok()); ASSERT_EQ(delete_count, 2); + ASSERT_EQ(remove_keys.size(), 2); keys.clear(); + remove_keys.clear(); db.Keys(DataType::kHashes, "*", &keys); ASSERT_EQ(keys.size(), 2); ASSERT_EQ(keys[0], "GP5_PKPATTERNMATCHDEL_HASH_KEY6_0xxx0"); @@ -2386,12 +2423,15 @@ TEST_F(KeysTest, PKPatternMatchDel) { for (size_t idx = 0; idx < gp6_total_hash; ++idx) { db.HSet("GP6_PKPATTERNMATCHDEL_HASH_KEY" + std::to_string(idx), "FIELD", "VALUE", &ret); } - s = db.PKPatternMatchDel(DataType::kHashes, "*", &delete_count); + s = db.PKPatternMatchDelWithRemoveKeys("*", &delete_count, &remove_keys, max_count); ASSERT_TRUE(s.ok()); - ASSERT_EQ(delete_count, gp6_total_hash); + ASSERT_EQ(delete_count, max_count); + ASSERT_EQ(remove_keys.size(), max_count); keys.clear(); + remove_keys.clear(); db.Keys(DataType::kHashes, "*", &keys); - ASSERT_EQ(keys.size(), 0); + ASSERT_EQ(keys.size(), gp6_total_hash - max_count); + db.Del(keys); //=============================== ZSets =============================== @@ -2402,10 +2442,12 @@ TEST_F(KeysTest, PKPatternMatchDel) { db.ZAdd("GP1_PKPATTERNMATCHDEL_ZSET_KEY4", {{1, "M"}}, &ret); db.ZAdd("GP1_PKPATTERNMATCHDEL_ZSET_KEY5", {{1, "M"}}, &ret); db.ZAdd("GP1_PKPATTERNMATCHDEL_ZSET_KEY6", {{1, "M"}}, &ret); - s = db.PKPatternMatchDel(DataType::kZSets, "*", &delete_count); + s = db.PKPatternMatchDelWithRemoveKeys("*", &delete_count, &remove_keys, max_count); ASSERT_TRUE(s.ok()); ASSERT_EQ(delete_count, 6); + ASSERT_EQ(remove_keys.size(), 6); keys.clear(); + remove_keys.clear(); db.Keys(DataType::kZSets, "*", &keys); ASSERT_EQ(keys.size(), 0); @@ -2419,10 +2461,12 @@ TEST_F(KeysTest, PKPatternMatchDel) { ASSERT_TRUE(make_expired(&db, "GP2_PKPATTERNMATCHDEL_ZSET_KEY1")); ASSERT_TRUE(make_expired(&db, "GP2_PKPATTERNMATCHDEL_ZSET_KEY3")); ASSERT_TRUE(make_expired(&db, "GP2_PKPATTERNMATCHDEL_ZSET_KEY5")); - s = db.PKPatternMatchDel(DataType::kZSets, "*", &delete_count); + s = db.PKPatternMatchDelWithRemoveKeys("*", &delete_count, &remove_keys, max_count); ASSERT_TRUE(s.ok()); ASSERT_EQ(delete_count, 3); + ASSERT_EQ(remove_keys.size(), 3); keys.clear(); + remove_keys.clear(); db.Keys(DataType::kZSets, "*", &keys); ASSERT_EQ(keys.size(), 0); @@ -2433,10 +2477,12 @@ TEST_F(KeysTest, PKPatternMatchDel) { db.ZAdd("GP3_PKPATTERNMATCHDEL_ZSET_KEY4_0ooo0", {{1, "M"}}, &ret); db.ZAdd("GP3_PKPATTERNMATCHDEL_ZSET_KEY5_0xxx0", {{1, "M"}}, &ret); db.ZAdd("GP3_PKPATTERNMATCHDEL_ZSET_KEY6_0ooo0", {{1, "M"}}, &ret); - s = db.PKPatternMatchDel(DataType::kZSets, "*0ooo0", &delete_count); + s = db.PKPatternMatchDelWithRemoveKeys("*0ooo0", &delete_count, &remove_keys, max_count); ASSERT_TRUE(s.ok()); ASSERT_EQ(delete_count, 3); + ASSERT_EQ(remove_keys.size(), 3); keys.clear(); + remove_keys.clear(); db.Keys(DataType::kZSets, "*", &keys); ASSERT_EQ(keys.size(), 3); ASSERT_EQ("GP3_PKPATTERNMATCHDEL_ZSET_KEY1_0xxx0", keys[0]); @@ -2455,10 +2501,12 @@ TEST_F(KeysTest, PKPatternMatchDel) { db.ZRem("GP4_PKPATTERNMATCHDEL_ZSET_KEY1", {"M"}, &ret); db.ZRem("GP4_PKPATTERNMATCHDEL_ZSET_KEY3", {"M"}, &ret); db.ZRem("GP4_PKPATTERNMATCHDEL_ZSET_KEY5", {"M"}, &ret); - s = db.PKPatternMatchDel(DataType::kZSets, "*", &delete_count); + s = db.PKPatternMatchDelWithRemoveKeys("*", &delete_count, &remove_keys, max_count); ASSERT_TRUE(s.ok()); ASSERT_EQ(delete_count, 3); + ASSERT_EQ(remove_keys.size(), 3); keys.clear(); + remove_keys.clear(); db.Keys(DataType::kZSets, "*", &keys); ASSERT_EQ(keys.size(), 0); @@ -2475,10 +2523,12 @@ TEST_F(KeysTest, PKPatternMatchDel) { ASSERT_TRUE(make_expired(&db, "GP5_PKPATTERNMATCHDEL_ZSET_KEY2_0xxx0")); db.ZRem("GP5_PKPATTERNMATCHDEL_ZSET_KEY3_0ooo0", {"M"}, &ret); db.ZRem("GP5_PKPATTERNMATCHDEL_ZSET_KEY4_0xxx0", {"M"}, &ret); - s = db.PKPatternMatchDel(DataType::kZSets, "*0ooo0", &delete_count); + s = db.PKPatternMatchDelWithRemoveKeys("*0ooo0", &delete_count, &remove_keys, max_count); ASSERT_TRUE(s.ok()); ASSERT_EQ(delete_count, 2); + ASSERT_EQ(remove_keys.size(), 2); keys.clear(); + remove_keys.clear(); db.Keys(DataType::kZSets, "*", &keys); ASSERT_EQ(keys.size(), 2); ASSERT_EQ(keys[0], "GP5_PKPATTERNMATCHDEL_ZSET_KEY6_0xxx0"); @@ -2491,12 +2541,15 @@ TEST_F(KeysTest, PKPatternMatchDel) { for (size_t idx = 0; idx < gp6_total_zset; ++idx) { db.ZAdd("GP6_PKPATTERNMATCHDEL_ZSET_KEY" + std::to_string(idx), {{1, "M"}}, &ret); } - s = db.PKPatternMatchDel(DataType::kZSets, "*", &delete_count); + s = db.PKPatternMatchDelWithRemoveKeys("*", &delete_count, &remove_keys, max_count); ASSERT_TRUE(s.ok()); - ASSERT_EQ(delete_count, gp6_total_zset); + ASSERT_EQ(delete_count, max_count); + ASSERT_EQ(remove_keys.size(), max_count); keys.clear(); + remove_keys.clear(); db.Keys(DataType::kZSets, "*", &keys); - ASSERT_EQ(keys.size(), 0); + ASSERT_EQ(keys.size(), gp6_total_zset-max_count); + db.Del(keys); //=============================== List =============================== @@ -2507,10 +2560,12 @@ TEST_F(KeysTest, PKPatternMatchDel) { db.LPush("GP1_PKPATTERNMATCHDEL_LIST_KEY4", {"VALUE"}, &ret64); db.LPush("GP1_PKPATTERNMATCHDEL_LIST_KEY5", {"VALUE"}, &ret64); db.LPush("GP1_PKPATTERNMATCHDEL_LIST_KEY6", {"VALUE"}, &ret64); - s = db.PKPatternMatchDel(DataType::kLists, "*", &delete_count); + s = db.PKPatternMatchDelWithRemoveKeys("*", &delete_count, &remove_keys, max_count); ASSERT_TRUE(s.ok()); ASSERT_EQ(delete_count, 6); + ASSERT_EQ(remove_keys.size(), 6); keys.clear(); + remove_keys.clear(); db.Keys(DataType::kLists, "*", &keys); ASSERT_EQ(keys.size(), 0); @@ -2524,10 +2579,12 @@ TEST_F(KeysTest, PKPatternMatchDel) { ASSERT_TRUE(make_expired(&db, "GP2_PKPATTERNMATCHDEL_LIST_KEY1")); ASSERT_TRUE(make_expired(&db, "GP2_PKPATTERNMATCHDEL_LIST_KEY3")); ASSERT_TRUE(make_expired(&db, "GP2_PKPATTERNMATCHDEL_LIST_KEY5")); - s = db.PKPatternMatchDel(DataType::kLists, "*", &delete_count); + s = db.PKPatternMatchDelWithRemoveKeys("*", &delete_count, &remove_keys, max_count); ASSERT_TRUE(s.ok()); ASSERT_EQ(delete_count, 3); + ASSERT_EQ(remove_keys.size(), 3); keys.clear(); + remove_keys.clear(); db.Keys(DataType::kLists, "*", &keys); ASSERT_EQ(keys.size(), 0); @@ -2538,10 +2595,12 @@ TEST_F(KeysTest, PKPatternMatchDel) { db.LPush("GP3_PKPATTERNMATCHDEL_LIST_KEY4_0ooo0", {"VALUE"}, &ret64); db.LPush("GP3_PKPATTERNMATCHDEL_LIST_KEY5_0xxx0", {"VALUE"}, &ret64); db.LPush("GP3_PKPATTERNMATCHDEL_LIST_KEY6_0ooo0", {"VALUE"}, &ret64); - s = db.PKPatternMatchDel(DataType::kLists, "*0ooo0", &delete_count); + s = db.PKPatternMatchDelWithRemoveKeys("*0ooo0", &delete_count, &remove_keys, max_count); ASSERT_TRUE(s.ok()); ASSERT_EQ(delete_count, 3); + ASSERT_EQ(remove_keys.size(), 3); keys.clear(); + remove_keys.clear(); db.Keys(DataType::kLists, "*", &keys); ASSERT_EQ(keys.size(), 3); ASSERT_EQ("GP3_PKPATTERNMATCHDEL_LIST_KEY1_0xxx0", keys[0]); @@ -2560,10 +2619,12 @@ TEST_F(KeysTest, PKPatternMatchDel) { db.LRem("GP4_PKPATTERNMATCHDEL_LIST_KEY1", 1, "VALUE", &ret64); db.LRem("GP4_PKPATTERNMATCHDEL_LIST_KEY3", 1, "VALUE", &ret64); db.LRem("GP4_PKPATTERNMATCHDEL_LIST_KEY5", 1, "VALUE", &ret64); - s = db.PKPatternMatchDel(DataType::kLists, "*", &delete_count); + s = db.PKPatternMatchDelWithRemoveKeys("*", &delete_count, &remove_keys, max_count); ASSERT_TRUE(s.ok()); ASSERT_EQ(delete_count, 3); + ASSERT_EQ(remove_keys.size(), 3); keys.clear(); + remove_keys.clear(); db.Keys(DataType::kLists, "*", &keys); ASSERT_EQ(keys.size(), 0); @@ -2580,10 +2641,12 @@ TEST_F(KeysTest, PKPatternMatchDel) { ASSERT_TRUE(make_expired(&db, "GP5_PKPATTERNMATCHDEL_LIST_KEY2_0xxx0")); db.LRem("GP5_PKPATTERNMATCHDEL_LIST_KEY3_0ooo0", 1, "VALUE", &ret64); db.LRem("GP5_PKPATTERNMATCHDEL_LIST_KEY4_0xxx0", 1, "VALUE", &ret64); - s = db.PKPatternMatchDel(DataType::kLists, "*0ooo0", &delete_count); + s = db.PKPatternMatchDelWithRemoveKeys("*0ooo0", &delete_count, &remove_keys, max_count); ASSERT_TRUE(s.ok()); ASSERT_EQ(delete_count, 2); + ASSERT_EQ(remove_keys.size(), 2); keys.clear(); + remove_keys.clear(); db.Keys(DataType::kLists, "*", &keys); ASSERT_EQ(keys.size(), 2); ASSERT_EQ(keys[0], "GP5_PKPATTERNMATCHDEL_LIST_KEY6_0xxx0"); @@ -2596,12 +2659,15 @@ TEST_F(KeysTest, PKPatternMatchDel) { for (size_t idx = 0; idx < gp6_total_list; ++idx) { db.LPush("GP6_PKPATTERNMATCHDEL_LIST_KEY" + std::to_string(idx), {"VALUE"}, &ret64); } - s = db.PKPatternMatchDel(DataType::kLists, "*", &delete_count); + s = db.PKPatternMatchDelWithRemoveKeys("*", &delete_count, &remove_keys, max_count); ASSERT_TRUE(s.ok()); - ASSERT_EQ(delete_count, gp6_total_hash); + ASSERT_EQ(delete_count, max_count); + ASSERT_EQ(remove_keys.size(), max_count); keys.clear(); + remove_keys.clear(); db.Keys(DataType::kLists, "*", &keys); - ASSERT_EQ(keys.size(), 0); + ASSERT_EQ(keys.size(), gp6_total_list - max_count); + db.Del(keys); sleep(2); db.Compact(DataType::kAll, true);