diff --git a/src/storage/redis_db.cc b/src/storage/redis_db.cc index 2898c3b855d..9fef1c82a69 100644 --- a/src/storage/redis_db.cc +++ b/src/storage/redis_db.cc @@ -208,12 +208,37 @@ rocksdb::Status Database::MDel(engine::Context &ctx, const std::vector &k } rocksdb::Status Database::Exists(engine::Context &ctx, const std::vector &keys, int *ret) { + *ret = 0; + + if (keys.empty()) { + return rocksdb::Status::OK(); + } + std::vector ns_keys; + std::vector slice_keys; ns_keys.reserve(keys.size()); + slice_keys.reserve(keys.size()); + for (const auto &key : keys) { ns_keys.emplace_back(AppendNamespacePrefix(key)); + slice_keys.emplace_back(ns_keys.back()); + } + + std::vector statuses(slice_keys.size()); + std::vector pin_values(slice_keys.size()); + storage_->MultiGet(ctx, ctx.DefaultMultiGetOptions(), metadata_cf_handle_, slice_keys.size(), slice_keys.data(), + pin_values.data(), statuses.data()); + + for (size_t i = 0; i < slice_keys.size(); i++) { + if (!statuses[i].ok() && !statuses[i].IsNotFound()) return statuses[i]; + if (statuses[i].ok()) { + Metadata metadata(kRedisNone, false); + auto s = metadata.Decode(pin_values[i]); + if (!s.ok()) return s; + if (!metadata.Expired()) *ret += 1; + } } - return existsInternal(ctx, ns_keys, ret); + return rocksdb::Status::OK(); } rocksdb::Status Database::TTL(engine::Context &ctx, const Slice &user_key, int64_t *ttl) { @@ -621,23 +646,6 @@ Status WriteBatchLogData::Decode(const rocksdb::Slice &blob) { return Status::OK(); } -rocksdb::Status Database::existsInternal(engine::Context &ctx, const std::vector &keys, int *ret) { - *ret = 0; - rocksdb::Status s; - std::string value; - for (const auto &key : keys) { - s = storage_->Get(ctx, ctx.GetReadOptions(), metadata_cf_handle_, key, &value); - if (!s.ok() && !s.IsNotFound()) return s; - if (s.ok()) { - Metadata metadata(kRedisNone, false); - s = metadata.Decode(value); - if (!s.ok()) return s; - if (!metadata.Expired()) *ret += 1; - } - } - return rocksdb::Status::OK(); -} - rocksdb::Status Database::typeInternal(engine::Context &ctx, const Slice &key, RedisType *type) { *type = kRedisNone; std::string value; @@ -667,7 +675,15 @@ rocksdb::Status Database::Copy(engine::Context &ctx, const std::string &key, con if (nx) { int exist = 0; - if (s = existsInternal(ctx, {new_key}, &exist), !s.ok()) return s; + std::string value; + s = storage_->Get(ctx, ctx.GetReadOptions(), metadata_cf_handle_, new_key, &value); + if (!s.ok() && !s.IsNotFound()) return s; + if (s.ok()) { + Metadata metadata(kRedisNone, false); + s = metadata.Decode(value); + if (!s.ok()) return s; + if (!metadata.Expired()) exist = 1; + } if (exist > 0) { *res = CopyResult::KEY_ALREADY_EXIST; return rocksdb::Status::OK(); diff --git a/src/storage/redis_db.h b/src/storage/redis_db.h index 16d98dcd395..c5a3c6eab9b 100644 --- a/src/storage/redis_db.h +++ b/src/storage/redis_db.h @@ -155,7 +155,6 @@ class Database { private: // Already internal keys - [[nodiscard]] rocksdb::Status existsInternal(engine::Context &ctx, const std::vector &keys, int *ret); [[nodiscard]] rocksdb::Status typeInternal(engine::Context &ctx, const Slice &key, RedisType *type); /// lookupKeyByPattern is a helper function of `Sort` to support `GET` and `BY` fields. diff --git a/src/storage/redis_metadata.h b/src/storage/redis_metadata.h index fd80e5a5ba0..b3c11ae8ab3 100644 --- a/src/storage/redis_metadata.h +++ b/src/storage/redis_metadata.h @@ -199,7 +199,10 @@ class Metadata { bool IsEmptyableType() const; virtual void Encode(std::string *dst) const; + + // Calls remove_prefix() internally and would modify the original `input` state. [[nodiscard]] virtual rocksdb::Status Decode(Slice *input); + [[nodiscard]] rocksdb::Status Decode(Slice input); bool operator==(const Metadata &that) const;