Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/search/indexer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ StatusOr<FieldValueRetriever> FieldValueRetriever::Create(SearchOnDataType type,
Hash db(storage, ns);
std::string ns_key = db.AppendNamespacePrefix(key);
HashMetadata metadata(false);
auto s = db.GetMetadata(ns_key, &metadata);
auto s = db.GetMetadata(Database::GetOptions{}, ns_key, &metadata);
if (!s.ok()) return {Status::NotOK, s.ToString()};
return FieldValueRetriever(db, metadata, key);
} else if (type == SearchOnDataType::JSON) {
Expand Down
14 changes: 7 additions & 7 deletions src/stats/disk_stats.cc
Original file line number Diff line number Diff line change
Expand Up @@ -77,21 +77,21 @@ rocksdb::Status Disk::GetStringSize(const Slice &ns_key, uint64_t *key_size) {

rocksdb::Status Disk::GetHashSize(const Slice &ns_key, uint64_t *key_size) {
HashMetadata metadata(false);
rocksdb::Status s = Database::GetMetadata({kRedisHash}, ns_key, &metadata);
rocksdb::Status s = Database::GetMetadata(Database::GetOptions{}, {kRedisHash}, ns_key, &metadata);
if (!s.ok()) return s.IsNotFound() ? rocksdb::Status::OK() : s;
return GetApproximateSizes(metadata, ns_key, storage_->GetCFHandle(engine::kSubkeyColumnFamilyName), key_size);
}

rocksdb::Status Disk::GetSetSize(const Slice &ns_key, uint64_t *key_size) {
SetMetadata metadata(false);
rocksdb::Status s = Database::GetMetadata({kRedisSet}, ns_key, &metadata);
rocksdb::Status s = Database::GetMetadata(Database::GetOptions{}, {kRedisSet}, ns_key, &metadata);
if (!s.ok()) return s.IsNotFound() ? rocksdb::Status::OK() : s;
return GetApproximateSizes(metadata, ns_key, storage_->GetCFHandle(engine::kSubkeyColumnFamilyName), key_size);
}

rocksdb::Status Disk::GetListSize(const Slice &ns_key, uint64_t *key_size) {
ListMetadata metadata(false);
rocksdb::Status s = Database::GetMetadata({kRedisList}, ns_key, &metadata);
rocksdb::Status s = Database::GetMetadata(Database::GetOptions{}, {kRedisList}, ns_key, &metadata);
if (!s.ok()) return s.IsNotFound() ? rocksdb::Status::OK() : s;
std::string buf;
PutFixed64(&buf, metadata.head);
Expand All @@ -100,7 +100,7 @@ rocksdb::Status Disk::GetListSize(const Slice &ns_key, uint64_t *key_size) {

rocksdb::Status Disk::GetZsetSize(const Slice &ns_key, uint64_t *key_size) {
ZSetMetadata metadata(false);
rocksdb::Status s = Database::GetMetadata({kRedisZSet}, ns_key, &metadata);
rocksdb::Status s = Database::GetMetadata(Database::GetOptions{}, {kRedisZSet}, ns_key, &metadata);
if (!s.ok()) return s.IsNotFound() ? rocksdb::Status::OK() : s;
std::string score_bytes;
PutDouble(&score_bytes, kMinScore);
Expand All @@ -112,15 +112,15 @@ rocksdb::Status Disk::GetZsetSize(const Slice &ns_key, uint64_t *key_size) {

rocksdb::Status Disk::GetBitmapSize(const Slice &ns_key, uint64_t *key_size) {
BitmapMetadata metadata(false);
rocksdb::Status s = Database::GetMetadata({kRedisBitmap}, ns_key, &metadata);
rocksdb::Status s = Database::GetMetadata(Database::GetOptions{}, {kRedisBitmap}, ns_key, &metadata);
if (!s.ok()) return s.IsNotFound() ? rocksdb::Status::OK() : s;
return GetApproximateSizes(metadata, ns_key, storage_->GetCFHandle(engine::kSubkeyColumnFamilyName), key_size,
std::to_string(0), std::to_string(0));
}

rocksdb::Status Disk::GetSortedintSize(const Slice &ns_key, uint64_t *key_size) {
SortedintMetadata metadata(false);
rocksdb::Status s = Database::GetMetadata({kRedisSortedint}, ns_key, &metadata);
rocksdb::Status s = Database::GetMetadata(Database::GetOptions{}, {kRedisSortedint}, ns_key, &metadata);
if (!s.ok()) return s.IsNotFound() ? rocksdb::Status::OK() : s;
std::string start_buf;
PutFixed64(&start_buf, 0);
Expand All @@ -130,7 +130,7 @@ rocksdb::Status Disk::GetSortedintSize(const Slice &ns_key, uint64_t *key_size)

rocksdb::Status Disk::GetStreamSize(const Slice &ns_key, uint64_t *key_size) {
StreamMetadata metadata(false);
rocksdb::Status s = Database::GetMetadata({kRedisStream}, ns_key, &metadata);
rocksdb::Status s = Database::GetMetadata(Database::GetOptions{}, {kRedisStream}, ns_key, &metadata);
if (!s.ok()) return s.IsNotFound() ? rocksdb::Status::OK() : s;
return GetApproximateSizes(metadata, ns_key, storage_->GetCFHandle(engine::kStreamColumnFamilyName), key_size);
}
Expand Down
32 changes: 15 additions & 17 deletions src/storage/redis_db.cc
Original file line number Diff line number Diff line change
Expand Up @@ -84,25 +84,25 @@ rocksdb::Status Database::ParseMetadata(RedisTypes types, Slice *bytes, Metadata
return s;
}

rocksdb::Status Database::GetMetadata(RedisTypes types, const Slice &ns_key, Metadata *metadata) {
rocksdb::Status Database::GetMetadata(GetOptions options, RedisTypes types, const Slice &ns_key, Metadata *metadata) {
std::string raw_value;
Slice rest;
return GetMetadata(types, ns_key, &raw_value, metadata, &rest);
return GetMetadata(options, types, ns_key, &raw_value, metadata, &rest);
}

rocksdb::Status Database::GetMetadata(RedisTypes types, const Slice &ns_key, std::string *raw_value, Metadata *metadata,
Slice *rest) {
auto s = GetRawMetadata(ns_key, raw_value);
rocksdb::Status Database::GetMetadata(GetOptions options, RedisTypes types, const Slice &ns_key, std::string *raw_value,
Metadata *metadata, Slice *rest) {
auto s = GetRawMetadata(options, ns_key, raw_value);
*rest = *raw_value;
if (!s.ok()) return s;
return ParseMetadata(types, rest, metadata);
}

rocksdb::Status Database::GetRawMetadata(const Slice &ns_key, std::string *bytes) {
LatestSnapShot ss(storage_);
rocksdb::ReadOptions read_options;
read_options.snapshot = ss.GetSnapShot();
return storage_->Get(read_options, metadata_cf_handle_, ns_key, bytes);
rocksdb::Status Database::GetRawMetadata(GetOptions options, const Slice &ns_key, std::string *bytes) {
rocksdb::ReadOptions opts;
// If options.snapshot == nullptr, we can avoid allocating a snapshot here.
opts.snapshot = options.snapshot;
return storage_->Get(opts, metadata_cf_handle_, ns_key, bytes);
}

rocksdb::Status Database::Expire(const Slice &user_key, uint64_t timestamp) {
Expand Down Expand Up @@ -247,7 +247,7 @@ rocksdb::Status Database::TTL(const Slice &user_key, int64_t *ttl) {
rocksdb::Status Database::GetExpireTime(const Slice &user_key, uint64_t *timestamp) {
std::string ns_key = AppendNamespacePrefix(user_key);
Metadata metadata(kRedisNone, false);
auto s = GetMetadata(RedisTypes::All(), ns_key, &metadata);
auto s = GetMetadata(GetOptions{}, RedisTypes::All(), ns_key, &metadata);
if (!s.ok()) return s;
*timestamp = metadata.expire;

Expand Down Expand Up @@ -517,7 +517,7 @@ rocksdb::Status Database::Dump(const Slice &user_key, std::vector<std::string> *

if (metadata.Type() == kRedisList) {
ListMetadata list_metadata(false);
s = GetMetadata({kRedisList}, ns_key, &list_metadata);
s = GetMetadata(GetOptions{}, {kRedisList}, ns_key, &list_metadata);
if (!s.ok()) return s.IsNotFound() ? rocksdb::Status::OK() : s;
infos->emplace_back("head");
infos->emplace_back(std::to_string(list_metadata.head));
Expand Down Expand Up @@ -618,8 +618,7 @@ rocksdb::Status Database::ClearKeysOfSlot(const rocksdb::Slice &ns, int slot) {

rocksdb::Status Database::KeyExist(const std::string &key) {
int cnt = 0;
std::vector<rocksdb::Slice> keys;
keys.emplace_back(key);
std::vector<rocksdb::Slice> keys{key};
auto s = Exists(keys, &cnt);
if (!s.ok()) {
return s;
Expand All @@ -636,12 +635,11 @@ rocksdb::Status SubKeyScanner::Scan(RedisType type, const Slice &user_key, const
uint64_t cnt = 0;
std::string ns_key = AppendNamespacePrefix(user_key);
Metadata metadata(type, false);
rocksdb::Status s = GetMetadata({type}, ns_key, &metadata);
LatestSnapShot ss(storage_);
rocksdb::Status s = GetMetadata(GetOptions{.snapshot = ss.GetSnapShot()}, {type}, ns_key, &metadata);
if (!s.ok()) return s;

LatestSnapShot ss(storage_);
rocksdb::ReadOptions read_options = storage_->DefaultScanOptions();
read_options.snapshot = ss.GetSnapShot();
auto iter = util::UniqueIterator(storage_, read_options);
std::string match_prefix_key =
InternalKey(ns_key, subkey_prefix, metadata.version, storage_->IsSlotIdEncoded()).Encode();
Expand Down
46 changes: 41 additions & 5 deletions src/storage/redis_db.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,53 @@
#include "storage.h"

namespace redis {

/// Database is a wrapper of underlying storage engine, it provides
/// some common operations for redis commands.
class Database {
public:
static constexpr uint64_t RANDOM_KEY_SCAN_LIMIT = 60;

struct GetOptions {
// If snapshot is not nullptr, read from the specified snapshot,
// otherwise read from the "latest" snapshot.
const rocksdb::Snapshot *snapshot = nullptr;
};

explicit Database(engine::Storage *storage, std::string ns = "");
/// Parsing metadata with type of `types` from bytes, the metadata is a base class of all metadata.
/// When parsing, the bytes will be consumed.
[[nodiscard]] rocksdb::Status ParseMetadata(RedisTypes types, Slice *bytes, Metadata *metadata);
[[nodiscard]] rocksdb::Status GetMetadata(RedisTypes types, const Slice &ns_key, Metadata *metadata);
[[nodiscard]] rocksdb::Status GetMetadata(RedisTypes types, const Slice &ns_key, std::string *raw_value,
Metadata *metadata, Slice *rest);
[[nodiscard]] rocksdb::Status GetRawMetadata(const Slice &ns_key, std::string *bytes);
/// GetMetadata is a helper function to get metadata from the database. It will read the "raw metadata"
/// from underlying storage, and then parse the raw metadata to the specified metadata type.
///
/// \param options The read options, including whether uses a snapshot during reading the metadata.
/// \param types The candidate types of the metadata.
/// \param ns_key The key with namespace of the metadata.
/// \param metadata The output metadata.
[[nodiscard]] rocksdb::Status GetMetadata(GetOptions options, RedisTypes types, const Slice &ns_key,
Metadata *metadata);
/// GetMetadata is a helper function to get metadata from the database. It will read the "raw metadata"
/// from underlying storage, and then parse the raw metadata to the specified metadata type.
///
/// Compared with the above function, this function will also return the rest of the bytes
/// after parsing the metadata.
///
/// \param options The read options, including whether uses a snapshot during reading the metadata.
/// \param types The candidate types of the metadata.
/// \param ns_key The key with namespace of the metadata.
/// \param raw_value Holding the raw metadata.
/// \param metadata The output metadata.
/// \param rest The rest of the bytes after parsing the metadata.
[[nodiscard]] rocksdb::Status GetMetadata(GetOptions options, RedisTypes types, const Slice &ns_key,
std::string *raw_value, Metadata *metadata, Slice *rest);
/// GetRawMetadata is a helper function to get the "raw metadata" from the database without parsing
/// it to the specified metadata type.
///
/// \param options The read options, including whether uses a snapshot during reading the metadata.
/// \param ns_key The key with namespace of the metadata.
/// \param bytes The output raw metadata.
[[nodiscard]] rocksdb::Status GetRawMetadata(GetOptions options, const Slice &ns_key, std::string *bytes);
[[nodiscard]] rocksdb::Status Expire(const Slice &user_key, uint64_t timestamp);
[[nodiscard]] rocksdb::Status Del(const Slice &user_key);
[[nodiscard]] rocksdb::Status MDel(const std::vector<Slice> &keys, uint64_t *deleted_cnt);
Expand Down Expand Up @@ -70,7 +107,6 @@ class Database {

friend class LatestSnapShot;
};

class LatestSnapShot {
public:
explicit LatestSnapShot(engine::Storage *storage) : storage_(storage), snapshot_(storage_->GetDB()->GetSnapshot()) {}
Expand Down
2 changes: 1 addition & 1 deletion src/storage/redis_metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ struct RedisTypes {
return RedisTypes(types);
}

bool Contains(RedisType type) { return types_[type]; }
bool Contains(RedisType type) const { return types_[type]; }

private:
using UnderlyingType = std::bitset<128>;
Expand Down
36 changes: 21 additions & 15 deletions src/types/redis_bitmap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,9 @@ uint32_t SegmentSubKeyIndexForBit(uint32_t bit_offset) {
return (bit_offset / kBitmapSegmentBits) * kBitmapSegmentBytes;
}

rocksdb::Status Bitmap::GetMetadata(const Slice &ns_key, BitmapMetadata *metadata, std::string *raw_value) {
auto s = GetRawMetadata(ns_key, raw_value);
rocksdb::Status Bitmap::GetMetadata(Database::GetOptions get_options, const Slice &ns_key, BitmapMetadata *metadata,
std::string *raw_value) {
auto s = GetRawMetadata(get_options, ns_key, raw_value);
if (!s.ok()) return s;

Slice slice = *raw_value;
Expand All @@ -107,15 +108,15 @@ rocksdb::Status Bitmap::GetBit(const Slice &user_key, uint32_t bit_offset, bool
std::string ns_key = AppendNamespacePrefix(user_key);

BitmapMetadata metadata(false);
rocksdb::Status s = GetMetadata(ns_key, &metadata, &raw_value);
LatestSnapShot ss(storage_);
rocksdb::Status s = GetMetadata(GetOptions{.snapshot = ss.GetSnapShot()}, ns_key, &metadata, &raw_value);
if (!s.ok()) return s.IsNotFound() ? rocksdb::Status::OK() : s;

if (metadata.Type() == kRedisString) {
redis::BitmapString bitmap_string_db(storage_, namespace_);
return bitmap_string_db.GetBit(raw_value, bit_offset, bit);
}

LatestSnapShot ss(storage_);
rocksdb::ReadOptions read_options;
read_options.snapshot = ss.GetSnapShot();
rocksdb::PinnableSlice value;
Expand All @@ -142,7 +143,8 @@ rocksdb::Status Bitmap::GetString(const Slice &user_key, const uint32_t max_btos
std::string ns_key = AppendNamespacePrefix(user_key);

BitmapMetadata metadata(false);
rocksdb::Status s = GetMetadata(ns_key, &metadata, &raw_value);
LatestSnapShot ss(storage_);
rocksdb::Status s = GetMetadata(GetOptions{.snapshot = ss.GetSnapShot()}, ns_key, &metadata, &raw_value);
if (!s.ok()) return s;
if (metadata.size > max_btos_size) {
return rocksdb::Status::Aborted(kErrBitmapStringOutOfRange);
Expand All @@ -152,7 +154,6 @@ rocksdb::Status Bitmap::GetString(const Slice &user_key, const uint32_t max_btos
std::string prefix_key = InternalKey(ns_key, "", metadata.version, storage_->IsSlotIdEncoded()).Encode();

rocksdb::ReadOptions read_options = storage_->DefaultScanOptions();
LatestSnapShot ss(storage_);
read_options.snapshot = ss.GetSnapShot();

auto iter = util::UniqueIterator(storage_, read_options);
Expand Down Expand Up @@ -184,7 +185,7 @@ rocksdb::Status Bitmap::SetBit(const Slice &user_key, uint32_t bit_offset, bool

LockGuard guard(storage_->GetLockManager(), ns_key);
BitmapMetadata metadata;
rocksdb::Status s = GetMetadata(ns_key, &metadata, &raw_value);
rocksdb::Status s = GetMetadata(GetOptions{}, ns_key, &metadata, &raw_value);
if (!s.ok() && !s.IsNotFound()) return s;

if (metadata.Type() == kRedisString) {
Expand Down Expand Up @@ -228,7 +229,8 @@ rocksdb::Status Bitmap::BitCount(const Slice &user_key, int64_t start, int64_t s
std::string ns_key = AppendNamespacePrefix(user_key);

BitmapMetadata metadata(false);
rocksdb::Status s = GetMetadata(ns_key, &metadata, &raw_value);
std::optional<LatestSnapShot> ss(storage_);
rocksdb::Status s = GetMetadata(GetOptions{.snapshot = ss->GetSnapShot()}, ns_key, &metadata, &raw_value);
if (!s.ok()) return s.IsNotFound() ? rocksdb::Status::OK() : s;

/* Convert negative indexes */
Expand All @@ -237,6 +239,9 @@ rocksdb::Status Bitmap::BitCount(const Slice &user_key, int64_t start, int64_t s
}

if (metadata.Type() == kRedisString) {
// Release snapshot ahead for performance, this requires
// `bitmap_string_db` doesn't get anything.
ss = std::nullopt;
redis::BitmapString bitmap_string_db(storage_, namespace_);
return bitmap_string_db.BitCount(raw_value, start, stop, is_bit_index, cnt);
}
Expand All @@ -257,9 +262,8 @@ rocksdb::Status Bitmap::BitCount(const Slice &user_key, int64_t start, int64_t s
auto u_start = static_cast<uint32_t>(start_byte);
auto u_stop = static_cast<uint32_t>(stop_byte);

LatestSnapShot ss(storage_);
rocksdb::ReadOptions read_options;
read_options.snapshot = ss.GetSnapShot();
read_options.snapshot = ss->GetSnapShot();
uint32_t start_index = u_start / kBitmapSegmentBytes;
uint32_t stop_index = u_stop / kBitmapSegmentBytes;
// Don't use multi get to prevent large range query, and take too much memory
Expand Down Expand Up @@ -308,14 +312,16 @@ rocksdb::Status Bitmap::BitPos(const Slice &user_key, bool bit, int64_t start, i
std::string ns_key = AppendNamespacePrefix(user_key);

BitmapMetadata metadata(false);
rocksdb::Status s = GetMetadata(ns_key, &metadata, &raw_value);
std::optional<LatestSnapShot> ss(storage_);
rocksdb::Status s = GetMetadata(GetOptions{.snapshot = ss->GetSnapShot()}, ns_key, &metadata, &raw_value);
if (!s.ok() && !s.IsNotFound()) return s;
if (s.IsNotFound()) {
*pos = bit ? -1 : 0;
return rocksdb::Status::OK();
}

if (metadata.Type() == kRedisString) {
ss = std::nullopt;
redis::BitmapString bitmap_string_db(storage_, namespace_);
return bitmap_string_db.BitPos(raw_value, bit, start, stop, stop_given, pos);
}
Expand All @@ -335,9 +341,8 @@ rocksdb::Status Bitmap::BitPos(const Slice &user_key, bool bit, int64_t start, i
return -1;
};

LatestSnapShot ss(storage_);
rocksdb::ReadOptions read_options;
read_options.snapshot = ss.GetSnapShot();
read_options.snapshot = ss->GetSnapShot();
uint32_t start_index = u_start / kBitmapSegmentBytes;
uint32_t stop_index = u_stop / kBitmapSegmentBytes;
// Don't use multi get to prevent large range query, and take too much memory
Expand Down Expand Up @@ -417,7 +422,7 @@ rocksdb::Status Bitmap::BitOp(BitOpFlags op_flag, const std::string &op_name, co
for (const auto &op_key : op_keys) {
BitmapMetadata metadata(false);
std::string ns_op_key = AppendNamespacePrefix(op_key);
auto s = GetMetadata(ns_op_key, &metadata, &raw_value);
auto s = GetMetadata(GetOptions{}, ns_op_key, &metadata, &raw_value);
if (!s.ok()) {
if (s.IsNotFound()) {
continue;
Expand Down Expand Up @@ -769,7 +774,8 @@ rocksdb::Status Bitmap::bitfield(const Slice &user_key, const std::vector<Bitfie

BitmapMetadata metadata;
std::string raw_value;
auto s = GetMetadata(ns_key, &metadata, &raw_value);
// TODO(mwish): maintain snapshot for read-only bitfield.
auto s = GetMetadata(GetOptions{}, ns_key, &metadata, &raw_value);
if (!s.ok() && !s.IsNotFound()) {
return s;
}
Expand Down
3 changes: 2 additions & 1 deletion src/types/redis_bitmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ class Bitmap : public Database {
std::vector<std::optional<BitfieldValue>> *rets);
static bool bitfieldWriteAheadLog(const ObserverOrUniquePtr<rocksdb::WriteBatchBase> &batch,
const std::vector<BitfieldOperation> &ops);
rocksdb::Status GetMetadata(const Slice &ns_key, BitmapMetadata *metadata, std::string *raw_value);
rocksdb::Status GetMetadata(Database::GetOptions get_options, const Slice &ns_key, BitmapMetadata *metadata,
std::string *raw_value);

template <bool ReadOnly>
static rocksdb::Status runBitfieldOperationsWithCache(SegmentCacheStore &cache,
Expand Down
Loading