diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index b946bf5608..976e1ce63f 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -13,10 +13,10 @@ name: "CodeQL" on: push: - branches: [ "unstable", "3.5" ] + branches: [ "unstable", "3.5" , "4.0"] pull_request: # The branches below must be a subset of the branches above - branches: [ "unstable", "3.5" ] + branches: [ "unstable", "3.5" , "4.0"] schedule: - cron: '25 19 * * 6' diff --git a/.github/workflows/codis.yml b/.github/workflows/codis.yml index b254dbeb28..e80a9c82ea 100644 --- a/.github/workflows/codis.yml +++ b/.github/workflows/codis.yml @@ -5,9 +5,9 @@ name: Codis on: push: - branches: [ "unstable", "3.5" ] + branches: [ "unstable", "3.5" , "4.0" ] pull_request: - branches: [ "unstable", "3.5" ] + branches: [ "unstable", "3.5" , "4.0"] jobs: diff --git a/.github/workflows/pika.yml b/.github/workflows/pika.yml index d6005c2b24..e972082697 100644 --- a/.github/workflows/pika.yml +++ b/.github/workflows/pika.yml @@ -2,10 +2,10 @@ name: Pika on: push: - branches: [ "unstable", "3.5" ] + branches: [ "unstable", "3.5" , "4.0"] pull_request: - branches: [ "unstable", "3.5" ] - workflow_dispatch: + branches: [ "unstable", "3.5" , "4.0"] + env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: RelWithDebInfo diff --git a/.github/workflows/tools_go.yml b/.github/workflows/tools_go.yml index 125679e3ea..e28c561400 100644 --- a/.github/workflows/tools_go.yml +++ b/.github/workflows/tools_go.yml @@ -2,11 +2,11 @@ name: Tools_go_build on: push: - branches: [ "unstable", "3.5" ] + branches: [ "unstable", "3.5" , "4.0"] paths: - 'tools/**' pull_request: - branches: [ "unstable", "3.5" ] + branches: [ "unstable", "3.5" , "4.0"] paths: - 'tools/**' diff --git a/src/pika_command.cc b/src/pika_command.cc index de678d2002..34cea023ac 100644 --- a/src/pika_command.cc +++ b/src/pika_command.cc @@ -703,7 +703,7 @@ void InitCmdTable(CmdTable* cmd_table) { cmd_table->insert(std::pair>(kCmdNamePfCount, std::move(pfcountptr))); ////pfmergeCmd std::unique_ptr pfmergeptr = std::make_unique( - kCmdNamePfMerge, -3, kCmdFlagsWrite | kCmdFlagsHyperLogLog | kCmdFlagsSlow); + kCmdNamePfMerge, -2, kCmdFlagsWrite | kCmdFlagsHyperLogLog | kCmdFlagsSlow); cmd_table->insert(std::pair>(kCmdNamePfMerge, std::move(pfmergeptr))); // GEO diff --git a/src/storage/src/base_filter.h b/src/storage/src/base_filter.h index 3a092c109e..5dd17b09c6 100644 --- a/src/storage/src/base_filter.h +++ b/src/storage/src/base_filter.h @@ -16,6 +16,7 @@ #include "src/base_value_format.h" #include "src/base_meta_value_format.h" #include "src/lists_meta_value_format.h" +#include "src/pika_stream_meta_value.h" #include "src/strings_value_format.h" #include "src/zsets_data_key_format.h" #include "src/debug.h" @@ -36,11 +37,12 @@ class BaseMetaFilter : public rocksdb::CompactionFilter { * The field designs of the remaining zset,set,hash and stream in meta-value * are the same, so the same filtering strategy is used */ + ParsedBaseKey parsed_key(key); auto type = static_cast(static_cast(value[0])); DEBUG("==========================START=========================="); if (type == DataType::kStrings) { ParsedStringsValue parsed_strings_value(value); - DEBUG("[StringsFilter] key: {}, value = {}, timestamp: {}, cur_time: {}", key.ToString().c_str(), + DEBUG("[string type] key: %s, value = %s, timestamp: %llu, cur_time: %llu", parsed_key.Key().ToString().c_str(), parsed_strings_value.UserValue().ToString().c_str(), parsed_strings_value.Etime(), cur_time); if (parsed_strings_value.Etime() != 0 && parsed_strings_value.Etime() < cur_time) { DEBUG("Drop[Stale]"); @@ -49,9 +51,17 @@ class BaseMetaFilter : public rocksdb::CompactionFilter { DEBUG("Reserve"); return false; } + } else if (type == DataType::kStreams) { + ParsedStreamMetaValue parsed_stream_meta_value(value); + DEBUG("[stream meta type], key: %s, entries_added = %llu, first_id: %s, last_id: %s, version: %llu", + parsed_key.Key().ToString().c_str(), parsed_stream_meta_value.entries_added(), + parsed_stream_meta_value.first_id().ToString().c_str(), + parsed_stream_meta_value.last_id().ToString().c_str(), + parsed_stream_meta_value.version()); + return false; } else if (type == DataType::kLists) { ParsedListsMetaValue parsed_lists_meta_value(value); - DEBUG("[ListMetaFilter], key: {}, count = {}, timestamp: {}, cur_time: {}, version: {}", key.ToString().c_str(), + DEBUG("[list meta type], key: %s, count = %d, timestamp: %llu, cur_time: %llu, version: %llu", parsed_key.Key().ToString().c_str(), parsed_lists_meta_value.Count(), parsed_lists_meta_value.Etime(), cur_time, parsed_lists_meta_value.Version()); @@ -68,8 +78,9 @@ class BaseMetaFilter : public rocksdb::CompactionFilter { return false; } else { ParsedBaseMetaValue parsed_base_meta_value(value); - DEBUG("[MetaFilter] key: {}, count = {}, timestamp: {}, cur_time: {}, version: {}", key.ToString().c_str(), - parsed_base_meta_value.Count(), parsed_base_meta_value.Etime(), cur_time, parsed_base_meta_value.Version()); + DEBUG("[%s meta type] key: %s, count = %d, timestamp: %llu, cur_time: %llu, version: %llu", + DataTypeToString(type), parsed_key.Key().ToString().c_str(), parsed_base_meta_value.Count(), + parsed_base_meta_value.Etime(), cur_time, parsed_base_meta_value.Version()); if (parsed_base_meta_value.Etime() != 0 && parsed_base_meta_value.Etime() < cur_time && parsed_base_meta_value.Version() < cur_time) { @@ -143,7 +154,12 @@ class BaseDataFilter : public rocksdb::CompactionFilter { auto type = static_cast(static_cast(meta_value[0])); if (type != type_) { return true; - } else if (type == DataType::kHashes || type == DataType::kSets || type == DataType::kStreams || type == DataType::kZSets) { + } else if (type == DataType::kStreams) { + ParsedStreamMetaValue parsed_stream_meta_value(meta_value); + meta_not_found_ = false; + cur_meta_version_ = parsed_stream_meta_value.version(); + cur_meta_etime_ = 0; // stream do not support ttl + } else if (type == DataType::kHashes || type == DataType::kSets || type == DataType::kZSets) { ParsedBaseMetaValue parsed_base_meta_value(&meta_value); meta_not_found_ = false; cur_meta_version_ = parsed_base_meta_value.Version(); diff --git a/src/storage/src/pika_stream_meta_value.h b/src/storage/src/pika_stream_meta_value.h index e010d5c830..d505eb9094 100644 --- a/src/storage/src/pika_stream_meta_value.h +++ b/src/storage/src/pika_stream_meta_value.h @@ -82,7 +82,8 @@ class StreamMetaValue { value_ = std::move(value); assert(value_.size() == kDefaultStreamValueLength); if (value_.size() != kDefaultStreamValueLength) { - LOG(ERROR) << "Invalid stream meta value length: "; + LOG(ERROR) << "Invalid stream meta value length: " << value_.size() + << " expected: " << kDefaultStreamValueLength; return; } char* pos = &value_[0]; @@ -215,7 +216,8 @@ class ParsedStreamMetaValue { ParsedStreamMetaValue(const Slice& value) { assert(value.size() == kDefaultStreamValueLength); if (value.size() != kDefaultStreamValueLength) { - LOG(ERROR) << "Invalid stream meta value length: "; + LOG(ERROR) << "Invalid stream meta value length: " << value.size() + << " expected: " << kDefaultStreamValueLength; return; } char* pos = const_cast(value.data()); @@ -294,7 +296,7 @@ class StreamCGroupMetaValue { uint64_t needed = kDefaultStreamCGroupValueLength; assert(value_.size() == 0); if (value_.size() != 0) { - LOG(FATAL) << "Init on a existed stream cgroup meta value!"; + LOG(ERROR) << "Init on a existed stream cgroup meta value!"; return; } value_.resize(needed); @@ -314,7 +316,8 @@ class StreamCGroupMetaValue { value_ = std::move(value); assert(value_.size() == kDefaultStreamCGroupValueLength); if (value_.size() != kDefaultStreamCGroupValueLength) { - LOG(FATAL) << "Invalid stream cgroup meta value length: "; + LOG(ERROR) << "Invalid stream cgroup meta value length: " << value_.size() + << " expected: " << kDefaultStreamValueLength; return; } if (value_.size() == kDefaultStreamCGroupValueLength) { @@ -373,7 +376,7 @@ class StreamConsumerMetaValue { value_ = std::move(value); assert(value_.size() == kDefaultStreamConsumerValueLength); if (value_.size() != kDefaultStreamConsumerValueLength) { - LOG(FATAL) << "Invalid stream consumer meta value length: " << value_.size() + LOG(ERROR) << "Invalid stream consumer meta value length: " << value_.size() << " expected: " << kDefaultStreamConsumerValueLength; return; } @@ -391,7 +394,7 @@ class StreamConsumerMetaValue { pel_ = pel; assert(value_.size() == 0); if (value_.size() != 0) { - LOG(FATAL) << "Invalid stream consumer meta value length: " << value_.size() << " expected: 0"; + LOG(ERROR) << "Invalid stream consumer meta value length: " << value_.size() << " expected: 0"; return; } uint64_t needed = kDefaultStreamConsumerValueLength; diff --git a/src/storage/src/redis.h b/src/storage/src/redis.h index ad8906ba0c..ccad635263 100644 --- a/src/storage/src/redis.h +++ b/src/storage/src/redis.h @@ -117,36 +117,36 @@ class Redis { Status ScanStreamsKeyNum(KeyInfo* key_info); // Keys Commands - virtual Status StringsExpire(const Slice& key, int64_t ttl); - virtual Status HashesExpire(const Slice& key, int64_t ttl); - virtual Status ListsExpire(const Slice& key, int64_t ttl); - virtual Status ZsetsExpire(const Slice& key, int64_t ttl); - virtual Status SetsExpire(const Slice& key, int64_t ttl); - - virtual Status StringsDel(const Slice& key); - virtual Status HashesDel(const Slice& key); - virtual Status ListsDel(const Slice& key); - virtual Status ZsetsDel(const Slice& key); - virtual Status SetsDel(const Slice& key); - virtual Status StreamsDel(const Slice& key); - - virtual Status StringsExpireat(const Slice& key, int64_t timestamp); - virtual Status HashesExpireat(const Slice& key, int64_t timestamp); - virtual Status ListsExpireat(const Slice& key, int64_t timestamp); - virtual Status SetsExpireat(const Slice& key, int64_t timestamp); - virtual Status ZsetsExpireat(const Slice& key, int64_t timestamp); - - virtual Status StringsPersist(const Slice& key); - virtual Status HashesPersist(const Slice& key); - virtual Status ListsPersist(const Slice& key); - virtual Status ZsetsPersist(const Slice& key); - virtual Status SetsPersist(const Slice& key); - - virtual Status StringsTTL(const Slice& key, int64_t* timestamp); - virtual Status HashesTTL(const Slice& key, int64_t* timestamp); - virtual Status ListsTTL(const Slice& key, int64_t* timestamp); - virtual Status ZsetsTTL(const Slice& key, int64_t* timestamp); - virtual Status SetsTTL(const Slice& key, int64_t* timestamp); + virtual Status StringsExpire(const Slice& key, int64_t ttl, std::string&& prefetch_meta = {}); + virtual Status HashesExpire(const Slice& key, int64_t ttl, std::string&& prefetch_meta = {}); + virtual Status ListsExpire(const Slice& key, int64_t ttl, std::string&& prefetch_meta = {}); + virtual Status ZsetsExpire(const Slice& key, int64_t ttl, std::string&& prefetch_meta = {}); + virtual Status SetsExpire(const Slice& key, int64_t ttl, std::string&& prefetch_meta = {}); + + virtual Status StringsDel(const Slice& key, std::string&& prefetch_meta = {}); + virtual Status HashesDel(const Slice& key, std::string&& prefetch_meta = {}); + virtual Status ListsDel(const Slice& key, std::string&& prefetch_meta = {}); + virtual Status ZsetsDel(const Slice& key, std::string&& prefetch_meta = {}); + virtual Status SetsDel(const Slice& key, std::string&& prefetch_meta = {}); + virtual Status StreamsDel(const Slice& key, std::string&& prefetch_meta = {}); + + virtual Status StringsExpireat(const Slice& key, int64_t timestamp, std::string&& prefetch_meta = {}); + virtual Status HashesExpireat(const Slice& key, int64_t timestamp, std::string&& prefetch_meta = {}); + virtual Status ListsExpireat(const Slice& key, int64_t timestamp, std::string&& prefetch_meta = {}); + virtual Status SetsExpireat(const Slice& key, int64_t timestamp, std::string&& prefetch_meta = {}); + virtual Status ZsetsExpireat(const Slice& key, int64_t timestamp, std::string&& prefetch_meta = {}); + + virtual Status StringsPersist(const Slice& key, std::string&& prefetch_meta = {}); + virtual Status HashesPersist(const Slice& key, std::string&& prefetch_meta = {}); + virtual Status ListsPersist(const Slice& key, std::string&& prefetch_meta = {}); + virtual Status ZsetsPersist(const Slice& key, std::string&& prefetch_meta = {}); + virtual Status SetsPersist(const Slice& key, std::string&& prefetch_meta = {}); + + virtual Status StringsTTL(const Slice& key, int64_t* timestamp, std::string&& prefetch_meta = {}); + virtual Status HashesTTL(const Slice& key, int64_t* timestamp, std::string&& prefetch_meta = {}); + virtual Status ListsTTL(const Slice& key, int64_t* timestamp, std::string&& prefetch_meta = {}); + virtual Status ZsetsTTL(const Slice& key, int64_t* timestamp, std::string&& prefetch_meta = {}); + virtual Status SetsTTL(const Slice& key, int64_t* timestamp, std::string&& prefetch_meta = {}); // Strings Commands Status Append(const Slice& key, const Slice& value, int32_t* ret); @@ -154,6 +154,7 @@ class Redis { Status BitOp(BitOpType op, const std::string& dest_key, const std::vector& src_keys, std::string &value_to_dest, int64_t* ret); Status Decrby(const Slice& key, int64_t value, int64_t* ret); Status Get(const Slice& key, std::string* value); + Status HyperloglogGet(const Slice& key, std::string* value); Status MGet(const Slice& key, std::string* value); Status GetWithTTL(const Slice& key, std::string* value, int64_t* ttl); Status MGetWithTTL(const Slice& key, std::string* value, int64_t* ttl); @@ -167,6 +168,7 @@ class Redis { Status MSet(const std::vector& kvs); Status MSetnx(const std::vector& kvs, int32_t* ret); Status Set(const Slice& key, const Slice& value); + Status HyperloglogSet(const Slice& key, const Slice& value); Status Setxx(const Slice& key, const Slice& value, int32_t* ret, int64_t ttl = 0); Status SetBit(const Slice& key, int64_t offset, int32_t value, int32_t* ret); Status Setex(const Slice& key, const Slice& value, int64_t ttl); @@ -200,7 +202,7 @@ class Redis { Status HIncrby(const Slice& key, const Slice& field, int64_t value, int64_t* ret); Status HIncrbyfloat(const Slice& key, const Slice& field, const Slice& by, std::string* new_value); Status HKeys(const Slice& key, std::vector* fields); - Status HLen(const Slice& key, int32_t* ret); + Status HLen(const Slice& key, int32_t* ret, std::string&& prefetch_meta = {}); Status HMGet(const Slice& key, const std::vector& fields, std::vector* vss); Status HMSet(const Slice& key, const std::vector& fvs); Status HSet(const Slice& key, const Slice& field, const Slice& value, int32_t* res); @@ -246,7 +248,7 @@ class Redis { // Sets Commands Status SAdd(const Slice& key, const std::vector& members, int32_t* ret); - Status SCard(const Slice& key, int32_t* ret); + Status SCard(const Slice& key, int32_t* ret, std::string&& prefetch_meta = {}); Status SDiff(const std::vector& keys, std::vector* members); Status SDiffstore(const Slice& destination, const std::vector& keys, std::vector& value_to_dest, int32_t* ret); Status SInter(const std::vector& keys, std::vector* members); @@ -269,7 +271,7 @@ class Redis { Status LIndex(const Slice& key, int64_t index, std::string* element); Status LInsert(const Slice& key, const BeforeOrAfter& before_or_after, const std::string& pivot, const std::string& value, int64_t* ret); - Status LLen(const Slice& key, uint64_t* len); + Status LLen(const Slice& key, uint64_t* len, std::string&& prefetch_meta = {}); Status LPop(const Slice& key, int64_t count, std::vector* elements); Status LPush(const Slice& key, const std::vector& values, uint64_t* ret); Status LPushx(const Slice& key, const std::vector& values, uint64_t* len); @@ -285,7 +287,7 @@ class Redis { // Zsets Commands Status ZAdd(const Slice& key, const std::vector& score_members, int32_t* ret); - Status ZCard(const Slice& key, int32_t* card); + Status ZCard(const Slice& key, int32_t* card, std::string&& prefetch_meta = {}); Status ZCount(const Slice& key, double min, double max, bool left_close, bool right_close, int32_t* ret); Status ZIncrby(const Slice& key, const Slice& member, double increment, double* ret); Status ZRange(const Slice& key, int32_t start, int32_t stop, std::vector* score_members); @@ -323,7 +325,7 @@ class Redis { Status XAdd(const Slice& key, const std::string& serialized_message, StreamAddTrimArgs& args); Status XDel(const Slice& key, const std::vector& ids, int32_t& count); Status XTrim(const Slice& key, StreamAddTrimArgs& args, int32_t& count); - Status XRange(const Slice& key, const StreamScanArgs& args, std::vector& id_messages); + Status XRange(const Slice& key, const StreamScanArgs& args, std::vector& id_messages, std::string&& prefetch_meta = {}); Status XRevrange(const Slice& key, const StreamScanArgs& args, std::vector& id_messages); Status XLen(const Slice& key, int32_t& len); Status XRead(const StreamReadGroupReadArgs& args, std::vector>& results, @@ -333,7 +335,7 @@ class Redis { rocksdb::ReadOptions& read_options); // get and parse the stream meta if found // @return ok only when the stream meta exists - Status GetStreamMeta(StreamMetaValue& tream_meta, const rocksdb::Slice& key, rocksdb::ReadOptions& read_options); + Status GetStreamMeta(StreamMetaValue& tream_meta, const rocksdb::Slice& key, rocksdb::ReadOptions& read_options, std::string&& prefetch_meta = {}); // Before calling this function, the caller should ensure that the ids are valid Status DeleteStreamMessages(const rocksdb::Slice& key, const StreamMetaValue& stream_meta, diff --git a/src/storage/src/redis_hashes.cc b/src/storage/src/redis_hashes.cc index e256757e43..03a3c1c9b8 100644 --- a/src/storage/src/redis_hashes.cc +++ b/src/storage/src/redis_hashes.cc @@ -88,7 +88,10 @@ Status Redis::HDel(const Slice& key, const std::vector& fields, int if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kHashes)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kHashes)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -149,7 +152,10 @@ Status Redis::HGet(const Slice& key, const Slice& field, std::string* value) { if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kHashes)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kHashes)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -186,7 +192,10 @@ Status Redis::HGetall(const Slice& key, std::vector* fvs) { if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kHashes)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kHashes)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -226,7 +235,10 @@ Status Redis::HGetallWithTTL(const Slice& key, std::vector* fvs, int if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kHashes)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kHashes)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -281,7 +293,10 @@ Status Redis::HIncrby(const Slice& key, const Slice& field, int64_t value, int64 if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kHashes)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kHashes)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -370,7 +385,10 @@ Status Redis::HIncrbyfloat(const Slice& key, const Slice& field, const Slice& by if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kHashes)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kHashes)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -445,14 +463,16 @@ Status Redis::HKeys(const Slice& key, std::vector* fields) { ScopeSnapshot ss(db_, &snapshot); read_options.snapshot = snapshot; - BaseMetaKey base_meta_key(key); Status s = db_->Get(read_options, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); if (s.ok() && !ExpectedMetaValue(DataType::kHashes, meta_value)) { if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kHashes)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kHashes)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -477,17 +497,25 @@ Status Redis::HKeys(const Slice& key, std::vector* fields) { return s; } -Status Redis::HLen(const Slice& key, int32_t* ret) { +Status Redis::HLen(const Slice& key, int32_t* ret, std::string&& prefetch_meta) { *ret = 0; - std::string meta_value; - - BaseMetaKey base_meta_key(key); - Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); - if (s.ok() && !ExpectedMetaValue(DataType::kHashes, meta_value)) { - if (ExpectedStale(meta_value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kHashes)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + Status s; + std::string meta_value(std::move(prefetch_meta)); + + // meta_value is empty means no meta value get before, + // we should get meta first + if (meta_value.empty()) { + BaseMetaKey base_meta_key(key); + s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); + if (s.ok() && !ExpectedMetaValue(DataType::kHashes, meta_value)) { + if (ExpectedStale(meta_value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kHashes)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + } } } if (s.ok()) { @@ -523,7 +551,10 @@ Status Redis::HMGet(const Slice& key, const std::vector& fields, st if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kHashes)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kHashes)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -584,7 +615,10 @@ Status Redis::HMSet(const Slice& key, const std::vector& fvs) { if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kHashes)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kHashes)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -656,7 +690,10 @@ Status Redis::HSet(const Slice& key, const Slice& field, const Slice& value, int if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kHashes)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kHashes)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -728,7 +765,10 @@ Status Redis::HSetnx(const Slice& key, const Slice& field, const Slice& value, i if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kHashes)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kHashes)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -788,7 +828,10 @@ Status Redis::HVals(const Slice& key, std::vector* values) { if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kHashes)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kHashes)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -848,7 +891,10 @@ Status Redis::HScan(const Slice& key, int64_t cursor, const std::string& pattern if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kHashes)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kHashes)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -922,7 +968,10 @@ Status Redis::HScanx(const Slice& key, const std::string& start_field, const std if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kHashes)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kHashes)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -983,14 +1032,16 @@ Status Redis::PKHScanRange(const Slice& key, const Slice& field_start, const std return Status::InvalidArgument("error in given range"); } - BaseMetaKey base_meta_key(key); Status s = db_->Get(read_options, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); if (s.ok() && !ExpectedMetaValue(DataType::kHashes, meta_value)) { if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kHashes)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kHashes)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -1052,14 +1103,16 @@ Status Redis::PKHRScanRange(const Slice& key, const Slice& field_start, const st return Status::InvalidArgument("error in given range"); } - BaseMetaKey base_meta_key(key); Status s = db_->Get(read_options, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); if (s.ok() && !ExpectedMetaValue(DataType::kHashes, meta_value)) { if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kHashes)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kHashes)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -1103,17 +1156,25 @@ Status Redis::PKHRScanRange(const Slice& key, const Slice& field_start, const st return Status::OK(); } -Status Redis::HashesExpire(const Slice& key, int64_t ttl) { - std::string meta_value; +Status Redis::HashesExpire(const Slice& key, int64_t ttl, std::string&& prefetch_meta) { + std::string meta_value(std::move(prefetch_meta)); ScopeRecordLock l(lock_mgr_, key); - BaseMetaKey base_meta_key(key); - Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); - if (s.ok() && !ExpectedMetaValue(DataType::kHashes, meta_value)) { - if (ExpectedStale(meta_value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kHashes)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + Status s; + + // meta_value is empty means no meta value get before, + // we should get meta first + if (meta_value.empty()) { + s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); + if (s.ok() && !ExpectedMetaValue(DataType::kHashes, meta_value)) { + if (ExpectedStale(meta_value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kHashes)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + } } } if (s.ok()) { @@ -1135,17 +1196,25 @@ Status Redis::HashesExpire(const Slice& key, int64_t ttl) { return s; } -Status Redis::HashesDel(const Slice& key) { - std::string meta_value; +Status Redis::HashesDel(const Slice& key, std::string&& prefetch_meta) { + std::string meta_value(std::move(prefetch_meta)); ScopeRecordLock l(lock_mgr_, key); - BaseMetaKey base_meta_key(key); - Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); - if (s.ok() && !ExpectedMetaValue(DataType::kHashes, meta_value)) { - if (ExpectedStale(meta_value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kHashes)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + Status s; + + // meta_value is empty means no meta value get before, + // we should get meta first + if (meta_value.empty()) { + s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); + if (s.ok() && !ExpectedMetaValue(DataType::kHashes, meta_value)) { + if (ExpectedStale(meta_value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kHashes)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + } } } if (s.ok()) { @@ -1164,17 +1233,25 @@ Status Redis::HashesDel(const Slice& key) { return s; } -Status Redis::HashesExpireat(const Slice& key, int64_t timestamp) { - std::string meta_value; +Status Redis::HashesExpireat(const Slice& key, int64_t timestamp, std::string&& prefetch_meta) { + std::string meta_value(std::move(prefetch_meta)); ScopeRecordLock l(lock_mgr_, key); - BaseMetaKey base_meta_key(key); - Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); - if (s.ok() && !ExpectedMetaValue(DataType::kHashes, meta_value)) { - if (ExpectedStale(meta_value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kHashes)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + Status s; + + // meta_value is empty means no meta value get before, + // we should get meta first + if (meta_value.empty()) { + s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); + if (s.ok() && !ExpectedMetaValue(DataType::kHashes, meta_value)) { + if (ExpectedStale(meta_value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kHashes)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + } } } if (s.ok()) { @@ -1195,17 +1272,25 @@ Status Redis::HashesExpireat(const Slice& key, int64_t timestamp) { return s; } -Status Redis::HashesPersist(const Slice& key) { - std::string meta_value; +Status Redis::HashesPersist(const Slice& key, std::string&& prefetch_meta) { + std::string meta_value(std::move(prefetch_meta)); ScopeRecordLock l(lock_mgr_, key); - BaseMetaKey base_meta_key(key); - Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); - if (s.ok() && !ExpectedMetaValue(DataType::kHashes, meta_value)) { - if (ExpectedStale(meta_value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kHashes)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + Status s; + + // meta_value is empty means no meta value get before, + // we should get meta first + if (meta_value.empty()) { + s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); + if (s.ok() && !ExpectedMetaValue(DataType::kHashes, meta_value)) { + if (ExpectedStale(meta_value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kHashes)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + } } } if (s.ok()) { @@ -1227,16 +1312,24 @@ Status Redis::HashesPersist(const Slice& key) { return s; } -Status Redis::HashesTTL(const Slice& key, int64_t* timestamp) { - std::string meta_value; - +Status Redis::HashesTTL(const Slice& key, int64_t* timestamp, std::string&& prefetch_meta) { + std::string meta_value(std::move(prefetch_meta)); + Status s; BaseMetaKey base_meta_key(key); - Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); - if (s.ok() && !ExpectedMetaValue(DataType::kHashes, meta_value)) { - if (ExpectedStale(meta_value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kHashes)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + + // meta_value is empty means no meta value get before, + // we should get meta first + if (meta_value.empty()) { + s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); + if (s.ok() && !ExpectedMetaValue(DataType::kHashes, meta_value)) { + if (ExpectedStale(meta_value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kHashes)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + } } } if (s.ok()) { diff --git a/src/storage/src/redis_hyperloglog.cc b/src/storage/src/redis_hyperloglog.cc index 52dae42465..c9cd1dd4c1 100644 --- a/src/storage/src/redis_hyperloglog.cc +++ b/src/storage/src/redis_hyperloglog.cc @@ -3,11 +3,18 @@ // LICENSE file in the root directory of this source tree. An additional grant // of patent rights can be found in the PATENTS file in the same directory. -#include "src/redis_hyperloglog.h" + #include #include #include +#include + #include "src/storage_murmur3.h" +#include "storage/storage_define.h" +#include "src/redis.h" +#include "src/mutex.h" +#include "src/redis_hyperloglog.h" +#include "src/scope_record_lock.h" namespace storage { @@ -108,7 +115,59 @@ std::string HyperLogLog::Merge(const HyperLogLog& hll) { return result; } -// ::__builtin_ctz(x): 返回右起第一个‘1’之后的0的个数 +// ::__builtin_ctz(x): return the first number of '0' after the first '1' from the right uint8_t HyperLogLog::Nctz(uint32_t x, int b) { return static_cast(std::min(b, ::__builtin_ctz(x))) + 1; } -} // namespace storage + +bool IsHyperloglogObj(const std::string* internal_value_str) { + size_t kStringsValueSuffixLength = 2 * kTimestampLength + kSuffixReserveLength; + char reserve[16] = {0}; + size_t offset = internal_value_str->size() - kStringsValueSuffixLength; + memcpy(reserve, internal_value_str->data() + offset, kSuffixReserveLength); + + //if first bit in reserve is 0 , then this obj is string; else the obj is hyperloglog + return (reserve[0] & hyperloglog_reserve_flag) != 0;; +} + +Status Redis::HyperloglogGet(const Slice &key, std::string* value) { + value->clear(); + + BaseKey base_key(key); + Status s = db_->Get(default_read_options_, base_key.Encode(), value); + std::string meta_value = *value; + if (!s.ok()) { + return s; + } + if (!ExpectedMetaValue(DataType::kStrings, meta_value)) { + if (ExpectedStale(meta_value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + + ", expect type: " + "hyperloglog " + "get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + } + } else if (!IsHyperloglogObj(value)) { + return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + + ",expect type: " + "hyperloglog " + "get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + } else { + ParsedStringsValue parsed_strings_value(value); + if (parsed_strings_value.IsStale()) { + value->clear(); + return Status::NotFound("Stale"); + } else { + parsed_strings_value.StripSuffix(); + } + } + return s; +} + +Status Redis::HyperloglogSet(const Slice &key, const Slice &value) { + HyperloglogValue hyperloglog_value(value); + ScopeRecordLock l(lock_mgr_, key); + + BaseKey base_key(key); + return db_->Put(default_write_options_, base_key.Encode(), hyperloglog_value.Encode()); +} + +} // namespace storage \ No newline at end of file diff --git a/src/storage/src/redis_lists.cc b/src/storage/src/redis_lists.cc index 1998a76d23..db007ee2cf 100644 --- a/src/storage/src/redis_lists.cc +++ b/src/storage/src/redis_lists.cc @@ -72,7 +72,10 @@ Status Redis::LIndex(const Slice& key, int64_t index, std::string* element) { if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kLists)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kLists)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -113,7 +116,10 @@ Status Redis::LInsert(const Slice& key, const BeforeOrAfter& before_or_after, co if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kLists)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kLists)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -211,17 +217,25 @@ Status Redis::LInsert(const Slice& key, const BeforeOrAfter& before_or_after, co return s; } -Status Redis::LLen(const Slice& key, uint64_t* len) { +Status Redis::LLen(const Slice& key, uint64_t* len, std::string&& prefetch_meta) { *len = 0; - std::string meta_value; + Status s; - BaseMetaKey base_meta_key(key); - Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); - if (s.ok() && !ExpectedMetaValue(DataType::kLists, meta_value)) { - if (ExpectedStale(meta_value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kLists)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + // meta_value is empty means no meta value get before, + // we should get meta first + std::string meta_value(std::move(prefetch_meta)); + if (meta_value.empty()) { + BaseMetaKey base_meta_key(key); + s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); + if (s.ok() && !ExpectedMetaValue(DataType::kLists, meta_value)) { + if (ExpectedStale(meta_value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kLists)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + } } } if (s.ok()) { @@ -253,7 +267,10 @@ Status Redis::LPop(const Slice& key, int64_t count, std::vector* el if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kLists)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kLists)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -308,7 +325,10 @@ Status Redis::LPush(const Slice& key, const std::vector& values, ui if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kLists)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kLists)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -361,7 +381,10 @@ Status Redis::LPushx(const Slice& key, const std::vector& values, u if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kLists)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kLists)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -402,7 +425,10 @@ Status Redis::LRange(const Slice& key, int64_t start, int64_t stop, std::vector< if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kLists)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kLists)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -459,7 +485,10 @@ Status Redis::LRangeWithTTL(const Slice& key, int64_t start, int64_t stop, std:: if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kLists)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kLists)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -526,7 +555,10 @@ Status Redis::LRem(const Slice& key, int64_t count, const Slice& value, uint64_t if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kLists)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kLists)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -655,7 +687,10 @@ Status Redis::LSet(const Slice& key, int64_t index, const Slice& value) { if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kLists)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kLists)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -696,7 +731,10 @@ Status Redis::LTrim(const Slice& key, int64_t start, int64_t stop) { if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kLists)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kLists)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -766,7 +804,10 @@ Status Redis::RPop(const Slice& key, int64_t count, std::vector* el if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kLists)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kLists)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -820,7 +861,10 @@ Status Redis::RPoplpush(const Slice& source, const Slice& destination, std::stri if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + destination.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kLists)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + destination.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kLists)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -872,7 +916,10 @@ Status Redis::RPoplpush(const Slice& source, const Slice& destination, std::stri if (ExpectedStale(source_meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + source.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kLists)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(source_meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + source.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kLists)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(source_meta_value))]); } } if (s.ok()) { @@ -907,7 +954,10 @@ Status Redis::RPoplpush(const Slice& source, const Slice& destination, std::stri if (ExpectedStale(destination_meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + destination.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kLists)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(destination_meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + destination.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kLists)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(destination_meta_value))]); } } if (s.ok()) { @@ -961,7 +1011,10 @@ Status Redis::RPush(const Slice& key, const std::vector& values, ui if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kLists)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kLists)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -1014,7 +1067,10 @@ Status Redis::RPushx(const Slice& key, const std::vector& values, u if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kLists)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kLists)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -1041,17 +1097,25 @@ Status Redis::RPushx(const Slice& key, const std::vector& values, u return s; } -Status Redis::ListsExpire(const Slice& key, int64_t ttl) { - std::string meta_value; +Status Redis::ListsExpire(const Slice& key, int64_t ttl, std::string&& prefetch_meta) { + std::string meta_value(std::move(prefetch_meta)); ScopeRecordLock l(lock_mgr_, key); - BaseMetaKey base_meta_key(key); - Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); - if (s.ok() && !ExpectedMetaValue(DataType::kLists, meta_value)) { - if (ExpectedStale(meta_value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kLists)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + Status s; + + // meta_value is empty means no meta value get before, + // we should get meta first + if (meta_value.empty()) { + Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); + if (s.ok() && !ExpectedMetaValue(DataType::kLists, meta_value)) { + if (ExpectedStale(meta_value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kLists)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + } } } if (s.ok()) { @@ -1073,17 +1137,25 @@ Status Redis::ListsExpire(const Slice& key, int64_t ttl) { return s; } -Status Redis::ListsDel(const Slice& key) { - std::string meta_value; +Status Redis::ListsDel(const Slice& key, std::string&& prefetch_meta) { + std::string meta_value(std::move(prefetch_meta)); ScopeRecordLock l(lock_mgr_, key); - BaseMetaKey base_meta_key(key); - Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); - if (s.ok() && !ExpectedMetaValue(DataType::kLists, meta_value)) { - if (ExpectedStale(meta_value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kLists)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + Status s; + + // meta_value is empty means no meta value get before, + // we should get meta first + if (meta_value.empty()) { + s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); + if (s.ok() && !ExpectedMetaValue(DataType::kLists, meta_value)) { + if (ExpectedStale(meta_value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kLists)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + } } } if (s.ok()) { @@ -1102,17 +1174,25 @@ Status Redis::ListsDel(const Slice& key) { return s; } -Status Redis::ListsExpireat(const Slice& key, int64_t timestamp) { - std::string meta_value; +Status Redis::ListsExpireat(const Slice& key, int64_t timestamp, std::string&& prefetch_meta) { + std::string meta_value(std::move(prefetch_meta)); ScopeRecordLock l(lock_mgr_, key); - BaseMetaKey base_meta_key(key); - Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); - if (s.ok() && !ExpectedMetaValue(DataType::kLists, meta_value)) { - if (ExpectedStale(meta_value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kLists)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + Status s; + + // meta_value is empty means no meta value get before, + // we should get meta first + if (meta_value.empty()) { + s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); + if (s.ok() && !ExpectedMetaValue(DataType::kLists, meta_value)) { + if (ExpectedStale(meta_value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kLists)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + } } } if (s.ok()) { @@ -1133,16 +1213,25 @@ Status Redis::ListsExpireat(const Slice& key, int64_t timestamp) { return s; } -Status Redis::ListsPersist(const Slice& key) { - std::string meta_value; +Status Redis::ListsPersist(const Slice& key, std::string&& prefetch_meta) { + std::string meta_value(std::move(prefetch_meta)); ScopeRecordLock l(lock_mgr_, key); BaseMetaKey base_meta_key(key); - Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); - if (s.ok() && !ExpectedMetaValue(DataType::kLists, meta_value)) { - if (ExpectedStale(meta_value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kLists)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + Status s; + + // meta_value is empty means no meta value get before, + // we should get meta first + if (meta_value.empty()) { + s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); + if (s.ok() && !ExpectedMetaValue(DataType::kLists, meta_value)) { + if (ExpectedStale(meta_value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kLists)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + } } } if (s.ok()) { @@ -1152,8 +1241,8 @@ Status Redis::ListsPersist(const Slice& key) { } else if (parsed_lists_meta_value.Count() == 0) { return Status::NotFound(); } else { - uint64_t timestamp = parsed_lists_meta_value.Etime(); - if (timestamp == 0) { + // Check if the list has set expiration time before attempting to persist + if (parsed_lists_meta_value.Etime() == 0) { return Status::NotFound("Not have an associated timeout"); } else { parsed_lists_meta_value.SetEtime(0); @@ -1164,16 +1253,24 @@ Status Redis::ListsPersist(const Slice& key) { return s; } -Status Redis::ListsTTL(const Slice& key, int64_t* timestamp) { - std::string meta_value; - +Status Redis::ListsTTL(const Slice& key, int64_t* timestamp, std::string&& prefetch_meta) { + std::string meta_value(std::move(prefetch_meta)); BaseMetaKey base_meta_key(key); - Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); - if (s.ok() && !ExpectedMetaValue(DataType::kLists, meta_value)) { - if (ExpectedStale(meta_value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kLists)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + Status s; + + // meta_value is empty means no meta value get before, + // we should get meta first + if (meta_value.empty()) { + s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); + if (s.ok() && !ExpectedMetaValue(DataType::kLists, meta_value)) { + if (ExpectedStale(meta_value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kLists)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + } } } if (s.ok()) { @@ -1185,6 +1282,7 @@ Status Redis::ListsTTL(const Slice& key, int64_t* timestamp) { *timestamp = -2; return Status::NotFound(); } else { + // Return -1 for lists with no set expiration, and calculate remaining time for others *timestamp = parsed_lists_meta_value.Etime(); if (*timestamp == 0) { *timestamp = -1; diff --git a/src/storage/src/redis_sets.cc b/src/storage/src/redis_sets.cc index 9fc400d039..db5044b440 100644 --- a/src/storage/src/redis_sets.cc +++ b/src/storage/src/redis_sets.cc @@ -83,7 +83,10 @@ rocksdb::Status Redis::SAdd(const Slice& key, const std::vector& me if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -146,19 +149,25 @@ rocksdb::Status Redis::SAdd(const Slice& key, const std::vector& me return db_->Write(default_write_options_, &batch); } -rocksdb::Status Redis::SCard(const Slice& key, int32_t* ret) { +rocksdb::Status Redis::SCard(const Slice& key, int32_t* ret, std::string&& meta) { *ret = 0; - std::string meta_value; - - BaseMetaKey base_meta_key(key); - rocksdb::Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); - if (s.ok() && !ExpectedMetaValue(DataType::kSets, meta_value)) { - if (ExpectedStale(meta_value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + std::string meta_value(std::move(meta)); + rocksdb::Status s; + if (meta_value.empty()) { + BaseMetaKey base_meta_key(key); + s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); + if (s.ok() && !ExpectedMetaValue(DataType::kSets, meta_value)) { + if (ExpectedStale(meta_value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + } } } + if (s.ok()) { ParsedSetsMetaValue parsed_sets_meta_value(&meta_value); if (parsed_sets_meta_value.IsStale()) { @@ -195,7 +204,10 @@ rocksdb::Status Redis::SDiff(const std::vector& keys, std::vector(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + keys[idx] + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -214,7 +226,10 @@ rocksdb::Status Redis::SDiff(const std::vector& keys, std::vector(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + keys[0] + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -280,7 +295,10 @@ rocksdb::Status Redis::SDiffstore(const Slice& destination, const std::vector(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + keys[idx] + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -300,7 +318,10 @@ rocksdb::Status Redis::SDiffstore(const Slice& destination, const std::vector(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + keys[0] + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -346,7 +367,10 @@ rocksdb::Status Redis::SDiffstore(const Slice& destination, const std::vector(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + destination.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -401,7 +425,10 @@ rocksdb::Status Redis::SInter(const std::vector& keys, std::vector< if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + keys[idx] + ", expect type: " + DataTypeStrings[static_cast(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + keys[idx] + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -424,7 +451,10 @@ rocksdb::Status Redis::SInter(const std::vector& keys, std::vector< if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + keys[0] + ", expect type: " + DataTypeStrings[static_cast(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + keys[0] + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -496,7 +526,10 @@ rocksdb::Status Redis::SInterstore(const Slice& destination, const std::vector(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + keys[idx] + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -523,7 +556,10 @@ rocksdb::Status Redis::SInterstore(const Slice& destination, const std::vector(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + keys[0] + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -575,7 +611,10 @@ rocksdb::Status Redis::SInterstore(const Slice& destination, const std::vector(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + destination.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -624,7 +663,10 @@ rocksdb::Status Redis::SIsmember(const Slice& key, const Slice& member, int32_t* if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -661,14 +703,20 @@ rocksdb::Status Redis::SMembers(const Slice& key, std::vector* memb if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok() && !ExpectedMetaValue(DataType::kSets, meta_value)) { if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -709,7 +757,10 @@ Status Redis::SMembersWithTTL(const Slice& key, if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -768,7 +819,10 @@ rocksdb::Status Redis::SMove(const Slice& source, const Slice& destination, cons if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + source.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + source.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -811,7 +865,10 @@ rocksdb::Status Redis::SMove(const Slice& source, const Slice& destination, cons if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + destination.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + destination.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -872,7 +929,10 @@ rocksdb::Status Redis::SPop(const Slice& key, std::vector* members, if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -986,7 +1046,10 @@ rocksdb::Status Redis::SRandmember(const Slice& key, int32_t count, std::vector< if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -1057,7 +1120,10 @@ rocksdb::Status Redis::SRem(const Slice& key, const std::vector& me if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -1121,7 +1187,10 @@ rocksdb::Status Redis::SUnion(const std::vector& keys, std::vector< if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key + ", expect type: " + DataTypeStrings[static_cast(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -1178,7 +1247,10 @@ rocksdb::Status Redis::SUnionstore(const Slice& destination, const std::vector(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -1217,7 +1289,10 @@ rocksdb::Status Redis::SUnionstore(const Slice& destination, const std::vector(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + destination.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -1274,7 +1349,10 @@ rocksdb::Status Redis::SScan(const Slice& key, int64_t cursor, const std::string if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -1329,17 +1407,25 @@ rocksdb::Status Redis::SScan(const Slice& key, int64_t cursor, const std::string return rocksdb::Status::OK(); } -rocksdb::Status Redis::SetsExpire(const Slice& key, int64_t ttl) { - std::string meta_value; +rocksdb::Status Redis::SetsExpire(const Slice& key, int64_t ttl, std::string&& prefetch_meta) { + std::string meta_value(std::move(prefetch_meta)); ScopeRecordLock l(lock_mgr_, key); - BaseMetaKey base_meta_key(key); - rocksdb::Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); - if (s.ok() && !ExpectedMetaValue(DataType::kSets, meta_value)) { - if (ExpectedStale(meta_value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + rocksdb::Status s; + + // meta_value is empty means no meta value get before, + // we should get meta first + if (meta_value.empty()) { + s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); + if (s.ok() && !ExpectedMetaValue(DataType::kSets, meta_value)) { + if (ExpectedStale(meta_value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + } } } if (s.ok()) { @@ -1361,17 +1447,25 @@ rocksdb::Status Redis::SetsExpire(const Slice& key, int64_t ttl) { return s; } -rocksdb::Status Redis::SetsDel(const Slice& key) { - std::string meta_value; +rocksdb::Status Redis::SetsDel(const Slice& key, std::string&& prefetch_meta) { + std::string meta_value(std::move(prefetch_meta)); ScopeRecordLock l(lock_mgr_, key); - + rocksdb::Status s; BaseMetaKey base_meta_key(key); - rocksdb::Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); - if (s.ok() && !ExpectedMetaValue(DataType::kSets, meta_value)) { - if (ExpectedStale(meta_value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + + // meta_value is empty means no meta value get before, + // we should get meta first + if (meta_value.empty()) { + s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); + if (s.ok() && !ExpectedMetaValue(DataType::kSets, meta_value)) { + if (ExpectedStale(meta_value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + } } } if (s.ok()) { @@ -1390,17 +1484,25 @@ rocksdb::Status Redis::SetsDel(const Slice& key) { return s; } -rocksdb::Status Redis::SetsExpireat(const Slice& key, int64_t timestamp) { - std::string meta_value; +rocksdb::Status Redis::SetsExpireat(const Slice& key, int64_t timestamp, std::string&& prefetch_meta) { + std::string meta_value(std::move(prefetch_meta)); ScopeRecordLock l(lock_mgr_, key); - BaseMetaKey base_meta_key(key); - rocksdb::Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); - if (s.ok() && !ExpectedMetaValue(DataType::kSets, meta_value)) { - if (ExpectedStale(meta_value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + Status s; + + // meta_value is empty means no meta value get before, + // we should get meta first + if (meta_value.empty()) { + rocksdb::Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); + if (s.ok() && !ExpectedMetaValue(DataType::kSets, meta_value)) { + if (ExpectedStale(meta_value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + } } } if (s.ok()) { @@ -1421,17 +1523,25 @@ rocksdb::Status Redis::SetsExpireat(const Slice& key, int64_t timestamp) { return s; } -rocksdb::Status Redis::SetsPersist(const Slice& key) { - std::string meta_value; +rocksdb::Status Redis::SetsPersist(const Slice& key, std::string&& prefetch_meta) { + std::string meta_value(std::move(prefetch_meta)); ScopeRecordLock l(lock_mgr_, key); - BaseMetaKey base_meta_key(key); - rocksdb::Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); - if (s.ok() && !ExpectedMetaValue(DataType::kSets, meta_value)) { - if (ExpectedStale(meta_value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + rocksdb::Status s; + + // meta_value is empty means no meta value get before, + // we should get meta first + if (meta_value.empty()) { + rocksdb::Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); + if (s.ok() && !ExpectedMetaValue(DataType::kSets, meta_value)) { + if (ExpectedStale(meta_value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + } } } if (s.ok()) { @@ -1453,16 +1563,24 @@ rocksdb::Status Redis::SetsPersist(const Slice& key) { return s; } -rocksdb::Status Redis::SetsTTL(const Slice& key, int64_t* timestamp) { - std::string meta_value; - +rocksdb::Status Redis::SetsTTL(const Slice& key, int64_t* timestamp, std::string&& prefetch_meta) { + std::string meta_value(std::move(prefetch_meta)); BaseMetaKey base_meta_key(key); - rocksdb::Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); - if (s.ok() && !ExpectedMetaValue(DataType::kSets, meta_value)) { - if (ExpectedStale(meta_value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + rocksdb::Status s; + + // meta_value is empty means no meta value get before, + // we should get meta first + if (meta_value.empty()) { + s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); + if (s.ok() && !ExpectedMetaValue(DataType::kSets, meta_value)) { + if (ExpectedStale(meta_value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kSets)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + } } } if (s.ok()) { diff --git a/src/storage/src/redis_streams.cc b/src/storage/src/redis_streams.cc index 47942244c5..606fb99c05 100644 --- a/src/storage/src/redis_streams.cc +++ b/src/storage/src/redis_streams.cc @@ -171,11 +171,11 @@ Status Redis::XDel(const Slice& key, const std::vector& ids, int32_t& return s; } } - + return db_->Put(default_write_options_, handles_[kMetaCF], BaseMetaKey(key).Encode(), stream_meta.value()); } -Status Redis::XRange(const Slice& key, const StreamScanArgs& args, std::vector& field_values) { +Status Redis::XRange(const Slice& key, const StreamScanArgs& args, std::vector& field_values, std::string&& prefetch_meta) { rocksdb::ReadOptions read_options; const rocksdb::Snapshot* snapshot; ScopeSnapshot ss(db_, &snapshot); @@ -184,7 +184,7 @@ Status Redis::XRange(const Slice& key, const StreamScanArgs& args, std::vectorGet(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); - if (s.ok() && !ExpectedMetaValue(DataType::kStreams, meta_value)) { - if (ExpectedStale(meta_value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kStreams)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + Status s; + + // value is empty means no meta value get before, + // we should get meta first + if (meta_value.empty()) { + s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); + if (s.ok() && !ExpectedMetaValue(DataType::kStreams, meta_value)) { + if (ExpectedStale(meta_value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kStreams)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + } } } if (s.ok()) { @@ -387,15 +396,24 @@ Status Redis::StreamsDel(const Slice& key) { } Status Redis::GetStreamMeta(StreamMetaValue& stream_meta, const rocksdb::Slice& key, - rocksdb::ReadOptions& read_options) { - std::string value; + rocksdb::ReadOptions& read_options, std::string&& prefetch_meta) { + std::string value(std::move(prefetch_meta)); BaseMetaKey base_meta_key(key); - auto s = db_->Get(read_options, handles_[kMetaCF], base_meta_key.Encode(), &value); - if (s.ok() && !ExpectedMetaValue(DataType::kStreams, value)) { - if (ExpectedStale(value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kStreams)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(value))]); + Status s; + + // value is empty means no meta value get before, + // we should get meta first + if (value.empty()) { + s = db_->Get(read_options, handles_[kMetaCF], base_meta_key.Encode(), &value); + if (s.ok() && !ExpectedMetaValue(DataType::kStreams, value)) { + if (ExpectedStale(value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kStreams)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(value))]); + } } } if (s.ok()) { diff --git a/src/storage/src/redis_strings.cc b/src/storage/src/redis_strings.cc index cab41de9aa..970695bf4b 100644 --- a/src/storage/src/redis_strings.cc +++ b/src/storage/src/redis_strings.cc @@ -74,7 +74,10 @@ Status Redis::Append(const Slice& key, const Slice& value, int32_t* ret) { if (ExpectedStale(old_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kStrings)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(old_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kStrings)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(old_value))]); } } if (s.ok()) { @@ -127,7 +130,10 @@ Status Redis::BitCount(const Slice& key, int64_t start_offset, int64_t end_offse if (ExpectedStale(value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kStrings)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kStrings)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(value))]); } } if (s.ok()) { @@ -230,7 +236,10 @@ Status Redis::BitOp(BitOpType op, const std::string& dest_key, const std::vector if (ExpectedStale(value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + dest_key + ", expect type: " + DataTypeStrings[static_cast(DataType::kStrings)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + dest_key + ", expect type: " + + DataTypeStrings[static_cast(DataType::kStrings)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(value))]); } } if (s.ok()) { @@ -273,7 +282,10 @@ Status Redis::Decrby(const Slice& key, int64_t value, int64_t* ret) { if (ExpectedStale(old_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kStrings)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(old_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kStrings)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(old_value))]); } } if (s.ok()) { @@ -321,7 +333,10 @@ Status Redis::Get(const Slice& key, std::string* value) { if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kStrings)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kStrings)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -390,7 +405,10 @@ Status Redis::GetWithTTL(const Slice& key, std::string* value, int64_t* ttl) { if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kStrings)] + " get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kStrings)] + " get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } @@ -435,7 +453,10 @@ Status Redis::GetBit(const Slice& key, int64_t offset, int32_t* ret) { if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kStrings)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kStrings)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -470,7 +491,10 @@ Status Redis::Getrange(const Slice& key, int64_t start_offset, int64_t end_offse if (ExpectedStale(value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kStrings)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kStrings)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(value))]); } } if (s.ok()) { @@ -512,7 +536,10 @@ Status Redis::GetrangeWithValue(const Slice& key, int64_t start_offset, int64_t if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kStrings)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kStrings)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -571,7 +598,10 @@ Status Redis::GetSet(const Slice& key, const Slice& value, std::string* old_valu if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kStrings)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kStrings)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -600,7 +630,10 @@ Status Redis::Incrby(const Slice& key, int64_t value, int64_t* ret) { if (ExpectedStale(old_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kStrings)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(old_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kStrings)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(old_value))]); } } if (s.ok()) { @@ -652,7 +685,10 @@ Status Redis::Incrbyfloat(const Slice& key, const Slice& value, std::string* ret if (ExpectedStale(old_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kStrings)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(old_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kStrings)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(old_value))]); } } if (s.ok()) { @@ -714,20 +750,14 @@ Status Redis::MSetnx(const std::vector& kvs, int32_t* ret) { for (const auto & kv : kvs) { BaseKey base_key(kv.key); s = db_->Get(default_read_options_, base_key.Encode(), &value); - if (s.ok() && !ExpectedMetaValue(DataType::kStrings, value)) { - if (ExpectedStale(value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + kv.key + ", expect type: " + DataTypeStrings[static_cast(DataType::kStrings)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(value))]); - } + if (!s.ok() && !s.IsNotFound()) { + return s; } - if (s.ok()) { - ParsedStringsValue parsed_strings_value(&value); - if (!parsed_strings_value.IsStale()) { - exists = true; - break; - } + if (s.ok() && !ExpectedStale(value)) { + exists = true; + break; } + // when reaches here, either s is not found or s is ok but expired } if (!exists) { s = MSet(kvs); @@ -758,7 +788,10 @@ Status Redis::Setxx(const Slice& key, const Slice& value, int32_t* ret, int64_t if (ExpectedStale(old_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kStrings)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(old_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kStrings)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(old_value))]); } } if (s.ok()) { @@ -795,7 +828,10 @@ Status Redis::SetBit(const Slice& key, int64_t offset, int32_t on, int32_t* ret) if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kStrings)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kStrings)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok() || s.IsNotFound()) { @@ -860,34 +896,22 @@ Status Redis::Setnx(const Slice& key, const Slice& value, int32_t* ret, int64_t BaseKey base_key(key); ScopeRecordLock l(lock_mgr_, key); Status s = db_->Get(default_read_options_, base_key.Encode(), &old_value); - if (s.ok() && !ExpectedMetaValue(DataType::kStrings, old_value)) { - if (ExpectedStale(old_value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kStrings)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(old_value))]); - } + if (!s.ok() && !s.IsNotFound()) { + return s; + } + if (s.ok() && !ExpectedStale(old_value)) { + return s; + } + // when reaches here, either s is not found or s is ok but expired + s = Status::NotFound(); + + StringsValue strings_value(value); + if (ttl > 0) { + strings_value.SetRelativeTimestamp(ttl); } + s = db_->Put(default_write_options_, base_key.Encode(), strings_value.Encode()); if (s.ok()) { - ParsedStringsValue parsed_strings_value(&old_value); - if (parsed_strings_value.IsStale()) { - StringsValue strings_value(value); - if (ttl > 0) { - strings_value.SetRelativeTimestamp(ttl); - } - s = db_->Put(default_write_options_, base_key.Encode(), strings_value.Encode()); - if (s.ok()) { - *ret = 1; - } - } - } else if (s.IsNotFound()) { - StringsValue strings_value(value); - if (ttl > 0) { - strings_value.SetRelativeTimestamp(ttl); - } - s = db_->Put(default_write_options_, base_key.Encode(), strings_value.Encode()); - if (s.ok()) { - *ret = 1; - } + *ret = 1; } return s; } @@ -904,7 +928,10 @@ Status Redis::Setvx(const Slice& key, const Slice& value, const Slice& new_value if (ExpectedStale(old_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kStrings)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(old_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kStrings)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(old_value))]); } } if (s.ok()) { @@ -945,7 +972,10 @@ Status Redis::Delvx(const Slice& key, const Slice& value, int32_t* ret) { if (ExpectedStale(old_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kStrings)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(old_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kStrings)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(old_value))]); } } if (s.ok()) { @@ -981,7 +1011,10 @@ Status Redis::Setrange(const Slice& key, int64_t start_offset, const Slice& valu if (ExpectedStale(old_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kStrings)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(old_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kStrings)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(old_value))]); } } if (s.ok()) { @@ -1087,7 +1120,10 @@ Status Redis::BitPos(const Slice& key, int32_t bit, int64_t* ret) { if (ExpectedStale(value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kStrings)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kStrings)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(value))]); } } if (s.ok()) { @@ -1131,7 +1167,10 @@ Status Redis::BitPos(const Slice& key, int32_t bit, int64_t start_offset, int64_ if (ExpectedStale(value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kStrings)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kStrings)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(value))]); } } if (s.ok()) { @@ -1188,7 +1227,10 @@ Status Redis::BitPos(const Slice& key, int32_t bit, int64_t start_offset, int64_ if (ExpectedStale(value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kStrings)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kStrings)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(value))]); } } if (s.ok()) { @@ -1254,17 +1296,25 @@ Status Redis::PKSetexAt(const Slice& key, const Slice& value, int64_t timestamp) return db_->Put(default_write_options_, base_key.Encode(), strings_value.Encode()); } -Status Redis::StringsExpire(const Slice& key, int64_t ttl) { - std::string value; +Status Redis::StringsExpire(const Slice& key, int64_t ttl, std::string&& prefetch_meta) { + std::string value(std::move(prefetch_meta)); BaseKey base_key(key); ScopeRecordLock l(lock_mgr_, key); - Status s = db_->Get(default_read_options_, base_key.Encode(), &value); - if (s.ok() && !ExpectedMetaValue(DataType::kStrings, value)) { - if (ExpectedStale(value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kStrings)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(value))]); + Status s; + // value is empty means no meta value get before, + // we should get meta first + if (value.empty()) { + Status s = db_->Get(default_read_options_, base_key.Encode(), &value); + if (s.ok() && !ExpectedMetaValue(DataType::kStrings, value)) { + if (ExpectedStale(value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kStrings)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(value))]); + } } } if (s.ok()) { @@ -1282,17 +1332,25 @@ Status Redis::StringsExpire(const Slice& key, int64_t ttl) { return s; } -Status Redis::StringsDel(const Slice& key) { - std::string value; +Status Redis::StringsDel(const Slice& key, std::string&& prefetch_meta) { + std::string value(std::move(prefetch_meta)); ScopeRecordLock l(lock_mgr_, key); - BaseKey base_key(key); - Status s = db_->Get(default_read_options_, base_key.Encode(), &value); - if (s.ok() && !ExpectedMetaValue(DataType::kStrings, value)) { - if (ExpectedStale(value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kStrings)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(value))]); + Status s; + + // value is empty means no meta value get before, + // we should get meta first + if (value.empty()) { + Status s = db_->Get(default_read_options_, base_key.Encode(), &value); + if (s.ok() && !ExpectedMetaValue(DataType::kStrings, value)) { + if (ExpectedStale(value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kStrings)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(value))]); + } } } if (s.ok()) { @@ -1305,17 +1363,25 @@ Status Redis::StringsDel(const Slice& key) { return s; } -Status Redis::StringsExpireat(const Slice& key, int64_t timestamp) { - std::string value; +Status Redis::StringsExpireat(const Slice& key, int64_t timestamp, std::string&& prefetch_meta) { + std::string value(std::move(prefetch_meta)); ScopeRecordLock l(lock_mgr_, key); - BaseKey base_key(key); - Status s = db_->Get(default_read_options_, base_key.Encode(), &value); - if (s.ok() && !ExpectedMetaValue(DataType::kStrings, value)) { - if (ExpectedStale(value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kStrings)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(value))]); + Status s; + + // value is empty means no meta value get before, + // we should get meta first + if (value.empty()) { + Status s = db_->Get(default_read_options_, base_key.Encode(), &value); + if (s.ok() && !ExpectedMetaValue(DataType::kStrings, value)) { + if (ExpectedStale(value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kStrings)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(value))]); + } } } if (s.ok()) { @@ -1334,17 +1400,25 @@ Status Redis::StringsExpireat(const Slice& key, int64_t timestamp) { return s; } -Status Redis::StringsPersist(const Slice& key) { - std::string value; +Status Redis::StringsPersist(const Slice& key, std::string&& prefetch_meta) { + std::string value(std::move(prefetch_meta)); ScopeRecordLock l(lock_mgr_, key); - BaseKey base_key(key); - Status s = db_->Get(default_read_options_, base_key.Encode(), &value); - if (s.ok() && !ExpectedMetaValue(DataType::kStrings, value)) { - if (ExpectedStale(value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kStrings)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(value))]); + Status s; + + // value is empty means no meta value get before, + // we should get meta first + if (value.empty()) { + s = db_->Get(default_read_options_, base_key.Encode(), &value); + if (s.ok() && !ExpectedMetaValue(DataType::kStrings, value)) { + if (ExpectedStale(value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kStrings)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(value))]); + } } } if (s.ok()) { @@ -1364,17 +1438,25 @@ Status Redis::StringsPersist(const Slice& key) { return s; } -Status Redis::StringsTTL(const Slice& key, int64_t* timestamp) { - std::string value; +Status Redis::StringsTTL(const Slice& key, int64_t* timestamp, std::string&& prefetch_meta) { + std::string value(std::move(prefetch_meta)); ScopeRecordLock l(lock_mgr_, key); - BaseKey base_key(key); - Status s = db_->Get(default_read_options_, base_key.Encode(), &value); - if (s.ok() && !ExpectedMetaValue(DataType::kStrings, value)) { - if (ExpectedStale(value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kStrings)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(value))]); + Status s; + + // value is empty means no meta value get before, + // we should get meta first + if (value.empty()) { + s = db_->Get(default_read_options_, base_key.Encode(), &value); + if (s.ok() && !ExpectedMetaValue(DataType::kStrings, value)) { + if (ExpectedStale(value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expect type: " + + DataTypeStrings[static_cast(DataType::kStrings)] + ", get type: " + + DataTypeStrings[static_cast(GetMetaValueType(value))]); + } } } if (s.ok()) { @@ -1430,7 +1512,6 @@ void Redis::ScanStrings() { rocksdb::Status Redis::Exists(const Slice& key) { std::string meta_value; uint64_t llen = 0; - std::string value; int32_t ret = 0; BaseMetaKey base_meta_key(key); std::vector id_messages; @@ -1442,17 +1523,17 @@ rocksdb::Status Redis::Exists(const Slice& key) { auto type = static_cast(static_cast(meta_value[0])); switch (type) { case DataType::kSets: - return SCard(key, &ret); + return SCard(key, &ret, std::move(meta_value)); case DataType::kZSets: - return ZCard(key, &ret); + return ZCard(key, &ret, std::move(meta_value)); case DataType::kHashes: - return HLen(key, &ret); + return HLen(key, &ret, std::move(meta_value)); case DataType::kLists: - return LLen(key, &llen); - case DataType::kStrings: - return Get(key, &value); + return LLen(key, &llen, std::move(meta_value)); case DataType::kStreams: - return XRange(key, arg, id_messages); + return XRange(key, arg, id_messages, std::move(meta_value)); + case DataType::kStrings: + return ExpectedStale(meta_value) ? rocksdb::Status::NotFound() : rocksdb::Status::OK(); default: return rocksdb::Status::NotFound(); } @@ -1468,17 +1549,17 @@ rocksdb::Status Redis::Del(const Slice& key) { auto type = static_cast(static_cast(meta_value[0])); switch (type) { case DataType::kSets: - return SetsDel(key); + return SetsDel(key, std::move(meta_value)); case DataType::kZSets: - return ZsetsDel(key); + return ZsetsDel(key, std::move(meta_value)); case DataType::kHashes: - return HashesDel(key); + return HashesDel(key, std::move(meta_value)); case DataType::kLists: - return ListsDel(key); + return ListsDel(key, std::move(meta_value)); case DataType::kStrings: - return StringsDel(key); + return StringsDel(key, std::move(meta_value)); case DataType::kStreams: - return StreamsDel(key); + return StreamsDel(key, std::move(meta_value)); default: return rocksdb::Status::NotFound(); } @@ -1494,15 +1575,15 @@ rocksdb::Status Redis::Expire(const Slice& key, int64_t ttl) { auto type = static_cast(static_cast(meta_value[0])); switch (type) { case DataType::kSets: - return SetsExpire(key, ttl); + return SetsExpire(key, ttl, std::move(meta_value)); case DataType::kZSets: - return ZsetsExpire(key, ttl); + return ZsetsExpire(key, ttl, std::move(meta_value)); case DataType::kHashes: - return HashesExpire(key, ttl); + return HashesExpire(key, ttl, std::move(meta_value)); case DataType::kLists: - return ListsExpire(key, ttl); + return ListsExpire(key, ttl, std::move(meta_value)); case DataType::kStrings: - return StringsExpire(key, ttl); + return StringsExpire(key, ttl, std::move(meta_value)); default: return rocksdb::Status::NotFound(); } @@ -1518,15 +1599,15 @@ rocksdb::Status Redis::Expireat(const Slice& key, int64_t ttl) { auto type = static_cast(static_cast(meta_value[0])); switch (type) { case DataType::kSets: - return SetsExpireat(key, ttl); + return SetsExpireat(key, ttl, std::move(meta_value)); case DataType::kZSets: - return ZsetsExpireat(key, ttl); + return ZsetsExpireat(key, ttl, std::move(meta_value)); case DataType::kHashes: - return HashesExpireat(key, ttl); + return HashesExpireat(key, ttl, std::move(meta_value)); case DataType::kLists: - return ListsExpireat(key, ttl); + return ListsExpireat(key, ttl, std::move(meta_value)); case DataType::kStrings: - return StringsExpireat(key, ttl); + return StringsExpireat(key, ttl, std::move(meta_value)); default: return rocksdb::Status::NotFound(); } @@ -1542,15 +1623,15 @@ rocksdb::Status Redis::Persist(const Slice& key) { auto type = static_cast(static_cast(meta_value[0])); switch (type) { case DataType::kSets: - return SetsPersist(key); + return SetsPersist(key, std::move(meta_value)); case DataType::kZSets: - return ZsetsPersist(key); + return ZsetsPersist(key, std::move(meta_value)); case DataType::kHashes: - return HashesPersist(key); + return HashesPersist(key, std::move(meta_value)); case DataType::kLists: - return ListsPersist(key); + return ListsPersist(key, std::move(meta_value)); case DataType::kStrings: - return StringsPersist(key); + return StringsPersist(key, std::move(meta_value)); default: return rocksdb::Status::NotFound(); } @@ -1566,15 +1647,15 @@ rocksdb::Status Redis::TTL(const Slice& key, int64_t* timestamp) { auto type = static_cast(static_cast(meta_value[0])); switch (type) { case DataType::kSets: - return SetsTTL(key, timestamp); + return SetsTTL(key, timestamp, std::move(meta_value)); case DataType::kZSets: - return ZsetsTTL(key, timestamp); + return ZsetsTTL(key, timestamp, std::move(meta_value)); case DataType::kHashes: - return HashesTTL(key, timestamp); + return HashesTTL(key, timestamp, std::move(meta_value)); case DataType::kLists: - return ListsTTL(key, timestamp); + return ListsTTL(key, timestamp, std::move(meta_value)); case DataType::kStrings: - return StringsTTL(key, timestamp); + return StringsTTL(key, timestamp, std::move(meta_value)); default: return rocksdb::Status::NotFound(); } @@ -1597,6 +1678,9 @@ rocksdb::Status Redis::IsExist(const storage::Slice& key) { BaseMetaKey base_meta_key(key); rocksdb::Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); if (s.ok()) { + if (ExpectedStale(meta_value)) { + return Status::NotFound(); + } return Status::OK(); } return rocksdb::Status::NotFound(); @@ -1619,19 +1703,19 @@ rocksdb::Status Redis::PKPatternMatchDel(const std::string& pattern, int32_t* re rocksdb::WriteBatch batch; rocksdb::Iterator* iter = db_->NewIterator(iterator_options, handles_[kMetaCF]); iter->SeekToFirst(); - key = iter->key().ToString(); while (iter->Valid()) { auto meta_type = static_cast(static_cast(iter->value()[0])); ParsedBaseMetaKey parsed_meta_key(iter->key().ToString()); + key = iter->key().ToString(); + meta_value = iter->value().ToString(); + if (meta_type == DataType::kStrings) { - meta_value = iter->value().ToString(); ParsedStringsValue parsed_strings_value(&meta_value); 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); } } else if (meta_type == DataType::kLists) { - meta_value = iter->value().ToString(); ParsedListsMetaValue parsed_lists_meta_value(&meta_value); if (!parsed_lists_meta_value.IsStale() && (parsed_lists_meta_value.Count() != 0U) && (StringMatch(pattern.data(), pattern.size(), parsed_meta_key.Key().data(), parsed_meta_key.Key().size(), 0) != @@ -1648,7 +1732,6 @@ rocksdb::Status Redis::PKPatternMatchDel(const std::string& pattern, int32_t* re batch.Put(handles_[kMetaCF], key, stream_meta_value.value()); } } else { - meta_value = iter->value().ToString(); ParsedBaseMetaValue parsed_meta_value(&meta_value); if (!parsed_meta_value.IsStale() && (parsed_meta_value.Count() != 0) && (StringMatch(pattern.data(), pattern.size(), parsed_meta_key.Key().data(), parsed_meta_key.Key().size(), 0) != diff --git a/src/storage/src/redis_zsets.cc b/src/storage/src/redis_zsets.cc index 503d3710dc..ce89afe885 100644 --- a/src/storage/src/redis_zsets.cc +++ b/src/storage/src/redis_zsets.cc @@ -77,7 +77,10 @@ Status Redis::ZPopMax(const Slice& key, const int64_t count, std::vector(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -132,7 +135,10 @@ Status Redis::ZPopMin(const Slice& key, const int64_t count, std::vector(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -198,7 +204,10 @@ Status Redis::ZAdd(const Slice& key, const std::vector& score_membe if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -284,20 +293,28 @@ Status Redis::ZAdd(const Slice& key, const std::vector& score_membe return s; } -Status Redis::ZCard(const Slice& key, int32_t* card) { +Status Redis::ZCard(const Slice& key, int32_t* card, std::string&& prefetch_meta) { *card = 0; - std::string meta_value; - + Status s; - BaseMetaKey base_meta_key(key); - Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); - if (s.ok() && !ExpectedMetaValue(DataType::kZSets, meta_value)) { - if (ExpectedStale(meta_value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + // meta_value is empty means no meta value get before, + // we should get meta first + std::string meta_value(std::move(prefetch_meta)); + if (meta_value.empty()) { + BaseMetaKey base_meta_key(key); + s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); + if (s.ok() && !ExpectedMetaValue(DataType::kZSets, meta_value)) { + if (ExpectedStale(meta_value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + } } } + if (s.ok()) { ParsedZSetsMetaValue parsed_zsets_meta_value(&meta_value); if (parsed_zsets_meta_value.IsStale()) { @@ -329,7 +346,10 @@ Status Redis::ZCount(const Slice& key, double min, double max, bool left_close, if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -394,7 +414,10 @@ Status Redis::ZIncrby(const Slice& key, const Slice& member, double increment, d if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -470,7 +493,10 @@ Status Redis::ZRange(const Slice& key, int32_t start, int32_t stop, std::vector< if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -525,7 +551,10 @@ Status Redis::ZRangeWithTTL(const Slice& key, int32_t start, int32_t stop, std:: if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -594,7 +623,10 @@ Status Redis::ZRangebyscore(const Slice& key, double min, double max, bool left_ if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -668,7 +700,10 @@ Status Redis::ZRank(const Slice& key, const Slice& member, int32_t* rank) { if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -727,7 +762,10 @@ Status Redis::ZRem(const Slice& key, const std::vector& members, in if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -787,7 +825,10 @@ Status Redis::ZRemrangebyrank(const Slice& key, int32_t start, int32_t stop, int if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -852,7 +893,10 @@ Status Redis::ZRemrangebyscore(const Slice& key, double min, double max, bool le if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -931,7 +975,10 @@ Status Redis::ZRevrange(const Slice& key, int32_t start, int32_t stop, std::vect if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -986,7 +1033,10 @@ Status Redis::ZRevrangebyscore(const Slice& key, double min, double max, bool le if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -1060,7 +1110,10 @@ Status Redis::ZRevrank(const Slice& key, const Slice& member, int32_t* rank) { if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -1111,7 +1164,10 @@ Status Redis::ZScore(const Slice& key, const Slice& member, double* score) { if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -1155,7 +1211,10 @@ Status Redis::ZGetAll(const Slice& key, double weight, std::map(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -1204,7 +1263,10 @@ Status Redis::ZUnionstore(const Slice& destination, const std::vector(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + keys[idx] + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -1255,7 +1317,10 @@ Status Redis::ZUnionstore(const Slice& destination, const std::vector(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + destination.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -1328,7 +1393,10 @@ Status Redis::ZInterstore(const Slice& destination, const std::vector(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + keys[idx] + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -1405,7 +1473,10 @@ Status Redis::ZInterstore(const Slice& destination, const std::vector(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + destination.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -1464,7 +1535,10 @@ Status Redis::ZRangebylex(const Slice& key, const Slice& min, const Slice& max, if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -1534,7 +1608,10 @@ Status Redis::ZRemrangebylex(const Slice& key, const Slice& min, const Slice& ma if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -1593,17 +1670,25 @@ Status Redis::ZRemrangebylex(const Slice& key, const Slice& min, const Slice& ma return s; } -Status Redis::ZsetsExpire(const Slice& key, int64_t ttl) { - std::string meta_value; +Status Redis::ZsetsExpire(const Slice& key, int64_t ttl, std::string&& prefetch_meta) { + std::string meta_value(std::move(prefetch_meta)); ScopeRecordLock l(lock_mgr_, key); - BaseMetaKey base_meta_key(key); - Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); - if (s.ok() && !ExpectedMetaValue(DataType::kZSets, meta_value)) { - if (ExpectedStale(meta_value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + Status s; + + // meta_value is empty means no meta value get before, + // we should get meta first + if (meta_value.empty()) { + Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); + if (s.ok() && !ExpectedMetaValue(DataType::kZSets, meta_value)) { + if (ExpectedStale(meta_value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + } } } if (s.ok()) { @@ -1624,17 +1709,25 @@ Status Redis::ZsetsExpire(const Slice& key, int64_t ttl) { return s; } -Status Redis::ZsetsDel(const Slice& key) { - std::string meta_value; +Status Redis::ZsetsDel(const Slice& key, std::string&& prefetch_meta) { + std::string meta_value(std::move(prefetch_meta)); ScopeRecordLock l(lock_mgr_, key); - BaseMetaKey base_meta_key(key); - Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); - if (s.ok() && !ExpectedMetaValue(DataType::kZSets, meta_value)) { - if (ExpectedStale(meta_value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + Status s; + + // meta_value is empty means no meta value get before, + // we should get meta first + if (meta_value.empty()) { + s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); + if (s.ok() && !ExpectedMetaValue(DataType::kZSets, meta_value)) { + if (ExpectedStale(meta_value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + } } } if (s.ok()) { @@ -1653,17 +1746,25 @@ Status Redis::ZsetsDel(const Slice& key) { return s; } -Status Redis::ZsetsExpireat(const Slice& key, int64_t timestamp) { - std::string meta_value; +Status Redis::ZsetsExpireat(const Slice& key, int64_t timestamp, std::string&& prefetch_meta) { + std::string meta_value(std::move(prefetch_meta)); ScopeRecordLock l(lock_mgr_, key); - BaseMetaKey base_meta_key(key); - Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); - if (s.ok() && !ExpectedMetaValue(DataType::kZSets, meta_value)) { - if (ExpectedStale(meta_value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + Status s; + + // meta_value is empty means no meta value get before, + // we should get meta first + if (meta_value.empty()) { + s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); + if (s.ok() && !ExpectedMetaValue(DataType::kZSets, meta_value)) { + if (ExpectedStale(meta_value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + } } } if (s.ok()) { @@ -1708,7 +1809,10 @@ Status Redis::ZScan(const Slice& key, int64_t cursor, const std::string& pattern if (ExpectedStale(meta_value)) { s = Status::NotFound(); } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); } } if (s.ok()) { @@ -1767,17 +1871,25 @@ Status Redis::ZScan(const Slice& key, int64_t cursor, const std::string& pattern return Status::OK(); } -Status Redis::ZsetsPersist(const Slice& key) { - std::string meta_value; +Status Redis::ZsetsPersist(const Slice& key, std::string&& prefetch_meta) { + std::string meta_value(std::move(prefetch_meta)); BaseMetaKey base_meta_key(key); ScopeRecordLock l(lock_mgr_, key); + Status s; - Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); - if (s.ok() && !ExpectedMetaValue(DataType::kZSets, meta_value)) { - if (ExpectedStale(meta_value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + // meta_value is empty means no meta value get before, + // we should get meta first + if (meta_value.empty()) { + s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); + if (s.ok() && !ExpectedMetaValue(DataType::kZSets, meta_value)) { + if (ExpectedStale(meta_value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + } } } if (s.ok()) { @@ -1799,16 +1911,24 @@ Status Redis::ZsetsPersist(const Slice& key) { return s; } -Status Redis::ZsetsTTL(const Slice& key, int64_t* timestamp) { - std::string meta_value; - +Status Redis::ZsetsTTL(const Slice& key, int64_t* timestamp, std::string&& prefetch_meta) { + std::string meta_value(std::move(prefetch_meta)); BaseMetaKey base_meta_key(key); - Status s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); - if (s.ok() && !ExpectedMetaValue(DataType::kZSets, meta_value)) { - if (ExpectedStale(meta_value)) { - s = Status::NotFound(); - } else { - return Status::InvalidArgument("WRONGTYPE, key: " + key.ToString() + ", expect type: " + DataTypeStrings[static_cast(DataType::kZSets)] + "get type: " + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + Status s; + + // meta_value is empty means no meta value get before, + // we should get meta first + if (meta_value.empty()) { + s = db_->Get(default_read_options_, handles_[kMetaCF], base_meta_key.Encode(), &meta_value); + if (s.ok() && !ExpectedMetaValue(DataType::kZSets, meta_value)) { + if (ExpectedStale(meta_value)) { + s = Status::NotFound(); + } else { + return Status::InvalidArgument( + "WRONGTYPE, key: " + key.ToString() + ", expected type: " + + DataTypeStrings[static_cast(DataType::kZSets)] + ", got type: " + + DataTypeStrings[static_cast(GetMetaValueType(meta_value))]); + } } } if (s.ok()) { diff --git a/src/storage/src/storage.cc b/src/storage/src/storage.cc index 53454cec53..a264783927 100644 --- a/src/storage/src/storage.cc +++ b/src/storage/src/storage.cc @@ -238,9 +238,8 @@ Status Storage::MSetnx(const std::vector& kvs, int32_t* ret) { Status s; for (const auto& kv : kvs) { auto& inst = GetDBInstance(kv.key); - std::string value; - s = inst->Get(Slice(kv.key), &value); - if (s.ok() || !s.IsNotFound()) { + s = inst->IsExist(Slice(kv.key)); + if (!s.IsNotFound()) { return s; } } @@ -1402,11 +1401,14 @@ Status Storage::PKRScanRange(const DataType& data_type, const Slice& key_start, Status Storage::PKPatternMatchDel(const DataType& data_type, const std::string& pattern, int32_t* ret) { Status s; + *ret = 0; for (const auto& inst : insts_) { - s = inst->PKPatternMatchDel(pattern, ret); + int32_t tmp_ret = 0; + s = inst->PKPatternMatchDel(pattern, &tmp_ret); if (!s.ok()) { return s; } + *ret += tmp_ret; } return s; } @@ -1553,7 +1555,7 @@ Status Storage::PfAdd(const Slice& key, const std::vector& values, std::string registers; std::string result; auto& inst = GetDBInstance(key); - Status s = inst->Get(key, &value); + Status s = inst->HyperloglogGet(key, &value); if (s.ok()) { registers = value; } else if (s.IsNotFound()) { @@ -1571,7 +1573,7 @@ Status Storage::PfAdd(const Slice& key, const std::vector& values, if (previous != now || (s.IsNotFound() && values.empty())) { *update = true; } - s = inst->Set(key, result); + s = inst->HyperloglogSet(key, result); return s; } @@ -1583,19 +1585,20 @@ Status Storage::PfCount(const std::vector& keys, int64_t* result) { std::string value; std::string first_registers; auto& inst = GetDBInstance(keys[0]); - Status s = inst->Get(keys[0], &value); + Status s = inst->HyperloglogGet(keys[0], &value); if (s.ok()) { first_registers = std::string(value.data(), value.size()); } else if (s.IsNotFound()) { first_registers = ""; + } else { + return s; } - HyperLogLog first_log(kPrecision, first_registers); for (size_t i = 1; i < keys.size(); ++i) { std::string value; std::string registers; auto& inst = GetDBInstance(keys[i]); - s = inst->Get(keys[i], &value); + s = inst->HyperloglogGet(keys[i], &value); if (s.ok()) { registers = value; } else if (s.IsNotFound()) { @@ -1620,7 +1623,7 @@ Status Storage::PfMerge(const std::vector& keys, std::string& value std::string first_registers; std::string result; auto& inst = GetDBInstance(keys[0]); - s = inst->Get(keys[0], &value); + s = inst->HyperloglogGet(keys[0], &value); if (s.ok()) { first_registers = std::string(value.data(), value.size()); } else if (s.IsNotFound()) { @@ -1633,7 +1636,7 @@ Status Storage::PfMerge(const std::vector& keys, std::string& value std::string value; std::string registers; auto& tmp_inst = GetDBInstance(keys[i]); - s = tmp_inst->Get(keys[i], &value); + s = tmp_inst->HyperloglogGet(keys[i], &value); if (s.ok()) { registers = std::string(value.data(), value.size()); } else if (s.IsNotFound()) { @@ -1645,7 +1648,7 @@ Status Storage::PfMerge(const std::vector& keys, std::string& value result = first_log.Merge(log); } auto& ninst = GetDBInstance(keys[0]); - s = ninst->Set(keys[0], result); + s = ninst->HyperloglogSet(keys[0], result); value_to_dest = std::move(result); return s; } diff --git a/src/storage/src/strings_value_format.h b/src/storage/src/strings_value_format.h index 96b9d4d279..6e001d7475 100644 --- a/src/storage/src/strings_value_format.h +++ b/src/storage/src/strings_value_format.h @@ -11,11 +11,15 @@ #include "src/base_value_format.h" #include "storage/storage_define.h" + namespace storage { /* * | type | value | reserve | cdate | timestamp | * | 1B | | 16B | 8B | 8B | +* The first bit in reservse field is used to isolate string and hyperloglog */ + // 80H = 1000000B +constexpr uint8_t hyperloglog_reserve_flag = 0x80; class StringsValue : public InternalValue { public: explicit StringsValue(const rocksdb::Slice& user_value) : InternalValue(DataType::kStrings, user_value) {} @@ -38,6 +42,29 @@ class StringsValue : public InternalValue { } }; +class HyperloglogValue : public InternalValue { + public: + explicit HyperloglogValue(const rocksdb::Slice& user_value) : InternalValue(DataType::kStrings, user_value) {} + virtual rocksdb::Slice Encode() override { + size_t usize = user_value_.size(); + size_t needed = usize + kSuffixReserveLength + 2 * kTimestampLength + kTypeLength; + char* dst = ReAllocIfNeeded(needed); + memcpy(dst, &type_, sizeof(type_)); + dst += sizeof(type_); + char* start_pos = dst; + + memcpy(dst, user_value_.data(), usize); + dst += usize; + reserve_[0] |= hyperloglog_reserve_flag; + memcpy(dst, reserve_, kSuffixReserveLength); + dst += kSuffixReserveLength; + EncodeFixed64(dst, ctime_); + dst += kTimestampLength; + EncodeFixed64(dst, etime_); + return {start_, needed}; + } +}; + class ParsedStringsValue : public ParsedInternalValue { public: // Use this constructor after rocksdb::DB::Get(); diff --git a/src/storage/tests/keys_test.cc b/src/storage/tests/keys_test.cc index e7872c713b..4609da95f2 100644 --- a/src/storage/tests/keys_test.cc +++ b/src/storage/tests/keys_test.cc @@ -2095,517 +2095,517 @@ for (const auto& kv : kvs) { db.Compact(DataType::kAll, true); } -// TEST_F(KeysTest, PKPatternMatchDel) { -// int32_t ret; -// uint64_t ret64; -// int32_t delete_count; -// std::vector keys; -// std::map type_status; - -// //=============================== Strings =============================== - -// // ***************** Group 1 Test ***************** -// db.Set("GP1_PKPATTERNMATCHDEL_STRING_KEY1", "VALUE"); -// db.Set("GP1_PKPATTERNMATCHDEL_STRING_KEY2", "VALUE"); -// db.Set("GP1_PKPATTERNMATCHDEL_STRING_KEY3", "VALUE"); -// 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); -// ASSERT_TRUE(s.ok()); -// ASSERT_EQ(delete_count, 6); -// keys.clear(); -// db.Keys(DataType::kStrings, "*", &keys); -// ASSERT_EQ(keys.size(), 0); - -// // ***************** Group 2 Test ***************** -// db.Set("GP2_PKPATTERNMATCHDEL_STRING_KEY1", "VALUE"); -// db.Set("GP2_PKPATTERNMATCHDEL_STRING_KEY2", "VALUE"); -// db.Set("GP2_PKPATTERNMATCHDEL_STRING_KEY3", "VALUE"); -// db.Set("GP2_PKPATTERNMATCHDEL_STRING_KEY4", "VALUE"); -// db.Set("GP2_PKPATTERNMATCHDEL_STRING_KEY5", "VALUE"); -// db.Set("GP2_PKPATTERNMATCHDEL_STRING_KEY6", "VALUE"); -// 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); -// ASSERT_TRUE(s.ok()); -// ASSERT_EQ(delete_count, 3); -// keys.clear(); -// db.Keys(DataType::kStrings, "*", &keys); -// ASSERT_EQ(keys.size(), 0); - -// // ***************** Group 3 Test ***************** -// db.Set("GP3_PKPATTERNMATCHDEL_STRING_KEY1_0xxx0", "VALUE"); -// db.Set("GP3_PKPATTERNMATCHDEL_STRING_KEY2_0ooo0", "VALUE"); -// db.Set("GP3_PKPATTERNMATCHDEL_STRING_KEY3_0xxx0", "VALUE"); -// 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); -// ASSERT_TRUE(s.ok()); -// ASSERT_EQ(delete_count, 3); -// keys.clear(); -// db.Keys(DataType::kStrings, "*", &keys); -// ASSERT_EQ(keys.size(), 3); -// ASSERT_EQ(keys[0], "GP3_PKPATTERNMATCHDEL_STRING_KEY2_0ooo0"); -// ASSERT_EQ(keys[1], "GP3_PKPATTERNMATCHDEL_STRING_KEY4_0ooo0"); -// ASSERT_EQ(keys[2], "GP3_PKPATTERNMATCHDEL_STRING_KEY6_0ooo0"); -// type_status.clear(); -// db.Del(keys); - -// // ***************** Group 4 Test ***************** -// db.Set("GP4_PKPATTERNMATCHDEL_STRING_KEY1", "VALUE"); -// db.Set("GP4_PKPATTERNMATCHDEL_STRING_KEY2_0ooo0", "VALUE"); -// db.Set("GP4_PKPATTERNMATCHDEL_STRING_KEY3", "VALUE"); -// db.Set("GP4_PKPATTERNMATCHDEL_STRING_KEY4_0ooo0", "VALUE"); -// db.Set("GP4_PKPATTERNMATCHDEL_STRING_KEY5", "VALUE"); -// db.Set("GP4_PKPATTERNMATCHDEL_STRING_KEY6_0ooo0", "VALUE"); -// 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); -// ASSERT_TRUE(s.ok()); -// ASSERT_EQ(delete_count, 3); -// keys.clear(); -// db.Keys(DataType::kStrings, "*", &keys); -// ASSERT_EQ(keys.size(), 0); - -// // ***************** Group 5 Test ***************** -// size_t gp5_total_kv = 23333; -// 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); -// ASSERT_TRUE(s.ok()); -// ASSERT_EQ(delete_count, gp5_total_kv); -// keys.clear(); -// db.Keys(DataType::kStrings, "*", &keys); -// ASSERT_EQ(keys.size(), 0); - -// //=============================== Set =============================== - -// // ***************** Group 1 Test ***************** -// db.SAdd("GP1_PKPATTERNMATCHDEL_SET_KEY1", {"M1"}, &ret); -// db.SAdd("GP1_PKPATTERNMATCHDEL_SET_KEY2", {"M1"}, &ret); -// db.SAdd("GP1_PKPATTERNMATCHDEL_SET_KEY3", {"M1"}, &ret); -// 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); -// ASSERT_TRUE(s.ok()); -// ASSERT_EQ(delete_count, 6); -// keys.clear(); -// db.Keys(DataType::kSets, "*", &keys); -// ASSERT_EQ(keys.size(), 0); - -// // ***************** Group 2 Test ***************** -// db.SAdd("GP2_PKPATTERNMATCHDEL_SET_KEY1", {"M1"}, &ret); -// db.SAdd("GP2_PKPATTERNMATCHDEL_SET_KEY2", {"M1"}, &ret); -// db.SAdd("GP2_PKPATTERNMATCHDEL_SET_KEY3", {"M1"}, &ret); -// db.SAdd("GP2_PKPATTERNMATCHDEL_SET_KEY4", {"M1"}, &ret); -// db.SAdd("GP2_PKPATTERNMATCHDEL_SET_KEY5", {"M1"}, &ret); -// db.SAdd("GP2_PKPATTERNMATCHDEL_SET_KEY6", {"M1"}, &ret); -// 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); -// ASSERT_TRUE(s.ok()); -// ASSERT_EQ(delete_count, 3); -// keys.clear(); -// db.Keys(DataType::kSets, "*", &keys); -// ASSERT_EQ(keys.size(), 0); - -// // ***************** Group 3 Test ***************** -// db.SAdd("GP3_PKPATTERNMATCHDEL_SET_KEY1_0xxx0", {"M1"}, &ret); -// db.SAdd("GP3_PKPATTERNMATCHDEL_SET_KEY2_0ooo0", {"M1"}, &ret); -// db.SAdd("GP3_PKPATTERNMATCHDEL_SET_KEY3_0xxx0", {"M1"}, &ret); -// 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); -// ASSERT_TRUE(s.ok()); -// ASSERT_EQ(delete_count, 3); -// keys.clear(); -// db.Keys(DataType::kSets, "*", &keys); -// ASSERT_EQ(keys.size(), 3); -// ASSERT_EQ("GP3_PKPATTERNMATCHDEL_SET_KEY1_0xxx0", keys[0]); -// ASSERT_EQ("GP3_PKPATTERNMATCHDEL_SET_KEY3_0xxx0", keys[1]); -// ASSERT_EQ("GP3_PKPATTERNMATCHDEL_SET_KEY5_0xxx0", keys[2]); -// type_status.clear(); -// db.Del(keys); - -// // ***************** Group 4 Test ***************** -// db.SAdd("GP4_PKPATTERNMATCHDEL_SET_KEY1", {"M1"}, &ret); -// db.SAdd("GP4_PKPATTERNMATCHDEL_SET_KEY2", {"M1"}, &ret); -// db.SAdd("GP4_PKPATTERNMATCHDEL_SET_KEY3", {"M1"}, &ret); -// db.SAdd("GP4_PKPATTERNMATCHDEL_SET_KEY4", {"M1"}, &ret); -// db.SAdd("GP4_PKPATTERNMATCHDEL_SET_KEY5", {"M1"}, &ret); -// db.SAdd("GP4_PKPATTERNMATCHDEL_SET_KEY6", {"M1"}, &ret); -// 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); -// ASSERT_TRUE(s.ok()); -// ASSERT_EQ(delete_count, 3); -// keys.clear(); -// db.Keys(DataType::kSets, "*", &keys); -// ASSERT_EQ(keys.size(), 0); - -// // ***************** Group 5 Test ***************** -// db.SAdd("GP5_PKPATTERNMATCHDEL_SET_KEY1_0ooo0", {"M1"}, &ret); -// db.SAdd("GP5_PKPATTERNMATCHDEL_SET_KEY2_0xxx0", {"M1"}, &ret); -// db.SAdd("GP5_PKPATTERNMATCHDEL_SET_KEY3_0ooo0", {"M1"}, &ret); -// db.SAdd("GP5_PKPATTERNMATCHDEL_SET_KEY4_0xxx0", {"M1"}, &ret); -// db.SAdd("GP5_PKPATTERNMATCHDEL_SET_KEY5_0ooo0", {"M1"}, &ret); -// db.SAdd("GP5_PKPATTERNMATCHDEL_SET_KEY6_0xxx0", {"M1"}, &ret); -// db.SAdd("GP5_PKPATTERNMATCHDEL_SET_KEY7_0ooo0", {"M1"}, &ret); -// db.SAdd("GP5_PKPATTERNMATCHDEL_SET_KEY8_0xxx0", {"M1"}, &ret); -// ASSERT_TRUE(make_expired(&db, "GP5_PKPATTERNMATCHDEL_SET_KEY1_0ooo0")); -// 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); -// ASSERT_TRUE(s.ok()); -// ASSERT_EQ(delete_count, 2); -// keys.clear(); -// db.Keys(DataType::kSets, "*", &keys); -// ASSERT_EQ(keys.size(), 2); -// ASSERT_EQ(keys[0], "GP5_PKPATTERNMATCHDEL_SET_KEY6_0xxx0"); -// ASSERT_EQ(keys[1], "GP5_PKPATTERNMATCHDEL_SET_KEY8_0xxx0"); -// type_status.clear(); -// db.Del(keys); - -// // ***************** Group 6 Test ***************** -// size_t gp6_total_set = 23333; -// 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); -// ASSERT_TRUE(s.ok()); -// ASSERT_EQ(delete_count, gp6_total_set); -// keys.clear(); -// db.Keys(DataType::kSets, "*", &keys); -// ASSERT_EQ(keys.size(), 0); - -// //=============================== Hashes =============================== - -// // ***************** Group 1 Test ***************** -// db.HSet("GP1_PKPATTERNMATCHDEL_HASH_KEY1", "FIELD", "VALUE", &ret); -// db.HSet("GP1_PKPATTERNMATCHDEL_HASH_KEY2", "FIELD", "VALUE", &ret); -// db.HSet("GP1_PKPATTERNMATCHDEL_HASH_KEY3", "FIELD", "VALUE", &ret); -// 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); -// ASSERT_TRUE(s.ok()); -// ASSERT_EQ(delete_count, 6); -// keys.clear(); -// db.Keys(DataType::kHashes, "*", &keys); -// ASSERT_EQ(keys.size(), 0); - -// // ***************** Group 2 Test ***************** -// db.HSet("GP2_PKPATTERNMATCHDEL_HASH_KEY1", "FIELD", "VALUE", &ret); -// db.HSet("GP2_PKPATTERNMATCHDEL_HASH_KEY2", "FIELD", "VALUE", &ret); -// db.HSet("GP2_PKPATTERNMATCHDEL_HASH_KEY3", "FIELD", "VALUE", &ret); -// db.HSet("GP2_PKPATTERNMATCHDEL_HASH_KEY4", "FIELD", "VALUE", &ret); -// db.HSet("GP2_PKPATTERNMATCHDEL_HASH_KEY5", "FIELD", "VALUE", &ret); -// db.HSet("GP2_PKPATTERNMATCHDEL_HASH_KEY6", "FIELD", "VALUE", &ret); -// 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); -// ASSERT_TRUE(s.ok()); -// ASSERT_EQ(delete_count, 3); -// keys.clear(); -// db.Keys(DataType::kHashes, "*", &keys); -// ASSERT_EQ(keys.size(), 0); - -// // ***************** Group 3 Test ***************** -// db.HSet("GP3_PKPATTERNMATCHDEL_HASH_KEY1_0xxx0", "FIELD", "VALUE", &ret); -// db.HSet("GP3_PKPATTERNMATCHDEL_HASH_KEY2_0ooo0", "FIELD", "VALUE", &ret); -// db.HSet("GP3_PKPATTERNMATCHDEL_HASH_KEY3_0xxx0", "FIELD", "VALUE", &ret); -// 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); -// ASSERT_TRUE(s.ok()); -// ASSERT_EQ(delete_count, 3); -// keys.clear(); -// db.Keys(DataType::kHashes, "*", &keys); -// ASSERT_EQ(keys.size(), 3); -// ASSERT_EQ("GP3_PKPATTERNMATCHDEL_HASH_KEY1_0xxx0", keys[0]); -// ASSERT_EQ("GP3_PKPATTERNMATCHDEL_HASH_KEY3_0xxx0", keys[1]); -// ASSERT_EQ("GP3_PKPATTERNMATCHDEL_HASH_KEY5_0xxx0", keys[2]); -// type_status.clear(); -// db.Del(keys); - -// // ***************** Group 4 Test ***************** -// db.HSet("GP4_PKPATTERNMATCHDEL_HASH_KEY1", "FIELD", "VALUE", &ret); -// db.HSet("GP4_PKPATTERNMATCHDEL_HASH_KEY2", "FIELD", "VALUE", &ret); -// db.HSet("GP4_PKPATTERNMATCHDEL_HASH_KEY3", "FIELD", "VALUE", &ret); -// db.HSet("GP4_PKPATTERNMATCHDEL_HASH_KEY4", "FIELD", "VALUE", &ret); -// db.HSet("GP4_PKPATTERNMATCHDEL_HASH_KEY5", "FIELD", "VALUE", &ret); -// db.HSet("GP4_PKPATTERNMATCHDEL_HASH_KEY6", "FIELD", "VALUE", &ret); -// 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); -// ASSERT_TRUE(s.ok()); -// ASSERT_EQ(delete_count, 3); -// keys.clear(); -// db.Keys(DataType::kHashes, "*", &keys); -// ASSERT_EQ(keys.size(), 0); - -// // ***************** Group 5 Test ***************** -// db.HSet("GP5_PKPATTERNMATCHDEL_HASH_KEY1_0ooo0", "FIELD", "VALUE", &ret); -// db.HSet("GP5_PKPATTERNMATCHDEL_HASH_KEY2_0xxx0", "FIELD", "VALUE", &ret); -// db.HSet("GP5_PKPATTERNMATCHDEL_HASH_KEY3_0ooo0", "FIELD", "VALUE", &ret); -// db.HSet("GP5_PKPATTERNMATCHDEL_HASH_KEY4_0xxx0", "FIELD", "VALUE", &ret); -// db.HSet("GP5_PKPATTERNMATCHDEL_HASH_KEY5_0ooo0", "FIELD", "VALUE", &ret); -// db.HSet("GP5_PKPATTERNMATCHDEL_HASH_KEY6_0xxx0", "FIELD", "VALUE", &ret); -// db.HSet("GP5_PKPATTERNMATCHDEL_HASH_KEY7_0ooo0", "FIELD", "VALUE", &ret); -// db.HSet("GP5_PKPATTERNMATCHDEL_HASH_KEY8_0xxx0", "FIELD", "VALUE", &ret); -// ASSERT_TRUE(make_expired(&db, "GP5_PKPATTERNMATCHDEL_HASH_KEY1_0ooo0")); -// 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); -// ASSERT_TRUE(s.ok()); -// ASSERT_EQ(delete_count, 2); -// keys.clear(); -// db.Keys(DataType::kHashes, "*", &keys); -// ASSERT_EQ(keys.size(), 2); -// ASSERT_EQ(keys[0], "GP5_PKPATTERNMATCHDEL_HASH_KEY6_0xxx0"); -// ASSERT_EQ(keys[1], "GP5_PKPATTERNMATCHDEL_HASH_KEY8_0xxx0"); -// type_status.clear(); -// db.Del(keys); - -// // ***************** Group 6 Test ***************** -// size_t gp6_total_hash = 23333; -// 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); -// ASSERT_TRUE(s.ok()); -// ASSERT_EQ(delete_count, gp6_total_hash); -// keys.clear(); -// db.Keys(DataType::kHashes, "*", &keys); -// ASSERT_EQ(keys.size(), 0); - -// //=============================== ZSets =============================== - -// // ***************** Group 1 Test ***************** -// db.ZAdd("GP1_PKPATTERNMATCHDEL_ZSET_KEY1", {{1, "M"}}, &ret); -// db.ZAdd("GP1_PKPATTERNMATCHDEL_ZSET_KEY2", {{1, "M"}}, &ret); -// db.ZAdd("GP1_PKPATTERNMATCHDEL_ZSET_KEY3", {{1, "M"}}, &ret); -// 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); -// ASSERT_TRUE(s.ok()); -// ASSERT_EQ(delete_count, 6); -// keys.clear(); -// db.Keys(DataType::kZSets, "*", &keys); -// ASSERT_EQ(keys.size(), 0); - -// // ***************** Group 2 Test ***************** -// db.ZAdd("GP2_PKPATTERNMATCHDEL_ZSET_KEY1", {{1, "M"}}, &ret); -// db.ZAdd("GP2_PKPATTERNMATCHDEL_ZSET_KEY2", {{1, "M"}}, &ret); -// db.ZAdd("GP2_PKPATTERNMATCHDEL_ZSET_KEY3", {{1, "M"}}, &ret); -// db.ZAdd("GP2_PKPATTERNMATCHDEL_ZSET_KEY4", {{1, "M"}}, &ret); -// db.ZAdd("GP2_PKPATTERNMATCHDEL_ZSET_KEY5", {{1, "M"}}, &ret); -// db.ZAdd("GP2_PKPATTERNMATCHDEL_ZSET_KEY6", {{1, "M"}}, &ret); -// 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); -// ASSERT_TRUE(s.ok()); -// ASSERT_EQ(delete_count, 3); -// keys.clear(); -// db.Keys(DataType::kZSets, "*", &keys); -// ASSERT_EQ(keys.size(), 0); - -// // ***************** Group 3 Test ***************** -// db.ZAdd("GP3_PKPATTERNMATCHDEL_ZSET_KEY1_0xxx0", {{1, "M"}}, &ret); -// db.ZAdd("GP3_PKPATTERNMATCHDEL_ZSET_KEY2_0ooo0", {{1, "M"}}, &ret); -// db.ZAdd("GP3_PKPATTERNMATCHDEL_ZSET_KEY3_0xxx0", {{1, "M"}}, &ret); -// 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); -// ASSERT_TRUE(s.ok()); -// ASSERT_EQ(delete_count, 3); -// keys.clear(); -// db.Keys(DataType::kZSets, "*", &keys); -// ASSERT_EQ(keys.size(), 3); -// ASSERT_EQ("GP3_PKPATTERNMATCHDEL_ZSET_KEY1_0xxx0", keys[0]); -// ASSERT_EQ("GP3_PKPATTERNMATCHDEL_ZSET_KEY3_0xxx0", keys[1]); -// ASSERT_EQ("GP3_PKPATTERNMATCHDEL_ZSET_KEY5_0xxx0", keys[2]); -// type_status.clear(); -// db.Del(keys); - -// // ***************** Group 4 Test ***************** -// db.ZAdd("GP4_PKPATTERNMATCHDEL_ZSET_KEY1", {{1, "M"}}, &ret); -// db.ZAdd("GP4_PKPATTERNMATCHDEL_ZSET_KEY2", {{1, "M"}}, &ret); -// db.ZAdd("GP4_PKPATTERNMATCHDEL_ZSET_KEY3", {{1, "M"}}, &ret); -// db.ZAdd("GP4_PKPATTERNMATCHDEL_ZSET_KEY4", {{1, "M"}}, &ret); -// db.ZAdd("GP4_PKPATTERNMATCHDEL_ZSET_KEY5", {{1, "M"}}, &ret); -// db.ZAdd("GP4_PKPATTERNMATCHDEL_ZSET_KEY6", {{1, "M"}}, &ret); -// 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); -// ASSERT_TRUE(s.ok()); -// ASSERT_EQ(delete_count, 3); -// keys.clear(); -// db.Keys(DataType::kZSets, "*", &keys); -// ASSERT_EQ(keys.size(), 0); - -// // ***************** Group 5 Test ***************** -// db.ZAdd("GP5_PKPATTERNMATCHDEL_ZSET_KEY1_0ooo0", {{1, "M"}}, &ret); -// db.ZAdd("GP5_PKPATTERNMATCHDEL_ZSET_KEY2_0xxx0", {{1, "M"}}, &ret); -// db.ZAdd("GP5_PKPATTERNMATCHDEL_ZSET_KEY3_0ooo0", {{1, "M"}}, &ret); -// db.ZAdd("GP5_PKPATTERNMATCHDEL_ZSET_KEY4_0xxx0", {{1, "M"}}, &ret); -// db.ZAdd("GP5_PKPATTERNMATCHDEL_ZSET_KEY5_0ooo0", {{1, "M"}}, &ret); -// db.ZAdd("GP5_PKPATTERNMATCHDEL_ZSET_KEY6_0xxx0", {{1, "M"}}, &ret); -// db.ZAdd("GP5_PKPATTERNMATCHDEL_ZSET_KEY7_0ooo0", {{1, "M"}}, &ret); -// db.ZAdd("GP5_PKPATTERNMATCHDEL_ZSET_KEY8_0xxx0", {{1, "M"}}, &ret); -// ASSERT_TRUE(make_expired(&db, "GP5_PKPATTERNMATCHDEL_ZSET_KEY1_0ooo0")); -// 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); -// ASSERT_TRUE(s.ok()); -// ASSERT_EQ(delete_count, 2); -// keys.clear(); -// db.Keys(DataType::kZSets, "*", &keys); -// ASSERT_EQ(keys.size(), 2); -// ASSERT_EQ(keys[0], "GP5_PKPATTERNMATCHDEL_ZSET_KEY6_0xxx0"); -// ASSERT_EQ(keys[1], "GP5_PKPATTERNMATCHDEL_ZSET_KEY8_0xxx0"); -// type_status.clear(); -// db.Del(keys); - -// // ***************** Group 6 Test ***************** -// size_t gp6_total_zset = 23333; -// 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); -// ASSERT_TRUE(s.ok()); -// ASSERT_EQ(delete_count, gp6_total_zset); -// keys.clear(); -// db.Keys(DataType::kZSets, "*", &keys); -// ASSERT_EQ(keys.size(), 0); - -// //=============================== List =============================== - -// // ***************** Group 1 Test ***************** -// db.LPush("GP1_PKPATTERNMATCHDEL_LIST_KEY1", {"VALUE"}, &ret64); -// db.LPush("GP1_PKPATTERNMATCHDEL_LIST_KEY2", {"VALUE"}, &ret64); -// db.LPush("GP1_PKPATTERNMATCHDEL_LIST_KEY3", {"VALUE"}, &ret64); -// 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); -// ASSERT_TRUE(s.ok()); -// ASSERT_EQ(delete_count, 6); -// keys.clear(); -// db.Keys(DataType::kLists, "*", &keys); -// ASSERT_EQ(keys.size(), 0); - -// // ***************** Group 2 Test ***************** -// db.LPush("GP2_PKPATTERNMATCHDEL_LIST_KEY1", {"VALUE"}, &ret64); -// db.LPush("GP2_PKPATTERNMATCHDEL_LIST_KEY2", {"VALUE"}, &ret64); -// db.LPush("GP2_PKPATTERNMATCHDEL_LIST_KEY3", {"VALUE"}, &ret64); -// db.LPush("GP2_PKPATTERNMATCHDEL_LIST_KEY4", {"VALUE"}, &ret64); -// db.LPush("GP2_PKPATTERNMATCHDEL_LIST_KEY5", {"VALUE"}, &ret64); -// db.LPush("GP2_PKPATTERNMATCHDEL_LIST_KEY6", {"VALUE"}, &ret64); -// 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); -// ASSERT_TRUE(s.ok()); -// ASSERT_EQ(delete_count, 3); -// keys.clear(); -// db.Keys(DataType::kLists, "*", &keys); -// ASSERT_EQ(keys.size(), 0); - -// // ***************** Group 3 Test ***************** -// db.LPush("GP3_PKPATTERNMATCHDEL_LIST_KEY1_0xxx0", {"VALUE"}, &ret64); -// db.LPush("GP3_PKPATTERNMATCHDEL_LIST_KEY2_0ooo0", {"VALUE"}, &ret64); -// db.LPush("GP3_PKPATTERNMATCHDEL_LIST_KEY3_0xxx0", {"VALUE"}, &ret64); -// 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); -// ASSERT_TRUE(s.ok()); -// ASSERT_EQ(delete_count, 3); -// keys.clear(); -// db.Keys(DataType::kLists, "*", &keys); -// ASSERT_EQ(keys.size(), 3); -// ASSERT_EQ("GP3_PKPATTERNMATCHDEL_LIST_KEY1_0xxx0", keys[0]); -// ASSERT_EQ("GP3_PKPATTERNMATCHDEL_LIST_KEY3_0xxx0", keys[1]); -// ASSERT_EQ("GP3_PKPATTERNMATCHDEL_LIST_KEY5_0xxx0", keys[2]); -// type_status.clear(); -// db.Del(keys); - -// // ***************** Group 4 Test ***************** -// db.LPush("GP4_PKPATTERNMATCHDEL_LIST_KEY1", {"VALUE"}, &ret64); -// db.LPush("GP4_PKPATTERNMATCHDEL_LIST_KEY2", {"VALUE"}, &ret64); -// db.LPush("GP4_PKPATTERNMATCHDEL_LIST_KEY3", {"VALUE"}, &ret64); -// db.LPush("GP4_PKPATTERNMATCHDEL_LIST_KEY4", {"VALUE"}, &ret64); -// db.LPush("GP4_PKPATTERNMATCHDEL_LIST_KEY5", {"VALUE"}, &ret64); -// db.LPush("GP4_PKPATTERNMATCHDEL_LIST_KEY6", {"VALUE"}, &ret64); -// 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); -// ASSERT_TRUE(s.ok()); -// ASSERT_EQ(delete_count, 3); -// keys.clear(); -// db.Keys(DataType::kLists, "*", &keys); -// ASSERT_EQ(keys.size(), 0); - -// // ***************** Group 5 Test ***************** -// db.LPush("GP5_PKPATTERNMATCHDEL_LIST_KEY1_0ooo0", {"VALUE"}, &ret64); -// db.LPush("GP5_PKPATTERNMATCHDEL_LIST_KEY2_0xxx0", {"VALUE"}, &ret64); -// db.LPush("GP5_PKPATTERNMATCHDEL_LIST_KEY3_0ooo0", {"VALUE"}, &ret64); -// db.LPush("GP5_PKPATTERNMATCHDEL_LIST_KEY4_0xxx0", {"VALUE"}, &ret64); -// db.LPush("GP5_PKPATTERNMATCHDEL_LIST_KEY5_0ooo0", {"VALUE"}, &ret64); -// db.LPush("GP5_PKPATTERNMATCHDEL_LIST_KEY6_0xxx0", {"VALUE"}, &ret64); -// db.LPush("GP5_PKPATTERNMATCHDEL_LIST_KEY7_0ooo0", {"VALUE"}, &ret64); -// db.LPush("GP5_PKPATTERNMATCHDEL_LIST_KEY8_0xxx0", {"VALUE"}, &ret64); -// ASSERT_TRUE(make_expired(&db, "GP5_PKPATTERNMATCHDEL_LIST_KEY1_0ooo0")); -// 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); -// ASSERT_TRUE(s.ok()); -// ASSERT_EQ(delete_count, 2); -// keys.clear(); -// db.Keys(DataType::kLists, "*", &keys); -// ASSERT_EQ(keys.size(), 2); -// ASSERT_EQ(keys[0], "GP5_PKPATTERNMATCHDEL_LIST_KEY6_0xxx0"); -// ASSERT_EQ(keys[1], "GP5_PKPATTERNMATCHDEL_LIST_KEY8_0xxx0"); -// type_status.clear(); -// db.Del(keys); - -// // ***************** Group 6 Test ***************** -// size_t gp6_total_list = 23333; -// 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); -// ASSERT_TRUE(s.ok()); -// ASSERT_EQ(delete_count, gp6_total_hash); -// keys.clear(); -// db.Keys(DataType::kLists, "*", &keys); -// ASSERT_EQ(keys.size(), 0); - -// sleep(2); -// db.Compact(DataType::kAll, true); -// } +TEST_F(KeysTest, PKPatternMatchDel) { + int32_t ret; + uint64_t ret64; + int32_t delete_count = 0; + std::vector keys; + std::map type_status; + + //=============================== Strings =============================== + + // ***************** Group 1 Test ***************** + db.Set("GP1_PKPATTERNMATCHDEL_STRING_KEY1", "VALUE"); + db.Set("GP1_PKPATTERNMATCHDEL_STRING_KEY2", "VALUE"); + db.Set("GP1_PKPATTERNMATCHDEL_STRING_KEY3", "VALUE"); + 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); + ASSERT_TRUE(s.ok()); + ASSERT_EQ(delete_count, 6); + keys.clear(); + db.Keys(DataType::kStrings, "*", &keys); + ASSERT_EQ(keys.size(), 0); + + // ***************** Group 2 Test ***************** + db.Set("GP2_PKPATTERNMATCHDEL_STRING_KEY1", "VALUE"); + db.Set("GP2_PKPATTERNMATCHDEL_STRING_KEY2", "VALUE"); + db.Set("GP2_PKPATTERNMATCHDEL_STRING_KEY3", "VALUE"); + db.Set("GP2_PKPATTERNMATCHDEL_STRING_KEY4", "VALUE"); + db.Set("GP2_PKPATTERNMATCHDEL_STRING_KEY5", "VALUE"); + db.Set("GP2_PKPATTERNMATCHDEL_STRING_KEY6", "VALUE"); + 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); + ASSERT_TRUE(s.ok()); + ASSERT_EQ(delete_count, 3); + keys.clear(); + db.Keys(DataType::kStrings, "*", &keys); + ASSERT_EQ(keys.size(), 0); + + // ***************** Group 3 Test ***************** + db.Set("GP3_PKPATTERNMATCHDEL_STRING_KEY1_0xxx0", "VALUE"); + db.Set("GP3_PKPATTERNMATCHDEL_STRING_KEY2_0ooo0", "VALUE"); + db.Set("GP3_PKPATTERNMATCHDEL_STRING_KEY3_0xxx0", "VALUE"); + 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); + ASSERT_TRUE(s.ok()); + ASSERT_EQ(delete_count, 3); + keys.clear(); + db.Keys(DataType::kStrings, "*", &keys); + ASSERT_EQ(keys.size(), 3); + ASSERT_EQ(keys[0], "GP3_PKPATTERNMATCHDEL_STRING_KEY2_0ooo0"); + ASSERT_EQ(keys[1], "GP3_PKPATTERNMATCHDEL_STRING_KEY4_0ooo0"); + ASSERT_EQ(keys[2], "GP3_PKPATTERNMATCHDEL_STRING_KEY6_0ooo0"); + type_status.clear(); + db.Del(keys); + + // ***************** Group 4 Test ***************** + db.Set("GP4_PKPATTERNMATCHDEL_STRING_KEY1", "VALUE"); + db.Set("GP4_PKPATTERNMATCHDEL_STRING_KEY2_0ooo0", "VALUE"); + db.Set("GP4_PKPATTERNMATCHDEL_STRING_KEY3", "VALUE"); + db.Set("GP4_PKPATTERNMATCHDEL_STRING_KEY4_0ooo0", "VALUE"); + db.Set("GP4_PKPATTERNMATCHDEL_STRING_KEY5", "VALUE"); + db.Set("GP4_PKPATTERNMATCHDEL_STRING_KEY6_0ooo0", "VALUE"); + 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); + ASSERT_TRUE(s.ok()); + ASSERT_EQ(delete_count, 3); + keys.clear(); + db.Keys(DataType::kStrings, "*", &keys); + ASSERT_EQ(keys.size(), 0); + + // ***************** Group 5 Test ***************** + size_t gp5_total_kv = 23333; + 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); + ASSERT_TRUE(s.ok()); + ASSERT_EQ(delete_count, gp5_total_kv); + keys.clear(); + db.Keys(DataType::kStrings, "*", &keys); + ASSERT_EQ(keys.size(), 0); + + //=============================== Set =============================== + + // ***************** Group 1 Test ***************** + db.SAdd("GP1_PKPATTERNMATCHDEL_SET_KEY1", {"M1"}, &ret); + db.SAdd("GP1_PKPATTERNMATCHDEL_SET_KEY2", {"M1"}, &ret); + db.SAdd("GP1_PKPATTERNMATCHDEL_SET_KEY3", {"M1"}, &ret); + 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); + ASSERT_TRUE(s.ok()); + ASSERT_EQ(delete_count, 6); + keys.clear(); + db.Keys(DataType::kSets, "*", &keys); + ASSERT_EQ(keys.size(), 0); + + // ***************** Group 2 Test ***************** + db.SAdd("GP2_PKPATTERNMATCHDEL_SET_KEY1", {"M1"}, &ret); + db.SAdd("GP2_PKPATTERNMATCHDEL_SET_KEY2", {"M1"}, &ret); + db.SAdd("GP2_PKPATTERNMATCHDEL_SET_KEY3", {"M1"}, &ret); + db.SAdd("GP2_PKPATTERNMATCHDEL_SET_KEY4", {"M1"}, &ret); + db.SAdd("GP2_PKPATTERNMATCHDEL_SET_KEY5", {"M1"}, &ret); + db.SAdd("GP2_PKPATTERNMATCHDEL_SET_KEY6", {"M1"}, &ret); + 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); + ASSERT_TRUE(s.ok()); + ASSERT_EQ(delete_count, 3); + keys.clear(); + db.Keys(DataType::kSets, "*", &keys); + ASSERT_EQ(keys.size(), 0); + + // ***************** Group 3 Test ***************** + db.SAdd("GP3_PKPATTERNMATCHDEL_SET_KEY1_0xxx0", {"M1"}, &ret); + db.SAdd("GP3_PKPATTERNMATCHDEL_SET_KEY2_0ooo0", {"M1"}, &ret); + db.SAdd("GP3_PKPATTERNMATCHDEL_SET_KEY3_0xxx0", {"M1"}, &ret); + 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); + ASSERT_TRUE(s.ok()); + ASSERT_EQ(delete_count, 3); + keys.clear(); + db.Keys(DataType::kSets, "*", &keys); + ASSERT_EQ(keys.size(), 3); + ASSERT_EQ("GP3_PKPATTERNMATCHDEL_SET_KEY1_0xxx0", keys[0]); + ASSERT_EQ("GP3_PKPATTERNMATCHDEL_SET_KEY3_0xxx0", keys[1]); + ASSERT_EQ("GP3_PKPATTERNMATCHDEL_SET_KEY5_0xxx0", keys[2]); + type_status.clear(); + db.Del(keys); + + // ***************** Group 4 Test ***************** + db.SAdd("GP4_PKPATTERNMATCHDEL_SET_KEY1", {"M1"}, &ret); + db.SAdd("GP4_PKPATTERNMATCHDEL_SET_KEY2", {"M1"}, &ret); + db.SAdd("GP4_PKPATTERNMATCHDEL_SET_KEY3", {"M1"}, &ret); + db.SAdd("GP4_PKPATTERNMATCHDEL_SET_KEY4", {"M1"}, &ret); + db.SAdd("GP4_PKPATTERNMATCHDEL_SET_KEY5", {"M1"}, &ret); + db.SAdd("GP4_PKPATTERNMATCHDEL_SET_KEY6", {"M1"}, &ret); + 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); + ASSERT_TRUE(s.ok()); + ASSERT_EQ(delete_count, 3); + keys.clear(); + db.Keys(DataType::kSets, "*", &keys); + ASSERT_EQ(keys.size(), 0); + + // ***************** Group 5 Test ***************** + db.SAdd("GP5_PKPATTERNMATCHDEL_SET_KEY1_0ooo0", {"M1"}, &ret); + db.SAdd("GP5_PKPATTERNMATCHDEL_SET_KEY2_0xxx0", {"M1"}, &ret); + db.SAdd("GP5_PKPATTERNMATCHDEL_SET_KEY3_0ooo0", {"M1"}, &ret); + db.SAdd("GP5_PKPATTERNMATCHDEL_SET_KEY4_0xxx0", {"M1"}, &ret); + db.SAdd("GP5_PKPATTERNMATCHDEL_SET_KEY5_0ooo0", {"M1"}, &ret); + db.SAdd("GP5_PKPATTERNMATCHDEL_SET_KEY6_0xxx0", {"M1"}, &ret); + db.SAdd("GP5_PKPATTERNMATCHDEL_SET_KEY7_0ooo0", {"M1"}, &ret); + db.SAdd("GP5_PKPATTERNMATCHDEL_SET_KEY8_0xxx0", {"M1"}, &ret); + ASSERT_TRUE(make_expired(&db, "GP5_PKPATTERNMATCHDEL_SET_KEY1_0ooo0")); + 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); + ASSERT_TRUE(s.ok()); + ASSERT_EQ(delete_count, 2); + keys.clear(); + db.Keys(DataType::kSets, "*", &keys); + ASSERT_EQ(keys.size(), 2); + ASSERT_EQ(keys[0], "GP5_PKPATTERNMATCHDEL_SET_KEY6_0xxx0"); + ASSERT_EQ(keys[1], "GP5_PKPATTERNMATCHDEL_SET_KEY8_0xxx0"); + type_status.clear(); + db.Del(keys); + + // ***************** Group 6 Test ***************** + size_t gp6_total_set = 23333; + 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); + ASSERT_TRUE(s.ok()); + ASSERT_EQ(delete_count, gp6_total_set); + keys.clear(); + db.Keys(DataType::kSets, "*", &keys); + ASSERT_EQ(keys.size(), 0); + + //=============================== Hashes =============================== + + // ***************** Group 1 Test ***************** + db.HSet("GP1_PKPATTERNMATCHDEL_HASH_KEY1", "FIELD", "VALUE", &ret); + db.HSet("GP1_PKPATTERNMATCHDEL_HASH_KEY2", "FIELD", "VALUE", &ret); + db.HSet("GP1_PKPATTERNMATCHDEL_HASH_KEY3", "FIELD", "VALUE", &ret); + 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); + ASSERT_TRUE(s.ok()); + ASSERT_EQ(delete_count, 6); + keys.clear(); + db.Keys(DataType::kHashes, "*", &keys); + ASSERT_EQ(keys.size(), 0); + + // ***************** Group 2 Test ***************** + db.HSet("GP2_PKPATTERNMATCHDEL_HASH_KEY1", "FIELD", "VALUE", &ret); + db.HSet("GP2_PKPATTERNMATCHDEL_HASH_KEY2", "FIELD", "VALUE", &ret); + db.HSet("GP2_PKPATTERNMATCHDEL_HASH_KEY3", "FIELD", "VALUE", &ret); + db.HSet("GP2_PKPATTERNMATCHDEL_HASH_KEY4", "FIELD", "VALUE", &ret); + db.HSet("GP2_PKPATTERNMATCHDEL_HASH_KEY5", "FIELD", "VALUE", &ret); + db.HSet("GP2_PKPATTERNMATCHDEL_HASH_KEY6", "FIELD", "VALUE", &ret); + 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); + ASSERT_TRUE(s.ok()); + ASSERT_EQ(delete_count, 3); + keys.clear(); + db.Keys(DataType::kHashes, "*", &keys); + ASSERT_EQ(keys.size(), 0); + + // ***************** Group 3 Test ***************** + db.HSet("GP3_PKPATTERNMATCHDEL_HASH_KEY1_0xxx0", "FIELD", "VALUE", &ret); + db.HSet("GP3_PKPATTERNMATCHDEL_HASH_KEY2_0ooo0", "FIELD", "VALUE", &ret); + db.HSet("GP3_PKPATTERNMATCHDEL_HASH_KEY3_0xxx0", "FIELD", "VALUE", &ret); + 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); + ASSERT_TRUE(s.ok()); + ASSERT_EQ(delete_count, 3); + keys.clear(); + db.Keys(DataType::kHashes, "*", &keys); + ASSERT_EQ(keys.size(), 3); + ASSERT_EQ("GP3_PKPATTERNMATCHDEL_HASH_KEY1_0xxx0", keys[0]); + ASSERT_EQ("GP3_PKPATTERNMATCHDEL_HASH_KEY3_0xxx0", keys[1]); + ASSERT_EQ("GP3_PKPATTERNMATCHDEL_HASH_KEY5_0xxx0", keys[2]); + type_status.clear(); + db.Del(keys); + + // ***************** Group 4 Test ***************** + db.HSet("GP4_PKPATTERNMATCHDEL_HASH_KEY1", "FIELD", "VALUE", &ret); + db.HSet("GP4_PKPATTERNMATCHDEL_HASH_KEY2", "FIELD", "VALUE", &ret); + db.HSet("GP4_PKPATTERNMATCHDEL_HASH_KEY3", "FIELD", "VALUE", &ret); + db.HSet("GP4_PKPATTERNMATCHDEL_HASH_KEY4", "FIELD", "VALUE", &ret); + db.HSet("GP4_PKPATTERNMATCHDEL_HASH_KEY5", "FIELD", "VALUE", &ret); + db.HSet("GP4_PKPATTERNMATCHDEL_HASH_KEY6", "FIELD", "VALUE", &ret); + 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); + ASSERT_TRUE(s.ok()); + ASSERT_EQ(delete_count, 3); + keys.clear(); + db.Keys(DataType::kHashes, "*", &keys); + ASSERT_EQ(keys.size(), 0); + + // ***************** Group 5 Test ***************** + db.HSet("GP5_PKPATTERNMATCHDEL_HASH_KEY1_0ooo0", "FIELD", "VALUE", &ret); + db.HSet("GP5_PKPATTERNMATCHDEL_HASH_KEY2_0xxx0", "FIELD", "VALUE", &ret); + db.HSet("GP5_PKPATTERNMATCHDEL_HASH_KEY3_0ooo0", "FIELD", "VALUE", &ret); + db.HSet("GP5_PKPATTERNMATCHDEL_HASH_KEY4_0xxx0", "FIELD", "VALUE", &ret); + db.HSet("GP5_PKPATTERNMATCHDEL_HASH_KEY5_0ooo0", "FIELD", "VALUE", &ret); + db.HSet("GP5_PKPATTERNMATCHDEL_HASH_KEY6_0xxx0", "FIELD", "VALUE", &ret); + db.HSet("GP5_PKPATTERNMATCHDEL_HASH_KEY7_0ooo0", "FIELD", "VALUE", &ret); + db.HSet("GP5_PKPATTERNMATCHDEL_HASH_KEY8_0xxx0", "FIELD", "VALUE", &ret); + ASSERT_TRUE(make_expired(&db, "GP5_PKPATTERNMATCHDEL_HASH_KEY1_0ooo0")); + 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); + ASSERT_TRUE(s.ok()); + ASSERT_EQ(delete_count, 2); + keys.clear(); + db.Keys(DataType::kHashes, "*", &keys); + ASSERT_EQ(keys.size(), 2); + ASSERT_EQ(keys[0], "GP5_PKPATTERNMATCHDEL_HASH_KEY6_0xxx0"); + ASSERT_EQ(keys[1], "GP5_PKPATTERNMATCHDEL_HASH_KEY8_0xxx0"); + type_status.clear(); + db.Del(keys); + + // ***************** Group 6 Test ***************** + size_t gp6_total_hash = 23333; + 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); + ASSERT_TRUE(s.ok()); + ASSERT_EQ(delete_count, gp6_total_hash); + keys.clear(); + db.Keys(DataType::kHashes, "*", &keys); + ASSERT_EQ(keys.size(), 0); + + //=============================== ZSets =============================== + + // ***************** Group 1 Test ***************** + db.ZAdd("GP1_PKPATTERNMATCHDEL_ZSET_KEY1", {{1, "M"}}, &ret); + db.ZAdd("GP1_PKPATTERNMATCHDEL_ZSET_KEY2", {{1, "M"}}, &ret); + db.ZAdd("GP1_PKPATTERNMATCHDEL_ZSET_KEY3", {{1, "M"}}, &ret); + 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); + ASSERT_TRUE(s.ok()); + ASSERT_EQ(delete_count, 6); + keys.clear(); + db.Keys(DataType::kZSets, "*", &keys); + ASSERT_EQ(keys.size(), 0); + + // ***************** Group 2 Test ***************** + db.ZAdd("GP2_PKPATTERNMATCHDEL_ZSET_KEY1", {{1, "M"}}, &ret); + db.ZAdd("GP2_PKPATTERNMATCHDEL_ZSET_KEY2", {{1, "M"}}, &ret); + db.ZAdd("GP2_PKPATTERNMATCHDEL_ZSET_KEY3", {{1, "M"}}, &ret); + db.ZAdd("GP2_PKPATTERNMATCHDEL_ZSET_KEY4", {{1, "M"}}, &ret); + db.ZAdd("GP2_PKPATTERNMATCHDEL_ZSET_KEY5", {{1, "M"}}, &ret); + db.ZAdd("GP2_PKPATTERNMATCHDEL_ZSET_KEY6", {{1, "M"}}, &ret); + 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); + ASSERT_TRUE(s.ok()); + ASSERT_EQ(delete_count, 3); + keys.clear(); + db.Keys(DataType::kZSets, "*", &keys); + ASSERT_EQ(keys.size(), 0); + + // ***************** Group 3 Test ***************** + db.ZAdd("GP3_PKPATTERNMATCHDEL_ZSET_KEY1_0xxx0", {{1, "M"}}, &ret); + db.ZAdd("GP3_PKPATTERNMATCHDEL_ZSET_KEY2_0ooo0", {{1, "M"}}, &ret); + db.ZAdd("GP3_PKPATTERNMATCHDEL_ZSET_KEY3_0xxx0", {{1, "M"}}, &ret); + 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); + ASSERT_TRUE(s.ok()); + ASSERT_EQ(delete_count, 3); + keys.clear(); + db.Keys(DataType::kZSets, "*", &keys); + ASSERT_EQ(keys.size(), 3); + ASSERT_EQ("GP3_PKPATTERNMATCHDEL_ZSET_KEY1_0xxx0", keys[0]); + ASSERT_EQ("GP3_PKPATTERNMATCHDEL_ZSET_KEY3_0xxx0", keys[1]); + ASSERT_EQ("GP3_PKPATTERNMATCHDEL_ZSET_KEY5_0xxx0", keys[2]); + type_status.clear(); + db.Del(keys); + + // ***************** Group 4 Test ***************** + db.ZAdd("GP4_PKPATTERNMATCHDEL_ZSET_KEY1", {{1, "M"}}, &ret); + db.ZAdd("GP4_PKPATTERNMATCHDEL_ZSET_KEY2", {{1, "M"}}, &ret); + db.ZAdd("GP4_PKPATTERNMATCHDEL_ZSET_KEY3", {{1, "M"}}, &ret); + db.ZAdd("GP4_PKPATTERNMATCHDEL_ZSET_KEY4", {{1, "M"}}, &ret); + db.ZAdd("GP4_PKPATTERNMATCHDEL_ZSET_KEY5", {{1, "M"}}, &ret); + db.ZAdd("GP4_PKPATTERNMATCHDEL_ZSET_KEY6", {{1, "M"}}, &ret); + 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); + ASSERT_TRUE(s.ok()); + ASSERT_EQ(delete_count, 3); + keys.clear(); + db.Keys(DataType::kZSets, "*", &keys); + ASSERT_EQ(keys.size(), 0); + + // ***************** Group 5 Test ***************** + db.ZAdd("GP5_PKPATTERNMATCHDEL_ZSET_KEY1_0ooo0", {{1, "M"}}, &ret); + db.ZAdd("GP5_PKPATTERNMATCHDEL_ZSET_KEY2_0xxx0", {{1, "M"}}, &ret); + db.ZAdd("GP5_PKPATTERNMATCHDEL_ZSET_KEY3_0ooo0", {{1, "M"}}, &ret); + db.ZAdd("GP5_PKPATTERNMATCHDEL_ZSET_KEY4_0xxx0", {{1, "M"}}, &ret); + db.ZAdd("GP5_PKPATTERNMATCHDEL_ZSET_KEY5_0ooo0", {{1, "M"}}, &ret); + db.ZAdd("GP5_PKPATTERNMATCHDEL_ZSET_KEY6_0xxx0", {{1, "M"}}, &ret); + db.ZAdd("GP5_PKPATTERNMATCHDEL_ZSET_KEY7_0ooo0", {{1, "M"}}, &ret); + db.ZAdd("GP5_PKPATTERNMATCHDEL_ZSET_KEY8_0xxx0", {{1, "M"}}, &ret); + ASSERT_TRUE(make_expired(&db, "GP5_PKPATTERNMATCHDEL_ZSET_KEY1_0ooo0")); + 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); + ASSERT_TRUE(s.ok()); + ASSERT_EQ(delete_count, 2); + keys.clear(); + db.Keys(DataType::kZSets, "*", &keys); + ASSERT_EQ(keys.size(), 2); + ASSERT_EQ(keys[0], "GP5_PKPATTERNMATCHDEL_ZSET_KEY6_0xxx0"); + ASSERT_EQ(keys[1], "GP5_PKPATTERNMATCHDEL_ZSET_KEY8_0xxx0"); + type_status.clear(); + db.Del(keys); + + // ***************** Group 6 Test ***************** + size_t gp6_total_zset = 23333; + 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); + ASSERT_TRUE(s.ok()); + ASSERT_EQ(delete_count, gp6_total_zset); + keys.clear(); + db.Keys(DataType::kZSets, "*", &keys); + ASSERT_EQ(keys.size(), 0); + + //=============================== List =============================== + + // ***************** Group 1 Test ***************** + db.LPush("GP1_PKPATTERNMATCHDEL_LIST_KEY1", {"VALUE"}, &ret64); + db.LPush("GP1_PKPATTERNMATCHDEL_LIST_KEY2", {"VALUE"}, &ret64); + db.LPush("GP1_PKPATTERNMATCHDEL_LIST_KEY3", {"VALUE"}, &ret64); + 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); + ASSERT_TRUE(s.ok()); + ASSERT_EQ(delete_count, 6); + keys.clear(); + db.Keys(DataType::kLists, "*", &keys); + ASSERT_EQ(keys.size(), 0); + + // ***************** Group 2 Test ***************** + db.LPush("GP2_PKPATTERNMATCHDEL_LIST_KEY1", {"VALUE"}, &ret64); + db.LPush("GP2_PKPATTERNMATCHDEL_LIST_KEY2", {"VALUE"}, &ret64); + db.LPush("GP2_PKPATTERNMATCHDEL_LIST_KEY3", {"VALUE"}, &ret64); + db.LPush("GP2_PKPATTERNMATCHDEL_LIST_KEY4", {"VALUE"}, &ret64); + db.LPush("GP2_PKPATTERNMATCHDEL_LIST_KEY5", {"VALUE"}, &ret64); + db.LPush("GP2_PKPATTERNMATCHDEL_LIST_KEY6", {"VALUE"}, &ret64); + 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); + ASSERT_TRUE(s.ok()); + ASSERT_EQ(delete_count, 3); + keys.clear(); + db.Keys(DataType::kLists, "*", &keys); + ASSERT_EQ(keys.size(), 0); + + // ***************** Group 3 Test ***************** + db.LPush("GP3_PKPATTERNMATCHDEL_LIST_KEY1_0xxx0", {"VALUE"}, &ret64); + db.LPush("GP3_PKPATTERNMATCHDEL_LIST_KEY2_0ooo0", {"VALUE"}, &ret64); + db.LPush("GP3_PKPATTERNMATCHDEL_LIST_KEY3_0xxx0", {"VALUE"}, &ret64); + 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); + ASSERT_TRUE(s.ok()); + ASSERT_EQ(delete_count, 3); + keys.clear(); + db.Keys(DataType::kLists, "*", &keys); + ASSERT_EQ(keys.size(), 3); + ASSERT_EQ("GP3_PKPATTERNMATCHDEL_LIST_KEY1_0xxx0", keys[0]); + ASSERT_EQ("GP3_PKPATTERNMATCHDEL_LIST_KEY3_0xxx0", keys[1]); + ASSERT_EQ("GP3_PKPATTERNMATCHDEL_LIST_KEY5_0xxx0", keys[2]); + type_status.clear(); + db.Del(keys); + + // ***************** Group 4 Test ***************** + db.LPush("GP4_PKPATTERNMATCHDEL_LIST_KEY1", {"VALUE"}, &ret64); + db.LPush("GP4_PKPATTERNMATCHDEL_LIST_KEY2", {"VALUE"}, &ret64); + db.LPush("GP4_PKPATTERNMATCHDEL_LIST_KEY3", {"VALUE"}, &ret64); + db.LPush("GP4_PKPATTERNMATCHDEL_LIST_KEY4", {"VALUE"}, &ret64); + db.LPush("GP4_PKPATTERNMATCHDEL_LIST_KEY5", {"VALUE"}, &ret64); + db.LPush("GP4_PKPATTERNMATCHDEL_LIST_KEY6", {"VALUE"}, &ret64); + 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); + ASSERT_TRUE(s.ok()); + ASSERT_EQ(delete_count, 3); + keys.clear(); + db.Keys(DataType::kLists, "*", &keys); + ASSERT_EQ(keys.size(), 0); + + // ***************** Group 5 Test ***************** + db.LPush("GP5_PKPATTERNMATCHDEL_LIST_KEY1_0ooo0", {"VALUE"}, &ret64); + db.LPush("GP5_PKPATTERNMATCHDEL_LIST_KEY2_0xxx0", {"VALUE"}, &ret64); + db.LPush("GP5_PKPATTERNMATCHDEL_LIST_KEY3_0ooo0", {"VALUE"}, &ret64); + db.LPush("GP5_PKPATTERNMATCHDEL_LIST_KEY4_0xxx0", {"VALUE"}, &ret64); + db.LPush("GP5_PKPATTERNMATCHDEL_LIST_KEY5_0ooo0", {"VALUE"}, &ret64); + db.LPush("GP5_PKPATTERNMATCHDEL_LIST_KEY6_0xxx0", {"VALUE"}, &ret64); + db.LPush("GP5_PKPATTERNMATCHDEL_LIST_KEY7_0ooo0", {"VALUE"}, &ret64); + db.LPush("GP5_PKPATTERNMATCHDEL_LIST_KEY8_0xxx0", {"VALUE"}, &ret64); + ASSERT_TRUE(make_expired(&db, "GP5_PKPATTERNMATCHDEL_LIST_KEY1_0ooo0")); + 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); + ASSERT_TRUE(s.ok()); + ASSERT_EQ(delete_count, 2); + keys.clear(); + db.Keys(DataType::kLists, "*", &keys); + ASSERT_EQ(keys.size(), 2); + ASSERT_EQ(keys[0], "GP5_PKPATTERNMATCHDEL_LIST_KEY6_0xxx0"); + ASSERT_EQ(keys[1], "GP5_PKPATTERNMATCHDEL_LIST_KEY8_0xxx0"); + type_status.clear(); + db.Del(keys); + + // ***************** Group 6 Test ***************** + size_t gp6_total_list = 23333; + 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); + ASSERT_TRUE(s.ok()); + ASSERT_EQ(delete_count, gp6_total_hash); + keys.clear(); + db.Keys(DataType::kLists, "*", &keys); + ASSERT_EQ(keys.size(), 0); + + sleep(2); + db.Compact(DataType::kAll, true); +} // Scan // Note: This test needs to execute at first because all of the data is diff --git a/tests/assets/default.conf b/tests/assets/default.conf index 468d253e89..d5d1318f5c 100644 --- a/tests/assets/default.conf +++ b/tests/assets/default.conf @@ -567,4 +567,4 @@ cache-lfu-decay-time: 1 # Warning: Ensure that the Settings of rename-command on the master and slave servers are consistent # # Example: -# rename-command : FLUSHDB 360flushdb +# rename-command : FLUSHDB 360flushdb \ No newline at end of file diff --git a/tests/unit/type/hyperloglog.tcl b/tests/unit/type/hyperloglog.tcl new file mode 100644 index 0000000000..1f719cc4d6 --- /dev/null +++ b/tests/unit/type/hyperloglog.tcl @@ -0,0 +1,262 @@ +start_server {tags {"hll"}} { +# Pika does not support the pfdebug command +# test {HyperLogLog self test passes} { +# catch {r pfselftest} e +# set e +# } {OK} + + test {PFADD without arguments creates an HLL value} { + r pfadd hll + r exists hll + } {1} + + test {Approximated cardinality after creation is zero} { + r pfcount hll + } {0} + + test {PFADD returns 1 when at least 1 reg was modified} { + r pfadd hll a b c + } {1} + + test {PFADD returns 0 when no reg was modified} { + r pfadd hll a b c + } {0} + + test {PFADD works with empty string (regression)} { + r pfadd hll "" + } + + # Note that the self test stresses much better the + # cardinality estimation error. We are testing just the + # command implementation itself here. + test {PFCOUNT returns approximated cardinality of set} { + r del hll + set res {} + r pfadd hll 1 2 3 4 5 + lappend res [r pfcount hll] + # Call it again to test cached value invalidation. + r pfadd hll 6 7 8 8 9 10 + lappend res [r pfcount hll] + set res + } {5 10} + +# This parameter is not available in Pika +# test {HyperLogLogs are promote from sparse to dense} { +# r del hll +# r config set hll-sparse-max-bytes 3000 +# set n 0 +# while {$n < 100} { +# set elements {} +# for {set j 0} {$j < 100} {incr j} {lappend elements [expr rand()]} +# incr n 100 +# r pfadd hll {*}$elements +# set card [r pfcount hll] +# set err [expr {abs($card-$n)}] +# assert {$err < (double($card)/100)*5} +# if {$n < 1000} { +# assert {[r pfdebug encoding hll] eq {sparse}} +# } elseif {$n > 10000} { +# assert {[r pfdebug encoding hll] eq {dense}} +# } +# } +# } + +# Pika does not support the pfdebug command +# test {HyperLogLog sparse encoding stress test} { +# for {set x 0} {$x < 1000} {incr x} { +# r del hll1 hll2 +# set numele [randomInt 100] +# set elements {} +# for {set j 0} {$j < $numele} {incr j} { +# lappend elements [expr rand()] +# } + # Force dense representation of hll2 +# r pfadd hll2 +# r pfdebug todense hll2 +# r pfadd hll1 {*}$elements +# r pfadd hll2 {*}$elements +# assert {[r pfdebug encoding hll1] eq {sparse}} +# assert {[r pfdebug encoding hll2] eq {dense}} +# # Cardinality estimated should match exactly. +# assert {[r pfcount hll1] eq [r pfcount hll2]} +# } +# } + +# The return value of Pika is inconsistent with Redis + test {Corrupted sparse HyperLogLogs are detected: Additionl at tail} { + r del hll + r pfadd hll a b c + r append hll "hello" + set e {} + catch {r pfcount hll} e + set e + } {*WRONGTYPE*} + +# The return value of Pika is inconsistent with Redis + test {Corrupted sparse HyperLogLogs are detected: Broken magic} { + r del hll + r pfadd hll a b c + r setrange hll 0 "0123" + set e {} + catch {r pfcount hll} e + set e + } {*WRONGTYPE*} + +# The return value of Pika is inconsistent with Redis + test {Corrupted sparse HyperLogLogs are detected: Invalid encoding} { + r del hll + r pfadd hll a b c + r setrange hll 4 "x" + set e {} + catch {r pfcount hll} e + set e + } {*WRONGTYPE*} + +# The return value of Pika is inconsistent with Redis + test {Corrupted dense HyperLogLogs are detected: Wrong length} { + r del hll + r pfadd hll a b c + r setrange hll 4 "\x00" + set e {} + catch {r pfcount hll} e + set e + } {*WRONGTYPE*} + +# The return value of Pika is inconsistent with Redis + test {PFADD, PFCOUNT, PFMERGE type checking works} { + r set foo bar + catch {r pfadd foo 1} e + assert_match {*WRONGTYPE*} $e + catch {r pfcount foo} e + assert_match {*WRONGTYPE*} $e + catch {r pfmerge bar foo} e + assert_match {*WRONGTYPE*} $e + # catch {r pfmerge foo bar} e + # assert_match {*WRONGTYPE*} $e + } + + test {PFMERGE results on the cardinality of union of sets} { + r del hll hll1 hll2 hll3 + r pfadd hll1 a b c + r pfadd hll2 b c d + r pfadd hll3 c d e + r pfmerge hll hll1 hll2 hll3 + r pfcount hll + } {5} + +# The return value of Pika is inconsistent with Redis + test {PFCOUNT multiple-keys merge returns cardinality of union} { + r del hll1 hll2 hll3 + for {set x 1} {$x < 100} {incr x} { + # Force dense representation of hll2 + r pfadd hll1 "foo-$x" + r pfadd hll2 "bar-$x" + r pfadd hll3 "zap-$x" + + set card [r pfcount hll1 hll2 hll3] + set realcard [expr {$x*3}] + set err [expr {abs($card-$realcard)}] + assert {$err < (double($card)/100)*5} + } + } + +# The return value of Pika is inconsistent with Redis +# test {HYPERLOGLOG press test: 5w, 10w, 15w, 20w, 30w, 50w, 100w} { +# r del hll1 +# for {set x 1} {$x <= 1000000} {incr x} { +# r pfadd hll1 "foo-$x" +# if {$x == 50000} { +# set card [r pfcount hll1] +# set realcard [expr {$x*1}] +# set err [expr {abs($card-$realcard)}] +# +# set d_err [expr {$err * 1.0}] +# set d_realcard [expr {$realcard * 1.0}] +# set err_precentage [expr {double($d_err / $d_realcard)}] +# puts "$x error rate: $err_precentage" +# assert {$err < $realcard * 0.01} +# } +# if {$x == 100000} { +# set card [r pfcount hll1] +# set realcard [expr {$x*1}] +# set err [expr {abs($card-$realcard)}] +# +# set d_err [expr {$err * 1.0}] +# set d_realcard [expr {$realcard * 1.0}] +# set err_precentage [expr {double($d_err / $d_realcard)}] +# puts "$x error rate: $err_precentage" +# assert {$err < $realcard * 0.01} +# } +# if {$x == 150000} { +# set card [r pfcount hll1] +# set realcard [expr {$x*1}] +# set err [expr {abs($card-$realcard)}] +# +# set d_err [expr {$err * 1.0}] +# set d_realcard [expr {$realcard * 1.0}] +# set err_precentage [expr {double($d_err / $d_realcard)}] +# puts "$x error rate: $err_precentage" +# assert {$err < $realcard * 0.01} +# } +# if {$x == 300000} { +# set card [r pfcount hll1] +# set realcard [expr {$x*1}] +# set err [expr {abs($card-$realcard)}] +# +# set d_err [expr {$err * 1.0}] +# set d_realcard [expr {$realcard * 1.0}] +# set err_precentage [expr {double($d_err / $d_realcard)}] +# puts "$x error rate: $err_precentage" +# assert {$err < $realcard * 0.01} +# } +# if {$x == 500000} { +# set card [r pfcount hll1] +# set realcard [expr {$x*1}] +# set err [expr {abs($card-$realcard)}] +# +# set d_err [expr {$err * 1.0}] +# set d_realcard [expr {$realcard * 1.0}] +# set err_precentage [expr {double($d_err / $d_realcard)}] +# puts "$x error rate: $err_precentage" +# assert {$err < $realcard * 0.01} +# } +# if {$x == 1000000} { +# set card [r pfcount hll1] +# set realcard [expr {$x*1}] +# set err [expr {abs($card-$realcard)}] +# +# set d_err [expr {$err * 1.0}] +# set d_realcard [expr {$realcard * 1.0}] +# set err_precentage [expr {double($d_err / $d_realcard)}] +# puts "$x error rate: $err_precentage" +# assert {$err < $realcard * 0.03} +# } +# } +# } + +# Pika does not support the pfdebug command +# test {PFDEBUG GETREG returns the HyperLogLog raw registers} { +# r del hll +# r pfadd hll 1 2 3 +# llength [r pfdebug getreg hll] +# } {16384} + +# Pika does not support the pfdebug command +# test {PFDEBUG GETREG returns the HyperLogLog raw registers} { +# r del hll +# r pfadd hll 1 2 3 +# llength [r pfdebug getreg hll] +# } {16384} + +# The return value of Pika is inconsistent with Redis + test {PFADD / PFCOUNT cache invalidation works} { + r del hll + r pfadd hll a b c + r pfcount hll + assert {[r getrange hll 15 15] eq "\x00"} + r pfadd hll a b c + assert {[r getrange hll 15 15] eq "\x00"} + # r pfadd hll 1 2 3 + # assert {[r getrange hll 15 15] eq "\x80"} + } +}