From d188c7b40509c8ead5a357c8a6b18cda82e7cc5b Mon Sep 17 00:00:00 2001 From: anotherJJz <470623352@qq.com> Date: Tue, 16 Jul 2024 10:24:31 +0800 Subject: [PATCH] Add a field indicate whether the expiration time of field is included --- src/storage/redis_db.cc | 4 ++-- src/storage/redis_metadata.cc | 23 +++++++++++++++++++++-- src/storage/redis_metadata.h | 7 +++++-- src/types/redis_hash.cc | 16 ++++++++-------- 4 files changed, 36 insertions(+), 14 deletions(-) diff --git a/src/storage/redis_db.cc b/src/storage/redis_db.cc index 3a5943b9ee4..d582e937d78 100644 --- a/src/storage/redis_db.cc +++ b/src/storage/redis_db.cc @@ -581,7 +581,7 @@ rocksdb::Status SubKeyScanner::Scan(RedisType type, const Slice &user_key, const InternalKey ikey(iter->key(), storage_->IsSlotIdEncoded()); auto value = iter->value().ToString(); // filter expired hash field - if (type == kRedisHash && (static_cast(&metadata))->IsEncodedFieldHasTTL()) { + if (type == kRedisHash && (static_cast(&metadata))->is_ttl_field_encoded) { uint64_t expire = 0; rocksdb::Slice data(value.data(), value.size()); GetFixed64(&data, &expire); @@ -662,7 +662,7 @@ rocksdb::Status Database::typeInternal(const Slice &key, RedisType *type) { if (!s.ok()) return s; if (metadata.Expired()) { *type = kRedisNone; - } else if (metadata.Type() == kRedisHash && (static_cast(&metadata))->IsEncodedFieldHasTTL()) { + } else if (metadata.Type() == kRedisHash && (static_cast(&metadata))->is_ttl_field_encoded) { redis::Hash hash_db(storage_, namespace_); auto [_, user_key] = ExtractNamespaceKey(key, storage_->IsSlotIdEncoded()); std::vector field_values; diff --git a/src/storage/redis_metadata.cc b/src/storage/redis_metadata.cc index 98c4269009c..6a15ea68158 100644 --- a/src/storage/redis_metadata.cc +++ b/src/storage/redis_metadata.cc @@ -334,8 +334,27 @@ bool Metadata::IsEmptyableType() const { bool Metadata::Expired() const { return ExpireAt(util::GetTimeStampMS()); } -bool HashMetadata::IsEncodedFieldHasTTL() const { - return flags & METADATA_HASH_FIELD_EXPIRE_MASK; +void HashMetadata::Encode(std::string *dst) const { + Metadata::Encode(dst); + if (is_ttl_field_encoded) { + uint8_t flag = 0; + flag |= METADATA_HASH_FIELD_EXPIRE_MASK; + PutFixed8(dst, flag); + } +} + +rocksdb::Status HashMetadata::Decode(Slice *input) { + if (auto s = Metadata::Decode(input); !s.ok()) { + return s; + } + + if (input->size() >= 1) { + uint8_t flag = 0; + GetFixed8(input, &flag); + is_ttl_field_encoded = flag &= METADATA_HASH_FIELD_EXPIRE_MASK; + } + + return rocksdb::Status::OK(); } ListMetadata::ListMetadata(bool generate_version) diff --git a/src/storage/redis_metadata.h b/src/storage/redis_metadata.h index 72d92d6a914..10ad3395bf8 100644 --- a/src/storage/redis_metadata.h +++ b/src/storage/redis_metadata.h @@ -134,8 +134,8 @@ class InternalKey { }; constexpr uint8_t METADATA_64BIT_ENCODING_MASK = 0x80; -constexpr uint8_t METADATA_HASH_FIELD_EXPIRE_MASK = 0x40; constexpr uint8_t METADATA_TYPE_MASK = 0x0f; +constexpr uint8_t METADATA_HASH_FIELD_EXPIRE_MASK = 0x01; class Metadata { public: @@ -203,9 +203,12 @@ class Metadata { class HashMetadata : public Metadata { public: + bool is_ttl_field_encoded; explicit HashMetadata(bool generate_version = true) : Metadata(kRedisHash, generate_version) {} - bool IsEncodedFieldHasTTL() const; + void Encode(std::string *dst) const override; + using Metadata::Decode; + rocksdb::Status Decode(Slice *input) override; }; class SetMetadata : public Metadata { diff --git a/src/types/redis_hash.cc b/src/types/redis_hash.cc index 1d2da05f648..a5ff11d33c2 100644 --- a/src/types/redis_hash.cc +++ b/src/types/redis_hash.cc @@ -46,7 +46,7 @@ rocksdb::Status Hash::Size(const Slice &user_key, uint64_t *size) { HashMetadata metadata(false); rocksdb::Status s = GetMetadata(Database::GetOptions{}, ns_key, &metadata); if (!s.ok()) return s; - if (!metadata.IsEncodedFieldHasTTL()) { + if (!metadata.is_ttl_field_encoded) { *size = metadata.size; } else { std::vector field_values; @@ -113,7 +113,7 @@ rocksdb::Status Hash::IncrBy(const Slice &user_key, const Slice &field, int64_t WriteBatchLogData log_data(kRedisHash); batch->PutLogData(log_data.Encode()); auto value_str = std::to_string(*new_value); - if (metadata.IsEncodedFieldHasTTL()) { + if (metadata.is_ttl_field_encoded) { encodeFieldAndTTL(&value_str, expire); } batch->Put(sub_key, value_str); @@ -164,7 +164,7 @@ rocksdb::Status Hash::IncrByFloat(const Slice &user_key, const Slice &field, dou WriteBatchLogData log_data(kRedisHash); batch->PutLogData(log_data.Encode()); auto value_str = std::to_string(*new_value); - if (metadata.IsEncodedFieldHasTTL()) { + if (metadata.is_ttl_field_encoded) { encodeFieldAndTTL(&value_str, expire); } batch->Put(sub_key, value_str); @@ -308,7 +308,7 @@ rocksdb::Status Hash::MSet(const Slice &user_key, const std::vector } auto value = it->value; - if (metadata.IsEncodedFieldHasTTL()) { + if (metadata.is_ttl_field_encoded) { encodeFieldAndTTL(&value, expire); } batch->Put(sub_key, value); @@ -545,8 +545,8 @@ rocksdb::Status Hash::ExpireFields(const Slice &user_key, uint64_t expire_ms, } // convert rest field encoding - if (!metadata.IsEncodedFieldHasTTL()) { - metadata.flags |= METADATA_HASH_FIELD_EXPIRE_MASK; + if (!metadata.is_ttl_field_encoded) { + metadata.is_ttl_field_encoded = true; std::unordered_set field_set; for (auto field : fields) { @@ -636,7 +636,7 @@ rocksdb::Status Hash::TTLFields(const Slice &user_key, const std::vector } bool Hash::IsFieldExpired(Metadata &metadata, const Slice &value) { - if (!(static_cast(&metadata))->IsEncodedFieldHasTTL()) { + if (!(static_cast(&metadata))->is_ttl_field_encoded) { return false; } uint64_t expire = 0; @@ -646,7 +646,7 @@ bool Hash::IsFieldExpired(Metadata &metadata, const Slice &value) { } rocksdb::Status Hash::decodeFieldAndTTL(const HashMetadata &metadata, std::string *value, uint64_t &expire) { - if (!metadata.IsEncodedFieldHasTTL()) { + if (!metadata.is_ttl_field_encoded) { return rocksdb::Status::OK(); } rocksdb::Slice data(value->data(), value->size());