Compare commits

...

20 Commits

Author SHA1 Message Date
anand76 3e00130da2 Fix bug in WAL streaming uncompression (#11198)
Summary:
Fix a bug in the calculation of the input buffer address/offset in log_reader.cc. The bug is when consecutive fragments of a compressed record are located at the same offset in the log reader buffer, the second fragment input buffer is treated as a leftover from the previous input buffer. As a result, the offset in the `ZSTD_inBuffer` is not reset.

Pull Request resolved: https://github.com/facebook/rocksdb/pull/11198

Test Plan: Add a unit test in log_test.cc that fails without the fix and passes with it.

Reviewed By: ajkr, cbi42

Differential Revision: D43102692

Pulled By: anand1976

fbshipit-source-id: aa2648f4802c33991b76a3233c5a58d4cc9e77fd
2023-02-10 15:25:18 -08:00
anand76 6357d00172 Fix prefetch_test for CircleCI 2023-02-02 17:26:19 -08:00
Andrew Kryczka 1b759e3f19 update HISTORY.md and version.h for 7.9.3 2023-02-01 08:06:40 -08:00
Andrew Kryczka 5c70943b68 make format 2023-02-01 08:06:14 -08:00
sdong 6cf49ba1eb ~SleepingBackgroundTask() to wake up the sleeping task (#11036)
Summary:
Right now, in unit tests, when background tests are sleeping using SleepingBackgroundTask, and the test exits with test assertion failure, the process will hang and it might prevent us to see the test failure message in CI runs. Try to wake up the thread so that the test can exit correctly.

Pull Request resolved: https://github.com/facebook/rocksdb/pull/11036

Test Plan: Watch CI succeeds

Reviewed By: riversand963

Differential Revision: D42020489

fbshipit-source-id: 5b8441b18d5f67bbb3ade59a1225a8d3c860c2eb
2023-02-01 07:35:35 -08:00
Andrew Kryczka a63980ee5c add missing sync point 2023-02-01 07:35:35 -08:00
Andrew Kryczka fe8d347217 Allow canceling manual compaction while waiting for conflicting compaction (#11165)
Summary:
This PR adds logic to the `RunManualCompaction()` loop to check for cancellation before waiting on any conflicting compactions to finish. In case of cancellation, `RunManualCompaction()` no longer waits on conflicting compactions

Pull Request resolved: https://github.com/facebook/rocksdb/pull/11165

Test Plan: repro test case

Reviewed By: cbi42

Differential Revision: D42864058

Pulled By: ajkr

fbshipit-source-id: ea4dd1a8f294abe212905495a8fbe8f07fca3f5a
2023-01-31 20:20:30 -08:00
Hui Xiao 4c464fa6fa Fix data race on ColumnFamilyData::flush_reason by letting FlushRequest/Job owns flush_reason instead of CFD (#11111)
Summary:
**Context:**
Concurrent flushes on the same CF can set on `ColumnFamilyData::flush_reason` before each other flush finishes. An symptom is one CF has different flush_reason with others though all of them are in an atomic flush  `db_stress: db/db_impl/db_impl_compaction_flush.cc:423: rocksdb::Status rocksdb::DBImpl::AtomicFlushMemTablesToOutputFiles(const rocksdb::autovector<rocksdb::DBImpl::BGFlushArg>&, bool*, rocksdb::JobContext*, rocksdb::LogBuffer*, rocksdb::Env::Priority): Assertion cfd->GetFlushReason() == cfds[0]->GetFlushReason() failed. `

**Summary:**
Suggested by ltamasi, we now refactor and let FlushRequest/Job to own flush_reason as there is no good way to define `ColumnFamilyData::flush_reason` in face of concurrent flushes on the same CF (which wasn't the case a long time ago when `ColumnFamilyData::flush_reason ` first introduced`)

**Tets:**
- new unit test
- make check
- aggressive crash test rehearsal

Pull Request resolved: https://github.com/facebook/rocksdb/pull/11111

Reviewed By: ajkr

Differential Revision: D42644600

Pulled By: hx235

fbshipit-source-id: 8589c8184869d3415e5b780c887f877818a5ebaf
2023-01-31 19:46:15 -08:00
anand76 444b3f4845 Add a unit test for PR 11049 2022-12-22 09:30:39 -08:00
anand76 23bec22a81 Bump version to 7.9.2 2022-12-21 09:51:53 -08:00
anand76 208310ad99 Fix async prefetch heap use after free (#11049)
Summary:
This PR fixes a heap use after free bug in the async prefetch code that happens in the following scenario -
1. Scan thread starts 2 async reads for Seek, one for the seek block and one for prefetching
2. Before the first read in https://github.com/facebook/rocksdb/issues/1 completes, another thread reads and loads the block in cache
3. The first scan thread finds the block in cache, continues and the next block cache miss is for a block that spans the boundary of the 2 prefetch buffers, and the 1st read is complete but the 2nd one is not complete yet
4. The scan thread will reallocate (i.e free the old buffer and allocate a new one) the 2nd prefetch buffer, and the in-progress prefetch is orphaned
5. The orphaned prefetch finally completes, resulting in a use after free

Also add a few asserts to surface bugs earlier in the crash tests.

Pull Request resolved: https://github.com/facebook/rocksdb/pull/11049

Test Plan: Repro with db_stress and verify the fix

Reviewed By: akankshamahajan15

Differential Revision: D42181118

Pulled By: anand1976

fbshipit-source-id: 1ac55d2f64a89ce128c1c574262b8aa7d82eb8cc
2022-12-21 09:46:30 -08:00
anand76 afa92034d9 Update version.h to 7.9.1 2022-12-08 19:54:29 -08:00
anand76 a5e9481295 Update HISTORY.md for 7.9.1 2022-12-08 19:25:26 -08:00
anand76 742035d21f Fix table cache leak in MultiGet with async_io (#10997)
Summary:
When MultiGet with the async_io option encounters an IO error in TableCache::GetTableReader, it may result in leakage of table cache handles due to queued coroutines being abandoned. This PR fixes it by ensuring any queued coroutines are run before aborting the MultiGet.

Pull Request resolved: https://github.com/facebook/rocksdb/pull/10997

Test Plan:
1. New unit test in db_basic_test
2. asan_crash

Reviewed By: pdillinger

Differential Revision: D41587244

Pulled By: anand1976

fbshipit-source-id: 900920cd3fba47cb0fc744a62facc5ffe2eccb64
2022-12-08 17:51:33 -08:00
Peter Dillinger 62f3e58936 Revert "Improve / refactor anonymous mmap capabilities (#10810)"
This reverts commit 8367f0d2d7.
2022-11-30 17:14:01 -08:00
Peter Dillinger be728f83e8 Revert "Fix include of windows.h in mmap.h (#10885)"
This reverts commit 49b7f219de.
2022-11-30 17:12:09 -08:00
Hui Xiao 3ff86f39ae Revert PR 10777 "Fix FIFO causing overlapping seqnos in L0 files due to overla…" (#10999)
Summary:
**Context/Summary:**

This reverts commit fc74abb436 and related HISTORY record.

The issue with PR 10777 or general approach using earliest_mem_seqno like https://github.com/facebook/rocksdb/pull/5958#issue-511150930 is that the earliest seqno of memtable of each CFs does not get persisted and will always start with 0 upon Recover(). Later when creating a new memtable in certain CF, we use the last seqno of the whole DB (but not of that CF from previous DB session) for this CF.  This will lead to false positive overlapping seqno and PR 10777 will throw something like https://github.com/facebook/rocksdb/blob/main/db/compaction/compaction_picker.cc#L1002-L1004

Luckily a more elegant and complete solution to the overlapping seqno problem these PR aim to solve does not have above problem, see https://github.com/facebook/rocksdb/pull/10922. It is already being pursued and in the process of review. So we can just revert this PR and focus on getting PR10922 to land.

Pull Request resolved: https://github.com/facebook/rocksdb/pull/10999

Test Plan: make check

Reviewed By: anand1976

Differential Revision: D41572604

Pulled By: hx235

fbshipit-source-id: 9d9bdf594abd235e2137045cef513ca0b14e0a3a
2022-11-29 11:39:13 -08:00
Changyu Bi ab9741a6a9 Merge pull request #10984 from cbi42/7.9-iterate-upperbound
[7.9] Prevent iterating over range tombstones beyond `iterate_upper_bound`
2022-11-23 16:28:01 -08:00
Changyu Bi 9399bb844b Prevent iterating over range tombstones beyond iterate_upper_bound (#10966)
Summary:
Currently, `iterate_upper_bound` is not checked for range tombstone keys in MergingIterator. This may impact performance when there is a large number of range tombstones right after `iterate_upper_bound`. This PR fixes this issue by checking `iterate_upper_bound` in MergingIterator for range tombstone keys.

Pull Request resolved: https://github.com/facebook/rocksdb/pull/10966

Test Plan:
- added unit test
- stress test: `python3 tools/db_crashtest.py whitebox --simple --verify_iterator_with_expected_state_one_in=5 --delrangepercent=5 --prefixpercent=18 --writepercent=48 --readpercen=15 --duration=36000 --range_deletion_width=100`
- ran different stress tests over sandcastle
- Falcon team ran some test traffic and saw reduced CPU usage on processing range tombstones.

Reviewed By: ajkr

Differential Revision: D41414172

Pulled By: cbi42

fbshipit-source-id: 9b2c29eb3abb99327c6a649bdc412e70d863f981
2022-11-23 15:46:51 -08:00
Yanqin Jin ed91ed0a50 Make best-efforts recovery verify SST unique ID before Version construction (#10962)
Summary:
The check for SST unique IDs added to best-efforts recovery (`Options::best_efforts_recovery` is true).

With best_efforts_recovery being true, RocksDB will recover to the latest point in
MANIFEST such that all valid SST files included up to this point pass unique ID checks as well.

Pull Request resolved: https://github.com/facebook/rocksdb/pull/10962

Test Plan: make check

Reviewed By: pdillinger

Differential Revision: D41378241

Pulled By: riversand963

fbshipit-source-id: a036064e2c17dec13d080a24ef2a9f85d607b16c
2022-11-23 09:01:51 -08:00
55 changed files with 1071 additions and 863 deletions
+1 -1
View File
@@ -76,7 +76,7 @@ commands:
name: "Test RocksDB" name: "Test RocksDB"
shell: powershell.exe shell: powershell.exe
command: | command: |
build_tools\run_ci_db_test.ps1 -SuiteRun arena_test,db_basic_test,db_test,db_test2,db_merge_operand_test,bloom_test,c_test,coding_test,crc32c_test,dynamic_bloom_test,env_basic_test,env_test,hash_test,random_test -Concurrency 16 build_tools\run_ci_db_test.ps1 -SuiteRun db_basic_test,db_test,db_test2,db_merge_operand_test,bloom_test,c_test,coding_test,crc32c_test,dynamic_bloom_test,env_basic_test,env_test,hash_test,random_test -Concurrency 16
pre-steps-macos: pre-steps-macos:
steps: steps:
- pre-steps - pre-steps
-1
View File
@@ -796,7 +796,6 @@ set(SOURCES
options/options.cc options/options.cc
options/options_helper.cc options/options_helper.cc
options/options_parser.cc options/options_parser.cc
port/mmap.cc
port/stack_trace.cc port/stack_trace.cc
table/adaptive/adaptive_table_factory.cc table/adaptive/adaptive_table_factory.cc
table/block_based/binary_search_index_reader.cc table/block_based/binary_search_index_reader.cc
+21 -1
View File
@@ -1,10 +1,30 @@
# Rocksdb Change Log # Rocksdb Change Log
## Unreleased
### Bug Fixes
* Fixed a bug in DB open/recovery from a compressed WAL that was caused due to incorrect handling of certain record fragments with the same offset within a WAL block.
## 7.9.3 (02/01/2023)
### Bug Fixes
* Fixed a data race on `ColumnFamilyData::flush_reason` caused by concurrent flushes.
* Fixed `DisableManualCompaction()` and `CompactRangeOptions::canceled` to cancel compactions even when they are waiting on conflicting compactions to finish
## 7.9.2 (12/21/2022)
### Bug Fixes
* Fixed a heap use after free bug in async scan prefetching when the scan thread and another thread try to read and load the same seek block into cache.
## 7.9.1 (12/8/2022)
### Bug Fixes
* Fixed a regression in iterator where range tombstones after `iterate_upper_bound` is processed.
* Fixed a memory leak in MultiGet with async_io read option, caused by IO errors during table file open
### Behavior changes
* Make best-efforts recovery verify SST unique ID before Version construction (#10962)
## 7.9.0 (11/21/2022) ## 7.9.0 (11/21/2022)
### Performance Improvements ### Performance Improvements
* Fixed an iterator performance regression for delete range users when scanning through a consecutive sequence of range tombstones (#10877). * Fixed an iterator performance regression for delete range users when scanning through a consecutive sequence of range tombstones (#10877).
### Bug Fixes ### Bug Fixes
* Fix FIFO compaction causing corruption of overlapping seqnos in L0 files due to ingesting files of overlapping seqnos with memtable's under `CompactionOptionsFIFO::allow_compaction=true` or `CompactionOptionsFIFO::age_for_warm>0` or `CompactRange()/CompactFiles()` is used. Before the fix, `force_consistency_checks=true` may catch the corruption before it's exposed to readers, in which case writes returning `Status::Corruption` would be expected.
* Fix memory corruption error in scans if async_io is enabled. Memory corruption happened if there is IOError while reading the data leading to empty buffer and other buffer already in progress of async read goes again for reading. * Fix memory corruption error in scans if async_io is enabled. Memory corruption happened if there is IOError while reading the data leading to empty buffer and other buffer already in progress of async read goes again for reading.
* Fix failed memtable flush retry bug that could cause wrongly ordered updates, which would surface to writers as `Status::Corruption` in case of `force_consistency_checks=true` (default). It affects use cases that enable both parallel flush (`max_background_flushes > 1` or `max_background_jobs >= 8`) and non-default memtable count (`max_write_buffer_number > 2`). * Fix failed memtable flush retry bug that could cause wrongly ordered updates, which would surface to writers as `Status::Corruption` in case of `force_consistency_checks=true` (default). It affects use cases that enable both parallel flush (`max_background_flushes > 1` or `max_background_jobs >= 8`) and non-default memtable count (`max_write_buffer_number > 2`).
* Fixed an issue where the `READ_NUM_MERGE_OPERANDS` ticker was not updated when the base key-value or tombstone was read from an SST file. * Fixed an issue where the `READ_NUM_MERGE_OPERANDS` ticker was not updated when the base key-value or tombstone was read from an SST file.
-2
View File
@@ -163,7 +163,6 @@ cpp_library_wrapper(name="rocksdb_lib", srcs=[
"options/options.cc", "options/options.cc",
"options/options_helper.cc", "options/options_helper.cc",
"options/options_parser.cc", "options/options_parser.cc",
"port/mmap.cc",
"port/port_posix.cc", "port/port_posix.cc",
"port/stack_trace.cc", "port/stack_trace.cc",
"port/win/env_default.cc", "port/win/env_default.cc",
@@ -503,7 +502,6 @@ cpp_library_wrapper(name="rocksdb_whole_archive_lib", srcs=[
"options/options.cc", "options/options.cc",
"options/options_helper.cc", "options/options_helper.cc",
"options/options_parser.cc", "options/options_parser.cc",
"port/mmap.cc",
"port/port_posix.cc", "port/port_posix.cc",
"port/stack_trace.cc", "port/stack_trace.cc",
"port/win/env_default.cc", "port/win/env_default.cc",
+2 -5
View File
@@ -557,7 +557,6 @@ ColumnFamilyData::ColumnFamilyData(
next_(nullptr), next_(nullptr),
prev_(nullptr), prev_(nullptr),
log_number_(0), log_number_(0),
flush_reason_(FlushReason::kOthers),
column_family_set_(column_family_set), column_family_set_(column_family_set),
queued_for_flush_(false), queued_for_flush_(false),
queued_for_compaction_(false), queued_for_compaction_(false),
@@ -1212,17 +1211,15 @@ Compaction* ColumnFamilyData::CompactRange(
const InternalKey* begin, const InternalKey* end, const InternalKey* begin, const InternalKey* end,
InternalKey** compaction_end, bool* conflict, InternalKey** compaction_end, bool* conflict,
uint64_t max_file_num_to_ignore, const std::string& trim_ts) { uint64_t max_file_num_to_ignore, const std::string& trim_ts) {
SequenceNumber earliest_mem_seqno =
std::min(mem_->GetEarliestSequenceNumber(),
imm_.current()->GetEarliestSequenceNumber(false));
auto* result = compaction_picker_->CompactRange( auto* result = compaction_picker_->CompactRange(
GetName(), mutable_cf_options, mutable_db_options, GetName(), mutable_cf_options, mutable_db_options,
current_->storage_info(), input_level, output_level, current_->storage_info(), input_level, output_level,
compact_range_options, begin, end, compaction_end, conflict, compact_range_options, begin, end, compaction_end, conflict,
max_file_num_to_ignore, trim_ts, earliest_mem_seqno); max_file_num_to_ignore, trim_ts);
if (result != nullptr) { if (result != nullptr) {
result->SetInputVersion(current_); result->SetInputVersion(current_);
} }
TEST_SYNC_POINT("ColumnFamilyData::CompactRange:Return");
return result; return result;
} }
-6
View File
@@ -310,10 +310,6 @@ class ColumnFamilyData {
void SetLogNumber(uint64_t log_number) { log_number_ = log_number; } void SetLogNumber(uint64_t log_number) { log_number_ = log_number; }
uint64_t GetLogNumber() const { return log_number_; } uint64_t GetLogNumber() const { return log_number_; }
void SetFlushReason(FlushReason flush_reason) {
flush_reason_ = flush_reason;
}
FlushReason GetFlushReason() const { return flush_reason_; }
// thread-safe // thread-safe
const FileOptions* soptions() const; const FileOptions* soptions() const;
const ImmutableOptions* ioptions() const { return &ioptions_; } const ImmutableOptions* ioptions() const { return &ioptions_; }
@@ -598,8 +594,6 @@ class ColumnFamilyData {
// recovered from // recovered from
uint64_t log_number_; uint64_t log_number_;
std::atomic<FlushReason> flush_reason_;
// An object that keeps all the compaction stats // An object that keeps all the compaction stats
// and picks the next compaction // and picks the next compaction
std::unique_ptr<CompactionPicker> compaction_picker_; std::unique_ptr<CompactionPicker> compaction_picker_;
+6 -17
View File
@@ -32,7 +32,7 @@ bool FindIntraL0Compaction(const std::vector<FileMetaData*>& level_files,
uint64_t max_compact_bytes_per_del_file, uint64_t max_compact_bytes_per_del_file,
uint64_t max_compaction_bytes, uint64_t max_compaction_bytes,
CompactionInputFiles* comp_inputs, CompactionInputFiles* comp_inputs,
const SequenceNumber earliest_mem_seqno) { SequenceNumber earliest_mem_seqno) {
// Do not pick ingested file when there is at least one memtable not flushed // Do not pick ingested file when there is at least one memtable not flushed
// which of seqno is overlap with the sst. // which of seqno is overlap with the sst.
TEST_SYNC_POINT("FindIntraL0Compaction"); TEST_SYNC_POINT("FindIntraL0Compaction");
@@ -613,8 +613,7 @@ Compaction* CompactionPicker::CompactRange(
int input_level, int output_level, int input_level, int output_level,
const CompactRangeOptions& compact_range_options, const InternalKey* begin, const CompactRangeOptions& compact_range_options, const InternalKey* begin,
const InternalKey* end, InternalKey** compaction_end, bool* manual_conflict, const InternalKey* end, InternalKey** compaction_end, bool* manual_conflict,
uint64_t max_file_num_to_ignore, const std::string& trim_ts, uint64_t max_file_num_to_ignore, const std::string& trim_ts) {
const SequenceNumber /*earliest_mem_seqno*/) {
// CompactionPickerFIFO has its own implementation of compact range // CompactionPickerFIFO has its own implementation of compact range
assert(ioptions_.compaction_style != kCompactionStyleFIFO); assert(ioptions_.compaction_style != kCompactionStyleFIFO);
@@ -919,8 +918,7 @@ bool HaveOverlappingKeyRanges(const Comparator* c, const SstFileMetaData& a,
Status CompactionPicker::SanitizeCompactionInputFilesForAllLevels( Status CompactionPicker::SanitizeCompactionInputFilesForAllLevels(
std::unordered_set<uint64_t>* input_files, std::unordered_set<uint64_t>* input_files,
const ColumnFamilyMetaData& cf_meta, const int output_level, const ColumnFamilyMetaData& cf_meta, const int output_level) const {
const SequenceNumber earliest_mem_seqno) const {
auto& levels = cf_meta.levels; auto& levels = cf_meta.levels;
auto comparator = icmp_->user_comparator(); auto comparator = icmp_->user_comparator();
@@ -997,13 +995,6 @@ Status CompactionPicker::SanitizeCompactionInputFilesForAllLevels(
current_files[f].name + current_files[f].name +
" is currently being compacted."); " is currently being compacted.");
} }
if (output_level == 0 &&
current_files[f].largest_seqno > earliest_mem_seqno) {
return Status::Aborted(
"Necessary compaction input file " + current_files[f].name +
" has overlapping seqnos with earliest memtable seqnos.");
}
input_files->insert(TableFileNameToNumber(current_files[f].name)); input_files->insert(TableFileNameToNumber(current_files[f].name));
} }
@@ -1060,14 +1051,12 @@ Status CompactionPicker::SanitizeCompactionInputFilesForAllLevels(
"A running compaction is writing to the same output level in an " "A running compaction is writing to the same output level in an "
"overlapping key range"); "overlapping key range");
} }
return Status::OK(); return Status::OK();
} }
Status CompactionPicker::SanitizeCompactionInputFiles( Status CompactionPicker::SanitizeCompactionInputFiles(
std::unordered_set<uint64_t>* input_files, std::unordered_set<uint64_t>* input_files,
const ColumnFamilyMetaData& cf_meta, const int output_level, const ColumnFamilyMetaData& cf_meta, const int output_level) const {
const SequenceNumber earliest_mem_seqno) const {
assert(static_cast<int>(cf_meta.levels.size()) - 1 == assert(static_cast<int>(cf_meta.levels.size()) - 1 ==
cf_meta.levels[cf_meta.levels.size() - 1].level); cf_meta.levels[cf_meta.levels.size() - 1].level);
if (output_level >= static_cast<int>(cf_meta.levels.size())) { if (output_level >= static_cast<int>(cf_meta.levels.size())) {
@@ -1093,8 +1082,8 @@ Status CompactionPicker::SanitizeCompactionInputFiles(
"A compaction must contain at least one file."); "A compaction must contain at least one file.");
} }
Status s = SanitizeCompactionInputFilesForAllLevels( Status s = SanitizeCompactionInputFilesForAllLevels(input_files, cf_meta,
input_files, cf_meta, output_level, earliest_mem_seqno); output_level);
if (!s.ok()) { if (!s.ok()) {
return s; return s;
+25 -45
View File
@@ -51,24 +51,15 @@ class CompactionPicker {
virtual ~CompactionPicker(); virtual ~CompactionPicker();
// Pick level and inputs for a new compaction. // Pick level and inputs for a new compaction.
//
// `earliest_mem_seqno` is the earliest seqno of unflushed memtables.
// It is needed to compare with compaction input SST files' largest seqnos
// in order to exclude those of seqnos potentially overlap with memtables'
// seqnos when doing compaction to L0. This will avoid creating a SST files in
// L0 newer than a unflushed memtable. Such SST file can exist in the first
// place when it's ingested or resulted from compaction involving files
// ingested.
//
// Returns nullptr if there is no compaction to be done. // Returns nullptr if there is no compaction to be done.
// Otherwise returns a pointer to a heap-allocated object that // Otherwise returns a pointer to a heap-allocated object that
// describes the compaction. Caller should delete the result. // describes the compaction. Caller should delete the result.
virtual Compaction* PickCompaction( virtual Compaction* PickCompaction(
const std::string& cf_name, const MutableCFOptions& mutable_cf_options, const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
const MutableDBOptions& mutable_db_options, VersionStorageInfo* vstorage, const MutableDBOptions& mutable_db_options, VersionStorageInfo* vstorage,
LogBuffer* log_buffer, const SequenceNumber earliest_mem_seqno) = 0; LogBuffer* log_buffer,
SequenceNumber earliest_memtable_seqno = kMaxSequenceNumber) = 0;
// `earliest_mem_seqno`: see PickCompaction() API
// Return a compaction object for compacting the range [begin,end] in // Return a compaction object for compacting the range [begin,end] in
// the specified level. Returns nullptr if there is nothing in that // the specified level. Returns nullptr if there is nothing in that
// level that overlaps the specified range. Caller should delete // level that overlaps the specified range. Caller should delete
@@ -87,8 +78,7 @@ class CompactionPicker {
const CompactRangeOptions& compact_range_options, const CompactRangeOptions& compact_range_options,
const InternalKey* begin, const InternalKey* end, const InternalKey* begin, const InternalKey* end,
InternalKey** compaction_end, bool* manual_conflict, InternalKey** compaction_end, bool* manual_conflict,
uint64_t max_file_num_to_ignore, const std::string& trim_ts, uint64_t max_file_num_to_ignore, const std::string& trim_ts);
const SequenceNumber earliest_mem_seqno);
// The maximum allowed output level. Default value is NumberLevels() - 1. // The maximum allowed output level. Default value is NumberLevels() - 1.
virtual int MaxOutputLevel() const { return NumberLevels() - 1; } virtual int MaxOutputLevel() const { return NumberLevels() - 1; }
@@ -101,18 +91,10 @@ class CompactionPicker {
// files. If it's not possible to conver an invalid input_files // files. If it's not possible to conver an invalid input_files
// into a valid one by adding more files, the function will return a // into a valid one by adding more files, the function will return a
// non-ok status with specific reason. // non-ok status with specific reason.
//
// Cases of returning non-ok status include but not limited to:
// - When output_level == 0 and input_files contains sst files
// of largest seqno greater than `earliest_mem_seqno`. This will
// avoid creating a SST files in L0 newer than a unflushed memtable.
// Such SST file can exist in the first place when it's ingested or
// resulted from compaction involving files ingested.
#ifndef ROCKSDB_LITE #ifndef ROCKSDB_LITE
Status SanitizeCompactionInputFiles( Status SanitizeCompactionInputFiles(std::unordered_set<uint64_t>* input_files,
std::unordered_set<uint64_t>* input_files, const ColumnFamilyMetaData& cf_meta,
const ColumnFamilyMetaData& cf_meta, const int output_level, const int output_level) const;
const SequenceNumber earliest_mem_seqno) const;
#endif // ROCKSDB_LITE #endif // ROCKSDB_LITE
// Free up the files that participated in a compaction // Free up the files that participated in a compaction
@@ -248,8 +230,7 @@ class CompactionPicker {
#ifndef ROCKSDB_LITE #ifndef ROCKSDB_LITE
virtual Status SanitizeCompactionInputFilesForAllLevels( virtual Status SanitizeCompactionInputFilesForAllLevels(
std::unordered_set<uint64_t>* input_files, std::unordered_set<uint64_t>* input_files,
const ColumnFamilyMetaData& cf_meta, const int output_level, const ColumnFamilyMetaData& cf_meta, const int output_level) const;
const SequenceNumber earliest_mem_seqno) const;
#endif // ROCKSDB_LITE #endif // ROCKSDB_LITE
// Keeps track of all compactions that are running on Level0. // Keeps track of all compactions that are running on Level0.
@@ -279,22 +260,23 @@ class NullCompactionPicker : public CompactionPicker {
const MutableCFOptions& /*mutable_cf_options*/, const MutableCFOptions& /*mutable_cf_options*/,
const MutableDBOptions& /*mutable_db_options*/, const MutableDBOptions& /*mutable_db_options*/,
VersionStorageInfo* /*vstorage*/, LogBuffer* /* log_buffer */, VersionStorageInfo* /*vstorage*/, LogBuffer* /* log_buffer */,
const SequenceNumber /* earliest_mem_seqno */) override { SequenceNumber /* earliest_memtable_seqno */) override {
return nullptr; return nullptr;
} }
// Always return "nullptr" // Always return "nullptr"
Compaction* CompactRange( Compaction* CompactRange(const std::string& /*cf_name*/,
const std::string& /*cf_name*/, const MutableCFOptions& /*mutable_cf_options*/,
const MutableCFOptions& /*mutable_cf_options*/, const MutableDBOptions& /*mutable_db_options*/,
const MutableDBOptions& /*mutable_db_options*/, VersionStorageInfo* /*vstorage*/,
VersionStorageInfo* /*vstorage*/, int /*input_level*/, int /*input_level*/, int /*output_level*/,
int /*output_level*/, const CompactRangeOptions& /*compact_range_options*/,
const CompactRangeOptions& /*compact_range_options*/, const InternalKey* /*begin*/,
const InternalKey* /*begin*/, const InternalKey* /*end*/, const InternalKey* /*end*/,
InternalKey** /*compaction_end*/, bool* /*manual_conflict*/, InternalKey** /*compaction_end*/,
uint64_t /*max_file_num_to_ignore*/, const std::string& /*trim_ts*/, bool* /*manual_conflict*/,
const SequenceNumber /* earliest_mem_seqno */) override { uint64_t /*max_file_num_to_ignore*/,
const std::string& /*trim_ts*/) override {
return nullptr; return nullptr;
} }
@@ -321,14 +303,12 @@ class NullCompactionPicker : public CompactionPicker {
// initialized with corresponding input // initialized with corresponding input
// files. Cannot be nullptr. // files. Cannot be nullptr.
// //
// @param earliest_mem_seqno See PickCompaction() API
// @return true iff compaction was found. // @return true iff compaction was found.
bool FindIntraL0Compaction(const std::vector<FileMetaData*>& level_files, bool FindIntraL0Compaction(
size_t min_files_to_compact, const std::vector<FileMetaData*>& level_files, size_t min_files_to_compact,
uint64_t max_compact_bytes_per_del_file, uint64_t max_compact_bytes_per_del_file, uint64_t max_compaction_bytes,
uint64_t max_compaction_bytes, CompactionInputFiles* comp_inputs,
CompactionInputFiles* comp_inputs, SequenceNumber earliest_mem_seqno = kMaxSequenceNumber);
const SequenceNumber earliest_mem_seqno);
CompressionType GetCompressionType(const VersionStorageInfo* vstorage, CompressionType GetCompressionType(const VersionStorageInfo* vstorage,
const MutableCFOptions& mutable_cf_options, const MutableCFOptions& mutable_cf_options,
+10 -17
View File
@@ -139,7 +139,7 @@ Compaction* FIFOCompactionPicker::PickTTLCompaction(
Compaction* FIFOCompactionPicker::PickSizeCompaction( Compaction* FIFOCompactionPicker::PickSizeCompaction(
const std::string& cf_name, const MutableCFOptions& mutable_cf_options, const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
const MutableDBOptions& mutable_db_options, VersionStorageInfo* vstorage, const MutableDBOptions& mutable_db_options, VersionStorageInfo* vstorage,
LogBuffer* log_buffer, const SequenceNumber earliest_mem_seqno) { LogBuffer* log_buffer) {
// compute the total size and identify the last non-empty level // compute the total size and identify the last non-empty level
int last_level = 0; int last_level = 0;
uint64_t total_size = 0; uint64_t total_size = 0;
@@ -176,8 +176,7 @@ Compaction* FIFOCompactionPicker::PickSizeCompaction(
.level0_file_num_compaction_trigger /* min_files_to_compact */ .level0_file_num_compaction_trigger /* min_files_to_compact */
, ,
max_compact_bytes_per_del_file, max_compact_bytes_per_del_file,
mutable_cf_options.max_compaction_bytes, &comp_inputs, mutable_cf_options.max_compaction_bytes, &comp_inputs)) {
earliest_mem_seqno)) {
Compaction* c = new Compaction( Compaction* c = new Compaction(
vstorage, ioptions_, mutable_cf_options, mutable_db_options, vstorage, ioptions_, mutable_cf_options, mutable_db_options,
{comp_inputs}, 0, 16 * 1024 * 1024 /* output file size limit */, {comp_inputs}, 0, 16 * 1024 * 1024 /* output file size limit */,
@@ -276,8 +275,7 @@ Compaction* FIFOCompactionPicker::PickSizeCompaction(
Compaction* FIFOCompactionPicker::PickCompactionToWarm( Compaction* FIFOCompactionPicker::PickCompactionToWarm(
const std::string& cf_name, const MutableCFOptions& mutable_cf_options, const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
const MutableDBOptions& mutable_db_options, VersionStorageInfo* vstorage, const MutableDBOptions& mutable_db_options, VersionStorageInfo* vstorage,
LogBuffer* log_buffer, const SequenceNumber earliest_mem_seqno) { LogBuffer* log_buffer) {
TEST_SYNC_POINT("PickCompactionToWarm");
if (mutable_cf_options.compaction_options_fifo.age_for_warm == 0) { if (mutable_cf_options.compaction_options_fifo.age_for_warm == 0) {
return nullptr; return nullptr;
} }
@@ -301,8 +299,6 @@ Compaction* FIFOCompactionPicker::PickCompactionToWarm(
cf_name.c_str(), status.ToString().c_str()); cf_name.c_str(), status.ToString().c_str());
return nullptr; return nullptr;
} }
TEST_SYNC_POINT_CALLBACK("PickCompactionToWarm::BeforeGetCurrentTime",
&_current_time);
const uint64_t current_time = static_cast<uint64_t>(_current_time); const uint64_t current_time = static_cast<uint64_t>(_current_time);
if (!level0_compactions_in_progress_.empty()) { if (!level0_compactions_in_progress_.empty()) {
@@ -349,8 +345,7 @@ Compaction* FIFOCompactionPicker::PickCompactionToWarm(
// for warm tier. // for warm tier.
break; break;
} }
if (prev_file != nullptr && if (prev_file != nullptr) {
prev_file->fd.largest_seqno <= earliest_mem_seqno) {
compaction_size += prev_file->fd.GetFileSize(); compaction_size += prev_file->fd.GetFileSize();
if (compaction_size > mutable_cf_options.max_compaction_bytes) { if (compaction_size > mutable_cf_options.max_compaction_bytes) {
break; break;
@@ -394,7 +389,7 @@ Compaction* FIFOCompactionPicker::PickCompactionToWarm(
Compaction* FIFOCompactionPicker::PickCompaction( Compaction* FIFOCompactionPicker::PickCompaction(
const std::string& cf_name, const MutableCFOptions& mutable_cf_options, const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
const MutableDBOptions& mutable_db_options, VersionStorageInfo* vstorage, const MutableDBOptions& mutable_db_options, VersionStorageInfo* vstorage,
LogBuffer* log_buffer, const SequenceNumber earliest_mem_seqno) { LogBuffer* log_buffer, SequenceNumber /*earliest_memtable_seqno*/) {
Compaction* c = nullptr; Compaction* c = nullptr;
if (mutable_cf_options.ttl > 0) { if (mutable_cf_options.ttl > 0) {
c = PickTTLCompaction(cf_name, mutable_cf_options, mutable_db_options, c = PickTTLCompaction(cf_name, mutable_cf_options, mutable_db_options,
@@ -402,11 +397,11 @@ Compaction* FIFOCompactionPicker::PickCompaction(
} }
if (c == nullptr) { if (c == nullptr) {
c = PickSizeCompaction(cf_name, mutable_cf_options, mutable_db_options, c = PickSizeCompaction(cf_name, mutable_cf_options, mutable_db_options,
vstorage, log_buffer, earliest_mem_seqno); vstorage, log_buffer);
} }
if (c == nullptr) { if (c == nullptr) {
c = PickCompactionToWarm(cf_name, mutable_cf_options, mutable_db_options, c = PickCompactionToWarm(cf_name, mutable_cf_options, mutable_db_options,
vstorage, log_buffer, earliest_mem_seqno); vstorage, log_buffer);
} }
RegisterCompaction(c); RegisterCompaction(c);
return c; return c;
@@ -419,8 +414,7 @@ Compaction* FIFOCompactionPicker::CompactRange(
const CompactRangeOptions& /*compact_range_options*/, const CompactRangeOptions& /*compact_range_options*/,
const InternalKey* /*begin*/, const InternalKey* /*end*/, const InternalKey* /*begin*/, const InternalKey* /*end*/,
InternalKey** compaction_end, bool* /*manual_conflict*/, InternalKey** compaction_end, bool* /*manual_conflict*/,
uint64_t /*max_file_num_to_ignore*/, const std::string& /*trim_ts*/, uint64_t /*max_file_num_to_ignore*/, const std::string& /*trim_ts*/) {
const SequenceNumber earliest_mem_seqno) {
#ifdef NDEBUG #ifdef NDEBUG
(void)input_level; (void)input_level;
(void)output_level; (void)output_level;
@@ -429,9 +423,8 @@ Compaction* FIFOCompactionPicker::CompactRange(
assert(output_level == 0); assert(output_level == 0);
*compaction_end = nullptr; *compaction_end = nullptr;
LogBuffer log_buffer(InfoLogLevel::INFO_LEVEL, ioptions_.logger); LogBuffer log_buffer(InfoLogLevel::INFO_LEVEL, ioptions_.logger);
Compaction* c = Compaction* c = PickCompaction(cf_name, mutable_cf_options,
PickCompaction(cf_name, mutable_cf_options, mutable_db_options, vstorage, mutable_db_options, vstorage, &log_buffer);
&log_buffer, earliest_mem_seqno);
log_buffer.FlushBufferToLog(); log_buffer.FlushBufferToLog();
return c; return c;
} }
+5 -11
View File
@@ -22,12 +22,9 @@ class FIFOCompactionPicker : public CompactionPicker {
virtual Compaction* PickCompaction( virtual Compaction* PickCompaction(
const std::string& cf_name, const MutableCFOptions& mutable_cf_options, const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
const MutableDBOptions& mutable_db_options, VersionStorageInfo* version, const MutableDBOptions& mutable_db_options, VersionStorageInfo* version,
LogBuffer* log_buffer, const SequenceNumber earliest_mem_seqno) override; LogBuffer* log_buffer,
SequenceNumber earliest_memtable_seqno = kMaxSequenceNumber) override;
// `earliest_mem_seqno`: see PickCompaction() API for more. In FIFO's
// implementation of CompactRange(), different from others, we will not return
// `nullptr` right away when intput files of compaction to L0 has seqnos
// potentially overlapping with memtable's but exlucde those files.
virtual Compaction* CompactRange( virtual Compaction* CompactRange(
const std::string& cf_name, const MutableCFOptions& mutable_cf_options, const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
const MutableDBOptions& mutable_db_options, VersionStorageInfo* vstorage, const MutableDBOptions& mutable_db_options, VersionStorageInfo* vstorage,
@@ -35,8 +32,7 @@ class FIFOCompactionPicker : public CompactionPicker {
const CompactRangeOptions& compact_range_options, const CompactRangeOptions& compact_range_options,
const InternalKey* begin, const InternalKey* end, const InternalKey* begin, const InternalKey* end,
InternalKey** compaction_end, bool* manual_conflict, InternalKey** compaction_end, bool* manual_conflict,
uint64_t max_file_num_to_ignore, const std::string& trim_ts, uint64_t max_file_num_to_ignore, const std::string& trim_ts) override;
const SequenceNumber earliest_mem_seqno) override;
// The maximum allowed output level. Always returns 0. // The maximum allowed output level. Always returns 0.
virtual int MaxOutputLevel() const override { return 0; } virtual int MaxOutputLevel() const override { return 0; }
@@ -55,15 +51,13 @@ class FIFOCompactionPicker : public CompactionPicker {
const MutableCFOptions& mutable_cf_options, const MutableCFOptions& mutable_cf_options,
const MutableDBOptions& mutable_db_options, const MutableDBOptions& mutable_db_options,
VersionStorageInfo* version, VersionStorageInfo* version,
LogBuffer* log_buffer, LogBuffer* log_buffer);
SequenceNumber earliest_mem_seqno);
Compaction* PickCompactionToWarm(const std::string& cf_name, Compaction* PickCompactionToWarm(const std::string& cf_name,
const MutableCFOptions& mutable_cf_options, const MutableCFOptions& mutable_cf_options,
const MutableDBOptions& mutable_db_options, const MutableDBOptions& mutable_db_options,
VersionStorageInfo* version, VersionStorageInfo* version,
LogBuffer* log_buffer, LogBuffer* log_buffer);
const SequenceNumber earliest_mem_seqno);
}; };
} // namespace ROCKSDB_NAMESPACE } // namespace ROCKSDB_NAMESPACE
#endif // !ROCKSDB_LITE #endif // !ROCKSDB_LITE
+3 -3
View File
@@ -50,7 +50,7 @@ class LevelCompactionBuilder {
public: public:
LevelCompactionBuilder(const std::string& cf_name, LevelCompactionBuilder(const std::string& cf_name,
VersionStorageInfo* vstorage, VersionStorageInfo* vstorage,
const SequenceNumber earliest_mem_seqno, SequenceNumber earliest_mem_seqno,
CompactionPicker* compaction_picker, CompactionPicker* compaction_picker,
LogBuffer* log_buffer, LogBuffer* log_buffer,
const MutableCFOptions& mutable_cf_options, const MutableCFOptions& mutable_cf_options,
@@ -122,7 +122,7 @@ class LevelCompactionBuilder {
const std::string& cf_name_; const std::string& cf_name_;
VersionStorageInfo* vstorage_; VersionStorageInfo* vstorage_;
const SequenceNumber earliest_mem_seqno_; SequenceNumber earliest_mem_seqno_;
CompactionPicker* compaction_picker_; CompactionPicker* compaction_picker_;
LogBuffer* log_buffer_; LogBuffer* log_buffer_;
int start_level_ = -1; int start_level_ = -1;
@@ -832,7 +832,7 @@ bool LevelCompactionBuilder::PickIntraL0Compaction() {
Compaction* LevelCompactionPicker::PickCompaction( Compaction* LevelCompactionPicker::PickCompaction(
const std::string& cf_name, const MutableCFOptions& mutable_cf_options, const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
const MutableDBOptions& mutable_db_options, VersionStorageInfo* vstorage, const MutableDBOptions& mutable_db_options, VersionStorageInfo* vstorage,
LogBuffer* log_buffer, const SequenceNumber earliest_mem_seqno) { LogBuffer* log_buffer, SequenceNumber earliest_mem_seqno) {
LevelCompactionBuilder builder(cf_name, vstorage, earliest_mem_seqno, this, LevelCompactionBuilder builder(cf_name, vstorage, earliest_mem_seqno, this,
log_buffer, mutable_cf_options, ioptions_, log_buffer, mutable_cf_options, ioptions_,
mutable_db_options); mutable_db_options);
+2 -1
View File
@@ -23,7 +23,8 @@ class LevelCompactionPicker : public CompactionPicker {
virtual Compaction* PickCompaction( virtual Compaction* PickCompaction(
const std::string& cf_name, const MutableCFOptions& mutable_cf_options, const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
const MutableDBOptions& mutable_db_options, VersionStorageInfo* vstorage, const MutableDBOptions& mutable_db_options, VersionStorageInfo* vstorage,
LogBuffer* log_buffer, const SequenceNumber earliest_mem_seqno) override; LogBuffer* log_buffer,
SequenceNumber earliest_memtable_seqno = kMaxSequenceNumber) override;
virtual bool NeedsCompaction( virtual bool NeedsCompaction(
const VersionStorageInfo* vstorage) const override; const VersionStorageInfo* vstorage) const override;
+90 -90
View File
@@ -218,7 +218,7 @@ TEST_F(CompactionPickerTest, Empty) {
UpdateVersionStorageInfo(); UpdateVersionStorageInfo();
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() == nullptr); ASSERT_TRUE(compaction.get() == nullptr);
} }
@@ -230,7 +230,7 @@ TEST_F(CompactionPickerTest, Single) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() == nullptr); ASSERT_TRUE(compaction.get() == nullptr);
} }
@@ -244,7 +244,7 @@ TEST_F(CompactionPickerTest, Level0Trigger) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(2U, compaction->num_input_files(0)); ASSERT_EQ(2U, compaction->num_input_files(0));
ASSERT_EQ(1U, compaction->input(0, 0)->fd.GetNumber()); ASSERT_EQ(1U, compaction->input(0, 0)->fd.GetNumber());
@@ -258,7 +258,7 @@ TEST_F(CompactionPickerTest, Level1Trigger) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(1U, compaction->num_input_files(0)); ASSERT_EQ(1U, compaction->num_input_files(0));
ASSERT_EQ(66U, compaction->input(0, 0)->fd.GetNumber()); ASSERT_EQ(66U, compaction->input(0, 0)->fd.GetNumber());
@@ -277,7 +277,7 @@ TEST_F(CompactionPickerTest, Level1Trigger2) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(1U, compaction->num_input_files(0)); ASSERT_EQ(1U, compaction->num_input_files(0));
ASSERT_EQ(2U, compaction->num_input_files(1)); ASSERT_EQ(2U, compaction->num_input_files(1));
@@ -309,7 +309,7 @@ TEST_F(CompactionPickerTest, LevelMaxScore) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(1U, compaction->num_input_files(0)); ASSERT_EQ(1U, compaction->num_input_files(0));
ASSERT_EQ(7U, compaction->input(0, 0)->fd.GetNumber()); ASSERT_EQ(7U, compaction->input(0, 0)->fd.GetNumber());
@@ -357,7 +357,7 @@ TEST_F(CompactionPickerTest, Level0TriggerDynamic) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(2U, compaction->num_input_files(0)); ASSERT_EQ(2U, compaction->num_input_files(0));
ASSERT_EQ(1U, compaction->input(0, 0)->fd.GetNumber()); ASSERT_EQ(1U, compaction->input(0, 0)->fd.GetNumber());
@@ -382,7 +382,7 @@ TEST_F(CompactionPickerTest, Level0TriggerDynamic2) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(2U, compaction->num_input_files(0)); ASSERT_EQ(2U, compaction->num_input_files(0));
ASSERT_EQ(1U, compaction->input(0, 0)->fd.GetNumber()); ASSERT_EQ(1U, compaction->input(0, 0)->fd.GetNumber());
@@ -408,7 +408,7 @@ TEST_F(CompactionPickerTest, Level0TriggerDynamic3) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(2U, compaction->num_input_files(0)); ASSERT_EQ(2U, compaction->num_input_files(0));
ASSERT_EQ(1U, compaction->input(0, 0)->fd.GetNumber()); ASSERT_EQ(1U, compaction->input(0, 0)->fd.GetNumber());
@@ -438,7 +438,7 @@ TEST_F(CompactionPickerTest, Level0TriggerDynamic4) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(2U, compaction->num_input_files(0)); ASSERT_EQ(2U, compaction->num_input_files(0));
ASSERT_EQ(1U, compaction->input(0, 0)->fd.GetNumber()); ASSERT_EQ(1U, compaction->input(0, 0)->fd.GetNumber());
@@ -471,7 +471,7 @@ TEST_F(CompactionPickerTest, LevelTriggerDynamic4) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(1U, compaction->num_input_files(0)); ASSERT_EQ(1U, compaction->num_input_files(0));
ASSERT_EQ(5U, compaction->input(0, 0)->fd.GetNumber()); ASSERT_EQ(5U, compaction->input(0, 0)->fd.GetNumber());
@@ -528,7 +528,7 @@ TEST_F(CompactionPickerTest, CompactionUniversalIngestBehindReservedLevel) {
std::unique_ptr<Compaction> compaction( std::unique_ptr<Compaction> compaction(
universal_compaction_picker.PickCompaction( universal_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
// output level should be the one above the bottom-most // output level should be the one above the bottom-most
ASSERT_EQ(1, compaction->output_level()); ASSERT_EQ(1, compaction->output_level());
@@ -563,7 +563,7 @@ TEST_F(CompactionPickerTest, CannotTrivialMoveUniversal) {
std::unique_ptr<Compaction> compaction( std::unique_ptr<Compaction> compaction(
universal_compaction_picker.PickCompaction( universal_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(!compaction->is_trivial_move()); ASSERT_TRUE(!compaction->is_trivial_move());
} }
@@ -590,7 +590,7 @@ TEST_F(CompactionPickerTest, AllowsTrivialMoveUniversal) {
std::unique_ptr<Compaction> compaction( std::unique_ptr<Compaction> compaction(
universal_compaction_picker.PickCompaction( universal_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction->is_trivial_move()); ASSERT_TRUE(compaction->is_trivial_move());
} }
@@ -619,7 +619,7 @@ TEST_F(CompactionPickerTest, UniversalPeriodicCompaction1) {
std::unique_ptr<Compaction> compaction( std::unique_ptr<Compaction> compaction(
universal_compaction_picker.PickCompaction( universal_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction); ASSERT_TRUE(compaction);
ASSERT_EQ(4, compaction->output_level()); ASSERT_EQ(4, compaction->output_level());
@@ -650,7 +650,7 @@ TEST_F(CompactionPickerTest, UniversalPeriodicCompaction2) {
std::unique_ptr<Compaction> compaction( std::unique_ptr<Compaction> compaction(
universal_compaction_picker.PickCompaction( universal_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_FALSE(compaction); ASSERT_FALSE(compaction);
} }
@@ -677,7 +677,7 @@ TEST_F(CompactionPickerTest, UniversalPeriodicCompaction3) {
std::unique_ptr<Compaction> compaction( std::unique_ptr<Compaction> compaction(
universal_compaction_picker.PickCompaction( universal_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_FALSE(compaction); ASSERT_FALSE(compaction);
} }
@@ -708,7 +708,7 @@ TEST_F(CompactionPickerTest, UniversalPeriodicCompaction4) {
std::unique_ptr<Compaction> compaction( std::unique_ptr<Compaction> compaction(
universal_compaction_picker.PickCompaction( universal_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(!compaction || ASSERT_TRUE(!compaction ||
compaction->start_level() != compaction->output_level()); compaction->start_level() != compaction->output_level());
} }
@@ -729,7 +729,7 @@ TEST_F(CompactionPickerTest, UniversalPeriodicCompaction5) {
std::unique_ptr<Compaction> compaction( std::unique_ptr<Compaction> compaction(
universal_compaction_picker.PickCompaction( universal_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction); ASSERT_TRUE(compaction);
ASSERT_EQ(0, compaction->start_level()); ASSERT_EQ(0, compaction->start_level());
ASSERT_EQ(1U, compaction->num_input_files(0)); ASSERT_EQ(1U, compaction->num_input_files(0));
@@ -754,7 +754,7 @@ TEST_F(CompactionPickerTest, UniversalPeriodicCompaction6) {
std::unique_ptr<Compaction> compaction( std::unique_ptr<Compaction> compaction(
universal_compaction_picker.PickCompaction( universal_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction); ASSERT_TRUE(compaction);
ASSERT_EQ(4, compaction->start_level()); ASSERT_EQ(4, compaction->start_level());
ASSERT_EQ(2U, compaction->num_input_files(0)); ASSERT_EQ(2U, compaction->num_input_files(0));
@@ -792,7 +792,7 @@ TEST_F(CompactionPickerTest, UniversalIncrementalSpace1) {
std::unique_ptr<Compaction> compaction( std::unique_ptr<Compaction> compaction(
universal_compaction_picker.PickCompaction( universal_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction); ASSERT_TRUE(compaction);
ASSERT_EQ(4, compaction->output_level()); ASSERT_EQ(4, compaction->output_level());
ASSERT_EQ(3, compaction->start_level()); ASSERT_EQ(3, compaction->start_level());
@@ -834,7 +834,7 @@ TEST_F(CompactionPickerTest, UniversalIncrementalSpace2) {
std::unique_ptr<Compaction> compaction( std::unique_ptr<Compaction> compaction(
universal_compaction_picker.PickCompaction( universal_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction); ASSERT_TRUE(compaction);
ASSERT_EQ(4, compaction->output_level()); ASSERT_EQ(4, compaction->output_level());
ASSERT_EQ(2, compaction->start_level()); ASSERT_EQ(2, compaction->start_level());
@@ -876,7 +876,7 @@ TEST_F(CompactionPickerTest, UniversalIncrementalSpace3) {
std::unique_ptr<Compaction> compaction( std::unique_ptr<Compaction> compaction(
universal_compaction_picker.PickCompaction( universal_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction); ASSERT_TRUE(compaction);
ASSERT_EQ(4, compaction->output_level()); ASSERT_EQ(4, compaction->output_level());
ASSERT_EQ(2, compaction->start_level()); ASSERT_EQ(2, compaction->start_level());
@@ -924,7 +924,7 @@ TEST_F(CompactionPickerTest, UniversalIncrementalSpace4) {
std::unique_ptr<Compaction> compaction( std::unique_ptr<Compaction> compaction(
universal_compaction_picker.PickCompaction( universal_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction); ASSERT_TRUE(compaction);
ASSERT_EQ(4, compaction->output_level()); ASSERT_EQ(4, compaction->output_level());
ASSERT_EQ(3, compaction->start_level()); ASSERT_EQ(3, compaction->start_level());
@@ -968,7 +968,7 @@ TEST_F(CompactionPickerTest, UniversalIncrementalSpace5) {
std::unique_ptr<Compaction> compaction( std::unique_ptr<Compaction> compaction(
universal_compaction_picker.PickCompaction( universal_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction); ASSERT_TRUE(compaction);
ASSERT_EQ(4, compaction->output_level()); ASSERT_EQ(4, compaction->output_level());
ASSERT_EQ(3, compaction->start_level()); ASSERT_EQ(3, compaction->start_level());
@@ -1035,7 +1035,7 @@ TEST_F(CompactionPickerTest, FIFOToWarm1) {
ASSERT_EQ(fifo_compaction_picker.NeedsCompaction(vstorage_.get()), true); ASSERT_EQ(fifo_compaction_picker.NeedsCompaction(vstorage_.get()), true);
std::unique_ptr<Compaction> compaction(fifo_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(fifo_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(1U, compaction->num_input_files(0)); ASSERT_EQ(1U, compaction->num_input_files(0));
ASSERT_EQ(3U, compaction->input(0, 0)->fd.GetNumber()); ASSERT_EQ(3U, compaction->input(0, 0)->fd.GetNumber());
@@ -1073,7 +1073,7 @@ TEST_F(CompactionPickerTest, FIFOToWarm2) {
ASSERT_EQ(fifo_compaction_picker.NeedsCompaction(vstorage_.get()), true); ASSERT_EQ(fifo_compaction_picker.NeedsCompaction(vstorage_.get()), true);
std::unique_ptr<Compaction> compaction(fifo_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(fifo_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(2U, compaction->num_input_files(0)); ASSERT_EQ(2U, compaction->num_input_files(0));
ASSERT_EQ(2U, compaction->input(0, 0)->fd.GetNumber()); ASSERT_EQ(2U, compaction->input(0, 0)->fd.GetNumber());
@@ -1114,7 +1114,7 @@ TEST_F(CompactionPickerTest, FIFOToWarmMaxSize) {
ASSERT_EQ(fifo_compaction_picker.NeedsCompaction(vstorage_.get()), true); ASSERT_EQ(fifo_compaction_picker.NeedsCompaction(vstorage_.get()), true);
std::unique_ptr<Compaction> compaction(fifo_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(fifo_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(2U, compaction->num_input_files(0)); ASSERT_EQ(2U, compaction->num_input_files(0));
ASSERT_EQ(1U, compaction->input(0, 0)->fd.GetNumber()); ASSERT_EQ(1U, compaction->input(0, 0)->fd.GetNumber());
@@ -1155,7 +1155,7 @@ TEST_F(CompactionPickerTest, FIFOToWarmWithExistingWarm) {
ASSERT_EQ(fifo_compaction_picker.NeedsCompaction(vstorage_.get()), true); ASSERT_EQ(fifo_compaction_picker.NeedsCompaction(vstorage_.get()), true);
std::unique_ptr<Compaction> compaction(fifo_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(fifo_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(2U, compaction->num_input_files(0)); ASSERT_EQ(2U, compaction->num_input_files(0));
ASSERT_EQ(2U, compaction->input(0, 0)->fd.GetNumber()); ASSERT_EQ(2U, compaction->input(0, 0)->fd.GetNumber());
@@ -1197,7 +1197,7 @@ TEST_F(CompactionPickerTest, FIFOToWarmWithOngoing) {
ASSERT_EQ(fifo_compaction_picker.NeedsCompaction(vstorage_.get()), true); ASSERT_EQ(fifo_compaction_picker.NeedsCompaction(vstorage_.get()), true);
std::unique_ptr<Compaction> compaction(fifo_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(fifo_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
// Stop if a file is being compacted // Stop if a file is being compacted
ASSERT_TRUE(compaction.get() == nullptr); ASSERT_TRUE(compaction.get() == nullptr);
} }
@@ -1236,7 +1236,7 @@ TEST_F(CompactionPickerTest, FIFOToWarmWithHotBetweenWarms) {
ASSERT_EQ(fifo_compaction_picker.NeedsCompaction(vstorage_.get()), true); ASSERT_EQ(fifo_compaction_picker.NeedsCompaction(vstorage_.get()), true);
std::unique_ptr<Compaction> compaction(fifo_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(fifo_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
// Stop if a file is being compacted // Stop if a file is being compacted
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(1U, compaction->num_input_files(0)); ASSERT_EQ(1U, compaction->num_input_files(0));
@@ -1267,7 +1267,7 @@ TEST_F(CompactionPickerTest, CompactionPriMinOverlapping1) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(1U, compaction->num_input_files(0)); ASSERT_EQ(1U, compaction->num_input_files(0));
// Pick file 8 because it overlaps with 0 files on level 3. // Pick file 8 because it overlaps with 0 files on level 3.
@@ -1300,7 +1300,7 @@ TEST_F(CompactionPickerTest, CompactionPriMinOverlapping2) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(1U, compaction->num_input_files(0)); ASSERT_EQ(1U, compaction->num_input_files(0));
// Picking file 7 because overlapping ratio is the biggest. // Picking file 7 because overlapping ratio is the biggest.
@@ -1328,7 +1328,7 @@ TEST_F(CompactionPickerTest, CompactionPriMinOverlapping3) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(1U, compaction->num_input_files(0)); ASSERT_EQ(1U, compaction->num_input_files(0));
// Picking file 8 because overlapping ratio is the biggest. // Picking file 8 because overlapping ratio is the biggest.
@@ -1359,7 +1359,7 @@ TEST_F(CompactionPickerTest, CompactionPriMinOverlapping4) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(1U, compaction->num_input_files(0)); ASSERT_EQ(1U, compaction->num_input_files(0));
// Picking file 8 because overlapping ratio is the biggest. // Picking file 8 because overlapping ratio is the biggest.
@@ -1395,7 +1395,7 @@ TEST_F(CompactionPickerTest, CompactionPriRoundRobin) {
std::unique_ptr<Compaction> compaction( std::unique_ptr<Compaction> compaction(
local_level_compaction_picker.PickCompaction( local_level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
// Since the max bytes for level 2 is 120M, picking one file to compact // Since the max bytes for level 2 is 120M, picking one file to compact
// makes the post-compaction level size less than 120M, there is exactly one // makes the post-compaction level size less than 120M, there is exactly one
@@ -1435,7 +1435,7 @@ TEST_F(CompactionPickerTest, CompactionPriMultipleFilesRoundRobin1) {
std::unique_ptr<Compaction> compaction( std::unique_ptr<Compaction> compaction(
local_level_compaction_picker.PickCompaction( local_level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
// The maximum compaction bytes is very large in this case so we can igore its // The maximum compaction bytes is very large in this case so we can igore its
@@ -1478,7 +1478,7 @@ TEST_F(CompactionPickerTest, CompactionPriMultipleFilesRoundRobin2) {
std::unique_ptr<Compaction> compaction( std::unique_ptr<Compaction> compaction(
local_level_compaction_picker.PickCompaction( local_level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
// The maximum compaction bytes is only 2500 bytes now. Even though we are // The maximum compaction bytes is only 2500 bytes now. Even though we are
@@ -1522,7 +1522,7 @@ TEST_F(CompactionPickerTest, CompactionPriMultipleFilesRoundRobin3) {
std::unique_ptr<Compaction> compaction( std::unique_ptr<Compaction> compaction(
local_level_compaction_picker.PickCompaction( local_level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
// Cannot pick more files since we reach the last file in level 2 // Cannot pick more files since we reach the last file in level 2
@@ -1581,7 +1581,7 @@ TEST_F(CompactionPickerTest, CompactionPriMinOverlappingManyFiles) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(1U, compaction->num_input_files(0)); ASSERT_EQ(1U, compaction->num_input_files(0));
// Picking file 8 because overlapping ratio is the biggest. // Picking file 8 because overlapping ratio is the biggest.
@@ -1609,7 +1609,7 @@ TEST_F(CompactionPickerTest, ParentIndexResetBug) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
} }
// This test checks ExpandWhileOverlapping() by having overlapping user keys // This test checks ExpandWhileOverlapping() by having overlapping user keys
@@ -1627,7 +1627,7 @@ TEST_F(CompactionPickerTest, OverlappingUserKeys) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(1U, compaction->num_input_levels()); ASSERT_EQ(1U, compaction->num_input_levels());
ASSERT_EQ(2U, compaction->num_input_files(0)); ASSERT_EQ(2U, compaction->num_input_files(0));
@@ -1647,7 +1647,7 @@ TEST_F(CompactionPickerTest, OverlappingUserKeys2) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(2U, compaction->num_input_levels()); ASSERT_EQ(2U, compaction->num_input_levels());
ASSERT_EQ(2U, compaction->num_input_files(0)); ASSERT_EQ(2U, compaction->num_input_files(0));
@@ -1675,7 +1675,7 @@ TEST_F(CompactionPickerTest, OverlappingUserKeys3) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(2U, compaction->num_input_levels()); ASSERT_EQ(2U, compaction->num_input_levels());
ASSERT_EQ(5U, compaction->num_input_files(0)); ASSERT_EQ(5U, compaction->num_input_files(0));
@@ -1706,7 +1706,7 @@ TEST_F(CompactionPickerTest, OverlappingUserKeys4) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(2U, compaction->num_input_levels()); ASSERT_EQ(2U, compaction->num_input_levels());
ASSERT_EQ(1U, compaction->num_input_files(0)); ASSERT_EQ(1U, compaction->num_input_files(0));
@@ -1730,7 +1730,7 @@ TEST_F(CompactionPickerTest, OverlappingUserKeys5) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() == nullptr); ASSERT_TRUE(compaction.get() == nullptr);
} }
@@ -1752,7 +1752,7 @@ TEST_F(CompactionPickerTest, OverlappingUserKeys6) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(2U, compaction->num_input_levels()); ASSERT_EQ(2U, compaction->num_input_levels());
ASSERT_EQ(1U, compaction->num_input_files(0)); ASSERT_EQ(1U, compaction->num_input_files(0));
@@ -1773,7 +1773,7 @@ TEST_F(CompactionPickerTest, OverlappingUserKeys7) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(2U, compaction->num_input_levels()); ASSERT_EQ(2U, compaction->num_input_levels());
ASSERT_GE(1U, compaction->num_input_files(0)); ASSERT_GE(1U, compaction->num_input_files(0));
@@ -1802,7 +1802,7 @@ TEST_F(CompactionPickerTest, OverlappingUserKeys8) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(2U, compaction->num_input_levels()); ASSERT_EQ(2U, compaction->num_input_levels());
ASSERT_EQ(3U, compaction->num_input_files(0)); ASSERT_EQ(3U, compaction->num_input_files(0));
@@ -1835,7 +1835,7 @@ TEST_F(CompactionPickerTest, OverlappingUserKeys9) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(2U, compaction->num_input_levels()); ASSERT_EQ(2U, compaction->num_input_levels());
ASSERT_EQ(5U, compaction->num_input_files(0)); ASSERT_EQ(5U, compaction->num_input_files(0));
@@ -1876,7 +1876,7 @@ TEST_F(CompactionPickerTest, OverlappingUserKeys10) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(2U, compaction->num_input_levels()); ASSERT_EQ(2U, compaction->num_input_levels());
ASSERT_EQ(1U, compaction->num_input_files(0)); ASSERT_EQ(1U, compaction->num_input_files(0));
@@ -1915,7 +1915,7 @@ TEST_F(CompactionPickerTest, OverlappingUserKeys11) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(2U, compaction->num_input_levels()); ASSERT_EQ(2U, compaction->num_input_levels());
ASSERT_EQ(1U, compaction->num_input_files(0)); ASSERT_EQ(1U, compaction->num_input_files(0));
@@ -2013,7 +2013,7 @@ TEST_F(CompactionPickerTest, NotScheduleL1IfL0WithHigherPri1) {
ASSERT_EQ(1, vstorage_->CompactionScoreLevel(1)); ASSERT_EQ(1, vstorage_->CompactionScoreLevel(1));
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() == nullptr); ASSERT_TRUE(compaction.get() == nullptr);
} }
@@ -2044,7 +2044,7 @@ TEST_F(CompactionPickerTest, NotScheduleL1IfL0WithHigherPri2) {
ASSERT_EQ(1, vstorage_->CompactionScoreLevel(1)); ASSERT_EQ(1, vstorage_->CompactionScoreLevel(1));
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
} }
@@ -2078,7 +2078,7 @@ TEST_F(CompactionPickerTest, NotScheduleL1IfL0WithHigherPri3) {
ASSERT_EQ(0, vstorage_->CompactionScoreLevel(1)); ASSERT_EQ(0, vstorage_->CompactionScoreLevel(1));
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
} }
@@ -2374,7 +2374,7 @@ TEST_F(CompactionPickerTest, MaxCompactionBytesHit) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(2U, compaction->num_input_levels()); ASSERT_EQ(2U, compaction->num_input_levels());
ASSERT_EQ(1U, compaction->num_input_files(0)); ASSERT_EQ(1U, compaction->num_input_files(0));
@@ -2400,7 +2400,7 @@ TEST_F(CompactionPickerTest, MaxCompactionBytesNotHit) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(2U, compaction->num_input_levels()); ASSERT_EQ(2U, compaction->num_input_levels());
ASSERT_EQ(3U, compaction->num_input_files(0)); ASSERT_EQ(3U, compaction->num_input_files(0));
@@ -2430,7 +2430,7 @@ TEST_F(CompactionPickerTest, IsTrivialMoveOn) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_TRUE(compaction->IsTrivialMove()); ASSERT_TRUE(compaction->IsTrivialMove());
} }
@@ -2455,7 +2455,7 @@ TEST_F(CompactionPickerTest, L0TrivialMove1) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(1, compaction->num_input_levels()); ASSERT_EQ(1, compaction->num_input_levels());
ASSERT_EQ(2, compaction->num_input_files(0)); ASSERT_EQ(2, compaction->num_input_files(0));
@@ -2484,7 +2484,7 @@ TEST_F(CompactionPickerTest, L0TrivialMoveOneFile) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(1, compaction->num_input_levels()); ASSERT_EQ(1, compaction->num_input_levels());
ASSERT_EQ(1, compaction->num_input_files(0)); ASSERT_EQ(1, compaction->num_input_files(0));
@@ -2510,7 +2510,7 @@ TEST_F(CompactionPickerTest, L0TrivialMoveWholeL0) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(1, compaction->num_input_levels()); ASSERT_EQ(1, compaction->num_input_levels());
ASSERT_EQ(4, compaction->num_input_files(0)); ASSERT_EQ(4, compaction->num_input_files(0));
@@ -2541,7 +2541,7 @@ TEST_F(CompactionPickerTest, IsTrivialMoveOffSstPartitioned) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
// No trivial move, because partitioning is applied // No trivial move, because partitioning is applied
ASSERT_TRUE(!compaction->IsTrivialMove()); ASSERT_TRUE(!compaction->IsTrivialMove());
@@ -2564,7 +2564,7 @@ TEST_F(CompactionPickerTest, IsTrivialMoveOff) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_FALSE(compaction->IsTrivialMove()); ASSERT_FALSE(compaction->IsTrivialMove());
} }
@@ -2593,7 +2593,7 @@ TEST_F(CompactionPickerTest, TrivialMoveMultipleFiles1) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_TRUE(compaction->IsTrivialMove()); ASSERT_TRUE(compaction->IsTrivialMove());
ASSERT_EQ(1, compaction->num_input_levels()); ASSERT_EQ(1, compaction->num_input_levels());
@@ -2627,7 +2627,7 @@ TEST_F(CompactionPickerTest, TrivialMoveMultipleFiles2) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_TRUE(compaction->IsTrivialMove()); ASSERT_TRUE(compaction->IsTrivialMove());
ASSERT_EQ(1, compaction->num_input_levels()); ASSERT_EQ(1, compaction->num_input_levels());
@@ -2660,7 +2660,7 @@ TEST_F(CompactionPickerTest, TrivialMoveMultipleFiles3) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_TRUE(compaction->IsTrivialMove()); ASSERT_TRUE(compaction->IsTrivialMove());
ASSERT_EQ(1, compaction->num_input_levels()); ASSERT_EQ(1, compaction->num_input_levels());
@@ -2686,7 +2686,7 @@ TEST_F(CompactionPickerTest, TrivialMoveMultipleFiles4) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_TRUE(compaction->IsTrivialMove()); ASSERT_TRUE(compaction->IsTrivialMove());
ASSERT_EQ(1, compaction->num_input_levels()); ASSERT_EQ(1, compaction->num_input_levels());
@@ -2716,7 +2716,7 @@ TEST_F(CompactionPickerTest, TrivialMoveMultipleFiles5) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_TRUE(compaction->IsTrivialMove()); ASSERT_TRUE(compaction->IsTrivialMove());
ASSERT_EQ(1, compaction->num_input_levels()); ASSERT_EQ(1, compaction->num_input_levels());
@@ -2750,7 +2750,7 @@ TEST_F(CompactionPickerTest, TrivialMoveMultipleFiles6) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_TRUE(compaction->IsTrivialMove()); ASSERT_TRUE(compaction->IsTrivialMove());
ASSERT_EQ(1, compaction->num_input_levels()); ASSERT_EQ(1, compaction->num_input_levels());
@@ -2785,7 +2785,7 @@ TEST_F(CompactionPickerTest, CacheNextCompactionIndex) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(2U, compaction->num_input_levels()); ASSERT_EQ(2U, compaction->num_input_levels());
ASSERT_EQ(1U, compaction->num_input_files(0)); ASSERT_EQ(1U, compaction->num_input_files(0));
@@ -2795,7 +2795,7 @@ TEST_F(CompactionPickerTest, CacheNextCompactionIndex) {
compaction.reset(level_compaction_picker.PickCompaction( compaction.reset(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(2U, compaction->num_input_levels()); ASSERT_EQ(2U, compaction->num_input_levels());
ASSERT_EQ(1U, compaction->num_input_files(0)); ASSERT_EQ(1U, compaction->num_input_files(0));
@@ -2805,7 +2805,7 @@ TEST_F(CompactionPickerTest, CacheNextCompactionIndex) {
compaction.reset(level_compaction_picker.PickCompaction( compaction.reset(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() == nullptr); ASSERT_TRUE(compaction.get() == nullptr);
ASSERT_EQ(4, vstorage_->NextCompactionIndex(1 /* level */)); ASSERT_EQ(4, vstorage_->NextCompactionIndex(1 /* level */));
} }
@@ -2831,7 +2831,7 @@ TEST_F(CompactionPickerTest, IntraL0MaxCompactionBytesNotHit) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(1U, compaction->num_input_levels()); ASSERT_EQ(1U, compaction->num_input_levels());
ASSERT_EQ(5U, compaction->num_input_files(0)); ASSERT_EQ(5U, compaction->num_input_files(0));
@@ -2862,7 +2862,7 @@ TEST_F(CompactionPickerTest, IntraL0MaxCompactionBytesHit) {
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction( std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction.get() != nullptr); ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(1U, compaction->num_input_levels()); ASSERT_EQ(1U, compaction->num_input_levels());
ASSERT_EQ(4U, compaction->num_input_files(0)); ASSERT_EQ(4U, compaction->num_input_files(0));
@@ -2928,7 +2928,7 @@ TEST_F(CompactionPickerTest, UniversalMarkedCompactionFullOverlap) {
std::unique_ptr<Compaction> compaction( std::unique_ptr<Compaction> compaction(
universal_compaction_picker.PickCompaction( universal_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction); ASSERT_TRUE(compaction);
// Validate that its a compaction to reduce sorted runs // Validate that its a compaction to reduce sorted runs
@@ -2946,7 +2946,7 @@ TEST_F(CompactionPickerTest, UniversalMarkedCompactionFullOverlap) {
std::unique_ptr<Compaction> compaction2( std::unique_ptr<Compaction> compaction2(
universal_compaction_picker.PickCompaction( universal_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_FALSE(compaction2); ASSERT_FALSE(compaction2);
} }
@@ -2971,7 +2971,7 @@ TEST_F(CompactionPickerTest, UniversalMarkedCompactionFullOverlap2) {
std::unique_ptr<Compaction> compaction( std::unique_ptr<Compaction> compaction(
universal_compaction_picker.PickCompaction( universal_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction); ASSERT_TRUE(compaction);
// Validate that its a delete triggered compaction // Validate that its a delete triggered compaction
@@ -2990,7 +2990,7 @@ TEST_F(CompactionPickerTest, UniversalMarkedCompactionFullOverlap2) {
std::unique_ptr<Compaction> compaction2( std::unique_ptr<Compaction> compaction2(
universal_compaction_picker.PickCompaction( universal_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_FALSE(compaction2); ASSERT_FALSE(compaction2);
} }
@@ -3031,7 +3031,7 @@ TEST_F(CompactionPickerTest, UniversalMarkedCompactionStartOutputOverlap) {
std::unique_ptr<Compaction> compaction( std::unique_ptr<Compaction> compaction(
universal_compaction_picker.PickCompaction( universal_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction); ASSERT_TRUE(compaction);
// Validate that its a delete triggered compaction // Validate that its a delete triggered compaction
@@ -3062,7 +3062,7 @@ TEST_F(CompactionPickerTest, UniversalMarkedCompactionStartOutputOverlap) {
std::unique_ptr<Compaction> compaction2( std::unique_ptr<Compaction> compaction2(
universal_compaction_picker.PickCompaction( universal_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_FALSE(compaction2); ASSERT_FALSE(compaction2);
DeleteVersionStorage(); DeleteVersionStorage();
} }
@@ -3088,7 +3088,7 @@ TEST_F(CompactionPickerTest, UniversalMarkedL0NoOverlap) {
std::unique_ptr<Compaction> compaction( std::unique_ptr<Compaction> compaction(
universal_compaction_picker.PickCompaction( universal_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction); ASSERT_TRUE(compaction);
// Validate that its a delete triggered compaction // Validate that its a delete triggered compaction
@@ -3125,7 +3125,7 @@ TEST_F(CompactionPickerTest, UniversalMarkedL0WithOverlap) {
std::unique_ptr<Compaction> compaction( std::unique_ptr<Compaction> compaction(
universal_compaction_picker.PickCompaction( universal_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction); ASSERT_TRUE(compaction);
// Validate that its a delete triggered compaction // Validate that its a delete triggered compaction
@@ -3159,7 +3159,7 @@ TEST_F(CompactionPickerTest, UniversalMarkedL0Overlap2) {
std::unique_ptr<Compaction> compaction( std::unique_ptr<Compaction> compaction(
universal_compaction_picker.PickCompaction( universal_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction); ASSERT_TRUE(compaction);
// Validate that its a delete triggered compaction // Validate that its a delete triggered compaction
@@ -3180,7 +3180,7 @@ TEST_F(CompactionPickerTest, UniversalMarkedL0Overlap2) {
std::unique_ptr<Compaction> compaction2( std::unique_ptr<Compaction> compaction2(
universal_compaction_picker.PickCompaction( universal_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
ASSERT_TRUE(compaction2); ASSERT_TRUE(compaction2);
ASSERT_EQ(3U, compaction->num_input_files(0)); ASSERT_EQ(3U, compaction->num_input_files(0));
ASSERT_TRUE(file_map_[1].first->being_compacted); ASSERT_TRUE(file_map_[1].first->being_compacted);
@@ -3215,7 +3215,7 @@ TEST_F(CompactionPickerTest, UniversalMarkedManualCompaction) {
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
ColumnFamilyData::kCompactAllLevels, 6, CompactRangeOptions(), ColumnFamilyData::kCompactAllLevels, 6, CompactRangeOptions(),
nullptr, nullptr, &manual_end, &manual_conflict, nullptr, nullptr, &manual_end, &manual_conflict,
std::numeric_limits<uint64_t>::max(), "", kMaxSequenceNumber)); std::numeric_limits<uint64_t>::max(), ""));
ASSERT_TRUE(compaction); ASSERT_TRUE(compaction);
@@ -3256,7 +3256,7 @@ TEST_F(CompactionPickerTest, UniversalSizeAmpTierCompactionNonLastLevel) {
std::unique_ptr<Compaction> compaction( std::unique_ptr<Compaction> compaction(
universal_compaction_picker.PickCompaction( universal_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
// Make sure it's a size amp compaction and includes all files // Make sure it's a size amp compaction and includes all files
ASSERT_EQ(compaction->compaction_reason(), ASSERT_EQ(compaction->compaction_reason(),
@@ -3292,7 +3292,7 @@ TEST_F(CompactionPickerTest, UniversalSizeRatioTierCompactionLastLevel) {
std::unique_ptr<Compaction> compaction( std::unique_ptr<Compaction> compaction(
universal_compaction_picker.PickCompaction( universal_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
// Internally, size amp compaction is evaluated before size ratio compaction. // Internally, size amp compaction is evaluated before size ratio compaction.
// Here to make sure it's size ratio compaction instead of size amp // Here to make sure it's size ratio compaction instead of size amp
@@ -3329,7 +3329,7 @@ TEST_F(CompactionPickerTest, UniversalSizeAmpTierCompactionNotSuport) {
std::unique_ptr<Compaction> compaction( std::unique_ptr<Compaction> compaction(
universal_compaction_picker.PickCompaction( universal_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
// size amp compaction is still triggered even preclude_last_level is set // size amp compaction is still triggered even preclude_last_level is set
ASSERT_EQ(compaction->compaction_reason(), ASSERT_EQ(compaction->compaction_reason(),
@@ -3363,7 +3363,7 @@ TEST_F(CompactionPickerTest, UniversalSizeAmpTierCompactionLastLevel) {
std::unique_ptr<Compaction> compaction( std::unique_ptr<Compaction> compaction(
universal_compaction_picker.PickCompaction( universal_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
// It's a Size Amp compaction, but doesn't include the last level file and // It's a Size Amp compaction, but doesn't include the last level file and
// output to the penultimate level. // output to the penultimate level.
@@ -3471,7 +3471,7 @@ TEST_F(CompactionPickerU64TsTest, CannotTrivialMoveUniversal) {
std::unique_ptr<Compaction> compaction( std::unique_ptr<Compaction> compaction(
universal_compaction_picker.PickCompaction( universal_compaction_picker.PickCompaction(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
&log_buffer_, kMaxSequenceNumber)); &log_buffer_));
assert(compaction); assert(compaction);
ASSERT_TRUE(!compaction->is_trivial_move()); ASSERT_TRUE(!compaction->is_trivial_move());
} }
+1 -1
View File
@@ -293,7 +293,7 @@ bool UniversalCompactionPicker::NeedsCompaction(
Compaction* UniversalCompactionPicker::PickCompaction( Compaction* UniversalCompactionPicker::PickCompaction(
const std::string& cf_name, const MutableCFOptions& mutable_cf_options, const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
const MutableDBOptions& mutable_db_options, VersionStorageInfo* vstorage, const MutableDBOptions& mutable_db_options, VersionStorageInfo* vstorage,
LogBuffer* log_buffer, const SequenceNumber /* earliest_mem_seqno */) { LogBuffer* log_buffer, SequenceNumber /* earliest_memtable_seqno */) {
UniversalCompactionBuilder builder(ioptions_, icmp_, cf_name, UniversalCompactionBuilder builder(ioptions_, icmp_, cf_name,
mutable_cf_options, mutable_db_options, mutable_cf_options, mutable_db_options,
vstorage, this, log_buffer); vstorage, this, log_buffer);
+2 -1
View File
@@ -21,7 +21,8 @@ class UniversalCompactionPicker : public CompactionPicker {
virtual Compaction* PickCompaction( virtual Compaction* PickCompaction(
const std::string& cf_name, const MutableCFOptions& mutable_cf_options, const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
const MutableDBOptions& mutable_db_options, VersionStorageInfo* vstorage, const MutableDBOptions& mutable_db_options, VersionStorageInfo* vstorage,
LogBuffer* log_buffer, const SequenceNumber earliest_mem_seqno) override; LogBuffer* log_buffer,
SequenceNumber earliest_memtable_seqno = kMaxSequenceNumber) override;
virtual int MaxOutputLevel() const override { return NumberLevels() - 1; } virtual int MaxOutputLevel() const override { return NumberLevels() - 1; }
virtual bool NeedsCompaction( virtual bool NeedsCompaction(
+72 -5
View File
@@ -2158,11 +2158,11 @@ class DBMultiGetAsyncIOTest : public DBBasicTest,
: DBBasicTest(), statistics_(ROCKSDB_NAMESPACE::CreateDBStatistics()) { : DBBasicTest(), statistics_(ROCKSDB_NAMESPACE::CreateDBStatistics()) {
BlockBasedTableOptions bbto; BlockBasedTableOptions bbto;
bbto.filter_policy.reset(NewBloomFilterPolicy(10)); bbto.filter_policy.reset(NewBloomFilterPolicy(10));
Options options = CurrentOptions(); options_ = CurrentOptions();
options.disable_auto_compactions = true; options_.disable_auto_compactions = true;
options.statistics = statistics_; options_.statistics = statistics_;
options.table_factory.reset(NewBlockBasedTableFactory(bbto)); options_.table_factory.reset(NewBlockBasedTableFactory(bbto));
Reopen(options); Reopen(options_);
int num_keys = 0; int num_keys = 0;
// Put all keys in the bottommost level, and overwrite some keys // Put all keys in the bottommost level, and overwrite some keys
@@ -2227,8 +2227,12 @@ class DBMultiGetAsyncIOTest : public DBBasicTest,
const std::shared_ptr<Statistics>& statistics() { return statistics_; } const std::shared_ptr<Statistics>& statistics() { return statistics_; }
protected:
void ReopenDB() { Reopen(options_); }
private: private:
std::shared_ptr<Statistics> statistics_; std::shared_ptr<Statistics> statistics_;
Options options_;
}; };
TEST_P(DBMultiGetAsyncIOTest, GetFromL0) { TEST_P(DBMultiGetAsyncIOTest, GetFromL0) {
@@ -2305,6 +2309,69 @@ TEST_P(DBMultiGetAsyncIOTest, GetFromL1) {
ASSERT_EQ(statistics()->getTickerCount(MULTIGET_COROUTINE_COUNT), 3); ASSERT_EQ(statistics()->getTickerCount(MULTIGET_COROUTINE_COUNT), 3);
} }
TEST_P(DBMultiGetAsyncIOTest, GetFromL1Error) {
std::vector<std::string> key_strs;
std::vector<Slice> keys;
std::vector<PinnableSlice> values;
std::vector<Status> statuses;
key_strs.push_back(Key(33));
key_strs.push_back(Key(54));
key_strs.push_back(Key(102));
keys.push_back(key_strs[0]);
keys.push_back(key_strs[1]);
keys.push_back(key_strs[2]);
values.resize(keys.size());
statuses.resize(keys.size());
SyncPoint::GetInstance()->SetCallBack(
"TableCache::GetTableReader:BeforeOpenFile", [&](void* status) {
static int count = 0;
count++;
// Fail the last table reader open, which is the 6th SST file
// since 3 overlapping L0 files + 3 L1 files containing the keys
if (count == 6) {
Status* s = static_cast<Status*>(status);
*s = Status::IOError();
}
});
// DB open will create table readers unless we reduce the table cache
// capacity.
// SanitizeOptions will set max_open_files to minimum of 20. Table cache
// is allocated with max_open_files - 10 as capacity. So override
// max_open_files to 11 so table cache capacity will become 1. This will
// prevent file open during DB open and force the file to be opened
// during MultiGet
SyncPoint::GetInstance()->SetCallBack(
"SanitizeOptions::AfterChangeMaxOpenFiles", [&](void* arg) {
int* max_open_files = (int*)arg;
*max_open_files = 11;
});
SyncPoint::GetInstance()->EnableProcessing();
ReopenDB();
ReadOptions ro;
ro.async_io = true;
ro.optimize_multiget_for_io = GetParam();
dbfull()->MultiGet(ro, dbfull()->DefaultColumnFamily(), keys.size(),
keys.data(), values.data(), statuses.data());
SyncPoint::GetInstance()->DisableProcessing();
ASSERT_EQ(values.size(), 3);
ASSERT_EQ(statuses[0], Status::OK());
ASSERT_EQ(statuses[1], Status::OK());
ASSERT_EQ(statuses[2], Status::IOError());
HistogramData multiget_io_batch_size;
statistics()->histogramData(MULTIGET_IO_BATCH_SIZE, &multiget_io_batch_size);
// A batch of 3 async IOs is expected, one for each overlapping file in L1
ASSERT_EQ(multiget_io_batch_size.count, 1);
ASSERT_EQ(multiget_io_batch_size.max, 2);
ASSERT_EQ(statistics()->getTickerCount(MULTIGET_COROUTINE_COUNT), 2);
}
TEST_P(DBMultiGetAsyncIOTest, LastKeyInFile) { TEST_P(DBMultiGetAsyncIOTest, LastKeyInFile) {
std::vector<std::string> key_strs; std::vector<std::string> key_strs;
std::vector<Slice> keys; std::vector<Slice> keys;
+53 -164
View File
@@ -186,13 +186,6 @@ class RoundRobinSubcompactionsAgainstResources
int max_compaction_limits_; int max_compaction_limits_;
}; };
class DBCompactionTestFIFOCheckConsistencyWithParam
: public DBCompactionTest,
public testing::WithParamInterface<std::string> {
public:
DBCompactionTestFIFOCheckConsistencyWithParam() : DBCompactionTest() {}
};
namespace { namespace {
class FlushedFileCollector : public EventListener { class FlushedFileCollector : public EventListener {
public: public:
@@ -3526,6 +3519,59 @@ TEST_P(DBCompactionTestWithParam, FullCompactionInBottomPriThreadPool) {
Env::Default()->SetBackgroundThreads(0, Env::Priority::BOTTOM); Env::Default()->SetBackgroundThreads(0, Env::Priority::BOTTOM);
} }
TEST_F(DBCompactionTest, CancelCompactionWaitingOnConflict) {
// This test verifies cancellation of a compaction waiting to be scheduled due
// to conflict with a running compaction.
//
// A `CompactRange()` in universal compacts all files, waiting for files to
// become available if they are locked for another compaction. This test
// triggers an automatic compaction that blocks a `CompactRange()`, and
// verifies that `DisableManualCompaction()` can successfully cancel the
// `CompactRange()` without waiting for the automatic compaction to finish.
const int kNumSortedRuns = 4;
Options options = CurrentOptions();
options.compaction_style = kCompactionStyleUniversal;
options.level0_file_num_compaction_trigger = kNumSortedRuns;
options.memtable_factory.reset(
test::NewSpecialSkipListFactory(KNumKeysByGenerateNewFile - 1));
Reopen(options);
test::SleepingBackgroundTask auto_compaction_sleeping_task;
// Block automatic compaction when it runs in the callback
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"CompactionJob::Run():Start",
[&](void* /*arg*/) { auto_compaction_sleeping_task.DoSleep(); });
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
// Fill overlapping files in L0 to trigger an automatic compaction
Random rnd(301);
for (int i = 0; i < kNumSortedRuns; ++i) {
int key_idx = 0;
GenerateNewFile(&rnd, &key_idx, true /* nowait */);
}
auto_compaction_sleeping_task.WaitUntilSleeping();
// Make sure the manual compaction has seen the conflict before being canceled
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency(
{{"ColumnFamilyData::CompactRange:Return",
"DBCompactionTest::CancelCompactionWaitingOnConflict:"
"PreDisableManualCompaction"}});
auto manual_compaction_thread = port::Thread([this]() {
ASSERT_TRUE(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr)
.IsIncomplete());
});
// Cancel it. Thread should be joinable, i.e., manual compaction was unblocked
// despite finding a conflict with an automatic compaction that is still
// running
TEST_SYNC_POINT(
"DBCompactionTest::CancelCompactionWaitingOnConflict:"
"PreDisableManualCompaction");
db_->DisableManualCompaction();
manual_compaction_thread.join();
}
TEST_F(DBCompactionTest, OptimizedDeletionObsoleting) { TEST_F(DBCompactionTest, OptimizedDeletionObsoleting) {
// Deletions can be dropped when compacted to non-last level if they fall // Deletions can be dropped when compacted to non-last level if they fall
// outside the lower-level files' key-ranges. // outside the lower-level files' key-ranges.
@@ -6444,163 +6490,6 @@ TEST_P(DBCompactionTestWithParam,
} }
} }
INSTANTIATE_TEST_CASE_P(DBCompactionTestFIFOCheckConsistencyWithParam,
DBCompactionTestFIFOCheckConsistencyWithParam,
::testing::Values("FindIntraL0Compaction",
"PickCompactionToWarm",
"CompactRange", "CompactFile"));
TEST_P(DBCompactionTestFIFOCheckConsistencyWithParam,
FlushAfterIntraL0CompactionWithIngestedFile) {
Options options = CurrentOptions();
options.create_if_missing = true;
options.compression = kNoCompression;
options.force_consistency_checks = true;
options.compaction_style = kCompactionStyleFIFO;
options.max_open_files = -1;
options.num_levels = 1;
options.level0_file_num_compaction_trigger = 3;
CompactionOptionsFIFO fifo_options;
const std::string compaction_path_to_test = GetParam();
if (compaction_path_to_test == "FindIntraL0Compaction") {
fifo_options.allow_compaction = true;
fifo_options.age_for_warm = 0;
} else if (compaction_path_to_test == "PickCompactionToWarm") {
fifo_options.allow_compaction = false;
fifo_options.age_for_warm = 2;
} else if (compaction_path_to_test == "CompactRange") {
// FIFOCompactionPicker::CompactRange() implementes
// on top of regular compaction paths. Here we choose
// to trigger FIFOCompactionPicker::PickCompactionToWarm()
// for simplicity
fifo_options.allow_compaction = false;
fifo_options.age_for_warm = 2;
options.disable_auto_compactions = true;
} else if (compaction_path_to_test == "CompactFile") {
fifo_options.allow_compaction = false;
fifo_options.age_for_warm = 0;
options.disable_auto_compactions = true;
} else {
assert(false);
}
options.compaction_options_fifo = fifo_options;
DestroyAndReopen(options);
// To force assigning the global seqno to ingested file
// for our test purpose
const Snapshot* snapshot = db_->GetSnapshot();
std::atomic<bool> compaction_path_sync_point_called(false);
if (compaction_path_to_test == "FindIntraL0Compaction") {
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"FindIntraL0Compaction",
[&](void* /*arg*/) { compaction_path_sync_point_called.store(true); });
} else if (compaction_path_to_test == "PickCompactionToWarm" ||
compaction_path_to_test == "CompactRange") {
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"PickCompactionToWarm",
[&](void* /*arg*/) { compaction_path_sync_point_called.store(true); });
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"PickCompactionToWarm::BeforeGetCurrentTime",
[&fifo_options](void* current_time_arg) -> void {
// The unit test goes so quickly that there is almost no time
// elapsed after we ingest a file and before we check whether ingested
// files can compact to warm.
// Therefore we need this trick to simulate elapsed
// time in reality.
int64_t* current_time = (int64_t*)current_time_arg;
*current_time = *current_time + fifo_options.age_for_warm + 1;
});
} else if (compaction_path_to_test == "CompactFile") {
// Sync point is not needed in this case
compaction_path_sync_point_called.store(true);
}
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
// Create an existing SST file s0 of key range [key1,key4] and seqno range
// [1,2]
ASSERT_OK(Put("key1", "seq1"));
ASSERT_OK(Put("key4", "seq2"));
ASSERT_OK(Flush());
ASSERT_EQ(1, NumTableFilesAtLevel(0));
// Accumulate entries in a memtable m1 of key range [key1,key2] and seqno
// range [3,4] Noted that it contains a overlaped key with s0
ASSERT_OK(Put("key1", "seq3")); // overlapped key
ASSERT_OK(Put("key2", "seq4"));
ASSERT_TRUE(compaction_path_to_test == "CompactFile" ||
!compaction_path_sync_point_called.load());
// Stop background compaction job to obtain accurate
// `NumTableFilesAtLevel(0)` after file ingestion
test::SleepingBackgroundTask sleeping_tasks;
if (!options.disable_auto_compactions) {
env_->SetBackgroundThreads(1, Env::LOW);
env_->Schedule(&test::SleepingBackgroundTask::DoSleepTask, &sleeping_tasks,
Env::Priority::LOW);
sleeping_tasks.WaitUntilSleeping();
}
// Ingested two SST files, s1 of key range [key5,key5] and seqno range [5,5]
// and s2 of key range [key6,key6] and seqno range [6,6]
IngestOneKeyValue(dbfull(), "key5", "seq5", options);
IngestOneKeyValue(dbfull(), "key6", "seq6", options);
// Up to now, L0 contains s0, s1, s2
ASSERT_EQ(3, NumTableFilesAtLevel(0));
// Resume background compaction job so that Intra level0 compaction can be
// triggered
if (!options.disable_auto_compactions) {
sleeping_tasks.WakeUp();
sleeping_tasks.WaitUntilDone();
}
if (compaction_path_to_test == "CompactRange") {
// `start` and `end` is carefully chosen so that compact range:
// (1) doesn't overlap with memtable therefore the memtable won't be flushed
// (2) should target at compacting s0 with s1 and s2
Slice start("key4"), end("key6");
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), &start, &end));
} else if (compaction_path_to_test == "CompactFile") {
ColumnFamilyMetaData cf_meta_data;
db_->GetColumnFamilyMetaData(&cf_meta_data);
assert(cf_meta_data.levels[0].files.size() == 3);
std::vector<std::string> input_files;
for (const auto& file : cf_meta_data.levels[0].files) {
input_files.push_back(file.name);
}
Status s = db_->CompactFiles(CompactionOptions(), input_files, 0);
EXPECT_TRUE(s.IsAborted());
EXPECT_TRUE(s.ToString().find(
"has overlapping seqnos with earliest memtable seqnos") !=
std::string::npos);
} else {
ASSERT_OK(dbfull()->TEST_WaitForCompact());
}
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
ASSERT_TRUE(compaction_path_to_test == "CompactFile" ||
compaction_path_sync_point_called.load());
// To verify compaction of s0, s1 and s2 (leading to new SST s4) didn't
// happen.
//
// Otherwise, when m1 flushes in the next step and become s3,
// we will have s3 of seqnos [3, 4], s4 of seqnos [1, 6], which is a
// corruption because s3 is older than s4 based on largest seqno while s2
// contains a value of Key(1) newer than the value of Key(1) contained in s4.
// And in this case, Flush() will return Status::Corruption() caught by
// `force_consistency_checks=1`
EXPECT_EQ(3, NumTableFilesAtLevel(0));
EXPECT_OK(Flush());
db_->ReleaseSnapshot(snapshot);
}
TEST_P(DBCompactionTestWithBottommostParam, SequenceKeysManualCompaction) { TEST_P(DBCompactionTestWithBottommostParam, SequenceKeysManualCompaction) {
constexpr int kSstNum = 10; constexpr int kSstNum = 10;
Options options = CurrentOptions(); Options options = CurrentOptions();
+65 -4
View File
@@ -746,6 +746,64 @@ class TestFlushListener : public EventListener {
}; };
#endif // !ROCKSDB_LITE #endif // !ROCKSDB_LITE
// RocksDB lite does not support GetLiveFiles()
#ifndef ROCKSDB_LITE
TEST_F(DBFlushTest, FixFlushReasonRaceFromConcurrentFlushes) {
Options options = CurrentOptions();
options.atomic_flush = true;
options.disable_auto_compactions = true;
CreateAndReopenWithCF({"cf1"}, options);
for (int idx = 0; idx < 1; ++idx) {
ASSERT_OK(Put(0, Key(idx), std::string(1, 'v')));
ASSERT_OK(Put(1, Key(idx), std::string(1, 'v')));
}
// To coerce a manual flush happenning in the middle of GetLiveFiles's flush,
// we need to pause background flush thread and enable it later.
std::shared_ptr<test::SleepingBackgroundTask> sleeping_task =
std::make_shared<test::SleepingBackgroundTask>();
env_->SetBackgroundThreads(1, Env::HIGH);
env_->Schedule(&test::SleepingBackgroundTask::DoSleepTask,
sleeping_task.get(), Env::Priority::HIGH);
sleeping_task->WaitUntilSleeping();
// Coerce a manual flush happenning in the middle of GetLiveFiles's flush
bool get_live_files_paused_at_sync_point = false;
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"DBImpl::AtomicFlushMemTables:AfterScheduleFlush", [&](void* /* arg */) {
if (get_live_files_paused_at_sync_point) {
// To prevent non-GetLiveFiles() flush from pausing at this sync point
return;
}
get_live_files_paused_at_sync_point = true;
FlushOptions fo;
fo.wait = false;
fo.allow_write_stall = true;
ASSERT_OK(dbfull()->Flush(fo));
// Resume background flush thread so GetLiveFiles() can finish
sleeping_task->WakeUp();
sleeping_task->WaitUntilDone();
});
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
std::vector<std::string> files;
uint64_t manifest_file_size;
// Before the fix, a race condition on default cf's flush reason due to
// concurrent GetLiveFiles's flush and manual flush will fail
// an internal assertion.
// After the fix, such race condition is fixed and there is no assertion
// failure.
ASSERT_OK(db_->GetLiveFiles(files, &manifest_file_size, /*flush*/ true));
ASSERT_TRUE(get_live_files_paused_at_sync_point);
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks();
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
}
#endif // !ROCKSDB_LITE
TEST_F(DBFlushTest, MemPurgeBasic) { TEST_F(DBFlushTest, MemPurgeBasic) {
Options options = CurrentOptions(); Options options = CurrentOptions();
@@ -2440,7 +2498,9 @@ TEST_P(DBAtomicFlushTest, ManualFlushUnder2PC) {
options.atomic_flush = GetParam(); options.atomic_flush = GetParam();
// 64MB so that memtable flush won't be trigger by the small writes. // 64MB so that memtable flush won't be trigger by the small writes.
options.write_buffer_size = (static_cast<size_t>(64) << 20); options.write_buffer_size = (static_cast<size_t>(64) << 20);
auto flush_listener = std::make_shared<FlushCounterListener>();
flush_listener->expected_flush_reason = FlushReason::kManualFlush;
options.listeners.push_back(flush_listener);
// Destroy the DB to recreate as a TransactionDB. // Destroy the DB to recreate as a TransactionDB.
Close(); Close();
Destroy(options, true); Destroy(options, true);
@@ -2507,7 +2567,6 @@ TEST_P(DBAtomicFlushTest, ManualFlushUnder2PC) {
auto cfh = static_cast<ColumnFamilyHandleImpl*>(handles_[i]); auto cfh = static_cast<ColumnFamilyHandleImpl*>(handles_[i]);
ASSERT_EQ(0, cfh->cfd()->imm()->NumNotFlushed()); ASSERT_EQ(0, cfh->cfd()->imm()->NumNotFlushed());
ASSERT_TRUE(cfh->cfd()->mem()->IsEmpty()); ASSERT_TRUE(cfh->cfd()->mem()->IsEmpty());
ASSERT_EQ(cfh->cfd()->GetFlushReason(), FlushReason::kManualFlush);
} }
// The recovered min log number with prepared data should be non-zero. // The recovered min log number with prepared data should be non-zero.
@@ -2520,13 +2579,15 @@ TEST_P(DBAtomicFlushTest, ManualFlushUnder2PC) {
ASSERT_TRUE(db_impl->allow_2pc()); ASSERT_TRUE(db_impl->allow_2pc());
ASSERT_NE(db_impl->MinLogNumberToKeep(), 0); ASSERT_NE(db_impl->MinLogNumberToKeep(), 0);
} }
#endif // ROCKSDB_LITE
TEST_P(DBAtomicFlushTest, ManualAtomicFlush) { TEST_P(DBAtomicFlushTest, ManualAtomicFlush) {
Options options = CurrentOptions(); Options options = CurrentOptions();
options.create_if_missing = true; options.create_if_missing = true;
options.atomic_flush = GetParam(); options.atomic_flush = GetParam();
options.write_buffer_size = (static_cast<size_t>(64) << 20); options.write_buffer_size = (static_cast<size_t>(64) << 20);
auto flush_listener = std::make_shared<FlushCounterListener>();
flush_listener->expected_flush_reason = FlushReason::kManualFlush;
options.listeners.push_back(flush_listener);
CreateAndReopenWithCF({"pikachu", "eevee"}, options); CreateAndReopenWithCF({"pikachu", "eevee"}, options);
size_t num_cfs = handles_.size(); size_t num_cfs = handles_.size();
@@ -2551,11 +2612,11 @@ TEST_P(DBAtomicFlushTest, ManualAtomicFlush) {
for (size_t i = 0; i != num_cfs; ++i) { for (size_t i = 0; i != num_cfs; ++i) {
auto cfh = static_cast<ColumnFamilyHandleImpl*>(handles_[i]); auto cfh = static_cast<ColumnFamilyHandleImpl*>(handles_[i]);
ASSERT_EQ(cfh->cfd()->GetFlushReason(), FlushReason::kManualFlush);
ASSERT_EQ(0, cfh->cfd()->imm()->NumNotFlushed()); ASSERT_EQ(0, cfh->cfd()->imm()->NumNotFlushed());
ASSERT_TRUE(cfh->cfd()->mem()->IsEmpty()); ASSERT_TRUE(cfh->cfd()->mem()->IsEmpty());
} }
} }
#endif // ROCKSDB_LITE
TEST_P(DBAtomicFlushTest, PrecomputeMinLogNumberToKeepNon2PC) { TEST_P(DBAtomicFlushTest, PrecomputeMinLogNumberToKeepNon2PC) {
Options options = CurrentOptions(); Options options = CurrentOptions();
+3 -2
View File
@@ -604,7 +604,7 @@ Status DBImpl::CloseHelper() {
while (!flush_queue_.empty()) { while (!flush_queue_.empty()) {
const FlushRequest& flush_req = PopFirstFromFlushQueue(); const FlushRequest& flush_req = PopFirstFromFlushQueue();
for (const auto& iter : flush_req) { for (const auto& iter : flush_req.cfd_to_max_mem_id_to_persist) {
iter.first->UnrefAndTryDelete(); iter.first->UnrefAndTryDelete();
} }
} }
@@ -1823,7 +1823,8 @@ InternalIterator* DBImpl::NewInternalIterator(
MergeIteratorBuilder merge_iter_builder( MergeIteratorBuilder merge_iter_builder(
&cfd->internal_comparator(), arena, &cfd->internal_comparator(), arena,
!read_options.total_order_seek && !read_options.total_order_seek &&
super_version->mutable_cf_options.prefix_extractor != nullptr); super_version->mutable_cf_options.prefix_extractor != nullptr,
read_options.iterate_upper_bound);
// Collect iterator for mutable memtable // Collect iterator for mutable memtable
auto mem_iter = super_version->mem->NewIterator(read_options, arena); auto mem_iter = super_version->mem->NewIterator(read_options, arena);
Status s; Status s;
+25 -14
View File
@@ -16,6 +16,7 @@
#include <map> #include <map>
#include <set> #include <set>
#include <string> #include <string>
#include <unordered_map>
#include <utility> #include <utility>
#include <vector> #include <vector>
@@ -1383,7 +1384,7 @@ class DBImpl : public DB {
void NotifyOnFlushBegin(ColumnFamilyData* cfd, FileMetaData* file_meta, void NotifyOnFlushBegin(ColumnFamilyData* cfd, FileMetaData* file_meta,
const MutableCFOptions& mutable_cf_options, const MutableCFOptions& mutable_cf_options,
int job_id); int job_id, FlushReason flush_reason);
void NotifyOnFlushCompleted( void NotifyOnFlushCompleted(
ColumnFamilyData* cfd, const MutableCFOptions& mutable_cf_options, ColumnFamilyData* cfd, const MutableCFOptions& mutable_cf_options,
@@ -1675,12 +1676,17 @@ class DBImpl : public DB {
// Argument required by background flush thread. // Argument required by background flush thread.
struct BGFlushArg { struct BGFlushArg {
BGFlushArg() BGFlushArg()
: cfd_(nullptr), max_memtable_id_(0), superversion_context_(nullptr) {} : cfd_(nullptr),
max_memtable_id_(0),
superversion_context_(nullptr),
flush_reason_(FlushReason::kOthers) {}
BGFlushArg(ColumnFamilyData* cfd, uint64_t max_memtable_id, BGFlushArg(ColumnFamilyData* cfd, uint64_t max_memtable_id,
SuperVersionContext* superversion_context) SuperVersionContext* superversion_context,
FlushReason flush_reason)
: cfd_(cfd), : cfd_(cfd),
max_memtable_id_(max_memtable_id), max_memtable_id_(max_memtable_id),
superversion_context_(superversion_context) {} superversion_context_(superversion_context),
flush_reason_(flush_reason) {}
// Column family to flush. // Column family to flush.
ColumnFamilyData* cfd_; ColumnFamilyData* cfd_;
@@ -1691,6 +1697,7 @@ class DBImpl : public DB {
// installs a new superversion for the column family. This operation // installs a new superversion for the column family. This operation
// requires a SuperVersionContext object (currently embedded in JobContext). // requires a SuperVersionContext object (currently embedded in JobContext).
SuperVersionContext* superversion_context_; SuperVersionContext* superversion_context_;
FlushReason flush_reason_;
}; };
// Argument passed to flush thread. // Argument passed to flush thread.
@@ -1819,7 +1826,7 @@ class DBImpl : public DB {
// installs a new super version for the column family. // installs a new super version for the column family.
Status FlushMemTableToOutputFile( Status FlushMemTableToOutputFile(
ColumnFamilyData* cfd, const MutableCFOptions& mutable_cf_options, ColumnFamilyData* cfd, const MutableCFOptions& mutable_cf_options,
bool* madeProgress, JobContext* job_context, bool* madeProgress, JobContext* job_context, FlushReason flush_reason,
SuperVersionContext* superversion_context, SuperVersionContext* superversion_context,
std::vector<SequenceNumber>& snapshot_seqs, std::vector<SequenceNumber>& snapshot_seqs,
SequenceNumber earliest_write_conflict_snapshot, SequenceNumber earliest_write_conflict_snapshot,
@@ -2037,18 +2044,22 @@ class DBImpl : public DB {
void MaybeScheduleFlushOrCompaction(); void MaybeScheduleFlushOrCompaction();
// A flush request specifies the column families to flush as well as the struct FlushRequest {
// largest memtable id to persist for each column family. Once all the FlushReason flush_reason;
// memtables whose IDs are smaller than or equal to this per-column-family // A map from column family to flush to largest memtable id to persist for
// specified value, this flush request is considered to have completed its // each column family. Once all the memtables whose IDs are smaller than or
// work of flushing this column family. After completing the work for all // equal to this per-column-family specified value, this flush request is
// column families in this request, this flush is considered complete. // considered to have completed its work of flushing this column family.
using FlushRequest = std::vector<std::pair<ColumnFamilyData*, uint64_t>>; // After completing the work for all column families in this request, this
// flush is considered complete.
std::unordered_map<ColumnFamilyData*, uint64_t>
cfd_to_max_mem_id_to_persist;
};
void GenerateFlushRequest(const autovector<ColumnFamilyData*>& cfds, void GenerateFlushRequest(const autovector<ColumnFamilyData*>& cfds,
FlushRequest* req); FlushReason flush_reason, FlushRequest* req);
void SchedulePendingFlush(const FlushRequest& req, FlushReason flush_reason); void SchedulePendingFlush(const FlushRequest& req);
void SchedulePendingCompaction(ColumnFamilyData* cfd); void SchedulePendingCompaction(ColumnFamilyData* cfd);
void SchedulePendingPurge(std::string fname, std::string dir_to_sync, void SchedulePendingPurge(std::string fname, std::string dir_to_sync,
+79 -63
View File
@@ -155,7 +155,7 @@ IOStatus DBImpl::SyncClosedLogs(JobContext* job_context,
Status DBImpl::FlushMemTableToOutputFile( Status DBImpl::FlushMemTableToOutputFile(
ColumnFamilyData* cfd, const MutableCFOptions& mutable_cf_options, ColumnFamilyData* cfd, const MutableCFOptions& mutable_cf_options,
bool* made_progress, JobContext* job_context, bool* made_progress, JobContext* job_context, FlushReason flush_reason,
SuperVersionContext* superversion_context, SuperVersionContext* superversion_context,
std::vector<SequenceNumber>& snapshot_seqs, std::vector<SequenceNumber>& snapshot_seqs,
SequenceNumber earliest_write_conflict_snapshot, SequenceNumber earliest_write_conflict_snapshot,
@@ -215,7 +215,8 @@ Status DBImpl::FlushMemTableToOutputFile(
dbname_, cfd, immutable_db_options_, mutable_cf_options, max_memtable_id, dbname_, cfd, immutable_db_options_, mutable_cf_options, max_memtable_id,
file_options_for_compaction_, versions_.get(), &mutex_, &shutting_down_, file_options_for_compaction_, versions_.get(), &mutex_, &shutting_down_,
snapshot_seqs, earliest_write_conflict_snapshot, snapshot_checker, snapshot_seqs, earliest_write_conflict_snapshot, snapshot_checker,
job_context, log_buffer, directories_.GetDbDir(), GetDataDir(cfd, 0U), job_context, flush_reason, log_buffer, directories_.GetDbDir(),
GetDataDir(cfd, 0U),
GetCompressionFlush(*cfd->ioptions(), mutable_cf_options), stats_, GetCompressionFlush(*cfd->ioptions(), mutable_cf_options), stats_,
&event_logger_, mutable_cf_options.report_bg_io_stats, &event_logger_, mutable_cf_options.report_bg_io_stats,
true /* sync_output_directory */, true /* write_manifest */, thread_pri, true /* sync_output_directory */, true /* write_manifest */, thread_pri,
@@ -260,7 +261,8 @@ Status DBImpl::FlushMemTableToOutputFile(
#ifndef ROCKSDB_LITE #ifndef ROCKSDB_LITE
// may temporarily unlock and lock the mutex. // may temporarily unlock and lock the mutex.
NotifyOnFlushBegin(cfd, &file_meta, mutable_cf_options, job_context->job_id); NotifyOnFlushBegin(cfd, &file_meta, mutable_cf_options, job_context->job_id,
flush_reason);
#endif // ROCKSDB_LITE #endif // ROCKSDB_LITE
bool switched_to_mempurge = false; bool switched_to_mempurge = false;
@@ -390,8 +392,9 @@ Status DBImpl::FlushMemTablesToOutputFiles(
MutableCFOptions mutable_cf_options_copy = *cfd->GetLatestMutableCFOptions(); MutableCFOptions mutable_cf_options_copy = *cfd->GetLatestMutableCFOptions();
SuperVersionContext* superversion_context = SuperVersionContext* superversion_context =
bg_flush_arg.superversion_context_; bg_flush_arg.superversion_context_;
FlushReason flush_reason = bg_flush_arg.flush_reason_;
Status s = FlushMemTableToOutputFile( Status s = FlushMemTableToOutputFile(
cfd, mutable_cf_options_copy, made_progress, job_context, cfd, mutable_cf_options_copy, made_progress, job_context, flush_reason,
superversion_context, snapshot_seqs, earliest_write_conflict_snapshot, superversion_context, snapshot_seqs, earliest_write_conflict_snapshot,
snapshot_checker, log_buffer, thread_pri); snapshot_checker, log_buffer, thread_pri);
return s; return s;
@@ -420,7 +423,9 @@ Status DBImpl::AtomicFlushMemTablesToOutputFiles(
for (const auto cfd : cfds) { for (const auto cfd : cfds) {
assert(cfd->imm()->NumNotFlushed() != 0); assert(cfd->imm()->NumNotFlushed() != 0);
assert(cfd->imm()->IsFlushPending()); assert(cfd->imm()->IsFlushPending());
assert(cfd->GetFlushReason() == cfds[0]->GetFlushReason()); }
for (const auto bg_flush_arg : bg_flush_args) {
assert(bg_flush_arg.flush_reason_ == bg_flush_args[0].flush_reason_);
} }
#endif /* !NDEBUG */ #endif /* !NDEBUG */
@@ -459,13 +464,15 @@ Status DBImpl::AtomicFlushMemTablesToOutputFiles(
all_mutable_cf_options.emplace_back(*cfd->GetLatestMutableCFOptions()); all_mutable_cf_options.emplace_back(*cfd->GetLatestMutableCFOptions());
const MutableCFOptions& mutable_cf_options = all_mutable_cf_options.back(); const MutableCFOptions& mutable_cf_options = all_mutable_cf_options.back();
uint64_t max_memtable_id = bg_flush_args[i].max_memtable_id_; uint64_t max_memtable_id = bg_flush_args[i].max_memtable_id_;
FlushReason flush_reason = bg_flush_args[i].flush_reason_;
jobs.emplace_back(new FlushJob( jobs.emplace_back(new FlushJob(
dbname_, cfd, immutable_db_options_, mutable_cf_options, dbname_, cfd, immutable_db_options_, mutable_cf_options,
max_memtable_id, file_options_for_compaction_, versions_.get(), &mutex_, max_memtable_id, file_options_for_compaction_, versions_.get(), &mutex_,
&shutting_down_, snapshot_seqs, earliest_write_conflict_snapshot, &shutting_down_, snapshot_seqs, earliest_write_conflict_snapshot,
snapshot_checker, job_context, log_buffer, directories_.GetDbDir(), snapshot_checker, job_context, flush_reason, log_buffer,
data_dir, GetCompressionFlush(*cfd->ioptions(), mutable_cf_options), directories_.GetDbDir(), data_dir,
stats_, &event_logger_, mutable_cf_options.report_bg_io_stats, GetCompressionFlush(*cfd->ioptions(), mutable_cf_options), stats_,
&event_logger_, mutable_cf_options.report_bg_io_stats,
false /* sync_output_directory */, false /* write_manifest */, false /* sync_output_directory */, false /* write_manifest */,
thread_pri, io_tracer_, seqno_time_mapping_, db_id_, db_session_id_, thread_pri, io_tracer_, seqno_time_mapping_, db_id_, db_session_id_,
cfd->GetFullHistoryTsLow(), &blob_callback_)); cfd->GetFullHistoryTsLow(), &blob_callback_));
@@ -483,8 +490,9 @@ Status DBImpl::AtomicFlushMemTablesToOutputFiles(
for (int i = 0; i != num_cfs; ++i) { for (int i = 0; i != num_cfs; ++i) {
const MutableCFOptions& mutable_cf_options = all_mutable_cf_options.at(i); const MutableCFOptions& mutable_cf_options = all_mutable_cf_options.at(i);
// may temporarily unlock and lock the mutex. // may temporarily unlock and lock the mutex.
FlushReason flush_reason = bg_flush_args[i].flush_reason_;
NotifyOnFlushBegin(cfds[i], &file_meta[i], mutable_cf_options, NotifyOnFlushBegin(cfds[i], &file_meta[i], mutable_cf_options,
job_context->job_id); job_context->job_id, flush_reason);
} }
#endif /* !ROCKSDB_LITE */ #endif /* !ROCKSDB_LITE */
@@ -642,8 +650,9 @@ Status DBImpl::AtomicFlushMemTablesToOutputFiles(
bool resuming_from_bg_err = bool resuming_from_bg_err =
error_handler_.IsDBStopped() || error_handler_.IsDBStopped() ||
(cfds[0]->GetFlushReason() == FlushReason::kErrorRecovery || (bg_flush_args[0].flush_reason_ == FlushReason::kErrorRecovery ||
cfds[0]->GetFlushReason() == FlushReason::kErrorRecoveryRetryFlush); bg_flush_args[0].flush_reason_ ==
FlushReason::kErrorRecoveryRetryFlush);
while ((!resuming_from_bg_err || error_handler_.GetRecoveryError().ok())) { while ((!resuming_from_bg_err || error_handler_.GetRecoveryError().ok())) {
std::pair<Status, bool> res = wait_to_install_func(); std::pair<Status, bool> res = wait_to_install_func();
@@ -660,8 +669,9 @@ Status DBImpl::AtomicFlushMemTablesToOutputFiles(
resuming_from_bg_err = resuming_from_bg_err =
error_handler_.IsDBStopped() || error_handler_.IsDBStopped() ||
(cfds[0]->GetFlushReason() == FlushReason::kErrorRecovery || (bg_flush_args[0].flush_reason_ == FlushReason::kErrorRecovery ||
cfds[0]->GetFlushReason() == FlushReason::kErrorRecoveryRetryFlush); bg_flush_args[0].flush_reason_ ==
FlushReason::kErrorRecoveryRetryFlush);
} }
if (!resuming_from_bg_err) { if (!resuming_from_bg_err) {
@@ -816,7 +826,7 @@ Status DBImpl::AtomicFlushMemTablesToOutputFiles(
void DBImpl::NotifyOnFlushBegin(ColumnFamilyData* cfd, FileMetaData* file_meta, void DBImpl::NotifyOnFlushBegin(ColumnFamilyData* cfd, FileMetaData* file_meta,
const MutableCFOptions& mutable_cf_options, const MutableCFOptions& mutable_cf_options,
int job_id) { int job_id, FlushReason flush_reason) {
#ifndef ROCKSDB_LITE #ifndef ROCKSDB_LITE
if (immutable_db_options_.listeners.size() == 0U) { if (immutable_db_options_.listeners.size() == 0U) {
return; return;
@@ -849,7 +859,7 @@ void DBImpl::NotifyOnFlushBegin(ColumnFamilyData* cfd, FileMetaData* file_meta,
info.triggered_writes_stop = triggered_writes_stop; info.triggered_writes_stop = triggered_writes_stop;
info.smallest_seqno = file_meta->fd.smallest_seqno; info.smallest_seqno = file_meta->fd.smallest_seqno;
info.largest_seqno = file_meta->fd.largest_seqno; info.largest_seqno = file_meta->fd.largest_seqno;
info.flush_reason = cfd->GetFlushReason(); info.flush_reason = flush_reason;
for (auto listener : immutable_db_options_.listeners) { for (auto listener : immutable_db_options_.listeners) {
listener->OnFlushBegin(this, info); listener->OnFlushBegin(this, info);
} }
@@ -862,6 +872,7 @@ void DBImpl::NotifyOnFlushBegin(ColumnFamilyData* cfd, FileMetaData* file_meta,
(void)file_meta; (void)file_meta;
(void)mutable_cf_options; (void)mutable_cf_options;
(void)job_id; (void)job_id;
(void)flush_reason;
#endif // ROCKSDB_LITE #endif // ROCKSDB_LITE
} }
@@ -1344,18 +1355,8 @@ Status DBImpl::CompactFilesImpl(
} }
} }
SequenceNumber earliest_mem_seqno = kMaxSequenceNumber;
if (cfd->mem() != nullptr) {
earliest_mem_seqno =
std::min(cfd->mem()->GetEarliestSequenceNumber(), earliest_mem_seqno);
}
if (cfd->imm() != nullptr && cfd->imm()->current() != nullptr) {
earliest_mem_seqno =
std::min(cfd->imm()->current()->GetEarliestSequenceNumber(false),
earliest_mem_seqno);
}
Status s = cfd->compaction_picker()->SanitizeCompactionInputFiles( Status s = cfd->compaction_picker()->SanitizeCompactionInputFiles(
&input_set, cf_meta, output_level, earliest_mem_seqno); &input_set, cf_meta, output_level);
if (!s.ok()) { if (!s.ok()) {
return s; return s;
} }
@@ -1929,11 +1930,19 @@ Status DBImpl::RunManualCompaction(
manual.begin, manual.end, &manual.manual_end, &manual_conflict, manual.begin, manual.end, &manual.manual_end, &manual_conflict,
max_file_num_to_ignore, trim_ts)) == nullptr && max_file_num_to_ignore, trim_ts)) == nullptr &&
manual_conflict))) { manual_conflict))) {
// exclusive manual compactions should not see a conflict during if (!scheduled) {
// CompactRange // There is a conflicting compaction
assert(!exclusive || !manual_conflict); if (manual_compaction_paused_ > 0 || manual.canceled == true) {
// Running either this or some other manual compaction // Stop waiting since it was canceled. Pretend the error came from
bg_cv_.Wait(); // compaction so the below cleanup/error handling code can process it.
manual.done = true;
manual.status =
Status::Incomplete(Status::SubCode::kManualCompactionPaused);
}
}
if (!manual.done) {
bg_cv_.Wait();
}
if (manual_compaction_paused_ > 0 && scheduled && !unscheduled) { if (manual_compaction_paused_ > 0 && scheduled && !unscheduled) {
assert(thread_pool_priority != Env::Priority::TOTAL); assert(thread_pool_priority != Env::Priority::TOTAL);
// unschedule all manual compactions // unschedule all manual compactions
@@ -2011,16 +2020,17 @@ Status DBImpl::RunManualCompaction(
} }
void DBImpl::GenerateFlushRequest(const autovector<ColumnFamilyData*>& cfds, void DBImpl::GenerateFlushRequest(const autovector<ColumnFamilyData*>& cfds,
FlushRequest* req) { FlushReason flush_reason, FlushRequest* req) {
assert(req != nullptr); assert(req != nullptr);
req->reserve(cfds.size()); req->flush_reason = flush_reason;
req->cfd_to_max_mem_id_to_persist.reserve(cfds.size());
for (const auto cfd : cfds) { for (const auto cfd : cfds) {
if (nullptr == cfd) { if (nullptr == cfd) {
// cfd may be null, see DBImpl::ScheduleFlushes // cfd may be null, see DBImpl::ScheduleFlushes
continue; continue;
} }
uint64_t max_memtable_id = cfd->imm()->GetLatestMemTableID(); uint64_t max_memtable_id = cfd->imm()->GetLatestMemTableID();
req->emplace_back(cfd, max_memtable_id); req->cfd_to_max_mem_id_to_persist.emplace(cfd, max_memtable_id);
} }
} }
@@ -2078,7 +2088,7 @@ Status DBImpl::FlushMemTable(ColumnFamilyData* cfd,
if (s.ok()) { if (s.ok()) {
if (cfd->imm()->NumNotFlushed() != 0 || !cfd->mem()->IsEmpty() || if (cfd->imm()->NumNotFlushed() != 0 || !cfd->mem()->IsEmpty() ||
!cached_recoverable_state_empty_.load()) { !cached_recoverable_state_empty_.load()) {
FlushRequest req{{cfd, flush_memtable_id}}; FlushRequest req{flush_reason, {{cfd, flush_memtable_id}}};
flush_reqs.emplace_back(std::move(req)); flush_reqs.emplace_back(std::move(req));
memtable_ids_to_wait.emplace_back(cfd->imm()->GetLatestMemTableID()); memtable_ids_to_wait.emplace_back(cfd->imm()->GetLatestMemTableID());
} }
@@ -2106,7 +2116,7 @@ Status DBImpl::FlushMemTable(ColumnFamilyData* cfd,
"to avoid holding old logs", "to avoid holding old logs",
cfd->GetName().c_str()); cfd->GetName().c_str());
s = SwitchMemtable(cfd_stats, &context); s = SwitchMemtable(cfd_stats, &context);
FlushRequest req{{cfd_stats, flush_memtable_id}}; FlushRequest req{flush_reason, {{cfd_stats, flush_memtable_id}}};
flush_reqs.emplace_back(std::move(req)); flush_reqs.emplace_back(std::move(req));
memtable_ids_to_wait.emplace_back( memtable_ids_to_wait.emplace_back(
cfd->imm()->GetLatestMemTableID()); cfd->imm()->GetLatestMemTableID());
@@ -2117,8 +2127,9 @@ Status DBImpl::FlushMemTable(ColumnFamilyData* cfd,
if (s.ok() && !flush_reqs.empty()) { if (s.ok() && !flush_reqs.empty()) {
for (const auto& req : flush_reqs) { for (const auto& req : flush_reqs) {
assert(req.size() == 1); assert(req.cfd_to_max_mem_id_to_persist.size() == 1);
ColumnFamilyData* loop_cfd = req[0].first; ColumnFamilyData* loop_cfd =
req.cfd_to_max_mem_id_to_persist.begin()->first;
loop_cfd->imm()->FlushRequested(); loop_cfd->imm()->FlushRequested();
} }
// If the caller wants to wait for this flush to complete, it indicates // If the caller wants to wait for this flush to complete, it indicates
@@ -2127,13 +2138,14 @@ Status DBImpl::FlushMemTable(ColumnFamilyData* cfd,
// Therefore, we increase the cfd's ref count. // Therefore, we increase the cfd's ref count.
if (flush_options.wait) { if (flush_options.wait) {
for (const auto& req : flush_reqs) { for (const auto& req : flush_reqs) {
assert(req.size() == 1); assert(req.cfd_to_max_mem_id_to_persist.size() == 1);
ColumnFamilyData* loop_cfd = req[0].first; ColumnFamilyData* loop_cfd =
req.cfd_to_max_mem_id_to_persist.begin()->first;
loop_cfd->Ref(); loop_cfd->Ref();
} }
} }
for (const auto& req : flush_reqs) { for (const auto& req : flush_reqs) {
SchedulePendingFlush(req, flush_reason); SchedulePendingFlush(req);
} }
MaybeScheduleFlushOrCompaction(); MaybeScheduleFlushOrCompaction();
} }
@@ -2152,8 +2164,8 @@ Status DBImpl::FlushMemTable(ColumnFamilyData* cfd,
autovector<const uint64_t*> flush_memtable_ids; autovector<const uint64_t*> flush_memtable_ids;
assert(flush_reqs.size() == memtable_ids_to_wait.size()); assert(flush_reqs.size() == memtable_ids_to_wait.size());
for (size_t i = 0; i < flush_reqs.size(); ++i) { for (size_t i = 0; i < flush_reqs.size(); ++i) {
assert(flush_reqs[i].size() == 1); assert(flush_reqs[i].cfd_to_max_mem_id_to_persist.size() == 1);
cfds.push_back(flush_reqs[i][0].first); cfds.push_back(flush_reqs[i].cfd_to_max_mem_id_to_persist.begin()->first);
flush_memtable_ids.push_back(&(memtable_ids_to_wait[i])); flush_memtable_ids.push_back(&(memtable_ids_to_wait[i]));
} }
s = WaitForFlushMemTables( s = WaitForFlushMemTables(
@@ -2250,8 +2262,8 @@ Status DBImpl::AtomicFlushMemTables(
cfd->Ref(); cfd->Ref();
} }
} }
GenerateFlushRequest(cfds, &flush_req); GenerateFlushRequest(cfds, flush_reason, &flush_req);
SchedulePendingFlush(flush_req, flush_reason); SchedulePendingFlush(flush_req);
MaybeScheduleFlushOrCompaction(); MaybeScheduleFlushOrCompaction();
} }
@@ -2266,7 +2278,7 @@ Status DBImpl::AtomicFlushMemTables(
TEST_SYNC_POINT("DBImpl::AtomicFlushMemTables:BeforeWaitForBgFlush"); TEST_SYNC_POINT("DBImpl::AtomicFlushMemTables:BeforeWaitForBgFlush");
if (s.ok() && flush_options.wait) { if (s.ok() && flush_options.wait) {
autovector<const uint64_t*> flush_memtable_ids; autovector<const uint64_t*> flush_memtable_ids;
for (auto& iter : flush_req) { for (auto& iter : flush_req.cfd_to_max_mem_id_to_persist) {
flush_memtable_ids.push_back(&(iter.second)); flush_memtable_ids.push_back(&(iter.second));
} }
s = WaitForFlushMemTables( s = WaitForFlushMemTables(
@@ -2613,9 +2625,9 @@ DBImpl::FlushRequest DBImpl::PopFirstFromFlushQueue() {
FlushRequest flush_req = flush_queue_.front(); FlushRequest flush_req = flush_queue_.front();
flush_queue_.pop_front(); flush_queue_.pop_front();
if (!immutable_db_options_.atomic_flush) { if (!immutable_db_options_.atomic_flush) {
assert(flush_req.size() == 1); assert(flush_req.cfd_to_max_mem_id_to_persist.size() == 1);
} }
for (const auto& elem : flush_req) { for (const auto& elem : flush_req.cfd_to_max_mem_id_to_persist) {
if (!immutable_db_options_.atomic_flush) { if (!immutable_db_options_.atomic_flush) {
ColumnFamilyData* cfd = elem.first; ColumnFamilyData* cfd = elem.first;
assert(cfd); assert(cfd);
@@ -2623,7 +2635,6 @@ DBImpl::FlushRequest DBImpl::PopFirstFromFlushQueue() {
cfd->set_queued_for_flush(false); cfd->set_queued_for_flush(false);
} }
} }
// TODO: need to unset flush reason?
return flush_req; return flush_req;
} }
@@ -2653,31 +2664,29 @@ ColumnFamilyData* DBImpl::PickCompactionFromQueue(
return cfd; return cfd;
} }
void DBImpl::SchedulePendingFlush(const FlushRequest& flush_req, void DBImpl::SchedulePendingFlush(const FlushRequest& flush_req) {
FlushReason flush_reason) {
mutex_.AssertHeld(); mutex_.AssertHeld();
if (flush_req.empty()) { if (flush_req.cfd_to_max_mem_id_to_persist.empty()) {
return; return;
} }
if (!immutable_db_options_.atomic_flush) { if (!immutable_db_options_.atomic_flush) {
// For the non-atomic flush case, we never schedule multiple column // For the non-atomic flush case, we never schedule multiple column
// families in the same flush request. // families in the same flush request.
assert(flush_req.size() == 1); assert(flush_req.cfd_to_max_mem_id_to_persist.size() == 1);
ColumnFamilyData* cfd = flush_req[0].first; ColumnFamilyData* cfd =
flush_req.cfd_to_max_mem_id_to_persist.begin()->first;
assert(cfd); assert(cfd);
if (!cfd->queued_for_flush() && cfd->imm()->IsFlushPending()) { if (!cfd->queued_for_flush() && cfd->imm()->IsFlushPending()) {
cfd->Ref(); cfd->Ref();
cfd->set_queued_for_flush(true); cfd->set_queued_for_flush(true);
cfd->SetFlushReason(flush_reason);
++unscheduled_flushes_; ++unscheduled_flushes_;
flush_queue_.push_back(flush_req); flush_queue_.push_back(flush_req);
} }
} else { } else {
for (auto& iter : flush_req) { for (auto& iter : flush_req.cfd_to_max_mem_id_to_persist) {
ColumnFamilyData* cfd = iter.first; ColumnFamilyData* cfd = iter.first;
cfd->Ref(); cfd->Ref();
cfd->SetFlushReason(flush_reason);
} }
++unscheduled_flushes_; ++unscheduled_flushes_;
flush_queue_.push_back(flush_req); flush_queue_.push_back(flush_req);
@@ -2809,10 +2818,12 @@ Status DBImpl::BackgroundFlush(bool* made_progress, JobContext* job_context,
while (!flush_queue_.empty()) { while (!flush_queue_.empty()) {
// This cfd is already referenced // This cfd is already referenced
const FlushRequest& flush_req = PopFirstFromFlushQueue(); const FlushRequest& flush_req = PopFirstFromFlushQueue();
FlushReason flush_reason = flush_req.flush_reason;
superversion_contexts.clear(); superversion_contexts.clear();
superversion_contexts.reserve(flush_req.size()); superversion_contexts.reserve(
flush_req.cfd_to_max_mem_id_to_persist.size());
for (const auto& iter : flush_req) { for (const auto& iter : flush_req.cfd_to_max_mem_id_to_persist) {
ColumnFamilyData* cfd = iter.first; ColumnFamilyData* cfd = iter.first;
if (cfd->GetMempurgeUsed()) { if (cfd->GetMempurgeUsed()) {
// If imm() contains silent memtables (e.g.: because // If imm() contains silent memtables (e.g.: because
@@ -2828,7 +2839,7 @@ Status DBImpl::BackgroundFlush(bool* made_progress, JobContext* job_context,
} }
superversion_contexts.emplace_back(SuperVersionContext(true)); superversion_contexts.emplace_back(SuperVersionContext(true));
bg_flush_args.emplace_back(cfd, iter.second, bg_flush_args.emplace_back(cfd, iter.second,
&(superversion_contexts.back())); &(superversion_contexts.back()), flush_reason);
} }
if (!bg_flush_args.empty()) { if (!bg_flush_args.empty()) {
break; break;
@@ -2852,9 +2863,14 @@ Status DBImpl::BackgroundFlush(bool* made_progress, JobContext* job_context,
status = FlushMemTablesToOutputFiles(bg_flush_args, made_progress, status = FlushMemTablesToOutputFiles(bg_flush_args, made_progress,
job_context, log_buffer, thread_pri); job_context, log_buffer, thread_pri);
TEST_SYNC_POINT("DBImpl::BackgroundFlush:BeforeFlush"); TEST_SYNC_POINT("DBImpl::BackgroundFlush:BeforeFlush");
// All the CFDs in the FlushReq must have the same flush reason, so just // All the CFD/bg_flush_arg in the FlushReq must have the same flush reason, so
// grab the first one // just grab the first one
*reason = bg_flush_args[0].cfd_->GetFlushReason(); #ifndef NDEBUG
for (const auto bg_flush_arg : bg_flush_args) {
assert(bg_flush_arg.flush_reason_ == bg_flush_args[0].flush_reason_);
}
#endif /* !NDEBUG */
*reason = bg_flush_args[0].flush_reason_;
for (auto& arg : bg_flush_args) { for (auto& arg : bg_flush_args) {
ColumnFamilyData* cfd = arg.cfd_; ColumnFamilyData* cfd = arg.cfd_;
if (cfd->UnrefAndTryDelete()) { if (cfd->UnrefAndTryDelete()) {
+13 -12
View File
@@ -1644,14 +1644,14 @@ Status DBImpl::SwitchWAL(WriteContext* write_context) {
cfd->imm()->FlushRequested(); cfd->imm()->FlushRequested();
if (!immutable_db_options_.atomic_flush) { if (!immutable_db_options_.atomic_flush) {
FlushRequest flush_req; FlushRequest flush_req;
GenerateFlushRequest({cfd}, &flush_req); GenerateFlushRequest({cfd}, FlushReason::kWalFull, &flush_req);
SchedulePendingFlush(flush_req, FlushReason::kWalFull); SchedulePendingFlush(flush_req);
} }
} }
if (immutable_db_options_.atomic_flush) { if (immutable_db_options_.atomic_flush) {
FlushRequest flush_req; FlushRequest flush_req;
GenerateFlushRequest(cfds, &flush_req); GenerateFlushRequest(cfds, FlushReason::kWalFull, &flush_req);
SchedulePendingFlush(flush_req, FlushReason::kWalFull); SchedulePendingFlush(flush_req);
} }
MaybeScheduleFlushOrCompaction(); MaybeScheduleFlushOrCompaction();
} }
@@ -1735,14 +1735,15 @@ Status DBImpl::HandleWriteBufferManagerFlush(WriteContext* write_context) {
cfd->imm()->FlushRequested(); cfd->imm()->FlushRequested();
if (!immutable_db_options_.atomic_flush) { if (!immutable_db_options_.atomic_flush) {
FlushRequest flush_req; FlushRequest flush_req;
GenerateFlushRequest({cfd}, &flush_req); GenerateFlushRequest({cfd}, FlushReason::kWriteBufferManager,
SchedulePendingFlush(flush_req, FlushReason::kWriteBufferManager); &flush_req);
SchedulePendingFlush(flush_req);
} }
} }
if (immutable_db_options_.atomic_flush) { if (immutable_db_options_.atomic_flush) {
FlushRequest flush_req; FlushRequest flush_req;
GenerateFlushRequest(cfds, &flush_req); GenerateFlushRequest(cfds, FlushReason::kWriteBufferManager, &flush_req);
SchedulePendingFlush(flush_req, FlushReason::kWriteBufferManager); SchedulePendingFlush(flush_req);
} }
MaybeScheduleFlushOrCompaction(); MaybeScheduleFlushOrCompaction();
} }
@@ -1998,13 +1999,13 @@ Status DBImpl::ScheduleFlushes(WriteContext* context) {
if (immutable_db_options_.atomic_flush) { if (immutable_db_options_.atomic_flush) {
AssignAtomicFlushSeq(cfds); AssignAtomicFlushSeq(cfds);
FlushRequest flush_req; FlushRequest flush_req;
GenerateFlushRequest(cfds, &flush_req); GenerateFlushRequest(cfds, FlushReason::kWriteBufferFull, &flush_req);
SchedulePendingFlush(flush_req, FlushReason::kWriteBufferFull); SchedulePendingFlush(flush_req);
} else { } else {
for (auto* cfd : cfds) { for (auto* cfd : cfds) {
FlushRequest flush_req; FlushRequest flush_req;
GenerateFlushRequest({cfd}, &flush_req); GenerateFlushRequest({cfd}, FlushReason::kWriteBufferFull, &flush_req);
SchedulePendingFlush(flush_req, FlushReason::kWriteBufferFull); SchedulePendingFlush(flush_req);
} }
} }
MaybeScheduleFlushOrCompaction(); MaybeScheduleFlushOrCompaction();
+40
View File
@@ -2756,6 +2756,46 @@ TEST_F(DBRangeDelTest, RefreshMemtableIter) {
ASSERT_OK(iter->Refresh()); ASSERT_OK(iter->Refresh());
} }
TEST_F(DBRangeDelTest, RangeTombstoneRespectIterateUpperBound) {
// Memtable: a, [b, bz)
// Do a Seek on `a` with iterate_upper_bound being az
// range tombstone [b, bz) should not be processed (added to and
// popped from the min_heap in MergingIterator).
Options options = CurrentOptions();
options.disable_auto_compactions = true;
DestroyAndReopen(options);
ASSERT_OK(Put("a", "bar"));
ASSERT_OK(
db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), "b", "bz"));
// I could not find a cleaner way to test this without relying on
// implementation detail. Tried to test the value of
// `internal_range_del_reseek_count` but that did not work
// since BlockBasedTable iterator becomes !Valid() when point key
// is out of bound and that reseek only happens when a point key
// is covered by some range tombstone.
SyncPoint::GetInstance()->SetCallBack("MergeIterator::PopDeleteRangeStart",
[](void*) {
// there should not be any range
// tombstone in the heap.
FAIL();
});
SyncPoint::GetInstance()->EnableProcessing();
ReadOptions read_opts;
std::string upper_bound = "az";
Slice upper_bound_slice = upper_bound;
read_opts.iterate_upper_bound = &upper_bound_slice;
std::unique_ptr<Iterator> iter{db_->NewIterator(read_opts)};
iter->Seek("a");
ASSERT_TRUE(iter->Valid());
ASSERT_EQ(iter->key(), "a");
iter->Next();
ASSERT_FALSE(iter->Valid());
ASSERT_OK(iter->status());
}
#endif // ROCKSDB_LITE #endif // ROCKSDB_LITE
} // namespace ROCKSDB_NAMESPACE } // namespace ROCKSDB_NAMESPACE
+74
View File
@@ -7509,6 +7509,80 @@ TEST_F(DBTest2, SstUniqueIdVerifyMultiCFs) {
ASSERT_TRUE(s.IsCorruption()); ASSERT_TRUE(s.IsCorruption());
} }
TEST_F(DBTest2, BestEffortsRecoveryWithSstUniqueIdVerification) {
const auto tamper_with_uniq_id = [&](void* arg) {
auto props = static_cast<TableProperties*>(arg);
assert(props);
// update table property session_id to a different one
props->db_session_id = DBImpl::GenerateDbSessionId(nullptr);
};
const auto assert_db = [&](size_t expected_count,
const std::string& expected_v) {
std::unique_ptr<Iterator> it(db_->NewIterator(ReadOptions()));
size_t cnt = 0;
for (it->SeekToFirst(); it->Valid(); it->Next(), ++cnt) {
ASSERT_EQ(std::to_string(cnt), it->key());
ASSERT_EQ(expected_v, it->value());
}
ASSERT_EQ(expected_count, cnt);
};
const int num_l0_compaction_trigger = 8;
const int num_l0 = num_l0_compaction_trigger - 1;
Options options = CurrentOptions();
options.level0_file_num_compaction_trigger = num_l0_compaction_trigger;
for (int k = 0; k < num_l0; ++k) {
// Allow mismatch for now
options.verify_sst_unique_id_in_manifest = false;
DestroyAndReopen(options);
constexpr size_t num_keys_per_file = 10;
for (int i = 0; i < num_l0; ++i) {
for (size_t j = 0; j < num_keys_per_file; ++j) {
ASSERT_OK(Put(std::to_string(j), "v" + std::to_string(i)));
}
if (i == k) {
SyncPoint::GetInstance()->DisableProcessing();
SyncPoint::GetInstance()->SetCallBack(
"PropertyBlockBuilder::AddTableProperty:Start",
tamper_with_uniq_id);
SyncPoint::GetInstance()->EnableProcessing();
}
ASSERT_OK(Flush());
}
options.verify_sst_unique_id_in_manifest = true;
Status s = TryReopen(options);
ASSERT_TRUE(s.IsCorruption());
options.best_efforts_recovery = true;
Reopen(options);
assert_db(k == 0 ? 0 : num_keys_per_file, "v" + std::to_string(k - 1));
// Reopen with regular recovery
options.best_efforts_recovery = false;
Reopen(options);
assert_db(k == 0 ? 0 : num_keys_per_file, "v" + std::to_string(k - 1));
SyncPoint::GetInstance()->DisableProcessing();
SyncPoint::GetInstance()->ClearAllCallBacks();
for (size_t i = 0; i < num_keys_per_file; ++i) {
ASSERT_OK(Put(std::to_string(i), "v"));
}
ASSERT_OK(Flush());
Reopen(options);
{
for (size_t i = 0; i < num_keys_per_file; ++i) {
ASSERT_EQ("v", Get(std::to_string(i)));
}
}
}
}
#ifndef ROCKSDB_LITE #ifndef ROCKSDB_LITE
TEST_F(DBTest2, GetLatestSeqAndTsForKey) { TEST_F(DBTest2, GetLatestSeqAndTsForKey) {
Destroy(last_options_); Destroy(last_options_);
-3
View File
@@ -49,9 +49,6 @@
#include "util/string_util.h" #include "util/string_util.h"
#include "utilities/merge_operators.h" #include "utilities/merge_operators.h"
// In case defined by Windows headers
#undef small
namespace ROCKSDB_NAMESPACE { namespace ROCKSDB_NAMESPACE {
class MockEnv; class MockEnv;
+6 -6
View File
@@ -90,7 +90,7 @@ FlushJob::FlushJob(
std::vector<SequenceNumber> existing_snapshots, std::vector<SequenceNumber> existing_snapshots,
SequenceNumber earliest_write_conflict_snapshot, SequenceNumber earliest_write_conflict_snapshot,
SnapshotChecker* snapshot_checker, JobContext* job_context, SnapshotChecker* snapshot_checker, JobContext* job_context,
LogBuffer* log_buffer, FSDirectory* db_directory, FlushReason flush_reason, LogBuffer* log_buffer, FSDirectory* db_directory,
FSDirectory* output_file_directory, CompressionType output_compression, FSDirectory* output_file_directory, CompressionType output_compression,
Statistics* stats, EventLogger* event_logger, bool measure_io_stats, Statistics* stats, EventLogger* event_logger, bool measure_io_stats,
const bool sync_output_directory, const bool write_manifest, const bool sync_output_directory, const bool write_manifest,
@@ -113,6 +113,7 @@ FlushJob::FlushJob(
earliest_write_conflict_snapshot_(earliest_write_conflict_snapshot), earliest_write_conflict_snapshot_(earliest_write_conflict_snapshot),
snapshot_checker_(snapshot_checker), snapshot_checker_(snapshot_checker),
job_context_(job_context), job_context_(job_context),
flush_reason_(flush_reason),
log_buffer_(log_buffer), log_buffer_(log_buffer),
db_directory_(db_directory), db_directory_(db_directory),
output_file_directory_(output_file_directory), output_file_directory_(output_file_directory),
@@ -243,9 +244,8 @@ Status FlushJob::Run(LogsWithPrepTracker* prep_tracker, FileMetaData* file_meta,
} }
Status mempurge_s = Status::NotFound("No MemPurge."); Status mempurge_s = Status::NotFound("No MemPurge.");
if ((mempurge_threshold > 0.0) && if ((mempurge_threshold > 0.0) &&
(cfd_->GetFlushReason() == FlushReason::kWriteBufferFull) && (flush_reason_ == FlushReason::kWriteBufferFull) && (!mems_.empty()) &&
(!mems_.empty()) && MemPurgeDecider(mempurge_threshold) && MemPurgeDecider(mempurge_threshold) && !(db_options_.atomic_flush)) {
!(db_options_.atomic_flush)) {
cfd_->SetMempurgeUsed(); cfd_->SetMempurgeUsed();
mempurge_s = MemPurge(); mempurge_s = MemPurge();
if (!mempurge_s.ok()) { if (!mempurge_s.ok()) {
@@ -876,7 +876,7 @@ Status FlushJob::WriteLevel0Table() {
<< total_num_deletes << "total_data_size" << total_num_deletes << "total_data_size"
<< total_data_size << "memory_usage" << total_data_size << "memory_usage"
<< total_memory_usage << "flush_reason" << total_memory_usage << "flush_reason"
<< GetFlushReasonString(cfd_->GetFlushReason()); << GetFlushReasonString(flush_reason_);
{ {
ScopedArenaIterator iter( ScopedArenaIterator iter(
@@ -1074,7 +1074,7 @@ std::unique_ptr<FlushJobInfo> FlushJob::GetFlushJobInfo() const {
info->smallest_seqno = meta_.fd.smallest_seqno; info->smallest_seqno = meta_.fd.smallest_seqno;
info->largest_seqno = meta_.fd.largest_seqno; info->largest_seqno = meta_.fd.largest_seqno;
info->table_properties = table_properties_; info->table_properties = table_properties_;
info->flush_reason = cfd_->GetFlushReason(); info->flush_reason = flush_reason_;
info->blob_compression_type = mutable_cf_options_.blob_compression_type; info->blob_compression_type = mutable_cf_options_.blob_compression_type;
// Update BlobFilesInfo. // Update BlobFilesInfo.
+3 -2
View File
@@ -67,8 +67,8 @@ class FlushJob {
std::vector<SequenceNumber> existing_snapshots, std::vector<SequenceNumber> existing_snapshots,
SequenceNumber earliest_write_conflict_snapshot, SequenceNumber earliest_write_conflict_snapshot,
SnapshotChecker* snapshot_checker, JobContext* job_context, SnapshotChecker* snapshot_checker, JobContext* job_context,
LogBuffer* log_buffer, FSDirectory* db_directory, FlushReason flush_reason, LogBuffer* log_buffer,
FSDirectory* output_file_directory, FSDirectory* db_directory, FSDirectory* output_file_directory,
CompressionType output_compression, Statistics* stats, CompressionType output_compression, Statistics* stats,
EventLogger* event_logger, bool measure_io_stats, EventLogger* event_logger, bool measure_io_stats,
const bool sync_output_directory, const bool write_manifest, const bool sync_output_directory, const bool write_manifest,
@@ -150,6 +150,7 @@ class FlushJob {
SequenceNumber earliest_write_conflict_snapshot_; SequenceNumber earliest_write_conflict_snapshot_;
SnapshotChecker* snapshot_checker_; SnapshotChecker* snapshot_checker_;
JobContext* job_context_; JobContext* job_context_;
FlushReason flush_reason_;
LogBuffer* log_buffer_; LogBuffer* log_buffer_;
FSDirectory* db_directory_; FSDirectory* db_directory_;
FSDirectory* output_file_directory_; FSDirectory* output_file_directory_;
+29 -29
View File
@@ -164,15 +164,15 @@ TEST_F(FlushJobTest, Empty) {
auto cfd = versions_->GetColumnFamilySet()->GetDefault(); auto cfd = versions_->GetColumnFamilySet()->GetDefault();
EventLogger event_logger(db_options_.info_log.get()); EventLogger event_logger(db_options_.info_log.get());
SnapshotChecker* snapshot_checker = nullptr; // not relavant SnapshotChecker* snapshot_checker = nullptr; // not relavant
FlushJob flush_job(dbname_, versions_->GetColumnFamilySet()->GetDefault(), FlushJob flush_job(
db_options_, *cfd->GetLatestMutableCFOptions(), dbname_, versions_->GetColumnFamilySet()->GetDefault(), db_options_,
std::numeric_limits<uint64_t>::max() /* memtable_id */, *cfd->GetLatestMutableCFOptions(),
env_options_, versions_.get(), &mutex_, &shutting_down_, std::numeric_limits<uint64_t>::max() /* memtable_id */, env_options_,
{}, kMaxSequenceNumber, snapshot_checker, &job_context, versions_.get(), &mutex_, &shutting_down_, {}, kMaxSequenceNumber,
nullptr, nullptr, nullptr, kNoCompression, nullptr, snapshot_checker, &job_context, FlushReason::kTest, nullptr, nullptr,
&event_logger, false, true /* sync_output_directory */, nullptr, kNoCompression, nullptr, &event_logger, false,
true /* write_manifest */, Env::Priority::USER, true /* sync_output_directory */, true /* write_manifest */,
nullptr /*IOTracer*/, empty_seqno_to_time_mapping_); Env::Priority::USER, nullptr /*IOTracer*/, empty_seqno_to_time_mapping_);
{ {
InstrumentedMutexLock l(&mutex_); InstrumentedMutexLock l(&mutex_);
flush_job.PickMemTable(); flush_job.PickMemTable();
@@ -255,9 +255,9 @@ TEST_F(FlushJobTest, NonEmpty) {
*cfd->GetLatestMutableCFOptions(), *cfd->GetLatestMutableCFOptions(),
std::numeric_limits<uint64_t>::max() /* memtable_id */, env_options_, std::numeric_limits<uint64_t>::max() /* memtable_id */, env_options_,
versions_.get(), &mutex_, &shutting_down_, {}, kMaxSequenceNumber, versions_.get(), &mutex_, &shutting_down_, {}, kMaxSequenceNumber,
snapshot_checker, &job_context, nullptr, nullptr, nullptr, kNoCompression, snapshot_checker, &job_context, FlushReason::kTest, nullptr, nullptr,
db_options_.statistics.get(), &event_logger, true, nullptr, kNoCompression, db_options_.statistics.get(), &event_logger,
true /* sync_output_directory */, true /* write_manifest */, true, true /* sync_output_directory */, true /* write_manifest */,
Env::Priority::USER, nullptr /*IOTracer*/, empty_seqno_to_time_mapping_); Env::Priority::USER, nullptr /*IOTracer*/, empty_seqno_to_time_mapping_);
HistogramData hist; HistogramData hist;
@@ -318,9 +318,9 @@ TEST_F(FlushJobTest, FlushMemTablesSingleColumnFamily) {
dbname_, versions_->GetColumnFamilySet()->GetDefault(), db_options_, dbname_, versions_->GetColumnFamilySet()->GetDefault(), db_options_,
*cfd->GetLatestMutableCFOptions(), flush_memtable_id, env_options_, *cfd->GetLatestMutableCFOptions(), flush_memtable_id, env_options_,
versions_.get(), &mutex_, &shutting_down_, {}, kMaxSequenceNumber, versions_.get(), &mutex_, &shutting_down_, {}, kMaxSequenceNumber,
snapshot_checker, &job_context, nullptr, nullptr, nullptr, kNoCompression, snapshot_checker, &job_context, FlushReason::kTest, nullptr, nullptr,
db_options_.statistics.get(), &event_logger, true, nullptr, kNoCompression, db_options_.statistics.get(), &event_logger,
true /* sync_output_directory */, true /* write_manifest */, true, true /* sync_output_directory */, true /* write_manifest */,
Env::Priority::USER, nullptr /*IOTracer*/, empty_seqno_to_time_mapping_); Env::Priority::USER, nullptr /*IOTracer*/, empty_seqno_to_time_mapping_);
HistogramData hist; HistogramData hist;
FileMetaData file_meta; FileMetaData file_meta;
@@ -391,8 +391,8 @@ TEST_F(FlushJobTest, FlushMemtablesMultipleColumnFamilies) {
dbname_, cfd, db_options_, *cfd->GetLatestMutableCFOptions(), dbname_, cfd, db_options_, *cfd->GetLatestMutableCFOptions(),
memtable_ids[k], env_options_, versions_.get(), &mutex_, memtable_ids[k], env_options_, versions_.get(), &mutex_,
&shutting_down_, snapshot_seqs, kMaxSequenceNumber, snapshot_checker, &shutting_down_, snapshot_seqs, kMaxSequenceNumber, snapshot_checker,
&job_context, nullptr, nullptr, nullptr, kNoCompression, &job_context, FlushReason::kTest, nullptr, nullptr, nullptr,
db_options_.statistics.get(), &event_logger, true, kNoCompression, db_options_.statistics.get(), &event_logger, true,
false /* sync_output_directory */, false /* write_manifest */, false /* sync_output_directory */, false /* write_manifest */,
Env::Priority::USER, nullptr /*IOTracer*/, Env::Priority::USER, nullptr /*IOTracer*/,
empty_seqno_to_time_mapping_)); empty_seqno_to_time_mapping_));
@@ -520,9 +520,9 @@ TEST_F(FlushJobTest, Snapshots) {
*cfd->GetLatestMutableCFOptions(), *cfd->GetLatestMutableCFOptions(),
std::numeric_limits<uint64_t>::max() /* memtable_id */, env_options_, std::numeric_limits<uint64_t>::max() /* memtable_id */, env_options_,
versions_.get(), &mutex_, &shutting_down_, snapshots, kMaxSequenceNumber, versions_.get(), &mutex_, &shutting_down_, snapshots, kMaxSequenceNumber,
snapshot_checker, &job_context, nullptr, nullptr, nullptr, kNoCompression, snapshot_checker, &job_context, FlushReason::kTest, nullptr, nullptr,
db_options_.statistics.get(), &event_logger, true, nullptr, kNoCompression, db_options_.statistics.get(), &event_logger,
true /* sync_output_directory */, true /* write_manifest */, true, true /* sync_output_directory */, true /* write_manifest */,
Env::Priority::USER, nullptr /*IOTracer*/, empty_seqno_to_time_mapping_); Env::Priority::USER, nullptr /*IOTracer*/, empty_seqno_to_time_mapping_);
mutex_.Lock(); mutex_.Lock();
flush_job.PickMemTable(); flush_job.PickMemTable();
@@ -576,9 +576,9 @@ TEST_F(FlushJobTest, GetRateLimiterPriorityForWrite) {
dbname_, versions_->GetColumnFamilySet()->GetDefault(), db_options_, dbname_, versions_->GetColumnFamilySet()->GetDefault(), db_options_,
*cfd->GetLatestMutableCFOptions(), flush_memtable_id, env_options_, *cfd->GetLatestMutableCFOptions(), flush_memtable_id, env_options_,
versions_.get(), &mutex_, &shutting_down_, {}, kMaxSequenceNumber, versions_.get(), &mutex_, &shutting_down_, {}, kMaxSequenceNumber,
snapshot_checker, &job_context, nullptr, nullptr, nullptr, kNoCompression, snapshot_checker, &job_context, FlushReason::kTest, nullptr, nullptr,
db_options_.statistics.get(), &event_logger, true, nullptr, kNoCompression, db_options_.statistics.get(), &event_logger,
true /* sync_output_directory */, true /* write_manifest */, true, true /* sync_output_directory */, true /* write_manifest */,
Env::Priority::USER, nullptr /*IOTracer*/, empty_seqno_to_time_mapping_); Env::Priority::USER, nullptr /*IOTracer*/, empty_seqno_to_time_mapping_);
// When the state from WriteController is normal. // When the state from WriteController is normal.
@@ -656,9 +656,9 @@ TEST_F(FlushJobTimestampTest, AllKeysExpired) {
dbname_, cfd, db_options_, *cfd->GetLatestMutableCFOptions(), dbname_, cfd, db_options_, *cfd->GetLatestMutableCFOptions(),
std::numeric_limits<uint64_t>::max() /* memtable_id */, env_options_, std::numeric_limits<uint64_t>::max() /* memtable_id */, env_options_,
versions_.get(), &mutex_, &shutting_down_, snapshots, kMaxSequenceNumber, versions_.get(), &mutex_, &shutting_down_, snapshots, kMaxSequenceNumber,
snapshot_checker, &job_context, nullptr, nullptr, nullptr, kNoCompression, snapshot_checker, &job_context, FlushReason::kTest, nullptr, nullptr,
db_options_.statistics.get(), &event_logger, true, nullptr, kNoCompression, db_options_.statistics.get(), &event_logger,
true /* sync_output_directory */, true /* write_manifest */, true, true /* sync_output_directory */, true /* write_manifest */,
Env::Priority::USER, nullptr /*IOTracer*/, empty_seqno_to_time_mapping_, Env::Priority::USER, nullptr /*IOTracer*/, empty_seqno_to_time_mapping_,
/*db_id=*/"", /*db_id=*/"",
/*db_session_id=*/"", full_history_ts_low); /*db_session_id=*/"", full_history_ts_low);
@@ -709,9 +709,9 @@ TEST_F(FlushJobTimestampTest, NoKeyExpired) {
dbname_, cfd, db_options_, *cfd->GetLatestMutableCFOptions(), dbname_, cfd, db_options_, *cfd->GetLatestMutableCFOptions(),
std::numeric_limits<uint64_t>::max() /* memtable_id */, env_options_, std::numeric_limits<uint64_t>::max() /* memtable_id */, env_options_,
versions_.get(), &mutex_, &shutting_down_, snapshots, kMaxSequenceNumber, versions_.get(), &mutex_, &shutting_down_, snapshots, kMaxSequenceNumber,
snapshot_checker, &job_context, nullptr, nullptr, nullptr, kNoCompression, snapshot_checker, &job_context, FlushReason::kTest, nullptr, nullptr,
db_options_.statistics.get(), &event_logger, true, nullptr, kNoCompression, db_options_.statistics.get(), &event_logger,
true /* sync_output_directory */, true /* write_manifest */, true, true /* sync_output_directory */, true /* write_manifest */,
Env::Priority::USER, nullptr /*IOTracer*/, empty_seqno_to_time_mapping_, Env::Priority::USER, nullptr /*IOTracer*/, empty_seqno_to_time_mapping_,
/*db_id=*/"", /*db_id=*/"",
/*db_session_id=*/"", full_history_ts_low); /*db_session_id=*/"", full_history_ts_low);
+8 -6
View File
@@ -515,10 +515,11 @@ unsigned int Reader::ReadPhysicalRecord(Slice* result, size_t* drop_size,
size_t uncompressed_size = 0; size_t uncompressed_size = 0;
int remaining = 0; int remaining = 0;
const char* input = header + header_size;
do { do {
remaining = uncompress_->Uncompress(header + header_size, length, remaining = uncompress_->Uncompress(
uncompressed_buffer_.get(), input, length, uncompressed_buffer_.get(), &uncompressed_size);
&uncompressed_size); input = nullptr;
if (remaining < 0) { if (remaining < 0) {
buffer_.clear(); buffer_.clear();
return kBadRecord; return kBadRecord;
@@ -830,10 +831,11 @@ bool FragmentBufferedReader::TryReadFragment(
uncompressed_record_.clear(); uncompressed_record_.clear();
size_t uncompressed_size = 0; size_t uncompressed_size = 0;
int remaining = 0; int remaining = 0;
const char* input = header + header_size;
do { do {
remaining = uncompress_->Uncompress(header + header_size, length, remaining = uncompress_->Uncompress(
uncompressed_buffer_.get(), input, length, uncompressed_buffer_.get(), &uncompressed_size);
&uncompressed_size); input = nullptr;
if (remaining < 0) { if (remaining < 0) {
buffer_.clear(); buffer_.clear();
*fragment_type_or_err = kBadRecord; *fragment_type_or_err = kBadRecord;
+35 -2
View File
@@ -979,6 +979,38 @@ TEST_P(CompressionLogTest, Fragmentation) {
ASSERT_EQ("EOF", Read()); ASSERT_EQ("EOF", Read());
} }
TEST_P(CompressionLogTest, AlignedFragmentation) {
CompressionType compression_type = std::get<2>(GetParam());
if (!StreamingCompressionTypeSupported(compression_type)) {
ROCKSDB_GTEST_SKIP("Test requires support for compression type");
return;
}
ASSERT_OK(SetupTestEnv());
Random rnd(301);
int num_filler_records = 0;
// Keep writing small records until the next record will be aligned at the
// beginning of the block.
while ((WrittenBytes() & (kBlockSize - 1)) >= kHeaderSize) {
char entry = 'a';
ASSERT_OK(writer_->AddRecord(Slice(&entry, 1)));
num_filler_records++;
}
const std::vector<std::string> wal_entries = {
rnd.RandomBinaryString(3 * kBlockSize),
};
for (const std::string& wal_entry : wal_entries) {
Write(wal_entry);
}
for (int i = 0; i < num_filler_records; ++i) {
ASSERT_EQ("a", Read());
}
for (const std::string& wal_entry : wal_entries) {
ASSERT_EQ(wal_entry, Read());
}
ASSERT_EQ("EOF", Read());
}
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
Compression, CompressionLogTest, Compression, CompressionLogTest,
::testing::Combine(::testing::Values(0, 1), ::testing::Bool(), ::testing::Combine(::testing::Values(0, 1), ::testing::Bool(),
@@ -1026,10 +1058,11 @@ TEST_P(StreamingCompressionTest, Basic) {
for (int i = 0; i < (int)compressed_buffers.size(); i++) { for (int i = 0; i < (int)compressed_buffers.size(); i++) {
// Call uncompress till either the entire input is consumed or the output // Call uncompress till either the entire input is consumed or the output
// buffer size is equal to the allocated output buffer size. // buffer size is equal to the allocated output buffer size.
const char* input = compressed_buffers[i].c_str();
do { do {
ret_val = uncompress->Uncompress(compressed_buffers[i].c_str(), ret_val = uncompress->Uncompress(input, compressed_buffers[i].size(),
compressed_buffers[i].size(),
uncompressed_output_buffer, &output_pos); uncompressed_output_buffer, &output_pos);
input = nullptr;
if (output_pos > 0) { if (output_pos > 0) {
std::string uncompressed_fragment; std::string uncompressed_fragment;
uncompressed_fragment.assign(uncompressed_output_buffer, output_pos); uncompressed_fragment.assign(uncompressed_output_buffer, output_pos);
+1 -1
View File
@@ -76,7 +76,7 @@ MemTable::MemTable(const InternalKeyComparator& cmp,
: comparator_(cmp), : comparator_(cmp),
moptions_(ioptions, mutable_cf_options), moptions_(ioptions, mutable_cf_options),
refs_(0), refs_(0),
kArenaBlockSize(Arena::OptimizeBlockSize(moptions_.arena_block_size)), kArenaBlockSize(OptimizeBlockSize(moptions_.arena_block_size)),
mem_tracker_(write_buffer_manager), mem_tracker_(write_buffer_manager),
arena_(moptions_.arena_block_size, arena_(moptions_.arena_block_size,
(write_buffer_manager != nullptr && (write_buffer_manager != nullptr &&
+2
View File
@@ -127,6 +127,8 @@ Status TableCache::GetTableReader(
FileOptions fopts = file_options; FileOptions fopts = file_options;
fopts.temperature = file_temperature; fopts.temperature = file_temperature;
Status s = PrepareIOFromReadOptions(ro, ioptions_.clock, fopts.io_options); Status s = PrepareIOFromReadOptions(ro, ioptions_.clock, fopts.io_options);
TEST_SYNC_POINT_CALLBACK("TableCache::GetTableReader:BeforeOpenFile",
const_cast<Status*>(&s));
if (s.ok()) { if (s.ok()) {
s = ioptions_.fs->NewRandomAccessFile(fname, fopts, &file, nullptr); s = ioptions_.fs->NewRandomAccessFile(fname, fopts, &file, nullptr);
} }
+28 -5
View File
@@ -734,12 +734,13 @@ Status VersionEditHandlerPointInTime::MaybeCreateVersion(
assert(!cfd->ioptions()->cf_paths.empty()); assert(!cfd->ioptions()->cf_paths.empty());
Status s; Status s;
for (const auto& elem : edit.GetNewFiles()) { for (const auto& elem : edit.GetNewFiles()) {
int level = elem.first;
const FileMetaData& meta = elem.second; const FileMetaData& meta = elem.second;
const FileDescriptor& fd = meta.fd; const FileDescriptor& fd = meta.fd;
uint64_t file_num = fd.GetNumber(); uint64_t file_num = fd.GetNumber();
const std::string fpath = const std::string fpath =
MakeTableFileName(cfd->ioptions()->cf_paths[0].path, file_num); MakeTableFileName(cfd->ioptions()->cf_paths[0].path, file_num);
s = VerifyFile(fpath, meta); s = VerifyFile(cfd, fpath, level, meta);
if (s.IsPathNotFound() || s.IsNotFound() || s.IsCorruption()) { if (s.IsPathNotFound() || s.IsNotFound() || s.IsCorruption()) {
missing_files.insert(file_num); missing_files.insert(file_num);
s = Status::OK(); s = Status::OK();
@@ -804,6 +805,18 @@ Status VersionEditHandlerPointInTime::MaybeCreateVersion(
auto* version = new Version(cfd, version_set_, version_set_->file_options_, auto* version = new Version(cfd, version_set_, version_set_->file_options_,
*cfd->GetLatestMutableCFOptions(), io_tracer_, *cfd->GetLatestMutableCFOptions(), io_tracer_,
version_set_->current_version_number_++); version_set_->current_version_number_++);
s = builder->LoadTableHandlers(
cfd->internal_stats(),
version_set_->db_options_->max_file_opening_threads, false, true,
cfd->GetLatestMutableCFOptions()->prefix_extractor,
MaxFileSizeForL0MetaPin(*cfd->GetLatestMutableCFOptions()));
if (!s.ok()) {
delete version;
if (s.IsCorruption()) {
s = Status::OK();
}
return s;
}
s = builder->SaveTo(version->storage_info()); s = builder->SaveTo(version->storage_info());
if (s.ok()) { if (s.ok()) {
version->PrepareAppend( version->PrepareAppend(
@@ -823,9 +836,11 @@ Status VersionEditHandlerPointInTime::MaybeCreateVersion(
return s; return s;
} }
Status VersionEditHandlerPointInTime::VerifyFile(const std::string& fpath, Status VersionEditHandlerPointInTime::VerifyFile(ColumnFamilyData* cfd,
const std::string& fpath,
int level,
const FileMetaData& fmeta) { const FileMetaData& fmeta) {
return version_set_->VerifyFileMetadata(fpath, fmeta); return version_set_->VerifyFileMetadata(cfd, fpath, level, fmeta);
} }
Status VersionEditHandlerPointInTime::VerifyBlobFile( Status VersionEditHandlerPointInTime::VerifyBlobFile(
@@ -843,6 +858,12 @@ Status VersionEditHandlerPointInTime::VerifyBlobFile(
return s; return s;
} }
Status VersionEditHandlerPointInTime::LoadTables(
ColumnFamilyData* /*cfd*/, bool /*prefetch_index_and_filter_in_cache*/,
bool /*is_initial_load*/) {
return Status::OK();
}
Status ManifestTailer::Initialize() { Status ManifestTailer::Initialize() {
if (Mode::kRecovery == mode_) { if (Mode::kRecovery == mode_) {
return VersionEditHandler::Initialize(); return VersionEditHandler::Initialize();
@@ -930,9 +951,11 @@ void ManifestTailer::CheckIterationResult(const log::Reader& reader,
} }
} }
Status ManifestTailer::VerifyFile(const std::string& fpath, Status ManifestTailer::VerifyFile(ColumnFamilyData* cfd,
const std::string& fpath, int level,
const FileMetaData& fmeta) { const FileMetaData& fmeta) {
Status s = VersionEditHandlerPointInTime::VerifyFile(fpath, fmeta); Status s =
VersionEditHandlerPointInTime::VerifyFile(cfd, fpath, level, fmeta);
// TODO: Open file or create hard link to prevent the file from being // TODO: Open file or create hard link to prevent the file from being
// deleted. // deleted.
return s; return s;
+10 -6
View File
@@ -164,9 +164,9 @@ class VersionEditHandler : public VersionEditHandlerBase {
ColumnFamilyData* cfd, ColumnFamilyData* cfd,
bool force_create_version); bool force_create_version);
Status LoadTables(ColumnFamilyData* cfd, virtual Status LoadTables(ColumnFamilyData* cfd,
bool prefetch_index_and_filter_in_cache, bool prefetch_index_and_filter_in_cache,
bool is_initial_load); bool is_initial_load);
virtual bool MustOpenAllColumnFamilies() const { return !read_only_; } virtual bool MustOpenAllColumnFamilies() const { return !read_only_; }
@@ -213,11 +213,15 @@ class VersionEditHandlerPointInTime : public VersionEditHandler {
ColumnFamilyData* DestroyCfAndCleanup(const VersionEdit& edit) override; ColumnFamilyData* DestroyCfAndCleanup(const VersionEdit& edit) override;
Status MaybeCreateVersion(const VersionEdit& edit, ColumnFamilyData* cfd, Status MaybeCreateVersion(const VersionEdit& edit, ColumnFamilyData* cfd,
bool force_create_version) override; bool force_create_version) override;
virtual Status VerifyFile(const std::string& fpath, virtual Status VerifyFile(ColumnFamilyData* cfd, const std::string& fpath,
const FileMetaData& fmeta); int level, const FileMetaData& fmeta);
virtual Status VerifyBlobFile(ColumnFamilyData* cfd, uint64_t blob_file_num, virtual Status VerifyBlobFile(ColumnFamilyData* cfd, uint64_t blob_file_num,
const BlobFileAddition& blob_addition); const BlobFileAddition& blob_addition);
Status LoadTables(ColumnFamilyData* cfd,
bool prefetch_index_and_filter_in_cache,
bool is_initial_load) override;
std::unordered_map<uint32_t, Version*> versions_; std::unordered_map<uint32_t, Version*> versions_;
}; };
@@ -250,7 +254,7 @@ class ManifestTailer : public VersionEditHandlerPointInTime {
void CheckIterationResult(const log::Reader& reader, Status* s) override; void CheckIterationResult(const log::Reader& reader, Status* s) override;
Status VerifyFile(const std::string& fpath, Status VerifyFile(ColumnFamilyData* cfd, const std::string& fpath, int level,
const FileMetaData& fmeta) override; const FileMetaData& fmeta) override;
enum Mode : uint8_t { enum Mode : uint8_t {
+58 -15
View File
@@ -2539,16 +2539,19 @@ void Version::MultiGet(const ReadOptions& read_options, MultiGetRange* range,
} }
f = fp.GetNextFileInLevel(); f = fp.GetNextFileInLevel();
} }
if (s.ok() && mget_tasks.size() > 0) { if (mget_tasks.size() > 0) {
RecordTick(db_statistics_, MULTIGET_COROUTINE_COUNT, RecordTick(db_statistics_, MULTIGET_COROUTINE_COUNT,
mget_tasks.size()); mget_tasks.size());
// Collect all results so far // Collect all results so far
std::vector<Status> statuses = folly::coro::blockingWait( std::vector<Status> statuses = folly::coro::blockingWait(
folly::coro::collectAllRange(std::move(mget_tasks)) folly::coro::collectAllRange(std::move(mget_tasks))
.scheduleOn(&range->context()->executor())); .scheduleOn(&range->context()->executor()));
for (Status stat : statuses) { if (s.ok()) {
if (!stat.ok()) { for (Status stat : statuses) {
s = stat; if (!stat.ok()) {
s = std::move(stat);
break;
}
} }
} }
@@ -2794,6 +2797,9 @@ Status Version::MultiGetAsync(
unsigned int num_tasks_queued = 0; unsigned int num_tasks_queued = 0;
to_process.pop_front(); to_process.pop_front();
if (batch->IsSearchEnded() || batch->GetRange().empty()) { if (batch->IsSearchEnded() || batch->GetRange().empty()) {
// If to_process is empty, i.e no more batches to look at, then we need
// schedule the enqueued coroutines and wait for them. Otherwise, we
// skip this batch and move to the next one in to_process.
if (!to_process.empty()) { if (!to_process.empty()) {
continue; continue;
} }
@@ -2802,9 +2808,6 @@ Status Version::MultiGetAsync(
// to_process // to_process
s = ProcessBatch(options, batch, mget_tasks, blob_ctxs, batches, waiting, s = ProcessBatch(options, batch, mget_tasks, blob_ctxs, batches, waiting,
to_process, num_tasks_queued, mget_stats); to_process, num_tasks_queued, mget_stats);
if (!s.ok()) {
break;
}
// If ProcessBatch didn't enqueue any coroutine tasks, it means all // If ProcessBatch didn't enqueue any coroutine tasks, it means all
// keys were filtered out. So put the batch back in to_process to // keys were filtered out. So put the batch back in to_process to
// lookup in the next level // lookup in the next level
@@ -2815,8 +2818,10 @@ Status Version::MultiGetAsync(
waiting.emplace_back(idx); waiting.emplace_back(idx);
} }
} }
if (to_process.empty()) { // If ProcessBatch() returned an error, then schedule the enqueued
if (s.ok() && mget_tasks.size() > 0) { // coroutines and wait for them, then abort the MultiGet.
if (to_process.empty() || !s.ok()) {
if (mget_tasks.size() > 0) {
assert(waiting.size()); assert(waiting.size());
RecordTick(db_statistics_, MULTIGET_COROUTINE_COUNT, mget_tasks.size()); RecordTick(db_statistics_, MULTIGET_COROUTINE_COUNT, mget_tasks.size());
// Collect all results so far // Collect all results so far
@@ -2824,10 +2829,12 @@ Status Version::MultiGetAsync(
folly::coro::collectAllRange(std::move(mget_tasks)) folly::coro::collectAllRange(std::move(mget_tasks))
.scheduleOn(&range->context()->executor())); .scheduleOn(&range->context()->executor()));
mget_tasks.clear(); mget_tasks.clear();
for (Status stat : statuses) { if (s.ok()) {
if (!stat.ok()) { for (Status stat : statuses) {
s = stat; if (!stat.ok()) {
break; s = std::move(stat);
break;
}
} }
} }
@@ -2850,6 +2857,9 @@ Status Version::MultiGetAsync(
assert(!s.ok() || waiting.size() == 0); assert(!s.ok() || waiting.size() == 0);
} }
} }
if (!s.ok()) {
break;
}
} }
uint64_t num_levels = 0; uint64_t num_levels = 0;
@@ -6704,8 +6714,9 @@ uint64_t VersionSet::GetTotalBlobFileSize(Version* dummy_versions) {
return all_versions_blob_file_size; return all_versions_blob_file_size;
} }
Status VersionSet::VerifyFileMetadata(const std::string& fpath, Status VersionSet::VerifyFileMetadata(ColumnFamilyData* cfd,
const FileMetaData& meta) const { const std::string& fpath, int level,
const FileMetaData& meta) {
uint64_t fsize = 0; uint64_t fsize = 0;
Status status = fs_->GetFileSize(fpath, IOOptions(), &fsize, nullptr); Status status = fs_->GetFileSize(fpath, IOOptions(), &fsize, nullptr);
if (status.ok()) { if (status.ok()) {
@@ -6713,6 +6724,38 @@ Status VersionSet::VerifyFileMetadata(const std::string& fpath,
status = Status::Corruption("File size mismatch: " + fpath); status = Status::Corruption("File size mismatch: " + fpath);
} }
} }
if (status.ok() && db_options_->verify_sst_unique_id_in_manifest) {
assert(cfd);
TableCache* table_cache = cfd->table_cache();
assert(table_cache);
const MutableCFOptions* const cf_opts = cfd->GetLatestMutableCFOptions();
assert(cf_opts);
std::shared_ptr<const SliceTransform> pe = cf_opts->prefix_extractor;
size_t max_sz_for_l0_meta_pin = MaxFileSizeForL0MetaPin(*cf_opts);
const FileOptions& file_opts = file_options();
Version* version = cfd->current();
assert(version);
VersionStorageInfo& storage_info = version->storage_info_;
const InternalKeyComparator* icmp = storage_info.InternalComparator();
assert(icmp);
InternalStats* internal_stats = cfd->internal_stats();
FileMetaData meta_copy = meta;
status = table_cache->FindTable(
ReadOptions(), file_opts, *icmp, meta_copy,
&(meta_copy.table_reader_handle), pe,
/*no_io=*/false, /*record_read_stats=*/true,
internal_stats->GetFileReadHist(level), false, level,
/*prefetch_index_and_filter_in_cache*/ false, max_sz_for_l0_meta_pin,
meta_copy.temperature);
if (meta_copy.table_reader_handle) {
table_cache->ReleaseHandle(meta_copy.table_reader_handle);
}
}
return status; return status;
} }
+2 -2
View File
@@ -1501,8 +1501,8 @@ class VersionSet {
ColumnFamilyData* CreateColumnFamily(const ColumnFamilyOptions& cf_options, ColumnFamilyData* CreateColumnFamily(const ColumnFamilyOptions& cf_options,
const VersionEdit* edit); const VersionEdit* edit);
Status VerifyFileMetadata(const std::string& fpath, Status VerifyFileMetadata(ColumnFamilyData* cfd, const std::string& fpath,
const FileMetaData& meta) const; int level, const FileMetaData& meta);
// Protected by DB mutex. // Protected by DB mutex.
WalSet wals_; WalSet wals_;
-1
View File
@@ -150,7 +150,6 @@ DECLARE_string(cache_type);
DECLARE_uint64(subcompactions); DECLARE_uint64(subcompactions);
DECLARE_uint64(periodic_compaction_seconds); DECLARE_uint64(periodic_compaction_seconds);
DECLARE_uint64(compaction_ttl); DECLARE_uint64(compaction_ttl);
DECLARE_bool(fifo_allow_compaction);
DECLARE_bool(allow_concurrent_memtable_write); DECLARE_bool(allow_concurrent_memtable_write);
DECLARE_double(experimental_mempurge_threshold); DECLARE_double(experimental_mempurge_threshold);
DECLARE_bool(enable_write_thread_adaptive_yield); DECLARE_bool(enable_write_thread_adaptive_yield);
-4
View File
@@ -379,10 +379,6 @@ DEFINE_uint64(compaction_ttl, 1000,
DEFINE_bool(allow_concurrent_memtable_write, false, DEFINE_bool(allow_concurrent_memtable_write, false,
"Allow multi-writers to update mem tables in parallel."); "Allow multi-writers to update mem tables in parallel.");
DEFINE_bool(fifo_allow_compaction, false,
"If true, set `Options::compaction_options_fifo.allow_compaction = "
"true`. It only take effect when FIFO compaction is used.");
DEFINE_double(experimental_mempurge_threshold, 0.0, DEFINE_double(experimental_mempurge_threshold, 0.0,
"Maximum estimated useful payload that triggers a " "Maximum estimated useful payload that triggers a "
"mempurge process to collect memtable garbage bytes."); "mempurge process to collect memtable garbage bytes.");
-5
View File
@@ -3121,11 +3121,6 @@ void InitializeOptionsFromFlags(
options.max_background_flushes = FLAGS_max_background_flushes; options.max_background_flushes = FLAGS_max_background_flushes;
options.compaction_style = options.compaction_style =
static_cast<ROCKSDB_NAMESPACE::CompactionStyle>(FLAGS_compaction_style); static_cast<ROCKSDB_NAMESPACE::CompactionStyle>(FLAGS_compaction_style);
if (options.compaction_style ==
ROCKSDB_NAMESPACE::CompactionStyle::kCompactionStyleFIFO) {
options.compaction_options_fifo.allow_compaction =
FLAGS_fifo_allow_compaction;
}
options.compaction_pri = options.compaction_pri =
static_cast<ROCKSDB_NAMESPACE::CompactionPri>(FLAGS_compaction_pri); static_cast<ROCKSDB_NAMESPACE::CompactionPri>(FLAGS_compaction_pri);
options.num_levels = FLAGS_num_levels; options.num_levels = FLAGS_num_levels;
+14 -1
View File
@@ -247,10 +247,14 @@ void FilePrefetchBuffer::AbortAllIOs() {
// Release io_handles. // Release io_handles.
if (bufs_[curr_].io_handle_ != nullptr && bufs_[curr_].del_fn_ != nullptr) { if (bufs_[curr_].io_handle_ != nullptr && bufs_[curr_].del_fn_ != nullptr) {
DestroyAndClearIOHandle(curr_); DestroyAndClearIOHandle(curr_);
} else {
bufs_[curr_].async_read_in_progress_ = false;
} }
if (bufs_[second].io_handle_ != nullptr && bufs_[second].del_fn_ != nullptr) { if (bufs_[second].io_handle_ != nullptr && bufs_[second].del_fn_ != nullptr) {
DestroyAndClearIOHandle(second); DestroyAndClearIOHandle(second);
} else {
bufs_[second].async_read_in_progress_ = false;
} }
} }
@@ -325,7 +329,16 @@ Status FilePrefetchBuffer::HandleOverlappingData(
uint64_t& tmp_offset, size_t& tmp_length) { uint64_t& tmp_offset, size_t& tmp_length) {
Status s; Status s;
size_t alignment = reader->file()->GetRequiredBufferAlignment(); size_t alignment = reader->file()->GetRequiredBufferAlignment();
uint32_t second = curr_ ^ 1; uint32_t second;
// Check if the first buffer has the required offset and the async read is
// still in progress. This should only happen if a prefetch was initiated
// by Seek, but the next access is at another offset.
if (bufs_[curr_].async_read_in_progress_ &&
IsOffsetInBufferWithAsyncProgress(offset, curr_)) {
PollAndUpdateBuffersIfNeeded(offset);
}
second = curr_ ^ 1;
// If data is overlapping over two buffers, copy the data from curr_ and // If data is overlapping over two buffers, copy the data from curr_ and
// call ReadAsync on curr_. // call ReadAsync on curr_.
+76
View File
@@ -4,10 +4,14 @@
// (found in the LICENSE.Apache file in the root directory). // (found in the LICENSE.Apache file in the root directory).
#include "db/db_test_util.h" #include "db/db_test_util.h"
#include "file/file_prefetch_buffer.h"
#include "file/file_util.h"
#include "rocksdb/file_system.h"
#include "test_util/sync_point.h" #include "test_util/sync_point.h"
#ifdef GFLAGS #ifdef GFLAGS
#include "tools/io_tracer_parser_tool.h" #include "tools/io_tracer_parser_tool.h"
#endif #endif
#include "util/random.h"
namespace ROCKSDB_NAMESPACE { namespace ROCKSDB_NAMESPACE {
@@ -2023,6 +2027,78 @@ TEST_P(PrefetchTest, TraceReadAsyncWithCallbackWrapper) {
Close(); Close();
} }
#endif // GFLAGS #endif // GFLAGS
class FilePrefetchBufferTest : public testing::Test {
public:
void SetUp() override {
SetupSyncPointsToMockDirectIO();
env_ = Env::Default();
fs_ = FileSystem::Default();
test_dir_ = test::PerThreadDBPath("file_prefetch_buffer_test");
ASSERT_OK(fs_->CreateDir(test_dir_, IOOptions(), nullptr));
}
void TearDown() override { EXPECT_OK(DestroyDir(env_, test_dir_)); }
void Write(const std::string& fname, const std::string& content) {
std::unique_ptr<FSWritableFile> f;
ASSERT_OK(fs_->NewWritableFile(Path(fname), FileOptions(), &f, nullptr));
ASSERT_OK(f->Append(content, IOOptions(), nullptr));
ASSERT_OK(f->Close(IOOptions(), nullptr));
}
void Read(const std::string& fname, const FileOptions& opts,
std::unique_ptr<RandomAccessFileReader>* reader) {
std::string fpath = Path(fname);
std::unique_ptr<FSRandomAccessFile> f;
ASSERT_OK(fs_->NewRandomAccessFile(fpath, opts, &f, nullptr));
reader->reset(new RandomAccessFileReader(std::move(f), fpath,
env_->GetSystemClock().get()));
}
void AssertResult(const std::string& content,
const std::vector<FSReadRequest>& reqs) {
for (const auto& r : reqs) {
ASSERT_OK(r.status);
ASSERT_EQ(r.len, r.result.size());
ASSERT_EQ(content.substr(r.offset, r.len), r.result.ToString());
}
}
FileSystem* fs() { return fs_.get(); }
private:
Env* env_;
std::shared_ptr<FileSystem> fs_;
std::string test_dir_;
std::string Path(const std::string& fname) { return test_dir_ + "/" + fname; }
};
TEST_F(FilePrefetchBufferTest, SeekWithBlockCacheHit) {
std::string fname = "seek-with-block-cache-hit";
Random rand(0);
std::string content = rand.RandomString(32768);
Write(fname, content);
FileOptions opts;
std::unique_ptr<RandomAccessFileReader> r;
Read(fname, opts, &r);
FilePrefetchBuffer fpb(16384, 16384, true, false, false, 0, 0, fs());
Slice result;
// Simulate a seek of 4096 bytes at offset 0. Due to the readahead settings,
// it will do two reads of 4096+8192 and 8192
Status s = fpb.PrefetchAsync(IOOptions(), r.get(), 0, 4096, &result);
// Platforms that don't have IO uring may not support async IO
ASSERT_TRUE(s.IsTryAgain() || s.IsNotSupported());
// Simulate a block cache hit
fpb.UpdateReadPattern(0, 4096, false);
// Now read some data that straddles the two prefetch buffers - offset 8192 to
// 16384
ASSERT_TRUE(fpb.TryReadFromCacheAsync(IOOptions(), r.get(), 8192, 8192,
&result, &s, Env::IOPriority::IO_LOW));
}
#endif // ROCKSDB_LITE #endif // ROCKSDB_LITE
} // namespace ROCKSDB_NAMESPACE } // namespace ROCKSDB_NAMESPACE
+25 -18
View File
@@ -1285,30 +1285,37 @@ struct DBOptions {
// Default: nullptr // Default: nullptr
std::shared_ptr<FileChecksumGenFactory> file_checksum_gen_factory = nullptr; std::shared_ptr<FileChecksumGenFactory> file_checksum_gen_factory = nullptr;
// By default, RocksDB recovery fails if any table/blob file referenced in // By default, RocksDB recovery fails if any table/blob file referenced in the
// final version reconstructed from the
// MANIFEST are missing after scanning the MANIFEST pointed to by the // MANIFEST are missing after scanning the MANIFEST pointed to by the
// CURRENT file. // CURRENT file. It can also fail if verification of unique SST id fails.
// Best-efforts recovery is another recovery mode that tolerates missing or // Best-efforts recovery is another recovery mode that does not necessarily
// corrupted table or blob files. // fail when certain table/blob files are missing/corrupted or have mismatched
// unique id table property. Instead, best-efforts recovery recovers each
// column family to a point in the MANIFEST that corresponds to a version. In
// such a version, all valid table/blob files referenced have the expected
// file size. For table files, their unique id table property match the
// MANIFEST.
//
// Best-efforts recovery does not need a valid CURRENT file, and tries to // Best-efforts recovery does not need a valid CURRENT file, and tries to
// recover the database using one of the available MANIFEST files in the db // recover the database using one of the available MANIFEST files in the db
// directory. // directory.
// Best-efforts recovery recovers database to a state in which the database
// includes only table and blob files whose actual sizes match the
// information in the chosen MANIFEST without holes in the history.
// Best-efforts recovery tries the available MANIFEST files from high file // Best-efforts recovery tries the available MANIFEST files from high file
// numbers (newer) to low file numbers (older), and stops after finding the // numbers (newer) to low file numbers (older), and stops after finding the
// first MANIFEST file from which the db can be recovered to a state without // first MANIFEST file from which the db can be recovered to a state without
// invalid (missing/file-mismatch) table and blob files. // invalid (missing/filesize-mismatch/unique-id-mismatch) table and blob
// It is possible that the database can be restored to an empty state with no // files. It is possible that the database can be restored to an empty state
// table or blob files. // with no table or blob files.
// Regardless of this option, the IDENTITY file is updated if needed during //
// recovery to match the DB ID in the MANIFEST (if previously using // Regardless of this option, the IDENTITY file
// write_dbid_to_manifest) or to be in some valid state (non-empty DB ID). // is updated if needed during recovery to match the DB ID in the MANIFEST (if
// Currently, not compatible with atomic flush. Furthermore, WAL files will // previously using write_dbid_to_manifest) or to be in some valid state
// not be used for recovery if best_efforts_recovery is true. // (non-empty DB ID). Currently, not compatible with atomic flush.
// Also requires either 1) LOCK file exists or 2) underlying env's LockFile() // Furthermore, WAL files will not be used for recovery if
// call returns ok even for non-existing LOCK file. // best_efforts_recovery is true. Also requires either 1) LOCK file exists or
// 2) underlying env's LockFile() call returns ok even for non-existing LOCK
// file.
//
// Default: false // Default: false
bool best_efforts_recovery = false; bool best_efforts_recovery = false;
@@ -1480,7 +1487,7 @@ struct ReadOptions {
const Slice* iterate_lower_bound; const Slice* iterate_lower_bound;
// "iterate_upper_bound" defines the extent up to which the forward iterator // "iterate_upper_bound" defines the extent up to which the forward iterator
// can returns entries. Once the bound is reached, Valid() will be false. // can return entries. Once the bound is reached, Valid() will be false.
// "iterate_upper_bound" is exclusive ie the bound value is // "iterate_upper_bound" is exclusive ie the bound value is
// not a valid entry. If prefix_extractor is not null: // not a valid entry. If prefix_extractor is not null:
// 1. If options.auto_prefix_mode = true, iterate_upper_bound will be used // 1. If options.auto_prefix_mode = true, iterate_upper_bound will be used
+1 -1
View File
@@ -13,7 +13,7 @@
// minor or major version number planned for release. // minor or major version number planned for release.
#define ROCKSDB_MAJOR 7 #define ROCKSDB_MAJOR 7
#define ROCKSDB_MINOR 9 #define ROCKSDB_MINOR 9
#define ROCKSDB_PATCH 0 #define ROCKSDB_PATCH 3
// Do not use these. We made the mistake of declaring macros starting with // Do not use these. We made the mistake of declaring macros starting with
// double underscore. Now we have to live with our choice. We'll deprecate these // double underscore. Now we have to live with our choice. We'll deprecate these
+87 -22
View File
@@ -8,7 +8,9 @@
// found in the LICENSE file. See the AUTHORS file for names of contributors. // found in the LICENSE file. See the AUTHORS file for names of contributors.
#include "memory/arena.h" #include "memory/arena.h"
#ifndef OS_WIN
#include <sys/mman.h>
#endif
#include <algorithm> #include <algorithm>
#include "logging/logging.h" #include "logging/logging.h"
@@ -20,7 +22,16 @@
namespace ROCKSDB_NAMESPACE { namespace ROCKSDB_NAMESPACE {
size_t Arena::OptimizeBlockSize(size_t block_size) { // MSVC complains that it is already defined since it is static in the header.
#ifndef _MSC_VER
const size_t Arena::kInlineSize;
#endif
const size_t Arena::kMinBlockSize = 4096;
const size_t Arena::kMaxBlockSize = 2u << 30;
static const int kAlignUnit = alignof(max_align_t);
size_t OptimizeBlockSize(size_t block_size) {
// Make sure block_size is in optimal range // Make sure block_size is in optimal range
block_size = std::max(Arena::kMinBlockSize, block_size); block_size = std::max(Arena::kMinBlockSize, block_size);
block_size = std::min(Arena::kMaxBlockSize, block_size); block_size = std::min(Arena::kMaxBlockSize, block_size);
@@ -42,12 +53,14 @@ Arena::Arena(size_t block_size, AllocTracker* tracker, size_t huge_page_size)
blocks_memory_ += alloc_bytes_remaining_; blocks_memory_ += alloc_bytes_remaining_;
aligned_alloc_ptr_ = inline_block_; aligned_alloc_ptr_ = inline_block_;
unaligned_alloc_ptr_ = inline_block_ + alloc_bytes_remaining_; unaligned_alloc_ptr_ = inline_block_ + alloc_bytes_remaining_;
if (MemMapping::kHugePageSupported) { #ifdef MAP_HUGETLB
hugetlb_size_ = huge_page_size; hugetlb_size_ = huge_page_size;
if (hugetlb_size_ && kBlockSize > hugetlb_size_) { if (hugetlb_size_ && kBlockSize > hugetlb_size_) {
hugetlb_size_ = ((kBlockSize - 1U) / hugetlb_size_ + 1U) * hugetlb_size_; hugetlb_size_ = ((kBlockSize - 1U) / hugetlb_size_ + 1U) * hugetlb_size_;
}
} }
#else
(void)huge_page_size;
#endif
if (tracker_ != nullptr) { if (tracker_ != nullptr) {
tracker_->Allocate(kInlineSize); tracker_->Allocate(kInlineSize);
} }
@@ -58,6 +71,21 @@ Arena::~Arena() {
assert(tracker_->is_freed()); assert(tracker_->is_freed());
tracker_->FreeMem(); tracker_->FreeMem();
} }
for (const auto& block : blocks_) {
delete[] block;
}
#ifdef MAP_HUGETLB
for (const auto& mmap_info : huge_blocks_) {
if (mmap_info.addr_ == nullptr) {
continue;
}
auto ret = munmap(mmap_info.addr_, mmap_info.length_);
if (ret != 0) {
// TODO(sdong): Better handling
}
}
#endif
} }
char* Arena::AllocateFallback(size_t bytes, bool aligned) { char* Arena::AllocateFallback(size_t bytes, bool aligned) {
@@ -71,10 +99,12 @@ char* Arena::AllocateFallback(size_t bytes, bool aligned) {
// We waste the remaining space in the current block. // We waste the remaining space in the current block.
size_t size = 0; size_t size = 0;
char* block_head = nullptr; char* block_head = nullptr;
if (MemMapping::kHugePageSupported && hugetlb_size_ > 0) { #ifdef MAP_HUGETLB
if (hugetlb_size_) {
size = hugetlb_size_; size = hugetlb_size_;
block_head = AllocateFromHugePage(size); block_head = AllocateFromHugePage(size);
} }
#endif
if (!block_head) { if (!block_head) {
size = kBlockSize; size = kBlockSize;
block_head = AllocateNewBlock(size); block_head = AllocateNewBlock(size);
@@ -93,22 +123,45 @@ char* Arena::AllocateFallback(size_t bytes, bool aligned) {
} }
char* Arena::AllocateFromHugePage(size_t bytes) { char* Arena::AllocateFromHugePage(size_t bytes) {
MemMapping mm = MemMapping::AllocateHuge(bytes); #ifdef MAP_HUGETLB
auto addr = static_cast<char*>(mm.Get()); if (hugetlb_size_ == 0) {
if (addr) { return nullptr;
huge_blocks_.push_back(std::move(mm));
blocks_memory_ += bytes;
if (tracker_ != nullptr) {
tracker_->Allocate(bytes);
}
} }
return addr; // Reserve space in `huge_blocks_` before calling `mmap`.
// Use `emplace_back()` instead of `reserve()` to let std::vector manage its
// own memory and do fewer reallocations.
//
// - If `emplace_back` throws, no memory leaks because we haven't called
// `mmap` yet.
// - If `mmap` throws, no memory leaks because the vector will be cleaned up
// via RAII.
huge_blocks_.emplace_back(nullptr /* addr */, 0 /* length */);
void* addr = mmap(nullptr, bytes, (PROT_READ | PROT_WRITE),
(MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB), -1, 0);
if (addr == MAP_FAILED) {
return nullptr;
}
huge_blocks_.back() = MmapInfo(addr, bytes);
blocks_memory_ += bytes;
if (tracker_ != nullptr) {
tracker_->Allocate(bytes);
}
return reinterpret_cast<char*>(addr);
#else
(void)bytes;
return nullptr;
#endif
} }
char* Arena::AllocateAligned(size_t bytes, size_t huge_page_size, char* Arena::AllocateAligned(size_t bytes, size_t huge_page_size,
Logger* logger) { Logger* logger) {
if (MemMapping::kHugePageSupported && hugetlb_size_ > 0 && assert((kAlignUnit & (kAlignUnit - 1)) ==
huge_page_size > 0 && bytes > 0) { 0); // Pointer size should be a power of 2
#ifdef MAP_HUGETLB
if (huge_page_size > 0 && bytes > 0) {
// Allocate from a huge page TLB table. // Allocate from a huge page TLB table.
size_t reserved_size = size_t reserved_size =
((bytes - 1U) / huge_page_size + 1U) * huge_page_size; ((bytes - 1U) / huge_page_size + 1U) * huge_page_size;
@@ -124,6 +177,10 @@ char* Arena::AllocateAligned(size_t bytes, size_t huge_page_size,
return addr; return addr;
} }
} }
#else
(void)huge_page_size;
(void)logger;
#endif
size_t current_mod = size_t current_mod =
reinterpret_cast<uintptr_t>(aligned_alloc_ptr_) & (kAlignUnit - 1); reinterpret_cast<uintptr_t>(aligned_alloc_ptr_) & (kAlignUnit - 1);
@@ -143,10 +200,17 @@ char* Arena::AllocateAligned(size_t bytes, size_t huge_page_size,
} }
char* Arena::AllocateNewBlock(size_t block_bytes) { char* Arena::AllocateNewBlock(size_t block_bytes) {
auto uniq = std::make_unique<char[]>(block_bytes); // Reserve space in `blocks_` before allocating memory via new.
char* block = uniq.get(); // Use `emplace_back()` instead of `reserve()` to let std::vector manage its
blocks_.push_back(std::move(uniq)); // own memory and do fewer reallocations.
//
// - If `emplace_back` throws, no memory leaks because we haven't called `new`
// yet.
// - If `new` throws, no memory leaks because the vector will be cleaned up
// via RAII.
blocks_.emplace_back(nullptr);
char* block = new char[block_bytes];
size_t allocated_size; size_t allocated_size;
#ifdef ROCKSDB_MALLOC_USABLE_SIZE #ifdef ROCKSDB_MALLOC_USABLE_SIZE
allocated_size = malloc_usable_size(block); allocated_size = malloc_usable_size(block);
@@ -163,6 +227,7 @@ char* Arena::AllocateNewBlock(size_t block_bytes) {
if (tracker_ != nullptr) { if (tracker_ != nullptr) {
tracker_->Allocate(allocated_size); tracker_->Allocate(allocated_size);
} }
blocks_.back() = block;
return block; return block;
} }
+32 -23
View File
@@ -12,13 +12,18 @@
// size, it uses malloc to directly get the requested size. // size, it uses malloc to directly get the requested size.
#pragma once #pragma once
#ifndef OS_WIN
#include <sys/mman.h>
#endif
#include <assert.h>
#include <stdint.h>
#include <cerrno>
#include <cstddef> #include <cstddef>
#include <deque> #include <vector>
#include "memory/allocator.h" #include "memory/allocator.h"
#include "port/mmap.h" #include "util/mutexlock.h"
#include "rocksdb/env.h"
namespace ROCKSDB_NAMESPACE { namespace ROCKSDB_NAMESPACE {
@@ -28,13 +33,9 @@ class Arena : public Allocator {
Arena(const Arena&) = delete; Arena(const Arena&) = delete;
void operator=(const Arena&) = delete; void operator=(const Arena&) = delete;
static constexpr size_t kInlineSize = 2048; static const size_t kInlineSize = 2048;
static constexpr size_t kMinBlockSize = 4096; static const size_t kMinBlockSize;
static constexpr size_t kMaxBlockSize = 2u << 30; static const size_t kMaxBlockSize;
static constexpr unsigned kAlignUnit = alignof(std::max_align_t);
static_assert((kAlignUnit & (kAlignUnit - 1)) == 0,
"Pointer size should be power of 2");
// huge_page_size: if 0, don't use huge page TLB. If > 0 (should set to the // huge_page_size: if 0, don't use huge page TLB. If > 0 (should set to the
// supported hugepage size of the system), block allocation will try huge // supported hugepage size of the system), block allocation will try huge
@@ -64,7 +65,7 @@ class Arena : public Allocator {
// by the arena (exclude the space allocated but not yet used for future // by the arena (exclude the space allocated but not yet used for future
// allocations). // allocations).
size_t ApproximateMemoryUsage() const { size_t ApproximateMemoryUsage() const {
return blocks_memory_ + blocks_.size() * sizeof(char*) - return blocks_memory_ + blocks_.capacity() * sizeof(char*) -
alloc_bytes_remaining_; alloc_bytes_remaining_;
} }
@@ -82,19 +83,22 @@ class Arena : public Allocator {
return blocks_.empty() && huge_blocks_.empty(); return blocks_.empty() && huge_blocks_.empty();
} }
// check and adjust the block_size so that the return value is
// 1. in the range of [kMinBlockSize, kMaxBlockSize].
// 2. the multiple of align unit.
static size_t OptimizeBlockSize(size_t block_size);
private: private:
alignas(std::max_align_t) char inline_block_[kInlineSize]; char inline_block_[kInlineSize]
__attribute__((__aligned__(alignof(max_align_t))));
// Number of bytes allocated in one block // Number of bytes allocated in one block
const size_t kBlockSize; const size_t kBlockSize;
// Allocated memory blocks // Array of new[] allocated memory blocks
std::deque<std::unique_ptr<char[]>> blocks_; using Blocks = std::vector<char*>;
// Huge page allocations Blocks blocks_;
std::deque<MemMapping> huge_blocks_;
struct MmapInfo {
void* addr_;
size_t length_;
MmapInfo(void* addr, size_t length) : addr_(addr), length_(length) {}
};
std::vector<MmapInfo> huge_blocks_;
size_t irregular_block_num = 0; size_t irregular_block_num = 0;
// Stats for current active block. // Stats for current active block.
@@ -107,15 +111,15 @@ class Arena : public Allocator {
// How many bytes left in currently active block? // How many bytes left in currently active block?
size_t alloc_bytes_remaining_ = 0; size_t alloc_bytes_remaining_ = 0;
#ifdef MAP_HUGETLB
size_t hugetlb_size_ = 0; size_t hugetlb_size_ = 0;
#endif // MAP_HUGETLB
char* AllocateFromHugePage(size_t bytes); char* AllocateFromHugePage(size_t bytes);
char* AllocateFallback(size_t bytes, bool aligned); char* AllocateFallback(size_t bytes, bool aligned);
char* AllocateNewBlock(size_t block_bytes); char* AllocateNewBlock(size_t block_bytes);
// Bytes of memory in blocks allocated so far // Bytes of memory in blocks allocated so far
size_t blocks_memory_ = 0; size_t blocks_memory_ = 0;
// Non-owned
AllocTracker* tracker_; AllocTracker* tracker_;
}; };
@@ -132,4 +136,9 @@ inline char* Arena::Allocate(size_t bytes) {
return AllocateFallback(bytes, false /* unaligned */); return AllocateFallback(bytes, false /* unaligned */);
} }
// check and adjust the block_size so that the return value is
// 1. in the range of [kMinBlockSize, kMaxBlockSize].
// 2. the multiple of align unit.
extern size_t OptimizeBlockSize(size_t block_size);
} // namespace ROCKSDB_NAMESPACE } // namespace ROCKSDB_NAMESPACE
-60
View File
@@ -8,11 +8,6 @@
// found in the LICENSE file. See the AUTHORS file for names of contributors. // found in the LICENSE file. See the AUTHORS file for names of contributors.
#include "memory/arena.h" #include "memory/arena.h"
#ifndef OS_WIN
#include <sys/resource.h>
#endif
#include "port/port.h"
#include "test_util/testharness.h" #include "test_util/testharness.h"
#include "util/random.h" #include "util/random.h"
@@ -201,61 +196,6 @@ TEST_F(ArenaTest, Simple) {
SimpleTest(0); SimpleTest(0);
SimpleTest(kHugePageSize); SimpleTest(kHugePageSize);
} }
// Number of minor page faults since last call
size_t PopMinorPageFaultCount() {
#ifdef RUSAGE_SELF
static long prev = 0;
struct rusage usage;
EXPECT_EQ(getrusage(RUSAGE_SELF, &usage), 0);
size_t rv = usage.ru_minflt - prev;
prev = usage.ru_minflt;
return rv;
#else
// Conservative
return SIZE_MAX;
#endif // RUSAGE_SELF
}
TEST(MmapTest, AllocateLazyZeroed) {
// Doesn't have to be page aligned
constexpr size_t len = 1234567;
MemMapping m = MemMapping::AllocateLazyZeroed(len);
auto arr = static_cast<char*>(m.Get());
// Should generally work
ASSERT_NE(arr, nullptr);
// Start counting page faults
PopMinorPageFaultCount();
// Access half of the allocation
size_t i = 0;
for (; i < len / 2; ++i) {
ASSERT_EQ(arr[i], 0);
arr[i] = static_cast<char>(i & 255);
}
// Appropriate page faults (maybe more)
size_t faults = PopMinorPageFaultCount();
ASSERT_GE(faults, len / 2 / port::kPageSize);
// Access rest of the allocation
for (; i < len; ++i) {
ASSERT_EQ(arr[i], 0);
arr[i] = static_cast<char>(i & 255);
}
// Appropriate page faults (maybe more)
faults = PopMinorPageFaultCount();
ASSERT_GE(faults, len / 2 / port::kPageSize);
// Verify data
for (i = 0; i < len; ++i) {
ASSERT_EQ(arr[i], static_cast<char>(i & 255));
}
}
} // namespace ROCKSDB_NAMESPACE } // namespace ROCKSDB_NAMESPACE
int main(int argc, char** argv) { int main(int argc, char** argv) {
-98
View File
@@ -1,98 +0,0 @@
// 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).
#include "port/mmap.h"
#include <cassert>
#include <cstdio>
#include <cstring>
#include <new>
#include <utility>
#include "util/hash.h"
namespace ROCKSDB_NAMESPACE {
MemMapping::~MemMapping() {
#ifdef OS_WIN
if (addr_ != nullptr) {
(void)::UnmapViewOfFile(addr_);
}
if (page_file_handle_ != NULL) {
(void)::CloseHandle(page_file_handle_);
}
#else // OS_WIN -> !OS_WIN
if (addr_ != nullptr) {
auto status = munmap(addr_, length_);
assert(status == 0);
if (status != 0) {
// TODO: handle error?
}
}
#endif // OS_WIN
}
MemMapping::MemMapping(MemMapping&& other) noexcept {
*this = std::move(other);
}
MemMapping& MemMapping::operator=(MemMapping&& other) noexcept {
if (&other == this) {
return *this;
}
this->~MemMapping();
std::memcpy(this, &other, sizeof(*this));
new (&other) MemMapping();
return *this;
}
MemMapping MemMapping::AllocateAnonymous(size_t length, bool huge) {
MemMapping mm;
mm.length_ = length;
assert(mm.addr_ == nullptr);
if (length == 0) {
// OK to leave addr as nullptr
return mm;
}
int huge_flag = 0;
#ifdef OS_WIN
if (huge) {
#ifdef FILE_MAP_LARGE_PAGES
huge_flag = FILE_MAP_LARGE_PAGES;
#endif // FILE_MAP_LARGE_PAGES
}
mm.page_file_handle_ = ::CreateFileMapping(
INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE | SEC_COMMIT,
Upper32of64(length), Lower32of64(length), nullptr);
if (mm.page_file_handle_ == NULL) {
// Failure
return mm;
}
mm.addr_ = ::MapViewOfFile(mm.page_file_handle_, FILE_MAP_WRITE | huge_flag,
0, 0, length);
#else // OS_WIN -> !OS_WIN
if (huge) {
#ifdef MAP_HUGETLB
huge_flag = MAP_HUGETLB;
#endif // MAP_HUGE_TLB
}
mm.addr_ = mmap(nullptr, length, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | huge_flag, -1, 0);
if (mm.addr_ == MAP_FAILED) {
mm.addr_ = nullptr;
}
#endif // OS_WIN
return mm;
}
MemMapping MemMapping::AllocateHuge(size_t length) {
return AllocateAnonymous(length, /*huge*/ true);
}
MemMapping MemMapping::AllocateLazyZeroed(size_t length) {
return AllocateAnonymous(length, /*huge*/ false);
}
} // namespace ROCKSDB_NAMESPACE
-70
View File
@@ -1,70 +0,0 @@
// 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).
#pragma once
#ifdef OS_WIN
#include "port/win/port_win.h"
// ^^^ For proper/safe inclusion of windows.h. Must come first.
#include <memoryapi.h>
#else
#include <sys/mman.h>
#endif // OS_WIN
#include <cstdint>
#include "rocksdb/rocksdb_namespace.h"
namespace ROCKSDB_NAMESPACE {
// An RAII wrapper for mmaped memory
class MemMapping {
public:
static constexpr bool kHugePageSupported =
#if defined(MAP_HUGETLB) || defined(FILE_MAP_LARGE_PAGES)
true;
#else
false;
#endif
// Allocate memory requesting to be backed by huge pages
static MemMapping AllocateHuge(size_t length);
// Allocate memory that is only lazily mapped to resident memory and
// guaranteed to be zero-initialized. Note that some platforms like
// Linux allow memory over-commit, where only the used portion of memory
// matters, while other platforms require enough swap space (page file) to
// back the full mapping.
static MemMapping AllocateLazyZeroed(size_t length);
// No copies
MemMapping(const MemMapping&) = delete;
MemMapping& operator=(const MemMapping&) = delete;
// Move
MemMapping(MemMapping&&) noexcept;
MemMapping& operator=(MemMapping&&) noexcept;
// Releases the mapping
~MemMapping();
inline void* Get() const { return addr_; }
inline size_t Length() const { return length_; }
private:
MemMapping() {}
// The mapped memory, or nullptr on failure / not supported
void* addr_ = nullptr;
// The known usable number of bytes starting at that address
size_t length_ = 0;
#ifdef OS_WIN
HANDLE page_file_handle_ = NULL;
#endif // OS_WIN
static MemMapping AllocateAnonymous(size_t length, bool huge);
};
} // namespace ROCKSDB_NAMESPACE
-1
View File
@@ -154,7 +154,6 @@ LIB_SOURCES = \
options/options.cc \ options/options.cc \
options/options_helper.cc \ options/options_helper.cc \
options/options_parser.cc \ options/options_parser.cc \
port/mmap.cc \
port/port_posix.cc \ port/port_posix.cc \
port/win/env_default.cc \ port/win/env_default.cc \
port/win/env_win.cc \ port/win/env_win.cc \
+43 -10
View File
@@ -117,14 +117,16 @@ class MergingIterator : public InternalIterator {
public: public:
MergingIterator(const InternalKeyComparator* comparator, MergingIterator(const InternalKeyComparator* comparator,
InternalIterator** children, int n, bool is_arena_mode, InternalIterator** children, int n, bool is_arena_mode,
bool prefix_seek_mode) bool prefix_seek_mode,
const Slice* iterate_upper_bound = nullptr)
: is_arena_mode_(is_arena_mode), : is_arena_mode_(is_arena_mode),
prefix_seek_mode_(prefix_seek_mode), prefix_seek_mode_(prefix_seek_mode),
direction_(kForward), direction_(kForward),
comparator_(comparator), comparator_(comparator),
current_(nullptr), current_(nullptr),
minHeap_(comparator_), minHeap_(comparator_),
pinned_iters_mgr_(nullptr) { pinned_iters_mgr_(nullptr),
iterate_upper_bound_(iterate_upper_bound) {
children_.resize(n); children_.resize(n);
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
children_[i].level = i; children_[i].level = i;
@@ -202,11 +204,26 @@ class MergingIterator : public InternalIterator {
assert(!range_tombstone_iters_.empty() && assert(!range_tombstone_iters_.empty() &&
range_tombstone_iters_[level]->Valid()); range_tombstone_iters_[level]->Valid());
if (start_key) { if (start_key) {
pinned_heap_item_[level].SetTombstoneKey( ParsedInternalKey pik = range_tombstone_iters_[level]->start_key();
range_tombstone_iters_[level]->start_key()); // iterate_upper_bound does not have timestamp
if (iterate_upper_bound_ &&
comparator_->user_comparator()->CompareWithoutTimestamp(
pik.user_key, true /* a_has_ts */, *iterate_upper_bound_,
false /* b_has_ts */) >= 0) {
if (replace_top) {
// replace_top implies this range tombstone iterator is still in
// minHeap_ and at the top.
minHeap_.pop();
}
return;
}
pinned_heap_item_[level].SetTombstoneKey(std::move(pik));
pinned_heap_item_[level].type = HeapItem::DELETE_RANGE_START; pinned_heap_item_[level].type = HeapItem::DELETE_RANGE_START;
assert(active_.count(level) == 0); assert(active_.count(level) == 0);
} else { } else {
// allow end key to go over upper bound (if present) since start key is
// before upper bound and the range tombstone could still cover a
// range before upper bound.
pinned_heap_item_[level].SetTombstoneKey( pinned_heap_item_[level].SetTombstoneKey(
range_tombstone_iters_[level]->end_key()); range_tombstone_iters_[level]->end_key());
pinned_heap_item_[level].type = HeapItem::DELETE_RANGE_END; pinned_heap_item_[level].type = HeapItem::DELETE_RANGE_END;
@@ -251,6 +268,7 @@ class MergingIterator : public InternalIterator {
void PopDeleteRangeStart() { void PopDeleteRangeStart() {
while (!minHeap_.empty() && while (!minHeap_.empty() &&
minHeap_.top()->type == HeapItem::DELETE_RANGE_START) { minHeap_.top()->type == HeapItem::DELETE_RANGE_START) {
TEST_SYNC_POINT_CALLBACK("MergeIterator::PopDeleteRangeStart", nullptr);
// insert end key of this range tombstone and updates active_ // insert end key of this range tombstone and updates active_
InsertRangeTombstoneToMinHeap( InsertRangeTombstoneToMinHeap(
minHeap_.top()->level, false /* start_key */, true /* replace_top */); minHeap_.top()->level, false /* start_key */, true /* replace_top */);
@@ -573,6 +591,10 @@ class MergingIterator : public InternalIterator {
std::unique_ptr<MergerMaxIterHeap> maxHeap_; std::unique_ptr<MergerMaxIterHeap> maxHeap_;
PinnedIteratorsManager* pinned_iters_mgr_; PinnedIteratorsManager* pinned_iters_mgr_;
// Used to bound range tombstones. For point keys, DBIter and SSTable iterator
// take care of boundary checking.
const Slice* iterate_upper_bound_;
// In forward direction, process a child that is not in the min heap. // In forward direction, process a child that is not in the min heap.
// If valid, add to the min heap. Otherwise, check status. // If valid, add to the min heap. Otherwise, check status.
void AddToMinHeapOrCheckStatus(HeapItem*); void AddToMinHeapOrCheckStatus(HeapItem*);
@@ -634,9 +656,19 @@ void MergingIterator::SeekImpl(const Slice& target, size_t starting_level,
for (size_t level = 0; level < starting_level; ++level) { for (size_t level = 0; level < starting_level; ++level) {
if (range_tombstone_iters_[level] && if (range_tombstone_iters_[level] &&
range_tombstone_iters_[level]->Valid()) { range_tombstone_iters_[level]->Valid()) {
assert(static_cast<bool>(active_.count(level)) == // use an iterator on active_ if performance becomes an issue here
(pinned_heap_item_[level].type == HeapItem::DELETE_RANGE_END)); if (active_.count(level) > 0) {
minHeap_.push(&pinned_heap_item_[level]); assert(pinned_heap_item_[level].type == HeapItem::DELETE_RANGE_END);
// if it was active, then start key must be within upper_bound,
// so we can add to minHeap_ directly.
minHeap_.push(&pinned_heap_item_[level]);
} else {
// this takes care of checking iterate_upper_bound, but with an extra
// key comparison if range_tombstone_iters_[level] was already out of
// bound. Consider using a new HeapItem type or some flag to remember
// boundary checking result.
InsertRangeTombstoneToMinHeap(level);
}
} else { } else {
assert(!active_.count(level)); assert(!active_.count(level));
} }
@@ -1280,11 +1312,12 @@ InternalIterator* NewMergingIterator(const InternalKeyComparator* cmp,
} }
MergeIteratorBuilder::MergeIteratorBuilder( MergeIteratorBuilder::MergeIteratorBuilder(
const InternalKeyComparator* comparator, Arena* a, bool prefix_seek_mode) const InternalKeyComparator* comparator, Arena* a, bool prefix_seek_mode,
const Slice* iterate_upper_bound)
: first_iter(nullptr), use_merging_iter(false), arena(a) { : first_iter(nullptr), use_merging_iter(false), arena(a) {
auto mem = arena->AllocateAligned(sizeof(MergingIterator)); auto mem = arena->AllocateAligned(sizeof(MergingIterator));
merge_iter = merge_iter = new (mem) MergingIterator(comparator, nullptr, 0, true,
new (mem) MergingIterator(comparator, nullptr, 0, true, prefix_seek_mode); prefix_seek_mode, iterate_upper_bound);
} }
MergeIteratorBuilder::~MergeIteratorBuilder() { MergeIteratorBuilder::~MergeIteratorBuilder() {
+2 -1
View File
@@ -45,7 +45,8 @@ class MergeIteratorBuilder {
// comparator: the comparator used in merging comparator // comparator: the comparator used in merging comparator
// arena: where the merging iterator needs to be allocated from. // arena: where the merging iterator needs to be allocated from.
explicit MergeIteratorBuilder(const InternalKeyComparator* comparator, explicit MergeIteratorBuilder(const InternalKeyComparator* comparator,
Arena* arena, bool prefix_seek_mode = false); Arena* arena, bool prefix_seek_mode = false,
const Slice* iterate_upper_bound = nullptr);
~MergeIteratorBuilder(); ~MergeIteratorBuilder();
// Add iter to the merging iterator. // Add iter to the merging iterator.
+10
View File
@@ -363,6 +363,16 @@ class SleepingBackgroundTask {
done_with_sleep_(false), done_with_sleep_(false),
sleeping_(false) {} sleeping_(false) {}
~SleepingBackgroundTask() {
MutexLock l(&mutex_);
should_sleep_ = false;
while (sleeping_) {
assert(!should_sleep_);
bg_cv_.SignalAll();
bg_cv_.Wait();
}
}
bool IsSleeping() { bool IsSleeping() {
MutexLock l(&mutex_); MutexLock l(&mutex_);
return sleeping_; return sleeping_;
-1
View File
@@ -139,7 +139,6 @@ default_params = {
# 0 = never (used by some), 10 = often (for threading bugs), 600 = default # 0 = never (used by some), 10 = often (for threading bugs), 600 = default
"stats_dump_period_sec": lambda: random.choice([0, 10, 600]), "stats_dump_period_sec": lambda: random.choice([0, 10, 600]),
"compaction_ttl": lambda: random.choice([0, 0, 1, 2, 10, 100, 1000]), "compaction_ttl": lambda: random.choice([0, 0, 1, 2, 10, 100, 1000]),
"fifo_allow_compaction": lambda: random.randint(0, 1),
# Test small max_manifest_file_size in a smaller chance, as most of the # 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 # time we wnat manifest history to be preserved to help debug
"max_manifest_file_size": lambda: random.choice( "max_manifest_file_size": lambda: random.choice(
+2 -2
View File
@@ -85,14 +85,14 @@ void ZSTDStreamingCompress::Reset() {
int ZSTDStreamingUncompress::Uncompress(const char* input, size_t input_size, int ZSTDStreamingUncompress::Uncompress(const char* input, size_t input_size,
char* output, size_t* output_pos) { char* output, size_t* output_pos) {
assert(input != nullptr && output != nullptr && output_pos != nullptr); assert(output != nullptr && output_pos != nullptr);
*output_pos = 0; *output_pos = 0;
// Don't need to uncompress an empty input // Don't need to uncompress an empty input
if (input_size == 0) { if (input_size == 0) {
return 0; return 0;
} }
#ifdef ZSTD_STREAMING #ifdef ZSTD_STREAMING
if (input_buffer_.src != input) { if (input) {
// New input // New input
input_buffer_ = {input, input_size, /*pos=*/0}; input_buffer_ = {input, input_size, /*pos=*/0};
} }
+5 -2
View File
@@ -1705,8 +1705,11 @@ class StreamingUncompress {
compress_format_version_(compress_format_version), compress_format_version_(compress_format_version),
max_output_len_(max_output_len) {} max_output_len_(max_output_len) {}
virtual ~StreamingUncompress() = default; virtual ~StreamingUncompress() = default;
// uncompress should be called again with the same input if output_size is // Uncompress can be called repeatedly to progressively process the same
// equal to max_output_len or with the next input fragment. // input buffer, or can be called with a new input buffer. When the input
// buffer is not fully consumed, the return value is > 0 or output_size
// == max_output_len. When calling uncompress to continue processing the
// same input buffer, the input argument should be nullptr.
// Parameters: // Parameters:
// input - buffer to uncompress // input - buffer to uncompress
// input_size - size of input buffer // input_size - size of input buffer