mirror of
https://github.com/facebook/rocksdb.git
synced 2026-07-07 14:47:40 +08:00
Compare commits
10 Commits
f2c0eb41ef
...
v10.8.3
| Author | SHA1 | Date | |
|---|---|---|---|
| 6bf472dace | |||
| 3a196076d1 | |||
| 0a7ce8204d | |||
| 41c6640085 | |||
| f324397aca | |||
| 4de3ce3b01 | |||
| 92ede49ffd | |||
| 840fad9610 | |||
| 2db33019f5 | |||
| 5202d73c1e |
@@ -4844,6 +4844,12 @@ cpp_unittest_wrapper(name="db_encryption_test",
|
||||
extra_compiler_flags=[])
|
||||
|
||||
|
||||
cpp_unittest_wrapper(name="db_etc3_test",
|
||||
srcs=["db/db_etc3_test.cc"],
|
||||
deps=[":rocksdb_test_lib"],
|
||||
extra_compiler_flags=[])
|
||||
|
||||
|
||||
cpp_unittest_wrapper(name="db_flush_test",
|
||||
srcs=["db/db_flush_test.cc"],
|
||||
deps=[":rocksdb_test_lib"],
|
||||
|
||||
@@ -1359,6 +1359,7 @@ if(WITH_TESTS)
|
||||
db/db_clip_test.cc
|
||||
db/db_dynamic_level_test.cc
|
||||
db/db_encryption_test.cc
|
||||
db/db_etc3_test.cc
|
||||
db/db_flush_test.cc
|
||||
db/db_inplace_update_test.cc
|
||||
db/db_io_failure_test.cc
|
||||
|
||||
+34
@@ -1,6 +1,40 @@
|
||||
# Rocksdb Change Log
|
||||
> NOTE: Entries for next release do not go here. Follow instructions in `unreleased_history/README.txt`
|
||||
|
||||
## 10.8.3 (11/10/2025)
|
||||
### New Features
|
||||
* Add a GetColumnFamilyMetaData API variant in DB to get the SST files intersecting a given key range.
|
||||
|
||||
## 10.8.2 (11/07/2025)
|
||||
### New Features
|
||||
* Added an auto-tuning feature for DB manifest file size that also (by default) improves the safety of existing configurations in case `max_manifest_file_size` is repeatedly exceeded. The new recommendation is to set `max_manifest_file_size` to something small like 1MB and tune `max_manifest_space_amp_pct` as needed to balance write amp and space amp in the manifest. Refer to comments on those options in `DBOptions` for details. Both options are (now) mutable.
|
||||
* Add a new option allow_trivial_move in CompactionOptions to allow CompactFiles to perform trivial move if possible. By default the flag of allow_trivial_move is false, so it preserve the original behavior.
|
||||
|
||||
## 10.8.1 (10/29/2025)
|
||||
### Behavior Changes
|
||||
* PosixWritableFile now repositions the seek pointer to the new end of file after a call to Truncate.
|
||||
|
||||
## 10.8.0 (10/21/2025)
|
||||
### New Features
|
||||
* Add kFSPrefetch to FSSupportedOps enum to allow file systems to indicate prefetch support capability, avoiding unnecessary prefetch system calls on file systems that don't support them.
|
||||
* Added experimental support `OpenAndCompactOptions::allow_resumption` for resumable compaction that persists progress during `OpenAndCompact()`, allowing interrupted compactions to resume from the last progress persitence. The default behavior is to not persist progress.
|
||||
|
||||
### Public API Changes
|
||||
* Allow specifying output temperature in CompactionOptions
|
||||
* Added `DB::FlushWAL(const FlushWALOptions&)` as an alternative to `DB::FlushWAL(bool sync)`, where `FlushWALOptions` includes a new `rate_limiter_priority` field (default `Env::IO_TOTAL`) that allows rate limiting and priority passing of manual WAL flush's IO operations.
|
||||
* The MultiScan API contract is updated. After a multi scan range got prepared with Prepare API call, the following seeks must seek the start of each prepared scan range in order. In addition, when limit is set, upper bound must be set to the same value of limit before each seek
|
||||
|
||||
### Behavior Changes
|
||||
* `kChangeTemperature` FIFO compaction will now honor `compaction_target_temp` to all levels regardless of `cf_options::last_level_temperature`
|
||||
* Allow UDIs with a non BytewiseComparator
|
||||
|
||||
### Bug Fixes
|
||||
* Fix incorrect MultiScan seek error status due to bugs in handling range limit falling between adjacent SST files key range.
|
||||
* Fix a bug in Page unpinning in MultiScan
|
||||
|
||||
### Performance Improvements
|
||||
* Fixed a performance regression in LZ4 compression that started in version 10.6.0
|
||||
|
||||
## 10.7.0 (09/19/2025)
|
||||
### New Features
|
||||
* Add the fail_if_no_udi_on_open flag in BlockBasedTableOption to control whether a missing user defined index block in a SST is a hard error or not.
|
||||
|
||||
@@ -1496,6 +1496,9 @@ db_test: $(OBJ_DIR)/db/db_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
db_test2: $(OBJ_DIR)/db/db_test2.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
db_etc3_test: $(OBJ_DIR)/db/db_etc3_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
compression_test: $(OBJ_DIR)/util/compression_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
|
||||
@@ -534,6 +534,232 @@ TEST_F(CompactFilesTest, GetCompactionJobInfo) {
|
||||
delete db;
|
||||
}
|
||||
|
||||
// Helper function to generate zero-padded keys
|
||||
// e.g., MakeKey("a", 5) -> "a05", MakeKey("b", 42) -> "b42"
|
||||
static std::string MakeKey(const std::string& prefix, int index) {
|
||||
return prefix + (index < 10 ? "0" : "") + std::to_string(index);
|
||||
}
|
||||
|
||||
TEST_F(CompactFilesTest, TrivialMoveNonOverlappingFiles) {
|
||||
Options options;
|
||||
options.create_if_missing = true;
|
||||
options.disable_auto_compactions = true;
|
||||
options.compression = kNoCompression;
|
||||
options.level_compaction_dynamic_level_bytes = false;
|
||||
|
||||
DB* db = nullptr;
|
||||
ASSERT_OK(DestroyDB(db_name_, options));
|
||||
Status s = DB::Open(options, db_name_, &db);
|
||||
ASSERT_OK(s);
|
||||
ASSERT_NE(db, nullptr);
|
||||
|
||||
// Create 3 non-overlapping files in L0
|
||||
// File 1: keys [a00-a99]
|
||||
for (int i = 0; i < 100; i++) {
|
||||
std::string key = MakeKey("a", i);
|
||||
ASSERT_OK(db->Put(WriteOptions(), key, "value_" + key));
|
||||
}
|
||||
ASSERT_OK(db->Flush(FlushOptions()));
|
||||
|
||||
// File 2: keys [b00-b99]
|
||||
for (int i = 0; i < 100; i++) {
|
||||
std::string key = MakeKey("b", i);
|
||||
ASSERT_OK(db->Put(WriteOptions(), key, "value_" + key));
|
||||
}
|
||||
ASSERT_OK(db->Flush(FlushOptions()));
|
||||
|
||||
// File 3: keys [c00-c99]
|
||||
for (int i = 0; i < 100; i++) {
|
||||
std::string key = MakeKey("c", i);
|
||||
ASSERT_OK(db->Put(WriteOptions(), key, "value_" + key));
|
||||
}
|
||||
ASSERT_OK(db->Flush(FlushOptions()));
|
||||
|
||||
// Verify files are in L0
|
||||
ColumnFamilyMetaData meta;
|
||||
db->GetColumnFamilyMetaData(&meta);
|
||||
ASSERT_EQ(meta.levels[0].files.size(), 3);
|
||||
ASSERT_EQ(meta.levels[1].files.size(), 0);
|
||||
|
||||
// Get L0 files
|
||||
std::vector<std::string> l0_files;
|
||||
for (const auto& file : meta.levels[0].files) {
|
||||
l0_files.push_back(file.db_path + "/" + file.name);
|
||||
}
|
||||
|
||||
CompactionOptions compact_option;
|
||||
compact_option.allow_trivial_move = true;
|
||||
// Compact all L0 files to L1 (non-overlapping in L1)
|
||||
ASSERT_OK(db->CompactFiles(compact_option, l0_files, 1));
|
||||
|
||||
// Verify files are now in L1
|
||||
db->GetColumnFamilyMetaData(&meta);
|
||||
ASSERT_EQ(meta.levels[0].files.size(), 0);
|
||||
ASSERT_EQ(meta.levels[1].files.size(), 3);
|
||||
|
||||
// Get the first file from L1 (should be the one with keys a00-a99)
|
||||
std::string l1_file_to_move;
|
||||
std::vector<std::string> l1_files_to_move_later;
|
||||
uint64_t l1_file_number = 0;
|
||||
for (const auto& file : meta.levels[1].files) {
|
||||
if (file.smallestkey[0] == 'a') {
|
||||
l1_file_to_move = file.db_path + "/" + file.name;
|
||||
l1_file_number = file.file_number;
|
||||
} else {
|
||||
l1_files_to_move_later.push_back(file.db_path + "/" + file.name);
|
||||
}
|
||||
}
|
||||
ASSERT_FALSE(l1_file_to_move.empty());
|
||||
|
||||
// Set up sync point to verify trivial move path is taken
|
||||
bool trivial_move_executed = false;
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::CompactFilesImpl:TrivialMove",
|
||||
[&](void* /*arg*/) { trivial_move_executed = true; });
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
// Move the file from L1 to L6 - this should be a trivial move
|
||||
// because the file doesn't overlap with anything in L6
|
||||
std::vector<std::string> files_to_move = {l1_file_to_move};
|
||||
ASSERT_OK(db->CompactFiles(compact_option, files_to_move, 6));
|
||||
|
||||
// Verify trivial move was executed
|
||||
ASSERT_TRUE(trivial_move_executed);
|
||||
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
|
||||
// Verify the file is now in L6
|
||||
db->GetColumnFamilyMetaData(&meta);
|
||||
ASSERT_EQ(meta.levels[1].files.size(), 2); // Two files remain in L1
|
||||
ASSERT_EQ(meta.levels[6].files.size(), 1); // One file in L6
|
||||
|
||||
// Verify it's the correct file in L6
|
||||
bool found_file_in_l6 = false;
|
||||
for (const auto& file : meta.levels[6].files) {
|
||||
if (file.file_number == l1_file_number) {
|
||||
found_file_in_l6 = true;
|
||||
// Verify key range hasn't changed
|
||||
ASSERT_EQ(file.smallestkey[0], 'a');
|
||||
ASSERT_EQ(file.largestkey[0], 'a');
|
||||
break;
|
||||
}
|
||||
}
|
||||
ASSERT_TRUE(found_file_in_l6);
|
||||
|
||||
// Move the other 2 files from L1 to L6, with allow_trivial_move set to false.
|
||||
// This will trigger a normal compaction, so the 2 files will be compacted
|
||||
// into a single file in L6.
|
||||
ASSERT_OK(db->CompactFiles(CompactionOptions(), l1_files_to_move_later, 6));
|
||||
|
||||
// Verify files in L6
|
||||
db->GetColumnFamilyMetaData(&meta);
|
||||
ASSERT_EQ(meta.levels[1].files.size(), 0); // Zero files remain in L1
|
||||
ASSERT_EQ(meta.levels[6].files.size(), 2); // Two file in L6
|
||||
|
||||
// Verify data integrity - all keys should still be readable
|
||||
for (int i = 0; i < 100; i++) {
|
||||
std::string key = MakeKey("a", i);
|
||||
std::string value;
|
||||
ASSERT_OK(db->Get(ReadOptions(), key, &value));
|
||||
ASSERT_EQ(value, "value_" + key);
|
||||
}
|
||||
|
||||
delete db;
|
||||
}
|
||||
|
||||
TEST_F(CompactFilesTest, TrivialMoveBlockedByOverlap) {
|
||||
Options options;
|
||||
options.create_if_missing = true;
|
||||
options.disable_auto_compactions = true;
|
||||
options.compression = kNoCompression;
|
||||
options.level_compaction_dynamic_level_bytes = false;
|
||||
options.num_levels = 7;
|
||||
|
||||
DB* db = nullptr;
|
||||
ASSERT_OK(DestroyDB(db_name_, options));
|
||||
Status s = DB::Open(options, db_name_, &db);
|
||||
ASSERT_OK(s);
|
||||
ASSERT_NE(db, nullptr);
|
||||
|
||||
// Create a file in L6 with keys [m00-m99] (wide range)
|
||||
for (int i = 0; i < 100; i++) {
|
||||
std::string key = MakeKey("m", i);
|
||||
ASSERT_OK(db->Put(WriteOptions(), key, "value_" + key));
|
||||
}
|
||||
ASSERT_OK(db->Flush(FlushOptions()));
|
||||
|
||||
// Get L0 file
|
||||
ColumnFamilyMetaData meta;
|
||||
db->GetColumnFamilyMetaData(&meta);
|
||||
std::vector<std::string> l0_files;
|
||||
for (const auto& file : meta.levels[0].files) {
|
||||
l0_files.push_back(file.db_path + "/" + file.name);
|
||||
}
|
||||
|
||||
CompactionOptions compact_option;
|
||||
compact_option.allow_trivial_move = true;
|
||||
|
||||
// Move to L6
|
||||
ASSERT_OK(db->CompactFiles(compact_option, l0_files, 6));
|
||||
|
||||
// Now create a file in L1 with overlapping keys [m50-m60]
|
||||
for (int i = 50; i <= 60; i++) {
|
||||
std::string key = "m" + std::to_string(i);
|
||||
ASSERT_OK(db->Put(WriteOptions(), key, "updated_value_" + key));
|
||||
}
|
||||
ASSERT_OK(db->Flush(FlushOptions()));
|
||||
|
||||
// Get the L0 file
|
||||
db->GetColumnFamilyMetaData(&meta);
|
||||
std::vector<std::string> l0_files_2;
|
||||
for (const auto& file : meta.levels[0].files) {
|
||||
l0_files_2.push_back(file.db_path + "/" + file.name);
|
||||
}
|
||||
|
||||
// Move to L1
|
||||
ASSERT_OK(db->CompactFiles(compact_option, l0_files_2, 1));
|
||||
|
||||
// Get the L1 file
|
||||
db->GetColumnFamilyMetaData(&meta);
|
||||
ASSERT_EQ(meta.levels[1].files.size(), 1);
|
||||
std::string l1_file =
|
||||
meta.levels[1].files[0].db_path + "/" + meta.levels[1].files[0].name;
|
||||
|
||||
// Set up sync point to verify full compaction path is taken
|
||||
bool trivial_move_executed = false;
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::CompactFilesImpl:TrivialMove",
|
||||
[&](void* /*arg*/) { trivial_move_executed = true; });
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
// Try to move from L1 to L6 - this should NOT be a trivial move
|
||||
// because the file overlaps with the existing file in L6
|
||||
ASSERT_OK(db->CompactFiles(compact_option, {l1_file}, 6));
|
||||
|
||||
// Verify trivial move was NOT executed (full compaction happened)
|
||||
ASSERT_FALSE(trivial_move_executed);
|
||||
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
|
||||
// Verify the result - should have merged data in L6
|
||||
db->GetColumnFamilyMetaData(&meta);
|
||||
ASSERT_EQ(meta.levels[1].files.size(), 0); // L1 should be empty
|
||||
// L6 should have the merged file (may be 1 file if merged, or 2 if not)
|
||||
ASSERT_GE(meta.levels[6].files.size(), 1);
|
||||
|
||||
// Verify updated values are present
|
||||
for (int i = 50; i <= 60; i++) {
|
||||
std::string key = "m" + std::to_string(i);
|
||||
std::string value;
|
||||
ASSERT_OK(db->Get(ReadOptions(), key, &value));
|
||||
ASSERT_EQ(value, "updated_value_" + key);
|
||||
}
|
||||
|
||||
delete db;
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
@@ -812,20 +812,19 @@ Status CompactionJob::SyncOutputDirectories() {
|
||||
Status CompactionJob::VerifyOutputFiles() {
|
||||
Status status;
|
||||
std::vector<port::Thread> thread_pool;
|
||||
std::vector<const CompactionOutputs::Output*> files_output;
|
||||
for (const auto& state : compact_->sub_compact_states) {
|
||||
for (const auto& output : state.GetOutputs()) {
|
||||
files_output.emplace_back(&output);
|
||||
}
|
||||
}
|
||||
ColumnFamilyData* cfd = compact_->compaction->column_family_data();
|
||||
std::atomic<size_t> next_file_idx(0);
|
||||
auto verify_table = [&](Status& output_status) {
|
||||
while (true) {
|
||||
size_t file_idx = next_file_idx.fetch_add(1);
|
||||
if (file_idx >= files_output.size()) {
|
||||
break;
|
||||
}
|
||||
VerifyOutputFlags verify_output_flags =
|
||||
compact_->compaction->mutable_cf_options().verify_output_flags;
|
||||
|
||||
// For backward compatibility
|
||||
if (paranoid_file_checks_) {
|
||||
verify_output_flags |= VerifyOutputFlags::kVerifyIteration;
|
||||
verify_output_flags |= VerifyOutputFlags::kEnableForLocalCompaction;
|
||||
verify_output_flags |= VerifyOutputFlags::kEnableForRemoteCompaction;
|
||||
}
|
||||
|
||||
auto verify_table = [&](SubcompactionState& subcompaction_state) {
|
||||
for (const auto& output_file : subcompaction_state.GetOutputs()) {
|
||||
// Verify that the table is usable
|
||||
// We set for_compaction to false and don't
|
||||
// OptimizeForCompactionTableRead here because this is a special case
|
||||
@@ -834,13 +833,19 @@ Status CompactionJob::VerifyOutputFiles() {
|
||||
// verification as user reads since the goal is to cache it here for
|
||||
// further user reads
|
||||
ReadOptions verify_table_read_options(Env::IOActivity::kCompaction);
|
||||
verify_table_read_options.verify_checksums = true;
|
||||
verify_table_read_options.readahead_size =
|
||||
file_options_for_read_.compaction_readahead_size;
|
||||
|
||||
std::unique_ptr<TableReader> table_reader_guard;
|
||||
TableReader* table_reader_ptr = table_reader_guard.get();
|
||||
verify_table_read_options.rate_limiter_priority =
|
||||
GetRateLimiterPriority();
|
||||
InternalIterator* iter = cfd->table_cache()->NewIterator(
|
||||
verify_table_read_options, file_options_, cfd->internal_comparator(),
|
||||
files_output[file_idx]->meta,
|
||||
output_file.meta,
|
||||
/*range_del_agg=*/nullptr, compact_->compaction->mutable_cf_options(),
|
||||
/*table_reader_ptr=*/nullptr,
|
||||
/*table_reader_ptr=*/&table_reader_ptr,
|
||||
cfd->internal_stats()->GetFileReadHist(
|
||||
compact_->compaction->output_level()),
|
||||
TableReaderCaller::kCompactionRefill, /*arena=*/nullptr,
|
||||
@@ -850,38 +855,63 @@ Status CompactionJob::VerifyOutputFiles() {
|
||||
/*largest_compaction_key=*/nullptr,
|
||||
/*allow_unprepared_value=*/false);
|
||||
auto s = iter->status();
|
||||
if (s.ok()) {
|
||||
// Check for remote/local compaction and verify_output_flags flags
|
||||
const bool should_verify =
|
||||
(subcompaction_state.compaction_job_stats.is_remote_compaction &&
|
||||
!!(verify_output_flags &
|
||||
VerifyOutputFlags::kEnableForRemoteCompaction)) ||
|
||||
(!subcompaction_state.compaction_job_stats.is_remote_compaction &&
|
||||
!!(verify_output_flags &
|
||||
VerifyOutputFlags::kEnableForLocalCompaction));
|
||||
|
||||
if (s.ok() && paranoid_file_checks_) {
|
||||
OutputValidator validator(cfd->internal_comparator(),
|
||||
/*_enable_hash=*/true);
|
||||
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
|
||||
s = validator.Add(iter->key(), iter->value());
|
||||
if (!s.ok()) {
|
||||
break;
|
||||
if (should_verify) {
|
||||
const bool should_verify_block_checksum =
|
||||
!!(verify_output_flags & VerifyOutputFlags::kVerifyBlockChecksum);
|
||||
const bool should_verify_iteration =
|
||||
!!(verify_output_flags & VerifyOutputFlags::kVerifyIteration);
|
||||
if (should_verify_block_checksum) {
|
||||
assert(table_reader_ptr != nullptr);
|
||||
// If verifying iteration as well, verify meta blocks here only to
|
||||
// avoid redundant checks on data blocks
|
||||
s = table_reader_ptr->VerifyChecksum(
|
||||
verify_table_read_options, TableReaderCaller::kCompaction,
|
||||
/*meta_blocks_only=*/should_verify_iteration);
|
||||
}
|
||||
if (s.ok() && should_verify_iteration) {
|
||||
OutputValidator validator(cfd->internal_comparator(),
|
||||
/*_enable_hash=*/true);
|
||||
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
|
||||
s = validator.Add(iter->key(), iter->value());
|
||||
if (!s.ok()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (s.ok()) {
|
||||
s = iter->status();
|
||||
}
|
||||
if (s.ok() && !validator.CompareValidator(output_file.validator)) {
|
||||
s = Status::Corruption(
|
||||
"Key-value checksum of compaction output doesn't match what "
|
||||
"was computed when written");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (s.ok()) {
|
||||
s = iter->status();
|
||||
}
|
||||
if (s.ok() &&
|
||||
!validator.CompareValidator(files_output[file_idx]->validator)) {
|
||||
s = Status::Corruption("Paranoid checksums do not match");
|
||||
}
|
||||
}
|
||||
|
||||
delete iter;
|
||||
|
||||
if (!s.ok()) {
|
||||
output_status = s;
|
||||
subcompaction_state.status = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
for (size_t i = 1; i < compact_->sub_compact_states.size(); i++) {
|
||||
thread_pool.emplace_back(verify_table,
|
||||
std::ref(compact_->sub_compact_states[i].status));
|
||||
std::ref(compact_->sub_compact_states[i]));
|
||||
}
|
||||
verify_table(compact_->sub_compact_states[0].status);
|
||||
verify_table(compact_->sub_compact_states[0]);
|
||||
for (auto& thread : thread_pool) {
|
||||
thread.join();
|
||||
}
|
||||
|
||||
@@ -211,12 +211,12 @@ class CompactionJobTestBase : public testing::Test {
|
||||
table_cache_(NewLRUCache(50000, 16)),
|
||||
write_buffer_manager_(db_options_.db_write_buffer_size),
|
||||
versions_(new VersionSet(
|
||||
dbname_, &db_options_, env_options_, table_cache_.get(),
|
||||
&write_buffer_manager_, &write_controller_,
|
||||
dbname_, &db_options_, mutable_db_options_, env_options_,
|
||||
table_cache_.get(), &write_buffer_manager_, &write_controller_,
|
||||
/*block_cache_tracer=*/nullptr,
|
||||
/*io_tracer=*/nullptr, /*db_id=*/"", /*db_session_id=*/"",
|
||||
/*daily_offpeak_time_utc=*/"",
|
||||
/*error_handler=*/nullptr, /*read_only=*/false)),
|
||||
/*error_handler=*/nullptr, /*unchanging=*/false)),
|
||||
shutting_down_(false),
|
||||
mock_table_factory_(new mock::MockTableFactory()),
|
||||
error_handler_(nullptr, db_options_, &mutex_),
|
||||
@@ -546,13 +546,13 @@ class CompactionJobTestBase : public testing::Test {
|
||||
ASSERT_OK(s);
|
||||
db_options_.info_log = info_log;
|
||||
|
||||
versions_.reset(
|
||||
new VersionSet(dbname_, &db_options_, env_options_, table_cache_.get(),
|
||||
&write_buffer_manager_, &write_controller_,
|
||||
/*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
|
||||
test::kUnitTestDbId, /*db_session_id=*/"",
|
||||
/*daily_offpeak_time_utc=*/"",
|
||||
/*error_handler=*/nullptr, /*read_only=*/false));
|
||||
versions_.reset(new VersionSet(
|
||||
dbname_, &db_options_, mutable_db_options_, env_options_,
|
||||
table_cache_.get(), &write_buffer_manager_, &write_controller_,
|
||||
/*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
|
||||
test::kUnitTestDbId, /*db_session_id=*/"",
|
||||
/*daily_offpeak_time_utc=*/"",
|
||||
/*error_handler=*/nullptr, /*unchanging=*/false));
|
||||
compaction_job_stats_.Reset();
|
||||
|
||||
VersionEdit new_db;
|
||||
@@ -2420,7 +2420,7 @@ class ResumableCompactionJobTest : public CompactionJobTestBase {
|
||||
|
||||
protected:
|
||||
static constexpr const char* kCancelBeforeThisKey = "cancel_before_this_key";
|
||||
std::string progress_dir_ = "";
|
||||
std::string progress_dir_;
|
||||
bool enable_cancel_ = false;
|
||||
std::atomic<int> stop_count_{0};
|
||||
std::atomic<bool> cancel_{false};
|
||||
@@ -2580,7 +2580,9 @@ class ResumableCompactionJobTest : public CompactionJobTestBase {
|
||||
|
||||
while (reader.ReadRecord(&slice, &record)) {
|
||||
VersionEdit edit;
|
||||
if (!edit.DecodeFrom(slice).ok()) continue;
|
||||
if (!edit.DecodeFrom(slice).ok()) {
|
||||
continue;
|
||||
}
|
||||
builder.ProcessVersionEdit(edit);
|
||||
}
|
||||
|
||||
|
||||
@@ -1047,6 +1047,7 @@ TEST_F(CompactionServiceTest, CorruptedOutputParanoidFileCheck) {
|
||||
Destroy(options);
|
||||
options.disable_auto_compactions = true;
|
||||
options.paranoid_file_checks = paranoid_file_check_enabled;
|
||||
options.verify_output_flags = VerifyOutputFlags::kVerifyNone;
|
||||
ReopenWithCompactionService(&options);
|
||||
GenerateTestData();
|
||||
|
||||
@@ -1101,6 +1102,87 @@ TEST_F(CompactionServiceTest, CorruptedOutputParanoidFileCheck) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(CompactionServiceTest, CorruptedOutputVerifyOutputFlags) {
|
||||
for (VerifyOutputFlags verify_output_flags :
|
||||
{VerifyOutputFlags::kVerifyNone,
|
||||
VerifyOutputFlags::kEnableForLocalCompaction |
|
||||
VerifyOutputFlags::kVerifyBlockChecksum,
|
||||
VerifyOutputFlags::kEnableForRemoteCompaction |
|
||||
VerifyOutputFlags::kVerifyBlockChecksum,
|
||||
VerifyOutputFlags::kEnableForRemoteCompaction |
|
||||
VerifyOutputFlags::kVerifyIteration,
|
||||
VerifyOutputFlags::kVerifyAll}) {
|
||||
SCOPED_TRACE(
|
||||
"verify_output_flags=" +
|
||||
std::to_string(static_cast<std::underlying_type_t<VerifyOutputFlags>>(
|
||||
verify_output_flags)));
|
||||
|
||||
Options options = CurrentOptions();
|
||||
Destroy(options);
|
||||
options.disable_auto_compactions = true;
|
||||
options.paranoid_file_checks = false;
|
||||
options.verify_output_flags = verify_output_flags;
|
||||
ReopenWithCompactionService(&options);
|
||||
GenerateTestData();
|
||||
|
||||
auto my_cs = GetCompactionService();
|
||||
|
||||
std::string start_str = Key(15);
|
||||
std::string end_str = Key(45);
|
||||
Slice start(start_str);
|
||||
Slice end(end_str);
|
||||
uint64_t comp_num = my_cs->GetCompactionNum();
|
||||
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"CompactionServiceCompactionJob::Run:0", [&](void* arg) {
|
||||
CompactionServiceResult* compaction_result =
|
||||
*(static_cast<CompactionServiceResult**>(arg));
|
||||
ASSERT_TRUE(compaction_result != nullptr &&
|
||||
!compaction_result->output_files.empty());
|
||||
// Corrupt files here
|
||||
for (const auto& output_file : compaction_result->output_files) {
|
||||
std::string file_name =
|
||||
compaction_result->output_path + "/" + output_file.file_name;
|
||||
|
||||
// Corrupt very small range of bytes. This corruption is so small
|
||||
// that this isn't caught by default light-weight check
|
||||
ASSERT_OK(test::CorruptFile(env_, file_name, 0, 1,
|
||||
false /* verifyChecksum */));
|
||||
}
|
||||
});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
const bool is_enabled_for_remote_compaction =
|
||||
!!(verify_output_flags & VerifyOutputFlags::kEnableForRemoteCompaction);
|
||||
const bool should_verify_block_checksum =
|
||||
!!(verify_output_flags & VerifyOutputFlags::kVerifyBlockChecksum);
|
||||
const bool should_verify_iteration =
|
||||
!!(verify_output_flags & VerifyOutputFlags::kVerifyIteration);
|
||||
|
||||
Status s = db_->CompactRange(CompactRangeOptions(), &start, &end);
|
||||
if (is_enabled_for_remote_compaction &&
|
||||
(should_verify_block_checksum || should_verify_iteration)) {
|
||||
ASSERT_NOK(s);
|
||||
ASSERT_TRUE(s.IsCorruption());
|
||||
} else {
|
||||
// CompactRange() goes through if block checksum wasn't verified
|
||||
ASSERT_OK(s);
|
||||
}
|
||||
|
||||
ASSERT_GE(my_cs->GetCompactionNum(), comp_num + 1);
|
||||
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
|
||||
// On the worker side, the compaction is considered success
|
||||
// Verification is done on the primary side
|
||||
CompactionServiceResult result;
|
||||
my_cs->GetResult(&result);
|
||||
ASSERT_OK(result.status);
|
||||
ASSERT_TRUE(result.stats.is_manual_compaction);
|
||||
ASSERT_TRUE(result.stats.is_remote_compaction);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(CompactionServiceTest, TruncatedOutput) {
|
||||
Options options = CurrentOptions();
|
||||
options.disable_auto_compactions = true;
|
||||
|
||||
@@ -675,30 +675,6 @@ TEST_F(DBBasicTest, Flush) {
|
||||
} while (ChangeCompactOptions());
|
||||
}
|
||||
|
||||
TEST_F(DBBasicTest, ManifestRollOver) {
|
||||
do {
|
||||
Options options;
|
||||
options.max_manifest_file_size = 10; // 10 bytes
|
||||
options = CurrentOptions(options);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
{
|
||||
ASSERT_OK(Put(1, "manifest_key1", std::string(1000, '1')));
|
||||
ASSERT_OK(Put(1, "manifest_key2", std::string(1000, '2')));
|
||||
ASSERT_OK(Put(1, "manifest_key3", std::string(1000, '3')));
|
||||
uint64_t manifest_before_flush = dbfull()->TEST_Current_Manifest_FileNo();
|
||||
ASSERT_OK(Flush(1)); // This should trigger LogAndApply.
|
||||
uint64_t manifest_after_flush = dbfull()->TEST_Current_Manifest_FileNo();
|
||||
ASSERT_GT(manifest_after_flush, manifest_before_flush);
|
||||
ReopenWithColumnFamilies({"default", "pikachu"}, options);
|
||||
ASSERT_GT(dbfull()->TEST_Current_Manifest_FileNo(), manifest_after_flush);
|
||||
// check if a new manifest file got inserted or not.
|
||||
ASSERT_EQ(std::string(1000, '1'), Get(1, "manifest_key1"));
|
||||
ASSERT_EQ(std::string(1000, '2'), Get(1, "manifest_key2"));
|
||||
ASSERT_EQ(std::string(1000, '3'), Get(1, "manifest_key3"));
|
||||
}
|
||||
} while (ChangeCompactOptions());
|
||||
}
|
||||
|
||||
TEST_F(DBBasicTest, IdentityAcrossRestarts) {
|
||||
constexpr size_t kMinIdSize = 10;
|
||||
do {
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
#include "db/db_test_util.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
class DBEtc3Test : public DBTestBase {
|
||||
public:
|
||||
DBEtc3Test() : DBTestBase("db_etc3_test", /*env_do_fsync=*/true) {}
|
||||
};
|
||||
|
||||
TEST_F(DBEtc3Test, ManifestRollOver) {
|
||||
do {
|
||||
Options options;
|
||||
// Force new manifest on each manifest write
|
||||
options.max_manifest_file_size = 0;
|
||||
options.max_manifest_space_amp_pct = 0;
|
||||
options = CurrentOptions(options);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
{
|
||||
ASSERT_OK(Put(1, "key1", std::string(1000, '1')));
|
||||
ASSERT_OK(Put(1, "key2", std::string(1000, '2')));
|
||||
ASSERT_OK(Put(1, "key3", std::string(1000, '3')));
|
||||
uint64_t manifest_before_flush = dbfull()->TEST_Current_Manifest_FileNo();
|
||||
ASSERT_OK(Flush(1)); // This should trigger LogAndApply.
|
||||
uint64_t manifest_after_flush = dbfull()->TEST_Current_Manifest_FileNo();
|
||||
ASSERT_GT(manifest_after_flush, manifest_before_flush);
|
||||
// Re-open should always re-create manifest file
|
||||
ReopenWithColumnFamilies({"default", "pikachu"}, options);
|
||||
ASSERT_GT(dbfull()->TEST_Current_Manifest_FileNo(), manifest_after_flush);
|
||||
ASSERT_EQ(std::string(1000, '1'), Get(1, "key1"));
|
||||
ASSERT_EQ(std::string(1000, '2'), Get(1, "key2"));
|
||||
ASSERT_EQ(std::string(1000, '3'), Get(1, "key3"));
|
||||
}
|
||||
} while (ChangeCompactOptions());
|
||||
}
|
||||
|
||||
TEST_F(DBEtc3Test, AutoTuneManifestSize) {
|
||||
// Ensure we have auto-tuning beyond max_manifest_file_size by default
|
||||
ASSERT_EQ(DBOptions{}.max_manifest_space_amp_pct, 500);
|
||||
|
||||
Options options = CurrentOptions();
|
||||
ASSERT_OK(db_->SetOptions({{"level0_file_num_compaction_trigger", "20"}}));
|
||||
|
||||
// Use large column family names to essentially control the amount of payload
|
||||
// data needed for the manifest file. Drop manifest entries don't include the
|
||||
// CF name so are small.
|
||||
uint64_t prev_manifest_num = 0, cur_manifest_num = 0;
|
||||
std::deque<ColumnFamilyHandle*> handles;
|
||||
int counter = 5;
|
||||
auto AddCfFn = [&]() {
|
||||
std::string name = "cf" + std::to_string(counter++);
|
||||
name.resize(1000, 'a');
|
||||
ASSERT_OK(db_->CreateColumnFamily(options, name, &handles.emplace_back()));
|
||||
prev_manifest_num = cur_manifest_num;
|
||||
cur_manifest_num = dbfull()->TEST_Current_Manifest_FileNo();
|
||||
};
|
||||
auto DropCfFn = [&]() {
|
||||
ASSERT_OK(db_->DropColumnFamily(handles.front()));
|
||||
ASSERT_OK(db_->DestroyColumnFamilyHandle(handles.front()));
|
||||
handles.pop_front();
|
||||
prev_manifest_num = cur_manifest_num;
|
||||
cur_manifest_num = dbfull()->TEST_Current_Manifest_FileNo();
|
||||
};
|
||||
auto TrivialManifestWriteFn = [&]() {
|
||||
ASSERT_OK(Put("x", std::to_string(counter++)));
|
||||
ASSERT_OK(Flush());
|
||||
prev_manifest_num = cur_manifest_num;
|
||||
cur_manifest_num = dbfull()->TEST_Current_Manifest_FileNo();
|
||||
};
|
||||
|
||||
options.max_manifest_file_size = 1000000;
|
||||
options.max_manifest_space_amp_pct = 0; // no auto-tuning yet
|
||||
DestroyAndReopen(options);
|
||||
|
||||
// With the generous (minimum) maximum manifest size, should not be rotated
|
||||
AddCfFn();
|
||||
AddCfFn();
|
||||
AddCfFn();
|
||||
ASSERT_EQ(prev_manifest_num, cur_manifest_num);
|
||||
|
||||
// Change options for small max and (still) no auto-tuning
|
||||
ASSERT_OK(db_->SetDBOptions({{"max_manifest_file_size", "3000"}}));
|
||||
|
||||
// Takes effect on the next manifest write
|
||||
TrivialManifestWriteFn();
|
||||
ASSERT_LT(prev_manifest_num, cur_manifest_num);
|
||||
|
||||
// Now we have to rewrite the whole manifest on each write because the
|
||||
// compacted size exceeds the "max" size.
|
||||
AddCfFn();
|
||||
ASSERT_LT(prev_manifest_num, cur_manifest_num);
|
||||
DropCfFn();
|
||||
ASSERT_LT(prev_manifest_num, cur_manifest_num);
|
||||
AddCfFn();
|
||||
ASSERT_LT(prev_manifest_num, cur_manifest_num);
|
||||
TrivialManifestWriteFn();
|
||||
ASSERT_LT(prev_manifest_num, cur_manifest_num);
|
||||
|
||||
// Enabling auto-tuning should fix this, immediately for next manifest writes.
|
||||
// This will allow up to double-ish the size of the compacted manifest,
|
||||
// which last should have been 4000 + some bytes.
|
||||
ASSERT_EQ(handles.size(), 4U);
|
||||
ASSERT_OK(db_->SetDBOptions({{"max_manifest_space_amp_pct", "105"}}));
|
||||
|
||||
// After 9 CF names should be enough to rotate the manifest
|
||||
for (int i = 1; i <= 5; ++i) {
|
||||
if ((i % 2) == 1) {
|
||||
DropCfFn();
|
||||
}
|
||||
AddCfFn();
|
||||
ASSERT_EQ(prev_manifest_num, cur_manifest_num);
|
||||
}
|
||||
TrivialManifestWriteFn();
|
||||
ASSERT_LT(prev_manifest_num, cur_manifest_num);
|
||||
|
||||
// We now have a different last compacted manifest size, should be
|
||||
// able to go beyond 9 CFs named in manifest this time.
|
||||
ASSERT_EQ(handles.size(), 6U);
|
||||
|
||||
DropCfFn();
|
||||
DropCfFn();
|
||||
for (int i = 1; i <= 4; ++i) {
|
||||
DropCfFn();
|
||||
AddCfFn();
|
||||
ASSERT_EQ(prev_manifest_num, cur_manifest_num);
|
||||
}
|
||||
// We've written 10 named CFs to the manifest. We should be able to
|
||||
// dynamically change the auto-tuning still based on the last "compacted"
|
||||
// manifest size of 7000 + some bytes.
|
||||
ASSERT_OK(db_->SetDBOptions({{"max_manifest_space_amp_pct", "51"}}));
|
||||
TrivialManifestWriteFn();
|
||||
ASSERT_LT(prev_manifest_num, cur_manifest_num);
|
||||
// And the "compacted" manifest size has reset again, so should be changed
|
||||
// again sooner.
|
||||
ASSERT_EQ(handles.size(), 4U);
|
||||
for (int i = 1; i <= 2; ++i) {
|
||||
AddCfFn();
|
||||
ASSERT_EQ(prev_manifest_num, cur_manifest_num);
|
||||
}
|
||||
// Enough for manifest change
|
||||
AddCfFn();
|
||||
ASSERT_LT(prev_manifest_num, cur_manifest_num);
|
||||
|
||||
// Wrap up
|
||||
while (!handles.empty()) {
|
||||
DropCfFn();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
RegisterCustomObjects(argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
+18
-5
@@ -258,10 +258,10 @@ DBImpl::DBImpl(const DBOptions& options, const std::string& dbname,
|
||||
[this]() { this->TriggerPeriodicCompaction(); });
|
||||
|
||||
versions_.reset(new VersionSet(
|
||||
dbname_, &immutable_db_options_, file_options_, table_cache_.get(),
|
||||
write_buffer_manager_, &write_controller_, &block_cache_tracer_,
|
||||
io_tracer_, db_id_, db_session_id_, options.daily_offpeak_time_utc,
|
||||
&error_handler_, read_only));
|
||||
dbname_, &immutable_db_options_, mutable_db_options_, file_options_,
|
||||
table_cache_.get(), write_buffer_manager_, &write_controller_,
|
||||
&block_cache_tracer_, io_tracer_, db_id_, db_session_id_,
|
||||
options.daily_offpeak_time_utc, &error_handler_, read_only));
|
||||
column_family_memtables_.reset(
|
||||
new ColumnFamilyMemTablesImpl(versions_->GetColumnFamilySet()));
|
||||
|
||||
@@ -1412,7 +1412,7 @@ Status DBImpl::SetDBOptions(
|
||||
file_options_for_compaction_ = FileOptions(new_db_options);
|
||||
file_options_for_compaction_ = fs_->OptimizeForCompactionTableWrite(
|
||||
file_options_for_compaction_, immutable_db_options_);
|
||||
versions_->ChangeFileOptions(mutable_db_options_);
|
||||
versions_->UpdatedMutableDbOptions(mutable_db_options_, &mutex_);
|
||||
// TODO(xiez): clarify why apply optimize for read to write options
|
||||
file_options_for_compaction_ = fs_->OptimizeForCompactionTableRead(
|
||||
file_options_for_compaction_, immutable_db_options_);
|
||||
@@ -5047,6 +5047,19 @@ void DBImpl::GetColumnFamilyMetaData(ColumnFamilyHandle* column_family,
|
||||
}
|
||||
}
|
||||
|
||||
void DBImpl::GetColumnFamilyMetaData(
|
||||
ColumnFamilyHandle* column_family,
|
||||
const GetColumnFamilyMetaDataOptions& options,
|
||||
ColumnFamilyMetaData* metadata) {
|
||||
assert(column_family);
|
||||
auto* cfd =
|
||||
static_cast_with_check<ColumnFamilyHandleImpl>(column_family)->cfd();
|
||||
{
|
||||
InstrumentedMutexLock l(&mutex_);
|
||||
cfd->current()->GetColumnFamilyMetaData(options, metadata);
|
||||
}
|
||||
}
|
||||
|
||||
void DBImpl::GetAllColumnFamilyMetaData(
|
||||
std::vector<ColumnFamilyMetaData>* metadata) {
|
||||
InstrumentedMutexLock l(&mutex_);
|
||||
|
||||
@@ -573,6 +573,11 @@ class DBImpl : public DB {
|
||||
void GetColumnFamilyMetaData(ColumnFamilyHandle* column_family,
|
||||
ColumnFamilyMetaData* metadata) override;
|
||||
|
||||
// Get column family metadata with filtering based on key range and level
|
||||
void GetColumnFamilyMetaData(ColumnFamilyHandle* column_family,
|
||||
const GetColumnFamilyMetaDataOptions& options,
|
||||
ColumnFamilyMetaData* metadata) override;
|
||||
|
||||
void GetAllColumnFamilyMetaData(
|
||||
std::vector<ColumnFamilyMetaData>* metadata) override;
|
||||
|
||||
@@ -2396,6 +2401,14 @@ class DBImpl : public DB {
|
||||
JobContext* job_context, LogBuffer* log_buffer,
|
||||
CompactionJobInfo* compaction_job_info);
|
||||
|
||||
// Helper function to perform trivial move by updating manifest metadata
|
||||
// without rewriting data files. This is called when IsTrivialMove() is true.
|
||||
// REQUIRES: mutex held
|
||||
// Returns: Status of the trivial move operation
|
||||
Status PerformTrivialMove(Compaction& c, LogBuffer* log_buffer,
|
||||
bool& compaction_released, size_t& moved_files,
|
||||
size_t& moved_bytes);
|
||||
|
||||
// REQUIRES: mutex unlocked
|
||||
void TrackOrUntrackFiles(const std::vector<std::string>& existing_data_files,
|
||||
bool track);
|
||||
|
||||
@@ -1424,6 +1424,56 @@ Status DBImpl::CompactFiles(const CompactionOptions& compact_options,
|
||||
return s;
|
||||
}
|
||||
|
||||
Status DBImpl::PerformTrivialMove(Compaction& c, LogBuffer* log_buffer,
|
||||
bool& compaction_released,
|
||||
size_t& moved_files, size_t& moved_bytes) {
|
||||
mutex_.AssertHeld();
|
||||
|
||||
ROCKS_LOG_BUFFER(log_buffer, "[%s] Moving %d files to level-%d\n",
|
||||
c.column_family_data()->GetName().c_str(),
|
||||
static_cast<int>(c.num_input_files(0)), c.output_level());
|
||||
|
||||
// Move files to the output level by editing the manifest
|
||||
for (unsigned int l = 0; l < c.num_input_levels(); l++) {
|
||||
if (c.level(l) == c.output_level()) {
|
||||
continue;
|
||||
}
|
||||
for (size_t i = 0; i < c.num_input_files(l); i++) {
|
||||
FileMetaData* f = c.input(l, i);
|
||||
c.edit()->DeleteFile(c.level(l), f->fd.GetNumber());
|
||||
c.edit()->AddFile(c.output_level(), f->fd.GetNumber(), f->fd.GetPathId(),
|
||||
f->fd.GetFileSize(), f->smallest, f->largest,
|
||||
f->fd.smallest_seqno, f->fd.largest_seqno,
|
||||
f->marked_for_compaction, f->temperature,
|
||||
f->oldest_blob_file_number, f->oldest_ancester_time,
|
||||
f->file_creation_time, f->epoch_number,
|
||||
f->file_checksum, f->file_checksum_func_name,
|
||||
f->unique_id, f->compensated_range_deletion_size,
|
||||
f->tail_size, f->user_defined_timestamps_persisted);
|
||||
moved_bytes += static_cast<size_t>(c.input(l, i)->fd.GetFileSize());
|
||||
ROCKS_LOG_BUFFER(
|
||||
log_buffer, "[%s] Moved #%" PRIu64 " to level-%d %" PRIu64 " bytes\n",
|
||||
c.column_family_data()->GetName().c_str(), f->fd.GetNumber(),
|
||||
c.output_level(), f->fd.GetFileSize());
|
||||
}
|
||||
moved_files += c.num_input_files(l);
|
||||
}
|
||||
|
||||
// Install the new version
|
||||
const ReadOptions read_options(Env::IOActivity::kCompaction);
|
||||
const WriteOptions write_options(Env::IOActivity::kCompaction);
|
||||
Status status = versions_->LogAndApply(
|
||||
c.column_family_data(), read_options, write_options, c.edit(), &mutex_,
|
||||
directories_.GetDbDir(), /*new_descriptor_log=*/false,
|
||||
/*column_family_options=*/nullptr,
|
||||
[&c, &compaction_released](const Status& s) {
|
||||
c.ReleaseCompactionFiles(s);
|
||||
compaction_released = true;
|
||||
});
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
Status DBImpl::CompactFilesImpl(
|
||||
const CompactionOptions& compact_options, ColumnFamilyData* cfd,
|
||||
Version* version, const std::vector<std::string>& input_file_names,
|
||||
@@ -1511,6 +1561,63 @@ Status DBImpl::CompactFilesImpl(
|
||||
// deletion compaction currently not allowed in CompactFiles.
|
||||
assert(!c->deletion_compaction());
|
||||
|
||||
// Check if this can be a trivial move (metadata-only update)
|
||||
// Similar to the logic in DBImpl::BackgroundCompaction
|
||||
// Note: We disable trivial move when compaction_service is present because
|
||||
// the service expects all compactions to go through CompactionJob for
|
||||
// tracking
|
||||
bool is_trivial_move = compact_options.allow_trivial_move &&
|
||||
c->IsTrivialMove() &&
|
||||
immutable_db_options().compaction_service == nullptr;
|
||||
|
||||
if (is_trivial_move) {
|
||||
// Perform trivial move: just update manifest without rewriting data
|
||||
TEST_SYNC_POINT("DBImpl::CompactFilesImpl:TrivialMove");
|
||||
|
||||
bool compaction_released = false;
|
||||
size_t moved_files = 0;
|
||||
size_t moved_bytes = 0;
|
||||
Status status = PerformTrivialMove(
|
||||
*c.get(), log_buffer, compaction_released, moved_files, moved_bytes);
|
||||
|
||||
if (status.ok()) {
|
||||
InstallSuperVersionAndScheduleWork(
|
||||
c->column_family_data(), job_context->superversion_contexts.data());
|
||||
|
||||
// Populate output file names for trivial move
|
||||
if (output_file_names != nullptr) {
|
||||
for (const auto& newf : c->edit()->GetNewFiles()) {
|
||||
output_file_names->push_back(TableFileName(
|
||||
c->immutable_options().cf_paths, newf.second.fd.GetNumber(),
|
||||
newf.second.fd.GetPathId()));
|
||||
}
|
||||
}
|
||||
|
||||
ROCKS_LOG_BUFFER(
|
||||
log_buffer,
|
||||
"[%s] Trivial move succeeded for %zu files, %zu bytes total\n",
|
||||
c->column_family_data()->GetName().c_str(), moved_files, moved_bytes);
|
||||
} else {
|
||||
if (!compaction_released) {
|
||||
c->ReleaseCompactionFiles(status);
|
||||
}
|
||||
ROCKS_LOG_BUFFER(log_buffer, "[%s] Trivial move failed: %s\n",
|
||||
c->column_family_data()->GetName().c_str(),
|
||||
status.ToString().c_str());
|
||||
error_handler_.SetBGError(status, BackgroundErrorReason::kCompaction);
|
||||
}
|
||||
|
||||
c.reset();
|
||||
bg_compaction_scheduled_--;
|
||||
if (bg_compaction_scheduled_ == 0) {
|
||||
bg_cv_.SignalAll();
|
||||
}
|
||||
MaybeScheduleFlushOrCompaction();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Not a trivial move, proceed with full compaction
|
||||
InitSnapshotContext(job_context);
|
||||
|
||||
std::unique_ptr<std::list<uint64_t>::iterator> pending_outputs_inserted_elem(
|
||||
@@ -4074,35 +4181,6 @@ Status DBImpl::BackgroundCompaction(bool* made_progress,
|
||||
NotifyOnCompactionBegin(c->column_family_data(), c.get(), status,
|
||||
compaction_job_stats, job_context->job_id);
|
||||
|
||||
// Move files to next level
|
||||
int32_t moved_files = 0;
|
||||
int64_t moved_bytes = 0;
|
||||
for (unsigned int l = 0; l < c->num_input_levels(); l++) {
|
||||
if (c->level(l) == c->output_level()) {
|
||||
continue;
|
||||
}
|
||||
for (size_t i = 0; i < c->num_input_files(l); i++) {
|
||||
FileMetaData* f = c->input(l, i);
|
||||
c->edit()->DeleteFile(c->level(l), f->fd.GetNumber());
|
||||
c->edit()->AddFile(
|
||||
c->output_level(), f->fd.GetNumber(), f->fd.GetPathId(),
|
||||
f->fd.GetFileSize(), f->smallest, f->largest, f->fd.smallest_seqno,
|
||||
f->fd.largest_seqno, f->marked_for_compaction, f->temperature,
|
||||
f->oldest_blob_file_number, f->oldest_ancester_time,
|
||||
f->file_creation_time, f->epoch_number, f->file_checksum,
|
||||
f->file_checksum_func_name, f->unique_id,
|
||||
f->compensated_range_deletion_size, f->tail_size,
|
||||
f->user_defined_timestamps_persisted);
|
||||
|
||||
ROCKS_LOG_BUFFER(
|
||||
log_buffer,
|
||||
"[%s] Moving #%" PRIu64 " to level-%d %" PRIu64 " bytes\n",
|
||||
c->column_family_data()->GetName().c_str(), f->fd.GetNumber(),
|
||||
c->output_level(), f->fd.GetFileSize());
|
||||
++moved_files;
|
||||
moved_bytes += f->fd.GetFileSize();
|
||||
}
|
||||
}
|
||||
if (c->compaction_reason() == CompactionReason::kLevelMaxLevelSize &&
|
||||
c->immutable_options().compaction_pri == kRoundRobin) {
|
||||
int start_level = c->start_level();
|
||||
@@ -4113,14 +4191,12 @@ Status DBImpl::BackgroundCompaction(bool* made_progress,
|
||||
vstorage->GetNextCompactCursor(start_level, c->num_input_files(0)));
|
||||
}
|
||||
}
|
||||
status = versions_->LogAndApply(
|
||||
c->column_family_data(), read_options, write_options, c->edit(),
|
||||
&mutex_, directories_.GetDbDir(),
|
||||
/*new_descriptor_log=*/false, /*column_family_options=*/nullptr,
|
||||
[&c, &compaction_released](const Status& s) {
|
||||
c->ReleaseCompactionFiles(s);
|
||||
compaction_released = true;
|
||||
});
|
||||
|
||||
// Perform the trivial move
|
||||
size_t moved_files = 0;
|
||||
size_t moved_bytes = 0;
|
||||
status = PerformTrivialMove(*c.get(), log_buffer, compaction_released,
|
||||
moved_files, moved_bytes);
|
||||
io_s = versions_->io_status();
|
||||
InstallSuperVersionAndScheduleWork(
|
||||
c->column_family_data(), job_context->superversion_contexts.data());
|
||||
@@ -4135,8 +4211,7 @@ Status DBImpl::BackgroundCompaction(bool* made_progress,
|
||||
<< "total_files_size" << moved_bytes;
|
||||
}
|
||||
ROCKS_LOG_BUFFER(
|
||||
log_buffer,
|
||||
"[%s] Moved #%d files to level-%d %" PRIu64 " bytes %s: %s\n",
|
||||
log_buffer, "[%s] Moved #%d files to level-%zu %zu bytes %s: %s\n",
|
||||
c->column_family_data()->GetName().c_str(), moved_files,
|
||||
c->output_level(), moved_bytes, status.ToString().c_str(),
|
||||
c->column_family_data()->current()->storage_info()->LevelSummary(&tmp));
|
||||
|
||||
@@ -293,9 +293,9 @@ Status DB::OpenAsFollower(
|
||||
DBImplFollower* impl =
|
||||
new DBImplFollower(tmp_opts, std::move(new_env), dbname, src_path);
|
||||
impl->versions_.reset(new ReactiveVersionSet(
|
||||
dbname, &impl->immutable_db_options_, impl->file_options_,
|
||||
impl->table_cache_.get(), impl->write_buffer_manager_,
|
||||
&impl->write_controller_, impl->io_tracer_));
|
||||
dbname, &impl->immutable_db_options_, impl->mutable_db_options_,
|
||||
impl->file_options_, impl->table_cache_.get(),
|
||||
impl->write_buffer_manager_, &impl->write_controller_, impl->io_tracer_));
|
||||
impl->column_family_memtables_.reset(
|
||||
new ColumnFamilyMemTablesImpl(impl->versions_->GetColumnFamilySet()));
|
||||
impl->wal_in_db_path_ = impl->immutable_db_options_.IsWalDirSameAsDBPath();
|
||||
|
||||
@@ -329,7 +329,7 @@ Status DBImpl::NewDB(std::vector<std::string>* new_filenames) {
|
||||
}
|
||||
FileTypeSet tmp_set = immutable_db_options_.checksum_handoff_file_types;
|
||||
file->SetPreallocationBlockSize(
|
||||
immutable_db_options_.manifest_preallocation_size);
|
||||
mutable_db_options_.manifest_preallocation_size);
|
||||
std::unique_ptr<WritableFileWriter> file_writer(new WritableFileWriter(
|
||||
std::move(file), manifest, file_options, immutable_db_options_.clock,
|
||||
io_tracer_, nullptr /* stats */,
|
||||
|
||||
@@ -783,9 +783,9 @@ Status DB::OpenAsSecondary(
|
||||
handles->clear();
|
||||
DBImplSecondary* impl = new DBImplSecondary(tmp_opts, dbname, secondary_path);
|
||||
impl->versions_.reset(new ReactiveVersionSet(
|
||||
dbname, &impl->immutable_db_options_, impl->file_options_,
|
||||
impl->table_cache_.get(), impl->write_buffer_manager_,
|
||||
&impl->write_controller_, impl->io_tracer_));
|
||||
dbname, &impl->immutable_db_options_, impl->mutable_db_options_,
|
||||
impl->file_options_, impl->table_cache_.get(),
|
||||
impl->write_buffer_manager_, &impl->write_controller_, impl->io_tracer_));
|
||||
impl->column_family_memtables_.reset(
|
||||
new ColumnFamilyMemTablesImpl(impl->versions_->GetColumnFamilySet()));
|
||||
impl->wal_in_db_path_ = impl->immutable_db_options_.IsWalDirSameAsDBPath();
|
||||
|
||||
@@ -432,12 +432,47 @@ TEST_F(DBOptionsTest, SetWalBytesPerSync) {
|
||||
ASSERT_GT(low_bytes_per_sync, counter);
|
||||
}
|
||||
|
||||
TEST_F(DBOptionsTest, MutableManifestOptions) {
|
||||
// These aren't end-to-end tests, but sufficient to ensure the VersionSet
|
||||
// receives the updates with SetDBOptions
|
||||
for (int64_t i : {0, 1, 100, 100000, 10000000}) {
|
||||
ASSERT_OK(
|
||||
db_->SetDBOptions({{"max_manifest_file_size", std::to_string(i)}}));
|
||||
ASSERT_EQ(i,
|
||||
static_cast<int64_t>(db_->GetDBOptions().max_manifest_file_size));
|
||||
ASSERT_EQ(i,
|
||||
static_cast<int64_t>(
|
||||
dbfull()->GetVersionSet()->TEST_GetMinMaxManifestFileSize()));
|
||||
if (i > 1) {
|
||||
++i;
|
||||
}
|
||||
ASSERT_OK(
|
||||
db_->SetDBOptions({{"max_manifest_space_amp_pct", std::to_string(i)}}));
|
||||
ASSERT_EQ(i, static_cast<int64_t>(
|
||||
db_->GetDBOptions().max_manifest_space_amp_pct));
|
||||
ASSERT_EQ(i,
|
||||
static_cast<int64_t>(
|
||||
dbfull()->GetVersionSet()->TEST_GetMaxManifestSpaceAmpPct()));
|
||||
if (i > 1) {
|
||||
++i;
|
||||
}
|
||||
ASSERT_OK(db_->SetDBOptions(
|
||||
{{"manifest_preallocation_size", std::to_string(i)}}));
|
||||
ASSERT_EQ(i, static_cast<int64_t>(
|
||||
db_->GetDBOptions().manifest_preallocation_size));
|
||||
ASSERT_EQ(
|
||||
i, static_cast<int64_t>(
|
||||
dbfull()->GetVersionSet()->TEST_GetManifestPreallocationSize()));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DBOptionsTest, WritableFileMaxBufferSize) {
|
||||
Options options;
|
||||
options.create_if_missing = true;
|
||||
options.writable_file_max_buffer_size = 1024 * 1024;
|
||||
options.level0_file_num_compaction_trigger = 3;
|
||||
options.max_manifest_file_size = 1;
|
||||
options.max_manifest_space_amp_pct = 0;
|
||||
options.env = env_;
|
||||
int buffer_size = 1024 * 1024;
|
||||
Reopen(options);
|
||||
|
||||
+245
@@ -1492,6 +1492,246 @@ TEST_F(DBTest, MetaDataTest) {
|
||||
CheckLiveFilesMeta(live_file_meta, files_by_level);
|
||||
}
|
||||
|
||||
TEST_F(DBTest, GetColumnFamilyMetaDataWithKeyRangeAndLevel) {
|
||||
Options options = CurrentOptions();
|
||||
options.create_if_missing = true;
|
||||
options.disable_auto_compactions = true;
|
||||
|
||||
int64_t temp_time = 0;
|
||||
ASSERT_OK(options.env->GetCurrentTime(&temp_time));
|
||||
|
||||
DestroyAndReopen(options);
|
||||
|
||||
Random rnd(301);
|
||||
int key_index = 0;
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
// Add a single blob reference to each file
|
||||
std::string blob_index;
|
||||
BlobIndex::EncodeBlob(&blob_index, /* blob_file_number */ i + 1000,
|
||||
/* offset */ 1234, /* size */ 5678, kNoCompression);
|
||||
|
||||
WriteBatch batch;
|
||||
ASSERT_OK(WriteBatchInternal::PutBlobIndex(&batch, 0, Key(key_index),
|
||||
blob_index));
|
||||
ASSERT_OK(dbfull()->Write(WriteOptions(), &batch));
|
||||
|
||||
++key_index;
|
||||
|
||||
// Fill up the rest of the file with random values.
|
||||
GenerateNewFile(&rnd, &key_index, /* nowait */ true);
|
||||
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
|
||||
std::vector<std::vector<FileMetaData>> files_by_level;
|
||||
dbfull()->TEST_GetFilesMetaData(db_->DefaultColumnFamily(), &files_by_level);
|
||||
|
||||
ASSERT_OK(options.env->GetCurrentTime(&temp_time));
|
||||
|
||||
ColumnFamilyMetaData cf_meta;
|
||||
// Keys in the SST files are distributed
|
||||
// (key000000, key000100) ->File 1
|
||||
// (key000101, key000201) -> File 2
|
||||
// (key000202, key000302) -> File 3
|
||||
// (key009999, key010099) -> File 100
|
||||
|
||||
// With keySlice (key000050, key000150) => should only pick 2 files(instead of
|
||||
// default 100 that is in the level)
|
||||
auto startKey = Slice("key000050");
|
||||
auto endKey = Slice("key000150");
|
||||
GetColumnFamilyMetaDataOptions cf_options(startKey, endKey, 0);
|
||||
db_->GetColumnFamilyMetaData(cf_options, &cf_meta);
|
||||
ASSERT_EQ(cf_meta.levels.size(), 1);
|
||||
const auto& level_meta_from_cf = cf_meta.levels[0];
|
||||
ASSERT_EQ(level_meta_from_cf.files.size(), 2);
|
||||
ASSERT_LT(level_meta_from_cf.files[1].smallestkey,
|
||||
std::string(startKey.data()));
|
||||
ASSERT_GT(level_meta_from_cf.files[0].largestkey, std::string(endKey.data()));
|
||||
|
||||
GetColumnFamilyMetaDataOptions cf_option_default;
|
||||
db_->GetColumnFamilyMetaData(cf_option_default, &cf_meta);
|
||||
ASSERT_EQ(cf_meta.levels.size(), 1);
|
||||
ASSERT_EQ(cf_meta.levels[0].files.size(), 100);
|
||||
|
||||
// Test with start key valid and end key unbounded
|
||||
// This should get all files from key000150 onwards (99 files)
|
||||
auto startKeyUnbounded = Slice("key000150");
|
||||
GetColumnFamilyMetaDataOptions cf_options_unbounded_end(startKeyUnbounded,
|
||||
OptSlice(), 0);
|
||||
db_->GetColumnFamilyMetaData(cf_options_unbounded_end, &cf_meta);
|
||||
ASSERT_EQ(cf_meta.levels.size(), 1);
|
||||
ASSERT_EQ(cf_meta.levels[0].files.size(), 99);
|
||||
|
||||
// Test with end key valid and start key unbounded
|
||||
// This should get all files from beginning to key000250 ( 3 files)
|
||||
auto endKeyUnbounded = Slice("key000250");
|
||||
GetColumnFamilyMetaDataOptions cf_options_unbounded_start(OptSlice(),
|
||||
endKeyUnbounded, 0);
|
||||
db_->GetColumnFamilyMetaData(cf_options_unbounded_start, &cf_meta);
|
||||
ASSERT_EQ(cf_meta.levels.size(), 1);
|
||||
ASSERT_EQ(cf_meta.levels[0].files.size(), 3);
|
||||
}
|
||||
|
||||
TEST_F(DBTest, GetColumnFamilyMetaDataBottommostLevel) {
|
||||
Options options = CurrentOptions();
|
||||
options.create_if_missing = true;
|
||||
options.disable_auto_compactions = true;
|
||||
options.num_levels = 7;
|
||||
|
||||
DestroyAndReopen(options);
|
||||
|
||||
Random rnd(301);
|
||||
int key_index = 0;
|
||||
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
GenerateNewFile(&rnd, &key_index, /* nowait */ true);
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
|
||||
CompactRangeOptions compact_options;
|
||||
compact_options.bottommost_level_compaction =
|
||||
BottommostLevelCompaction::kForce;
|
||||
compact_options.change_level = true;
|
||||
compact_options.target_level = 6;
|
||||
ASSERT_OK(db_->CompactRange(compact_options, nullptr, nullptr));
|
||||
|
||||
// Nothing on Level 0 after compaction
|
||||
ColumnFamilyMetaData cf_meta;
|
||||
GetColumnFamilyMetaDataOptions cf_options_0(OptSlice(), OptSlice(), 0);
|
||||
db_->GetColumnFamilyMetaData(cf_options_0, &cf_meta);
|
||||
|
||||
ASSERT_EQ(cf_meta.levels.size(), 0);
|
||||
ASSERT_EQ(cf_meta.file_count, 0);
|
||||
|
||||
// Data should be in Level 6
|
||||
GetColumnFamilyMetaDataOptions cf_options(OptSlice(), OptSlice(), 6);
|
||||
db_->GetColumnFamilyMetaData(cf_options, &cf_meta);
|
||||
|
||||
ASSERT_EQ(cf_meta.levels.size(), 1);
|
||||
ASSERT_EQ(cf_meta.levels[0].level, 6);
|
||||
ASSERT_GT(cf_meta.levels[0].files.size(), 0);
|
||||
size_t all_files = cf_meta.levels[0].files.size();
|
||||
|
||||
// Keys in the SST files are distributed across level 6
|
||||
// Test with key range - should only return files within the range
|
||||
auto startKey = Slice("key000050");
|
||||
auto endKey = Slice("key000150");
|
||||
GetColumnFamilyMetaDataOptions cf_options_range(startKey, endKey, 6);
|
||||
db_->GetColumnFamilyMetaData(cf_options_range, &cf_meta);
|
||||
|
||||
ASSERT_EQ(cf_meta.levels.size(), 1);
|
||||
ASSERT_EQ(cf_meta.levels[0].level, 6);
|
||||
ASSERT_GT(cf_meta.levels[0].files.size(), 0);
|
||||
size_t files_in_range = cf_meta.levels[0].files.size();
|
||||
|
||||
// Files in range should be less than or equal to all files
|
||||
ASSERT_LE(files_in_range, all_files);
|
||||
}
|
||||
|
||||
TEST_F(DBTest, GetColumnFamilyMetaDataMultipleLevels) {
|
||||
Options options = CurrentOptions();
|
||||
options.create_if_missing = true;
|
||||
options.disable_auto_compactions = true;
|
||||
options.num_levels = 7;
|
||||
|
||||
DestroyAndReopen(options);
|
||||
|
||||
Random rnd(301);
|
||||
int key_index = 0;
|
||||
|
||||
for (int i = 0; i < 50; ++i) {
|
||||
GenerateNewFile(&rnd, &key_index, /* nowait */ true);
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
|
||||
CompactRangeOptions compact_options;
|
||||
compact_options.bottommost_level_compaction =
|
||||
BottommostLevelCompaction::kForce;
|
||||
compact_options.change_level = true;
|
||||
compact_options.target_level = 6;
|
||||
ASSERT_OK(db_->CompactRange(compact_options, nullptr, nullptr));
|
||||
|
||||
for (int i = 0; i < 30; ++i) {
|
||||
GenerateNewFile(&rnd, &key_index, /* nowait */ true);
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
|
||||
// First verify both levels have files without key range filter
|
||||
ColumnFamilyMetaData cf_meta_all_no_range;
|
||||
GetColumnFamilyMetaDataOptions cf_options_all_no_range;
|
||||
db_->GetColumnFamilyMetaData(cf_options_all_no_range, &cf_meta_all_no_range);
|
||||
|
||||
bool has_level_0 = false;
|
||||
bool has_level_6 = false;
|
||||
for (const auto& level : cf_meta_all_no_range.levels) {
|
||||
if (level.level == 0 && level.files.size() > 0) {
|
||||
has_level_0 = true;
|
||||
}
|
||||
if (level.level == 6 && level.files.size() > 0) {
|
||||
has_level_6 = true;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_TRUE(has_level_0);
|
||||
ASSERT_TRUE(has_level_6);
|
||||
|
||||
// Test querying bottommost level only with key range
|
||||
// Use a range that should be in the first set of files (now in level 6)
|
||||
auto startKey = Slice("key000050");
|
||||
auto endKey = Slice("key000150");
|
||||
ColumnFamilyMetaData cf_meta_bottommost;
|
||||
GetColumnFamilyMetaDataOptions cf_options_bottommost(startKey, endKey, 6);
|
||||
db_->GetColumnFamilyMetaData(cf_options_bottommost, &cf_meta_bottommost);
|
||||
|
||||
ASSERT_EQ(cf_meta_bottommost.levels.size(), 1);
|
||||
ASSERT_EQ(cf_meta_bottommost.levels[0].level, 6);
|
||||
ASSERT_GT(cf_meta_bottommost.levels[0].files.size(), 0);
|
||||
size_t level_6_files_in_range = cf_meta_bottommost.levels[0].files.size();
|
||||
|
||||
// Test querying all levels with same key range
|
||||
ColumnFamilyMetaData cf_meta_all;
|
||||
GetColumnFamilyMetaDataOptions cf_options_all(startKey, endKey);
|
||||
db_->GetColumnFamilyMetaData(cf_options_all, &cf_meta_all);
|
||||
|
||||
size_t level_6_files_in_range_from_all = 0;
|
||||
for (const auto& level : cf_meta_all.levels) {
|
||||
if (level.level == 6) {
|
||||
level_6_files_in_range_from_all = level.files.size();
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_GT(level_6_files_in_range_from_all, 0);
|
||||
ASSERT_EQ(level_6_files_in_range, level_6_files_in_range_from_all);
|
||||
}
|
||||
|
||||
TEST_F(DBTest, GetColumnFamilyMetaDataEmptyDB) {
|
||||
Options options = CurrentOptions();
|
||||
options.create_if_missing = true;
|
||||
options.num_levels = 7;
|
||||
|
||||
DestroyAndReopen(options);
|
||||
|
||||
// Test on empty database
|
||||
ColumnFamilyMetaData cf_meta_empty_db;
|
||||
GetColumnFamilyMetaDataOptions cf_options_empty_db;
|
||||
db_->GetColumnFamilyMetaData(cf_options_empty_db, &cf_meta_empty_db);
|
||||
|
||||
ASSERT_EQ(cf_meta_empty_db.levels.size(), 0);
|
||||
ASSERT_EQ(cf_meta_empty_db.file_count, 0);
|
||||
ASSERT_EQ(cf_meta_empty_db.size, 0);
|
||||
|
||||
// Test on empty database with key range
|
||||
auto startKey = Slice("key000050");
|
||||
auto endKey = Slice("key000150");
|
||||
ColumnFamilyMetaData cf_meta_empty_range;
|
||||
GetColumnFamilyMetaDataOptions cf_options_empty_range(startKey, endKey);
|
||||
db_->GetColumnFamilyMetaData(cf_options_empty_range, &cf_meta_empty_range);
|
||||
|
||||
ASSERT_EQ(cf_meta_empty_range.levels.size(), 0);
|
||||
ASSERT_EQ(cf_meta_empty_range.file_count, 0);
|
||||
ASSERT_EQ(cf_meta_empty_range.size, 0);
|
||||
}
|
||||
|
||||
TEST_F(DBTest, AllMetaDataTest) {
|
||||
Options options = CurrentOptions();
|
||||
options.create_if_missing = true;
|
||||
@@ -3535,6 +3775,11 @@ class ModelDB : public DB {
|
||||
void GetColumnFamilyMetaData(ColumnFamilyHandle* /*column_family*/,
|
||||
ColumnFamilyMetaData* /*metadata*/) override {}
|
||||
|
||||
void GetColumnFamilyMetaData(
|
||||
ColumnFamilyHandle* /*column_family*/,
|
||||
const GetColumnFamilyMetaDataOptions& /*options*/,
|
||||
ColumnFamilyMetaData* /*metadata*/) override {}
|
||||
|
||||
Status GetDbIdentity(std::string& /*identity*/) const override {
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
@@ -5205,6 +5205,7 @@ TEST_F(DBTest2, SwitchMemtableRaceWithNewManifest) {
|
||||
Options options = CurrentOptions();
|
||||
DestroyAndReopen(options);
|
||||
options.max_manifest_file_size = 10;
|
||||
options.max_manifest_space_amp_pct = 0;
|
||||
options.create_if_missing = true;
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
ASSERT_EQ(2, handles_.size());
|
||||
@@ -5896,6 +5897,7 @@ TEST_P(RenameCurrentTest, Flush) {
|
||||
Destroy(last_options_);
|
||||
Options options = GetDefaultOptions();
|
||||
options.max_manifest_file_size = 1;
|
||||
options.max_manifest_space_amp_pct = 0;
|
||||
options.create_if_missing = true;
|
||||
Reopen(options);
|
||||
ASSERT_OK(Put("key", "value"));
|
||||
@@ -5915,6 +5917,7 @@ TEST_P(RenameCurrentTest, Compaction) {
|
||||
Destroy(last_options_);
|
||||
Options options = GetDefaultOptions();
|
||||
options.max_manifest_file_size = 1;
|
||||
options.max_manifest_space_amp_pct = 0;
|
||||
options.create_if_missing = true;
|
||||
Reopen(options);
|
||||
ASSERT_OK(Put("a", "a_value"));
|
||||
|
||||
+2
-1
@@ -454,7 +454,8 @@ Options DBTestBase::GetOptions(
|
||||
options.allow_mmap_reads = can_allow_mmap;
|
||||
break;
|
||||
case kManifestFileSize:
|
||||
options.max_manifest_file_size = 50; // 50 bytes
|
||||
options.max_manifest_file_size = 50; // 50 bytes
|
||||
options.max_manifest_space_amp_pct = 0; // old behavior
|
||||
break;
|
||||
case kPerfOptions:
|
||||
options.delayed_write_rate = 8 * 1024 * 1024;
|
||||
|
||||
+3
-2
@@ -1746,8 +1746,8 @@ class RecoveryTestHelper {
|
||||
WriteController write_controller;
|
||||
|
||||
versions.reset(new VersionSet(
|
||||
test->dbname_, &db_options, file_options, table_cache.get(),
|
||||
&write_buffer_manager, &write_controller,
|
||||
test->dbname_, &db_options, MutableDBOptions{options}, file_options,
|
||||
table_cache.get(), &write_buffer_manager, &write_controller,
|
||||
/*block_cache_tracer=*/nullptr,
|
||||
/*io_tracer=*/nullptr, /*db_id=*/"", /*db_session_id=*/"",
|
||||
options.daily_offpeak_time_utc,
|
||||
@@ -2277,6 +2277,7 @@ TEST_F(DBWALTest, FixSyncWalOnObseletedWalWithNewManifestCausingMissingWAL) {
|
||||
Options options = CurrentOptions();
|
||||
// Small size to force manifest creation
|
||||
options.max_manifest_file_size = 1;
|
||||
options.max_manifest_space_amp_pct = 0;
|
||||
options.track_and_verify_wals_in_manifest = true;
|
||||
DestroyAndReopen(options);
|
||||
|
||||
|
||||
@@ -142,13 +142,13 @@ class FlushJobTestBase : public testing::Test {
|
||||
column_families.emplace_back(cf_name, cf_options_);
|
||||
}
|
||||
|
||||
versions_.reset(
|
||||
new VersionSet(dbname_, &db_options_, env_options_, table_cache_.get(),
|
||||
&write_buffer_manager_, &write_controller_,
|
||||
/*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
|
||||
test::kUnitTestDbId, /*db_session_id=*/"",
|
||||
/*daily_offpeak_time_utc=*/"",
|
||||
/*error_handler=*/nullptr, /*read_only=*/false));
|
||||
versions_.reset(new VersionSet(
|
||||
dbname_, &db_options_, MutableDBOptions{options_}, env_options_,
|
||||
table_cache_.get(), &write_buffer_manager_, &write_controller_,
|
||||
/*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
|
||||
test::kUnitTestDbId, /*db_session_id=*/"",
|
||||
/*daily_offpeak_time_utc=*/"",
|
||||
/*error_handler=*/nullptr, /*read_only=*/false));
|
||||
EXPECT_OK(versions_->Recover(column_families, false));
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +112,8 @@ class MemTableListTest : public testing::Test {
|
||||
WriteBufferManager write_buffer_manager(db_options.db_write_buffer_size);
|
||||
WriteController write_controller(10000000u);
|
||||
|
||||
VersionSet versions(dbname, &immutable_db_options, env_options,
|
||||
VersionSet versions(dbname, &immutable_db_options,
|
||||
MutableDBOptions{db_options}, env_options,
|
||||
table_cache.get(), &write_buffer_manager,
|
||||
&write_controller, /*block_cache_tracer=*/nullptr,
|
||||
/*io_tracer=*/nullptr, /*db_id=*/"",
|
||||
@@ -163,7 +164,8 @@ class MemTableListTest : public testing::Test {
|
||||
WriteBufferManager write_buffer_manager(db_options.db_write_buffer_size);
|
||||
WriteController write_controller(10000000u);
|
||||
|
||||
VersionSet versions(dbname, &immutable_db_options, env_options,
|
||||
VersionSet versions(dbname, &immutable_db_options,
|
||||
MutableDBOptions{db_options}, env_options,
|
||||
table_cache.get(), &write_buffer_manager,
|
||||
&write_controller, /*block_cache_tracer=*/nullptr,
|
||||
/*io_tracer=*/nullptr, /*db_id=*/"",
|
||||
|
||||
+2
-2
@@ -120,8 +120,8 @@ class Repairer {
|
||||
/*io_tracer=*/nullptr, db_session_id_)),
|
||||
wb_(db_options_.db_write_buffer_size),
|
||||
wc_(db_options_.delayed_write_rate),
|
||||
vset_(dbname_, &immutable_db_options_, file_options_,
|
||||
raw_table_cache_.get(), &wb_, &wc_,
|
||||
vset_(dbname_, &immutable_db_options_, MutableDBOptions{db_options_},
|
||||
file_options_, raw_table_cache_.get(), &wb_, &wc_,
|
||||
/*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
|
||||
/*db_id=*/"", db_session_id_, db_options.daily_offpeak_time_utc,
|
||||
/*error_handler=*/nullptr, /*read_only=*/false),
|
||||
|
||||
+125
-12
@@ -2024,6 +2024,79 @@ void Version::GetColumnFamilyMetaData(ColumnFamilyMetaData* cf_meta) {
|
||||
}
|
||||
}
|
||||
|
||||
void Version::GetColumnFamilyMetaData(
|
||||
const GetColumnFamilyMetaDataOptions& options,
|
||||
ColumnFamilyMetaData* cf_meta) {
|
||||
assert(cf_meta);
|
||||
assert(cfd_);
|
||||
|
||||
cf_meta->name = cfd_->GetName();
|
||||
cf_meta->size = 0;
|
||||
cf_meta->file_count = 0;
|
||||
cf_meta->levels.clear();
|
||||
cf_meta->blob_file_size = 0;
|
||||
cf_meta->blob_file_count = 0;
|
||||
cf_meta->blob_files.clear();
|
||||
|
||||
const auto& ioptions = cfd_->ioptions();
|
||||
auto* vstorage = storage_info();
|
||||
|
||||
int first_level = (options.level >= 0) ? options.level : 0;
|
||||
int last_level =
|
||||
(options.level >= 0) ? options.level + 1 : cfd_->NumberLevels();
|
||||
|
||||
InternalKey ikey_start, ikey_end;
|
||||
const InternalKey* begin = nullptr;
|
||||
const InternalKey* end = nullptr;
|
||||
|
||||
if (options.range.start.has_value()) {
|
||||
ikey_start = InternalKey(options.range.start.value(), kMaxSequenceNumber,
|
||||
kValueTypeForSeek);
|
||||
begin = &ikey_start;
|
||||
}
|
||||
|
||||
if (options.range.limit.has_value()) {
|
||||
ikey_end = InternalKey(options.range.limit.value(), kMaxSequenceNumber,
|
||||
kValueTypeForSeek);
|
||||
end = &ikey_end;
|
||||
}
|
||||
|
||||
for (int l = first_level; l < last_level; ++l) {
|
||||
uint64_t level_size = 0;
|
||||
std::vector<SstFileMetaData> files;
|
||||
std::vector<FileMetaData*> overlapping_files;
|
||||
vstorage->GetOverlappingInputs(l, begin, end, &overlapping_files);
|
||||
|
||||
for (const auto& file : overlapping_files) {
|
||||
uint32_t path_id = file->fd.GetPathId();
|
||||
const auto& file_path = (path_id < ioptions.cf_paths.size())
|
||||
? ioptions.cf_paths[path_id].path
|
||||
: ioptions.cf_paths.back().path;
|
||||
const uint64_t file_number = file->fd.GetNumber();
|
||||
files.emplace_back(
|
||||
MakeTableFileName("", file_number), file_number, file_path,
|
||||
file->fd.GetFileSize(), file->fd.smallest_seqno,
|
||||
file->fd.largest_seqno, file->smallest.user_key().ToString(),
|
||||
file->largest.user_key().ToString(),
|
||||
file->stats.num_reads_sampled.load(std::memory_order_relaxed),
|
||||
file->being_compacted, file->temperature,
|
||||
file->oldest_blob_file_number, file->TryGetOldestAncesterTime(),
|
||||
file->TryGetFileCreationTime(), file->epoch_number,
|
||||
file->file_checksum, file->file_checksum_func_name);
|
||||
files.back().num_entries = file->num_entries;
|
||||
files.back().num_deletions = file->num_deletions;
|
||||
files.back().smallest = file->smallest.Encode().ToString();
|
||||
files.back().largest = file->largest.Encode().ToString();
|
||||
level_size += file->fd.GetFileSize();
|
||||
cf_meta->file_count++;
|
||||
}
|
||||
if (!files.empty()) {
|
||||
cf_meta->levels.emplace_back(l, level_size, std::move(files));
|
||||
cf_meta->size += level_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t Version::GetSstFilesSize() {
|
||||
uint64_t sst_files_size = 0;
|
||||
for (int level = 0; level < storage_info_.num_levels_; level++) {
|
||||
@@ -5307,6 +5380,7 @@ void AtomicGroupReadBuffer::Clear() {
|
||||
|
||||
VersionSet::VersionSet(
|
||||
const std::string& dbname, const ImmutableDBOptions* _db_options,
|
||||
const MutableDBOptions& mutable_db_options,
|
||||
const FileOptions& storage_options, Cache* table_cache,
|
||||
WriteBufferManager* write_buffer_manager, WriteController* write_controller,
|
||||
BlockCacheTracer* const block_cache_tracer,
|
||||
@@ -5335,6 +5409,7 @@ VersionSet::VersionSet(
|
||||
prev_log_number_(0),
|
||||
current_version_number_(0),
|
||||
manifest_file_size_(0),
|
||||
last_compacted_manifest_file_size_(0),
|
||||
file_options_(storage_options),
|
||||
block_cache_tracer_(block_cache_tracer),
|
||||
io_tracer_(io_tracer),
|
||||
@@ -5342,7 +5417,9 @@ VersionSet::VersionSet(
|
||||
offpeak_time_option_(OffpeakTimeOption(daily_offpeak_time_utc)),
|
||||
error_handler_(error_handler),
|
||||
unchanging_(unchanging),
|
||||
closed_(false) {}
|
||||
closed_(false) {
|
||||
UpdatedMutableDbOptions(mutable_db_options, /*mu=*/nullptr);
|
||||
}
|
||||
|
||||
Status VersionSet::Close(FSDirectory* db_dir, InstrumentedMutex* mu) {
|
||||
Status s;
|
||||
@@ -5438,11 +5515,35 @@ void VersionSet::Reset() {
|
||||
current_version_number_ = 0;
|
||||
manifest_writers_.clear();
|
||||
manifest_file_size_ = 0;
|
||||
last_compacted_manifest_file_size_ = 0;
|
||||
TuneMaxManifestFileSize();
|
||||
obsolete_files_.clear();
|
||||
obsolete_manifests_.clear();
|
||||
wals_.Reset();
|
||||
}
|
||||
|
||||
void VersionSet::UpdatedMutableDbOptions(
|
||||
const MutableDBOptions& updated_options, InstrumentedMutex* mu) {
|
||||
// Must be holding mutex if not called during initialization
|
||||
if (manifest_file_size_ > 0) {
|
||||
mu->AssertHeld();
|
||||
}
|
||||
file_options_.writable_file_max_buffer_size =
|
||||
updated_options.writable_file_max_buffer_size;
|
||||
min_max_manifest_file_size_ = updated_options.max_manifest_file_size;
|
||||
max_manifest_space_amp_pct_ = static_cast<unsigned>(
|
||||
std::max(updated_options.max_manifest_space_amp_pct, 0));
|
||||
manifest_preallocation_size_ = updated_options.manifest_preallocation_size;
|
||||
TuneMaxManifestFileSize();
|
||||
}
|
||||
|
||||
void VersionSet::TuneMaxManifestFileSize() {
|
||||
tuned_max_manifest_file_size_ =
|
||||
std::max(min_max_manifest_file_size_,
|
||||
last_compacted_manifest_file_size_ *
|
||||
(100U + max_manifest_space_amp_pct_) / 100U);
|
||||
}
|
||||
|
||||
void VersionSet::AppendVersion(ColumnFamilyData* column_family_data,
|
||||
Version* v) {
|
||||
// compute new compaction score
|
||||
@@ -5686,10 +5787,11 @@ Status VersionSet::ProcessManifestWrites(
|
||||
}
|
||||
#endif // NDEBUG
|
||||
|
||||
uint64_t prev_manifest_file_size = manifest_file_size_;
|
||||
assert(pending_manifest_file_number_ == 0);
|
||||
if (!skip_manifest_write &&
|
||||
(!descriptor_log_ ||
|
||||
manifest_file_size_ > db_options_->max_manifest_file_size)) {
|
||||
prev_manifest_file_size >= tuned_max_manifest_file_size_)) {
|
||||
TEST_SYNC_POINT("VersionSet::ProcessManifestWrites:BeforeNewManifest");
|
||||
new_descriptor_log = true;
|
||||
} else {
|
||||
@@ -5729,6 +5831,8 @@ Status VersionSet::ProcessManifestWrites(
|
||||
IOStatus manifest_io_status;
|
||||
manifest_io_status.PermitUncheckedError();
|
||||
std::unique_ptr<log::Writer> new_desc_log_ptr;
|
||||
// Save before releasing mu
|
||||
uint64_t manifest_preallocation_size = manifest_preallocation_size_;
|
||||
if (skip_manifest_write) {
|
||||
if (s.ok()) {
|
||||
constexpr bool update_stats = true;
|
||||
@@ -5772,16 +5876,13 @@ Status VersionSet::ProcessManifestWrites(
|
||||
// This is fine because everything inside of this block is serialized --
|
||||
// only one thread can be here at the same time
|
||||
// create new manifest file
|
||||
ROCKS_LOG_INFO(db_options_->info_log, "Creating manifest %" PRIu64 "\n",
|
||||
pending_manifest_file_number_);
|
||||
std::string descriptor_fname =
|
||||
DescriptorFileName(dbname_, pending_manifest_file_number_);
|
||||
std::unique_ptr<FSWritableFile> descriptor_file;
|
||||
io_s = NewWritableFile(fs_.get(), descriptor_fname, &descriptor_file,
|
||||
opt_file_opts);
|
||||
if (io_s.ok()) {
|
||||
descriptor_file->SetPreallocationBlockSize(
|
||||
db_options_->manifest_preallocation_size);
|
||||
descriptor_file->SetPreallocationBlockSize(manifest_preallocation_size);
|
||||
FileTypeSet tmp_set = db_options_->checksum_handoff_file_types;
|
||||
std::unique_ptr<WritableFileWriter> file_writer(new WritableFileWriter(
|
||||
std::move(descriptor_file), descriptor_fname, opt_file_opts, clock_,
|
||||
@@ -5882,6 +5983,13 @@ Status VersionSet::ProcessManifestWrites(
|
||||
if (s.ok()) {
|
||||
// find offset in manifest file where this version is stored.
|
||||
new_manifest_file_size = raw_desc_log_ptr->file()->GetFileSize();
|
||||
if (new_descriptor_log) {
|
||||
ROCKS_LOG_INFO(db_options_->info_log,
|
||||
"Created manifest %" PRIu64
|
||||
", compacted+appended from %" PRIu64 " to %" PRIu64 "\n",
|
||||
pending_manifest_file_number_, prev_manifest_file_size,
|
||||
new_manifest_file_size);
|
||||
}
|
||||
}
|
||||
|
||||
if (first_writer.edit_list.front()->IsColumnFamilyDrop()) {
|
||||
@@ -5930,6 +6038,8 @@ Status VersionSet::ProcessManifestWrites(
|
||||
descriptor_log_ = std::move(new_desc_log_ptr);
|
||||
obsolete_manifests_.emplace_back(
|
||||
DescriptorFileName("", manifest_file_number_));
|
||||
last_compacted_manifest_file_size_ = new_manifest_file_size;
|
||||
TuneMaxManifestFileSize();
|
||||
}
|
||||
|
||||
// Install the new versions
|
||||
@@ -6563,14 +6673,16 @@ Status VersionSet::ReduceNumberOfLevels(const std::string& dbname,
|
||||
const ReadOptions read_options;
|
||||
const WriteOptions write_options;
|
||||
|
||||
ImmutableDBOptions db_options(*options);
|
||||
ImmutableDBOptions imm_db_options(*options);
|
||||
MutableDBOptions mutable_db_options(*options);
|
||||
ColumnFamilyOptions cf_options(*options);
|
||||
std::shared_ptr<Cache> tc(NewLRUCache(options->max_open_files - 10,
|
||||
options->table_cache_numshardbits));
|
||||
WriteController wc(options->delayed_write_rate);
|
||||
WriteBufferManager wb(options->db_write_buffer_size);
|
||||
VersionSet versions(dbname, &db_options, file_options, tc.get(), &wb, &wc,
|
||||
nullptr /*BlockCacheTracer*/, nullptr /*IOTracer*/,
|
||||
VersionSet versions(dbname, &imm_db_options, mutable_db_options, file_options,
|
||||
tc.get(), &wb, &wc, nullptr /*BlockCacheTracer*/,
|
||||
nullptr /*IOTracer*/,
|
||||
/*db_id*/ "",
|
||||
/*db_session_id*/ "", options->daily_offpeak_time_utc,
|
||||
/*error_handler_*/ nullptr, /*unchanging=*/false);
|
||||
@@ -7622,12 +7734,13 @@ Status VersionSet::VerifyFileMetadata(const ReadOptions& read_options,
|
||||
}
|
||||
|
||||
ReactiveVersionSet::ReactiveVersionSet(
|
||||
const std::string& dbname, const ImmutableDBOptions* _db_options,
|
||||
const std::string& dbname, const ImmutableDBOptions* imm_db_options,
|
||||
const MutableDBOptions& mutable_db_options,
|
||||
const FileOptions& _file_options, Cache* table_cache,
|
||||
WriteBufferManager* write_buffer_manager, WriteController* write_controller,
|
||||
const std::shared_ptr<IOTracer>& io_tracer)
|
||||
: VersionSet(dbname, _db_options, _file_options, table_cache,
|
||||
write_buffer_manager, write_controller,
|
||||
: VersionSet(dbname, imm_db_options, mutable_db_options, _file_options,
|
||||
table_cache, write_buffer_manager, write_controller,
|
||||
/*block_cache_tracer=*/nullptr, io_tracer, /*db_id*/ "",
|
||||
/*db_session_id*/ "", /*daily_offpeak_time_utc*/ "",
|
||||
/*error_handler=*/nullptr, /*unchanging=*/false) {}
|
||||
|
||||
+45
-5
@@ -1044,6 +1044,10 @@ class Version {
|
||||
|
||||
void GetColumnFamilyMetaData(ColumnFamilyMetaData* cf_meta);
|
||||
|
||||
// Get column family metadata with optional filtering by key range and level.
|
||||
void GetColumnFamilyMetaData(const GetColumnFamilyMetaDataOptions& options,
|
||||
ColumnFamilyMetaData* cf_meta);
|
||||
|
||||
void GetSstFilesBoundaryKeys(Slice* smallest_user_key,
|
||||
Slice* largest_user_key);
|
||||
|
||||
@@ -1186,7 +1190,9 @@ class AtomicGroupReadBuffer {
|
||||
// but false for secondary instance or writable DB).
|
||||
class VersionSet {
|
||||
public:
|
||||
VersionSet(const std::string& dbname, const ImmutableDBOptions* db_options,
|
||||
VersionSet(const std::string& dbname,
|
||||
const ImmutableDBOptions* imm_db_options,
|
||||
const MutableDBOptions& mutable_db_options,
|
||||
const FileOptions& file_options, Cache* table_cache,
|
||||
WriteBufferManager* write_buffer_manager,
|
||||
WriteController* write_controller,
|
||||
@@ -1203,6 +1209,13 @@ class VersionSet {
|
||||
|
||||
virtual Status Close(FSDirectory* db_dir, InstrumentedMutex* mu);
|
||||
|
||||
// Requires: already holding DB mutex `mu`, to ensure
|
||||
// * Safely read values from `updated_options`
|
||||
// * Safely update fields on `this` (must be read elsewhere while holding mu)
|
||||
// except `mu` can be nullptr during initialization
|
||||
void UpdatedMutableDbOptions(const MutableDBOptions& updated_options,
|
||||
InstrumentedMutex* mu);
|
||||
|
||||
Status LogAndApplyToDefaultColumnFamily(
|
||||
const ReadOptions& read_options, const WriteOptions& write_options,
|
||||
VersionEdit* edit, InstrumentedMutex* mu,
|
||||
@@ -1548,10 +1561,6 @@ class VersionSet {
|
||||
}
|
||||
|
||||
const FileOptions& file_options() { return file_options_; }
|
||||
void ChangeFileOptions(const MutableDBOptions& new_options) {
|
||||
file_options_.writable_file_max_buffer_size =
|
||||
new_options.writable_file_max_buffer_size;
|
||||
}
|
||||
|
||||
// TODO - Consider updating together when file options change in SetDBOptions
|
||||
const OffpeakTimeOption& offpeak_time_option() {
|
||||
@@ -1590,6 +1599,16 @@ class VersionSet {
|
||||
|
||||
bool& TEST_unchanging() { return const_cast<bool&>(unchanging_); }
|
||||
|
||||
uint64_t TEST_GetMinMaxManifestFileSize() {
|
||||
return min_max_manifest_file_size_;
|
||||
}
|
||||
unsigned TEST_GetMaxManifestSpaceAmpPct() {
|
||||
return max_manifest_space_amp_pct_;
|
||||
}
|
||||
size_t TEST_GetManifestPreallocationSize() {
|
||||
return manifest_preallocation_size_;
|
||||
}
|
||||
|
||||
protected:
|
||||
struct ManifestWriter;
|
||||
|
||||
@@ -1610,6 +1629,7 @@ class VersionSet {
|
||||
}
|
||||
};
|
||||
|
||||
// Revert back to a post-construction state (keep same options/settings)
|
||||
void Reset();
|
||||
|
||||
// Returns approximated offset of a key in a file for a given version.
|
||||
@@ -1648,6 +1668,11 @@ class VersionSet {
|
||||
ColumnFamilyData* cfd, const std::string& fpath,
|
||||
int level, const FileMetaData& meta);
|
||||
|
||||
// Auto-tune next max size for the current manifest file based on its initial
|
||||
// "compacted" size and other parameters saved in this VersionSet. Must be
|
||||
// holding DB mutex if outside of DB startup.
|
||||
void TuneMaxManifestFileSize();
|
||||
|
||||
// Protected by DB mutex.
|
||||
WalSet wals_;
|
||||
|
||||
@@ -1699,6 +1724,20 @@ class VersionSet {
|
||||
// Current size of manifest file
|
||||
uint64_t manifest_file_size_;
|
||||
|
||||
// Size of the populated manifest file last time it was re-written from
|
||||
// scratch.
|
||||
uint64_t last_compacted_manifest_file_size_;
|
||||
|
||||
// Auto-tuned max allowed size for the current manifest file
|
||||
uint64_t tuned_max_manifest_file_size_;
|
||||
|
||||
// Saved copy of max_manifest_file_size in (Mutable)DBOptions
|
||||
uint64_t min_max_manifest_file_size_;
|
||||
// Saved, sanitized copy from (Mutable)DBOptions
|
||||
unsigned max_manifest_space_amp_pct_;
|
||||
// Saved copy from (Mutable)DBOptions
|
||||
size_t manifest_preallocation_size_;
|
||||
|
||||
// Obsolete files, or during DB shutdown any files not referenced by what's
|
||||
// left of the in-memory LSM state.
|
||||
std::vector<ObsoleteFileInfo> obsolete_files_;
|
||||
@@ -1751,6 +1790,7 @@ class ReactiveVersionSet : public VersionSet {
|
||||
public:
|
||||
ReactiveVersionSet(const std::string& dbname,
|
||||
const ImmutableDBOptions* _db_options,
|
||||
const MutableDBOptions& mutable_db_options,
|
||||
const FileOptions& _file_options, Cache* table_cache,
|
||||
WriteBufferManager* write_buffer_manager,
|
||||
WriteController* write_controller,
|
||||
|
||||
+41
-39
@@ -1159,12 +1159,12 @@ class VersionSetTestBase {
|
||||
: env_(nullptr),
|
||||
dbname_(test::PerThreadDBPath(name)),
|
||||
options_(),
|
||||
db_options_(options_),
|
||||
imm_db_options_(options_),
|
||||
cf_options_(options_),
|
||||
immutable_options_(db_options_, cf_options_),
|
||||
immutable_options_(imm_db_options_, cf_options_),
|
||||
mutable_cf_options_(cf_options_),
|
||||
table_cache_(NewLRUCache(50000, 16)),
|
||||
write_buffer_manager_(db_options_.db_write_buffer_size),
|
||||
write_buffer_manager_(imm_db_options_.db_write_buffer_size),
|
||||
shutting_down_(false),
|
||||
table_factory_(std::make_shared<mock::MockTableFactory>()) {
|
||||
EXPECT_OK(test::CreateEnvFromSystem(ConfigOptions(), &env_, &env_guard_));
|
||||
@@ -1178,8 +1178,8 @@ class VersionSetTestBase {
|
||||
EXPECT_OK(fs_->CreateDirIfMissing(dbname_, IOOptions(), nullptr));
|
||||
|
||||
options_.env = env_;
|
||||
db_options_.env = env_;
|
||||
db_options_.fs = fs_;
|
||||
imm_db_options_.env = env_;
|
||||
imm_db_options_.fs = fs_;
|
||||
immutable_options_.env = env_;
|
||||
immutable_options_.fs = fs_;
|
||||
immutable_options_.clock = env_->GetSystemClock().get();
|
||||
@@ -1188,16 +1188,17 @@ class VersionSetTestBase {
|
||||
mutable_cf_options_.table_factory = table_factory_;
|
||||
|
||||
versions_.reset(new VersionSet(
|
||||
dbname_, &db_options_, env_options_, table_cache_.get(),
|
||||
&write_buffer_manager_, &write_controller_,
|
||||
dbname_, &imm_db_options_, mutable_db_options_, env_options_,
|
||||
table_cache_.get(), &write_buffer_manager_, &write_controller_,
|
||||
/*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
|
||||
/*db_id=*/"", /*db_session_id=*/"", /*daily_offpeak_time_utc=*/"",
|
||||
/*error_handler=*/nullptr, /*read_only=*/false));
|
||||
reactive_versions_ = std::make_shared<ReactiveVersionSet>(
|
||||
dbname_, &db_options_, env_options_, table_cache_.get(),
|
||||
&write_buffer_manager_, &write_controller_, nullptr);
|
||||
db_options_.db_paths.emplace_back(dbname_,
|
||||
std::numeric_limits<uint64_t>::max());
|
||||
dbname_, &imm_db_options_, mutable_db_options_, env_options_,
|
||||
table_cache_.get(), &write_buffer_manager_, &write_controller_,
|
||||
nullptr);
|
||||
imm_db_options_.db_paths.emplace_back(dbname_,
|
||||
std::numeric_limits<uint64_t>::max());
|
||||
}
|
||||
|
||||
virtual ~VersionSetTestBase() {
|
||||
@@ -1220,7 +1221,7 @@ class VersionSetTestBase {
|
||||
ASSERT_OK(
|
||||
SetIdentityFile(WriteOptions(), env_, dbname_, Temperature::kUnknown));
|
||||
VersionEdit new_db;
|
||||
if (db_options_.write_dbid_to_manifest) {
|
||||
if (imm_db_options_.write_dbid_to_manifest) {
|
||||
DBOptions tmp_db_options;
|
||||
tmp_db_options.env = env_;
|
||||
std::unique_ptr<DBImpl> impl(new DBImpl(tmp_db_options, dbname_));
|
||||
@@ -1381,8 +1382,8 @@ class VersionSetTestBase {
|
||||
|
||||
void ReopenDB() {
|
||||
versions_.reset(new VersionSet(
|
||||
dbname_, &db_options_, env_options_, table_cache_.get(),
|
||||
&write_buffer_manager_, &write_controller_,
|
||||
dbname_, &imm_db_options_, mutable_db_options_, env_options_,
|
||||
table_cache_.get(), &write_buffer_manager_, &write_controller_,
|
||||
/*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
|
||||
/*db_id=*/"", /*db_session_id=*/"", /*daily_offpeak_time_utc=*/"",
|
||||
/*error_handler=*/nullptr, /*read_only=*/false));
|
||||
@@ -1471,7 +1472,8 @@ class VersionSetTestBase {
|
||||
const std::string dbname_;
|
||||
EnvOptions env_options_;
|
||||
Options options_;
|
||||
ImmutableDBOptions db_options_;
|
||||
ImmutableDBOptions imm_db_options_;
|
||||
MutableDBOptions mutable_db_options_;
|
||||
ColumnFamilyOptions cf_options_;
|
||||
ImmutableOptions immutable_options_;
|
||||
MutableCFOptions mutable_cf_options_;
|
||||
@@ -1902,8 +1904,8 @@ TEST_F(VersionSetTest, WalAddition) {
|
||||
// Recover a new VersionSet.
|
||||
{
|
||||
std::unique_ptr<VersionSet> new_versions(new VersionSet(
|
||||
dbname_, &db_options_, env_options_, table_cache_.get(),
|
||||
&write_buffer_manager_, &write_controller_,
|
||||
dbname_, &imm_db_options_, mutable_db_options_, env_options_,
|
||||
table_cache_.get(), &write_buffer_manager_, &write_controller_,
|
||||
/*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
|
||||
/*db_id=*/"", /*db_session_id=*/"", /*daily_offpeak_time_utc=*/"",
|
||||
/*error_handler=*/nullptr, /*unchanging=*/false));
|
||||
@@ -1970,8 +1972,8 @@ TEST_F(VersionSetTest, WalCloseWithoutSync) {
|
||||
// Recover a new VersionSet.
|
||||
{
|
||||
std::unique_ptr<VersionSet> new_versions(new VersionSet(
|
||||
dbname_, &db_options_, env_options_, table_cache_.get(),
|
||||
&write_buffer_manager_, &write_controller_,
|
||||
dbname_, &imm_db_options_, mutable_db_options_, env_options_,
|
||||
table_cache_.get(), &write_buffer_manager_, &write_controller_,
|
||||
/*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
|
||||
/*db_id=*/"", /*db_session_id=*/"", /*daily_offpeak_time_utc=*/"",
|
||||
/*error_handler=*/nullptr, /*unchanging=*/false));
|
||||
@@ -2024,8 +2026,8 @@ TEST_F(VersionSetTest, WalDeletion) {
|
||||
// Recover a new VersionSet, only the non-closed WAL should show up.
|
||||
{
|
||||
std::unique_ptr<VersionSet> new_versions(new VersionSet(
|
||||
dbname_, &db_options_, env_options_, table_cache_.get(),
|
||||
&write_buffer_manager_, &write_controller_,
|
||||
dbname_, &imm_db_options_, mutable_db_options_, env_options_,
|
||||
table_cache_.get(), &write_buffer_manager_, &write_controller_,
|
||||
/*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
|
||||
/*db_id=*/"", /*db_session_id=*/"", /*daily_offpeak_time_utc=*/"",
|
||||
/*error_handler=*/nullptr, /*unchanging=*/false));
|
||||
@@ -2063,8 +2065,8 @@ TEST_F(VersionSetTest, WalDeletion) {
|
||||
// Recover from the new MANIFEST, only the non-closed WAL should show up.
|
||||
{
|
||||
std::unique_ptr<VersionSet> new_versions(new VersionSet(
|
||||
dbname_, &db_options_, env_options_, table_cache_.get(),
|
||||
&write_buffer_manager_, &write_controller_,
|
||||
dbname_, &imm_db_options_, mutable_db_options_, env_options_,
|
||||
table_cache_.get(), &write_buffer_manager_, &write_controller_,
|
||||
/*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
|
||||
/*db_id=*/"", /*db_session_id=*/"", /*daily_offpeak_time_utc=*/"",
|
||||
/*error_handler=*/nullptr, /*unchanging=*/false));
|
||||
@@ -2184,8 +2186,8 @@ TEST_F(VersionSetTest, DeleteWalsBeforeNonExistingWalNumber) {
|
||||
// Recover a new VersionSet, WAL0 is deleted, WAL1 is not.
|
||||
{
|
||||
std::unique_ptr<VersionSet> new_versions(new VersionSet(
|
||||
dbname_, &db_options_, env_options_, table_cache_.get(),
|
||||
&write_buffer_manager_, &write_controller_,
|
||||
dbname_, &imm_db_options_, mutable_db_options_, env_options_,
|
||||
table_cache_.get(), &write_buffer_manager_, &write_controller_,
|
||||
/*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
|
||||
/*db_id=*/"", /*db_session_id=*/"", /*daily_offpeak_time_utc=*/"",
|
||||
/*error_handler=*/nullptr, /*unchanging=*/false));
|
||||
@@ -2221,8 +2223,8 @@ TEST_F(VersionSetTest, DeleteAllWals) {
|
||||
// Recover a new VersionSet, all WALs are deleted.
|
||||
{
|
||||
std::unique_ptr<VersionSet> new_versions(new VersionSet(
|
||||
dbname_, &db_options_, env_options_, table_cache_.get(),
|
||||
&write_buffer_manager_, &write_controller_,
|
||||
dbname_, &imm_db_options_, mutable_db_options_, env_options_,
|
||||
table_cache_.get(), &write_buffer_manager_, &write_controller_,
|
||||
/*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
|
||||
/*db_id=*/"", /*db_session_id=*/"", /*daily_offpeak_time_utc=*/"",
|
||||
/*error_handler=*/nullptr, /*unchanging=*/false));
|
||||
@@ -2264,8 +2266,8 @@ TEST_F(VersionSetTest, AtomicGroupWithWalEdits) {
|
||||
// kept.
|
||||
{
|
||||
std::unique_ptr<VersionSet> new_versions(new VersionSet(
|
||||
dbname_, &db_options_, env_options_, table_cache_.get(),
|
||||
&write_buffer_manager_, &write_controller_,
|
||||
dbname_, &imm_db_options_, mutable_db_options_, env_options_,
|
||||
table_cache_.get(), &write_buffer_manager_, &write_controller_,
|
||||
/*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
|
||||
/*db_id=*/"", /*db_session_id=*/"", /*daily_offpeak_time_utc=*/"",
|
||||
/*error_handler=*/nullptr, /*unchanging=*/false));
|
||||
@@ -2444,8 +2446,8 @@ class VersionSetWithTimestampTest : public VersionSetTest {
|
||||
|
||||
void VerifyFullHistoryTsLow(uint64_t expected_ts_low) {
|
||||
std::unique_ptr<VersionSet> vset(new VersionSet(
|
||||
dbname_, &db_options_, env_options_, table_cache_.get(),
|
||||
&write_buffer_manager_, &write_controller_,
|
||||
dbname_, &imm_db_options_, mutable_db_options_, env_options_,
|
||||
table_cache_.get(), &write_buffer_manager_, &write_controller_,
|
||||
/*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
|
||||
/*db_id=*/"", /*db_session_id=*/"", /*daily_offpeak_time_utc=*/"",
|
||||
/*error_handler=*/nullptr, /*unchanging=*/false));
|
||||
@@ -3500,7 +3502,7 @@ class VersionSetTestEmptyDb
|
||||
std::unique_ptr<log::Writer>* log_writer) override {
|
||||
assert(nullptr != log_writer);
|
||||
VersionEdit new_db;
|
||||
if (db_options_.write_dbid_to_manifest) {
|
||||
if (imm_db_options_.write_dbid_to_manifest) {
|
||||
ASSERT_OK(SetIdentityFile(WriteOptions(), env_, dbname_,
|
||||
Temperature::kUnknown));
|
||||
DBOptions tmp_db_options;
|
||||
@@ -3532,7 +3534,7 @@ class VersionSetTestEmptyDb
|
||||
const std::string VersionSetTestEmptyDb::kUnknownColumnFamilyName = "unknown";
|
||||
|
||||
TEST_P(VersionSetTestEmptyDb, OpenFromIncompleteManifest0) {
|
||||
db_options_.write_dbid_to_manifest = std::get<0>(GetParam());
|
||||
imm_db_options_.write_dbid_to_manifest = std::get<0>(GetParam());
|
||||
PrepareManifest(nullptr, nullptr, &log_writer_);
|
||||
log_writer_.reset();
|
||||
CreateCurrentFile();
|
||||
@@ -3564,7 +3566,7 @@ TEST_P(VersionSetTestEmptyDb, OpenFromIncompleteManifest0) {
|
||||
}
|
||||
|
||||
TEST_P(VersionSetTestEmptyDb, OpenFromIncompleteManifest1) {
|
||||
db_options_.write_dbid_to_manifest = std::get<0>(GetParam());
|
||||
imm_db_options_.write_dbid_to_manifest = std::get<0>(GetParam());
|
||||
PrepareManifest(nullptr, nullptr, &log_writer_);
|
||||
// Only a subset of column families in the MANIFEST.
|
||||
VersionEdit new_cf1;
|
||||
@@ -3605,7 +3607,7 @@ TEST_P(VersionSetTestEmptyDb, OpenFromIncompleteManifest1) {
|
||||
}
|
||||
|
||||
TEST_P(VersionSetTestEmptyDb, OpenFromInCompleteManifest2) {
|
||||
db_options_.write_dbid_to_manifest = std::get<0>(GetParam());
|
||||
imm_db_options_.write_dbid_to_manifest = std::get<0>(GetParam());
|
||||
PrepareManifest(nullptr, nullptr, &log_writer_);
|
||||
// Write all column families but no log_number, next_file_number and
|
||||
// last_sequence.
|
||||
@@ -3651,7 +3653,7 @@ TEST_P(VersionSetTestEmptyDb, OpenFromInCompleteManifest2) {
|
||||
}
|
||||
|
||||
TEST_P(VersionSetTestEmptyDb, OpenManifestWithUnknownCF) {
|
||||
db_options_.write_dbid_to_manifest = std::get<0>(GetParam());
|
||||
imm_db_options_.write_dbid_to_manifest = std::get<0>(GetParam());
|
||||
PrepareManifest(nullptr, nullptr, &log_writer_);
|
||||
// Write all column families but no log_number, next_file_number and
|
||||
// last_sequence.
|
||||
@@ -3708,7 +3710,7 @@ TEST_P(VersionSetTestEmptyDb, OpenManifestWithUnknownCF) {
|
||||
}
|
||||
|
||||
TEST_P(VersionSetTestEmptyDb, OpenCompleteManifest) {
|
||||
db_options_.write_dbid_to_manifest = std::get<0>(GetParam());
|
||||
imm_db_options_.write_dbid_to_manifest = std::get<0>(GetParam());
|
||||
PrepareManifest(nullptr, nullptr, &log_writer_);
|
||||
// Write all column families but no log_number, next_file_number and
|
||||
// last_sequence.
|
||||
@@ -3828,7 +3830,7 @@ class VersionSetTestMissingFiles : public VersionSetTestBase,
|
||||
ASSERT_OK(s);
|
||||
log_writer->reset(new log::Writer(std::move(file_writer), 0, false));
|
||||
VersionEdit new_db;
|
||||
if (db_options_.write_dbid_to_manifest) {
|
||||
if (imm_db_options_.write_dbid_to_manifest) {
|
||||
DBOptions tmp_db_options;
|
||||
tmp_db_options.env = env_;
|
||||
std::unique_ptr<DBImpl> impl(new DBImpl(tmp_db_options, dbname_));
|
||||
@@ -4088,7 +4090,7 @@ TEST_F(VersionSetTestMissingFiles, NoFileMissing) {
|
||||
}
|
||||
|
||||
TEST_F(VersionSetTestMissingFiles, MinLogNumberToKeep2PC) {
|
||||
db_options_.allow_2pc = true;
|
||||
imm_db_options_.allow_2pc = true;
|
||||
NewDB();
|
||||
|
||||
SstInfo sst(100, kDefaultColumnFamilyName, "a", 0 /* level */,
|
||||
|
||||
+3
-2
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
@@ -23,7 +23,8 @@ class OfflineManifestWriter {
|
||||
immutable_db_options_(WithDbPath(options, db_path)),
|
||||
tc_(NewLRUCache(1 << 20 /* capacity */,
|
||||
options.table_cache_numshardbits)),
|
||||
versions_(db_path, &immutable_db_options_, sopt_, tc_.get(), &wb_, &wc_,
|
||||
versions_(db_path, &immutable_db_options_, MutableDBOptions{options},
|
||||
sopt_, tc_.get(), &wb_, &wc_,
|
||||
/*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
|
||||
/*db_id=*/"", /*db_session_id=*/"",
|
||||
options.daily_offpeak_time_utc,
|
||||
|
||||
@@ -50,8 +50,8 @@ class WalManagerTest : public testing::Test {
|
||||
db_options_.clock = env_->GetSystemClock().get();
|
||||
|
||||
versions_.reset(new VersionSet(
|
||||
dbname_, &db_options_, env_options_, table_cache_.get(),
|
||||
&write_buffer_manager_, &write_controller_,
|
||||
dbname_, &db_options_, MutableDBOptions{}, env_options_,
|
||||
table_cache_.get(), &write_buffer_manager_, &write_controller_,
|
||||
/*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
|
||||
/*db_id=*/"", /*db_session_id=*/"", /*daily_offpeak_time_utc=*/"",
|
||||
/*error_handler=*/nullptr, /*read_only=*/false));
|
||||
|
||||
@@ -248,6 +248,7 @@ DECLARE_string(fs_uri);
|
||||
DECLARE_uint64(ops_per_thread);
|
||||
DECLARE_uint64(log2_keys_per_lock);
|
||||
DECLARE_uint64(max_manifest_file_size);
|
||||
DECLARE_int32(max_manifest_space_amp_pct);
|
||||
DECLARE_bool(in_place_update);
|
||||
DECLARE_string(memtablerep);
|
||||
DECLARE_int32(prefix_size);
|
||||
|
||||
@@ -978,7 +978,11 @@ DEFINE_uint64(log2_keys_per_lock, 2, "Log2 of number of keys per lock");
|
||||
static const bool FLAGS_log2_keys_per_lock_dummy __attribute__((__unused__)) =
|
||||
RegisterFlagValidator(&FLAGS_log2_keys_per_lock, &ValidateUint32Range);
|
||||
|
||||
DEFINE_uint64(max_manifest_file_size, 16384, "Maximum size of a MANIFEST file");
|
||||
DEFINE_uint64(max_manifest_file_size, 16384,
|
||||
"Maximum size of a MANIFEST file (without auto-tuning)");
|
||||
|
||||
DEFINE_int32(max_manifest_space_amp_pct, 500,
|
||||
"Max manifest space amp percentage for auto-tuning");
|
||||
|
||||
DEFINE_bool(in_place_update, false, "On true, does inplace update in memtable");
|
||||
|
||||
|
||||
@@ -4420,6 +4420,7 @@ void InitializeOptionsFromFlags(
|
||||
options.compression_opts.checksum = true;
|
||||
}
|
||||
options.max_manifest_file_size = FLAGS_max_manifest_file_size;
|
||||
options.max_manifest_space_amp_pct = FLAGS_max_manifest_space_amp_pct;
|
||||
options.max_subcompactions = static_cast<uint32_t>(FLAGS_subcompactions);
|
||||
options.allow_concurrent_memtable_write =
|
||||
FLAGS_allow_concurrent_memtable_write;
|
||||
|
||||
Vendored
+1
@@ -1406,6 +1406,7 @@ IOStatus PosixWritableFile::Truncate(uint64_t size, const IOOptions& /*opts*/,
|
||||
filename_, errno);
|
||||
} else {
|
||||
filesize_ = size;
|
||||
lseek(fd_, filesize_, SEEK_SET);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
Vendored
+43
@@ -4,6 +4,7 @@
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
#include "test_util/testharness.h"
|
||||
#include "util/random.h"
|
||||
|
||||
#ifdef ROCKSDB_LIB_IO_POSIX
|
||||
#include "env/io_posix.h"
|
||||
@@ -131,6 +132,48 @@ TEST_F(LogicalBlockSizeCacheTest, Ref) {
|
||||
}
|
||||
#endif
|
||||
|
||||
class PosixWritableFileTest : public testing::Test {};
|
||||
|
||||
TEST_F(PosixWritableFileTest, SeekAfterTruncate) {
|
||||
std::shared_ptr<FileSystem> fs = FileSystem::Default();
|
||||
std::string path =
|
||||
test::PerThreadDBPath("PosixWritableFileTest_SeekAfterTruncate");
|
||||
Random rnd(300);
|
||||
std::unique_ptr<FSWritableFile> wfile;
|
||||
|
||||
ASSERT_OK(fs->NewWritableFile(path, FileOptions(), &wfile, nullptr));
|
||||
ASSERT_OK(wfile->Append(rnd.RandomString(16384), IOOptions(), nullptr));
|
||||
ASSERT_OK(wfile->Truncate(4096, IOOptions(), nullptr));
|
||||
ASSERT_OK(wfile->Append(rnd.RandomString(4096), IOOptions(), nullptr));
|
||||
ASSERT_OK(wfile->Close(IOOptions(), nullptr));
|
||||
wfile.reset();
|
||||
|
||||
uint64_t size = 0;
|
||||
ASSERT_OK(fs->GetFileSize(path, IOOptions(), &size, nullptr));
|
||||
ASSERT_EQ(size, 8192);
|
||||
ASSERT_OK(fs->DeleteFile(path, IOOptions(), nullptr));
|
||||
}
|
||||
|
||||
TEST_F(PosixWritableFileTest, SeekAfterExtend) {
|
||||
std::shared_ptr<FileSystem> fs = FileSystem::Default();
|
||||
std::string path =
|
||||
test::PerThreadDBPath("PosixWritableFileTest_SeekAfterTruncate");
|
||||
Random rnd(300);
|
||||
std::unique_ptr<FSWritableFile> wfile;
|
||||
|
||||
ASSERT_OK(fs->NewWritableFile(path, FileOptions(), &wfile, nullptr));
|
||||
ASSERT_OK(wfile->Append(rnd.RandomString(4096), IOOptions(), nullptr));
|
||||
ASSERT_OK(wfile->Truncate(8192, IOOptions(), nullptr));
|
||||
ASSERT_OK(wfile->Append(rnd.RandomString(8192), IOOptions(), nullptr));
|
||||
ASSERT_OK(wfile->Close(IOOptions(), nullptr));
|
||||
wfile.reset();
|
||||
|
||||
uint64_t size = 0;
|
||||
ASSERT_OK(fs->GetFileSize(path, IOOptions(), &size, nullptr));
|
||||
ASSERT_EQ(size, 16384);
|
||||
ASSERT_OK(fs->DeleteFile(path, IOOptions(), nullptr));
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
#endif
|
||||
|
||||
|
||||
@@ -156,6 +156,61 @@ enum class PrepopulateBlobCache : uint8_t {
|
||||
kFlushOnly = 0x1, // Prepopulate blobs during flush only
|
||||
};
|
||||
|
||||
// Bitmask enum for verify output flags during compaction.
|
||||
// This allows fine-grained control over what verification is performed
|
||||
// on compaction output files and when it's enabled.
|
||||
enum class VerifyOutputFlags : uint32_t {
|
||||
kVerifyNone = 0x0, // No verification
|
||||
|
||||
// First set of bits: type of verifications
|
||||
kVerifyBlockChecksum = 1 << 0, // Verify block checksums
|
||||
kVerifyIteration = 1 << 1, // Verify iteration and full key/value hash
|
||||
// by comparing the one inserted into a
|
||||
// file, and what is read back.
|
||||
|
||||
// TODO - Implement
|
||||
// kVerifyFileChecksum = 1 << 2, // Verify file-level checksum
|
||||
|
||||
// Second set of bits: when to enable verification
|
||||
kEnableForLocalCompaction = 1 << 10, // Enable for local compaction
|
||||
kEnableForRemoteCompaction = 1 << 11, // Enable for remote compaction
|
||||
|
||||
// TODO - Implement
|
||||
// kEnableForFlush = 1 << 12, // Enable for flush
|
||||
|
||||
kVerifyAll = 0xFFFFFFFF,
|
||||
};
|
||||
|
||||
inline VerifyOutputFlags operator|(VerifyOutputFlags lhs,
|
||||
VerifyOutputFlags rhs) {
|
||||
using T = std::underlying_type_t<VerifyOutputFlags>;
|
||||
return static_cast<VerifyOutputFlags>(static_cast<T>(lhs) |
|
||||
static_cast<T>(rhs));
|
||||
}
|
||||
|
||||
inline VerifyOutputFlags& operator|=(VerifyOutputFlags& lhs,
|
||||
VerifyOutputFlags rhs) {
|
||||
lhs = lhs | rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
inline VerifyOutputFlags operator&(VerifyOutputFlags lhs,
|
||||
VerifyOutputFlags rhs) {
|
||||
using T = std::underlying_type_t<VerifyOutputFlags>;
|
||||
return static_cast<VerifyOutputFlags>(static_cast<T>(lhs) &
|
||||
static_cast<T>(rhs));
|
||||
}
|
||||
|
||||
inline VerifyOutputFlags& operator&=(VerifyOutputFlags& lhs,
|
||||
VerifyOutputFlags rhs) {
|
||||
lhs = lhs & rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
inline bool operator!(VerifyOutputFlags flag) {
|
||||
return flag == VerifyOutputFlags::kVerifyNone;
|
||||
}
|
||||
|
||||
struct AdvancedColumnFamilyOptions {
|
||||
// The maximum number of write buffers that are built up in memory.
|
||||
// The default and the minimum number is 2, so that when 1 write buffer
|
||||
@@ -704,6 +759,13 @@ struct AdvancedColumnFamilyOptions {
|
||||
// Dynamically changeable through SetOptions() API
|
||||
bool paranoid_file_checks = false;
|
||||
|
||||
// Bitmask enum for output verification option.
|
||||
//
|
||||
// Default: 0 (kVerifyNone)
|
||||
//
|
||||
// Dynamically changeable (as a uint32_t) through SetOptions() API.
|
||||
VerifyOutputFlags verify_output_flags = VerifyOutputFlags::kVerifyNone;
|
||||
|
||||
// In debug mode, RocksDB runs consistency checks on the LSM every time the
|
||||
// LSM changes (Flush, Compaction, AddFile). When this option is true, these
|
||||
// checks are also enabled in release mode. These checks were historically
|
||||
|
||||
@@ -1935,11 +1935,24 @@ class DB {
|
||||
virtual void GetColumnFamilyMetaData(ColumnFamilyHandle* /*column_family*/,
|
||||
ColumnFamilyMetaData* /*metadata*/) {}
|
||||
|
||||
// Obtains the LSM-tree meta data of the specified column family of the DB
|
||||
// with optional filtering by key range and level.
|
||||
virtual void GetColumnFamilyMetaData(
|
||||
ColumnFamilyHandle* /*column_family*/,
|
||||
const GetColumnFamilyMetaDataOptions& /*options*/,
|
||||
ColumnFamilyMetaData* /*metadata*/) {}
|
||||
|
||||
// Get the metadata of the default column family.
|
||||
void GetColumnFamilyMetaData(ColumnFamilyMetaData* metadata) {
|
||||
GetColumnFamilyMetaData(DefaultColumnFamily(), metadata);
|
||||
}
|
||||
|
||||
// Get the metadata of the default column family with optional filtering.
|
||||
void GetColumnFamilyMetaData(const GetColumnFamilyMetaDataOptions& options,
|
||||
ColumnFamilyMetaData* metadata) {
|
||||
GetColumnFamilyMetaData(DefaultColumnFamily(), options, metadata);
|
||||
}
|
||||
|
||||
// Obtains the LSM-tree meta data of all column families of the DB, including
|
||||
// metadata for each live table (SST) file and each blob file in the DB.
|
||||
virtual void GetAllColumnFamilyMetaData(
|
||||
|
||||
@@ -1166,8 +1166,10 @@ class FSWritableFile {
|
||||
|
||||
// Truncate is necessary to trim the file to the correct size
|
||||
// before closing. It is not always possible to keep track of the file
|
||||
// size due to whole pages writes. The behavior is undefined if called
|
||||
// with other writes to follow.
|
||||
// size due to whole pages writes. If called with other writes to follow,
|
||||
// the behavior is file system specific. Posix will reseek to the new EOF.
|
||||
// Other file systems may behave differently. Its the caller's
|
||||
// responsibility to check the file system contract.
|
||||
virtual IOStatus Truncate(uint64_t /*size*/, const IOOptions& /*options*/,
|
||||
IODebugContext* /*dbg*/) {
|
||||
return IOStatus::OK();
|
||||
|
||||
@@ -224,6 +224,20 @@ struct LevelMetaData {
|
||||
const std::vector<SstFileMetaData> files;
|
||||
};
|
||||
|
||||
// Options for filtering column family metadata by key range.
|
||||
struct GetColumnFamilyMetaDataOptions {
|
||||
RangeOpt range;
|
||||
|
||||
// The level to filter on. If -1, all levels are included.
|
||||
int level = -1;
|
||||
|
||||
GetColumnFamilyMetaDataOptions() = default;
|
||||
|
||||
GetColumnFamilyMetaDataOptions(const OptSlice& _start_key,
|
||||
const OptSlice& _end_key, int _level = -1)
|
||||
: range(_start_key, _end_key), level(_level) {}
|
||||
};
|
||||
|
||||
// The metadata that describes a column family.
|
||||
struct ColumnFamilyMetaData {
|
||||
ColumnFamilyMetaData() : size(0), file_count(0), name("") {}
|
||||
|
||||
@@ -958,12 +958,67 @@ struct DBOptions {
|
||||
// Default: 0
|
||||
size_t recycle_log_file_num = 0;
|
||||
|
||||
// manifest file is rolled over on reaching this limit.
|
||||
// The older manifest file be deleted.
|
||||
// The default value is 1GB so that the manifest file can grow, but not
|
||||
// reach the limit of storage capacity.
|
||||
// The manifest file is rolled over on reaching this limit AND the
|
||||
// space amp limit described in max_manifest_space_amp_pct. More trade-off
|
||||
// details there.
|
||||
//
|
||||
// NOTE: this option used to be a hard limit, but that made this a dangerous
|
||||
// tuning parameter for optimizing manifest file size because the best
|
||||
// size really depends on the DB size and average SST file size (and other
|
||||
// settings). Now it is essentially a minimum for the auto-tuned max manifest
|
||||
// file size.
|
||||
//
|
||||
// Until the max_manifest_space_amp_pct feature is fully validated to show a
|
||||
// smaller default here like 1MB is appropriate, the default value is 1GB to
|
||||
// match historical behavior (without it being a hard limit in case of giant
|
||||
// compacted manifest size).
|
||||
//
|
||||
// This option is mutable with SetDBOptions(), taking effect on the next
|
||||
// manifest write (e.g. completed DB compaction or flush).
|
||||
uint64_t max_manifest_file_size = 1024 * 1024 * 1024;
|
||||
|
||||
// This option mostly replaces max_manifest_file_size to control an auto-tuned
|
||||
// balance of manifest write amplification and space amplification. A new
|
||||
// manifest file is created with the "compacted" contents of the old one when
|
||||
// current_manifest_size
|
||||
// >
|
||||
// max(max_manifest_file_size,
|
||||
// est_compacted_manifest_size * (1 + max_manifest_space_amp_pct/100))
|
||||
//
|
||||
// where est_compacted_manifest_size is an estimate of how big a new compacted
|
||||
// version of the current manifest would be. Currently, the estimate used is
|
||||
// the last newly-written manifest, in its "compacted" form.
|
||||
//
|
||||
// Space amplification in the manifest file might be less of a concern for
|
||||
// primary storage space and more of a concern for DB recover time and size of
|
||||
// backup files that aren't incremental between backups. To minimize manifest
|
||||
// churn on initial DB population, setting max_manifest_file_size to something
|
||||
// not too small, like 1MB, should suffice. Similarly, write amp on the
|
||||
// manifest file is likely not a direct concern but completed compactions and
|
||||
// flushes cannot (currently) be committed while the (relatively small)
|
||||
// manifest file is being compacted. Manifest compactions should not
|
||||
// interfere with user write latency or throughput unless the DB is
|
||||
// chronically stalling or close to stalling writes already.
|
||||
//
|
||||
// For this option to have a meaningful effect, it is recommended to set
|
||||
// max_manifest_file_size to something modest like 1MB. Then we can interpret
|
||||
// values for this option as follows, starting with minimum space amp and
|
||||
// maximum write amp:
|
||||
// * 0 - Every manifest write (flush, compaction, etc.) generates a whole new
|
||||
// manifest. Only useful for testing.
|
||||
// * very small - Doesn't take many manifest writes to generate a whole new
|
||||
// manifest.
|
||||
// * 100 - In a DB with pretty consistent number of SST files, etc., achieves
|
||||
// about 1.0 write amp (writing about 2x the theoretical minimum) and a max of
|
||||
// about 1.0 space amp (manifest up to 2x the compacted size).
|
||||
// * 500 - Recommended and default: 0.2 write amp and up to roughly 5.0 space
|
||||
// amp.
|
||||
// * 10000 - 0.01 write amp and up to 100 space amp on the manifest.
|
||||
//
|
||||
// This option is mutable with SetDBOptions(), taking effect on the next
|
||||
// manifest write (e.g. completed DB compaction or flush).
|
||||
int max_manifest_space_amp_pct = 500;
|
||||
|
||||
// Number of shards used for table cache.
|
||||
int table_cache_numshardbits = 6;
|
||||
|
||||
@@ -2383,11 +2438,17 @@ struct CompactionOptions {
|
||||
// "default_write_temperature"
|
||||
Temperature output_temperature_override = Temperature::kUnknown;
|
||||
|
||||
// Option to optimize the manual compaction by enabling trivial move for non
|
||||
// overlapping files.
|
||||
// Default: false
|
||||
bool allow_trivial_move;
|
||||
|
||||
CompactionOptions()
|
||||
: compression(kDisableCompressionOption),
|
||||
output_file_size_limit(std::numeric_limits<uint64_t>::max()),
|
||||
max_subcompactions(0),
|
||||
canceled(nullptr) {}
|
||||
canceled(nullptr),
|
||||
allow_trivial_move(false) {}
|
||||
};
|
||||
|
||||
// For level based compaction, we can configure if we want to skip/force
|
||||
|
||||
@@ -456,6 +456,12 @@ class StackableDB : public DB {
|
||||
db_->GetColumnFamilyMetaData(column_family, cf_meta);
|
||||
}
|
||||
|
||||
void GetColumnFamilyMetaData(ColumnFamilyHandle* column_family,
|
||||
const GetColumnFamilyMetaDataOptions& options,
|
||||
ColumnFamilyMetaData* metadata) override {
|
||||
db_->GetColumnFamilyMetaData(column_family, options, metadata);
|
||||
}
|
||||
|
||||
using DB::StartBlockCacheTrace;
|
||||
Status StartBlockCacheTrace(
|
||||
const TraceOptions& trace_options,
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
// minor or major version number planned for release.
|
||||
#define ROCKSDB_MAJOR 10
|
||||
#define ROCKSDB_MINOR 8
|
||||
#define ROCKSDB_PATCH 0
|
||||
#define ROCKSDB_PATCH 3
|
||||
|
||||
// Make it easy to do conditional compilation based on version checks, i.e.
|
||||
// #if ROCKSDB_VERSION_GE(4, 5, 6)
|
||||
|
||||
@@ -395,6 +395,10 @@ static std::unordered_map<std::string, OptionTypeInfo>
|
||||
{offsetof(struct MutableCFOptions, paranoid_file_checks),
|
||||
OptionType::kBoolean, OptionVerificationType::kNormal,
|
||||
OptionTypeFlags::kMutable}},
|
||||
{"verify_output_flags",
|
||||
{offsetof(struct MutableCFOptions, verify_output_flags),
|
||||
OptionType::kUInt32T, OptionVerificationType::kNormal,
|
||||
OptionTypeFlags::kMutable}},
|
||||
{"verify_checksums_in_compaction",
|
||||
{0, OptionType::kBoolean, OptionVerificationType::kDeprecated,
|
||||
OptionTypeFlags::kMutable}},
|
||||
|
||||
@@ -143,6 +143,7 @@ struct MutableCFOptions {
|
||||
preclude_last_level_data_seconds(
|
||||
options.preclude_last_level_data_seconds),
|
||||
preserve_internal_time_seconds(options.preserve_internal_time_seconds),
|
||||
verify_output_flags(options.verify_output_flags),
|
||||
enable_blob_files(options.enable_blob_files),
|
||||
min_blob_size(options.min_blob_size),
|
||||
blob_file_size(options.blob_file_size),
|
||||
@@ -213,6 +214,7 @@ struct MutableCFOptions {
|
||||
compaction_options_fifo(),
|
||||
preclude_last_level_data_seconds(0),
|
||||
preserve_internal_time_seconds(0),
|
||||
verify_output_flags(VerifyOutputFlags::kVerifyNone),
|
||||
enable_blob_files(false),
|
||||
min_blob_size(0),
|
||||
blob_file_size(0),
|
||||
@@ -313,6 +315,7 @@ struct MutableCFOptions {
|
||||
CompactionOptionsUniversal compaction_options_universal;
|
||||
uint64_t preclude_last_level_data_seconds;
|
||||
uint64_t preserve_internal_time_seconds;
|
||||
VerifyOutputFlags verify_output_flags;
|
||||
|
||||
// Blob file related options
|
||||
bool enable_blob_files;
|
||||
|
||||
+27
-36
@@ -124,6 +124,18 @@ static std::unordered_map<std::string, OptionTypeInfo>
|
||||
{offsetof(struct MutableDBOptions, max_background_flushes),
|
||||
OptionType::kInt, OptionVerificationType::kNormal,
|
||||
OptionTypeFlags::kMutable}},
|
||||
{"max_manifest_file_size",
|
||||
{offsetof(struct MutableDBOptions, max_manifest_file_size),
|
||||
OptionType::kUInt64T, OptionVerificationType::kNormal,
|
||||
OptionTypeFlags::kMutable}},
|
||||
{"max_manifest_space_amp_pct",
|
||||
{offsetof(struct MutableDBOptions, max_manifest_space_amp_pct),
|
||||
OptionType::kInt, OptionVerificationType::kNormal,
|
||||
OptionTypeFlags::kMutable}},
|
||||
{"manifest_preallocation_size",
|
||||
{offsetof(struct MutableDBOptions, manifest_preallocation_size),
|
||||
OptionType::kSizeT, OptionVerificationType::kNormal,
|
||||
OptionTypeFlags::kMutable}},
|
||||
{"daily_offpeak_time_utc",
|
||||
{offsetof(struct MutableDBOptions, daily_offpeak_time_utc),
|
||||
OptionType::kString, OptionVerificationType::kNormal,
|
||||
@@ -288,10 +300,6 @@ static std::unordered_map<std::string, OptionTypeInfo>
|
||||
{offsetof(struct ImmutableDBOptions, log_file_time_to_roll),
|
||||
OptionType::kSizeT, OptionVerificationType::kNormal,
|
||||
OptionTypeFlags::kNone}},
|
||||
{"manifest_preallocation_size",
|
||||
{offsetof(struct ImmutableDBOptions, manifest_preallocation_size),
|
||||
OptionType::kSizeT, OptionVerificationType::kNormal,
|
||||
OptionTypeFlags::kNone}},
|
||||
{"max_log_file_size",
|
||||
{offsetof(struct ImmutableDBOptions, max_log_file_size),
|
||||
OptionType::kSizeT, OptionVerificationType::kNormal,
|
||||
@@ -310,10 +318,6 @@ static std::unordered_map<std::string, OptionTypeInfo>
|
||||
{offsetof(struct ImmutableDBOptions, WAL_ttl_seconds),
|
||||
OptionType::kUInt64T, OptionVerificationType::kNormal,
|
||||
OptionTypeFlags::kNone}},
|
||||
{"max_manifest_file_size",
|
||||
{offsetof(struct ImmutableDBOptions, max_manifest_file_size),
|
||||
OptionType::kUInt64T, OptionVerificationType::kNormal,
|
||||
OptionTypeFlags::kNone}},
|
||||
{"persist_stats_to_disk",
|
||||
{offsetof(struct ImmutableDBOptions, persist_stats_to_disk),
|
||||
OptionType::kBoolean, OptionVerificationType::kNormal,
|
||||
@@ -657,7 +661,7 @@ class DBOptionsConfigurable : public MutableDBConfigurable {
|
||||
explicit DBOptionsConfigurable(
|
||||
const DBOptions& opts,
|
||||
const std::unordered_map<std::string, std::string>* map = nullptr)
|
||||
: MutableDBConfigurable(MutableDBOptions(opts), map), db_options_(opts) {
|
||||
: MutableDBConfigurable(MutableDBOptions{opts}, map), db_options_(opts) {
|
||||
// The ImmutableDBOptions currently requires the env to be non-null. Make
|
||||
// sure it is
|
||||
if (opts.env != nullptr) {
|
||||
@@ -708,7 +712,7 @@ std::unique_ptr<Configurable> DBOptionsAsConfigurable(
|
||||
return ptr;
|
||||
}
|
||||
|
||||
ImmutableDBOptions::ImmutableDBOptions() : ImmutableDBOptions(Options()) {}
|
||||
ImmutableDBOptions::ImmutableDBOptions() : ImmutableDBOptions(DBOptions{}) {}
|
||||
|
||||
ImmutableDBOptions::ImmutableDBOptions(const DBOptions& options)
|
||||
: create_if_missing(options.create_if_missing),
|
||||
@@ -737,13 +741,11 @@ ImmutableDBOptions::ImmutableDBOptions(const DBOptions& options)
|
||||
log_file_time_to_roll(options.log_file_time_to_roll),
|
||||
keep_log_file_num(options.keep_log_file_num),
|
||||
recycle_log_file_num(options.recycle_log_file_num),
|
||||
max_manifest_file_size(options.max_manifest_file_size),
|
||||
table_cache_numshardbits(options.table_cache_numshardbits),
|
||||
WAL_ttl_seconds(options.WAL_ttl_seconds),
|
||||
WAL_size_limit_MB(options.WAL_size_limit_MB),
|
||||
max_write_batch_group_size_bytes(
|
||||
options.max_write_batch_group_size_bytes),
|
||||
manifest_preallocation_size(options.manifest_preallocation_size),
|
||||
allow_mmap_reads(options.allow_mmap_reads),
|
||||
allow_mmap_writes(options.allow_mmap_writes),
|
||||
use_direct_reads(options.use_direct_reads),
|
||||
@@ -850,9 +852,6 @@ void ImmutableDBOptions::Dump(Logger* log) const {
|
||||
ROCKS_LOG_HEADER(
|
||||
log, " Options.max_log_file_size: %" ROCKSDB_PRIszt,
|
||||
max_log_file_size);
|
||||
ROCKS_LOG_HEADER(log,
|
||||
" Options.max_manifest_file_size: %" PRIu64,
|
||||
max_manifest_file_size);
|
||||
ROCKS_LOG_HEADER(
|
||||
log, " Options.log_file_time_to_roll: %" ROCKSDB_PRIszt,
|
||||
log_file_time_to_roll);
|
||||
@@ -892,9 +891,6 @@ void ImmutableDBOptions::Dump(Logger* log) const {
|
||||
" "
|
||||
"Options.max_write_batch_group_size_bytes: %" PRIu64,
|
||||
max_write_batch_group_size_bytes);
|
||||
ROCKS_LOG_HEADER(
|
||||
log, " Options.manifest_preallocation_size: %" ROCKSDB_PRIszt,
|
||||
manifest_preallocation_size);
|
||||
ROCKS_LOG_HEADER(log, " Options.is_fd_close_on_exec: %d",
|
||||
is_fd_close_on_exec);
|
||||
ROCKS_LOG_HEADER(log, " Options.advise_random_on_open: %d",
|
||||
@@ -1025,24 +1021,7 @@ const std::string& ImmutableDBOptions::GetWalDir(
|
||||
}
|
||||
}
|
||||
|
||||
MutableDBOptions::MutableDBOptions()
|
||||
: max_background_jobs(2),
|
||||
max_background_compactions(-1),
|
||||
max_subcompactions(0),
|
||||
avoid_flush_during_shutdown(false),
|
||||
writable_file_max_buffer_size(1024 * 1024),
|
||||
delayed_write_rate(2 * 1024U * 1024U),
|
||||
max_total_wal_size(0),
|
||||
delete_obsolete_files_period_micros(6ULL * 60 * 60 * 1000000),
|
||||
stats_dump_period_sec(600),
|
||||
stats_persist_period_sec(600),
|
||||
stats_history_buffer_size(1024 * 1024),
|
||||
max_open_files(-1),
|
||||
bytes_per_sync(0),
|
||||
wal_bytes_per_sync(0),
|
||||
strict_bytes_per_sync(false),
|
||||
compaction_readahead_size(0),
|
||||
max_background_flushes(-1) {}
|
||||
MutableDBOptions::MutableDBOptions() : MutableDBOptions(DBOptions{}) {}
|
||||
|
||||
MutableDBOptions::MutableDBOptions(const DBOptions& options)
|
||||
: max_background_jobs(options.max_background_jobs),
|
||||
@@ -1063,6 +1042,9 @@ MutableDBOptions::MutableDBOptions(const DBOptions& options)
|
||||
strict_bytes_per_sync(options.strict_bytes_per_sync),
|
||||
compaction_readahead_size(options.compaction_readahead_size),
|
||||
max_background_flushes(options.max_background_flushes),
|
||||
max_manifest_file_size(options.max_manifest_file_size),
|
||||
max_manifest_space_amp_pct(options.max_manifest_space_amp_pct),
|
||||
manifest_preallocation_size(options.manifest_preallocation_size),
|
||||
daily_offpeak_time_utc(options.daily_offpeak_time_utc) {}
|
||||
|
||||
void MutableDBOptions::Dump(Logger* log) const {
|
||||
@@ -1107,6 +1089,15 @@ void MutableDBOptions::Dump(Logger* log) const {
|
||||
compaction_readahead_size);
|
||||
ROCKS_LOG_HEADER(log, " Options.max_background_flushes: %d",
|
||||
max_background_flushes);
|
||||
ROCKS_LOG_HEADER(log,
|
||||
" Options.max_manifest_file_size: %" PRIu64,
|
||||
max_manifest_file_size);
|
||||
ROCKS_LOG_HEADER(log,
|
||||
" Options.max_manifest_space_amp_pct: %d",
|
||||
max_manifest_space_amp_pct);
|
||||
ROCKS_LOG_HEADER(
|
||||
log, " Options.manifest_preallocation_size: %" ROCKSDB_PRIszt,
|
||||
manifest_preallocation_size);
|
||||
ROCKS_LOG_HEADER(log, "Options.daily_offpeak_time_utc: %s",
|
||||
daily_offpeak_time_utc.c_str());
|
||||
}
|
||||
|
||||
@@ -47,12 +47,10 @@ struct ImmutableDBOptions {
|
||||
size_t log_file_time_to_roll;
|
||||
size_t keep_log_file_num;
|
||||
size_t recycle_log_file_num;
|
||||
uint64_t max_manifest_file_size;
|
||||
int table_cache_numshardbits;
|
||||
uint64_t WAL_ttl_seconds;
|
||||
uint64_t WAL_size_limit_MB;
|
||||
uint64_t max_write_batch_group_size_bytes;
|
||||
size_t manifest_preallocation_size;
|
||||
bool allow_mmap_reads;
|
||||
bool allow_mmap_writes;
|
||||
bool use_direct_reads;
|
||||
@@ -146,6 +144,9 @@ struct MutableDBOptions {
|
||||
bool strict_bytes_per_sync;
|
||||
size_t compaction_readahead_size;
|
||||
int max_background_flushes;
|
||||
uint64_t max_manifest_file_size;
|
||||
int max_manifest_space_amp_pct;
|
||||
size_t manifest_preallocation_size;
|
||||
std::string daily_offpeak_time_utc;
|
||||
};
|
||||
|
||||
|
||||
@@ -99,13 +99,15 @@ void BuildDBOptions(const ImmutableDBOptions& immutable_db_options,
|
||||
options.log_file_time_to_roll = immutable_db_options.log_file_time_to_roll;
|
||||
options.keep_log_file_num = immutable_db_options.keep_log_file_num;
|
||||
options.recycle_log_file_num = immutable_db_options.recycle_log_file_num;
|
||||
options.max_manifest_file_size = immutable_db_options.max_manifest_file_size;
|
||||
options.max_manifest_file_size = mutable_db_options.max_manifest_file_size;
|
||||
options.max_manifest_space_amp_pct =
|
||||
mutable_db_options.max_manifest_space_amp_pct;
|
||||
options.table_cache_numshardbits =
|
||||
immutable_db_options.table_cache_numshardbits;
|
||||
options.WAL_ttl_seconds = immutable_db_options.WAL_ttl_seconds;
|
||||
options.WAL_size_limit_MB = immutable_db_options.WAL_size_limit_MB;
|
||||
options.manifest_preallocation_size =
|
||||
immutable_db_options.manifest_preallocation_size;
|
||||
mutable_db_options.manifest_preallocation_size;
|
||||
options.allow_mmap_reads = immutable_db_options.allow_mmap_reads;
|
||||
options.allow_mmap_writes = immutable_db_options.allow_mmap_writes;
|
||||
options.use_direct_reads = immutable_db_options.use_direct_reads;
|
||||
@@ -270,6 +272,8 @@ void UpdateColumnFamilyOptions(const MutableCFOptions& moptions,
|
||||
cf_opts->compaction_options_fifo = moptions.compaction_options_fifo;
|
||||
cf_opts->compaction_options_universal = moptions.compaction_options_universal;
|
||||
|
||||
cf_opts->verify_output_flags = moptions.verify_output_flags;
|
||||
|
||||
// Blob file related options
|
||||
cf_opts->enable_blob_files = moptions.enable_blob_files;
|
||||
cf_opts->min_blob_size = moptions.min_blob_size;
|
||||
|
||||
@@ -408,6 +408,7 @@ TEST_F(OptionsSettableTest, DBOptionsAllFieldsSettable) {
|
||||
"skip_stats_update_on_db_open=false;"
|
||||
"skip_checking_sst_file_sizes_on_db_open=false;"
|
||||
"max_manifest_file_size=4295009941;"
|
||||
"max_manifest_space_amp_pct=321;"
|
||||
"db_log_dir=path/to/db_log_dir;"
|
||||
"writable_file_max_buffer_size=1048576;"
|
||||
"paranoid_checks=true;"
|
||||
@@ -687,7 +688,8 @@ TEST_F(OptionsSettableTest, ColumnFamilyOptionsAllFieldsSettable) {
|
||||
"memtable_veirfy_per_key_checksum_on_seek=1;"
|
||||
"memtable_op_scan_flush_trigger=123;"
|
||||
"memtable_avg_op_scan_flush_trigger=12;"
|
||||
"cf_allow_ingest_behind=1;",
|
||||
"cf_allow_ingest_behind=1;"
|
||||
"verify_output_flags=2049;",
|
||||
new_options));
|
||||
|
||||
ASSERT_NE(new_options->blob_cache.get(), nullptr);
|
||||
|
||||
+19
-3
@@ -160,6 +160,7 @@ TEST_F(OptionsTest, GetOptionsFromMapTest) {
|
||||
{"keep_log_file_num", "39"},
|
||||
{"recycle_log_file_num", "5"},
|
||||
{"max_manifest_file_size", "40"},
|
||||
{"max_manifest_space_amp_pct", "42"},
|
||||
{"table_cache_numshardbits", "41"},
|
||||
{"WAL_ttl_seconds", "43"},
|
||||
{"WAL_size_limit_MB", "44"},
|
||||
@@ -341,7 +342,8 @@ TEST_F(OptionsTest, GetOptionsFromMapTest) {
|
||||
ASSERT_EQ(new_db_opt.log_file_time_to_roll, 38U);
|
||||
ASSERT_EQ(new_db_opt.keep_log_file_num, 39U);
|
||||
ASSERT_EQ(new_db_opt.recycle_log_file_num, 5U);
|
||||
ASSERT_EQ(new_db_opt.max_manifest_file_size, static_cast<uint64_t>(40));
|
||||
ASSERT_EQ(new_db_opt.max_manifest_file_size, uint64_t{40});
|
||||
ASSERT_EQ(new_db_opt.max_manifest_space_amp_pct, 42);
|
||||
ASSERT_EQ(new_db_opt.table_cache_numshardbits, 41);
|
||||
ASSERT_EQ(new_db_opt.WAL_ttl_seconds, static_cast<uint64_t>(43));
|
||||
ASSERT_EQ(new_db_opt.WAL_size_limit_MB, static_cast<uint64_t>(44));
|
||||
@@ -1720,13 +1722,24 @@ TEST_F(OptionsTest, MutableCFOptions) {
|
||||
|
||||
ASSERT_OK(GetColumnFamilyOptionsFromString(
|
||||
config_options, cf_opts,
|
||||
"paranoid_file_checks=true; block_based_table_factory.block_align=false; "
|
||||
"paranoid_file_checks=true; "
|
||||
"verify_output_flags=2049; "
|
||||
"block_based_table_factory.block_align=false; "
|
||||
"block_based_table_factory.super_block_alignment_size=65536; "
|
||||
"block_based_table_factory.super_block_alignment_space_overhead_ratio="
|
||||
"4096; "
|
||||
"block_based_table_factory.block_size=8192;",
|
||||
&cf_opts));
|
||||
ASSERT_TRUE(cf_opts.paranoid_file_checks);
|
||||
ASSERT_NE(
|
||||
(cf_opts.verify_output_flags & VerifyOutputFlags::kVerifyBlockChecksum),
|
||||
VerifyOutputFlags::kVerifyNone);
|
||||
ASSERT_NE((cf_opts.verify_output_flags &
|
||||
VerifyOutputFlags::kEnableForRemoteCompaction),
|
||||
VerifyOutputFlags::kVerifyNone);
|
||||
ASSERT_EQ((cf_opts.verify_output_flags &
|
||||
VerifyOutputFlags::kEnableForLocalCompaction),
|
||||
VerifyOutputFlags::kVerifyNone);
|
||||
ASSERT_NE(cf_opts.table_factory.get(), nullptr);
|
||||
auto* bbto = cf_opts.table_factory->GetOptions<BlockBasedTableOptions>();
|
||||
ASSERT_NE(bbto, nullptr);
|
||||
@@ -2468,6 +2481,7 @@ TEST_F(OptionsOldApiTest, GetOptionsFromMapTest) {
|
||||
{"keep_log_file_num", "39"},
|
||||
{"recycle_log_file_num", "5"},
|
||||
{"max_manifest_file_size", "40"},
|
||||
{"max_manifest_space_amp_pct", "42"},
|
||||
{"table_cache_numshardbits", "41"},
|
||||
{"WAL_ttl_seconds", "43"},
|
||||
{"WAL_size_limit_MB", "44"},
|
||||
@@ -2581,6 +2595,7 @@ TEST_F(OptionsOldApiTest, GetOptionsFromMapTest) {
|
||||
ASSERT_EQ(new_cf_opt.optimize_filters_for_hits, true);
|
||||
ASSERT_EQ(new_cf_opt.prefix_extractor->AsString(), "rocksdb.FixedPrefix.31");
|
||||
ASSERT_EQ(new_cf_opt.experimental_mempurge_threshold, 0.003);
|
||||
ASSERT_EQ(new_cf_opt.verify_output_flags, VerifyOutputFlags::kVerifyNone);
|
||||
ASSERT_EQ(new_cf_opt.enable_blob_files, true);
|
||||
ASSERT_EQ(new_cf_opt.min_blob_size, 1ULL << 10);
|
||||
ASSERT_EQ(new_cf_opt.blob_file_size, 1ULL << 30);
|
||||
@@ -2653,7 +2668,8 @@ TEST_F(OptionsOldApiTest, GetOptionsFromMapTest) {
|
||||
ASSERT_EQ(new_db_opt.log_file_time_to_roll, 38U);
|
||||
ASSERT_EQ(new_db_opt.keep_log_file_num, 39U);
|
||||
ASSERT_EQ(new_db_opt.recycle_log_file_num, 5U);
|
||||
ASSERT_EQ(new_db_opt.max_manifest_file_size, static_cast<uint64_t>(40));
|
||||
ASSERT_EQ(new_db_opt.max_manifest_file_size, uint64_t{40});
|
||||
ASSERT_EQ(new_db_opt.max_manifest_space_amp_pct, 42);
|
||||
ASSERT_EQ(new_db_opt.table_cache_numshardbits, 41);
|
||||
ASSERT_EQ(new_db_opt.WAL_ttl_seconds, static_cast<uint64_t>(43));
|
||||
ASSERT_EQ(new_db_opt.WAL_size_limit_MB, static_cast<uint64_t>(44));
|
||||
|
||||
@@ -494,6 +494,7 @@ TEST_MAIN_SOURCES = \
|
||||
db/db_clip_test.cc \
|
||||
db/db_dynamic_level_test.cc \
|
||||
db/db_encryption_test.cc \
|
||||
db/db_etc3_test.cc \
|
||||
db/db_flush_test.cc \
|
||||
db/db_follower_test.cc \
|
||||
db/db_readonly_with_timestamp_test.cc \
|
||||
|
||||
@@ -2705,7 +2705,7 @@ Status BlockBasedTable::Prefetch(const ReadOptions& read_options,
|
||||
}
|
||||
BlockCacheLookupContext lookup_context{TableReaderCaller::kPrefetch};
|
||||
IndexBlockIter iiter_on_stack;
|
||||
auto iiter = NewIndexIterator(read_options, /*need_upper_bound_check=*/false,
|
||||
auto iiter = NewIndexIterator(read_options, /*disable_prefix_seek=*/false,
|
||||
&iiter_on_stack, /*get_context=*/nullptr,
|
||||
&lookup_context);
|
||||
std::unique_ptr<InternalIteratorBase<IndexValue>> iiter_unique_ptr;
|
||||
@@ -2742,7 +2742,7 @@ Status BlockBasedTable::Prefetch(const ReadOptions& read_options,
|
||||
DataBlockIter biter;
|
||||
Status tmp_status;
|
||||
NewDataBlockIterator<DataBlockIter>(
|
||||
read_options, block_handle, &biter, /*type=*/BlockType::kData,
|
||||
read_options, block_handle, &biter, /*block_type=*/BlockType::kData,
|
||||
/*get_context=*/nullptr, &lookup_context,
|
||||
/*prefetch_buffer=*/nullptr, /*for_compaction=*/false,
|
||||
/*async_read=*/false, tmp_status, /*use_block_cache_for_lookup=*/true);
|
||||
@@ -2757,7 +2757,8 @@ Status BlockBasedTable::Prefetch(const ReadOptions& read_options,
|
||||
}
|
||||
|
||||
Status BlockBasedTable::VerifyChecksum(const ReadOptions& read_options,
|
||||
TableReaderCaller caller) {
|
||||
TableReaderCaller caller,
|
||||
bool meta_blocks_only) {
|
||||
Status s;
|
||||
// Check Meta blocks
|
||||
std::unique_ptr<Block> metaindex;
|
||||
@@ -2772,6 +2773,9 @@ Status BlockBasedTable::VerifyChecksum(const ReadOptions& read_options,
|
||||
} else {
|
||||
return s;
|
||||
}
|
||||
if (meta_blocks_only) {
|
||||
return s;
|
||||
}
|
||||
// Check Data blocks
|
||||
IndexBlockIter iiter_on_stack;
|
||||
BlockCacheLookupContext context{caller};
|
||||
@@ -2967,7 +2971,7 @@ bool BlockBasedTable::TEST_BlockInCache(const BlockHandle& handle) const {
|
||||
bool BlockBasedTable::TEST_KeyInCache(const ReadOptions& options,
|
||||
const Slice& key) {
|
||||
std::unique_ptr<InternalIteratorBase<IndexValue>> iiter(NewIndexIterator(
|
||||
options, /*need_upper_bound_check=*/false, /*input_iter=*/nullptr,
|
||||
options, /*disable_prefix_seek=*/false, /*input_iter=*/nullptr,
|
||||
/*get_context=*/nullptr, /*lookup_context=*/nullptr));
|
||||
iiter->Seek(key);
|
||||
assert(iiter->status().ok());
|
||||
@@ -3174,9 +3178,9 @@ bool BlockBasedTable::TEST_IndexBlockInCache() const {
|
||||
Status BlockBasedTable::GetKVPairsFromDataBlocks(
|
||||
const ReadOptions& read_options, std::vector<KVPairBlock>* kv_pair_blocks) {
|
||||
std::unique_ptr<InternalIteratorBase<IndexValue>> blockhandles_iter(
|
||||
NewIndexIterator(read_options, /*need_upper_bound_check=*/false,
|
||||
NewIndexIterator(read_options, /*disable_prefix_seek=*/false,
|
||||
/*input_iter=*/nullptr, /*get_context=*/nullptr,
|
||||
/*lookup_contex=*/nullptr));
|
||||
/*lookup_context=*/nullptr));
|
||||
|
||||
Status s = blockhandles_iter->status();
|
||||
if (!s.ok()) {
|
||||
@@ -3196,7 +3200,7 @@ Status BlockBasedTable::GetKVPairsFromDataBlocks(
|
||||
Status tmp_status;
|
||||
datablock_iter.reset(NewDataBlockIterator<DataBlockIter>(
|
||||
read_options, blockhandles_iter->value().handle,
|
||||
/*input_iter=*/nullptr, /*type=*/BlockType::kData,
|
||||
/*input_iter=*/nullptr, /*block_type=*/BlockType::kData,
|
||||
/*get_context=*/nullptr, /*lookup_context=*/nullptr,
|
||||
/*prefetch_buffer=*/nullptr, /*for_compaction=*/false,
|
||||
/*async_read=*/false, tmp_status, /*use_block_cache_for_lookup=*/true));
|
||||
@@ -3347,9 +3351,9 @@ Status BlockBasedTable::DumpIndexBlock(std::ostream& out_stream) {
|
||||
// TODO: plumb Env::IOActivity, Env::IOPriority
|
||||
const ReadOptions read_options;
|
||||
std::unique_ptr<InternalIteratorBase<IndexValue>> blockhandles_iter(
|
||||
NewIndexIterator(read_options, /*need_upper_bound_check=*/false,
|
||||
NewIndexIterator(read_options, /*disable_prefix_seek=*/false,
|
||||
/*input_iter=*/nullptr, /*get_context=*/nullptr,
|
||||
/*lookup_contex=*/nullptr));
|
||||
/*lookup_context=*/nullptr));
|
||||
Status s = blockhandles_iter->status();
|
||||
if (!s.ok()) {
|
||||
out_stream << "Can not read Index Block \n\n";
|
||||
@@ -3398,9 +3402,9 @@ Status BlockBasedTable::DumpDataBlocks(std::ostream& out_stream) {
|
||||
// TODO: plumb Env::IOActivity, Env::IOPriority
|
||||
const ReadOptions read_options;
|
||||
std::unique_ptr<InternalIteratorBase<IndexValue>> blockhandles_iter(
|
||||
NewIndexIterator(read_options, /*need_upper_bound_check=*/false,
|
||||
NewIndexIterator(read_options, /*disable_prefix_seek=*/false,
|
||||
/*input_iter=*/nullptr, /*get_context=*/nullptr,
|
||||
/*lookup_contex=*/nullptr));
|
||||
/*lookup_context=*/nullptr));
|
||||
Status s = blockhandles_iter->status();
|
||||
if (!s.ok()) {
|
||||
out_stream << "Can not read Index Block \n\n";
|
||||
@@ -3433,7 +3437,7 @@ Status BlockBasedTable::DumpDataBlocks(std::ostream& out_stream) {
|
||||
Status tmp_status;
|
||||
datablock_iter.reset(NewDataBlockIterator<DataBlockIter>(
|
||||
read_options, blockhandles_iter->value().handle,
|
||||
/*input_iter=*/nullptr, /*type=*/BlockType::kData,
|
||||
/*input_iter=*/nullptr, /*block_type=*/BlockType::kData,
|
||||
/*get_context=*/nullptr, /*lookup_context=*/nullptr,
|
||||
/*prefetch_buffer=*/nullptr, /*for_compaction=*/false,
|
||||
/*async_read=*/false, tmp_status, /*use_block_cache_for_lookup=*/true));
|
||||
|
||||
@@ -211,7 +211,8 @@ class BlockBasedTable : public TableReader {
|
||||
Status DumpTable(WritableFile* out_file) override;
|
||||
|
||||
Status VerifyChecksum(const ReadOptions& readOptions,
|
||||
TableReaderCaller caller) override;
|
||||
TableReaderCaller caller,
|
||||
bool meta_blocks_only = false) override;
|
||||
|
||||
void MarkObsolete(uint32_t uncache_aggressiveness) override;
|
||||
|
||||
@@ -429,7 +430,7 @@ class BlockBasedTable : public TableReader {
|
||||
// 3. We disallowed any io to be performed, that is, read_options ==
|
||||
// kBlockCacheTier
|
||||
InternalIteratorBase<IndexValue>* NewIndexIterator(
|
||||
const ReadOptions& read_options, bool need_upper_bound_check,
|
||||
const ReadOptions& read_options, bool disable_prefix_seek,
|
||||
IndexBlockIter* input_iter, GetContext* get_context,
|
||||
BlockCacheLookupContext* lookup_context) const;
|
||||
|
||||
|
||||
@@ -239,8 +239,8 @@ class ExternalTableReaderAdapter : public TableReader {
|
||||
"Get() not supported on external file iterator");
|
||||
}
|
||||
|
||||
virtual Status VerifyChecksum(const ReadOptions& /*ro*/,
|
||||
TableReaderCaller /*caller*/) override {
|
||||
Status VerifyChecksum(const ReadOptions& /*ro*/, TableReaderCaller /*caller*/,
|
||||
bool /*meta_blocks_only*/ = false) override {
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
|
||||
@@ -185,7 +185,8 @@ class TableReader {
|
||||
|
||||
// check whether there is corruption in this db file
|
||||
virtual Status VerifyChecksum(const ReadOptions& /*read_options*/,
|
||||
TableReaderCaller /*caller*/) {
|
||||
TableReaderCaller /*caller*/,
|
||||
bool /*meta_blocks_only*/ = false) {
|
||||
return Status::NotSupported("VerifyChecksum() not supported");
|
||||
}
|
||||
|
||||
|
||||
@@ -446,6 +446,14 @@ DEFINE_int64(db_write_buffer_size,
|
||||
ROCKSDB_NAMESPACE::Options().db_write_buffer_size,
|
||||
"Number of bytes to buffer in all memtables before compacting");
|
||||
|
||||
DEFINE_int64(max_manifest_file_size,
|
||||
ROCKSDB_NAMESPACE::Options().max_manifest_file_size,
|
||||
"Max manifest file size (or minimum max with auto-tuning)");
|
||||
|
||||
DEFINE_int32(max_manifest_space_amp_pct,
|
||||
ROCKSDB_NAMESPACE::Options().max_manifest_space_amp_pct,
|
||||
"Max manifest space amp percentage for auto-tuning");
|
||||
|
||||
DEFINE_bool(cost_write_buffer_to_cache, false,
|
||||
"The usage of memtable is costed to the block cache");
|
||||
|
||||
@@ -4368,6 +4376,8 @@ class Benchmark {
|
||||
options.write_buffer_manager.reset(
|
||||
new WriteBufferManager(FLAGS_db_write_buffer_size, cache_));
|
||||
}
|
||||
options.max_manifest_file_size = FLAGS_max_manifest_file_size;
|
||||
options.max_manifest_space_amp_pct = FLAGS_max_manifest_space_amp_pct;
|
||||
options.arena_block_size = FLAGS_arena_block_size;
|
||||
options.write_buffer_size = FLAGS_write_buffer_size;
|
||||
options.max_write_buffer_number = FLAGS_max_write_buffer_number;
|
||||
|
||||
@@ -245,8 +245,9 @@ default_params = {
|
||||
# Test small max_manifest_file_size in a smaller chance, as most of the
|
||||
# time we wnat manifest history to be preserved to help debug
|
||||
"max_manifest_file_size": lambda: random.choice(
|
||||
[t * 16384 if t < 3 else 1024 * 1024 * 1024 for t in range(1, 30)]
|
||||
[t * 2048 if t < 5 else 1024 * 1024 * 1024 for t in range(1, 30)]
|
||||
),
|
||||
"max_manifest_space_amp_pct": lambda: random.choice([0, 10, 100, 1000]),
|
||||
# Sync mode might make test runs slower so running it in a smaller chance
|
||||
"sync": lambda: random.choice([1 if t == 0 else 0 for t in range(0, 20)]),
|
||||
"bytes_per_sync": lambda: random.choice([0, 262144]),
|
||||
|
||||
+8
-5
@@ -1610,11 +1610,12 @@ void DumpManifestFile(Options options, std::string file, bool verbose, bool hex,
|
||||
WriteController wc(options.delayed_write_rate);
|
||||
WriteBufferManager wb(options.db_write_buffer_size);
|
||||
ImmutableDBOptions immutable_db_options(options);
|
||||
VersionSet versions(dbname, &immutable_db_options, sopt, tc.get(), &wb, &wc,
|
||||
VersionSet versions(dbname, &immutable_db_options, MutableDBOptions{}, sopt,
|
||||
tc.get(), &wb, &wc,
|
||||
/*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
|
||||
/*db_id=*/"", /*db_session_id=*/"",
|
||||
options.daily_offpeak_time_utc,
|
||||
/*error_handler=*/nullptr, /*read_only=*/true);
|
||||
/*error_handler=*/nullptr, /*unchanging=*/true);
|
||||
Status s = versions.DumpManifest(options, file, verbose, hex, json, cf_descs);
|
||||
if (!s.ok()) {
|
||||
fprintf(stderr, "Error in processing file %s %s\n", file.c_str(),
|
||||
@@ -1805,11 +1806,12 @@ Status GetLiveFilesChecksumInfoFromVersionSet(Options options,
|
||||
WriteController wc(options.delayed_write_rate);
|
||||
WriteBufferManager wb(options.db_write_buffer_size);
|
||||
ImmutableDBOptions immutable_db_options(options);
|
||||
VersionSet versions(dbname, &immutable_db_options, sopt, tc.get(), &wb, &wc,
|
||||
VersionSet versions(dbname, &immutable_db_options, MutableDBOptions{options},
|
||||
sopt, tc.get(), &wb, &wc,
|
||||
/*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
|
||||
/*db_id=*/"", /*db_session_id=*/"",
|
||||
options.daily_offpeak_time_utc,
|
||||
/*error_handler=*/nullptr, /*read_only=*/true);
|
||||
/*error_handler=*/nullptr, /*unchanging=*/true);
|
||||
std::vector<std::string> cf_name_list;
|
||||
s = versions.ListColumnFamilies(&cf_name_list, db_path,
|
||||
immutable_db_options.fs.get());
|
||||
@@ -2660,7 +2662,8 @@ Status ReduceDBLevelsCommand::GetOldNumOfLevels(Options& opt, int* levels) {
|
||||
const InternalKeyComparator cmp(opt.comparator);
|
||||
WriteController wc(opt.delayed_write_rate);
|
||||
WriteBufferManager wb(opt.db_write_buffer_size);
|
||||
VersionSet versions(db_path_, &db_options, soptions, tc.get(), &wb, &wc,
|
||||
VersionSet versions(db_path_, &db_options, MutableDBOptions{opt}, soptions,
|
||||
tc.get(), &wb, &wc,
|
||||
/*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
|
||||
/*db_id=*/"", /*db_session_id=*/"",
|
||||
opt.daily_offpeak_time_utc,
|
||||
|
||||
@@ -208,8 +208,9 @@ class FileChecksumTestHelper {
|
||||
WriteController wc(options_.delayed_write_rate);
|
||||
WriteBufferManager wb(options_.db_write_buffer_size);
|
||||
ImmutableDBOptions immutable_db_options(options_);
|
||||
VersionSet versions(dbname_, &immutable_db_options, sopt, tc.get(), &wb,
|
||||
&wc, nullptr, nullptr, "", "",
|
||||
VersionSet versions(dbname_, &immutable_db_options,
|
||||
MutableDBOptions{options_}, sopt, tc.get(), &wb, &wc,
|
||||
nullptr, nullptr, "", "",
|
||||
options_.daily_offpeak_time_utc, nullptr,
|
||||
/*read_only=*/false);
|
||||
std::vector<std::string> cf_name_list;
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
* `kChangeTemperature` FIFO compaction will now honor `compaction_target_temp` to all levels regardless of `cf_options::last_level_temperature`
|
||||
@@ -1 +0,0 @@
|
||||
Allow UDIs with a non BytewiseComparator
|
||||
@@ -1 +0,0 @@
|
||||
Fix incorrect MultiScan seek error status due to bugs in handling range limit falling between adjacent SST files key range.
|
||||
@@ -1 +0,0 @@
|
||||
Fix a bug in Page unpinning in MultiScan
|
||||
@@ -1 +0,0 @@
|
||||
Add kFSPrefetch to FSSupportedOps enum to allow file systems to indicate prefetch support capability, avoiding unnecessary prefetch system calls on file systems that don't support them.
|
||||
@@ -1 +0,0 @@
|
||||
Added experimental support `OpenAndCompactOptions::allow_resumption` for resumable compaction that persists progress during `OpenAndCompact()`, allowing interrupted compactions to resume from the last progress persitence. The default behavior is to not persist progress.
|
||||
@@ -1 +0,0 @@
|
||||
* Fixed a performance regression in LZ4 compression that started in version 10.6.0
|
||||
@@ -1 +0,0 @@
|
||||
* Allow specifying output temperature in CompactionOptions
|
||||
@@ -1 +0,0 @@
|
||||
Added `DB::FlushWAL(const FlushWALOptions&)` as an alternative to `DB::FlushWAL(bool sync)`, where `FlushWALOptions` includes a new `rate_limiter_priority` field (default `Env::IO_TOTAL`) that allows rate limiting and priority passing of manual WAL flush's IO operations.
|
||||
@@ -1 +0,0 @@
|
||||
The MultiScan API contract is updated. After a multi scan range got prepared with Prepare API call, the following seeks must seek the start of each prepared scan range in order. In addition, when limit is set, upper bound must be set to the same value of limit before each seek
|
||||
@@ -3541,6 +3541,7 @@ TEST_F(BackupEngineTest, EnvFailures) {
|
||||
TEST_F(BackupEngineTest, ChangeManifestDuringBackupCreation) {
|
||||
DestroyDBWithoutCheck(dbname_, options_);
|
||||
options_.max_manifest_file_size = 0; // always rollover manifest for file add
|
||||
options_.max_manifest_space_amp_pct = 0;
|
||||
OpenDBAndBackupEngine(true);
|
||||
FillDB(db_.get(), 0, 100, kAutoFlushOnly);
|
||||
|
||||
|
||||
@@ -596,6 +596,7 @@ TEST_F(CheckpointTest, CheckpointCFNoFlush) {
|
||||
TEST_F(CheckpointTest, CurrentFileModifiedWhileCheckpointing) {
|
||||
Options options = CurrentOptions();
|
||||
options.max_manifest_file_size = 0; // always rollover manifest for file add
|
||||
options.max_manifest_space_amp_pct = 0;
|
||||
Reopen(options);
|
||||
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency(
|
||||
|
||||
Reference in New Issue
Block a user