diff --git a/src/commands/cmd_server.cc b/src/commands/cmd_server.cc index 481f3f59613..6e72f5d55d0 100644 --- a/src/commands/cmd_server.cc +++ b/src/commands/cmd_server.cc @@ -878,7 +878,7 @@ class CommandScan : public CommandScanBase { std::vector keys; std::string end_key; - auto s = redis_db.Scan(key_name, limit_, prefix_, &keys, &end_key); + auto s = redis_db.Scan(key_name, limit_, prefix_, &keys, &end_key,pm_); if (!s.ok()) { return {Status::RedisExecErr, s.ToString()}; } diff --git a/src/commands/scan_base.h b/src/commands/scan_base.h index 2e11c989bd4..eab343d06a0 100644 --- a/src/commands/scan_base.h +++ b/src/commands/scan_base.h @@ -34,12 +34,23 @@ class CommandScanBase : public Commander { Status ParseMatchAndCountParam(const std::string &type, std::string value) { if (type == "match") { prefix_ = std::move(value); - if (!prefix_.empty() && prefix_[prefix_.size() - 1] == '*') { - prefix_ = prefix_.substr(0, prefix_.size() - 1); + if (!prefix_.empty() && (prefix_[prefix_.size() - 1] == '*' || prefix_[0] == '*')) { + if(prefix_.size()>=2&&prefix_[prefix_.size() - 1] == '*' && prefix_[0] == '*'){ + prefix_ = prefix_.substr(1, prefix_.size() - 2); + pm_ = 2; + } + else if (prefix_[prefix_.size() - 1] == '*') { + prefix_ = prefix_.substr(0, prefix_.size() - 1); + pm_ = 0; + } + else if (prefix_[0] == '*') { + prefix_ = prefix_.substr(1, prefix_.size() - 1); + pm_ = 1; + } return Status::OK(); } - return {Status::RedisParseErr, "only keys prefix match was supported"}; + return {Status::RedisParseErr, "It only supports matching three types: string prefix, string suffix, and substring. "}; } else if (type == "count") { auto parse_result = ParseInt(value, 10); if (!parse_result) { @@ -83,6 +94,7 @@ class CommandScanBase : public Commander { std::string cursor_; std::string prefix_; int limit_ = 20; + int pm_ = 0; }; class CommandSubkeyScanBase : public CommandScanBase { diff --git a/src/storage/redis_db.cc b/src/storage/redis_db.cc index e75a19b08ac..215dad15b67 100644 --- a/src/storage/redis_db.cc +++ b/src/storage/redis_db.cc @@ -20,6 +20,7 @@ #include "redis_db.h" +#include #include #include #include @@ -29,6 +30,7 @@ #include "db_util.h" #include "parse_util.h" #include "rocksdb/iterator.h" +#include "rocksdb/slice.h" #include "rocksdb/status.h" #include "server/server.h" #include "storage/iterator.h" @@ -322,8 +324,8 @@ rocksdb::Status Database::Keys(const std::string &prefix, std::vector *keys, std::string *end_cursor) { +rocksdb::Status Database::Scan(const std::string &cursor, uint64_t limit, const std::string &fix, + std::vector *keys, std::string *end_cursor,const int pm) { end_cursor->clear(); uint64_t cnt = 0; uint16_t slot_start = 0; @@ -336,15 +338,12 @@ rocksdb::Status Database::Scan(const std::string &cursor, uint64_t limit, const auto iter = util::UniqueIterator(storage_, read_options, metadata_cf_handle_); std::string ns_cursor = AppendNamespacePrefix(cursor); + ns_prefix = ComposeNamespaceKey(namespace_, "", false); if (storage_->IsSlotIdEncoded()) { slot_start = cursor.empty() ? 0 : GetSlotIdFromKey(cursor); - ns_prefix = ComposeNamespaceKey(namespace_, "", false); - if (!prefix.empty()) { + if (!fix.empty()) { PutFixed16(&ns_prefix, slot_start); - ns_prefix.append(prefix); } - } else { - ns_prefix = AppendNamespacePrefix(prefix); } if (!cursor.empty()) { @@ -361,8 +360,13 @@ rocksdb::Status Database::Scan(const std::string &cursor, uint64_t limit, const uint16_t slot_id = slot_start; while (true) { for (; iter->Valid() && cnt < limit; iter->Next()) { - if (!ns_prefix.empty() && !iter->key().starts_with(ns_prefix)) { - break; + if (!ns_prefix.empty()) { + if(!iter->key().starts_with(ns_prefix))break; + auto key_view = iter->key().ToStringView(); + auto sub_key_view = static_cast(key_view.substr(ns_prefix.size(),key_view.size()-ns_prefix.size())); + if(pm==0&&!sub_key_view.starts_with(fix))continue; + else if(pm==1&&!sub_key_view.ends_with(fix))continue; + else if(pm==2&&sub_key_view.ToStringView().find(fix)==std::string::npos)continue; } Metadata metadata(kRedisNone, false); auto s = metadata.Decode(iter->value()); @@ -373,7 +377,7 @@ rocksdb::Status Database::Scan(const std::string &cursor, uint64_t limit, const keys->emplace_back(user_key); cnt++; } - if (!storage_->IsSlotIdEncoded() || prefix.empty()) { + if (!storage_->IsSlotIdEncoded() || fix.empty()) { if (!keys->empty() && cnt >= limit) { end_cursor->append(user_key); } @@ -393,14 +397,13 @@ rocksdb::Status Database::Scan(const std::string &cursor, uint64_t limit, const if (keys->empty()) { if (iter->Valid()) { std::tie(std::ignore, user_key) = ExtractNamespaceKey(iter->key(), storage_->IsSlotIdEncoded()); - auto res = std::mismatch(prefix.begin(), prefix.end(), user_key.begin()); - if (res.first == prefix.end()) { + auto res = std::mismatch(fix.begin(), fix.end(), user_key.begin()); + if (res.first == fix.end()) { keys->emplace_back(user_key); } end_cursor->append(user_key); } - } else { end_cursor->append(user_key); } break; @@ -408,7 +411,6 @@ rocksdb::Status Database::Scan(const std::string &cursor, uint64_t limit, const ns_prefix = ComposeNamespaceKey(namespace_, "", false); PutFixed16(&ns_prefix, slot_id); - ns_prefix.append(prefix); iter->Seek(ns_prefix); } return rocksdb::Status::OK(); diff --git a/src/storage/redis_db.h b/src/storage/redis_db.h index 493b83c3e9b..d84de545f51 100644 --- a/src/storage/redis_db.h +++ b/src/storage/redis_db.h @@ -90,7 +90,7 @@ class Database { [[nodiscard]] rocksdb::Status Keys(const std::string &prefix, std::vector *keys = nullptr, KeyNumStats *stats = nullptr); [[nodiscard]] rocksdb::Status Scan(const std::string &cursor, uint64_t limit, const std::string &prefix, - std::vector *keys, std::string *end_cursor = nullptr); + std::vector *keys, std::string *end_cursor = nullptr,int pm = 0); [[nodiscard]] rocksdb::Status RandomKey(const std::string &cursor, std::string *key); std::string AppendNamespacePrefix(const Slice &user_key); [[nodiscard]] rocksdb::Status FindKeyRangeWithPrefix(const std::string &prefix, const std::string &prefix_end,