Refactor and unify blob file saving and the logic that finds the oldest live blob file (#9122)
Summary: The patch refactors and unifies the logic in `VersionBuilder::SaveBlobFilesTo` and `VersionBuilder::GetMinOldestBlobFileNumber` by introducing a generic helper that can "merge" the list of `BlobFileMetaData` in the base version with the list of `MutableBlobFileMetaData` representing the updated state after applying a sequence of `VersionEdit`s. This serves as groundwork for subsequent changes that will enable us to determine whether a blob file is live after applying a sequence of edits without calling `VersionBuilder::SaveTo`. Pull Request resolved: https://github.com/facebook/rocksdb/pull/9122 Test Plan: `make check` Reviewed By: riversand963 Differential Revision: D32151472 Pulled By: ltamasi fbshipit-source-id: 11622b475866de823334b8bc21b0e99d913af97e
This commit is contained in:
parent
3018a3e27e
commit
3fbddb1d27
@ -176,6 +176,11 @@ class VersionBuilder::Rep {
|
|||||||
return shared_meta_;
|
return shared_meta_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t GetBlobFileNumber() const {
|
||||||
|
assert(shared_meta_);
|
||||||
|
return shared_meta_->GetBlobFileNumber();
|
||||||
|
}
|
||||||
|
|
||||||
bool HasDelta() const { return !delta_.IsEmpty(); }
|
bool HasDelta() const { return !delta_.IsEmpty(); }
|
||||||
|
|
||||||
const std::unordered_set<uint64_t>& GetLinkedSsts() const {
|
const std::unordered_set<uint64_t>& GetLinkedSsts() const {
|
||||||
@ -309,7 +314,7 @@ class VersionBuilder::Rep {
|
|||||||
(*expected_linked_ssts)[blob_file_number].emplace(table_file_number);
|
(*expected_linked_ssts)[blob_file_number].emplace(table_file_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Checker>
|
template <typename Checker>
|
||||||
Status CheckConsistencyDetailsForLevel(
|
Status CheckConsistencyDetailsForLevel(
|
||||||
const VersionStorageInfo* vstorage, int level, Checker checker,
|
const VersionStorageInfo* vstorage, int level, Checker checker,
|
||||||
const std::string& sync_point,
|
const std::string& sync_point,
|
||||||
@ -669,28 +674,6 @@ class VersionBuilder::Rep {
|
|||||||
return meta->oldest_blob_file_number;
|
return meta->oldest_blob_file_number;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t GetMinOldestBlobFileNumber() const {
|
|
||||||
uint64_t min_oldest_blob_file_num = std::numeric_limits<uint64_t>::max();
|
|
||||||
for (int level = 0; level < num_levels_; ++level) {
|
|
||||||
const auto& base_files = base_vstorage_->LevelFiles(level);
|
|
||||||
for (const auto* fmeta : base_files) {
|
|
||||||
assert(fmeta);
|
|
||||||
min_oldest_blob_file_num =
|
|
||||||
std::min(min_oldest_blob_file_num, fmeta->oldest_blob_file_number);
|
|
||||||
}
|
|
||||||
const auto& added_files = levels_[level].added_files;
|
|
||||||
for (const auto& elem : added_files) {
|
|
||||||
assert(elem.second);
|
|
||||||
min_oldest_blob_file_num = std::min(
|
|
||||||
min_oldest_blob_file_num, elem.second->oldest_blob_file_number);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (min_oldest_blob_file_num == std::numeric_limits<uint64_t>::max()) {
|
|
||||||
min_oldest_blob_file_num = kInvalidBlobFileNumber;
|
|
||||||
}
|
|
||||||
return min_oldest_blob_file_num;
|
|
||||||
}
|
|
||||||
|
|
||||||
Status ApplyFileDeletion(int level, uint64_t file_number) {
|
Status ApplyFileDeletion(int level, uint64_t file_number) {
|
||||||
assert(level != VersionStorageInfo::FileLocation::Invalid().GetLevel());
|
assert(level != VersionStorageInfo::FileLocation::Invalid().GetLevel());
|
||||||
|
|
||||||
@ -864,48 +847,26 @@ class VersionBuilder::Rep {
|
|||||||
return Status::OK();
|
return Status::OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::shared_ptr<BlobFileMetaData> CreateBlobFileMetaData(
|
// Helper function template for merging the blob file metadata from the base
|
||||||
const MutableBlobFileMetaData& mutable_meta) {
|
// version with the mutable metadata representing the state after applying the
|
||||||
return BlobFileMetaData::Create(
|
// edits. The function objects process_base and process_mutable are
|
||||||
mutable_meta.GetSharedMeta(), mutable_meta.GetLinkedSsts(),
|
// respectively called to handle a base version object when there is no
|
||||||
mutable_meta.GetGarbageBlobCount(), mutable_meta.GetGarbageBlobBytes());
|
// matching mutable object, and a mutable object when there is no matching
|
||||||
}
|
// base version object. process_both is called to perform the merge when a
|
||||||
|
// given blob file appears both in the base version and the mutable list. The
|
||||||
// Add the blob file specified by meta to *vstorage if it is determined to
|
// helper stops processing objects if a function object returns false. Blob
|
||||||
// contain valid data (blobs). We make this decision based on the amount
|
// files with a file number below first_blob_file are not processed.
|
||||||
// of garbage in the file, and whether the file or any lower-numbered blob
|
template <typename ProcessBase, typename ProcessMutable, typename ProcessBoth>
|
||||||
// files have any linked SSTs. The latter condition is tracked using the
|
void MergeBlobFileMetas(uint64_t first_blob_file, ProcessBase process_base,
|
||||||
// flag *found_first_non_empty.
|
ProcessMutable process_mutable,
|
||||||
void AddBlobFileIfNeeded(VersionStorageInfo* vstorage,
|
ProcessBoth process_both) const {
|
||||||
const std::shared_ptr<BlobFileMetaData>& meta,
|
|
||||||
bool* found_first_non_empty) const {
|
|
||||||
assert(vstorage);
|
|
||||||
assert(meta);
|
|
||||||
assert(found_first_non_empty);
|
|
||||||
|
|
||||||
if (!meta->GetLinkedSsts().empty()) {
|
|
||||||
(*found_first_non_empty) = true;
|
|
||||||
} else if (!(*found_first_non_empty) ||
|
|
||||||
meta->GetGarbageBlobCount() >= meta->GetTotalBlobCount()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
vstorage->AddBlobFile(meta);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merge the blob file metadata from the base version with the changes (edits)
|
|
||||||
// applied, and save the result into *vstorage.
|
|
||||||
void SaveBlobFilesTo(VersionStorageInfo* vstorage) const {
|
|
||||||
assert(base_vstorage_);
|
assert(base_vstorage_);
|
||||||
assert(vstorage);
|
|
||||||
|
|
||||||
bool found_first_non_empty = false;
|
|
||||||
|
|
||||||
const auto& base_blob_files = base_vstorage_->GetBlobFiles();
|
const auto& base_blob_files = base_vstorage_->GetBlobFiles();
|
||||||
auto base_it = base_blob_files.begin();
|
auto base_it = base_blob_files.lower_bound(first_blob_file);
|
||||||
const auto base_it_end = base_blob_files.end();
|
const auto base_it_end = base_blob_files.end();
|
||||||
|
|
||||||
auto mutable_it = mutable_blob_file_metas_.begin();
|
auto mutable_it = mutable_blob_file_metas_.lower_bound(first_blob_file);
|
||||||
const auto mutable_it_end = mutable_blob_file_metas_.end();
|
const auto mutable_it_end = mutable_blob_file_metas_.end();
|
||||||
|
|
||||||
while (base_it != base_it_end && mutable_it != mutable_it_end) {
|
while (base_it != base_it_end && mutable_it != mutable_it_end) {
|
||||||
@ -915,15 +876,17 @@ class VersionBuilder::Rep {
|
|||||||
if (base_blob_file_number < mutable_blob_file_number) {
|
if (base_blob_file_number < mutable_blob_file_number) {
|
||||||
const auto& base_meta = base_it->second;
|
const auto& base_meta = base_it->second;
|
||||||
|
|
||||||
AddBlobFileIfNeeded(vstorage, base_meta, &found_first_non_empty);
|
if (!process_base(base_meta)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
++base_it;
|
++base_it;
|
||||||
} else if (mutable_blob_file_number < base_blob_file_number) {
|
} else if (mutable_blob_file_number < base_blob_file_number) {
|
||||||
const auto& mutable_meta = mutable_it->second;
|
const auto& mutable_meta = mutable_it->second;
|
||||||
|
|
||||||
auto meta = CreateBlobFileMetaData(mutable_meta);
|
if (!process_mutable(mutable_meta)) {
|
||||||
|
return;
|
||||||
AddBlobFileIfNeeded(vstorage, meta, &found_first_non_empty);
|
}
|
||||||
|
|
||||||
++mutable_it;
|
++mutable_it;
|
||||||
} else {
|
} else {
|
||||||
@ -932,21 +895,8 @@ class VersionBuilder::Rep {
|
|||||||
const auto& base_meta = base_it->second;
|
const auto& base_meta = base_it->second;
|
||||||
const auto& mutable_meta = mutable_it->second;
|
const auto& mutable_meta = mutable_it->second;
|
||||||
|
|
||||||
assert(base_meta);
|
if (!process_both(base_meta, mutable_meta)) {
|
||||||
assert(base_meta->GetSharedMeta() == mutable_meta.GetSharedMeta());
|
return;
|
||||||
|
|
||||||
if (!mutable_meta.HasDelta()) {
|
|
||||||
assert(base_meta->GetGarbageBlobCount() ==
|
|
||||||
mutable_meta.GetGarbageBlobCount());
|
|
||||||
assert(base_meta->GetGarbageBlobBytes() ==
|
|
||||||
mutable_meta.GetGarbageBlobBytes());
|
|
||||||
assert(base_meta->GetLinkedSsts() == mutable_meta.GetLinkedSsts());
|
|
||||||
|
|
||||||
AddBlobFileIfNeeded(vstorage, base_meta, &found_first_non_empty);
|
|
||||||
} else {
|
|
||||||
auto meta = CreateBlobFileMetaData(mutable_meta);
|
|
||||||
|
|
||||||
AddBlobFileIfNeeded(vstorage, meta, &found_first_non_empty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
++base_it;
|
++base_it;
|
||||||
@ -957,7 +907,9 @@ class VersionBuilder::Rep {
|
|||||||
while (base_it != base_it_end) {
|
while (base_it != base_it_end) {
|
||||||
const auto& base_meta = base_it->second;
|
const auto& base_meta = base_it->second;
|
||||||
|
|
||||||
AddBlobFileIfNeeded(vstorage, base_meta, &found_first_non_empty);
|
if (!process_base(base_meta)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
++base_it;
|
++base_it;
|
||||||
}
|
}
|
||||||
@ -965,14 +917,142 @@ class VersionBuilder::Rep {
|
|||||||
while (mutable_it != mutable_it_end) {
|
while (mutable_it != mutable_it_end) {
|
||||||
const auto& mutable_meta = mutable_it->second;
|
const auto& mutable_meta = mutable_it->second;
|
||||||
|
|
||||||
auto meta = CreateBlobFileMetaData(mutable_meta);
|
if (!process_mutable(mutable_meta)) {
|
||||||
|
return;
|
||||||
AddBlobFileIfNeeded(vstorage, meta, &found_first_non_empty);
|
}
|
||||||
|
|
||||||
++mutable_it;
|
++mutable_it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper function template for finding the first blob file that has linked
|
||||||
|
// SSTs.
|
||||||
|
template <typename Meta>
|
||||||
|
static bool CheckLinkedSsts(const Meta& meta,
|
||||||
|
uint64_t* min_oldest_blob_file_num) {
|
||||||
|
assert(min_oldest_blob_file_num);
|
||||||
|
|
||||||
|
if (!meta.GetLinkedSsts().empty()) {
|
||||||
|
assert(*min_oldest_blob_file_num == kInvalidBlobFileNumber);
|
||||||
|
|
||||||
|
*min_oldest_blob_file_num = meta.GetBlobFileNumber();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the oldest blob file that has linked SSTs.
|
||||||
|
uint64_t GetMinOldestBlobFileNumber() const {
|
||||||
|
uint64_t min_oldest_blob_file_num = kInvalidBlobFileNumber;
|
||||||
|
|
||||||
|
auto process_base =
|
||||||
|
[&min_oldest_blob_file_num](
|
||||||
|
const std::shared_ptr<BlobFileMetaData>& base_meta) {
|
||||||
|
assert(base_meta);
|
||||||
|
|
||||||
|
return CheckLinkedSsts(*base_meta, &min_oldest_blob_file_num);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto process_mutable = [&min_oldest_blob_file_num](
|
||||||
|
const MutableBlobFileMetaData& mutable_meta) {
|
||||||
|
return CheckLinkedSsts(mutable_meta, &min_oldest_blob_file_num);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto process_both = [&min_oldest_blob_file_num](
|
||||||
|
const std::shared_ptr<BlobFileMetaData>& base_meta,
|
||||||
|
const MutableBlobFileMetaData& mutable_meta) {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
assert(base_meta);
|
||||||
|
assert(base_meta->GetSharedMeta() == mutable_meta.GetSharedMeta());
|
||||||
|
#else
|
||||||
|
(void)base_meta;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Look at mutable_meta since it supersedes *base_meta
|
||||||
|
return CheckLinkedSsts(mutable_meta, &min_oldest_blob_file_num);
|
||||||
|
};
|
||||||
|
|
||||||
|
MergeBlobFileMetas(kInvalidBlobFileNumber, process_base, process_mutable,
|
||||||
|
process_both);
|
||||||
|
|
||||||
|
return min_oldest_blob_file_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::shared_ptr<BlobFileMetaData> CreateBlobFileMetaData(
|
||||||
|
const MutableBlobFileMetaData& mutable_meta) {
|
||||||
|
return BlobFileMetaData::Create(
|
||||||
|
mutable_meta.GetSharedMeta(), mutable_meta.GetLinkedSsts(),
|
||||||
|
mutable_meta.GetGarbageBlobCount(), mutable_meta.GetGarbageBlobBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the blob file specified by meta to *vstorage if it is determined to
|
||||||
|
// contain valid data (blobs).
|
||||||
|
template <typename Meta>
|
||||||
|
static void AddBlobFileIfNeeded(VersionStorageInfo* vstorage, Meta&& meta) {
|
||||||
|
assert(vstorage);
|
||||||
|
assert(meta);
|
||||||
|
|
||||||
|
if (meta->GetLinkedSsts().empty() &&
|
||||||
|
meta->GetGarbageBlobCount() >= meta->GetTotalBlobCount()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vstorage->AddBlobFile(std::forward<Meta>(meta));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge the blob file metadata from the base version with the changes (edits)
|
||||||
|
// applied, and save the result into *vstorage.
|
||||||
|
void SaveBlobFilesTo(VersionStorageInfo* vstorage) const {
|
||||||
|
assert(vstorage);
|
||||||
|
|
||||||
|
const uint64_t oldest_blob_file_with_linked_ssts =
|
||||||
|
GetMinOldestBlobFileNumber();
|
||||||
|
|
||||||
|
auto process_base =
|
||||||
|
[vstorage](const std::shared_ptr<BlobFileMetaData>& base_meta) {
|
||||||
|
assert(base_meta);
|
||||||
|
|
||||||
|
AddBlobFileIfNeeded(vstorage, base_meta);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto process_mutable =
|
||||||
|
[vstorage](const MutableBlobFileMetaData& mutable_meta) {
|
||||||
|
AddBlobFileIfNeeded(vstorage, CreateBlobFileMetaData(mutable_meta));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto process_both = [vstorage](
|
||||||
|
const std::shared_ptr<BlobFileMetaData>& base_meta,
|
||||||
|
const MutableBlobFileMetaData& mutable_meta) {
|
||||||
|
assert(base_meta);
|
||||||
|
assert(base_meta->GetSharedMeta() == mutable_meta.GetSharedMeta());
|
||||||
|
|
||||||
|
if (!mutable_meta.HasDelta()) {
|
||||||
|
assert(base_meta->GetGarbageBlobCount() ==
|
||||||
|
mutable_meta.GetGarbageBlobCount());
|
||||||
|
assert(base_meta->GetGarbageBlobBytes() ==
|
||||||
|
mutable_meta.GetGarbageBlobBytes());
|
||||||
|
assert(base_meta->GetLinkedSsts() == mutable_meta.GetLinkedSsts());
|
||||||
|
|
||||||
|
AddBlobFileIfNeeded(vstorage, base_meta);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddBlobFileIfNeeded(vstorage, CreateBlobFileMetaData(mutable_meta));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
MergeBlobFileMetas(oldest_blob_file_with_linked_ssts, process_base,
|
||||||
|
process_mutable, process_both);
|
||||||
|
}
|
||||||
|
|
||||||
void MaybeAddFile(VersionStorageInfo* vstorage, int level,
|
void MaybeAddFile(VersionStorageInfo* vstorage, int level,
|
||||||
FileMetaData* f) const {
|
FileMetaData* f) const {
|
||||||
const uint64_t file_number = f->fd.GetNumber();
|
const uint64_t file_number = f->fd.GetNumber();
|
||||||
@ -999,7 +1079,7 @@ class VersionBuilder::Rep {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Cmp>
|
template <typename Cmp>
|
||||||
void SaveSSTFilesTo(VersionStorageInfo* vstorage, int level, Cmp cmp) const {
|
void SaveSSTFilesTo(VersionStorageInfo* vstorage, int level, Cmp cmp) const {
|
||||||
// Merge the set of added files with the set of pre-existing files.
|
// Merge the set of added files with the set of pre-existing files.
|
||||||
// Drop any deleted files. Store the result in *vstorage.
|
// Drop any deleted files. Store the result in *vstorage.
|
||||||
|
@ -3044,8 +3044,7 @@ void VersionStorageInfo::AddBlobFile(
|
|||||||
auto it = blob_files_.lower_bound(blob_file_number);
|
auto it = blob_files_.lower_bound(blob_file_number);
|
||||||
assert(it == blob_files_.end() || it->first != blob_file_number);
|
assert(it == blob_files_.end() || it->first != blob_file_number);
|
||||||
|
|
||||||
blob_files_.insert(
|
blob_files_.emplace_hint(it, blob_file_number, std::move(blob_file_meta));
|
||||||
it, BlobFiles::value_type(blob_file_number, std::move(blob_file_meta)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Version::PrepareApply() need to be called before calling the function, or
|
// Version::PrepareApply() need to be called before calling the function, or
|
||||||
|
Loading…
Reference in New Issue
Block a user