diff --git a/db/version_set.cc b/db/version_set.cc index 6eda94bbe..4500d1262 100644 --- a/db/version_set.cc +++ b/db/version_set.cc @@ -5211,6 +5211,8 @@ Status VersionSet::WriteCurrentStateToManifest( } for (auto cfd : *column_family_set_) { + assert(cfd); + if (cfd->IsDropped()) { continue; } @@ -5243,6 +5245,9 @@ Status VersionSet::WriteCurrentStateToManifest( VersionEdit edit; edit.SetColumnFamily(cfd->GetID()); + assert(cfd->current()); + assert(cfd->current()->storage_info()); + for (int level = 0; level < cfd->NumberLevels(); level++) { for (const auto& f : cfd->current()->storage_info()->LevelFiles(level)) { @@ -5254,6 +5259,24 @@ Status VersionSet::WriteCurrentStateToManifest( f->file_checksum, f->file_checksum_func_name); } } + + const auto& blob_files = cfd->current()->storage_info()->GetBlobFiles(); + for (const auto& pair : blob_files) { + const uint64_t blob_file_number = pair.first; + const auto& meta = pair.second; + + assert(meta); + assert(blob_file_number == meta->GetBlobFileNumber()); + + edit.AddBlobFile(blob_file_number, meta->GetTotalBlobCount(), + meta->GetTotalBlobBytes(), meta->GetChecksumMethod(), + meta->GetChecksumValue()); + if (meta->GetGarbageBlobCount() > 0) { + edit.AddBlobFileGarbage(blob_file_number, meta->GetGarbageBlobCount(), + meta->GetGarbageBlobBytes()); + } + } + const auto iter = curr_state.find(cfd->GetID()); assert(iter != curr_state.end()); uint64_t log_number = iter->second.log_number; diff --git a/db/version_set_test.cc b/db/version_set_test.cc index 9f1dfc215..1c73cd713 100644 --- a/db/version_set_test.cc +++ b/db/version_set_test.cc @@ -827,6 +827,82 @@ TEST_F(VersionSetTest, SameColumnFamilyGroupCommit) { EXPECT_EQ(kGroupSize - 1, count); } +TEST_F(VersionSetTest, PersistBlobFileStateInNewManifest) { + // Initialize the database and add a couple of blob files, one with some + // garbage in it, and one without any garbage. + NewDB(); + + VersionEdit edit; + + { + constexpr uint64_t blob_file_number = 123; + constexpr uint64_t total_blob_count = 456; + constexpr uint64_t total_blob_bytes = 77777777; + constexpr char checksum_method[] = "SHA1"; + constexpr char checksum_value[] = + "bdb7f34a59dfa1592ce7f52e99f98c570c525cbd"; + constexpr uint64_t garbage_blob_count = 89; + constexpr uint64_t garbage_blob_bytes = 1000000; + + edit.AddBlobFile(blob_file_number, total_blob_count, total_blob_bytes, + checksum_method, checksum_value); + edit.AddBlobFileGarbage(blob_file_number, garbage_blob_count, + garbage_blob_bytes); + } + + { + constexpr uint64_t blob_file_number = 234; + constexpr uint64_t total_blob_count = 555; + constexpr uint64_t total_blob_bytes = 66666; + constexpr char checksum_method[] = "CRC32"; + constexpr char checksum_value[] = "3d87ff57"; + + edit.AddBlobFile(blob_file_number, total_blob_count, total_blob_bytes, + checksum_method, checksum_value); + } + + assert(versions_); + assert(versions_->GetColumnFamilySet()); + + mutex_.Lock(); + Status s = + versions_->LogAndApply(versions_->GetColumnFamilySet()->GetDefault(), + mutable_cf_options_, &edit, &mutex_); + mutex_.Unlock(); + + ASSERT_OK(s); + + // Force the creation of a new manifest file and make sure metadata for + // the blob files is re-persisted. + size_t addition_encoded = 0; + SyncPoint::GetInstance()->SetCallBack( + "BlobFileAddition::EncodeTo::CustomFields", + [&](void* /* arg */) { ++addition_encoded; }); + + size_t garbage_encoded = 0; + SyncPoint::GetInstance()->SetCallBack( + "BlobFileGarbage::EncodeTo::CustomFields", + [&](void* /* arg */) { ++garbage_encoded; }); + SyncPoint::GetInstance()->EnableProcessing(); + + VersionEdit dummy; + + mutex_.Lock(); + constexpr FSDirectory* db_directory = nullptr; + constexpr bool new_descriptor_log = true; + s = versions_->LogAndApply(versions_->GetColumnFamilySet()->GetDefault(), + mutable_cf_options_, &dummy, &mutex_, db_directory, + new_descriptor_log); + mutex_.Unlock(); + + ASSERT_OK(s); + ASSERT_EQ(addition_encoded, 2); + ASSERT_EQ(garbage_encoded, 1); + + SyncPoint::GetInstance()->DisableProcessing(); + SyncPoint::GetInstance()->ClearAllCallBacks(); +} + class VersionSetAtomicGroupTest : public VersionSetTestBase, public testing::Test { public: