#pragma once
#include <algorithm>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "db/blob/blob_file_addition.h"
#include "db/blob/blob_file_garbage.h"
#include "db/dbformat.h"
#include "db/wal_edit.h"
#include "memory/arena.h"
#include "rocksdb/cache.h"
#include "table/table_reader.h"
#include "util/autovector.h"
namespace ROCKSDB_NAMESPACE {
enum Tag : uint32_t {
kComparator = 1,
kLogNumber = 2,
kNextFileNumber = 3,
kLastSequence = 4,
kCompactPointer = 5,
kDeletedFile = 6,
kNewFile = 7,
kPrevLogNumber = 9,
kMinLogNumberToKeep = 10,
kNewFile2 = 100,
kNewFile3 = 102,
kNewFile4 = 103, kColumnFamily = 200, kColumnFamilyAdd = 201,
kColumnFamilyDrop = 202,
kMaxColumnFamily = 203,
kInAtomicGroup = 300,
kBlobFileAddition = 400,
kBlobFileGarbage,
kTagSafeIgnoreMask = 1 << 13,
kDbId,
kBlobFileAddition_DEPRECATED,
kBlobFileGarbage_DEPRECATED,
kWalAddition,
kWalDeletion,
kFullHistoryTsLow,
kWalAddition2,
kWalDeletion2,
};
enum NewFileCustomTag : uint32_t {
kTerminate = 1, kNeedCompaction = 2,
kMinLogNumberToKeepHack = 3,
kOldestBlobFileNumber = 4,
kOldestAncesterTime = 5,
kFileCreationTime = 6,
kFileChecksum = 7,
kFileChecksumFuncName = 8,
kCustomTagNonSafeIgnoreMask = 1 << 6,
kPathId,
};
class VersionSet;
constexpr uint64_t kFileNumberMask = 0x3FFFFFFFFFFFFFFF;
constexpr uint64_t kUnknownOldestAncesterTime = 0;
constexpr uint64_t kUnknownFileCreationTime = 0;
extern uint64_t PackFileNumberAndPathId(uint64_t number, uint64_t path_id);
struct FileDescriptor {
TableReader* table_reader;
uint64_t packed_number_and_path_id;
uint64_t file_size; SequenceNumber smallest_seqno; SequenceNumber largest_seqno;
FileDescriptor() : FileDescriptor(0, 0, 0) {}
FileDescriptor(uint64_t number, uint32_t path_id, uint64_t _file_size)
: FileDescriptor(number, path_id, _file_size, kMaxSequenceNumber, 0) {}
FileDescriptor(uint64_t number, uint32_t path_id, uint64_t _file_size,
SequenceNumber _smallest_seqno, SequenceNumber _largest_seqno)
: table_reader(nullptr),
packed_number_and_path_id(PackFileNumberAndPathId(number, path_id)),
file_size(_file_size),
smallest_seqno(_smallest_seqno),
largest_seqno(_largest_seqno) {}
FileDescriptor(const FileDescriptor& fd) { *this = fd; }
FileDescriptor& operator=(const FileDescriptor& fd) {
table_reader = fd.table_reader;
packed_number_and_path_id = fd.packed_number_and_path_id;
file_size = fd.file_size;
smallest_seqno = fd.smallest_seqno;
largest_seqno = fd.largest_seqno;
return *this;
}
uint64_t GetNumber() const {
return packed_number_and_path_id & kFileNumberMask;
}
uint32_t GetPathId() const {
return static_cast<uint32_t>(
packed_number_and_path_id / (kFileNumberMask + 1));
}
uint64_t GetFileSize() const { return file_size; }
};
struct FileSampledStats {
FileSampledStats() : num_reads_sampled(0) {}
FileSampledStats(const FileSampledStats& other) { *this = other; }
FileSampledStats& operator=(const FileSampledStats& other) {
num_reads_sampled = other.num_reads_sampled.load();
return *this;
}
mutable std::atomic<uint64_t> num_reads_sampled;
};
struct FileMetaData {
FileDescriptor fd;
InternalKey smallest; InternalKey largest;
Cache::Handle* table_reader_handle = nullptr;
FileSampledStats stats;
uint64_t compensated_file_size = 0;
uint64_t num_entries = 0; uint64_t num_deletions = 0; uint64_t raw_key_size = 0; uint64_t raw_value_size = 0;
int refs = 0;
bool being_compacted = false; bool init_stats_from_file = false;
bool marked_for_compaction = false;
uint64_t oldest_blob_file_number = kInvalidBlobFileNumber;
uint64_t oldest_ancester_time = kUnknownOldestAncesterTime;
uint64_t file_creation_time = kUnknownFileCreationTime;
std::string file_checksum = kUnknownFileChecksum;
std::string file_checksum_func_name = kUnknownFileChecksumFuncName;
FileMetaData() = default;
FileMetaData(uint64_t file, uint32_t file_path_id, uint64_t file_size,
const InternalKey& smallest_key, const InternalKey& largest_key,
const SequenceNumber& smallest_seq,
const SequenceNumber& largest_seq, bool marked_for_compact,
uint64_t oldest_blob_file, uint64_t _oldest_ancester_time,
uint64_t _file_creation_time, const std::string& _file_checksum,
const std::string& _file_checksum_func_name)
: fd(file, file_path_id, file_size, smallest_seq, largest_seq),
smallest(smallest_key),
largest(largest_key),
marked_for_compaction(marked_for_compact),
oldest_blob_file_number(oldest_blob_file),
oldest_ancester_time(_oldest_ancester_time),
file_creation_time(_file_creation_time),
file_checksum(_file_checksum),
file_checksum_func_name(_file_checksum_func_name) {
TEST_SYNC_POINT_CALLBACK("FileMetaData::FileMetaData", this);
}
void UpdateBoundaries(const Slice& key, const Slice& value,
SequenceNumber seqno, ValueType value_type);
void UpdateBoundariesForRange(const InternalKey& start,
const InternalKey& end, SequenceNumber seqno,
const InternalKeyComparator& icmp) {
if (smallest.size() == 0 || icmp.Compare(start, smallest) < 0) {
smallest = start;
}
if (largest.size() == 0 || icmp.Compare(largest, end) < 0) {
largest = end;
}
fd.smallest_seqno = std::min(fd.smallest_seqno, seqno);
fd.largest_seqno = std::max(fd.largest_seqno, seqno);
}
uint64_t TryGetOldestAncesterTime() {
if (oldest_ancester_time != kUnknownOldestAncesterTime) {
return oldest_ancester_time;
} else if (fd.table_reader != nullptr &&
fd.table_reader->GetTableProperties() != nullptr) {
return fd.table_reader->GetTableProperties()->creation_time;
}
return kUnknownOldestAncesterTime;
}
uint64_t TryGetFileCreationTime() {
if (file_creation_time != kUnknownFileCreationTime) {
return file_creation_time;
} else if (fd.table_reader != nullptr &&
fd.table_reader->GetTableProperties() != nullptr) {
return fd.table_reader->GetTableProperties()->file_creation_time;
}
return kUnknownFileCreationTime;
}
};
struct FdWithKeyRange {
FileDescriptor fd;
FileMetaData* file_metadata; Slice smallest_key; Slice largest_key;
FdWithKeyRange()
: fd(),
file_metadata(nullptr),
smallest_key(),
largest_key() {
}
FdWithKeyRange(FileDescriptor _fd, Slice _smallest_key, Slice _largest_key,
FileMetaData* _file_metadata)
: fd(_fd),
file_metadata(_file_metadata),
smallest_key(_smallest_key),
largest_key(_largest_key) {}
};
struct LevelFilesBrief {
size_t num_files;
FdWithKeyRange* files;
LevelFilesBrief() {
num_files = 0;
files = nullptr;
}
};
class VersionEdit {
public:
void Clear();
void SetDBId(const std::string& db_id) {
has_db_id_ = true;
db_id_ = db_id;
}
bool HasDbId() const { return has_db_id_; }
const std::string& GetDbId() const { return db_id_; }
void SetComparatorName(const Slice& name) {
has_comparator_ = true;
comparator_ = name.ToString();
}
bool HasComparatorName() const { return has_comparator_; }
const std::string& GetComparatorName() const { return comparator_; }
void SetLogNumber(uint64_t num) {
has_log_number_ = true;
log_number_ = num;
}
bool HasLogNumber() const { return has_log_number_; }
uint64_t GetLogNumber() const { return log_number_; }
void SetPrevLogNumber(uint64_t num) {
has_prev_log_number_ = true;
prev_log_number_ = num;
}
bool HasPrevLogNumber() const { return has_prev_log_number_; }
uint64_t GetPrevLogNumber() const { return prev_log_number_; }
void SetNextFile(uint64_t num) {
has_next_file_number_ = true;
next_file_number_ = num;
}
bool HasNextFile() const { return has_next_file_number_; }
uint64_t GetNextFile() const { return next_file_number_; }
void SetMaxColumnFamily(uint32_t max_column_family) {
has_max_column_family_ = true;
max_column_family_ = max_column_family;
}
bool HasMaxColumnFamily() const { return has_max_column_family_; }
uint32_t GetMaxColumnFamily() const { return max_column_family_; }
void SetMinLogNumberToKeep(uint64_t num) {
has_min_log_number_to_keep_ = true;
min_log_number_to_keep_ = num;
}
bool HasMinLogNumberToKeep() const { return has_min_log_number_to_keep_; }
uint64_t GetMinLogNumberToKeep() const { return min_log_number_to_keep_; }
void SetLastSequence(SequenceNumber seq) {
has_last_sequence_ = true;
last_sequence_ = seq;
}
bool HasLastSequence() const { return has_last_sequence_; }
SequenceNumber GetLastSequence() const { return last_sequence_; }
void DeleteFile(int level, uint64_t file) {
deleted_files_.emplace(level, file);
}
using DeletedFiles = std::set<std::pair<int, uint64_t>>;
const DeletedFiles& GetDeletedFiles() const { return deleted_files_; }
void AddFile(int level, uint64_t file, uint32_t file_path_id,
uint64_t file_size, const InternalKey& smallest,
const InternalKey& largest, const SequenceNumber& smallest_seqno,
const SequenceNumber& largest_seqno, bool marked_for_compaction,
uint64_t oldest_blob_file_number, uint64_t oldest_ancester_time,
uint64_t file_creation_time, const std::string& file_checksum,
const std::string& file_checksum_func_name) {
assert(smallest_seqno <= largest_seqno);
new_files_.emplace_back(
level, FileMetaData(file, file_path_id, file_size, smallest, largest,
smallest_seqno, largest_seqno,
marked_for_compaction, oldest_blob_file_number,
oldest_ancester_time, file_creation_time,
file_checksum, file_checksum_func_name));
}
void AddFile(int level, const FileMetaData& f) {
assert(f.fd.smallest_seqno <= f.fd.largest_seqno);
new_files_.emplace_back(level, f);
}
using NewFiles = std::vector<std::pair<int, FileMetaData>>;
const NewFiles& GetNewFiles() const { return new_files_; }
void AddBlobFile(uint64_t blob_file_number, uint64_t total_blob_count,
uint64_t total_blob_bytes, std::string checksum_method,
std::string checksum_value) {
blob_file_additions_.emplace_back(
blob_file_number, total_blob_count, total_blob_bytes,
std::move(checksum_method), std::move(checksum_value));
}
void AddBlobFile(BlobFileAddition blob_file_addition) {
blob_file_additions_.emplace_back(std::move(blob_file_addition));
}
using BlobFileAdditions = std::vector<BlobFileAddition>;
const BlobFileAdditions& GetBlobFileAdditions() const {
return blob_file_additions_;
}
void SetBlobFileAdditions(BlobFileAdditions blob_file_additions) {
assert(blob_file_additions_.empty());
blob_file_additions_ = std::move(blob_file_additions);
}
void AddBlobFileGarbage(uint64_t blob_file_number,
uint64_t garbage_blob_count,
uint64_t garbage_blob_bytes) {
blob_file_garbages_.emplace_back(blob_file_number, garbage_blob_count,
garbage_blob_bytes);
}
void AddBlobFileGarbage(BlobFileGarbage blob_file_garbage) {
blob_file_garbages_.emplace_back(std::move(blob_file_garbage));
}
using BlobFileGarbages = std::vector<BlobFileGarbage>;
const BlobFileGarbages& GetBlobFileGarbages() const {
return blob_file_garbages_;
}
void SetBlobFileGarbages(BlobFileGarbages blob_file_garbages) {
assert(blob_file_garbages_.empty());
blob_file_garbages_ = std::move(blob_file_garbages);
}
void AddWal(WalNumber number, WalMetadata metadata = WalMetadata()) {
assert(NumEntries() == wal_additions_.size());
wal_additions_.emplace_back(number, std::move(metadata));
}
const WalAdditions& GetWalAdditions() const { return wal_additions_; }
bool IsWalAddition() const { return !wal_additions_.empty(); }
void DeleteWalsBefore(WalNumber number) {
assert((NumEntries() == 1) == !wal_deletion_.IsEmpty());
wal_deletion_ = WalDeletion(number);
}
const WalDeletion& GetWalDeletion() const { return wal_deletion_; }
bool IsWalDeletion() const { return !wal_deletion_.IsEmpty(); }
bool IsWalManipulation() const {
size_t entries = NumEntries();
return (entries > 0) && ((entries == wal_additions_.size()) ||
(entries == !wal_deletion_.IsEmpty()));
}
size_t NumEntries() const {
return new_files_.size() + deleted_files_.size() +
blob_file_additions_.size() + blob_file_garbages_.size() +
wal_additions_.size() + !wal_deletion_.IsEmpty();
}
void SetColumnFamily(uint32_t column_family_id) {
column_family_ = column_family_id;
}
uint32_t GetColumnFamily() const { return column_family_; }
void AddColumnFamily(const std::string& name) {
assert(!is_column_family_drop_);
assert(!is_column_family_add_);
assert(NumEntries() == 0);
is_column_family_add_ = true;
column_family_name_ = name;
}
void DropColumnFamily() {
assert(!is_column_family_drop_);
assert(!is_column_family_add_);
assert(NumEntries() == 0);
is_column_family_drop_ = true;
}
bool IsColumnFamilyManipulation() const {
return is_column_family_add_ || is_column_family_drop_;
}
bool IsColumnFamilyAdd() const { return is_column_family_add_; }
bool IsColumnFamilyDrop() const { return is_column_family_drop_; }
void MarkAtomicGroup(uint32_t remaining_entries) {
is_in_atomic_group_ = true;
remaining_entries_ = remaining_entries;
}
bool IsInAtomicGroup() const { return is_in_atomic_group_; }
uint32_t GetRemainingEntries() const { return remaining_entries_; }
bool HasFullHistoryTsLow() const { return !full_history_ts_low_.empty(); }
const std::string& GetFullHistoryTsLow() const {
assert(HasFullHistoryTsLow());
return full_history_ts_low_;
}
void SetFullHistoryTsLow(std::string full_history_ts_low) {
assert(!full_history_ts_low.empty());
full_history_ts_low_ = std::move(full_history_ts_low);
}
bool EncodeTo(std::string* dst) const;
Status DecodeFrom(const Slice& src);
std::string DebugString(bool hex_key = false) const;
std::string DebugJSON(int edit_num, bool hex_key = false) const;
private:
friend class ReactiveVersionSet;
friend class VersionEditHandlerBase;
friend class ListColumnFamiliesHandler;
friend class VersionEditHandler;
friend class VersionEditHandlerPointInTime;
friend class DumpManifestHandler;
friend class VersionSet;
friend class Version;
friend class AtomicGroupReadBuffer;
bool GetLevel(Slice* input, int* level, const char** msg);
const char* DecodeNewFile4From(Slice* input);
int max_level_ = 0;
std::string db_id_;
std::string comparator_;
uint64_t log_number_ = 0;
uint64_t prev_log_number_ = 0;
uint64_t next_file_number_ = 0;
uint32_t max_column_family_ = 0;
uint64_t min_log_number_to_keep_ = 0;
SequenceNumber last_sequence_ = 0;
bool has_db_id_ = false;
bool has_comparator_ = false;
bool has_log_number_ = false;
bool has_prev_log_number_ = false;
bool has_next_file_number_ = false;
bool has_max_column_family_ = false;
bool has_min_log_number_to_keep_ = false;
bool has_last_sequence_ = false;
DeletedFiles deleted_files_;
NewFiles new_files_;
BlobFileAdditions blob_file_additions_;
BlobFileGarbages blob_file_garbages_;
WalAdditions wal_additions_;
WalDeletion wal_deletion_;
uint32_t column_family_ = 0;
bool is_column_family_drop_ = false;
bool is_column_family_add_ = false;
std::string column_family_name_;
bool is_in_atomic_group_ = false;
uint32_t remaining_entries_ = 0;
std::string full_history_ts_low_;
};
}