Compare commits

..
2 Commits
Author SHA1 Message Date
prerit 3a00304c7b update point_lock_manager.cc 2025-03-27 10:47:48 -07:00
prerit 7d971cbd33 Check for yields while waiting for lock in a loop 2025-03-27 10:38:01 -07:00
132 changed files with 1914 additions and 3814 deletions

No files matched your search

@@ -11,9 +11,9 @@ runs:
CMAKE_BIN: C:/Program Files/CMake/bin/cmake.exe
CTEST_BIN: C:/Program Files/CMake/bin/ctest.exe
JAVA_HOME: C:/Program Files/BellSoft/LibericaJDK-8
SNAPPY_HOME: ${{ github.workspace }}/thirdparty/snappy-1.2.2
SNAPPY_INCLUDE: ${{ github.workspace }}/thirdparty/snappy-1.2.2;${{ github.workspace }}/thirdparty/snappy-1.2.2/build
SNAPPY_LIB_DEBUG: ${{ github.workspace }}/thirdparty/snappy-1.2.2/build/Debug/snappy.lib
SNAPPY_HOME: ${{ github.workspace }}/thirdparty/snappy-1.1.8
SNAPPY_INCLUDE: ${{ github.workspace }}/thirdparty/snappy-1.1.8;${{ github.workspace }}/thirdparty/snappy-1.1.8/build
SNAPPY_LIB_DEBUG: ${{ github.workspace }}/thirdparty/snappy-1.1.8/build/Debug/snappy.lib
run: |-
# NOTE: if ... Exit $LASTEXITCODE lines needed to exit and report failure
echo ===================== Install Dependencies =====================
@@ -22,14 +22,14 @@ runs:
mkdir $Env:THIRDPARTY_HOME
cd $Env:THIRDPARTY_HOME
echo "Building Snappy dependency..."
curl -Lo snappy-1.2.2.zip https://github.com/google/snappy/archive/refs/tags/1.2.2.zip
curl -Lo snappy-1.1.8.zip https://github.com/google/snappy/archive/refs/tags/1.1.8.zip
if(!$?) { Exit $LASTEXITCODE }
unzip -q snappy-1.2.2.zip
unzip -q snappy-1.1.8.zip
if(!$?) { Exit $LASTEXITCODE }
cd snappy-1.2.2
cd snappy-1.1.8
mkdir build
cd build
& cmake -G "$Env:CMAKE_GENERATOR" .. -DSNAPPY_BUILD_TESTS=OFF -DSNAPPY_BUILD_BENCHMARKS=OFF
& cmake -G "$Env:CMAKE_GENERATOR" ..
if(!$?) { Exit $LASTEXITCODE }
msbuild Snappy.sln -maxCpuCount -property:Configuration=Debug -property:Platform=x64
if(!$?) { Exit $LASTEXITCODE }
-34
View File
@@ -1,40 +1,6 @@
# Rocksdb Change Log
> NOTE: Entries for next release do not go here. Follow instructions in `unreleased_history/README.txt`
## 10.2.3 (05/19/2025)
* Fix a failure in IngestExternalFiles() when ingesting an external table with the allow_db_generated_files option set to false.
## 10.2.2 (05/08/2025)
### Bug Fixes
* Pass wrapped WritableFileWriter pointer to ExternalTableBuilder so that the file checksum can be correctly calculated and returned by SstFileWriter for external table files.
## 10.2.1 (04/24/2025)
### Bug Fixes
* Fix improper initialization of ExternalTableOptions
## 10.2.0 (04/21/2025)
### New Features
* Provide histogram stats `COMPACTION_PREFETCH_BYTES` to measure number of bytes for RocksDB's prefetching (as opposed to file
system's prefetch) on SST file during compaction read
* A new API DB::GetNewestUserDefinedTimestamp is added to return the newest user defined timestamp seen in a column family
* Introduce API `IngestWriteBatchWithIndex()` for ingesting updates into DB while bypassing memtable writes. This improves performance when writing a large write batch to the DB.
* Add a new CF option `memtable_op_scan_flush_trigger` that triggers a flush of the memtable if an iterator's Seek()/Next() scans over a certain number of invisible entries from the memtable.
### Public API Changes
* AdvancedColumnFamilyOptions.max_write_buffer_number_to_maintain is deleted. It's deprecated since introduction of a better option max_write_buffer_size_to_maintain since RocksDB 6.5.0.
* Deprecated API `DB::MaxMemCompactionLevel()`.
* Deprecated `ReadOptions::ignore_range_deletions`.
* Deprecated API `experimental::PromoteL0()`.
* Added arbitrary string map for additional options to be overriden for remote compactions
* The fail_if_options_file_error option in DBOptions has been removed. The behavior now is to always return failure in any API that fails to persist the OPTIONS file.
### Behavior Changes
* Make stats `PREFETCH_BYTES_USEFUL`, `PREFETCH_HITS`, `PREFETCH_BYTES` only account for prefetching during user initiated scan
### Bug Fixes
* Fix a bug in Posix file system that the FSWritableFile created via `FileSystem::ReopenWritableFile` internally does not track the correct file size.
* Fix a bug where tail size of remote compaction output is not persisted in primary db's manifest
## 10.1.0 (03/24/2025)
### New Features
* Added a new `DBOptions.calculate_sst_write_lifetime_hint_set` setting that allows to customize which compaction styles SST write lifetime hint calculation is allowed on. Today RocksDB supports only two modes `kCompactionStyleLevel` and `kCompactionStyleUniversal`.
+15 -61
View File
@@ -11,29 +11,18 @@ CRASHTEST_MAKE=$(MAKE) -f crash_test.mk
CRASHTEST_PY=$(PYTHON) -u tools/db_crashtest.py --stress_cmd=$(DB_STRESS_CMD) --cleanup_cmd='$(DB_CLEANUP_CMD)'
.PHONY: crash_test crash_test_with_atomic_flush crash_test_with_txn \
crash_test_with_wc_txn crash_test_with_wp_txn crash_test_with_wup_txn \
crash_test_with_best_efforts_recovery crash_test_with_ts \
crash_test_with_multiops_wc_txn \
crash_test_with_multiops_wp_txn \
crash_test_with_multiops_wup_txn \
crash_test_with_optimistic_txn \
crash_test_with_tiered_storage \
blackbox_crash_test blackbox_crash_test_with_atomic_flush \
blackbox_crash_test_with_wc_txn blackbox_crash_test_with_wp_txn \
blackbox_crash_test_with_wup_txn \
blackbox_crash_test_with_txn blackbox_crash_test_with_ts \
blackbox_crash_test_with_best_efforts_recovery \
whitebox_crash_test whitebox_crash_test_with_atomic_flush \
whitebox_crash_test_with_txn whitebox_crash_test_with_ts \
blackbox_crash_test_with_multiops_wc_txn \
blackbox_crash_test_with_multiops_wp_txn \
blackbox_crash_test_with_multiops_wup_txn \
blackbox_crash_test_with_optimistic_txn \
blackbox_crash_test_with_tiered_storage \
whitebox_crash_test whitebox_crash_test_with_atomic_flush \
whitebox_crash_test_with_wc_txn whitebox_crash_test_with_wp_txn \
whitebox_crash_test_with_wup_txn \
whitebox_crash_test_with_txn whitebox_crash_test_with_ts \
whitebox_crash_test_with_optimistic_txn \
crash_test_with_tiered_storage blackbox_crash_test_with_tiered_storage \
whitebox_crash_test_with_tiered_storage \
whitebox_crash_test_with_optimistic_txn \
blackbox_crash_test_with_optimistic_txn \
crash_test: $(DB_STRESS_CMD)
# Do not parallelize
@@ -45,20 +34,10 @@ crash_test_with_atomic_flush: $(DB_STRESS_CMD)
$(CRASHTEST_MAKE) whitebox_crash_test_with_atomic_flush
$(CRASHTEST_MAKE) blackbox_crash_test_with_atomic_flush
crash_test_with_wc_txn: $(DB_STRESS_CMD)
crash_test_with_txn: $(DB_STRESS_CMD)
# Do not parallelize
$(CRASHTEST_MAKE) whitebox_crash_test_with_wc_txn
$(CRASHTEST_MAKE) blackbox_crash_test_with_wc_txn
crash_test_with_wp_txn: $(DB_STRESS_CMD)
# Do not parallelize
$(CRASHTEST_MAKE) whitebox_crash_test_with_wp_txn
$(CRASHTEST_MAKE) blackbox_crash_test_with_wp_txn
crash_test_with_wup_txn: $(DB_STRESS_CMD)
# Do not parallelize
$(CRASHTEST_MAKE) whitebox_crash_test_with_wup_txn
$(CRASHTEST_MAKE) blackbox_crash_test_with_wup_txn
$(CRASHTEST_MAKE) whitebox_crash_test_with_txn
$(CRASHTEST_MAKE) blackbox_crash_test_with_txn
crash_test_with_optimistic_txn: $(DB_STRESS_CMD)
# Do not parallelize
@@ -83,9 +62,6 @@ crash_test_with_multiops_wc_txn: $(DB_STRESS_CMD)
crash_test_with_multiops_wp_txn: $(DB_STRESS_CMD)
$(CRASHTEST_MAKE) blackbox_crash_test_with_multiops_wp_txn
crash_test_with_multiops_wup_txn: $(DB_STRESS_CMD)
$(CRASHTEST_MAKE) blackbox_crash_test_with_multiops_wup_txn
blackbox_crash_test: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --simple blackbox $(CRASH_TEST_EXT_ARGS)
$(CRASHTEST_PY) blackbox $(CRASH_TEST_EXT_ARGS)
@@ -93,14 +69,8 @@ blackbox_crash_test: $(DB_STRESS_CMD)
blackbox_crash_test_with_atomic_flush: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --cf_consistency blackbox $(CRASH_TEST_EXT_ARGS)
blackbox_crash_test_with_wc_txn: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --txn blackbox --txn_write_policy 0 $(CRASH_TEST_EXT_ARGS)
blackbox_crash_test_with_wp_txn: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --txn blackbox --txn_write_policy 1 $(CRASH_TEST_EXT_ARGS)
blackbox_crash_test_with_wup_txn: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --txn blackbox --txn_write_policy 2 $(CRASH_TEST_EXT_ARGS)
blackbox_crash_test_with_txn: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --txn blackbox $(CRASH_TEST_EXT_ARGS)
blackbox_crash_test_with_best_efforts_recovery: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --test_best_efforts_recovery blackbox $(CRASH_TEST_EXT_ARGS)
@@ -109,13 +79,10 @@ blackbox_crash_test_with_ts: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --enable_ts blackbox $(CRASH_TEST_EXT_ARGS)
blackbox_crash_test_with_multiops_wc_txn: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --test_multiops_txn --txn_write_policy 0 blackbox $(CRASH_TEST_EXT_ARGS)
$(CRASHTEST_PY) --test_multiops_txn --write_policy write_committed blackbox $(CRASH_TEST_EXT_ARGS)
blackbox_crash_test_with_multiops_wp_txn: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --test_multiops_txn --txn_write_policy 1 blackbox $(CRASH_TEST_EXT_ARGS)
blackbox_crash_test_with_multiops_wup_txn: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --test_multiops_txn --txn_write_policy 2 blackbox $(CRASH_TEST_EXT_ARGS)
$(CRASHTEST_PY) --test_multiops_txn --write_policy write_prepared blackbox $(CRASH_TEST_EXT_ARGS)
blackbox_crash_test_with_tiered_storage: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --test_tiered_storage blackbox $(CRASH_TEST_EXT_ARGS)
@@ -137,17 +104,9 @@ whitebox_crash_test_with_atomic_flush: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --cf_consistency whitebox --random_kill_odd \
$(CRASH_TEST_KILL_ODD) $(CRASH_TEST_EXT_ARGS)
whitebox_crash_test_with_wc_txn: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --txn whitebox --txn_write_policy 0 \
--random_kill_odd $(CRASH_TEST_KILL_ODD) $(CRASH_TEST_EXT_ARGS)
whitebox_crash_test_with_wp_txn: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --txn whitebox --txn_write_policy 1 \
--random_kill_odd $(CRASH_TEST_KILL_ODD) $(CRASH_TEST_EXT_ARGS)
whitebox_crash_test_with_wup_txn: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --txn whitebox --txn_write_policy 2 \
--random_kill_odd $(CRASH_TEST_KILL_ODD) $(CRASH_TEST_EXT_ARGS)
whitebox_crash_test_with_txn: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --txn whitebox --random_kill_odd \
$(CRASH_TEST_KILL_ODD) $(CRASH_TEST_EXT_ARGS)
whitebox_crash_test_with_ts: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --enable_ts whitebox --random_kill_odd \
@@ -160,8 +119,3 @@ whitebox_crash_test_with_tiered_storage: $(DB_STRESS_CMD)
whitebox_crash_test_with_optimistic_txn: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --optimistic_txn whitebox --random_kill_odd \
$(CRASH_TEST_KILL_ODD) $(CRASH_TEST_EXT_ARGS)
# Old names DEPRECATED
crash_test_with_txn: crash_test_with_wc_txn
whitebox_crash_test_with_txn: whitebox_crash_test_with_wc_txn
blackbox_crash_test_with_txn: blackbox_crash_test_with_wc_txn
+23 -27
View File
@@ -42,9 +42,9 @@ Status ArenaWrappedDBIter::GetProperty(std::string prop_name,
void ArenaWrappedDBIter::Init(
Env* env, const ReadOptions& read_options, const ImmutableOptions& ioptions,
const MutableCFOptions& mutable_cf_options, const Version* version,
const SequenceNumber& sequence, uint64_t version_number,
ReadCallback* read_callback, ColumnFamilyHandleImpl* cfh,
bool expose_blob_index, bool allow_refresh, ReadOnlyMemTable* active_mem) {
const SequenceNumber& sequence, uint64_t max_sequential_skip_in_iteration,
uint64_t version_number, ReadCallback* read_callback,
ColumnFamilyHandleImpl* cfh, bool expose_blob_index, bool allow_refresh) {
read_options_ = read_options;
if (!CheckFSFeatureSupport(env->GetFileSystem().get(),
FSSupportedOps::kAsyncIO)) {
@@ -52,14 +52,15 @@ void ArenaWrappedDBIter::Init(
}
read_options_.total_order_seek |= ioptions.prefix_seek_opt_in_only;
db_iter_ = DBIter::NewIter(
env, read_options_, ioptions, mutable_cf_options,
ioptions.user_comparator, /*internal_iter=*/nullptr, version, sequence,
read_callback, cfh, expose_blob_index, active_mem, &arena_);
auto mem = arena_.AllocateAligned(sizeof(DBIter));
db_iter_ = new (mem) DBIter(env, read_options_, ioptions, mutable_cf_options,
ioptions.user_comparator,
/* iter */ nullptr, version, sequence, true,
max_sequential_skip_in_iteration, read_callback,
cfh, expose_blob_index);
sv_number_ = version_number;
allow_refresh_ = allow_refresh;
allow_mark_memtable_for_flush_ = active_mem;
memtable_range_tombstone_iter_ = nullptr;
}
@@ -165,8 +166,9 @@ void ArenaWrappedDBIter::DoRefresh(const Snapshot* snapshot,
read_callback_->Refresh(read_seq);
}
Init(env, read_options_, cfd->ioptions(), sv->mutable_cf_options, sv->current,
read_seq, sv->version_number, read_callback_, cfh_, expose_blob_index_,
allow_refresh_, allow_mark_memtable_for_flush_ ? sv->mem : nullptr);
read_seq, sv->mutable_cf_options.max_sequential_skip_in_iterations,
sv->version_number, read_callback_, cfh_, expose_blob_index_,
allow_refresh_);
InternalIterator* internal_iter = db_impl->NewInternalIterator(
read_options_, cfd, sv, &arena_, read_seq,
@@ -251,26 +253,20 @@ Status ArenaWrappedDBIter::Refresh(const Snapshot* snapshot) {
}
ArenaWrappedDBIter* NewArenaWrappedDbIterator(
Env* env, const ReadOptions& read_options, ColumnFamilyHandleImpl* cfh,
SuperVersion* sv, const SequenceNumber& sequence,
ReadCallback* read_callback, DBImpl* db_impl, bool expose_blob_index,
bool allow_refresh, bool allow_mark_memtable_for_flush) {
ArenaWrappedDBIter* db_iter = new ArenaWrappedDBIter();
db_iter->Init(env, read_options, cfh->cfd()->ioptions(),
sv->mutable_cf_options, sv->current, sequence,
sv->version_number, read_callback, cfh, expose_blob_index,
allow_refresh,
allow_mark_memtable_for_flush ? sv->mem : nullptr);
Env* env, const ReadOptions& read_options, const ImmutableOptions& ioptions,
const MutableCFOptions& mutable_cf_options, const Version* version,
const SequenceNumber& sequence, uint64_t max_sequential_skip_in_iterations,
uint64_t version_number, ReadCallback* read_callback,
ColumnFamilyHandleImpl* cfh, bool expose_blob_index, bool allow_refresh) {
ArenaWrappedDBIter* iter = new ArenaWrappedDBIter();
iter->Init(env, read_options, ioptions, mutable_cf_options, version, sequence,
max_sequential_skip_in_iterations, version_number, read_callback,
cfh, expose_blob_index, allow_refresh);
if (cfh != nullptr && allow_refresh) {
db_iter->StoreRefreshInfo(cfh, read_callback, expose_blob_index);
iter->StoreRefreshInfo(cfh, read_callback, expose_blob_index);
}
InternalIterator* internal_iter = db_impl->NewInternalIterator(
db_iter->GetReadOptions(), cfh->cfd(), sv, db_iter->GetArena(), sequence,
/*allow_unprepared_value=*/true, db_iter);
db_iter->SetIterUnderDBIter(internal_iter);
return db_iter;
return iter;
}
} // namespace ROCKSDB_NAMESPACE
+13 -14
View File
@@ -19,6 +19,7 @@
#include "options/cf_options.h"
#include "rocksdb/db.h"
#include "rocksdb/iterator.h"
#include "util/autovector.h"
namespace ROCKSDB_NAMESPACE {
@@ -98,19 +99,13 @@ class ArenaWrappedDBIter : public Iterator {
bool PrepareValue() override { return db_iter_->PrepareValue(); }
void Prepare(const std::vector<ScanOptions>& scan_opts) override {
db_iter_->Prepare(scan_opts);
}
// FIXME: we could just pass SV in for mutable cf option, version and version
// number, but this is used by SstFileReader which does not have a SV.
void Init(Env* env, const ReadOptions& read_options,
const ImmutableOptions& ioptions,
const MutableCFOptions& mutable_cf_options, const Version* version,
const SequenceNumber& sequence, uint64_t version_number,
const SequenceNumber& sequence,
uint64_t max_sequential_skip_in_iterations, uint64_t version_number,
ReadCallback* read_callback, ColumnFamilyHandleImpl* cfh,
bool expose_blob_index, bool allow_refresh,
ReadOnlyMemTable* active_mem);
bool expose_blob_index, bool allow_refresh);
// Store some parameters so we can refresh the iterator at a later point
// with these same params
@@ -133,16 +128,20 @@ class ArenaWrappedDBIter : public Iterator {
ReadCallback* read_callback_;
bool expose_blob_index_ = false;
bool allow_refresh_ = true;
bool allow_mark_memtable_for_flush_ = true;
// If this is nullptr, it means the mutable memtable does not contain range
// tombstone when added under this DBIter.
std::unique_ptr<TruncatedRangeDelIterator>* memtable_range_tombstone_iter_ =
nullptr;
};
// Generate the arena wrapped iterator class.
// `cfh` is used for reneweal. If left null, renewal will not
// be supported.
ArenaWrappedDBIter* NewArenaWrappedDbIterator(
Env* env, const ReadOptions& read_options, ColumnFamilyHandleImpl* cfh,
SuperVersion* sv, const SequenceNumber& sequence,
ReadCallback* read_callback, DBImpl* db_impl, bool expose_blob_index,
bool allow_refresh, bool allow_mark_memtable_for_flush);
Env* env, const ReadOptions& read_options, const ImmutableOptions& ioptions,
const MutableCFOptions& mutable_cf_options, const Version* version,
const SequenceNumber& sequence, uint64_t max_sequential_skip_in_iterations,
uint64_t version_number, ReadCallback* read_callback,
ColumnFamilyHandleImpl* cfh = nullptr, bool expose_blob_index = false,
bool allow_refresh = true);
} // namespace ROCKSDB_NAMESPACE
+10 -10
View File
@@ -3295,16 +3295,6 @@ uint64_t rocksdb_options_get_periodic_compaction_seconds(
return opt->rep.periodic_compaction_seconds;
}
void rocksdb_options_set_memtable_op_scan_flush_trigger(rocksdb_options_t* opt,
uint32_t n) {
opt->rep.memtable_op_scan_flush_trigger = n;
}
uint32_t rocksdb_options_get_memtable_op_scan_flush_trigger(
rocksdb_options_t* opt) {
return opt->rep.memtable_op_scan_flush_trigger;
}
void rocksdb_options_enable_statistics(rocksdb_options_t* opt) {
opt->rep.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
}
@@ -3814,6 +3804,16 @@ int rocksdb_options_get_min_write_buffer_number_to_merge(
return opt->rep.min_write_buffer_number_to_merge;
}
void rocksdb_options_set_max_write_buffer_number_to_maintain(
rocksdb_options_t* opt, int n) {
opt->rep.max_write_buffer_number_to_maintain = n;
}
int rocksdb_options_get_max_write_buffer_number_to_maintain(
rocksdb_options_t* opt) {
return opt->rep.max_write_buffer_number_to_maintain;
}
void rocksdb_options_set_max_write_buffer_size_to_maintain(
rocksdb_options_t* opt, int64_t n) {
opt->rep.max_write_buffer_size_to_maintain = n;
+12 -10
View File
@@ -2129,10 +2129,6 @@ int main(int argc, char** argv) {
CheckCondition(100000 ==
rocksdb_options_get_periodic_compaction_seconds(o));
rocksdb_options_set_memtable_op_scan_flush_trigger(o, 100);
CheckCondition(100 ==
rocksdb_options_get_memtable_op_scan_flush_trigger(o));
rocksdb_options_set_ttl(o, 5000);
CheckCondition(5000 == rocksdb_options_get_ttl(o));
@@ -2150,6 +2146,10 @@ int main(int argc, char** argv) {
CheckCondition(23 ==
rocksdb_options_get_min_write_buffer_number_to_merge(o));
rocksdb_options_set_max_write_buffer_number_to_maintain(o, 64);
CheckCondition(64 ==
rocksdb_options_get_max_write_buffer_number_to_maintain(o));
rocksdb_options_set_max_write_buffer_size_to_maintain(o, 50000);
CheckCondition(50000 ==
rocksdb_options_get_max_write_buffer_size_to_maintain(o));
@@ -2407,6 +2407,8 @@ int main(int argc, char** argv) {
CheckCondition(97 == rocksdb_options_get_max_write_buffer_number(copy));
CheckCondition(23 ==
rocksdb_options_get_min_write_buffer_number_to_merge(copy));
CheckCondition(
64 == rocksdb_options_get_max_write_buffer_number_to_maintain(copy));
CheckCondition(50000 ==
rocksdb_options_get_max_write_buffer_size_to_maintain(copy));
CheckCondition(1 == rocksdb_options_get_enable_pipelined_write(copy));
@@ -2570,12 +2572,6 @@ int main(int argc, char** argv) {
CheckCondition(100000 ==
rocksdb_options_get_periodic_compaction_seconds(o));
rocksdb_options_set_memtable_op_scan_flush_trigger(copy, 800);
CheckCondition(800 ==
rocksdb_options_get_memtable_op_scan_flush_trigger(copy));
CheckCondition(100 ==
rocksdb_options_get_memtable_op_scan_flush_trigger(o));
rocksdb_options_set_ttl(copy, 8000);
CheckCondition(8000 == rocksdb_options_get_ttl(copy));
CheckCondition(5000 == rocksdb_options_get_ttl(o));
@@ -2600,6 +2596,12 @@ int main(int argc, char** argv) {
CheckCondition(23 ==
rocksdb_options_get_min_write_buffer_number_to_merge(o));
rocksdb_options_set_max_write_buffer_number_to_maintain(copy, 128);
CheckCondition(
128 == rocksdb_options_get_max_write_buffer_number_to_maintain(copy));
CheckCondition(64 ==
rocksdb_options_get_max_write_buffer_number_to_maintain(o));
rocksdb_options_set_max_write_buffer_size_to_maintain(copy, 9000);
CheckCondition(9000 ==
rocksdb_options_get_max_write_buffer_size_to_maintain(copy));
+6 -7
View File
@@ -262,10 +262,15 @@ ColumnFamilyOptions SanitizeCfOptions(const ImmutableDBOptions& db_options,
if (result.max_write_buffer_number < 2) {
result.max_write_buffer_number = 2;
}
// fall back max_write_buffer_number_to_maintain if
// max_write_buffer_size_to_maintain is not set
if (result.max_write_buffer_size_to_maintain < 0) {
result.max_write_buffer_size_to_maintain =
result.max_write_buffer_number *
static_cast<int64_t>(result.write_buffer_size);
} else if (result.max_write_buffer_size_to_maintain == 0 &&
result.max_write_buffer_number_to_maintain < 0) {
result.max_write_buffer_number_to_maintain = result.max_write_buffer_number;
}
// bloom filter size shouldn't exceed 1/4 of memtable size.
if (result.memtable_prefix_bloom_size_ratio > 0.25) {
@@ -448,13 +453,6 @@ ColumnFamilyOptions SanitizeCfOptions(const ImmutableDBOptions& db_options,
result.preclude_last_level_data_seconds = 0;
}
if (read_only && result.memtable_op_scan_flush_trigger != 0) {
ROCKS_LOG_WARN(db_options.info_log.get(),
"option memtable_op_scan_flush_trigger is sanitized to "
"0(disabled) for read only DB.");
result.memtable_op_scan_flush_trigger = 0;
}
return result;
}
@@ -579,6 +577,7 @@ ColumnFamilyData::ColumnFamilyData(
write_buffer_manager_(write_buffer_manager),
mem_(nullptr),
imm_(ioptions_.min_write_buffer_number_to_merge,
ioptions_.max_write_buffer_number_to_maintain,
ioptions_.max_write_buffer_size_to_maintain),
super_version_(nullptr),
super_version_number_(0),
-11
View File
@@ -537,12 +537,6 @@ class ColumnFamilyData {
assert(!ts_low.empty());
const Comparator* ucmp = user_comparator();
assert(ucmp);
// Guard against resurrected full_history_ts_low persisted in MANIFEST
// from previous DB sessions. This could happen if UDT was enabled and then
// disabled.
if (ucmp->timestamp_size() == 0) {
return;
}
if (full_history_ts_low_.empty() ||
ucmp->CompareTimestamp(ts_low, full_history_ts_low_) > 0) {
full_history_ts_low_ = std::move(ts_low);
@@ -550,11 +544,6 @@ class ColumnFamilyData {
}
const std::string& GetFullHistoryTsLow() const {
const Comparator* ucmp = user_comparator();
assert(ucmp);
if (ucmp->timestamp_size() == 0) {
assert(full_history_ts_low_.empty());
}
return full_history_ts_low_;
}
+2 -1
View File
@@ -72,6 +72,7 @@ class ColumnFamilyTestBase : public testing::Test {
env_->skip_fsync_ = true;
dbname_ = test::PerThreadDBPath("column_family_test");
db_options_.create_if_missing = true;
db_options_.fail_if_options_file_error = true;
db_options_.env = env_;
}
@@ -2175,7 +2176,7 @@ TEST_P(ColumnFamilyTest, FlushStaleColumnFamilies) {
ASSERT_TRUE(has_cf2_sst);
ASSERT_OK(Flush(0));
ASSERT_EQ(0, dbfull()->TEST_wals_total_size());
ASSERT_EQ(0, dbfull()->TEST_total_log_size());
Close();
}
+2 -5
View File
@@ -77,9 +77,7 @@ CompactionJob::ProcessKeyValueCompactionWithCompactionService(
dbname_, db_id_, db_session_id_, GetCompactionId(sub_compact),
thread_pri_, compaction->compaction_reason(),
compaction->is_full_compaction(), compaction->is_manual_compaction(),
compaction->bottommost_level(), compaction->start_level(),
compaction->output_level());
compaction->bottommost_level());
CompactionServiceScheduleResponse response =
db_options_.compaction_service->Schedule(info, compaction_input_binary);
switch (response.status) {
@@ -242,8 +240,7 @@ CompactionJob::ProcessKeyValueCompactionWithCompactionService(
meta.marked_for_compaction = file.marked_for_compaction;
meta.unique_id = file.unique_id;
meta.temperature = file.file_temperature;
meta.tail_size =
FileMetaData::CalculateTailSize(file_size, file.table_properties);
auto cfd = compaction->column_family_data();
CompactionOutputs* compaction_outputs =
sub_compact->Outputs(file.is_proximal_level_output);
+15 -70
View File
@@ -22,9 +22,9 @@ class MyTestCompactionService : public CompactionService {
options_(options),
statistics_(statistics),
start_info_("na", "na", "na", 0, Env::TOTAL, CompactionReason::kUnknown,
false, false, false, -1, -1),
false, false, false),
wait_info_("na", "na", "na", 0, Env::TOTAL, CompactionReason::kUnknown,
false, false, false, -1, -1),
false, false, false),
listeners_(listeners),
table_properties_collector_factories_(
std::move(table_properties_collector_factories)) {}
@@ -84,7 +84,6 @@ class MyTestCompactionService : public CompactionService {
options_override.table_factory = options_.table_factory;
options_override.sst_partitioner_factory = options_.sst_partitioner_factory;
options_override.statistics = statistics_;
options_override.info_log = options_.info_log;
if (!listeners_.empty()) {
options_override.listeners = listeners_;
}
@@ -278,17 +277,8 @@ TEST_F(CompactionServiceTest, BasicCompactions) {
Statistics* primary_statistics = GetPrimaryStatistics();
Statistics* compactor_statistics = GetCompactorStatistics();
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"BlockBasedTable::PrefetchTail::TaiSizeNotRecorded",
[&](void* /* arg */) {
// Trigger assertion to verify precise tail prefetch size calculation
assert(false);
});
SyncPoint::GetInstance()->EnableProcessing();
GenerateTestData();
ASSERT_OK(dbfull()->TEST_WaitForCompact());
SyncPoint::GetInstance()->DisableProcessing();
VerifyTestData();
auto my_cs = GetCompactionService();
@@ -390,7 +380,6 @@ TEST_F(CompactionServiceTest, BasicCompactions) {
ASSERT_FALSE(result.stats.is_full_compaction);
Close();
SyncPoint::GetInstance()->DisableProcessing();
}
TEST_F(CompactionServiceTest, ManualCompaction) {
@@ -901,12 +890,6 @@ TEST_F(CompactionServiceTest, TruncatedOutput) {
Slice end(end_str);
uint64_t comp_num = my_cs->GetCompactionNum();
// Skip calculating tail size to avoid crashing due to truncated file size
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"FileMetaData::CalculateTailSize", [&](void* arg) {
bool* skip = static_cast<bool*>(arg);
*skip = true;
});
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"CompactionServiceCompactionJob::Run:0", [&](void* arg) {
CompactionServiceResult* compaction_result =
@@ -923,7 +906,7 @@ TEST_F(CompactionServiceTest, TruncatedOutput) {
ASSERT_OK(s);
ASSERT_GT(file_size, 0);
ASSERT_OK(test::TruncateFile(env_, file_name, file_size / 4));
ASSERT_OK(test::TruncateFile(env_, file_name, file_size / 2));
}
});
SyncPoint::GetInstance()->EnableProcessing();
@@ -1267,31 +1250,17 @@ TEST_F(CompactionServiceTest, PrecludeLastLevel) {
// Verify Output Stats
auto my_cs = GetCompactionService();
{
CompactionServiceResult result;
my_cs->GetResult(&result);
ASSERT_OK(result.status);
ASSERT_GT(result.internal_stats.output_level_stats.cpu_micros, 0);
ASSERT_GT(result.internal_stats.output_level_stats.micros, 0);
ASSERT_EQ(result.internal_stats.output_level_stats.num_output_records +
result.internal_stats.proximal_level_stats.num_output_records,
kNumTrigger * kNumKeys);
ASSERT_EQ(result.internal_stats.output_level_stats.num_output_files +
result.internal_stats.proximal_level_stats.num_output_files,
2);
CompactionServiceJobInfo info = my_cs->GetCompactionInfoForStart();
ASSERT_EQ(0, info.base_input_level);
ASSERT_EQ(kNumLevels - 1, info.output_level);
}
SyncPoint::GetInstance()->DisableProcessing();
// Disable Preclude feature and run full compaction to the bottommost level
{
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
CompactionServiceJobInfo info = my_cs->GetCompactionInfoForStart();
ASSERT_EQ(kNumLevels - 2, info.base_input_level);
ASSERT_EQ(kNumLevels - 1, info.output_level);
}
CompactionServiceResult result;
my_cs->GetResult(&result);
ASSERT_OK(result.status);
ASSERT_GT(result.internal_stats.output_level_stats.cpu_micros, 0);
ASSERT_GT(result.internal_stats.output_level_stats.micros, 0);
ASSERT_EQ(result.internal_stats.output_level_stats.num_output_records +
result.internal_stats.proximal_level_stats.num_output_records,
kNumTrigger * kNumKeys);
ASSERT_EQ(result.internal_stats.output_level_stats.num_output_files +
result.internal_stats.proximal_level_stats.num_output_files,
2);
}
TEST_F(CompactionServiceTest, ConcurrentCompaction) {
@@ -1361,16 +1330,12 @@ TEST_F(CompactionServiceTest, CompactionInfo) {
ASSERT_EQ(true, info.is_manual_compaction);
ASSERT_EQ(false, info.is_full_compaction);
ASSERT_EQ(true, info.bottommost_level);
ASSERT_EQ(1, info.base_input_level);
ASSERT_EQ(2, info.output_level);
info = my_cs->GetCompactionInfoForWait();
ASSERT_EQ(Env::USER, info.priority);
ASSERT_EQ(CompactionReason::kManualCompaction, info.compaction_reason);
ASSERT_EQ(true, info.is_manual_compaction);
ASSERT_EQ(false, info.is_full_compaction);
ASSERT_EQ(true, info.bottommost_level);
ASSERT_EQ(1, info.base_input_level);
ASSERT_EQ(2, info.output_level);
// Test priority BOTTOM
env_->SetBackgroundThreads(1, Env::BOTTOM);
@@ -1402,24 +1367,18 @@ TEST_F(CompactionServiceTest, CompactionInfo) {
ASSERT_EQ(false, info.is_full_compaction);
ASSERT_EQ(true, info.bottommost_level);
ASSERT_EQ(Env::BOTTOM, info.priority);
ASSERT_EQ(0, info.base_input_level);
ASSERT_EQ(db_->NumberLevels() - 1, info.output_level);
info = my_cs->GetCompactionInfoForWait();
ASSERT_EQ(Env::BOTTOM, info.priority);
ASSERT_EQ(CompactionReason::kLevelL0FilesNum, info.compaction_reason);
ASSERT_EQ(false, info.is_manual_compaction);
ASSERT_EQ(false, info.is_full_compaction);
ASSERT_EQ(true, info.bottommost_level);
ASSERT_EQ(0, info.base_input_level);
ASSERT_EQ(db_->NumberLevels() - 1, info.output_level);
// Test Non-Bottommost Level
options.num_levels = 4;
ReopenWithCompactionService(&options);
my_cs =
static_cast_with_check<MyTestCompactionService>(GetCompactionService());
int compaction_num = my_cs->GetCompactionNum();
ASSERT_EQ(0, compaction_num);
for (int i = 0; i < options.level0_file_num_compaction_trigger; i++) {
for (int j = 0; j < 10; j++) {
@@ -1428,22 +1387,16 @@ TEST_F(CompactionServiceTest, CompactionInfo) {
}
ASSERT_OK(Flush());
}
ASSERT_OK(dbfull()->TEST_WaitForCompact());
// This is trivial move. Done locally.
ASSERT_EQ(0, my_cs->GetCompactionNum());
ASSERT_OK(dbfull()->TEST_WaitForCompact());
info = my_cs->GetCompactionInfoForStart();
ASSERT_EQ(false, info.is_manual_compaction);
ASSERT_EQ(false, info.is_full_compaction);
ASSERT_EQ(false, info.bottommost_level);
ASSERT_EQ(-1, info.base_input_level);
ASSERT_EQ(-1, info.output_level);
info = my_cs->GetCompactionInfoForWait();
ASSERT_EQ(false, info.is_manual_compaction);
ASSERT_EQ(false, info.is_full_compaction);
ASSERT_EQ(false, info.bottommost_level);
ASSERT_EQ(-1, info.base_input_level);
ASSERT_EQ(-1, info.output_level);
// Test Full Compaction + Bottommost Level
options.num_levels = 6;
@@ -1458,10 +1411,7 @@ TEST_F(CompactionServiceTest, CompactionInfo) {
}
ASSERT_OK(Flush());
}
MoveFilesToLevel(options.num_levels - 1);
// Force final level compaction
// base_input_level == output_level == last_level
CompactRangeOptions cro;
cro.bottommost_level_compaction = BottommostLevelCompaction::kForce;
ASSERT_OK(db_->CompactRange(cro, nullptr, nullptr));
@@ -1473,15 +1423,10 @@ TEST_F(CompactionServiceTest, CompactionInfo) {
ASSERT_EQ(true, info.bottommost_level);
ASSERT_EQ(CompactionReason::kManualCompaction, info.compaction_reason);
info = my_cs->GetCompactionInfoForWait();
ASSERT_EQ(options.num_levels - 1, info.base_input_level);
ASSERT_EQ(options.num_levels - 1, info.output_level);
ASSERT_EQ(true, info.is_manual_compaction);
ASSERT_EQ(true, info.is_full_compaction);
ASSERT_EQ(true, info.bottommost_level);
ASSERT_EQ(CompactionReason::kManualCompaction, info.compaction_reason);
ASSERT_EQ(options.num_levels - 1, info.base_input_level);
ASSERT_EQ(options.num_levels - 1, info.output_level);
ASSERT_EQ("0,0,0,0,0,1", FilesPerLevel());
}
TEST_F(CompactionServiceTest, FallbackLocalAuto) {
+14 -10
View File
@@ -75,9 +75,11 @@ Status DBImpl::GetLiveFiles(std::vector<std::string>& ret,
ret.emplace_back(CurrentFileName(""));
ret.emplace_back(DescriptorFileName("", versions_->manifest_file_number()));
// In read-only mode the OPTIONS file number is zero when no OPTIONS file
// exist at all. In this cases we do not record any OPTIONS file in the live
// file list.
// The OPTIONS file number is zero in read-write mode when OPTIONS file
// writing failed and the DB was configured with
// `fail_if_options_file_error == false`. In read-only mode the OPTIONS file
// number is zero when no OPTIONS file exist at all. In those cases we do not
// record any OPTIONS file in the live file list.
if (versions_->options_file_number() != 0) {
ret.emplace_back(OptionsFileName("", versions_->options_file_number()));
}
@@ -183,14 +185,14 @@ Status DBImpl::GetSortedWalFilesImpl(VectorWalPtr& files, bool need_seqnos) {
return s;
}
Status DBImpl::GetCurrentWalFile(std::unique_ptr<WalFile>* current_wal_file) {
Status DBImpl::GetCurrentWalFile(std::unique_ptr<WalFile>* current_log_file) {
uint64_t current_logfile_number;
{
InstrumentedMutexLock l(&mutex_);
current_logfile_number = cur_wal_number_;
current_logfile_number = logfile_number_;
}
return wal_manager_.GetLiveWalFile(current_logfile_number, current_wal_file);
return wal_manager_.GetLiveWalFile(current_logfile_number, current_log_file);
}
Status DBImpl::GetLiveFilesStorageInfo(
@@ -330,7 +332,7 @@ Status DBImpl::GetLiveFilesStorageInfo(
const uint64_t options_size = versions_->options_file_size_;
const uint64_t min_log_num = MinLogNumberToKeep();
// Ensure consistency with manifest for track_and_verify_wals_in_manifest
const uint64_t max_log_num = cur_wal_number_;
const uint64_t max_log_num = logfile_number_;
mutex_.Unlock();
@@ -367,9 +369,11 @@ Status DBImpl::GetLiveFilesStorageInfo(
}
}
// In read-only mode the OPTIONS file number is zero when no OPTIONS file
// exist at all. In this cases we do not record any OPTIONS file in the live
// file list.
// The OPTIONS file number is zero in read-write mode when OPTIONS file
// writing failed and the DB was configured with
// `fail_if_options_file_error == false`. In read-only mode the OPTIONS file
// number is zero when no OPTIONS file exist at all. In those cases we do not
// record any OPTIONS file in the live file list.
if (options_number != 0) {
results.emplace_back();
LiveFileStorageInfo& info = results.back();
+102 -121
View File
@@ -74,7 +74,6 @@
#include "options/cf_options.h"
#include "options/options_helper.h"
#include "options/options_parser.h"
#include "util/udt_util.h"
#ifdef ROCKSDB_JEMALLOC
#include "port/jemalloc_helper.h"
#endif
@@ -170,6 +169,7 @@ DBImpl::DBImpl(const DBOptions& options, const std::string& dbname,
bool read_only)
: dbname_(dbname),
own_info_log_(options.info_log == nullptr),
init_logger_creation_s_(),
initial_db_options_(SanitizeOptions(dbname, options, read_only,
&init_logger_creation_s_)),
env_(initial_db_options_.env),
@@ -185,6 +185,7 @@ DBImpl::DBImpl(const DBOptions& options, const std::string& dbname,
mutex_(stats_, immutable_db_options_.clock, DB_MUTEX_WAIT_MICROS,
immutable_db_options_.use_adaptive_mutex),
#endif // COERCE_CONTEXT_SWITCH
default_cf_handle_(nullptr),
error_handler_(this, immutable_db_options_, &mutex_),
event_logger_(immutable_db_options_.info_log.get()),
max_total_in_memory_state_(0),
@@ -193,15 +194,45 @@ DBImpl::DBImpl(const DBOptions& options, const std::string& dbname,
file_options_, immutable_db_options_)),
seq_per_batch_(seq_per_batch),
batch_per_txn_(batch_per_txn),
next_job_id_(1),
shutting_down_(false),
reject_new_background_jobs_(false),
db_lock_(nullptr),
manual_compaction_paused_(false),
bg_cv_(&mutex_),
wal_sync_cv_(&wal_write_mutex_),
logfile_number_(0),
log_dir_synced_(false),
log_empty_(true),
persist_stats_cf_handle_(nullptr),
log_sync_cv_(&log_write_mutex_),
total_log_size_(0),
is_snapshot_supported_(true),
write_buffer_manager_(immutable_db_options_.write_buffer_manager.get()),
write_thread_(immutable_db_options_),
nonmem_write_thread_(immutable_db_options_),
write_controller_(mutable_db_options_.delayed_write_rate),
last_batch_group_size_(0),
unscheduled_flushes_(0),
unscheduled_compactions_(0),
bg_bottom_compaction_scheduled_(0),
bg_compaction_scheduled_(0),
num_running_compactions_(0),
bg_flush_scheduled_(0),
num_running_flushes_(0),
bg_purge_scheduled_(0),
disable_delete_obsolete_files_(0),
pending_purge_obsolete_files_(0),
delete_obsolete_files_last_run_(immutable_db_options_.clock->NowMicros()),
has_unpersisted_data_(false),
unable_to_release_oldest_log_(false),
num_running_ingest_file_(0),
wal_manager_(immutable_db_options_, file_options_, io_tracer_,
seq_per_batch),
bg_work_paused_(0),
bg_compaction_paused_(0),
refitting_level_(false),
opened_successfully_(false),
periodic_task_scheduler_(),
two_write_queues_(options.two_write_queues),
manual_wal_flush_(options.manual_wal_flush),
// last_sequencee_ is always maintained by the main queue that also writes
@@ -219,11 +250,14 @@ DBImpl::DBImpl(const DBOptions& options, const std::string& dbname,
// requires a custom gc for compaction, we use that to set use_custom_gc_
// as well.
use_custom_gc_(seq_per_batch),
shutdown_initiated_(false),
own_sfm_(options.sst_file_manager == nullptr),
closed_(false),
atomic_flush_install_cv_(&mutex_),
blob_callback_(immutable_db_options_.sst_file_manager.get(), &mutex_,
&error_handler_, &event_logger_,
immutable_db_options_.listeners, dbname_) {
immutable_db_options_.listeners, dbname_),
lock_wal_count_(0) {
// !batch_per_trx_ implies seq_per_batch_ because it is only unset for
// WriteUnprepared, which should use seq_per_batch_.
assert(batch_per_txn_ || seq_per_batch_);
@@ -602,8 +636,8 @@ Status DBImpl::CloseHelper() {
mutex_.Lock();
}
{
InstrumentedMutexLock lock(&wal_write_mutex_);
for (auto l : wals_to_free_) {
InstrumentedMutexLock lock(&log_write_mutex_);
for (auto l : logs_to_free_) {
delete l;
}
for (auto& log : logs_) {
@@ -1146,11 +1180,11 @@ Status DBImpl::TablesRangeTombstoneSummary(ColumnFamilyHandle* column_family,
void DBImpl::ScheduleBgLogWriterClose(JobContext* job_context) {
mutex_.AssertHeld();
if (!job_context->wals_to_free.empty()) {
for (auto l : job_context->wals_to_free) {
if (!job_context->logs_to_free.empty()) {
for (auto l : job_context->logs_to_free) {
AddToLogsToFreeQueue(l);
}
job_context->wals_to_free.clear();
job_context->logs_to_free.clear();
}
}
@@ -1409,7 +1443,7 @@ Status DBImpl::SetDBOptions(
WriteThread::Writer w;
write_thread_.EnterUnbatched(&w, &mutex_);
if (wal_other_option_changed ||
wals_total_size_.LoadRelaxed() > GetMaxTotalWalSize()) {
total_log_size_ > GetMaxTotalWalSize()) {
Status purge_wal_status = SwitchWAL(&write_context);
if (!purge_wal_status.ok()) {
ROCKS_LOG_WARN(immutable_db_options_.info_log,
@@ -1436,9 +1470,14 @@ Status DBImpl::SetDBOptions(
ROCKS_LOG_INFO(immutable_db_options_.info_log, "SetDBOptions() succeeded");
new_options.Dump(immutable_db_options_.info_log.get());
if (!persist_options_status.ok()) {
s = Status::IOError(
"SetDBOptions() succeeded, but unable to persist options",
persist_options_status.ToString());
if (immutable_db_options_.fail_if_options_file_error) {
s = Status::IOError(
"SetDBOptions() succeeded, but unable to persist options",
persist_options_status.ToString());
}
ROCKS_LOG_WARN(immutable_db_options_.info_log,
"Unable to persist options in SetDBOptions() -- %s",
persist_options_status.ToString().c_str());
}
} else {
ROCKS_LOG_WARN(immutable_db_options_.info_log, "SetDBOptions failed");
@@ -1473,8 +1512,8 @@ Status DBImpl::FlushWAL(const WriteOptions& write_options, bool sync) {
if (manual_wal_flush_) {
IOStatus io_s;
{
// We need to lock wal_write_mutex_ since logs_ might change concurrently
InstrumentedMutexLock wl(&wal_write_mutex_);
// We need to lock log_write_mutex_ since logs_ might change concurrently
InstrumentedMutexLock wl(&log_write_mutex_);
log::Writer* cur_log_writer = logs_.back().writer;
io_s = cur_log_writer->WriteBuffer(write_options);
}
@@ -1501,7 +1540,7 @@ Status DBImpl::FlushWAL(const WriteOptions& write_options, bool sync) {
}
bool DBImpl::WALBufferIsEmpty() {
InstrumentedMutexLock l(&wal_write_mutex_);
InstrumentedMutexLock l(&log_write_mutex_);
log::Writer* cur_log_writer = logs_.back().writer;
auto res = cur_log_writer->BufferIsEmpty();
return res;
@@ -1509,7 +1548,7 @@ bool DBImpl::WALBufferIsEmpty() {
Status DBImpl::GetOpenWalSizes(std::map<uint64_t, uint64_t>& number_to_size) {
assert(number_to_size.empty());
InstrumentedMutexLock l(&wal_write_mutex_);
InstrumentedMutexLock l(&log_write_mutex_);
for (auto& log : logs_) {
auto* open_file = log.writer->file();
if (open_file) {
@@ -1551,15 +1590,15 @@ IOStatus DBImpl::SyncWalImpl(bool include_current_wal,
uint64_t up_to_number;
{
InstrumentedMutexLock l(&wal_write_mutex_);
InstrumentedMutexLock l(&log_write_mutex_);
assert(!logs_.empty());
maybe_active_number = cur_wal_number_;
maybe_active_number = logfile_number_;
up_to_number =
include_current_wal ? maybe_active_number : maybe_active_number - 1;
while (logs_.front().number <= up_to_number && logs_.front().IsSyncing()) {
wal_sync_cv_.Wait();
log_sync_cv_.Wait();
}
// First check that logs are safe to sync in background.
if (include_current_wal &&
@@ -1583,7 +1622,7 @@ IOStatus DBImpl::SyncWalImpl(bool include_current_wal,
}
}
need_wal_dir_sync = !wal_dir_synced_;
need_wal_dir_sync = !log_dir_synced_;
}
if (include_current_wal) {
@@ -1656,7 +1695,7 @@ IOStatus DBImpl::SyncWalImpl(bool include_current_wal,
/*arg=*/nullptr);
}
{
InstrumentedMutexLock l(&wal_write_mutex_);
InstrumentedMutexLock l(&log_write_mutex_);
for (auto* wal : wals_internally_closed) {
// We can only modify the state of log::Writer under the mutex
bool was_closed = wal->PublishIfClosed();
@@ -1773,9 +1812,9 @@ Status DBImpl::UnlockWAL() {
void DBImpl::MarkLogsSynced(uint64_t up_to, bool synced_dir,
VersionEdit* synced_wals) {
wal_write_mutex_.AssertHeld();
if (synced_dir && cur_wal_number_ == up_to) {
wal_dir_synced_ = true;
log_write_mutex_.AssertHeld();
if (synced_dir && logfile_number_ == up_to) {
log_dir_synced_ = true;
}
for (auto it = logs_.begin(); it != logs_.end() && it->number <= up_to;) {
auto& wal = *it;
@@ -1797,7 +1836,7 @@ void DBImpl::MarkLogsSynced(uint64_t up_to, bool synced_dir,
(immutable_db_options_.background_close_inactive_wals &&
wal.GetPreSyncSize() == wal.writer->file()->GetFlushedSize())) {
// Fully synced
wals_to_free_.push_back(wal.ReleaseWriter());
logs_to_free_.push_back(wal.ReleaseWriter());
it = logs_.erase(it);
} else {
wal.FinishSync();
@@ -1810,17 +1849,17 @@ void DBImpl::MarkLogsSynced(uint64_t up_to, bool synced_dir,
++it;
}
}
wal_sync_cv_.SignalAll();
log_sync_cv_.SignalAll();
}
void DBImpl::MarkLogsNotSynced(uint64_t up_to) {
wal_write_mutex_.AssertHeld();
log_write_mutex_.AssertHeld();
for (auto it = logs_.begin(); it != logs_.end() && it->number <= up_to;
++it) {
auto& wal = *it;
wal.FinishSync();
}
wal_sync_cv_.SignalAll();
log_sync_cv_.SignalAll();
}
SequenceNumber DBImpl::GetLatestSequenceNumber() const {
@@ -1856,69 +1895,6 @@ Status DBImpl::GetFullHistoryTsLow(ColumnFamilyHandle* column_family,
return Status::OK();
}
Status DBImpl::GetNewestUserDefinedTimestamp(ColumnFamilyHandle* column_family,
std::string* newest_timestamp) {
if (newest_timestamp == nullptr) {
return Status::InvalidArgument("newest_timestamp is nullptr");
}
ColumnFamilyData* cfd = nullptr;
if (column_family == nullptr) {
cfd = default_cf_handle_->cfd();
} else {
auto cfh = static_cast_with_check<ColumnFamilyHandleImpl>(column_family);
assert(cfh != nullptr);
cfd = cfh->cfd();
}
assert(cfd != nullptr && cfd->user_comparator() != nullptr);
if (cfd->user_comparator()->timestamp_size() == 0) {
return Status::InvalidArgument(
"Timestamp is not enabled in this column family");
}
if (cfd->ioptions().persist_user_defined_timestamps) {
return Status::NotSupported(
"GetNewestUserDefinedTimestamp doesn't support the case when user"
"defined timestamps are persisted.");
}
Status status;
// Acquire SuperVersion
SuperVersion* sv = GetAndRefSuperVersion(cfd);
{
InstrumentedMutexLock l(&mutex_);
bool enter_write_thread = sv->mem == cfd->mem();
WriteThread::Writer w;
// Enter write thread to read the mutable memtable to avoid racing access
// with concurrent writes. No need to enter nonmem_write_thread_ since this
// call only care about memtable writes, not WAL writes.
if (enter_write_thread) {
write_thread_.EnterUnbatched(&w, &mutex_);
WaitForPendingWrites();
}
*newest_timestamp = sv->mem->GetNewestUDT().ToString();
assert(!newest_timestamp->empty() || sv->mem->IsEmpty());
if (enter_write_thread) {
write_thread_.ExitUnbatched(&w);
}
}
// Read from immutable memtables if nothing found in mutable memtable.
if (newest_timestamp->empty()) {
*newest_timestamp = sv->imm->GetNewestUDT().ToString();
}
// Read from SST files if no result can be found in memtables.
if (newest_timestamp->empty() && sv->current->GetSstFilesSize() != 0) {
// full_history_ts_low is used to track the exclusive upperbound of
// flushed user defined timestamp. So we can use it to deduce the newest
// timestamp in the SST files that the column family has seen.
Slice full_history_ts_low = sv->full_history_ts_low;
if (!full_history_ts_low.empty()) {
GetU64CutoffTsFromFullHistoryTsLow(&full_history_ts_low,
newest_timestamp);
}
}
ReturnAndCleanupSuperVersion(cfd, sv);
return status;
}
InternalIterator* DBImpl::NewInternalIterator(const ReadOptions& read_options,
Arena* arena,
SequenceNumber sequence,
@@ -1952,10 +1928,10 @@ void DBImpl::BackgroundCallPurge() {
TEST_SYNC_POINT("DBImpl::BackgroundCallPurge:beforeMutexLock");
mutex_.Lock();
while (!wals_to_free_queue_.empty()) {
assert(!wals_to_free_queue_.empty());
log::Writer* log_writer = *(wals_to_free_queue_.begin());
wals_to_free_queue_.pop_front();
while (!logs_to_free_queue_.empty()) {
assert(!logs_to_free_queue_.empty());
log::Writer* log_writer = *(logs_to_free_queue_.begin());
logs_to_free_queue_.pop_front();
mutex_.Unlock();
delete log_writer;
mutex_.Lock();
@@ -3621,7 +3597,7 @@ Status DBImpl::CreateColumnFamilyImpl(const ReadOptions& read_options,
edit.AddColumnFamily(column_family_name);
uint32_t new_id = versions_->GetColumnFamilySet()->GetNextColumnFamilyID();
edit.SetColumnFamily(new_id);
edit.SetLogNumber(cur_wal_number_);
edit.SetLogNumber(logfile_number_);
edit.SetComparatorName(cf_options.comparator->Name());
edit.SetPersistUserDefinedTimestamps(
cf_options.persist_user_defined_timestamps);
@@ -3820,16 +3796,6 @@ bool DBImpl::KeyMayExist(const ReadOptions& read_options,
return s.ok() || s.IsIncomplete();
}
std::unique_ptr<MultiScan> DBImpl::NewMultiScan(
const ReadOptions& _read_options, ColumnFamilyHandle* column_family,
const std::vector<ScanOptions>& scan_opts) {
std::unique_ptr<Iterator> iter(NewIterator(_read_options, column_family));
iter->Prepare(scan_opts);
std::unique_ptr<MultiScan> ms_iter =
std::make_unique<MultiScan>(scan_opts, std::move(iter));
return ms_iter;
}
Iterator* DBImpl::NewIterator(const ReadOptions& _read_options,
ColumnFamilyHandle* column_family) {
if (_read_options.io_activity != Env::IOActivity::kUnknown &&
@@ -3886,12 +3852,11 @@ Iterator* DBImpl::NewIterator(const ReadOptions& _read_options,
auto iter = new ForwardIterator(this, read_options, cfd, sv,
/* allow_unprepared_value */ true);
result = DBIter::NewIter(env_, read_options, cfd->ioptions(),
sv->mutable_cf_options, cfd->user_comparator(),
iter, sv->current, kMaxSequenceNumber,
/*read_callback=*/nullptr, cfh,
/*expose_blob_index=*/false,
/*active_mem=*/sv->mem);
result = NewDBIterator(
env_, read_options, cfd->ioptions(), sv->mutable_cf_options,
cfd->user_comparator(), iter, sv->current, kMaxSequenceNumber,
sv->mutable_cf_options.max_sequential_skip_in_iterations,
nullptr /* read_callback */, cfh);
} else {
// Note: no need to consider the special case of
// last_seq_same_as_publish_seq_==false since NewIterator is overridden in
@@ -3969,9 +3934,18 @@ ArenaWrappedDBIter* DBImpl::NewIteratorImpl(
// Laying out the iterators in the order of being accessed makes it more
// likely that any iterator pointer is close to the iterator it points to so
// that they are likely to be in the same cache line and/or page.
return NewArenaWrappedDbIterator(
env_, read_options, cfh, sv, snapshot, read_callback, this,
expose_blob_index, allow_refresh, /*allow_mark_memtable_for_flush=*/true);
ArenaWrappedDBIter* db_iter = NewArenaWrappedDbIterator(
env_, read_options, cfh->cfd()->ioptions(), sv->mutable_cf_options,
sv->current, snapshot,
sv->mutable_cf_options.max_sequential_skip_in_iterations,
sv->version_number, read_callback, cfh, expose_blob_index, allow_refresh);
InternalIterator* internal_iter = NewInternalIterator(
db_iter->GetReadOptions(), cfh->cfd(), sv, db_iter->GetArena(), snapshot,
/* allow_unprepared_value */ true, db_iter);
db_iter->SetIterUnderDBIter(internal_iter);
return db_iter;
}
std::unique_ptr<Iterator> DBImpl::NewCoalescingIterator(
@@ -4096,11 +4070,13 @@ Status DBImpl::NewIterators(
cf_sv_pair.super_version,
/* allow_unprepared_value */ true);
iterators->push_back(
DBIter::NewIter(env_, read_options, cf_sv_pair.cfd->ioptions(),
cf_sv_pair.super_version->mutable_cf_options,
cf_sv_pair.cfd->user_comparator(), iter,
cf_sv_pair.super_version->current, kMaxSequenceNumber,
nullptr /*read_callback*/, cf_sv_pair.cfh));
NewDBIterator(env_, read_options, cf_sv_pair.cfd->ioptions(),
cf_sv_pair.super_version->mutable_cf_options,
cf_sv_pair.cfd->user_comparator(), iter,
cf_sv_pair.super_version->current, kMaxSequenceNumber,
cf_sv_pair.super_version->mutable_cf_options
.max_sequential_skip_in_iterations,
nullptr /*read_callback*/, cf_sv_pair.cfh));
}
} else {
for (const auto& cf_sv_pair : cf_sv_pairs) {
@@ -5459,7 +5435,12 @@ Status DBImpl::WriteOptionsFile(const WriteOptions& write_options,
if (!s.ok()) {
ROCKS_LOG_WARN(immutable_db_options_.info_log,
"Unnable to persist options -- %s", s.ToString().c_str());
s = Status::IOError("Unable to persist options.", s.ToString().c_str());
if (immutable_db_options_.fail_if_options_file_error) {
s = Status::IOError("Unable to persist options.", s.ToString().c_str());
} else {
// Ignore error
s = Status::OK();
}
}
// Restore lock if appropriate
+133 -171
View File
@@ -173,10 +173,10 @@ struct DBOpenLogRecordReadReporter : public log::Reader::Reporter {
void OldLogRecord(size_t bytes) override;
uint64_t GetCorruptedLogNumber() const { return corrupted_wal_number_; }
uint64_t GetCorruptedLogNumber() const { return corrupted_log_number_; }
private:
uint64_t corrupted_wal_number_ = kMaxSequenceNumber;
uint64_t corrupted_log_number_ = kMaxSequenceNumber;
};
// While DB is the public interface of RocksDB, and DBImpl is the actual
@@ -256,10 +256,6 @@ class DBImpl : public DB {
Status WriteWithCallback(const WriteOptions& options, WriteBatch* updates,
UserWriteCallback* user_write_cb) override;
Status IngestWriteBatchWithIndex(
const WriteOptions& options,
std::shared_ptr<WriteBatchWithIndex> wbwi) override;
using DB::Get;
Status Get(const ReadOptions& _read_options,
ColumnFamilyHandle* column_family, const Slice& key,
@@ -383,11 +379,6 @@ class DBImpl : public DB {
const std::vector<ColumnFamilyHandle*>& column_families,
std::vector<Iterator*>* iterators) override;
using DB::NewMultiScan;
std::unique_ptr<MultiScan> NewMultiScan(
const ReadOptions& _read_options, ColumnFamilyHandle* column_family,
const std::vector<ScanOptions>& scan_opts) override;
const Snapshot* GetSnapshot() override;
void ReleaseSnapshot(const Snapshot* snapshot) override;
@@ -506,9 +497,6 @@ class DBImpl : public DB {
Status GetFullHistoryTsLow(ColumnFamilyHandle* column_family,
std::string* ts_low) override;
Status GetNewestUserDefinedTimestamp(ColumnFamilyHandle* column_family,
std::string* newest_timestamp) override;
Status GetDbIdentity(std::string& identity) const override;
virtual Status GetDbIdentityFromIdentityFile(const IOOptions& opts,
@@ -542,11 +530,11 @@ class DBImpl : public DB {
// Get the known flushed sizes of WALs that might still be written to
// or have pending sync.
// NOTE: unlike alive_wal_files_, this function includes WALs that might
// NOTE: unlike alive_log_files_, this function includes WALs that might
// be obsolete (but not obsolete to a pending Checkpoint) and not yet fully
// synced.
Status GetOpenWalSizes(std::map<uint64_t, uint64_t>& number_to_size);
Status GetCurrentWalFile(std::unique_ptr<WalFile>* current_wal_file) override;
Status GetCurrentWalFile(std::unique_ptr<WalFile>* current_log_file) override;
Status GetCreationTimeOfOldestFile(uint64_t* creation_time) override;
Status GetUpdatesSince(
@@ -1080,7 +1068,7 @@ class DBImpl : public DB {
void AddToLogsToFreeQueue(log::Writer* log_writer) {
mutex_.AssertHeld();
wals_to_free_queue_.push_back(log_writer);
logs_to_free_queue_.push_back(log_writer);
}
void AddSuperVersionsToFreeQueue(SuperVersion* sv) {
@@ -1145,7 +1133,7 @@ class DBImpl : public DB {
bool TEST_UnableToReleaseOldestLog() { return unable_to_release_oldest_log_; }
bool TEST_IsLogGettingFlushed() {
return alive_wal_files_.begin()->getting_flushed;
return alive_log_files_.begin()->getting_flushed;
}
Status TEST_SwitchMemtable(ColumnFamilyData* cfd = nullptr);
@@ -1225,9 +1213,7 @@ class DBImpl : public DB {
uint64_t TEST_LogfileNumber();
uint64_t TEST_wals_total_size() const {
return wals_total_size_.LoadRelaxed();
}
uint64_t TEST_total_log_size() const { return total_log_size_; }
void TEST_GetAllBlockCaches(std::unordered_set<const Cache*>* cache_set);
@@ -1385,16 +1371,16 @@ class DBImpl : public DB {
// State below is protected by mutex_
// With two_write_queues enabled, some of the variables that accessed during
// WriteToWAL need different synchronization: wal_empty_, alive_wal_files_,
// logs_, cur_wal_number_. Refer to the definition of each variable below for
// WriteToWAL need different synchronization: log_empty_, alive_log_files_,
// logs_, logfile_number_. Refer to the definition of each variable below for
// more description.
//
// `mutex_` can be a hot lock in some workloads, so it deserves dedicated
// cachelines.
mutable CacheAlignedInstrumentedMutex mutex_;
ColumnFamilyHandleImpl* default_cf_handle_ = nullptr;
InternalStats* default_cf_internal_stats_ = nullptr;
ColumnFamilyHandleImpl* default_cf_handle_;
InternalStats* default_cf_internal_stats_;
// table_cache_ provides its own synchronization
std::shared_ptr<Cache> table_cache_;
@@ -1406,7 +1392,7 @@ class DBImpl : public DB {
// only used for dynamically adjusting max_total_wal_size. it is a sum of
// [write_buffer_size * max_write_buffer_number] over all column families
std::atomic<uint64_t> max_total_in_memory_state_ = 0;
std::atomic<uint64_t> max_total_in_memory_state_;
// The options to access storage files
const FileOptions file_options_;
@@ -1433,14 +1419,14 @@ class DBImpl : public DB {
// Each flush or compaction gets its own job id. this counter makes sure
// they're unique
std::atomic<int> next_job_id_ = 1;
std::atomic<int> next_job_id_;
std::atomic<bool> shutting_down_ = false;
std::atomic<bool> shutting_down_;
// No new background jobs can be queued if true. This is used to prevent new
// background jobs from being queued after WaitForCompact() completes waiting
// all background jobs then attempts to close when close_db_ option is true.
bool reject_new_background_jobs_ = false;
bool reject_new_background_jobs_;
// RecoveryContext struct stores the context about version edits along
// with corresponding column_family_data and column_family_options.
@@ -1538,11 +1524,11 @@ class DBImpl : public DB {
// ingests `wbwi` is done.
// @param memtable_updated Whether the same write that ingests wbwi has
// updated memtable. This is useful for determining whether to set bg
// error when IngestWBWIAsMemtable fails.
Status IngestWBWIAsMemtable(std::shared_ptr<WriteBatchWithIndex> wbwi,
const WBWIMemTable::SeqnoRange& assigned_seqno,
uint64_t min_prep_log, SequenceNumber last_seqno,
bool memtable_updated, bool ignore_missing_cf);
// error when IngestWBWI fails.
Status IngestWBWI(std::shared_ptr<WriteBatchWithIndex> wbwi,
const WBWIMemTable::SeqnoRange& assigned_seqno,
uint64_t min_prep_log, SequenceNumber last_seqno,
bool memtable_updated, bool ignore_missing_cf);
// If disable_memtable is set the application logic must guarantee that the
// batch will still be skipped from memtable during the recovery. An excption
@@ -1572,17 +1558,18 @@ class DBImpl : public DB {
Status WriteImpl(const WriteOptions& options, WriteBatch* updates,
WriteCallback* callback = nullptr,
UserWriteCallback* user_write_cb = nullptr,
uint64_t* wal_used = nullptr, uint64_t log_ref = 0,
uint64_t* log_used = nullptr, uint64_t log_ref = 0,
bool disable_memtable = false, uint64_t* seq_used = nullptr,
size_t batch_cnt = 0,
PreReleaseCallback* pre_release_callback = nullptr,
PostMemTableCallback* post_memtable_callback = nullptr,
std::shared_ptr<WriteBatchWithIndex> wbwi = nullptr);
std::shared_ptr<WriteBatchWithIndex> wbwi = nullptr,
uint64_t min_prep_log = 0);
Status PipelinedWriteImpl(const WriteOptions& options, WriteBatch* updates,
WriteCallback* callback = nullptr,
UserWriteCallback* user_write_cb = nullptr,
uint64_t* wal_used = nullptr, uint64_t log_ref = 0,
uint64_t* log_used = nullptr, uint64_t log_ref = 0,
bool disable_memtable = false,
uint64_t* seq_used = nullptr);
@@ -1609,7 +1596,7 @@ class DBImpl : public DB {
Status WriteImplWALOnly(
WriteThread* write_thread, const WriteOptions& options,
WriteBatch* updates, WriteCallback* callback,
UserWriteCallback* user_write_cb, uint64_t* wal_used,
UserWriteCallback* user_write_cb, uint64_t* log_used,
const uint64_t log_ref, uint64_t* seq_used, const size_t sub_batch_cnt,
PreReleaseCallback* pre_release_callback, const AssignOrder assign_order,
const PublishLastSeq publish_last_seq, const bool disable_memtable);
@@ -1770,9 +1757,9 @@ class DBImpl : public DB {
}
};
struct WalFileNumberSize {
explicit WalFileNumberSize(uint64_t _number) : number(_number) {}
WalFileNumberSize() {}
struct LogFileNumberSize {
explicit LogFileNumberSize(uint64_t _number) : number(_number) {}
LogFileNumberSize() {}
void AddSize(uint64_t new_size) { size += new_size; }
uint64_t number;
uint64_t size = 0;
@@ -1794,13 +1781,6 @@ class DBImpl : public DB {
if (writer->file()) {
// TODO: plumb Env::IOActivity, Env::IOPriority
s = writer->WriteBuffer(WriteOptions());
if (attempt_truncate_size < SIZE_MAX &&
attempt_truncate_size < writer->file()->GetFileSize()) {
Status s2 = writer->file()->writable_file()->Truncate(
attempt_truncate_size, IOOptions{}, nullptr);
// This is just a best effort attempt
s2.PermitUncheckedError();
}
}
delete writer;
writer = nullptr;
@@ -1833,11 +1813,6 @@ class DBImpl : public DB {
getting_synced = false;
}
void SetAttemptTruncateSize(uint64_t size) {
assert(attempt_truncate_size == SIZE_MAX);
attempt_truncate_size = size;
}
uint64_t number;
// Visual Studio doesn't support deque's member to be noncopyable because
// of a std::unique_ptr as a member.
@@ -1850,20 +1825,15 @@ class DBImpl : public DB {
// to be persisted even if appends happen during sync so it can be used for
// tracking the synced size in MANIFEST.
uint64_t pre_sync_size = 0;
// When < SIZE_MAX, attempt to truncate the WAL to this size on close,
// because a bad entry was written to it beyond that point and it likely
// won't be recoverable with the bad entry.
uint64_t attempt_truncate_size = SIZE_MAX;
};
struct WalContext {
explicit WalContext(bool need_sync = false)
: need_wal_sync(need_sync), need_wal_dir_sync(need_sync) {}
bool need_wal_sync = false;
bool need_wal_dir_sync = false;
struct LogContext {
explicit LogContext(bool need_sync = false)
: need_log_sync(need_sync), need_log_dir_sync(need_sync) {}
bool need_log_sync = false;
bool need_log_dir_sync = false;
log::Writer* writer = nullptr;
WalFileNumberSize* wal_file_number_size = nullptr;
uint64_t prev_size = SIZE_MAX;
LogFileNumberSize* log_file_number_size = nullptr;
};
// PurgeFileInfo is a structure to hold information of files to be deleted in
@@ -2071,10 +2041,10 @@ class DBImpl : public DB {
JobContext* job_context, LogBuffer* log_buffer, Env::Priority thread_pri);
// REQUIRES: log_numbers are sorted in ascending order
// corrupted_wal_found is set to true if we recover from a corrupted log file.
// corrupted_log_found is set to true if we recover from a corrupted log file.
Status RecoverLogFiles(const std::vector<uint64_t>& log_numbers,
SequenceNumber* next_sequence, bool read_only,
bool is_retry, bool* corrupted_wal_found,
bool is_retry, bool* corrupted_log_found,
RecoveryContext* recovery_ctx);
void SetupLogFilesRecovery(
@@ -2182,12 +2152,12 @@ class DBImpl : public DB {
// log file to its actual size, thereby freeing preallocated space.
// Return success even if truncate fails
Status GetLogSizeAndMaybeTruncate(uint64_t wal_number, bool truncate,
WalFileNumberSize* log);
LogFileNumberSize* log);
// Restore alive_wal_files_ and wals_total_size_ after recovery.
// Restore alive_log_files_ and total_log_size_ after recovery.
// It needs to run only when there's no flush during recovery
// (e.g. avoid_flush_during_recovery=true). May also trigger flush
// in case wals_total_size > max_total_wal_size.
// in case total_log_size > max_total_wal_size.
Status RestoreAliveLogFiles(const std::vector<uint64_t>& log_numbers);
// num_bytes: for slowdown case, delay time is calculated based on
@@ -2336,7 +2306,7 @@ class DBImpl : public DB {
// REQUIRES: mutex locked
Status PreprocessWrite(const WriteOptions& write_options,
WalContext* log_context, WriteContext* write_context);
LogContext* log_context, WriteContext* write_context);
// Merge write batches in the write group into merged_batch.
// Returns OK if merge is successful.
@@ -2347,21 +2317,20 @@ class DBImpl : public DB {
IOStatus WriteToWAL(const WriteBatch& merged_batch,
const WriteOptions& write_options,
log::Writer* log_writer, uint64_t* wal_used,
log::Writer* log_writer, uint64_t* log_used,
uint64_t* log_size,
WalFileNumberSize& wal_file_number_size,
LogFileNumberSize& log_file_number_size,
SequenceNumber sequence);
IOStatus WriteGroupToWAL(const WriteThread::WriteGroup& write_group,
log::Writer* log_writer, uint64_t* wal_used,
bool need_wal_sync, bool need_wal_dir_sync,
SequenceNumber sequence,
WalFileNumberSize& wal_file_number_size);
IOStatus WriteToWAL(const WriteThread::WriteGroup& write_group,
log::Writer* log_writer, uint64_t* log_used,
bool need_log_sync, bool need_log_dir_sync,
SequenceNumber sequence,
LogFileNumberSize& log_file_number_size);
IOStatus ConcurrentWriteGroupToWAL(const WriteThread::WriteGroup& write_group,
uint64_t* wal_used,
SequenceNumber* last_sequence,
size_t seq_inc);
IOStatus ConcurrentWriteToWAL(const WriteThread::WriteGroup& write_group,
uint64_t* log_used,
SequenceNumber* last_sequence, size_t seq_inc);
// Used by WriteImpl to update bg_error_ if paranoid check is enabled.
// Caller must hold mutex_.
@@ -2375,7 +2344,7 @@ class DBImpl : public DB {
void WALIOStatusCheck(const IOStatus& status);
// Used by WriteImpl to update bg_error_ in case of memtable insert error.
void HandleMemTableInsertFailure(const Status& nonok_memtable_insert_status);
void MemTableInsertStatusCheck(const Status& memtable_insert_status);
Status CompactFilesImpl(const CompactionOptions& compact_options,
ColumnFamilyData* cfd, Version* version,
@@ -2728,7 +2697,7 @@ class DBImpl : public DB {
ErrorIteratorFuncType error_iterator_func);
// Lock over the persistent DB state. Non-nullptr iff successfully acquired.
FileLock* db_lock_ = nullptr;
FileLock* db_lock_;
// Guards changes to DB and CF options to ensure consistency between
// * In-memory options objects
@@ -2742,20 +2711,20 @@ class DBImpl : public DB {
// Guards reads and writes to in-memory stats_history_.
InstrumentedMutex stats_history_mutex_;
// In addition to mutex_, wal_write_mutex_ protects writes to logs_ and
// cur_wal_number_. With two_write_queues it also protects alive_wal_files_,
// and wal_empty_. Refer to the definition of each variable below for more
// In addition to mutex_, log_write_mutex_ protects writes to logs_ and
// logfile_number_. With two_write_queues it also protects alive_log_files_,
// and log_empty_. Refer to the definition of each variable below for more
// details.
// Note: to avoid deadlock, if needed to acquire both wal_write_mutex_ and
// mutex_, the order should be first mutex_ and then wal_write_mutex_.
InstrumentedMutex wal_write_mutex_;
// Note: to avoid deadlock, if needed to acquire both log_write_mutex_ and
// mutex_, the order should be first mutex_ and then log_write_mutex_.
InstrumentedMutex log_write_mutex_;
// If zero, manual compactions are allowed to proceed. If non-zero, manual
// compactions may still be running, but will quickly fail with
// `Status::Incomplete`. The value indicates how many threads have paused
// manual compactions. It is accessed in read mode outside the DB mutex in
// compaction code paths.
std::atomic<int> manual_compaction_paused_ = false;
std::atomic<int> manual_compaction_paused_;
// This condition variable is signaled on these conditions:
// * whenever bg_compaction_scheduled_ goes down to 0
@@ -2771,114 +2740,106 @@ class DBImpl : public DB {
// * whenever SetOptions successfully updates options.
// * whenever a column family is dropped.
InstrumentedCondVar bg_cv_;
ColumnFamilyHandleImpl* persist_stats_cf_handle_ = nullptr;
bool persistent_stats_cfd_exists_ = true;
// Writes are protected by locking both mutex_ and wal_write_mutex_, and reads
// must be under either mutex_ or wal_write_mutex_. Since after ::Open,
// cur_wal_number_ is currently updated only in write_thread_, it can be read
// Writes are protected by locking both mutex_ and log_write_mutex_, and reads
// must be under either mutex_ or log_write_mutex_. Since after ::Open,
// logfile_number_ is currently updated only in write_thread_, it can be read
// from the same write_thread_ without any locks.
uint64_t cur_wal_number_ = 0;
uint64_t logfile_number_;
// Log files that we can recycle. Must be protected by db mutex_.
std::deque<uint64_t> wal_recycle_files_;
std::deque<uint64_t> log_recycle_files_;
// The minimum log file number taht can be recycled, if log recycling is
// enabled. This is used to ensure that log files created by previous
// instances of the database are not recycled, as we cannot be sure they
// were created in the recyclable format.
uint64_t min_wal_number_to_recycle_ = 0;
// Protected by wal_write_mutex_.
bool wal_dir_synced_ = false;
// Without two_write_queues, read and writes to wal_empty_ are protected by
uint64_t min_log_number_to_recycle_;
// Protected by log_write_mutex_.
bool log_dir_synced_;
// Without two_write_queues, read and writes to log_empty_ are protected by
// mutex_. Since it is currently updated/read only in write_thread_, it can be
// accessed from the same write_thread_ without any locks. With
// two_write_queues writes, where it can be updated in different threads,
// read and writes are protected by wal_write_mutex_ instead. This is to avoid
// expensive mutex_ lock during WAL write, which update wal_empty_.
bool wal_empty_ = true;
// read and writes are protected by log_write_mutex_ instead. This is to avoid
// expensive mutex_ lock during WAL write, which update log_empty_.
bool log_empty_;
ColumnFamilyHandleImpl* persist_stats_cf_handle_;
bool persistent_stats_cfd_exists_ = true;
// The current WAL file and those that have not been found obsolete from
// memtable flushes. A WAL not on this list might still be pending writer
// flush and/or sync and close and might still be in logs_. alive_wal_files_
// is protected by mutex_ and wal_write_mutex_ with details as follows:
// flush and/or sync and close and might still be in logs_. alive_log_files_
// is protected by mutex_ and log_write_mutex_ with details as follows:
// 1. read by FindObsoleteFiles() which can be called in either application
// thread or RocksDB bg threads, both mutex_ and wal_write_mutex_ are
// thread or RocksDB bg threads, both mutex_ and log_write_mutex_ are
// held.
// 2. pop_front() by FindObsoleteFiles(), both mutex_ and wal_write_mutex_
// 2. pop_front() by FindObsoleteFiles(), both mutex_ and log_write_mutex_
// are held.
// 3. push_back() by DBImpl::Open() and DBImpl::RestoreAliveLogFiles()
// (actually called by Open()), only mutex_ is held because at this point,
// the DB::Open() call has not returned success to application, and the
// only other thread(s) that can conflict are bg threads calling
// FindObsoleteFiles() which ensure that both mutex_ and wal_write_mutex_
// are held when accessing alive_wal_files_.
// FindObsoleteFiles() which ensure that both mutex_ and log_write_mutex_
// are held when accessing alive_log_files_.
// 4. read by DBImpl::Open() is protected by mutex_.
// 5. push_back() by SwitchMemtable(). Both mutex_ and wal_write_mutex_ are
// 5. push_back() by SwitchMemtable(). Both mutex_ and log_write_mutex_ are
// held. This is done by the write group leader. Note that in the case of
// two-write-queues, another WAL-only write thread can be writing to the
// WAL concurrently. See 9.
// 6. read by SwitchWAL() with both mutex_ and wal_write_mutex_ held. This is
// 6. read by SwitchWAL() with both mutex_ and log_write_mutex_ held. This is
// done by write group leader.
// 7. read by ConcurrentWriteToWAL() by the write group leader in the case of
// two-write-queues. Only wal_write_mutex_ is held to protect concurrent
// two-write-queues. Only log_write_mutex_ is held to protect concurrent
// pop_front() by FindObsoleteFiles().
// 8. read by PreprocessWrite() by the write group leader. wal_write_mutex_
// 8. read by PreprocessWrite() by the write group leader. log_write_mutex_
// is held to protect the data structure from concurrent pop_front() by
// FindObsoleteFiles().
// 9. read by ConcurrentWriteToWAL() by a WAL-only write thread in the case
// of two-write-queues. Only wal_write_mutex_ is held. This suffices to
// of two-write-queues. Only log_write_mutex_ is held. This suffices to
// protect the data structure from concurrent push_back() by current
// write group leader as well as pop_front() by FindObsoleteFiles().
std::deque<WalFileNumberSize> alive_wal_files_;
// Total size of all "alive" WALs (for easy access without synchronization)
RelaxedAtomic<uint64_t> wals_total_size_{0};
std::deque<LogFileNumberSize> alive_log_files_;
// Log files that aren't fully synced, and the current log file.
// Synchronization:
// 1. read by FindObsoleteFiles() which can be called either in application
// thread or RocksDB bg threads. wal_write_mutex_ is always held, while
// thread or RocksDB bg threads. log_write_mutex_ is always held, while
// some reads are performed without mutex_.
// 2. pop_front() by FindObsoleteFiles() with only wal_write_mutex_ held.
// 3. read by DBImpl::Open() with both mutex_ and wal_write_mutex_.
// 4. emplace_back() by DBImpl::Open() with both mutex_ and wal_write_mutex.
// 2. pop_front() by FindObsoleteFiles() with only log_write_mutex_ held.
// 3. read by DBImpl::Open() with both mutex_ and log_write_mutex_.
// 4. emplace_back() by DBImpl::Open() with both mutex_ and log_write_mutex.
// Note that at this point, DB::Open() has not returned success to
// application, thus the only other thread(s) that can conflict are bg
// threads calling FindObsoleteFiles(). See 1.
// 5. iteration and clear() from CloseHelper() always hold wal_write_mutex
// 5. iteration and clear() from CloseHelper() always hold log_write_mutex
// and mutex_.
// 6. back() called by APIs FlushWAL() and LockWAL() are protected by only
// wal_write_mutex_. These two can be called by application threads after
// log_write_mutex_. These two can be called by application threads after
// DB::Open() returns success to applications.
// 7. read by SyncWAL(), another API, protected by only wal_write_mutex_.
// 7. read by SyncWAL(), another API, protected by only log_write_mutex_.
// 8. read by MarkLogsNotSynced() and MarkLogsSynced() are protected by
// wal_write_mutex_.
// 9. erase() by MarkLogsSynced() protected by wal_write_mutex_.
// 10. read by SyncClosedWals() protected by only wal_write_mutex_. This can
// log_write_mutex_.
// 9. erase() by MarkLogsSynced() protected by log_write_mutex_.
// 10. read by SyncClosedWals() protected by only log_write_mutex_. This can
// happen in bg flush threads after DB::Open() returns success to
// applications.
// 11. reads, e.g. front(), iteration, and back() called by PreprocessWrite()
// holds only the wal_write_mutex_. This is done by the write group
// holds only the log_write_mutex_. This is done by the write group
// leader. A bg thread calling FindObsoleteFiles() or MarkLogsSynced()
// can happen concurrently. This is fine because wal_write_mutex_ is used
// can happen concurrently. This is fine because log_write_mutex_ is used
// by all parties. See 2, 5, 9.
// 12. reads, empty(), back() called by SwitchMemtable() hold both mutex_ and
// wal_write_mutex_. This happens in the write group leader.
// log_write_mutex_. This happens in the write group leader.
// 13. emplace_back() by SwitchMemtable() hold both mutex_ and
// wal_write_mutex_. This happens in the write group leader. Can conflict
// log_write_mutex_. This happens in the write group leader. Can conflict
// with bg threads calling FindObsoleteFiles(), MarkLogsSynced(),
// SyncClosedWals(), etc. as well as application threads calling
// FlushWAL(), SyncWAL(), LockWAL(). This is fine because all parties
// require at least wal_write_mutex_.
// require at least log_write_mutex_.
// 14. iteration called in WriteToWAL(write_group) protected by
// wal_write_mutex_. This is done by write group leader when
// log_write_mutex_. This is done by write group leader when
// two-write-queues is disabled and write needs to sync logs.
// 15. back() called in ConcurrentWriteToWAL() protected by wal_write_mutex_.
// 15. back() called in ConcurrentWriteToWAL() protected by log_write_mutex_.
// This can be done by the write group leader if two-write-queues is
// enabled. It can also be done by another WAL-only write thread.
//
@@ -2895,22 +2856,23 @@ class DBImpl : public DB {
std::deque<LogWriterNumber> logs_;
// Signaled when getting_synced becomes false for some of the logs_.
InstrumentedCondVar wal_sync_cv_;
InstrumentedCondVar log_sync_cv_;
// This is the app-level state that is written to the WAL but will be used
// only during recovery. Using this feature enables not writing the state to
// memtable on normal writes and hence improving the throughput. Each new
// write of the state will replace the previous state entirely even if the
// keys in the two consecutive states do not overlap.
// It is protected by wal_write_mutex_ when two_write_queues_ is enabled.
// It is protected by log_write_mutex_ when two_write_queues_ is enabled.
// Otherwise only the heaad of write_thread_ can access it.
WriteBatch cached_recoverable_state_;
std::atomic<bool> cached_recoverable_state_empty_ = {true};
std::atomic<uint64_t> total_log_size_;
// If this is non-empty, we need to delete these log files in background
// threads. Protected by wal_write_mutex_.
autovector<log::Writer*> wals_to_free_;
// threads. Protected by log_write_mutex_.
autovector<log::Writer*> logs_to_free_;
bool is_snapshot_supported_ = true;
bool is_snapshot_supported_;
std::map<uint64_t, std::map<std::string, uint64_t>> stats_history_;
@@ -2934,7 +2896,7 @@ class DBImpl : public DB {
// sleep if it uses up the quota.
// Note: This is to protect memtable and compaction. If the batch only writes
// to the WAL its size need not to be included in this.
uint64_t last_batch_group_size_ = 0;
uint64_t last_batch_group_size_;
FlushScheduler flush_scheduler_;
@@ -2993,32 +2955,32 @@ class DBImpl : public DB {
std::unordered_set<uint64_t> files_grabbed_for_purge_;
// A queue to store log writers to close. Protected by db mutex_.
std::deque<log::Writer*> wals_to_free_queue_;
std::deque<log::Writer*> logs_to_free_queue_;
std::deque<SuperVersion*> superversions_to_free_queue_;
int unscheduled_flushes_ = 0;
int unscheduled_flushes_;
int unscheduled_compactions_ = 0;
int unscheduled_compactions_;
// count how many background compactions are running or have been scheduled in
// the BOTTOM pool
int bg_bottom_compaction_scheduled_ = 0;
int bg_bottom_compaction_scheduled_;
// count how many background compactions are running or have been scheduled
int bg_compaction_scheduled_ = 0;
int bg_compaction_scheduled_;
// stores the number of compactions are currently running
int num_running_compactions_ = 0;
int num_running_compactions_;
// number of background memtable flush jobs, submitted to the HIGH pool
int bg_flush_scheduled_ = 0;
int bg_flush_scheduled_;
// stores the number of flushes are currently running
int num_running_flushes_ = 0;
int num_running_flushes_;
// number of background obsolete file purge jobs, submitted to the HIGH pool
int bg_purge_scheduled_ = 0;
int bg_purge_scheduled_;
std::deque<ManualCompactionState*> manual_compaction_dequeue_;
@@ -3028,11 +2990,11 @@ class DBImpl : public DB {
// This enables two different threads to call
// EnableFileDeletions() and DisableFileDeletions()
// without any synchronization
int disable_delete_obsolete_files_ = 0;
int disable_delete_obsolete_files_;
// Number of times FindObsoleteFiles has found deletable files and the
// corresponding call to PurgeObsoleteFiles has not yet finished.
int pending_purge_obsolete_files_ = 0;
int pending_purge_obsolete_files_;
// last time when DeleteObsoleteFiles with full scan was executed. Originally
// initialized with startup time.
@@ -3044,12 +3006,12 @@ class DBImpl : public DB {
// The mutex used by switch_cv_. mutex_ should be acquired beforehand.
std::mutex switch_mutex_;
// Number of threads intending to write to memtable
std::atomic<size_t> pending_memtable_writes_{0};
std::atomic<size_t> pending_memtable_writes_ = {};
// A flag indicating whether the current rocksdb database has any
// data that is not yet persisted into either WAL or SST file.
// Used when disableWAL is true.
std::atomic<bool> has_unpersisted_data_{false};
std::atomic<bool> has_unpersisted_data_;
// if an attempt was made to flush all column families that
// the oldest log depends on but uncommitted data in the oldest
@@ -3057,26 +3019,26 @@ class DBImpl : public DB {
// We must attempt to free the dependent memtables again
// at a later time after the transaction in the oldest
// log is fully commited.
bool unable_to_release_oldest_log_{false};
bool unable_to_release_oldest_log_;
// Number of running IngestExternalFile() or CreateColumnFamilyWithImport()
// calls.
// REQUIRES: mutex held
int num_running_ingest_file_ = 0;
int num_running_ingest_file_;
WalManager wal_manager_;
// A value of > 0 temporarily disables scheduling of background work
int bg_work_paused_ = 0;
int bg_work_paused_;
// A value of > 0 temporarily disables scheduling of background compaction
int bg_compaction_paused_ = 0;
int bg_compaction_paused_;
// Guard against multiple concurrent refitting
bool refitting_level_ = false;
bool refitting_level_;
// Indicate DB was opened successfully
bool opened_successfully_ = false;
bool opened_successfully_;
// The min threshold to triggere bottommost compaction for removing
// garbages, among all column families.
@@ -3122,13 +3084,13 @@ class DBImpl : public DB {
// error recovery from going on in parallel. The latter, shutting_down_,
// is set a little later during the shutdown after scheduling memtable
// flushes
std::atomic<bool> shutdown_initiated_{false};
std::atomic<bool> shutdown_initiated_;
// Flag to indicate whether sst_file_manager object was allocated in
// DB::Open() or passed to us
bool own_sfm_;
// Flag to check whether Close() has been called on this DB
bool closed_ = false;
bool closed_;
// save the closing status, for re-calling the close()
Status closing_status_;
// mutex for DB::Close()
@@ -3164,7 +3126,7 @@ class DBImpl : public DB {
// The number of LockWAL called without matching UnlockWAL call.
// See also lock_wal_write_token_
uint32_t lock_wal_count_ = 0;
uint32_t lock_wal_count_;
};
class GetWithTimestampReadCallback : public ReadCallback {
+4 -4
View File
@@ -168,7 +168,7 @@ Status DBImpl::FlushMemTableToOutputFile(
// had not been committed yet. Make sure we sync them to keep the persisted
// WAL state at least as new as the persisted SST state.
const bool needs_to_sync_closed_wals =
cur_wal_number_ > 0 &&
logfile_number_ > 0 &&
(versions_->GetColumnFamilySet()->NumberOfColumnFamilies() > 1 ||
allow_2pc());
@@ -224,7 +224,7 @@ Status DBImpl::FlushMemTableToOutputFile(
bool need_cancel = false;
IOStatus log_io_s = IOStatus::OK();
if (needs_to_sync_closed_wals) {
// SyncClosedWals() may unlock and re-lock the wal_write_mutex multiple
// SyncClosedWals() may unlock and re-lock the log_write_mutex multiple
// times.
VersionEdit synced_wals;
bool error_recovery_in_prog = error_handler_.IsRecoveryInProgress();
@@ -512,7 +512,7 @@ Status DBImpl::AtomicFlushMemTablesToOutputFiles(
job_context->job_id, flush_reason);
}
if (cur_wal_number_ > 0) {
if (logfile_number_ > 0) {
// TODO (yanqin) investigate whether we should sync the closed logs for
// single column family case.
VersionEdit synced_wals;
@@ -528,7 +528,7 @@ Status DBImpl::AtomicFlushMemTablesToOutputFiles(
if (!log_io_s.ok() && !log_io_s.IsShutdownInProgress() &&
!log_io_s.IsColumnFamilyDropped()) {
if (wals_total_size_.LoadRelaxed() > 0) {
if (total_log_size_ > 0) {
error_handler_.SetBGError(log_io_s, BackgroundErrorReason::kFlush);
} else {
// If the WAL is empty, we use different error reason
+3 -3
View File
@@ -224,13 +224,13 @@ void DBImpl::TEST_EndWrite(void* w) {
}
size_t DBImpl::TEST_LogsToFreeSize() {
InstrumentedMutexLock l(&wal_write_mutex_);
return wals_to_free_.size();
InstrumentedMutexLock l(&log_write_mutex_);
return logs_to_free_.size();
}
uint64_t DBImpl::TEST_LogfileNumber() {
InstrumentedMutexLock l(&mutex_);
return cur_wal_number_;
return logfile_number_;
}
void DBImpl::TEST_GetAllBlockCaches(
+35 -35
View File
@@ -28,7 +28,7 @@ uint64_t DBImpl::MinLogNumberToKeep() {
return versions_->min_log_number_to_keep();
}
uint64_t DBImpl::MinLogNumberToRecycle() { return min_wal_number_to_recycle_; }
uint64_t DBImpl::MinLogNumberToRecycle() { return min_log_number_to_recycle_; }
uint64_t DBImpl::MinObsoleteSstNumberToKeep() {
mutex_.AssertHeld();
@@ -272,77 +272,77 @@ void DBImpl::FindObsoleteFiles(JobContext* job_context, bool force,
// logs_ is empty when called during recovery, in which case there can't yet
// be any tracked obsolete logs
wal_write_mutex_.Lock();
log_write_mutex_.Lock();
if (alive_wal_files_.empty() || logs_.empty()) {
if (alive_log_files_.empty() || logs_.empty()) {
mutex_.AssertHeld();
// We may reach here if the db is DBImplSecondary
wal_write_mutex_.Unlock();
log_write_mutex_.Unlock();
return;
}
bool mutex_unlocked = false;
if (!alive_wal_files_.empty() && !logs_.empty()) {
if (!alive_log_files_.empty() && !logs_.empty()) {
uint64_t min_log_number = job_context->log_number;
size_t num_alive_wal_files = alive_wal_files_.size();
size_t num_alive_log_files = alive_log_files_.size();
// find newly obsoleted log files
while (alive_wal_files_.begin()->number < min_log_number) {
auto& earliest = *alive_wal_files_.begin();
while (alive_log_files_.begin()->number < min_log_number) {
auto& earliest = *alive_log_files_.begin();
if (immutable_db_options_.recycle_log_file_num >
wal_recycle_files_.size() &&
log_recycle_files_.size() &&
earliest.number >= MinLogNumberToRecycle()) {
ROCKS_LOG_INFO(immutable_db_options_.info_log,
"adding log %" PRIu64 " to recycle list\n",
earliest.number);
wal_recycle_files_.push_back(earliest.number);
log_recycle_files_.push_back(earliest.number);
} else {
job_context->log_delete_files.push_back(earliest.number);
}
if (job_context->size_log_to_delete == 0) {
job_context->prev_wals_total_size = wals_total_size_.LoadRelaxed();
job_context->num_alive_wal_files = num_alive_wal_files;
job_context->prev_total_log_size = total_log_size_;
job_context->num_alive_log_files = num_alive_log_files;
}
job_context->size_log_to_delete += earliest.size;
wals_total_size_.FetchSubRelaxed(earliest.size);
alive_wal_files_.pop_front();
total_log_size_ -= earliest.size;
alive_log_files_.pop_front();
// Current log should always stay alive since it can't have
// number < MinLogNumber().
assert(alive_wal_files_.size());
assert(alive_log_files_.size());
}
wal_write_mutex_.Unlock();
log_write_mutex_.Unlock();
mutex_.Unlock();
mutex_unlocked = true;
TEST_SYNC_POINT_CALLBACK("FindObsoleteFiles::PostMutexUnlock", nullptr);
wal_write_mutex_.Lock();
log_write_mutex_.Lock();
while (!logs_.empty() && logs_.front().number < min_log_number) {
auto& log = logs_.front();
if (log.IsSyncing()) {
wal_sync_cv_.Wait();
log_sync_cv_.Wait();
// logs_ could have changed while we were waiting.
continue;
}
// This WAL file is not live, so it's OK if we never sync the rest of it.
// If it's already closed, then it's been fully synced. If
// !background_close_inactive_wals then we need to Close it before
// removing from logs_ but not blocking while holding wal_write_mutex_.
// removing from logs_ but not blocking while holding log_write_mutex_.
if (!immutable_db_options_.background_close_inactive_wals &&
log.writer->file()) {
// We are taking ownership of and pinning the front entry, so we can
// expect it to be the same after releasing and re-acquiring the lock
log.PrepareForSync();
wal_write_mutex_.Unlock();
log_write_mutex_.Unlock();
// TODO: maybe check the return value of Close.
// TODO: plumb Env::IOActivity, Env::IOPriority
auto s = log.writer->file()->Close({});
s.PermitUncheckedError();
wal_write_mutex_.Lock();
log_write_mutex_.Lock();
log.writer->PublishIfClosed();
assert(&log == &logs_.front());
log.FinishSync();
wal_sync_cv_.SignalAll();
log_sync_cv_.SignalAll();
}
wals_to_free_.push_back(log.ReleaseWriter());
logs_to_free_.push_back(log.ReleaseWriter());
logs_.pop_front();
}
// Current log cannot be obsolete.
@@ -350,16 +350,16 @@ void DBImpl::FindObsoleteFiles(JobContext* job_context, bool force,
}
// We're just cleaning up for DB::Write().
assert(job_context->wals_to_free.empty());
job_context->wals_to_free = wals_to_free_;
assert(job_context->logs_to_free.empty());
job_context->logs_to_free = logs_to_free_;
wals_to_free_.clear();
wal_write_mutex_.Unlock();
logs_to_free_.clear();
log_write_mutex_.Unlock();
if (mutex_unlocked) {
mutex_.Lock();
}
job_context->log_recycle_files.assign(wal_recycle_files_.begin(),
wal_recycle_files_.end());
job_context->log_recycle_files.assign(log_recycle_files_.begin(),
log_recycle_files_.end());
}
// Delete obsolete files and log status and information of file deletion
@@ -431,7 +431,7 @@ void DBImpl::PurgeObsoleteFiles(JobContext& state, bool schedule_only) {
state.sst_live.end());
std::unordered_set<uint64_t> blob_live_set(state.blob_live.begin(),
state.blob_live.end());
std::unordered_set<uint64_t> wal_recycle_files_set(
std::unordered_set<uint64_t> log_recycle_files_set(
state.log_recycle_files.begin(), state.log_recycle_files.end());
std::unordered_set<uint64_t> quarantine_files_set(
state.files_to_quarantine.begin(), state.files_to_quarantine.end());
@@ -491,13 +491,13 @@ void DBImpl::PurgeObsoleteFiles(JobContext& state, bool schedule_only) {
std::unique(candidate_files.begin(), candidate_files.end()),
candidate_files.end());
if (state.prev_wals_total_size > 0) {
if (state.prev_total_log_size > 0) {
ROCKS_LOG_INFO(immutable_db_options_.info_log,
"[JOB %d] Try to delete WAL files size %" PRIu64
", prev total WAL file size %" PRIu64
", number of live WAL files %" ROCKSDB_PRIszt ".\n",
state.job_id, state.size_log_to_delete,
state.prev_wals_total_size, state.num_alive_wal_files);
state.prev_total_log_size, state.num_alive_log_files);
}
std::vector<std::string> old_info_log_files;
@@ -532,7 +532,7 @@ void DBImpl::PurgeObsoleteFiles(JobContext& state, bool schedule_only) {
optsfile_num2 = std::min(optsfile_num2, state.min_options_file_number);
// Close WALs before trying to delete them.
for (const auto w : state.wals_to_free) {
for (const auto w : state.logs_to_free) {
// TODO: maybe check the return value of Close.
// TODO: plumb Env::IOActivity, Env::IOPriority
auto s = w->Close({});
@@ -559,8 +559,8 @@ void DBImpl::PurgeObsoleteFiles(JobContext& state, bool schedule_only) {
case kWalFile:
keep = ((number >= state.log_number) ||
(number == state.prev_log_number) ||
(wal_recycle_files_set.find(number) !=
wal_recycle_files_set.end()));
(log_recycle_files_set.find(number) !=
log_recycle_files_set.end()));
break;
case kDescriptorFile:
// Keep my manifest file, and any newer incarnations'
+18 -18
View File
@@ -1119,7 +1119,7 @@ void DBOpenLogRecordReadReporter::Corruption(size_t bytes, const Status& s,
static_cast<int>(bytes), s.ToString().c_str());
if (status != nullptr && status->ok()) {
*status = s;
corrupted_wal_number_ = log_number;
corrupted_log_number_ = log_number;
}
}
@@ -1902,8 +1902,8 @@ void DBImpl::FinishLogFilesRecovery(int job_id, const Status& status) {
}
Status DBImpl::GetLogSizeAndMaybeTruncate(uint64_t wal_number, bool truncate,
WalFileNumberSize* log_ptr) {
WalFileNumberSize log(wal_number);
LogFileNumberSize* log_ptr) {
LogFileNumberSize log(wal_number);
std::string fname =
LogFileName(immutable_db_options_.GetWalDir(), wal_number);
Status s;
@@ -1946,27 +1946,27 @@ Status DBImpl::RestoreAliveLogFiles(const std::vector<uint64_t>& wal_numbers) {
assert(immutable_db_options_.avoid_flush_during_recovery);
// Mark these as alive so they'll be considered for deletion later by
// FindObsoleteFiles()
wals_total_size_.StoreRelaxed(0);
wal_empty_ = false;
total_log_size_ = 0;
log_empty_ = false;
uint64_t min_wal_with_unflushed_data =
versions_->MinLogNumberWithUnflushedData();
for (auto wal_number : wal_numbers) {
if (!allow_2pc() && wal_number < min_wal_with_unflushed_data) {
// In non-2pc mode, the WAL files not backing unflushed data are not
// alive, thus should not be added to the alive_wal_files_.
// alive, thus should not be added to the alive_log_files_.
continue;
}
// We preallocate space for wals, but then after a crash and restart, those
// preallocated space are not needed anymore. It is likely only the last
// log has such preallocated space, so we only truncate for the last log.
WalFileNumberSize log;
LogFileNumberSize log;
s = GetLogSizeAndMaybeTruncate(
wal_number, /*truncate=*/(wal_number == wal_numbers.back()), &log);
if (!s.ok()) {
break;
}
wals_total_size_.FetchAddRelaxed(log.size);
alive_wal_files_.push_back(log);
total_log_size_ += log.size;
alive_log_files_.push_back(log);
}
return s;
}
@@ -2449,18 +2449,18 @@ Status DBImpl::Open(const DBOptions& db_options, const std::string& dbname,
if (s.ok()) {
// Prevent log files created by previous instance from being recycled.
// They might be in alive_log_file_, and might get recycled otherwise.
impl->min_wal_number_to_recycle_ = new_log_number;
impl->min_log_number_to_recycle_ = new_log_number;
}
if (s.ok()) {
InstrumentedMutexLock wl(&impl->wal_write_mutex_);
impl->cur_wal_number_ = new_log_number;
InstrumentedMutexLock wl(&impl->log_write_mutex_);
impl->logfile_number_ = new_log_number;
assert(new_log != nullptr);
assert(impl->logs_.empty());
impl->logs_.emplace_back(new_log_number, new_log);
}
if (s.ok()) {
impl->alive_wal_files_.emplace_back(impl->cur_wal_number_);
impl->alive_log_files_.emplace_back(impl->logfile_number_);
// In WritePrepared there could be gap in sequence numbers. This breaks
// the trick we use in kPointInTimeRecovery which assumes the first seq in
// the log right after the corrupted log is one larger than the last seq
@@ -2473,14 +2473,14 @@ Status DBImpl::Open(const DBOptions& db_options, const std::string& dbname,
if (recovered_seq != kMaxSequenceNumber) {
WriteBatch empty_batch;
WriteBatchInternal::SetSequence(&empty_batch, recovered_seq);
uint64_t wal_used, log_size;
uint64_t log_used, log_size;
log::Writer* log_writer = impl->logs_.back().writer;
WalFileNumberSize& wal_file_number_size = impl->alive_wal_files_.back();
LogFileNumberSize& log_file_number_size = impl->alive_log_files_.back();
assert(log_writer->get_log_number() == wal_file_number_size.number);
assert(log_writer->get_log_number() == log_file_number_size.number);
impl->mutex_.AssertHeld();
s = impl->WriteToWAL(empty_batch, write_options, log_writer, &wal_used,
&log_size, wal_file_number_size, recovered_seq);
s = impl->WriteToWAL(empty_batch, write_options, log_writer, &log_used,
&log_size, log_file_number_size, recovered_seq);
if (s.ok()) {
// Need to fsync, otherwise it might get lost after a power reset.
s = impl->FlushWAL(write_options, false);
+23 -13
View File
@@ -185,10 +185,16 @@ Iterator* DBImplReadOnly::NewIterator(const ReadOptions& _read_options,
? static_cast<const SnapshotImpl*>(read_options.snapshot)->number_
: latest_snapshot;
ReadCallback* read_callback = nullptr; // No read callback provided.
return NewArenaWrappedDbIterator(
env_, read_options, cfh, super_version, read_seq, read_callback, this,
/*expose_blob_index=*/false, /*allow_refresh=*/false,
/*allow_mark_memtable_for_flush=*/false);
auto db_iter = NewArenaWrappedDbIterator(
env_, read_options, cfd->ioptions(), super_version->mutable_cf_options,
super_version->current, read_seq,
super_version->mutable_cf_options.max_sequential_skip_in_iterations,
super_version->version_number, read_callback);
auto internal_iter = NewInternalIterator(
db_iter->GetReadOptions(), cfd, super_version, db_iter->GetArena(),
read_seq, /* allow_unprepared_value */ true, db_iter);
db_iter->SetIterUnderDBIter(internal_iter);
return db_iter;
}
Status DBImplReadOnly::NewIterators(
@@ -225,32 +231,36 @@ Status DBImplReadOnly::NewIterators(
? static_cast<const SnapshotImpl*>(read_options.snapshot)->number_
: latest_snapshot;
autovector<std::tuple<ColumnFamilyHandleImpl*, SuperVersion*>> cfh_to_sv;
autovector<std::tuple<ColumnFamilyData*, SuperVersion*>> cfd_to_sv;
const bool check_read_ts =
read_options.timestamp && read_options.timestamp->size() > 0;
for (auto cfh : column_families) {
auto* cfd = static_cast_with_check<ColumnFamilyHandleImpl>(cfh)->cfd();
auto* sv = cfd->GetSuperVersion()->Ref();
cfh_to_sv.emplace_back(static_cast_with_check<ColumnFamilyHandleImpl>(cfh),
sv);
cfd_to_sv.emplace_back(cfd, sv);
if (check_read_ts) {
const Status s =
FailIfReadCollapsedHistory(cfd, sv, *(read_options.timestamp));
if (!s.ok()) {
for (auto prev_entry : cfh_to_sv) {
for (auto prev_entry : cfd_to_sv) {
std::get<1>(prev_entry)->Unref();
}
return s;
}
}
}
assert(cfh_to_sv.size() == column_families.size());
for (auto [cfh, sv] : cfh_to_sv) {
assert(cfd_to_sv.size() == column_families.size());
for (auto [cfd, sv] : cfd_to_sv) {
auto* db_iter = NewArenaWrappedDbIterator(
env_, read_options, cfh, sv, read_seq, read_callback, this,
/*expose_blob_index=*/false, /*allow_refresh=*/false,
/*allow_mark_memtable_for_flush=*/false);
env_, read_options, cfd->ioptions(), sv->mutable_cf_options,
sv->current, read_seq,
sv->mutable_cf_options.max_sequential_skip_in_iterations,
sv->version_number, read_callback);
auto* internal_iter = NewInternalIterator(
db_iter->GetReadOptions(), cfd, sv, db_iter->GetArena(), read_seq,
/* allow_unprepared_value */ true, db_iter);
db_iter->SetIterUnderDBIter(internal_iter);
iterators->push_back(db_iter);
}
+15 -34
View File
@@ -566,10 +566,17 @@ ArenaWrappedDBIter* DBImplSecondary::NewIteratorImpl(
assert(snapshot == kMaxSequenceNumber);
snapshot = versions_->LastSequence();
assert(snapshot != kMaxSequenceNumber);
return NewArenaWrappedDbIterator(env_, read_options, cfh, super_version,
snapshot, read_callback, this,
expose_blob_index, allow_refresh,
/*allow_mark_memtable_for_flush=*/false);
auto db_iter = NewArenaWrappedDbIterator(
env_, read_options, cfh->cfd()->ioptions(),
super_version->mutable_cf_options, super_version->current, snapshot,
super_version->mutable_cf_options.max_sequential_skip_in_iterations,
super_version->version_number, read_callback, cfh, expose_blob_index,
allow_refresh);
auto internal_iter = NewInternalIterator(
db_iter->GetReadOptions(), cfh->cfd(), super_version, db_iter->GetArena(),
snapshot, /* allow_unprepared_value */ true, db_iter);
db_iter->SetIterUnderDBIter(internal_iter);
return db_iter;
}
Status DBImplSecondary::NewIterators(
@@ -698,13 +705,13 @@ Status DBImplSecondary::CheckConsistency() {
Status DBImplSecondary::TryCatchUpWithPrimary() {
assert(versions_.get() != nullptr);
assert(manifest_reader_.get() != nullptr);
Status s;
// read the manifest and apply new changes to the secondary instance
std::unordered_set<ColumnFamilyData*> cfds_changed;
JobContext job_context(0, true /*create_superversion*/);
{
InstrumentedMutexLock lock_guard(&mutex_);
assert(manifest_reader_.get() != nullptr);
s = static_cast_with_check<ReactiveVersionSet>(versions_.get())
->ReadAndApply(&mutex_, &manifest_reader_,
manifest_reader_status_.get(), &cfds_changed,
@@ -984,7 +991,7 @@ Status DB::OpenAndCompact(
}
// 2. Load the options
DBOptions base_db_options;
DBOptions db_options;
ConfigOptions config_options;
config_options.env = override_options.env;
config_options.ignore_unknown_options = true;
@@ -997,22 +1004,13 @@ Status DB::OpenAndCompact(
std::string options_file_name =
OptionsFileName(name, compaction_input.options_file_number);
s = LoadOptionsFromFile(config_options, options_file_name, &base_db_options,
s = LoadOptionsFromFile(config_options, options_file_name, &db_options,
&all_column_families);
if (!s.ok()) {
return s;
}
// 3. Options to Override
// Override serializable configurations from override_options.options_map
DBOptions db_options;
s = GetDBOptionsFromMap(config_options, base_db_options,
override_options.options_map, &db_options);
if (!s.ok()) {
return s;
}
// Override options that are directly set as shared ptrs in
// 3. Override pointer configurations in DBOptions with
// CompactionServiceOptionsOverride
db_options.env = override_options.env;
db_options.file_checksum_gen_factory =
@@ -1023,7 +1021,6 @@ Status DB::OpenAndCompact(
// We will close the DB after the compaction anyway.
// Open as many files as needed for the compaction.
db_options.max_open_files = -1;
db_options.info_log = override_options.info_log;
// 4. Filter CFs that are needed for OpenAndCompact()
// We do not need to open all column families for the remote compaction.
@@ -1033,18 +1030,6 @@ Status DB::OpenAndCompact(
std::vector<ColumnFamilyDescriptor> column_families;
for (auto& cf : all_column_families) {
if (cf.name == compaction_input.cf_name) {
ColumnFamilyOptions cf_options;
// Override serializable configurations from override_options.options_map
s = GetColumnFamilyOptionsFromMap(config_options, cf.options,
override_options.options_map,
&cf_options);
if (!s.ok()) {
return s;
}
cf.options = std::move(cf_options);
// Override options that are directly set as shared ptrs in
// CompactionServiceOptionsOverride
cf.options.comparator = override_options.comparator;
cf.options.merge_operator = override_options.merge_operator;
cf.options.compaction_filter = override_options.compaction_filter;
@@ -1056,7 +1041,6 @@ Status DB::OpenAndCompact(
override_options.sst_partitioner_factory;
cf.options.table_properties_collector_factories =
override_options.table_properties_collector_factories;
column_families.emplace_back(cf);
} else if (cf.name == kDefaultColumnFamilyName) {
column_families.emplace_back(cf);
@@ -1073,9 +1057,6 @@ Status DB::OpenAndCompact(
}
assert(db);
TEST_SYNC_POINT_CALLBACK(
"DBImplSecondary::OpenAndCompact::AfterOpenAsSecondary:0", db);
// 6. Find the handle of the Column Family that this will compact
ColumnFamilyHandle* cfh = nullptr;
for (auto* handle : handles) {
+177 -275
View File
@@ -157,7 +157,7 @@ Status DBImpl::Write(const WriteOptions& write_options, WriteBatch* my_batch) {
if (s.ok()) {
s = WriteImpl(write_options, my_batch, /*callback=*/nullptr,
/*user_write_cb=*/nullptr,
/*wal_used=*/nullptr);
/*log_used=*/nullptr);
}
return s;
}
@@ -190,38 +190,11 @@ Status DBImpl::WriteWithCallback(const WriteOptions& write_options,
return s;
}
Status DBImpl::IngestWriteBatchWithIndex(
const WriteOptions& write_options,
std::shared_ptr<WriteBatchWithIndex> wbwi) {
if (!wbwi) {
return Status::InvalidArgument("Batch is nullptr!");
}
if (!write_options.disableWAL) {
return Status::NotSupported(
"IngestWriteBatchWithIndex does not support disableWAL=true");
}
Status s;
if (write_options.protection_bytes_per_key > 0) {
s = WriteBatchInternal::UpdateProtectionInfo(
wbwi->GetWriteBatch(), write_options.protection_bytes_per_key);
}
if (s.ok()) {
WriteBatch dummy_empty_batch;
s = WriteImpl(
write_options, /*updates=*/&dummy_empty_batch, /*callback=*/nullptr,
/*user_write_cb=*/nullptr, /*log_used=*/nullptr, /*log_ref=*/0,
/*disable_memtable=*/false, /*seq_used=*/nullptr,
/*batch_cnt=*/0, /*pre_release_callback=*/nullptr,
/*post_memtable_callback=*/nullptr, /*wbwi=*/wbwi);
}
return s;
}
Status DBImpl::IngestWBWIAsMemtable(
std::shared_ptr<WriteBatchWithIndex> wbwi,
const WBWIMemTable::SeqnoRange& assigned_seqno, uint64_t min_prep_log,
SequenceNumber last_seqno_after_ingest, bool memtable_updated,
bool ignore_missing_cf) {
Status DBImpl::IngestWBWI(std::shared_ptr<WriteBatchWithIndex> wbwi,
const WBWIMemTable::SeqnoRange& assigned_seqno,
uint64_t prep_log,
SequenceNumber last_seqno_after_ingest,
bool memtable_updated, bool ignore_missing_cf) {
// Keys in new memtable have seqno > last_seqno_after_ingest >= keys in wbwi.
assert(assigned_seqno.upper_bound <= last_seqno_after_ingest);
// Keys in the current memtable have seqno <= LastSequence() < keys in wbwi.
@@ -265,30 +238,12 @@ Status DBImpl::IngestWBWIAsMemtable(
wbwi_memtable->AssignSequenceNumbers(assigned_seqno);
// This is needed to keep the WAL that contains Prepare alive until
// committed data in this memtable is persisted.
wbwi_memtable->SetMinPrepLog(min_prep_log);
wbwi_memtable->SetMinPrepLog(prep_log);
memtables.push_back(wbwi_memtable);
cfd->Ref();
cfds.push_back(cfd);
}
autovector<ColumnFamilyData*> cfds_for_atomic_flush;
if (immutable_db_options_.atomic_flush) {
SelectColumnFamiliesForAtomicFlush(&cfds_for_atomic_flush);
for (auto cfd : cfds_for_atomic_flush) {
bool found = false;
for (auto existing_cfd : cfds) {
if (existing_cfd == cfd) {
found = true;
break;
}
}
if (!found) {
cfd->Ref();
cfds.push_back(cfd);
}
}
}
// Stop writes to the DB by entering both write threads
WriteThread::Writer nonmem_w;
if (two_write_queues_) {
@@ -298,16 +253,15 @@ Status DBImpl::IngestWBWIAsMemtable(
// Switch memtable and add WBWIMemTables
Status s;
for (size_t i = 0; i < cfds.size(); ++i) {
for (size_t i = 0; i < memtables.size(); ++i) {
assert(!immutable_db_options_.atomic_flush);
// NOTE: to support atomic flush, need to call
// SelectColumnFamiliesForAtomicFlush()
WriteContext write_context;
// TODO: not switch on empty memtable, may need to update metadata
// like NextLogNumber(), earliest_seqno and memtable id.
if (i < memtables.size()) {
s = SwitchMemtable(cfds[i], &write_context, memtables[i],
last_seqno_after_ingest);
} else {
s = SwitchMemtable(cfds[i], &write_context);
}
s = SwitchMemtable(cfds[i], &write_context, memtables[i],
last_seqno_after_ingest);
if (!s.ok()) {
// SwitchMemtable() can only fail if a new WAL is to be created, this
// should only happen for the first call to SwitchMemtable(). log will
@@ -347,18 +301,9 @@ Status DBImpl::IngestWBWIAsMemtable(
continue;
}
cfd->imm()->FlushRequested();
if (!immutable_db_options_.atomic_flush) {
FlushRequest flush_req;
// TODO: a new flush reason for ingesting memtable
GenerateFlushRequest({cfd}, FlushReason::kExternalFileIngestion,
&flush_req);
EnqueuePendingFlush(flush_req);
}
}
if (immutable_db_options_.atomic_flush) {
AssignAtomicFlushSeq(cfds);
FlushRequest flush_req;
GenerateFlushRequest(cfds, FlushReason::kExternalFileIngestion,
// TODO: a new flush reason for ingesting memtable
GenerateFlushRequest({cfd}, FlushReason::kExternalFileIngestion,
&flush_req);
EnqueuePendingFlush(flush_req);
}
@@ -369,12 +314,13 @@ Status DBImpl::IngestWBWIAsMemtable(
Status DBImpl::WriteImpl(const WriteOptions& write_options,
WriteBatch* my_batch, WriteCallback* callback,
UserWriteCallback* user_write_cb, uint64_t* wal_used,
UserWriteCallback* user_write_cb, uint64_t* log_used,
uint64_t log_ref, bool disable_memtable,
uint64_t* seq_used, size_t batch_cnt,
PreReleaseCallback* pre_release_callback,
PostMemTableCallback* post_memtable_callback,
std::shared_ptr<WriteBatchWithIndex> wbwi) {
std::shared_ptr<WriteBatchWithIndex> wbwi,
uint64_t prep_log) {
assert(!seq_per_batch_ || batch_cnt != 0);
assert(my_batch == nullptr || my_batch->Count() == 0 ||
write_options.protection_bytes_per_key == 0 ||
@@ -463,17 +409,9 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
return Status::NotSupported(
"DeleteRange is not compatible with row cache.");
}
// Whether the WBWI is from transaction commit or a direct write
// (IngestWriteBatchWithIndex())
bool ingest_wbwi_for_commit = false;
if (wbwi) {
if (my_batch->HasCommit()) {
ingest_wbwi_for_commit = true;
assert(log_ref);
} else {
// Only supports disableWAL for directly ingesting WBWI for now.
assert(write_options.disableWAL);
}
assert(prep_log > 0);
// Used only in WriteCommittedTxn::CommitInternal() with no `callback`.
assert(!callback);
if (immutable_db_options_.unordered_write) {
return Status::NotSupported(
@@ -483,9 +421,9 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
return Status::NotSupported(
"Ingesting WriteBatch does not support pipelined_write");
}
if (!wbwi->GetOverwriteKey()) {
if (immutable_db_options_.atomic_flush) {
return Status::NotSupported(
"WriteBatchWithIndex ingestion requires overwrite_key=true");
"Ingesting WriteBatch does not support atomic_flush");
}
}
// Otherwise IsLatestPersistentState optimization does not make sense
@@ -506,7 +444,7 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
// they don't consume sequence.
return WriteImplWALOnly(
&nonmem_write_thread_, write_options, my_batch, callback, user_write_cb,
wal_used, log_ref, seq_used, batch_cnt, pre_release_callback,
log_used, log_ref, seq_used, batch_cnt, pre_release_callback,
assign_order, kDontPublishLastSeq, disable_memtable);
}
@@ -520,7 +458,7 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
// sequence in in increasing order, iii) call pre_release_callback serially
Status status = WriteImplWALOnly(
&write_thread_, write_options, my_batch, callback, user_write_cb,
wal_used, log_ref, &seq, sub_batch_cnt, pre_release_callback,
log_used, log_ref, &seq, sub_batch_cnt, pre_release_callback,
kDoAssignOrder, kDoPublishLastSeq, disable_memtable);
TEST_SYNC_POINT("DBImpl::WriteImpl:UnorderedWriteAfterWriteWAL");
if (!status.ok()) {
@@ -539,7 +477,7 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
if (immutable_db_options_.enable_pipelined_write) {
return PipelinedWriteImpl(write_options, my_batch, callback, user_write_cb,
wal_used, log_ref, disable_memtable, seq_used);
log_used, log_ref, disable_memtable, seq_used);
}
PERF_TIMER_GUARD(write_pre_and_post_process_time);
@@ -586,19 +524,16 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
assert(tmp_s.ok());
}
}
if (w.status.ok()) { // Don't publish a partial batch write
versions_->SetLastSequence(last_sequence);
} else {
HandleMemTableInsertFailure(w.status);
}
versions_->SetLastSequence(last_sequence);
MemTableInsertStatusCheck(w.status);
write_thread_.ExitAsBatchGroupFollower(&w);
}
assert(w.state == WriteThread::STATE_COMPLETED);
// STATE_COMPLETED conditional below handles exit
}
if (w.state == WriteThread::STATE_COMPLETED) {
if (wal_used != nullptr) {
*wal_used = w.wal_used;
if (log_used != nullptr) {
*log_used = w.log_used;
}
if (seq_used != nullptr) {
*seq_used = w.sequence;
@@ -614,8 +549,7 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
// when it finds suitable, and finish them in the same write batch.
// This is how a write job could be done by the other writer.
WriteContext write_context;
// FIXME: also check disableWAL like others?
WalContext wal_context(write_options.sync);
LogContext log_context(write_options.sync);
WriteThread::WriteGroup write_group;
bool in_parallel_group = false;
uint64_t last_sequence = kMaxSequenceNumber;
@@ -629,7 +563,7 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
// PreprocessWrite does its own perf timing.
PERF_TIMER_STOP(write_pre_and_post_process_time);
status = PreprocessWrite(write_options, &wal_context, &write_context);
status = PreprocessWrite(write_options, &log_context, &write_context);
if (!two_write_queues_) {
// Assign it after ::PreprocessWrite since the sequence might advance
// inside it by WriteRecoverableState
@@ -697,13 +631,7 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
continue;
}
// TODO: maybe handle the tracing status?
if (wbwi && !ingest_wbwi_for_commit) {
// for transaction write, tracer only needs the commit marker which
// is in writer->batch
tracer_->Write(wbwi->GetWriteBatch()).PermitUncheckedError();
} else {
tracer_->Write(writer->batch).PermitUncheckedError();
}
tracer_->Write(writer->batch).PermitUncheckedError();
}
}
}
@@ -761,21 +689,22 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
if (!two_write_queues_) {
if (status.ok() && !write_options.disableWAL) {
assert(wal_context.wal_file_number_size);
wal_context.prev_size = wal_context.writer->file()->GetFileSize();
assert(log_context.log_file_number_size);
LogFileNumberSize& log_file_number_size =
*(log_context.log_file_number_size);
PERF_TIMER_GUARD(write_wal_time);
io_s = WriteGroupToWAL(write_group, wal_context.writer, wal_used,
wal_context.need_wal_sync,
wal_context.need_wal_dir_sync, last_sequence + 1,
*wal_context.wal_file_number_size);
io_s =
WriteToWAL(write_group, log_context.writer, log_used,
log_context.need_log_sync, log_context.need_log_dir_sync,
last_sequence + 1, log_file_number_size);
}
} else {
if (status.ok() && !write_options.disableWAL) {
PERF_TIMER_GUARD(write_wal_time);
// LastAllocatedSequence is increased inside WriteToWAL under
// wal_write_mutex_ to ensure ordered events in WAL
io_s = ConcurrentWriteGroupToWAL(write_group, wal_used, &last_sequence,
seq_inc);
io_s = ConcurrentWriteToWAL(write_group, log_used, &last_sequence,
seq_inc);
} else {
// Otherwise we inc seq number for memtable writes
last_sequence = versions_->FetchAddLastAllocatedSequence(seq_inc);
@@ -787,16 +716,16 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
last_sequence += seq_inc;
// Seqno assigned to this write are [current_sequence, last_sequence]
if (wal_context.need_wal_sync) {
if (log_context.need_log_sync) {
VersionEdit synced_wals;
wal_write_mutex_.Lock();
log_write_mutex_.Lock();
if (status.ok()) {
MarkLogsSynced(cur_wal_number_, wal_context.need_wal_dir_sync,
MarkLogsSynced(logfile_number_, log_context.need_log_dir_sync,
&synced_wals);
} else {
MarkLogsNotSynced(cur_wal_number_);
MarkLogsNotSynced(logfile_number_);
}
wal_write_mutex_.Unlock();
log_write_mutex_.Unlock();
if (status.ok() && synced_wals.IsWalAddition()) {
InstrumentedMutexLock l(&mutex_);
// TODO: plumb Env::IOActivity, Env::IOPriority
@@ -831,7 +760,7 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
writer->sequence = next_sequence;
if (writer->pre_release_callback) {
Status ws = writer->pre_release_callback->Callback(
writer->sequence, disable_memtable, writer->wal_used, index++,
writer->sequence, disable_memtable, writer->log_used, index++,
pre_release_callback_cnt);
if (!ws.ok()) {
status = pre_release_cb_status = ws;
@@ -905,13 +834,12 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
// handle exit, false means somebody else did
should_exit_batch_group = write_thread_.CompleteParallelMemTableWriter(&w);
}
if (wbwi && status.ok() && w.status.ok()) {
uint32_t wbwi_count = wbwi->GetWriteBatch()->Count();
// skip empty batch case
if (wbwi_count) {
if (wbwi) {
if (status.ok() && w.status.ok()) {
// w.batch contains (potentially empty) commit time batch updates,
// only ingest wbwi if w.batch is applied to memtable successfully
uint32_t memtable_update_count = w.batch->Count();
uint32_t wbwi_count = wbwi->GetWriteBatch()->Count();
// Seqno assigned to this write are [last_seq + 1 - seq_inc, last_seq].
// seq_inc includes w.batch (memtable updates) and wbwi
// w.batch gets first `memtable_update_count` sequence numbers.
@@ -924,11 +852,10 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
if (two_write_queues_) {
assert(ub <= versions_->LastAllocatedSequence());
}
status =
IngestWBWIAsMemtable(wbwi, {/*lower_bound=*/lb, /*upper_bound=*/ub},
/*min_prep_log=*/log_ref, last_sequence,
/*memtable_updated=*/memtable_update_count > 0,
write_options.ignore_missing_column_families);
status = IngestWBWI(wbwi, {/*lower_bound=*/lb, /*upper_bound=*/ub},
prep_log, last_sequence,
/*memtable_updated=*/memtable_update_count > 0,
write_options.ignore_missing_column_families);
}
}
@@ -946,19 +873,9 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
}
// Note: if we are to resume after non-OK statuses we need to revisit how
// we react to non-OK statuses here.
if (w.status.ok()) { // Don't publish a partial batch write
versions_->SetLastSequence(last_sequence);
}
}
if (!w.status.ok()) {
if (wal_context.prev_size < SIZE_MAX) {
InstrumentedMutexLock l(&wal_write_mutex_);
if (logs_.back().number == wal_context.wal_file_number_size->number) {
logs_.back().SetAttemptTruncateSize(wal_context.prev_size);
}
}
HandleMemTableInsertFailure(w.status);
versions_->SetLastSequence(last_sequence);
}
MemTableInsertStatusCheck(w.status);
write_thread_.ExitAsBatchGroupLeader(write_group, status);
}
@@ -971,7 +888,7 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
Status DBImpl::PipelinedWriteImpl(const WriteOptions& write_options,
WriteBatch* my_batch, WriteCallback* callback,
UserWriteCallback* user_write_cb,
uint64_t* wal_used, uint64_t log_ref,
uint64_t* log_used, uint64_t log_ref,
bool disable_memtable, uint64_t* seq_used) {
PERF_TIMER_GUARD(write_pre_and_post_process_time);
StopWatch write_sw(immutable_db_options_.clock, stats_, DB_WRITE);
@@ -988,10 +905,10 @@ Status DBImpl::PipelinedWriteImpl(const WriteOptions& write_options,
if (w.callback && !w.callback->AllowWriteBatching()) {
write_thread_.WaitForMemTableWriters();
}
WalContext wal_context(!write_options.disableWAL && write_options.sync);
LogContext log_context(!write_options.disableWAL && write_options.sync);
// PreprocessWrite does its own perf timing.
PERF_TIMER_STOP(write_pre_and_post_process_time);
w.status = PreprocessWrite(write_options, &wal_context, &write_context);
w.status = PreprocessWrite(write_options, &log_context, &write_context);
PERF_TIMER_START(write_pre_and_post_process_time);
// This can set non-OK status if callback fail.
@@ -1060,13 +977,13 @@ Status DBImpl::PipelinedWriteImpl(const WriteOptions& write_options,
wal_write_group.size - 1);
RecordTick(stats_, WRITE_DONE_BY_OTHER, wal_write_group.size - 1);
}
assert(wal_context.wal_file_number_size);
WalFileNumberSize& wal_file_number_size =
*(wal_context.wal_file_number_size);
io_s = WriteGroupToWAL(wal_write_group, wal_context.writer, wal_used,
wal_context.need_wal_sync,
wal_context.need_wal_dir_sync, current_sequence,
wal_file_number_size);
assert(log_context.log_file_number_size);
LogFileNumberSize& log_file_number_size =
*(log_context.log_file_number_size);
io_s =
WriteToWAL(wal_write_group, log_context.writer, log_used,
log_context.need_log_sync, log_context.need_log_dir_sync,
current_sequence, log_file_number_size);
w.status = io_s;
}
@@ -1078,13 +995,13 @@ Status DBImpl::PipelinedWriteImpl(const WriteOptions& write_options,
}
VersionEdit synced_wals;
if (wal_context.need_wal_sync) {
InstrumentedMutexLock l(&wal_write_mutex_);
if (log_context.need_log_sync) {
InstrumentedMutexLock l(&log_write_mutex_);
if (w.status.ok()) {
MarkLogsSynced(cur_wal_number_, wal_context.need_wal_dir_sync,
MarkLogsSynced(logfile_number_, log_context.need_log_dir_sync,
&synced_wals);
} else {
MarkLogsNotSynced(cur_wal_number_);
MarkLogsNotSynced(logfile_number_);
}
}
if (w.status.ok() && synced_wals.IsWalAddition()) {
@@ -1115,12 +1032,7 @@ Status DBImpl::PipelinedWriteImpl(const WriteOptions& write_options,
&flush_scheduler_, &trim_history_scheduler_,
write_options.ignore_missing_column_families, 0 /*log_number*/, this,
false /*concurrent_memtable_writes*/, seq_per_batch_, batch_per_txn_);
if (memtable_write_group.status
.ok()) { // Don't publish a partial batch write
versions_->SetLastSequence(memtable_write_group.last_sequence);
} else {
HandleMemTableInsertFailure(memtable_write_group.status);
}
versions_->SetLastSequence(memtable_write_group.last_sequence);
write_thread_.ExitAsMemTableWriter(&w, memtable_write_group);
}
} else {
@@ -1149,11 +1061,8 @@ Status DBImpl::PipelinedWriteImpl(const WriteOptions& write_options,
PERF_TIMER_START(write_pre_and_post_process_time);
if (write_thread_.CompleteParallelMemTableWriter(&w)) {
if (w.status.ok()) { // Don't publish a partial batch write
versions_->SetLastSequence(w.write_group->last_sequence);
} else {
HandleMemTableInsertFailure(w.status);
}
MemTableInsertStatusCheck(w.status);
versions_->SetLastSequence(w.write_group->last_sequence);
write_thread_.ExitAsMemTableWriter(&w, *w.write_group);
}
}
@@ -1225,7 +1134,7 @@ Status DBImpl::UnorderedWriteMemtable(const WriteOptions& write_options,
Status DBImpl::WriteImplWALOnly(
WriteThread* write_thread, const WriteOptions& write_options,
WriteBatch* my_batch, WriteCallback* callback,
UserWriteCallback* user_write_cb, uint64_t* wal_used,
UserWriteCallback* user_write_cb, uint64_t* log_used,
const uint64_t log_ref, uint64_t* seq_used, const size_t sub_batch_cnt,
PreReleaseCallback* pre_release_callback, const AssignOrder assign_order,
const PublishLastSeq publish_last_seq, const bool disable_memtable) {
@@ -1238,8 +1147,8 @@ Status DBImpl::WriteImplWALOnly(
write_thread->JoinBatchGroup(&w);
assert(w.state != WriteThread::STATE_PARALLEL_MEMTABLE_WRITER);
if (w.state == WriteThread::STATE_COMPLETED) {
if (wal_used != nullptr) {
*wal_used = w.wal_used;
if (log_used != nullptr) {
*log_used = w.log_used;
}
if (seq_used != nullptr) {
*seq_used = w.sequence;
@@ -1255,10 +1164,10 @@ Status DBImpl::WriteImplWALOnly(
// TODO(myabandeh): Make preliminary checks thread-safe so we could do them
// without paying the cost of obtaining the mutex.
WalContext wal_context;
LogContext log_context;
WriteContext write_context;
Status status =
PreprocessWrite(write_options, &wal_context, &write_context);
PreprocessWrite(write_options, &log_context, &write_context);
WriteStatusCheckOnLocked(status);
if (!status.ok()) {
@@ -1355,8 +1264,8 @@ Status DBImpl::WriteImplWALOnly(
}
Status status;
if (!write_options.disableWAL) {
IOStatus io_s = ConcurrentWriteGroupToWAL(write_group, wal_used,
&last_sequence, seq_inc);
IOStatus io_s =
ConcurrentWriteToWAL(write_group, log_used, &last_sequence, seq_inc);
status = io_s;
// last_sequence may not be set if there is an error
// This error checking and return is moved up to avoid using uninitialized
@@ -1408,7 +1317,7 @@ Status DBImpl::WriteImplWALOnly(
if (!writer->CallbackFailed() && writer->pre_release_callback) {
assert(writer->sequence != kMaxSequenceNumber);
Status ws = writer->pre_release_callback->Callback(
writer->sequence, disable_memtable, writer->wal_used, index++,
writer->sequence, disable_memtable, writer->log_used, index++,
pre_release_callback_cnt);
if (!ws.ok()) {
status = ws;
@@ -1477,22 +1386,24 @@ void DBImpl::WALIOStatusCheck(const IOStatus& io_status) {
}
}
void DBImpl::HandleMemTableInsertFailure(const Status& status) {
assert(!status.ok());
// A non-OK status on memtable insert indicates that the state implied by the
// WAL has diverged from the in-memory state. This could be because of a
// corrupt write_batch (very bad), or because the client specified an invalid
// column family and didn't specify ignore_missing_column_families.
mutex_.Lock();
assert(!error_handler_.IsBGWorkStopped());
error_handler_.SetBGError(status, BackgroundErrorReason::kMemTable);
mutex_.Unlock();
void DBImpl::MemTableInsertStatusCheck(const Status& status) {
// A non-OK status here indicates that the state implied by the
// WAL has diverged from the in-memory state. This could be
// because of a corrupt write_batch (very bad), or because the
// client specified an invalid column family and didn't specify
// ignore_missing_column_families.
if (!status.ok()) {
mutex_.Lock();
assert(!error_handler_.IsBGWorkStopped());
error_handler_.SetBGError(status, BackgroundErrorReason::kMemTable);
mutex_.Unlock();
}
}
Status DBImpl::PreprocessWrite(const WriteOptions& write_options,
WalContext* wal_context,
LogContext* log_context,
WriteContext* write_context) {
assert(write_context != nullptr && wal_context != nullptr);
assert(write_context != nullptr && log_context != nullptr);
Status status;
if (error_handler_.IsDBStopped()) {
@@ -1502,8 +1413,7 @@ Status DBImpl::PreprocessWrite(const WriteOptions& write_options,
PERF_TIMER_GUARD(write_scheduling_flushes_compactions_time);
if (UNLIKELY(status.ok() &&
wals_total_size_.LoadRelaxed() > GetMaxTotalWalSize())) {
if (UNLIKELY(status.ok() && total_log_size_ > GetMaxTotalWalSize())) {
assert(versions_);
InstrumentedMutexLock l(&mutex_);
const ColumnFamilySet* const column_families =
@@ -1572,17 +1482,17 @@ Status DBImpl::PreprocessWrite(const WriteOptions& write_options,
WriteBufferManagerStallWrites();
}
}
InstrumentedMutexLock l(&wal_write_mutex_);
if (status.ok() && wal_context->need_wal_sync) {
InstrumentedMutexLock l(&log_write_mutex_);
if (status.ok() && log_context->need_log_sync) {
// Wait until the parallel syncs are finished. Any sync process has to sync
// the front log too so it is enough to check the status of front()
// We do a while loop since wal_sync_cv_ is signalled when any sync is
// We do a while loop since log_sync_cv_ is signalled when any sync is
// finished
// Note: there does not seem to be a reason to wait for parallel sync at
// this early step but it is not important since parallel sync (SyncWAL) and
// need_wal_sync are usually not used together.
// need_log_sync are usually not used together.
while (logs_.front().IsSyncing()) {
wal_sync_cv_.Wait();
log_sync_cv_.Wait();
}
for (auto& log : logs_) {
// This is just to prevent the logs to be synced by a parallel SyncWAL
@@ -1593,12 +1503,12 @@ Status DBImpl::PreprocessWrite(const WriteOptions& write_options,
log.PrepareForSync();
}
} else {
wal_context->need_wal_sync = false;
log_context->need_log_sync = false;
}
wal_context->writer = logs_.back().writer;
wal_context->need_wal_dir_sync =
wal_context->need_wal_dir_sync && !wal_dir_synced_;
wal_context->wal_file_number_size = std::addressof(alive_wal_files_.back());
log_context->writer = logs_.back().writer;
log_context->need_log_dir_sync =
log_context->need_log_dir_sync && !log_dir_synced_;
log_context->log_file_number_size = std::addressof(alive_log_files_.back());
return status;
}
@@ -1649,12 +1559,12 @@ Status DBImpl::MergeBatch(const WriteThread::WriteGroup& write_group,
}
// When two_write_queues_ is disabled, this function is called from the only
// write thread. Otherwise this must be called holding wal_write_mutex_.
// write thread. Otherwise this must be called holding log_write_mutex_.
IOStatus DBImpl::WriteToWAL(const WriteBatch& merged_batch,
const WriteOptions& write_options,
log::Writer* log_writer, uint64_t* wal_used,
log::Writer* log_writer, uint64_t* log_used,
uint64_t* log_size,
WalFileNumberSize& wal_file_number_size,
LogFileNumberSize& log_file_number_size,
SequenceNumber sequence) {
assert(log_size != nullptr);
@@ -1666,7 +1576,7 @@ IOStatus DBImpl::WriteToWAL(const WriteBatch& merged_batch,
}
*log_size = log_entry.size();
// When two_write_queues_ WriteToWAL has to be protected from concurretn calls
// from the two queues anyway and wal_write_mutex_ is already held. Otherwise
// from the two queues anyway and log_write_mutex_ is already held. Otherwise
// if manual_wal_flush_ is enabled we need to protect log_writer->AddRecord
// from possible concurrent calls via the FlushWAL by the application.
const bool needs_locking = manual_wal_flush_ && !two_write_queues_;
@@ -1674,7 +1584,7 @@ IOStatus DBImpl::WriteToWAL(const WriteBatch& merged_batch,
// manual_wal_flush_ feature (by UNLIKELY) instead of the more common case
// when we do not need any locking.
if (UNLIKELY(needs_locking)) {
wal_write_mutex_.Lock();
log_write_mutex_.Lock();
}
IOStatus io_s = log_writer->MaybeAddUserDefinedTimestampSizeRecord(
write_options, versions_->GetColumnFamiliesTimestampSizeForRecord());
@@ -1684,24 +1594,23 @@ IOStatus DBImpl::WriteToWAL(const WriteBatch& merged_batch,
io_s = log_writer->AddRecord(write_options, log_entry, sequence);
if (UNLIKELY(needs_locking)) {
wal_write_mutex_.Unlock();
log_write_mutex_.Unlock();
}
if (wal_used != nullptr) {
*wal_used = cur_wal_number_;
assert(*wal_used == wal_file_number_size.number);
if (log_used != nullptr) {
*log_used = logfile_number_;
}
wals_total_size_.FetchAddRelaxed(log_entry.size());
wal_file_number_size.AddSize(*log_size);
wal_empty_ = false;
total_log_size_ += log_entry.size();
log_file_number_size.AddSize(*log_size);
log_empty_ = false;
return io_s;
}
IOStatus DBImpl::WriteGroupToWAL(const WriteThread::WriteGroup& write_group,
log::Writer* log_writer, uint64_t* wal_used,
bool need_wal_sync, bool need_wal_dir_sync,
SequenceNumber sequence,
WalFileNumberSize& wal_file_number_size) {
IOStatus DBImpl::WriteToWAL(const WriteThread::WriteGroup& write_group,
log::Writer* log_writer, uint64_t* log_used,
bool need_log_sync, bool need_log_dir_sync,
SequenceNumber sequence,
LogFileNumberSize& log_file_number_size) {
IOStatus io_s;
assert(!two_write_queues_);
assert(!write_group.leader->disable_wal);
@@ -1716,10 +1625,10 @@ IOStatus DBImpl::WriteGroupToWAL(const WriteThread::WriteGroup& write_group,
}
if (merged_batch == write_group.leader->batch) {
write_group.leader->wal_used = cur_wal_number_;
write_group.leader->log_used = logfile_number_;
} else if (write_with_wal > 1) {
for (auto writer : write_group) {
writer->wal_used = cur_wal_number_;
writer->log_used = logfile_number_;
}
}
@@ -1731,14 +1640,14 @@ IOStatus DBImpl::WriteGroupToWAL(const WriteThread::WriteGroup& write_group,
WriteOptions write_options;
write_options.rate_limiter_priority =
write_group.leader->rate_limiter_priority;
io_s = WriteToWAL(*merged_batch, write_options, log_writer, wal_used,
&log_size, wal_file_number_size, sequence);
io_s = WriteToWAL(*merged_batch, write_options, log_writer, log_used,
&log_size, log_file_number_size, sequence);
if (to_be_cached_state) {
cached_recoverable_state_ = *to_be_cached_state;
cached_recoverable_state_empty_ = false;
}
if (io_s.ok() && need_wal_sync) {
if (io_s.ok() && need_log_sync) {
StopWatch sw(immutable_db_options_.clock, stats_, WAL_FILE_SYNC_MICROS);
// It's safe to access logs_ with unlocked mutex_ here because:
// - we've set getting_synced=true for all logs,
@@ -1748,15 +1657,15 @@ IOStatus DBImpl::WriteGroupToWAL(const WriteThread::WriteGroup& write_group,
// - as long as other threads don't modify it, it's safe to read
// from std::deque from multiple threads concurrently.
//
// Sync operation should work with locked wal_write_mutex_, because:
// Sync operation should work with locked log_write_mutex_, because:
// when DBOptions.manual_wal_flush_ is set,
// FlushWAL function will be invoked by another thread.
// if without locked wal_write_mutex_, the log file may get data
// if without locked log_write_mutex_, the log file may get data
// corruption
const bool needs_locking = manual_wal_flush_ && !two_write_queues_;
if (UNLIKELY(needs_locking)) {
wal_write_mutex_.Lock();
log_write_mutex_.Lock();
}
if (io_s.ok()) {
@@ -1779,10 +1688,10 @@ IOStatus DBImpl::WriteGroupToWAL(const WriteThread::WriteGroup& write_group,
}
if (UNLIKELY(needs_locking)) {
wal_write_mutex_.Unlock();
log_write_mutex_.Unlock();
}
if (io_s.ok() && need_wal_dir_sync) {
if (io_s.ok() && need_log_dir_sync) {
// We only sync WAL directory the first time WAL syncing is
// requested, so that in case users never turn on WAL sync,
// we can avoid the disk I/O in the write code path.
@@ -1797,7 +1706,7 @@ IOStatus DBImpl::WriteGroupToWAL(const WriteThread::WriteGroup& write_group,
}
if (io_s.ok()) {
auto stats = default_cf_internal_stats_;
if (need_wal_sync) {
if (need_log_sync) {
stats->AddDBStats(InternalStats::kIntStatsWalFileSynced, 1);
RecordTick(stats_, WAL_FILE_SYNCED);
}
@@ -1814,8 +1723,8 @@ IOStatus DBImpl::WriteGroupToWAL(const WriteThread::WriteGroup& write_group,
return io_s;
}
IOStatus DBImpl::ConcurrentWriteGroupToWAL(
const WriteThread::WriteGroup& write_group, uint64_t* wal_used,
IOStatus DBImpl::ConcurrentWriteToWAL(
const WriteThread::WriteGroup& write_group, uint64_t* log_used,
SequenceNumber* last_sequence, size_t seq_inc) {
IOStatus io_s;
@@ -1832,14 +1741,14 @@ IOStatus DBImpl::ConcurrentWriteGroupToWAL(
return io_s;
}
// We need to lock wal_write_mutex_ since logs_ and alive_wal_files might be
// We need to lock log_write_mutex_ since logs_ and alive_log_files might be
// pushed back concurrently
wal_write_mutex_.Lock();
log_write_mutex_.Lock();
if (merged_batch == write_group.leader->batch) {
write_group.leader->wal_used = cur_wal_number_;
write_group.leader->log_used = logfile_number_;
} else if (write_with_wal > 1) {
for (auto writer : write_group) {
writer->wal_used = cur_wal_number_;
writer->log_used = logfile_number_;
}
}
*last_sequence = versions_->FetchAddLastAllocatedSequence(seq_inc);
@@ -1847,9 +1756,9 @@ IOStatus DBImpl::ConcurrentWriteGroupToWAL(
WriteBatchInternal::SetSequence(merged_batch, sequence);
log::Writer* log_writer = logs_.back().writer;
WalFileNumberSize& wal_file_number_size = alive_wal_files_.back();
LogFileNumberSize& log_file_number_size = alive_log_files_.back();
assert(log_writer->get_log_number() == wal_file_number_size.number);
assert(log_writer->get_log_number() == log_file_number_size.number);
uint64_t log_size;
@@ -1857,13 +1766,13 @@ IOStatus DBImpl::ConcurrentWriteGroupToWAL(
WriteOptions write_options;
write_options.rate_limiter_priority =
write_group.leader->rate_limiter_priority;
io_s = WriteToWAL(*merged_batch, write_options, log_writer, wal_used,
&log_size, wal_file_number_size, sequence);
io_s = WriteToWAL(*merged_batch, write_options, log_writer, log_used,
&log_size, log_file_number_size, sequence);
if (to_be_cached_state) {
cached_recoverable_state_ = *to_be_cached_state;
cached_recoverable_state_empty_ = false;
}
wal_write_mutex_.Unlock();
log_write_mutex_.Unlock();
if (io_s.ok()) {
const bool concurrent = true;
@@ -1891,7 +1800,7 @@ Status DBImpl::WriteRecoverableState() {
bool dont_care_bool;
SequenceNumber next_seq;
if (two_write_queues_) {
wal_write_mutex_.Lock();
log_write_mutex_.Lock();
}
SequenceNumber seq;
if (two_write_queues_) {
@@ -1906,17 +1815,13 @@ Status DBImpl::WriteRecoverableState() {
0 /*recovery_log_number*/, this, false /* concurrent_memtable_writes */,
&next_seq, &dont_care_bool, seq_per_batch_);
auto last_seq = next_seq - 1;
if (status.ok()) { // Don't publish a partial batch write
if (two_write_queues_) {
versions_->FetchAddLastAllocatedSequence(last_seq - seq);
versions_->SetLastPublishedSequence(last_seq);
}
versions_->SetLastSequence(last_seq);
} else {
HandleMemTableInsertFailure(status);
}
if (two_write_queues_) {
wal_write_mutex_.Unlock();
versions_->FetchAddLastAllocatedSequence(last_seq - seq);
versions_->SetLastPublishedSequence(last_seq);
}
versions_->SetLastSequence(last_seq);
if (two_write_queues_) {
log_write_mutex_.Unlock();
}
if (status.ok() && recoverable_state_pre_release_callback_) {
const bool DISABLE_MEMTABLE = true;
@@ -1988,10 +1893,7 @@ void DBImpl::AssignAtomicFlushSeq(const autovector<ColumnFamilyData*>& cfds) {
assert(immutable_db_options_.atomic_flush);
auto seq = versions_->LastSequence();
for (auto cfd : cfds) {
// cfd can be nullptr, see ScheduleFlushes()
if (cfd) {
cfd->imm()->AssignAtomicFlushSeq(seq);
}
cfd->imm()->AssignAtomicFlushSeq(seq);
}
}
@@ -2000,11 +1902,11 @@ Status DBImpl::SwitchWAL(WriteContext* write_context) {
assert(write_context != nullptr);
Status status;
if (alive_wal_files_.begin()->getting_flushed) {
if (alive_log_files_.begin()->getting_flushed) {
return status;
}
auto oldest_alive_log = alive_wal_files_.begin()->number;
auto oldest_alive_log = alive_log_files_.begin()->number;
bool flush_wont_release_oldest_log = false;
if (allow_2pc()) {
auto oldest_log_with_uncommitted_prep =
@@ -2034,14 +1936,14 @@ Status DBImpl::SwitchWAL(WriteContext* write_context) {
// transactions then we cannot flush this log until those transactions are
// commited.
unable_to_release_oldest_log_ = false;
alive_wal_files_.begin()->getting_flushed = true;
alive_log_files_.begin()->getting_flushed = true;
}
ROCKS_LOG_INFO(
immutable_db_options_.info_log,
"Flushing all column families with data in WAL number %" PRIu64
". Total log size is %" PRIu64 " while max_total_wal_size is %" PRIu64,
oldest_alive_log, wals_total_size_.LoadRelaxed(), GetMaxTotalWalSize());
oldest_alive_log, total_log_size_.load(), GetMaxTotalWalSize());
// no need to refcount because drop is happening in write thread, so can't
// happen while we're in the write thread
autovector<ColumnFamilyData*> cfds;
@@ -2511,21 +2413,21 @@ Status DBImpl::SwitchMemtable(ColumnFamilyData* cfd, WriteContext* context,
// Do this without holding the dbmutex lock.
assert(versions_->prev_log_number() == 0);
if (two_write_queues_) {
wal_write_mutex_.Lock();
log_write_mutex_.Lock();
}
bool creating_new_log = !wal_empty_;
bool creating_new_log = !log_empty_;
if (two_write_queues_) {
wal_write_mutex_.Unlock();
log_write_mutex_.Unlock();
}
uint64_t recycle_log_number = 0;
// If file deletion is disabled, don't recycle logs since it'll result in
// the file getting renamed
if (creating_new_log && immutable_db_options_.recycle_log_file_num &&
!wal_recycle_files_.empty() && IsFileDeletionsEnabled()) {
recycle_log_number = wal_recycle_files_.front();
!log_recycle_files_.empty() && IsFileDeletionsEnabled()) {
recycle_log_number = log_recycle_files_.front();
}
uint64_t new_log_number =
creating_new_log ? versions_->NewFileNumber() : cur_wal_number_;
creating_new_log ? versions_->NewFileNumber() : logfile_number_;
// For use outside of holding DB mutex
const MutableCFOptions mutable_cf_options_copy =
cfd->GetLatestMutableCFOptions();
@@ -2551,14 +2453,14 @@ Status DBImpl::SwitchMemtable(ColumnFamilyData* cfd, WriteContext* context,
mutex_.Unlock();
if (creating_new_log) {
PredecessorWALInfo info;
wal_write_mutex_.Lock();
log_write_mutex_.Lock();
if (!logs_.empty()) {
log::Writer* cur_log_writer = logs_.back().writer;
info = PredecessorWALInfo(cur_log_writer->get_log_number(),
cur_log_writer->file()->GetFileSize(),
cur_log_writer->GetLastSeqnoRecorded());
}
wal_write_mutex_.Unlock();
log_write_mutex_.Unlock();
// TODO: Write buffer size passed in should be max of all CF's instead
// of mutable_cf_options.write_buffer_size.
io_s = CreateWAL(write_options, new_log_number, recycle_log_number,
@@ -2599,11 +2501,11 @@ Status DBImpl::SwitchMemtable(ColumnFamilyData* cfd, WriteContext* context,
// concurrent full purges don't delete the file while we're recycling it.
// To achieve that we hold the old log number in the recyclable list until
// after it has been renamed.
assert(wal_recycle_files_.front() == recycle_log_number);
wal_recycle_files_.pop_front();
assert(log_recycle_files_.front() == recycle_log_number);
log_recycle_files_.pop_front();
}
if (s.ok() && creating_new_log) {
InstrumentedMutexLock l(&wal_write_mutex_);
InstrumentedMutexLock l(&log_write_mutex_);
assert(new_log != nullptr);
if (!logs_.empty()) {
// Alway flush the buffer of the last log before switching to a new one
@@ -2625,11 +2527,11 @@ Status DBImpl::SwitchMemtable(ColumnFamilyData* cfd, WriteContext* context,
}
}
if (s.ok()) {
cur_wal_number_ = new_log_number;
wal_empty_ = true;
wal_dir_synced_ = false;
logs_.emplace_back(cur_wal_number_, new_log);
alive_wal_files_.emplace_back(cur_wal_number_);
logfile_number_ = new_log_number;
log_empty_ = true;
log_dir_synced_ = false;
logs_.emplace_back(logfile_number_, new_log);
alive_log_files_.emplace_back(logfile_number_);
}
}
@@ -2660,7 +2562,7 @@ Status DBImpl::SwitchMemtable(ColumnFamilyData* cfd, WriteContext* context,
// obsolete. So we should track the WAL obsoletion event before actually
// updating the empty CF's log number.
uint64_t min_wal_number_to_keep =
versions_->PreComputeMinLogNumberWithUnflushedData(cur_wal_number_);
versions_->PreComputeMinLogNumberWithUnflushedData(logfile_number_);
if (min_wal_number_to_keep >
versions_->GetWalSet().GetMinWalNumberToKeep()) {
// TODO: plumb Env::IOActivity, Env::IOPriority
@@ -2695,7 +2597,7 @@ Status DBImpl::SwitchMemtable(ColumnFamilyData* cfd, WriteContext* context,
for (auto cf : empty_cfs) {
if (cf->IsEmpty()) {
cf->SetLogNumber(cur_wal_number_);
cf->SetLogNumber(logfile_number_);
// MEMPURGE: No need to change this, because new adds
// should still receive new sequence numbers.
cf->mem()->SetCreationSeq(versions_->LastSequence());
@@ -2712,14 +2614,14 @@ Status DBImpl::SwitchMemtable(ColumnFamilyData* cfd, WriteContext* context,
// advance the log number. no need to persist this in the manifest
if (cf->IsEmpty()) {
if (creating_new_log) {
cf->SetLogNumber(cur_wal_number_);
cf->SetLogNumber(logfile_number_);
}
cf->mem()->SetCreationSeq(versions_->LastSequence());
}
}
}
cfd->mem()->SetNextLogNumber(cur_wal_number_);
cfd->mem()->SetNextLogNumber(logfile_number_);
assert(new_mem != nullptr);
cfd->imm()->Add(cfd->mem(), &context->memtables_to_free_);
if (new_imm) {
@@ -2731,7 +2633,7 @@ Status DBImpl::SwitchMemtable(ColumnFamilyData* cfd, WriteContext* context,
// we always try to flush all immutable memtable. For atomic flush, these
// two memtables will be marked eligible for flush in the same call to
// AssignAtomicFlushSeq().
new_imm->SetNextLogNumber(cur_wal_number_);
new_imm->SetNextLogNumber(logfile_number_);
cfd->imm()->Add(new_imm, &context->memtables_to_free_);
}
new_mem->Ref();
+26 -29
View File
@@ -9,6 +9,7 @@
#include "db/db_iter.h"
#include <iostream>
#include <limits>
#include <string>
@@ -41,8 +42,9 @@ DBIter::DBIter(Env* _env, const ReadOptions& read_options,
const MutableCFOptions& mutable_cf_options,
const Comparator* cmp, InternalIterator* iter,
const Version* version, SequenceNumber s, bool arena_mode,
uint64_t max_sequential_skip_in_iterations,
ReadCallback* read_callback, ColumnFamilyHandleImpl* cfh,
bool expose_blob_index, ReadOnlyMemTable* active_mem)
bool expose_blob_index)
: prefix_extractor_(mutable_cf_options.prefix_extractor.get()),
env_(_env),
clock_(ioptions.clock),
@@ -56,21 +58,11 @@ DBIter::DBIter(Env* _env, const ReadOptions& read_options,
read_callback_(read_callback),
sequence_(s),
statistics_(ioptions.stats),
max_skip_(mutable_cf_options.max_sequential_skip_in_iterations),
max_skip_(max_sequential_skip_in_iterations),
max_skippable_internal_keys_(read_options.max_skippable_internal_keys),
num_internal_keys_skipped_(0),
iterate_lower_bound_(read_options.iterate_lower_bound),
iterate_upper_bound_(read_options.iterate_upper_bound),
cfh_(cfh),
timestamp_ub_(read_options.timestamp),
timestamp_lb_(read_options.iter_start_ts),
timestamp_size_(timestamp_ub_ ? timestamp_ub_->size() : 0),
active_mem_(active_mem),
memtable_seqno_lb_((active_mem_ && !active_mem_->IsEmpty())
? active_mem_->GetFirstSequenceNumber()
: kMaxSequenceNumber),
memtable_op_scan_flush_trigger_(
mutable_cf_options.memtable_op_scan_flush_trigger),
direction_(kForward),
valid_(false),
current_entry_is_merged_(false),
@@ -84,7 +76,11 @@ DBIter::DBIter(Env* _env, const ReadOptions& read_options,
expose_blob_index_(expose_blob_index),
allow_unprepared_value_(read_options.allow_unprepared_value),
is_blob_(false),
arena_mode_(arena_mode) {
arena_mode_(arena_mode),
cfh_(cfh),
timestamp_ub_(read_options.timestamp),
timestamp_lb_(read_options.iter_start_ts),
timestamp_size_(timestamp_ub_ ? timestamp_ub_->size() : 0) {
RecordTick(statistics_, NO_ITERATOR_CREATED);
if (pin_thru_lifetime_) {
pinned_iters_mgr_.StartPinning();
@@ -373,8 +369,6 @@ bool DBIter::FindNextUserEntryInternal(bool skipping_saved_key,
// to one.
bool reseek_done = false;
uint64_t mem_ops_scanned = 0;
bool marked_for_flush = false;
do {
// Will update is_key_seqnum_zero_ as soon as we parsed the current key
// but we need to save the previous value to be used in the loop.
@@ -431,12 +425,6 @@ bool DBIter::FindNextUserEntryInternal(bool skipping_saved_key,
CompareKeyForSkip(ikey_.user_key, saved_key_.GetUserKey()) <= 0) {
num_skipped++; // skip this entry
PERF_COUNTER_ADD(internal_key_skipped_count, 1);
if (memtable_op_scan_flush_trigger_ && active_mem_ &&
ikey_.sequence >= memtable_seqno_lb_ && !marked_for_flush &&
++mem_ops_scanned >= memtable_op_scan_flush_trigger_) {
active_mem_->MarkForFlush();
marked_for_flush = true;
}
} else {
assert(!skipping_saved_key ||
CompareKeyForSkip(ikey_.user_key, saved_key_.GetUserKey()) > 0);
@@ -458,12 +446,6 @@ bool DBIter::FindNextUserEntryInternal(bool skipping_saved_key,
!iter_.iter()->IsKeyPinned() /* copy */);
skipping_saved_key = true;
PERF_COUNTER_ADD(internal_delete_skipped_count, 1);
if (memtable_op_scan_flush_trigger_ && active_mem_ &&
ikey_.sequence >= memtable_seqno_lb_ && !marked_for_flush &&
++mem_ops_scanned >= memtable_op_scan_flush_trigger_) {
active_mem_->MarkForFlush();
marked_for_flush = true;
}
}
break;
case kTypeValue:
@@ -1242,8 +1224,6 @@ bool DBIter::FindValueForCurrentKeyUsingSeek() {
if (timestamp_lb_ != nullptr) {
saved_key_.SetInternalKey(ikey);
} else {
saved_key_.SetUserKey(ikey.user_key);
}
valid_ = true;
@@ -1810,4 +1790,21 @@ void DBIter::SeekToLast() {
StripTimestampFromUserKey(saved_key_.GetUserKey(), timestamp_size_)));
}
}
Iterator* NewDBIterator(Env* env, const ReadOptions& read_options,
const ImmutableOptions& ioptions,
const MutableCFOptions& mutable_cf_options,
const Comparator* user_key_comparator,
InternalIterator* internal_iter, const Version* version,
const SequenceNumber& sequence,
uint64_t max_sequential_skip_in_iterations,
ReadCallback* read_callback,
ColumnFamilyHandleImpl* cfh, bool expose_blob_index) {
DBIter* db_iter = new DBIter(
env, read_options, ioptions, mutable_cf_options, user_key_comparator,
internal_iter, version, sequence, false,
max_sequential_skip_in_iterations, read_callback, cfh, expose_blob_index);
return db_iter;
}
} // namespace ROCKSDB_NAMESPACE
+30 -61
View File
@@ -57,33 +57,6 @@ class Version;
// numbers, deletion markers, overwrites, etc.
class DBIter final : public Iterator {
public:
// Return a new DBIter that reads from `internal_iter` at the specified
// `sequence` number.
//
// @param active_mem Pointer to the active memtable that `internal_iter`
// is reading from. If not null, the memtable can be marked for flush
// according to option mutable_cf_options.memtable_op_scan_flush_trigger.
// @param arena_mode If true, the DBIter will be allocated from the arena.
static DBIter* NewIter(Env* env, const ReadOptions& read_options,
const ImmutableOptions& ioptions,
const MutableCFOptions& mutable_cf_options,
const Comparator* user_key_comparator,
InternalIterator* internal_iter,
const Version* version, const SequenceNumber& sequence,
ReadCallback* read_callback,
ColumnFamilyHandleImpl* cfh = nullptr,
bool expose_blob_index = false,
ReadOnlyMemTable* active_mem = nullptr,
Arena* arena = nullptr) {
void* mem = arena ? arena->AllocateAligned(sizeof(DBIter))
: operator new(sizeof(DBIter));
DBIter* db_iter = new (mem)
DBIter(env, read_options, ioptions, mutable_cf_options,
user_key_comparator, internal_iter, version, sequence, arena,
read_callback, cfh, expose_blob_index, active_mem);
return db_iter;
}
// The following is grossly complicated. TODO: clean it up
// Which direction is the iterator currently moving?
// (1) When moving forward:
@@ -140,6 +113,14 @@ class DBIter final : public Iterator {
uint64_t skip_count_;
};
DBIter(Env* _env, const ReadOptions& read_options,
const ImmutableOptions& ioptions,
const MutableCFOptions& mutable_cf_options, const Comparator* cmp,
InternalIterator* iter, const Version* version, SequenceNumber s,
bool arena_mode, uint64_t max_sequential_skip_in_iterations,
ReadCallback* read_callback, ColumnFamilyHandleImpl* cfh,
bool expose_blob_index);
// No copying allowed
DBIter(const DBIter&) = delete;
void operator=(const DBIter&) = delete;
@@ -239,26 +220,7 @@ class DBIter final : public Iterator {
bool PrepareValue() override;
void Prepare(const std::vector<ScanOptions>& scan_opts) override {
std::optional<std::vector<ScanOptions>> new_scan_opts;
new_scan_opts.emplace(scan_opts);
scan_opts_.swap(new_scan_opts);
if (!scan_opts.empty()) {
iter_.Prepare(&scan_opts_.value());
} else {
iter_.Prepare(nullptr);
}
}
private:
DBIter(Env* _env, const ReadOptions& read_options,
const ImmutableOptions& ioptions,
const MutableCFOptions& mutable_cf_options, const Comparator* cmp,
InternalIterator* iter, const Version* version, SequenceNumber s,
bool arena_mode, ReadCallback* read_callback,
ColumnFamilyHandleImpl* cfh, bool expose_blob_index,
ReadOnlyMemTable* active_mem);
class BlobReader {
public:
BlobReader(const Version* version, ReadTier read_tier,
@@ -463,21 +425,6 @@ class DBIter final : public Iterator {
IterKey prefix_;
Status status_;
Slice lazy_blob_index_;
// List of operands for merge operator.
MergeContext merge_context_;
LocalStatistics local_stats_;
PinnedIteratorsManager pinned_iters_mgr_;
ColumnFamilyHandleImpl* cfh_;
const Slice* const timestamp_ub_;
const Slice* const timestamp_lb_;
const size_t timestamp_size_;
std::string saved_timestamp_;
std::optional<std::vector<ScanOptions>> scan_opts_;
ReadOnlyMemTable* active_mem_;
SequenceNumber memtable_seqno_lb_;
uint32_t memtable_op_scan_flush_trigger_;
Direction direction_;
bool valid_;
bool current_entry_is_merged_;
@@ -496,7 +443,29 @@ class DBIter final : public Iterator {
// the stacked BlobDB implementation is used, false otherwise.
bool expose_blob_index_;
bool allow_unprepared_value_;
Slice lazy_blob_index_;
bool is_blob_;
bool arena_mode_;
// List of operands for merge operator.
MergeContext merge_context_;
LocalStatistics local_stats_;
PinnedIteratorsManager pinned_iters_mgr_;
ColumnFamilyHandleImpl* cfh_;
const Slice* const timestamp_ub_;
const Slice* const timestamp_lb_;
const size_t timestamp_size_;
std::string saved_timestamp_;
};
// Return a new iterator that converts internal keys (yielded by
// "*internal_iter") that were live at the specified `sequence` number
// into appropriate user keys.
Iterator* NewDBIterator(
Env* env, const ReadOptions& read_options, const ImmutableOptions& ioptions,
const MutableCFOptions& mutable_cf_options,
const Comparator* user_key_comparator, InternalIterator* internal_iter,
const Version* version, const SequenceNumber& sequence,
uint64_t max_sequential_skip_in_iterations, ReadCallback* read_callback,
ColumnFamilyHandleImpl* cfh = nullptr, bool expose_blob_index = false);
} // namespace ROCKSDB_NAMESPACE
+3 -2
View File
@@ -528,10 +528,11 @@ TEST_F(DBIteratorStressTest, StressTest) {
internal_iter->target_hidden_fraction =
target_hidden_fraction;
internal_iter->trace = trace;
db_iter.reset(DBIter::NewIter(
db_iter.reset(NewDBIterator(
env_, ropt, ImmutableOptions(options),
MutableCFOptions(options), BytewiseComparator(),
internal_iter, /*version=*/nullptr, sequence,
internal_iter, nullptr /* version */, sequence,
options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
}
+167 -105
View File
@@ -259,9 +259,10 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
internal_iter->Finish();
ReadOptions ro;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
@@ -293,9 +294,10 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
internal_iter->Finish();
ReadOptions ro;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
@@ -320,9 +322,10 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
ReadOptions ro;
ro.iterate_upper_bound = &prefix;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
@@ -353,9 +356,10 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
ReadOptions ro;
ro.iterate_upper_bound = &prefix;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
@@ -389,9 +393,10 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
ReadOptions ro;
ro.iterate_upper_bound = &prefix;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
@@ -420,9 +425,10 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
ReadOptions ro;
ro.iterate_upper_bound = &prefix;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 7 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
SetPerfLevel(kEnableCount);
@@ -459,9 +465,10 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
ReadOptions ro;
ro.iterate_upper_bound = &prefix;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 4 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
@@ -485,9 +492,10 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
ReadOptions ro;
ro.iterate_upper_bound = &prefix;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
@@ -509,9 +517,10 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
ReadOptions ro;
ro.iterate_upper_bound = &prefix;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
@@ -545,9 +554,10 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
ReadOptions ro;
ro.iterate_upper_bound = &prefix;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 7 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
SetPerfLevel(kEnableCount);
@@ -576,9 +586,10 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
internal_iter->Finish();
ReadOptions ro;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToFirst();
@@ -620,9 +631,10 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
internal_iter->Finish();
ReadOptions ro;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 2 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -652,9 +664,10 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
internal_iter->Finish();
ReadOptions ro;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -683,9 +696,10 @@ TEST_F(DBIteratorTest, DBIteratorEmpty) {
TestIterator* internal_iter = new TestIterator(BytewiseComparator());
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 0 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(!db_iter->Valid());
@@ -696,9 +710,10 @@ TEST_F(DBIteratorTest, DBIteratorEmpty) {
TestIterator* internal_iter = new TestIterator(BytewiseComparator());
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 0 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToFirst();
ASSERT_TRUE(!db_iter->Valid());
@@ -720,10 +735,11 @@ TEST_F(DBIteratorTest, DBIteratorUseSkipCountSkips) {
}
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
2 /* sequence */, nullptr /* read_callback */));
2 /* sequence */, options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "c");
@@ -766,10 +782,10 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
internal_iter->Finish();
options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, i + 2 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -804,10 +820,10 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
internal_iter->AddPut("c", "200");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, i + 2 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -835,10 +851,10 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
internal_iter->AddPut("c", "200");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 202 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -870,10 +886,10 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
}
internal_iter->AddPut("c", "200");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, i /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(!db_iter->Valid());
@@ -890,9 +906,10 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
}
internal_iter->AddPut("c", "200");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 200 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -927,10 +944,10 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
}
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, i + 2 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -964,10 +981,10 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
}
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, i + 2 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -1016,9 +1033,10 @@ TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) {
internal_iter->Finish();
ro.max_skippable_internal_keys = 0;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToFirst();
@@ -1063,9 +1081,10 @@ TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) {
internal_iter->Finish();
ro.max_skippable_internal_keys = 2;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToFirst();
@@ -1108,9 +1127,10 @@ TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) {
internal_iter->Finish();
ro.max_skippable_internal_keys = 2;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToFirst();
@@ -1147,9 +1167,10 @@ TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) {
internal_iter->Finish();
ro.max_skippable_internal_keys = 2;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToFirst();
@@ -1183,9 +1204,10 @@ TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) {
internal_iter->Finish();
ro.max_skippable_internal_keys = 2;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
@@ -1214,9 +1236,10 @@ TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) {
internal_iter->Finish();
ro.max_skippable_internal_keys = 2;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToFirst();
@@ -1252,9 +1275,10 @@ TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) {
internal_iter->Finish();
ro.max_skippable_internal_keys = 2;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToFirst();
@@ -1290,10 +1314,10 @@ TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) {
internal_iter->Finish();
ro.max_skippable_internal_keys = i;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 2 * i + 1 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToFirst();
@@ -1345,9 +1369,10 @@ TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) {
options.max_sequential_skip_in_iterations = 1000;
ro.max_skippable_internal_keys = i;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
env_, ro, ioptions, MutableCFOptions(options), BytewiseComparator(),
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 2 * i + 1 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToFirst();
@@ -1387,11 +1412,11 @@ TEST_F(DBIteratorTest, DBIteratorTimedPutBasic) {
internal_iter->AddTimedPut("d", "3", /*write_unix_time=*/0);
internal_iter->Finish();
options.max_sequential_skip_in_iterations = 1;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
7 /* sequence */, nullptr /* read_callback */));
7 /* sequence */, /*max_sequential_skip_in_iterations*/ 1,
nullptr /* read_callback */));
db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1438,10 +1463,11 @@ TEST_F(DBIteratorTest, DBIterator1) {
internal_iter->AddMerge("b", "2");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
1 /* sequence */, nullptr /* read_callback */));
1 /* sequence */, options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1467,10 +1493,11 @@ TEST_F(DBIteratorTest, DBIterator2) {
internal_iter->AddMerge("b", "2");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
0 /* sequence */, nullptr /* read_callback */));
0 /* sequence */, options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1492,10 +1519,11 @@ TEST_F(DBIteratorTest, DBIterator3) {
internal_iter->AddMerge("b", "2");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
2 /* sequence */, nullptr /* read_callback */));
2 /* sequence */, options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1517,10 +1545,11 @@ TEST_F(DBIteratorTest, DBIterator4) {
internal_iter->AddMerge("b", "2");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
4 /* sequence */, nullptr /* read_callback */));
4 /* sequence */, options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1551,9 +1580,10 @@ TEST_F(DBIteratorTest, DBIterator5) {
internal_iter->AddMerge("a", "merge_6");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 0 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -1575,9 +1605,10 @@ TEST_F(DBIteratorTest, DBIterator5) {
internal_iter->AddMerge("a", "merge_6");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 1 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -1599,9 +1630,10 @@ TEST_F(DBIteratorTest, DBIterator5) {
internal_iter->AddMerge("a", "merge_6");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 2 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -1623,9 +1655,10 @@ TEST_F(DBIteratorTest, DBIterator5) {
internal_iter->AddMerge("a", "merge_6");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 3 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -1647,9 +1680,10 @@ TEST_F(DBIteratorTest, DBIterator5) {
internal_iter->AddMerge("a", "merge_6");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 4 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -1671,9 +1705,10 @@ TEST_F(DBIteratorTest, DBIterator5) {
internal_iter->AddMerge("a", "merge_6");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 5 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -1695,9 +1730,10 @@ TEST_F(DBIteratorTest, DBIterator5) {
internal_iter->AddMerge("a", "merge_6");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 6 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -1717,9 +1753,10 @@ TEST_F(DBIteratorTest, DBIterator5) {
internal_iter->AddMerge("a", "merge_2");
internal_iter->AddPut("b", "val_b");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 10 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->Seek("b");
ASSERT_TRUE(db_iter->Valid());
@@ -1748,9 +1785,10 @@ TEST_F(DBIteratorTest, DBIterator6) {
internal_iter->AddMerge("a", "merge_6");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 0 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -1772,9 +1810,10 @@ TEST_F(DBIteratorTest, DBIterator6) {
internal_iter->AddMerge("a", "merge_6");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 1 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -1796,9 +1835,10 @@ TEST_F(DBIteratorTest, DBIterator6) {
internal_iter->AddMerge("a", "merge_6");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 2 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -1820,9 +1860,10 @@ TEST_F(DBIteratorTest, DBIterator6) {
internal_iter->AddMerge("a", "merge_6");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 3 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(!db_iter->Valid());
@@ -1840,9 +1881,10 @@ TEST_F(DBIteratorTest, DBIterator6) {
internal_iter->AddMerge("a", "merge_6");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 4 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -1864,9 +1906,10 @@ TEST_F(DBIteratorTest, DBIterator6) {
internal_iter->AddMerge("a", "merge_6");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 5 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -1888,9 +1931,10 @@ TEST_F(DBIteratorTest, DBIterator6) {
internal_iter->AddMerge("a", "merge_6");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 6 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -1932,9 +1976,10 @@ TEST_F(DBIteratorTest, DBIterator7) {
internal_iter->AddDeletion("c");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 0 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -1968,9 +2013,10 @@ TEST_F(DBIteratorTest, DBIterator7) {
internal_iter->AddDeletion("c");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 2 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -2010,9 +2056,10 @@ TEST_F(DBIteratorTest, DBIterator7) {
internal_iter->AddDeletion("c");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 4 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -2052,9 +2099,10 @@ TEST_F(DBIteratorTest, DBIterator7) {
internal_iter->AddDeletion("c");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 5 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -2099,9 +2147,10 @@ TEST_F(DBIteratorTest, DBIterator7) {
internal_iter->AddDeletion("c");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 6 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -2147,9 +2196,10 @@ TEST_F(DBIteratorTest, DBIterator7) {
internal_iter->AddDeletion("c");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 7 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -2189,9 +2239,10 @@ TEST_F(DBIteratorTest, DBIterator7) {
internal_iter->AddDeletion("c");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 9 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -2237,9 +2288,10 @@ TEST_F(DBIteratorTest, DBIterator7) {
internal_iter->AddDeletion("c");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 13 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -2286,9 +2338,10 @@ TEST_F(DBIteratorTest, DBIterator7) {
internal_iter->AddDeletion("c");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ioptions, mutable_cf_options, BytewiseComparator(),
internal_iter, nullptr /* version */, 14 /* sequence */,
options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -2318,10 +2371,11 @@ TEST_F(DBIteratorTest, DBIterator8) {
internal_iter->AddPut("b", "0");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
10 /* sequence */, nullptr /* read_callback */));
10 /* sequence */, options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "b");
@@ -2349,10 +2403,11 @@ TEST_F(DBIteratorTest, DBIterator9) {
internal_iter->AddMerge("d", "merge_6");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
10 /* sequence */, nullptr /* read_callback */));
10 /* sequence */, options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid());
@@ -2416,10 +2471,11 @@ TEST_F(DBIteratorTest, DBIterator10) {
internal_iter->AddPut("d", "4");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
10 /* sequence */, nullptr /* read_callback */));
10 /* sequence */, options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->Seek("c");
ASSERT_TRUE(db_iter->Valid());
@@ -2456,7 +2512,7 @@ TEST_F(DBIteratorTest, SeekToLastOccurrenceSeq0) {
internal_iter->AddPut("b", "2");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
10 /* sequence */, 0 /* force seek */, nullptr /* read_callback */));
@@ -2486,10 +2542,11 @@ TEST_F(DBIteratorTest, DBIterator11) {
internal_iter->AddMerge("b", "2");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
1 /* sequence */, nullptr /* read_callback */));
1 /* sequence */, options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -2514,7 +2571,7 @@ TEST_F(DBIteratorTest, DBIterator12) {
internal_iter->AddSingleDeletion("b");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
10 /* sequence */, 0 /* force seek */, nullptr /* read_callback */));
@@ -2553,11 +2610,11 @@ TEST_F(DBIteratorTest, DBIterator13) {
internal_iter->AddPut(key, "8");
internal_iter->Finish();
options.max_sequential_skip_in_iterations = 3;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
2 /* sequence */, nullptr /* read_callback */));
2 /* sequence */, 3 /* max_sequential_skip_in_iterations */,
nullptr /* read_callback */));
db_iter->Seek("b");
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), key);
@@ -2583,11 +2640,11 @@ TEST_F(DBIteratorTest, DBIterator14) {
internal_iter->AddPut("c", "9");
internal_iter->Finish();
options.max_sequential_skip_in_iterations = 1;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
4 /* sequence */, nullptr /* read_callback */));
4 /* sequence */, 1 /* max_sequential_skip_in_iterations */,
nullptr /* read_callback */));
db_iter->Seek("b");
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "b");
@@ -2623,11 +2680,11 @@ class DBIterWithMergeIterTest : public testing::Test {
InternalIterator* merge_iter =
NewMergingIterator(&icomp_, child_iters.data(), 2u);
options_.max_sequential_skip_in_iterations = 3;
db_iter_.reset(DBIter::NewIter(
db_iter_.reset(NewDBIterator(
env_, ro_, ImmutableOptions(options_), MutableCFOptions(options_),
BytewiseComparator(), merge_iter, nullptr /* version */,
8 /* read data earlier than seqId 8 */, nullptr /* read_callback */));
8 /* read data earlier than seqId 8 */,
3 /* max iterators before reseek */, nullptr /* read_callback */));
}
Env* env_;
@@ -3063,10 +3120,11 @@ TEST_F(DBIteratorTest, SeekPrefixTombstones) {
internal_iter->Finish();
ro.prefix_same_as_start = true;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
10 /* sequence */, nullptr /* read_callback */));
10 /* sequence */, options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
int skipped_keys = 0;
@@ -3099,10 +3157,11 @@ TEST_F(DBIteratorTest, SeekToFirstLowerBound) {
Slice lower_bound(lower_bound_str);
ro.iterate_lower_bound = &lower_bound;
Options options;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
10 /* sequence */, nullptr /* read_callback */));
10 /* sequence */, options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToFirst();
if (i == kNumKeys + 1) {
@@ -3138,10 +3197,11 @@ TEST_F(DBIteratorTest, PrevLowerBound) {
Slice lower_bound(lower_bound_str);
ro.iterate_lower_bound = &lower_bound;
Options options;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
10 /* sequence */, nullptr /* read_callback */));
10 /* sequence */, options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToLast();
for (int i = kNumKeys; i >= kLowerBound; --i) {
@@ -3166,10 +3226,11 @@ TEST_F(DBIteratorTest, SeekLessLowerBound) {
Slice lower_bound(lower_bound_str);
ro.iterate_lower_bound = &lower_bound;
Options options;
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
10 /* sequence */, nullptr /* read_callback */));
10 /* sequence */, options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
auto before_lower_bound_str = std::to_string(kLowerBound - 1);
Slice before_lower_bound(lower_bound_str);
@@ -3191,10 +3252,11 @@ TEST_F(DBIteratorTest, ReverseToForwardWithDisappearingKeys) {
}
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(DBIter::NewIter(
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ReadOptions(), ImmutableOptions(options), MutableCFOptions(options),
BytewiseComparator(), internal_iter, nullptr /* version */,
10 /* sequence */, nullptr /* read_callback */));
10 /* sequence */, options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekForPrev("a");
ASSERT_TRUE(db_iter->Valid());
-160
View File
@@ -3824,166 +3824,6 @@ TEST_F(DBIteratorTest, IteratorsConsistentViewExplicitSnapshot) {
}
}
TEST_P(DBIteratorTest, MemtableOpsScanFlushTriggerWithSeek) {
// Tests that option memtable_op_scan_flush_trigger works when the limit
// is reached during a Seek() operation.
const int kTrigger = 10;
Random* r = Random::GetTLSInstance();
for (int trigger : {kTrigger, kTrigger + 1}) {
for (bool delete_only : {false, true}) {
Options options;
options.create_if_missing = true;
options.memtable_op_scan_flush_trigger = trigger;
options.level_compaction_dynamic_level_bytes = true;
DestroyAndReopen(options);
// Base data that will be covered by a consecutive sequence of tombstones.
int kNumKeys = delete_only ? kTrigger : kTrigger / 2;
for (int i = 0; i < kNumKeys; ++i) {
ASSERT_OK(Put(Key(i), r->RandomString(100)));
}
ASSERT_OK(Flush());
ASSERT_OK(db_->CompactRange({}, nullptr, nullptr));
ASSERT_EQ(1, NumTableFilesAtLevel(6));
if (delete_only) {
for (int i = 0; i < kNumKeys; ++i) {
ASSERT_OK(SingleDelete(Key(i)));
}
} else {
for (int i = 0; i < kNumKeys; ++i) {
ASSERT_OK(Put(Key(i), r->RandomString(100)));
}
for (int i = 0; i < kNumKeys; ++i) {
ASSERT_OK(Delete(Key(i)));
}
}
SetPerfLevel(PerfLevel::kEnableCount);
get_perf_context()->Reset();
ReadOptions ro;
std::unique_ptr<Iterator> iter(db_->NewIterator(ro));
// Seek to the first key, this will scan through all the tombstones and
// hidden puts
iter->Seek(Key(0));
ASSERT_FALSE(
iter->Valid()); // All keys are deleted, so iterator is not valid
ASSERT_OK(iter->status());
ASSERT_EQ(get_perf_context()->next_on_memtable_count, kTrigger);
// Skipping kNumTrigger memtable entries in a single iterator operation
// should mark the memtable for flush.
//
// At the end of a write, we check and update memtable to request a flush
ASSERT_OK(Put(Key(11), "val"));
// Before a write, we schedule memtables for flush if requested.
ASSERT_OK(Put(Key(12), "val"));
ASSERT_OK(db_->WaitForCompact({}));
if (trigger <= kTrigger) {
// Check if memtable was flushed due to scan trigger
ASSERT_EQ(1, NumTableFilesAtLevel(0));
uint64_t val = 0;
ASSERT_TRUE(
db_->GetIntProperty("rocksdb.num-deletes-active-mem-table", &val));
ASSERT_EQ(0, val);
} else {
uint64_t val = 0;
ASSERT_TRUE(
db_->GetIntProperty("rocksdb.num-deletes-active-mem-table", &val));
ASSERT_EQ(kNumKeys, val);
}
}
}
}
TEST_P(DBIteratorTest, MemtableOpsScanFlushTriggerWithNext) {
// Tests that option memtable_op_scan_flush_trigger works when the limit
// is reached during a Next() operation, and not trigger a flush when
// the limit is reached across multiple Next() operations.
const int kTrigger = 10;
Random* r = Random::GetTLSInstance();
for (int trigger : {kTrigger, kTrigger + 1}) {
for (bool delete_only : {false, true}) {
Options options;
options.create_if_missing = true;
options.memtable_op_scan_flush_trigger = trigger;
options.level_compaction_dynamic_level_bytes = true;
DestroyAndReopen(options);
// Base data that will be covered by a consecutive sequence of tombstones.
int kNumKeys = delete_only ? kTrigger : kTrigger / 2;
for (int i = 0; i <= kNumKeys; ++i) {
ASSERT_OK(Put(Key(i), r->RandomString(100)));
}
ASSERT_OK(Flush());
ASSERT_OK(db_->CompactRange({}, nullptr, nullptr));
ASSERT_EQ(1, NumTableFilesAtLevel(6));
ASSERT_OK(Put(Key(0), "val"));
if (delete_only) {
for (int i = 1; i <= kNumKeys; ++i) {
ASSERT_OK(SingleDelete(Key(i)));
}
} else {
for (int i = 1; i <= kNumKeys; ++i) {
ASSERT_OK(Put(Key(i), r->RandomString(100)));
}
for (int i = 1; i <= kNumKeys; ++i) {
ASSERT_OK(Delete(Key(i)));
}
}
// Total number of tombstones and hidden puts scanned across multiple
// Next() operations below will be kTrigger, and it should not trigger a
// flush when the limit is kTrigger + 1.
ASSERT_OK(Put(Key(kNumKeys + 1), "v1"));
ASSERT_OK(Delete(Key(kNumKeys + 2)));
ASSERT_OK(Put(Key(kNumKeys + 3), "v3"));
SetPerfLevel(PerfLevel::kEnableCount);
get_perf_context()->Reset();
ReadOptions ro;
std::unique_ptr<Iterator> iter(db_->NewIterator(ro));
iter->Seek(Key(0));
ASSERT_TRUE(iter->Valid());
ASSERT_EQ(iter->value(), "val");
ASSERT_OK(iter->status());
ASSERT_EQ(get_perf_context()->next_on_memtable_count, 0);
iter->Next();
// kTrigger tombstones and invisible puts and 1 for the visible put
ASSERT_EQ(get_perf_context()->next_on_memtable_count, kTrigger + 1);
iter->Next();
ASSERT_EQ(get_perf_context()->next_on_memtable_count, kTrigger + 3);
// Skipping kNumTrigger memtable entries in a single iterator operation
// should mark the memtable for flush.
//
// At the end of a write, we check and update memtable to request a flush
ASSERT_OK(Put(Key(11), "val"));
// Before a write, we schedule memtables for flush if requested.
ASSERT_OK(Put(Key(12), "val"));
ASSERT_OK(db_->WaitForCompact({}));
if (trigger <= kTrigger) {
// Check if memtable was flushed due to scan trigger
ASSERT_EQ(1, NumTableFilesAtLevel(0));
uint64_t val = 0;
ASSERT_TRUE(
db_->GetIntProperty("rocksdb.num-deletes-active-mem-table", &val));
ASSERT_EQ(0, val);
} else {
uint64_t val = 0;
ASSERT_TRUE(
db_->GetIntProperty("rocksdb.num-deletes-active-mem-table", &val));
ASSERT_EQ(kNumKeys + 1, val);
}
}
}
}
} // namespace ROCKSDB_NAMESPACE
int main(int argc, char** argv) {
+8 -8
View File
@@ -312,12 +312,12 @@ TEST_P(DbKvChecksumTest, WriteToWALCorrupted) {
// Corrupted write batch leads to read-only mode, so we have to
// reopen for every attempt.
Reopen(options);
auto log_size_pre_write = dbfull()->TEST_wals_total_size();
auto log_size_pre_write = dbfull()->TEST_total_log_size();
SyncPoint::GetInstance()->EnableProcessing();
ASSERT_TRUE(ExecuteWrite(nullptr /* cf_handle */).IsCorruption());
// Confirm that nothing was written to WAL
ASSERT_EQ(log_size_pre_write, dbfull()->TEST_wals_total_size());
ASSERT_EQ(log_size_pre_write, dbfull()->TEST_total_log_size());
ASSERT_TRUE(dbfull()->TEST_GetBGError().IsCorruption());
SyncPoint::GetInstance()->DisableProcessing();
@@ -350,12 +350,12 @@ TEST_P(DbKvChecksumTest, WriteToWALWithColumnFamilyCorrupted) {
// Corrupted write batch leads to read-only mode, so we have to
// reopen for every attempt.
ReopenWithColumnFamilies({kDefaultColumnFamilyName, "pikachu"}, options);
auto log_size_pre_write = dbfull()->TEST_wals_total_size();
auto log_size_pre_write = dbfull()->TEST_total_log_size();
SyncPoint::GetInstance()->EnableProcessing();
ASSERT_TRUE(ExecuteWrite(nullptr /* cf_handle */).IsCorruption());
// Confirm that nothing was written to WAL
ASSERT_EQ(log_size_pre_write, dbfull()->TEST_wals_total_size());
ASSERT_EQ(log_size_pre_write, dbfull()->TEST_total_log_size());
ASSERT_TRUE(dbfull()->TEST_GetBGError().IsCorruption());
SyncPoint::GetInstance()->DisableProcessing();
@@ -487,7 +487,7 @@ TEST_P(DbKvChecksumTestMergedBatch, WriteToWALCorrupted) {
// Reopen DB since it failed WAL write which lead to read-only mode
Reopen(options);
SyncPoint::GetInstance()->EnableProcessing();
auto log_size_pre_write = dbfull()->TEST_wals_total_size();
auto log_size_pre_write = dbfull()->TEST_total_log_size();
leader_batch_and_status =
GetWriteBatch(GetCFHandleToUse(nullptr, op_type1_),
8 /* protection_bytes_per_key */, op_type1_);
@@ -499,7 +499,7 @@ TEST_P(DbKvChecksumTestMergedBatch, WriteToWALCorrupted) {
SyncPoint::GetInstance()->ClearCallBack("WriteThread::JoinBatchGroup:Wait");
ASSERT_EQ(1, leader_count);
// Nothing should have been written to WAL
ASSERT_EQ(log_size_pre_write, dbfull()->TEST_wals_total_size());
ASSERT_EQ(log_size_pre_write, dbfull()->TEST_total_log_size());
ASSERT_TRUE(dbfull()->TEST_GetBGError().IsCorruption());
corrupt_byte_offset++;
@@ -599,7 +599,7 @@ TEST_P(DbKvChecksumTestMergedBatch, WriteToWALWithColumnFamilyCorrupted) {
// Reopen DB since it failed WAL write which lead to read-only mode
ReopenWithColumnFamilies({kDefaultColumnFamilyName, "ramen"}, options);
SyncPoint::GetInstance()->EnableProcessing();
auto log_size_pre_write = dbfull()->TEST_wals_total_size();
auto log_size_pre_write = dbfull()->TEST_total_log_size();
leader_batch_and_status =
GetWriteBatch(GetCFHandleToUse(handles_[1], op_type1_),
8 /* protection_bytes_per_key */, op_type1_);
@@ -612,7 +612,7 @@ TEST_P(DbKvChecksumTestMergedBatch, WriteToWALWithColumnFamilyCorrupted) {
ASSERT_EQ(1, leader_count);
// Nothing should have been written to WAL
ASSERT_EQ(log_size_pre_write, dbfull()->TEST_wals_total_size());
ASSERT_EQ(log_size_pre_write, dbfull()->TEST_total_log_size());
ASSERT_TRUE(dbfull()->TEST_GetBGError().IsCorruption());
corrupt_byte_offset++;
+22 -17
View File
@@ -322,26 +322,31 @@ TEST_F(DBOptionsTest, SetWithCustomMemTableFactory) {
}
Options options;
options.create_if_missing = true;
options.env = env_;
options.disable_auto_compactions = false;
// Try with fail_if_options_file_error=false/true to update the options
for (bool on_error : {false, true}) {
options.fail_if_options_file_error = on_error;
options.env = env_;
options.disable_auto_compactions = false;
options.memtable_factory.reset(new DummySkipListFactory());
Reopen(options);
options.memtable_factory.reset(new DummySkipListFactory());
Reopen(options);
ColumnFamilyHandle* cfh = dbfull()->DefaultColumnFamily();
ASSERT_OK(dbfull()->SetOptions(cfh, {{"disable_auto_compactions", "true"}}));
ColumnFamilyDescriptor cfd;
ASSERT_OK(cfh->GetDescriptor(&cfd));
ASSERT_STREQ(cfd.options.memtable_factory->Name(),
DummySkipListFactory::kClassName());
ColumnFamilyHandle* test = nullptr;
ASSERT_OK(dbfull()->CreateColumnFamily(options, "test", &test));
ASSERT_OK(test->GetDescriptor(&cfd));
ASSERT_STREQ(cfd.options.memtable_factory->Name(),
DummySkipListFactory::kClassName());
ColumnFamilyHandle* cfh = dbfull()->DefaultColumnFamily();
ASSERT_OK(
dbfull()->SetOptions(cfh, {{"disable_auto_compactions", "true"}}));
ColumnFamilyDescriptor cfd;
ASSERT_OK(cfh->GetDescriptor(&cfd));
ASSERT_STREQ(cfd.options.memtable_factory->Name(),
DummySkipListFactory::kClassName());
ColumnFamilyHandle* test = nullptr;
ASSERT_OK(dbfull()->CreateColumnFamily(options, "test", &test));
ASSERT_OK(test->GetDescriptor(&cfd));
ASSERT_STREQ(cfd.options.memtable_factory->Name(),
DummySkipListFactory::kClassName());
ASSERT_OK(dbfull()->DropColumnFamily(test));
delete test;
ASSERT_OK(dbfull()->DropColumnFamily(test));
delete test;
}
}
TEST_F(DBOptionsTest, SetBytesPerSync) {
-75
View File
@@ -508,81 +508,6 @@ TEST_F(DBSecondaryTest, OpenAsSecondary) {
verify_db_func("new_foo_value", "new_bar_value");
}
TEST_F(DBSecondaryTest, OptionsOverrideTest) {
Options options;
options.env = env_;
options.preserve_internal_time_seconds = 300;
options.compaction_readahead_size = 200;
options.blob_compaction_readahead_size = 100;
Reopen(options);
for (int i = 0; i < 3; ++i) {
ASSERT_OK(Put("foo", "foo_value" + std::to_string(i)));
ASSERT_OK(Put("bar", "bar_value" + std::to_string(i)));
ASSERT_OK(Flush());
}
CompactionServiceInput input;
ColumnFamilyMetaData meta;
db_->GetColumnFamilyMetaData(&meta);
for (auto& file : meta.levels[0].files) {
ASSERT_EQ(0, meta.levels[0].level);
input.input_files.push_back(file.name);
}
ASSERT_EQ(input.input_files.size(), 3);
input.output_level = 1;
input.options_file_number = dbfull()->GetVersionSet()->options_file_number();
input.cf_name = kDefaultColumnFamilyName;
ASSERT_OK(db_->GetDbIdentity(input.db_id));
ASSERT_EQ(db_->GetOptions().compaction_readahead_size, 200);
ASSERT_EQ(db_->GetOptions().blob_compaction_readahead_size, 100);
Close();
std::string compaction_input_binary;
ASSERT_OK(input.Write(&compaction_input_binary));
std::string compaction_result_binary;
CompactionServiceOptionsOverride override_options;
override_options.env = env_;
override_options.table_factory.reset(
NewBlockBasedTableFactory(BlockBasedTableOptions()));
ASSERT_OK(
StringToMap("compaction_readahead_size=8388608;"
"blob_compaction_readahead_size=4194304;"
"some_invalid_option=ignore_me;"
"env=this_should_not_fail;"
"max_open_files=100;", // this should be always overriden as
// -1 in remote compaction
&override_options.options_map));
bool verified = false;
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"DBImplSecondary::OpenAndCompact::AfterOpenAsSecondary:0",
[&](void* arg) {
auto secondary_db = static_cast<DB*>(arg);
auto secondary_db_options = secondary_db->GetOptions();
// DBOption
ASSERT_EQ(secondary_db_options.compaction_readahead_size, 8388608);
ASSERT_EQ(secondary_db_options.max_open_files, -1);
// CFOption
ASSERT_EQ(secondary_db_options.blob_compaction_readahead_size, 4194304);
verified = true;
});
SyncPoint::GetInstance()->EnableProcessing();
ASSERT_OK(DB::OpenAndCompact(OpenAndCompactOptions(), dbname_,
secondary_path_, compaction_input_binary,
&compaction_result_binary, override_options));
SyncPoint::GetInstance()->DisableProcessing();
SyncPoint::GetInstance()->ClearAllCallBacks();
ASSERT_TRUE(verified);
}
namespace {
class TraceFileEnv : public EnvWrapper {
public:
+7 -7
View File
@@ -3351,6 +3351,11 @@ class ModelDB : public DB {
using DB::NumberLevels;
int NumberLevels(ColumnFamilyHandle* /*column_family*/) override { return 1; }
using DB::MaxMemCompactionLevel;
int MaxMemCompactionLevel(ColumnFamilyHandle* /*column_family*/) override {
return 1;
}
using DB::Level0StopWriteTrigger;
int Level0StopWriteTrigger(ColumnFamilyHandle* /*column_family*/) override {
return -1;
@@ -3407,7 +3412,7 @@ class ModelDB : public DB {
}
Status GetCurrentWalFile(
std::unique_ptr<LogFile>* /*current_wal_file*/) override {
std::unique_ptr<LogFile>* /*current_log_file*/) override {
return Status::OK();
}
@@ -3446,11 +3451,6 @@ class ModelDB : public DB {
return Status::OK();
}
Status GetNewestUserDefinedTimestamp(
ColumnFamilyHandle* /*cf*/, std::string* /*newest_timestamp*/) override {
return Status::OK();
}
ColumnFamilyHandle* DefaultColumnFamily() const override { return nullptr; }
private:
@@ -6419,7 +6419,7 @@ TEST_F(DBTest, TestLogCleanup) {
for (int i = 0; i < 100000; ++i) {
ASSERT_OK(Put(Key(i), "val"));
// only 2 memtables will be alive, so wals_to_free needs to always be below
// only 2 memtables will be alive, so logs_to_free needs to always be below
// 2
ASSERT_LT(dbfull()->TEST_LogsToFreeSize(), static_cast<size_t>(3));
}
+1
View File
@@ -592,6 +592,7 @@ Options DBTestBase::GetOptions(
options_override.level_compaction_dynamic_level_bytes;
options.env = env_;
options.create_if_missing = true;
options.fail_if_options_file_error = true;
return options;
}
+2 -2
View File
@@ -3024,13 +3024,13 @@ TEST_F(DBWALTest, GetCompressedWalsAfterSync) {
options.wal_compression = kZSTD;
DestroyAndReopen(options);
// Write something to memtable and WAL so that wal_empty_ will be false after
// Write something to memtable and WAL so that log_empty_ will be false after
// next DB::Open().
ASSERT_OK(Put("a", "v"));
Reopen(options);
// New WAL is created, thanks to !wal_empty_.
// New WAL is created, thanks to !log_empty_.
ASSERT_OK(dbfull()->TEST_SwitchWAL());
ASSERT_OK(Put("b", "v"));
+41 -222
View File
@@ -19,13 +19,6 @@
#include "utilities/merge_operators/string_append/stringappend2.h"
namespace ROCKSDB_NAMESPACE {
namespace {
std::string EncodeAsUint64(uint64_t v) {
std::string dst;
PutFixed64(&dst, v);
return dst;
}
} // namespace
class DBBasicTestWithTimestamp : public DBBasicTestWithTimestampBase {
public:
DBBasicTestWithTimestamp()
@@ -1487,24 +1480,13 @@ TEST_F(DBBasicTestWithTimestamp, ReseekToUserKeyBeforeSavedKey) {
Close();
}
class ReverseIterationWithUnpreparedBlobTest
: public DBBasicTestWithTimestampBase,
public testing::WithParamInterface<std::tuple<bool, uint64_t>> {
public:
ReverseIterationWithUnpreparedBlobTest()
: DBBasicTestWithTimestampBase(
"db_basic_test_with_timestamp_reverse_with_unprepare") {}
};
INSTANTIATE_TEST_CASE_P(ReverseIterationWithUnpreparedBlobTest,
ReverseIterationWithUnpreparedBlobTest,
::testing::Combine(::testing::Values(true, false),
::testing::Values(0, 2)));
TEST_P(ReverseIterationWithUnpreparedBlobTest, Basic) {
TEST_F(DBBasicTestWithTimestamp,
FIXME_ReverseIterationWithBlobAndUnpreparedValue) {
Options options = CurrentOptions();
options.create_if_missing = true;
options.env = env_;
options.enable_blob_files = true;
options.max_sequential_skip_in_iterations = std::get<1>(GetParam());
options.max_sequential_skip_in_iterations = 0;
const size_t kTimestampSize = Timestamp(0, 0).size();
TestComparator test_cmp(kTimestampSize);
@@ -1519,7 +1501,7 @@ TEST_P(ReverseIterationWithUnpreparedBlobTest, Basic) {
for (uint64_t key = 0; key <= kMaxKey; ++key) {
for (size_t i = 0; i < write_timestamps.size(); ++i) {
ASSERT_OK(db_->Put(WriteOptions(), Key1(key), write_timestamps[i],
Key1(key) + "value" + std::to_string(i)));
"value" + std::to_string(i)));
}
}
@@ -1531,28 +1513,17 @@ TEST_P(ReverseIterationWithUnpreparedBlobTest, Basic) {
ReadOptions read_opts;
read_opts.timestamp = &read_timestamp;
read_opts.allow_unprepared_value = std::get<0>(GetParam());
read_opts.allow_unprepared_value = true;
std::unique_ptr<Iterator> it(db_->NewIterator(read_opts));
it->SeekForPrev(Key1(kMaxKey));
uint64_t key = kMaxKey;
int count = 0;
while (it->Valid()) {
ASSERT_OK(it->status());
ASSERT_TRUE(it->PrepareValue());
ASSERT_TRUE(it->Valid());
ASSERT_OK(it->status());
ASSERT_EQ(it->key(), Key1(key));
ASSERT_EQ(it->timestamp(), Timestamp(3, 0));
ASSERT_EQ(it->value(), Key1(key) + "value" + std::to_string(1));
key--;
count++;
it->Prev();
}
ASSERT_TRUE(it->Valid());
ASSERT_OK(it->status());
ASSERT_EQ(kMaxKey + 1, count);
// FIXME: PrepareValue() should succeed and status() should remain OK
ASSERT_FALSE(it->PrepareValue());
ASSERT_TRUE(it->status().IsCorruption());
}
Close();
@@ -3775,42 +3746,17 @@ INSTANTIATE_TEST_CASE_P(
test::UserDefinedTimestampTestMode::kStripUserDefinedTimestamp,
test::UserDefinedTimestampTestMode::kNormal));
// Test params:
// 1) whether to flush before close
class EnableDisableUDTTest : public DBBasicTestWithTimestampBase,
public testing::WithParamInterface<bool> {
public:
EnableDisableUDTTest()
: DBBasicTestWithTimestampBase("/enable_disable_udt") {}
};
INSTANTIATE_TEST_CASE_P(EnableDisableUDTTest, EnableDisableUDTTest,
::testing::Values(true, false));
TEST_P(EnableDisableUDTTest, Basic) {
TEST_F(DBBasicTestWithTimestamp, EnableDisableUDT) {
Options options = CurrentOptions();
// Un-flushed data before close will involve a WAL replay on DB reopen.
bool flush_before_close = GetParam();
options.env = env_;
// Create a column family without user-defined timestamps.
options.comparator = BytewiseComparator();
options.persist_user_defined_timestamps = true;
DestroyAndReopen(options);
ReadOptions ropts;
std::string read_ts;
std::string value;
std::string key_ts;
// Create one SST file, its user keys have no user-defined timestamps.
ASSERT_OK(db_->Put(WriteOptions(), "foo", "val0"));
ASSERT_OK(db_->Put(WriteOptions(), "bar", "val0"));
ASSERT_OK(db_->DeleteRange(WriteOptions(), "bar", "baz"));
ASSERT_OK(db_->Get(ReadOptions(), "foo", &value));
ASSERT_EQ("val0", value);
ASSERT_TRUE(db_->Get(ReadOptions(), "bar", &value).IsNotFound());
if (flush_before_close) {
ASSERT_OK(Flush(0));
}
ASSERT_OK(db_->Put(WriteOptions(), "foo", "val1"));
ASSERT_OK(Flush(0));
Close();
// Reopen the existing column family and enable user-defined timestamps
@@ -3819,63 +3765,47 @@ TEST_P(EnableDisableUDTTest, Basic) {
options.persist_user_defined_timestamps = false;
options.allow_concurrent_memtable_write = false;
Reopen(options);
// Read data from previous session before and after compaction.
read_ts = EncodeAsUint64(1);
std::string value;
ASSERT_TRUE(db_->Get(ReadOptions(), "foo", &value).IsInvalidArgument());
std::string read_ts;
PutFixed64(&read_ts, 0);
ReadOptions ropts;
Slice read_ts_slice = read_ts;
ropts.timestamp = &read_ts_slice;
for (int i = 0; i < 2; i++) {
ASSERT_TRUE(db_->Get(ReadOptions(), "foo", &value).IsInvalidArgument());
// Entries in pre-existing SST files are treated as if they have minimum
// user-defined timestamps.
ASSERT_OK(db_->Get(ropts, "foo", &value, &key_ts));
ASSERT_EQ("val0", value);
ASSERT_EQ(EncodeAsUint64(0), key_ts);
ASSERT_TRUE(db_->Get(ropts, "bar", &value, &key_ts).IsNotFound());
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
}
// Do timestamped read / write.
ASSERT_OK(db_->Put(WriteOptions(), "foo", EncodeAsUint64(1), "val1"));
ASSERT_OK(db_->Put(WriteOptions(), "bar", EncodeAsUint64(1), "val1"));
ASSERT_OK(db_->DeleteRange(WriteOptions(), "bar", "baz", EncodeAsUint64(2)));
std::string key_ts;
// Entries in pre-existing SST files are treated as if they have minimum
// user-defined timestamps.
ASSERT_OK(db_->Get(ropts, "foo", &value, &key_ts));
ASSERT_EQ("val1", value);
ASSERT_EQ(EncodeAsUint64(1), key_ts);
ASSERT_OK(db_->Get(ropts, "bar", &value, &key_ts));
ASSERT_EQ("val1", value);
ASSERT_EQ(EncodeAsUint64(1), key_ts);
read_ts = EncodeAsUint64(2);
ASSERT_TRUE(db_->Get(ropts, "bar", &value, &key_ts).IsNotFound());
ASSERT_EQ(read_ts, key_ts);
// Do timestamped read / write.
std::string write_ts;
PutFixed64(&write_ts, 1);
ASSERT_OK(db_->Put(WriteOptions(), "foo", write_ts, "val2"));
read_ts.clear();
PutFixed64(&read_ts, 1);
ASSERT_OK(db_->Get(ropts, "foo", &value, &key_ts));
ASSERT_EQ("val2", value);
ASSERT_EQ(write_ts, key_ts);
// The user keys in this SST file don't have user-defined timestamps either,
// because `persist_user_defined_timestamps` flag is set to false.
if (flush_before_close) {
ASSERT_OK(Flush(0));
}
ASSERT_OK(Flush(0));
Close();
// Reopen the existing column family while disabling user-defined timestamps.
options.comparator = BytewiseComparator();
Reopen(options);
// Read data from previous session before and after compaction.
for (int i = 0; i < 2; i++) {
ASSERT_TRUE(db_->Get(ropts, "foo", &value).IsInvalidArgument());
ASSERT_OK(db_->Get(ReadOptions(), "foo", &value));
ASSERT_EQ("val1", value);
ASSERT_TRUE(db_->Get(ReadOptions(), "bar", &value).IsNotFound());
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
}
// Continue to write / read the column family without user-defined timestamps.
ASSERT_OK(db_->Put(WriteOptions(), "foo", "val2"));
ASSERT_OK(db_->Put(WriteOptions(), "bar", "val2"));
ASSERT_OK(db_->DeleteRange(WriteOptions(), "bar", "baz"));
ASSERT_TRUE(db_->Get(ropts, "foo", &value).IsInvalidArgument());
ASSERT_OK(db_->Get(ReadOptions(), "foo", &value));
ASSERT_EQ("val2", value);
ASSERT_TRUE(db_->Get(ReadOptions(), "bar", &value).IsNotFound());
if (flush_before_close) {
ASSERT_OK(Flush(0));
}
// Continue to write / read the column family without user-defined timestamps.
ASSERT_OK(db_->Put(WriteOptions(), "foo", "val3"));
ASSERT_OK(db_->Get(ReadOptions(), "foo", &value));
ASSERT_EQ("val3", value);
Close();
}
@@ -4914,117 +4844,6 @@ TEST_F(DBBasicTestWithTimestamp, TimestampFilterTableReadOnGet) {
Close();
}
class GetNewestUserDefinedTimestampTest : public DBBasicTestWithTimestampBase {
public:
explicit GetNewestUserDefinedTimestampTest()
: DBBasicTestWithTimestampBase("get_newest_udt_test") {}
};
TEST_F(GetNewestUserDefinedTimestampTest, Basic) {
std::string newest_timestamp;
// UDT disabled, get InvalidArgument.
ASSERT_TRUE(db_->GetNewestUserDefinedTimestamp(nullptr, &newest_timestamp)
.IsInvalidArgument());
Options options = CurrentOptions();
options.env = env_;
options.create_if_missing = true;
options.max_write_buffer_number = 5;
options.min_write_buffer_number_to_merge = 4;
options.comparator = test::BytewiseComparatorWithU64TsWrapper();
DestroyAndReopen(options);
// UDT persisted, get NotSupported.
ASSERT_TRUE(db_->GetNewestUserDefinedTimestamp(nullptr, &newest_timestamp)
.IsNotSupported());
options.persist_user_defined_timestamps = false;
options.allow_concurrent_memtable_write = false;
DestroyAndReopen(options);
ASSERT_TRUE(
db_->GetNewestUserDefinedTimestamp(nullptr, nullptr).IsInvalidArgument());
ColumnFamilyHandleImpl* cfh = static_cast_with_check<ColumnFamilyHandleImpl>(
db_->DefaultColumnFamily());
ColumnFamilyData* cfd = cfh->cfd();
// The column family hasn't seen any user defined timestamp
ASSERT_OK(db_->GetNewestUserDefinedTimestamp(nullptr, &newest_timestamp));
ASSERT_TRUE(newest_timestamp.empty());
ASSERT_OK(db_->Put(WriteOptions(), Key(1), EncodeAsUint64(1), "val1"));
// Testing get newest timestamp from mutable memtable.
ASSERT_OK(db_->GetNewestUserDefinedTimestamp(nullptr, &newest_timestamp));
ASSERT_EQ(EncodeAsUint64(1), newest_timestamp);
ASSERT_OK(db_->Put(WriteOptions(), Key(1), EncodeAsUint64(2), "val2"));
ASSERT_OK(dbfull()->TEST_SwitchMemtable(cfd));
// Testing get the newest timestamp from immutable memtable because the
// mutable one is empty.
ASSERT_OK(db_->GetNewestUserDefinedTimestamp(nullptr, &newest_timestamp));
ASSERT_EQ(EncodeAsUint64(2), newest_timestamp);
ASSERT_OK(db_->Put(WriteOptions(), Key(1), EncodeAsUint64(3), "val3"));
ASSERT_OK(db_->Put(WriteOptions(), Key(1), EncodeAsUint64(4), "val4"));
ASSERT_OK(dbfull()->TEST_SwitchMemtable(cfd));
// Testing get the newest timestamp from the more recent immutable memtable
// when there are multiple immutable memtables.
ASSERT_OK(db_->GetNewestUserDefinedTimestamp(nullptr, &newest_timestamp));
ASSERT_EQ(EncodeAsUint64(4), newest_timestamp);
ASSERT_OK(db_->Put(WriteOptions(), Key(1), EncodeAsUint64(5), "val5"));
// Testing get newest timestamp from mutable memtable when it has data, in the
// presence of immutable memtables.
ASSERT_OK(db_->GetNewestUserDefinedTimestamp(nullptr, &newest_timestamp));
ASSERT_EQ(EncodeAsUint64(5), newest_timestamp);
ASSERT_OK(Flush());
// After flushing and all the user defined timestamp are flushed. User defined
// timestamp info for SST files is available from MANIFEST.
ASSERT_OK(db_->GetNewestUserDefinedTimestamp(nullptr, &newest_timestamp));
ASSERT_EQ(EncodeAsUint64(5), newest_timestamp);
Reopen(options);
// Similar after flush, when there is no memtables, but some SST files,
// if MANIFEST records the upperbound of flushed timestamps because timestamps
// are not persisted in SST files, this info can be found.
ASSERT_OK(db_->GetNewestUserDefinedTimestamp(nullptr, &newest_timestamp));
ASSERT_EQ(EncodeAsUint64(5), newest_timestamp);
Close();
}
TEST_F(GetNewestUserDefinedTimestampTest, ConcurrentWrites) {
Options options = CurrentOptions();
options.create_if_missing = true;
options.comparator = test::BytewiseComparatorWithU64TsWrapper();
options.persist_user_defined_timestamps = false;
options.allow_concurrent_memtable_write = false;
DestroyAndReopen(options);
std::vector<std::thread> threads;
threads.reserve(10);
std::atomic<uint64_t> current_ts{0};
for (int i = 0; i < 10; i++) {
threads.emplace_back([this, i, &current_ts]() {
if (i % 2 == 0) {
std::string newest_timestamp;
ASSERT_OK(
db_->GetNewestUserDefinedTimestamp(nullptr, &newest_timestamp));
} else {
uint64_t write_ts = current_ts.fetch_add(1);
ASSERT_OK(db_->Put(WriteOptions(), Key(1), EncodeAsUint64(write_ts),
"val" + std::to_string(i)));
}
});
}
for (auto& t : threads) {
t.join();
}
Close();
}
} // namespace ROCKSDB_NAMESPACE
int main(int argc, char** argv) {
+1 -75
View File
@@ -987,7 +987,7 @@ TEST_P(DBWriteTest, RecycleLogToggleTest) {
options.recycle_log_file_num = 1;
Reopen(options);
// 1.log is added to alive_wal_files_
// 1.log is added to alive_log_files_
ASSERT_OK(Put(Key(2), "val1"));
ASSERT_OK(Flush());
// 1.log should be deleted and not recycled, since it
@@ -1000,80 +1000,6 @@ TEST_P(DBWriteTest, RecycleLogToggleTest) {
ASSERT_EQ(Get(Key(1)), "val2");
}
TEST_P(DBWriteTest, IngestWriteBatchWithIndex) {
if (GetParam() == kPipelinedWrite) {
return;
}
Options options = GetOptions();
options.disable_auto_compactions = true;
Reopen(options);
Options cf_options = GetOptions();
cf_options.merge_operator = MergeOperators::CreateStringAppendOperator();
CreateColumnFamilies({"cf1", "cf2"}, cf_options);
ReopenWithColumnFamilies({"default", "cf1", "cf2"},
{options, cf_options, cf_options});
// default cf
auto wbwi1 = std::make_shared<WriteBatchWithIndex>(options.comparator, 0,
/*overwrite_key=*/true);
ASSERT_OK(wbwi1->Put("key1", "value1"));
ASSERT_OK(wbwi1->Put("key2", "value2"));
if (GetParam() == kPipelinedWrite) {
ASSERT_TRUE(db_->IngestWriteBatchWithIndex({}, wbwi1).IsNotSupported());
return;
}
// Test disableWAL=false
ASSERT_TRUE(db_->IngestWriteBatchWithIndex({}, wbwi1).IsNotSupported());
WriteOptions wo;
wo.disableWAL = true;
ASSERT_OK(db_->IngestWriteBatchWithIndex(wo, wbwi1));
ASSERT_EQ("value1", Get("key1"));
ASSERT_EQ("value2", Get("key2"));
// Test with overwrites
auto wbwi = std::make_shared<WriteBatchWithIndex>(options.comparator, 0,
/*overwrite_key=*/true);
ASSERT_OK(wbwi->Put("key2", "value3"));
ASSERT_OK(wbwi->Delete("key1")); // Delete an existing key
ASSERT_OK(db_->IngestWriteBatchWithIndex(wo, wbwi));
ASSERT_EQ("NOT_FOUND", Get("key1"));
ASSERT_EQ("value3", Get("key2"));
auto wbwi2 = std::make_shared<WriteBatchWithIndex>(options.comparator, 0,
/*overwrite_key=*/true);
ASSERT_OK(wbwi2->Put(handles_[1], "cf1_key1", "cf1_value1"));
ASSERT_OK(wbwi2->Delete(handles_[1], "cf1_key2"));
// Test ingestion with column family
ASSERT_OK(db_->IngestWriteBatchWithIndex(wo, wbwi2));
ASSERT_EQ("cf1_value1", Get(1, "cf1_key1"));
ASSERT_EQ("NOT_FOUND", Get(1, "cf1_key2"));
auto wbwi3 = std::make_shared<WriteBatchWithIndex>(options.comparator, 0,
/*overwrite_key=*/true);
ASSERT_OK(wbwi3->Merge(handles_[2], "cf2_key1", "cf2_value1"));
ASSERT_OK(wbwi3->Merge(handles_[2], "cf2_key1", "cf2_value2"));
// Test ingestion with merge operations
ASSERT_OK(db_->IngestWriteBatchWithIndex(wo, wbwi3));
ASSERT_EQ("cf2_value1,cf2_value2", Get(2, "cf2_key1"));
// Test with overwrite_key = false
auto wbwi_no_overwrite = std::make_shared<WriteBatchWithIndex>(
options.comparator, 0, /*overwrite_key=*/false);
ASSERT_OK(wbwi_no_overwrite->Put("key1", "value1"));
Status s = db_->IngestWriteBatchWithIndex(wo, wbwi_no_overwrite);
ASSERT_TRUE(s.IsNotSupported());
auto empty_wbwi = std::make_shared<WriteBatchWithIndex>(
options.comparator, 0, /*overwrite_key=*/true);
ASSERT_OK(db_->IngestWriteBatchWithIndex(wo, empty_wbwi));
DestroyAndReopen(options);
// Should fail when trying to ingest to non-existent column family
ASSERT_NOK(db_->IngestWriteBatchWithIndex(wo, wbwi2));
}
INSTANTIATE_TEST_CASE_P(DBWriteTestInstance, DBWriteTest,
testing::Values(DBTestBase::kDefault,
DBTestBase::kConcurrentWALWrites,
+4 -10
View File
@@ -275,6 +275,9 @@ void ErrorHandler::HandleKnownErrors(const Status& bg_err,
return;
}
ROCKS_LOG_INFO(db_options_.info_log,
"ErrorHandler: Set regular background error\n");
bool paranoid = db_options_.paranoid_checks;
Status::Severity sev = Status::Severity::kFatalError;
Status new_bg_err;
@@ -332,21 +335,12 @@ void ErrorHandler::HandleKnownErrors(const Status& bg_err,
if (!s.ok() && (s.severity() > bg_error_.severity())) {
bg_error_ = s;
} else {
ROCKS_LOG_INFO(db_options_.info_log,
"ErrorHandler: Hit less severe background error\n");
// This error is less severe than previously encountered error. Don't
// take any further action
return;
}
}
bool stop = bg_error_.severity() >= Status::Severity::kHardError;
ROCKS_LOG_INFO(
db_options_.info_log,
"ErrorHandler: Set regular background error, auto_recovery=%d, stop=%d\n",
int{auto_recovery}, int{stop});
recover_context_ = context;
if (auto_recovery) {
recovery_in_prog_ = true;
@@ -357,7 +351,7 @@ void ErrorHandler::HandleKnownErrors(const Status& bg_err,
RecoverFromNoSpace();
}
}
if (stop) {
if (bg_error_.severity() >= Status::Severity::kHardError) {
is_db_stopped_.store(true, std::memory_order_release);
}
}
-75
View File
@@ -2693,81 +2693,6 @@ TEST_F(ExternalSSTFileBasicTest, IngestWithTemperature) {
}
}
// This tests an internal user's exact usage and expectation of the
// IngestExternalFiles APIs to bulk load and replace files.
TEST_F(ExternalSSTFileBasicTest,
AtomicReplaceColumnFamilyWithIngestedVersionKey) {
Options options = GetDefaultOptions();
options.create_if_missing = true;
options.compaction_style = CompactionStyle::kCompactionStyleUniversal;
options.num_levels = 7;
options.disallow_memtable_writes = false;
DestroyAndReopen(options);
SstFileWriter sst_file_writer(EnvOptions(), options);
std::string data_file_original = sst_files_dir_ + "data_original";
ASSERT_OK(sst_file_writer.Open(data_file_original));
ASSERT_OK(sst_file_writer.Put("ukey1", "uval1_orig"));
ASSERT_OK(sst_file_writer.Put("ukey2", "uval2_orig"));
ASSERT_OK(sst_file_writer.Finish());
ASSERT_OK(db_->IngestExternalFile(db_->DefaultColumnFamily(),
{data_file_original},
IngestExternalFileOptions()));
ASSERT_OK(Put("data_version", "v_original"));
ASSERT_OK(Flush());
std::string value;
ASSERT_OK(db_->Get(ReadOptions(), "data_version", &value));
ASSERT_EQ(value, "v_original");
ASSERT_OK(db_->Get(ReadOptions(), "ukey1", &value));
ASSERT_EQ(value, "uval1_orig");
ASSERT_OK(db_->Get(ReadOptions(), "ukey2", &value));
ASSERT_EQ(value, "uval2_orig");
// Set up a 1) data version key file on L0, and 2) a user data file on L6
// to test the initial transitioning to use `atomic_replace_range`.
ASSERT_EQ("1,0,0,0,0,0,1", FilesPerLevel());
// Test multiple cycles of replacing by atomically ingest a data file and a
// version key file while replace the whole range in the column family.
for (int i = 0; i < 10; i++) {
std::string version_file_path =
sst_files_dir_ + "version" + std::to_string(i);
ASSERT_OK(sst_file_writer.Open(version_file_path));
ASSERT_OK(sst_file_writer.Put("data_version", "v" + std::to_string(i)));
ASSERT_OK(sst_file_writer.Finish());
std::string file_path = sst_files_dir_ + std::to_string(i);
ASSERT_OK(sst_file_writer.Open(file_path));
ASSERT_OK(sst_file_writer.Put("ukey1", "uval1" + std::to_string(i)));
ASSERT_OK(sst_file_writer.Put("ukey2", "uval2" + std::to_string(i)));
ASSERT_OK(sst_file_writer.Finish());
IngestExternalFileArg arg;
arg.column_family = db_->DefaultColumnFamily();
arg.external_files = {version_file_path, file_path};
arg.atomic_replace_range = {{nullptr, nullptr}};
// Test both fail_if_not_bottomost_level: true and false
arg.options.fail_if_not_bottommost_level = i % 2 == 0;
arg.options.snapshot_consistency = false;
// Ingest 1) a new data version file and 2) a new user data file while erase
// the whole column family
Status s = db_->IngestExternalFiles({arg});
ASSERT_OK(s);
// Check ingestion result and the expected LSM shape:
// Two files on L6, 1) a data version file 2) a user data file.
ASSERT_OK(db_->Get(ReadOptions(), "ukey1", &value));
ASSERT_EQ(value, "uval1" + std::to_string(i));
ASSERT_OK(db_->Get(ReadOptions(), "ukey2", &value));
ASSERT_EQ(value, "uval2" + std::to_string(i));
ASSERT_OK(db_->Get(ReadOptions(), "data_version", &value));
ASSERT_EQ(value, "v" + std::to_string(i));
ASSERT_EQ("0,0,0,0,0,0,2", FilesPerLevel());
}
Close();
}
TEST_F(ExternalSSTFileBasicTest, FailIfNotBottommostLevelAndDisallowMemtable) {
for (bool disallow_memtable : {false, true}) {
Options options = GetDefaultOptions();
+10 -2
View File
@@ -610,8 +610,16 @@ Status ExternalSstFileIngestionJob::AssignLevelsForOneBatch(
current_time = oldest_ancester_time =
static_cast<uint64_t>(temp_current_time);
}
uint64_t tail_size = FileMetaData::CalculateTailSize(
file->fd.GetFileSize(), file->table_properties);
uint64_t tail_size = 0;
bool contain_no_data_blocks = file->table_properties.num_entries > 0 &&
(file->table_properties.num_entries ==
file->table_properties.num_range_deletions);
if (file->table_properties.tail_start_offset > 0 ||
contain_no_data_blocks) {
uint64_t file_size = file->fd.GetFileSize();
assert(file->table_properties.tail_start_offset <= file_size);
tail_size = file_size - file->table_properties.tail_start_offset;
}
bool marked_for_compaction =
file->table_properties.num_range_deletions == 1 &&
+2 -2
View File
@@ -901,9 +901,9 @@ Status FlushJob::WriteLevel0Table() {
for (ReadOnlyMemTable* m : mems_) {
ROCKS_LOG_INFO(db_options_.info_log,
"[%s] [JOB %d] Flushing memtable id %" PRIu64
" with next log file: %" PRIu64 ", marked_for_flush: %d\n",
" with next log file: %" PRIu64 "\n",
cfd_->GetName().c_str(), job_context_->job_id, m->GetID(),
m->GetNextLogNumber(), m->IsMarkedForFlush());
m->GetNextLogNumber());
if (logical_strip_timestamp) {
memtables.push_back(m->NewTimestampStrippingIterator(
ro, /*seqno_to_time_mapping=*/nullptr, &arena,
+9 -2
View File
@@ -201,8 +201,15 @@ Status ImportColumnFamilyJob::Run() {
const auto& f = files_to_import_[i][j];
const auto& file_metadata = *metadatas_[i][j];
uint64_t tail_size = FileMetaData::CalculateTailSize(f.fd.GetFileSize(),
f.table_properties);
uint64_t tail_size = 0;
bool contain_no_data_blocks = f.table_properties.num_entries > 0 &&
(f.table_properties.num_entries ==
f.table_properties.num_range_deletions);
if (f.table_properties.tail_start_offset > 0 || contain_no_data_blocks) {
uint64_t file_size = f.fd.GetFileSize();
assert(f.table_properties.tail_start_offset <= file_size);
tail_size = file_size - f.table_properties.tail_start_offset;
}
VersionEdit dummy_version_edit;
dummy_version_edit.AddFile(
+7 -7
View File
@@ -123,7 +123,7 @@ struct JobContext {
break;
}
}
return memtables_to_free.size() > 0 || wals_to_free.size() > 0 ||
return memtables_to_free.size() > 0 || logs_to_free.size() > 0 ||
job_snapshot != nullptr || sv_have_sth;
}
@@ -193,7 +193,7 @@ struct JobContext {
// contexts for installing superversions for multiple column families
std::vector<SuperVersionContext> superversion_contexts;
autovector<log::Writer*> wals_to_free;
autovector<log::Writer*> logs_to_free;
// the current manifest_file_number, log_number and prev_log_number
// that corresponds to the set of files in 'live'.
@@ -207,8 +207,8 @@ struct JobContext {
uint64_t prev_log_number;
uint64_t min_pending_output = 0;
uint64_t prev_wals_total_size = 0;
size_t num_alive_wal_files = 0;
uint64_t prev_total_log_size = 0;
size_t num_alive_log_files = 0;
uint64_t size_log_to_delete = 0;
// Snapshot taken before flush/compaction job.
@@ -237,18 +237,18 @@ struct JobContext {
for (auto m : memtables_to_free) {
delete m;
}
for (auto l : wals_to_free) {
for (auto l : logs_to_free) {
delete l;
}
memtables_to_free.clear();
wals_to_free.clear();
logs_to_free.clear();
job_snapshot.reset();
}
~JobContext() {
assert(memtables_to_free.size() == 0);
assert(wals_to_free.size() == 0);
assert(logs_to_free.size() == 0);
}
};
+5 -7
View File
@@ -147,6 +147,7 @@ MemTable::MemTable(const InternalKeyComparator& cmp,
const Comparator* ucmp = cmp.user_comparator();
assert(ucmp);
ts_sz_ = ucmp->timestamp_size();
persist_user_defined_timestamps_ = ioptions.persist_user_defined_timestamps;
}
MemTable::~MemTable() {
@@ -174,11 +175,6 @@ size_t MemTable::ApproximateMemoryUsage() {
}
bool MemTable::ShouldFlushNow() {
if (IsMarkedForFlush()) {
// TODO: dedicated flush reason when marked for flush
return true;
}
// This is set if memtable_max_range_deletions is > 0,
// and that many range deletions are done
if (memtable_max_range_deletions_ > 0 &&
@@ -1805,7 +1801,7 @@ uint64_t MemTable::GetMinLogContainingPrepSection() {
}
void MemTable::MaybeUpdateNewestUDT(const Slice& user_key) {
if (ts_sz_ == 0) {
if (ts_sz_ == 0 || persist_user_defined_timestamps_) {
return;
}
const Comparator* ucmp = GetInternalKeyComparator().user_comparator();
@@ -1816,7 +1812,9 @@ void MemTable::MaybeUpdateNewestUDT(const Slice& user_key) {
}
const Slice& MemTable::GetNewestUDT() const {
assert(ts_sz_ > 0);
// This path should not be invoked for MemTables that does not enable the UDT
// in Memtable only feature.
assert(ts_sz_ > 0 && !persist_user_defined_timestamps_);
return newest_udt_;
}
+8 -13
View File
@@ -30,7 +30,6 @@
#include "rocksdb/db.h"
#include "rocksdb/memtablerep.h"
#include "table/multiget_context.h"
#include "util/atomic.h"
#include "util/cast_util.h"
#include "util/dynamic_bloom.h"
#include "util/hash.h"
@@ -355,13 +354,13 @@ class ReadOnlyMemTable {
// be flushed to storage
// REQUIRES: external synchronization to prevent simultaneous
// operations on the same MemTable.
uint64_t GetNextLogNumber() const { return mem_next_walfile_number_; }
uint64_t GetNextLogNumber() const { return mem_next_logfile_number_; }
// Sets the next active logfile number when this memtable is about to
// be flushed to storage
// REQUIRES: external synchronization to prevent simultaneous
// operations on the same MemTable.
void SetNextLogNumber(uint64_t num) { mem_next_walfile_number_ = num; }
void SetNextLogNumber(uint64_t num) { mem_next_logfile_number_ = num; }
// REQUIRES: db_mutex held.
void SetID(uint64_t id) { id_ = id; }
@@ -497,10 +496,6 @@ class ReadOnlyMemTable {
return false;
}
void MarkForFlush() { marked_for_flush_.StoreRelaxed(true); }
bool IsMarkedForFlush() const { return marked_for_flush_.LoadRelaxed(); }
protected:
friend class MemTableList;
@@ -516,7 +511,7 @@ class ReadOnlyMemTable {
VersionEdit edit_;
// The log files earlier than this number can be deleted.
uint64_t mem_next_walfile_number_{0};
uint64_t mem_next_logfile_number_{0};
// Memtable id to track flush.
uint64_t id_ = 0;
@@ -529,8 +524,6 @@ class ReadOnlyMemTable {
// Flush job info of the current memtable.
std::unique_ptr<FlushJobInfo> flush_job_info_;
RelaxedAtomic<bool> marked_for_flush_{false};
};
class MemTable final : public ReadOnlyMemTable {
@@ -825,8 +818,6 @@ class MemTable final : public ReadOnlyMemTable {
is_range_del_table_empty_;
}
// Gets the newest user defined timestamps in the memtable. This should only
// be called when user defined timestamp is enabled.
const Slice& GetNewestUDT() const override;
// Returns Corruption status if verification fails.
@@ -902,10 +893,14 @@ class MemTable final : public ReadOnlyMemTable {
// Size in bytes for the user-defined timestamps.
size_t ts_sz_;
// Whether to persist user-defined timestamps
bool persist_user_defined_timestamps_;
// Newest user-defined timestamp contained in this MemTable. For ts1, and ts2
// if Comparator::CompareTimestamp(ts1, ts2) > 0, ts1 is considered newer than
// ts2. We track this field for a MemTable if its column family has UDT
// feature enabled.
// feature enabled and the `persist_user_defined_timestamp` flag is false.
// Otherwise, this field just contains an empty Slice.
Slice newest_udt_;
// Updates flush_state_ using ShouldFlushNow()
+11 -16
View File
@@ -51,7 +51,9 @@ void MemTableListVersion::UnrefMemTable(
MemTableListVersion::MemTableListVersion(
size_t* parent_memtable_list_memory_usage, const MemTableListVersion& old)
: max_write_buffer_size_to_maintain_(
: max_write_buffer_number_to_maintain_(
old.max_write_buffer_number_to_maintain_),
max_write_buffer_size_to_maintain_(
old.max_write_buffer_size_to_maintain_),
parent_memtable_list_memory_usage_(parent_memtable_list_memory_usage) {
memlist_ = old.memlist_;
@@ -67,8 +69,10 @@ MemTableListVersion::MemTableListVersion(
MemTableListVersion::MemTableListVersion(
size_t* parent_memtable_list_memory_usage,
int max_write_buffer_number_to_maintain,
int64_t max_write_buffer_size_to_maintain)
: max_write_buffer_size_to_maintain_(max_write_buffer_size_to_maintain),
: max_write_buffer_number_to_maintain_(max_write_buffer_number_to_maintain),
max_write_buffer_size_to_maintain_(max_write_buffer_size_to_maintain),
parent_memtable_list_memory_usage_(parent_memtable_list_memory_usage) {}
void MemTableListVersion::Ref() { ++refs_; }
@@ -319,7 +323,8 @@ void MemTableListVersion::Remove(ReadOnlyMemTable* m,
memlist_.remove(m);
m->MarkFlushed();
if (max_write_buffer_size_to_maintain_ > 0) {
if (max_write_buffer_size_to_maintain_ > 0 ||
max_write_buffer_number_to_maintain_ > 0) {
memlist_history_.push_front(m);
// Unable to get size of mutable memtable at this point, pass 0 to
// TrimHistory as a best effort.
@@ -351,6 +356,9 @@ bool MemTableListVersion::MemtableLimitExceeded(size_t usage) {
// whether to trim history
return MemoryAllocatedBytesExcludingLast() + usage >=
static_cast<size_t>(max_write_buffer_size_to_maintain_);
} else if (max_write_buffer_number_to_maintain_ > 0) {
return memlist_.size() + memlist_history_.size() >
static_cast<size_t>(max_write_buffer_number_to_maintain_);
} else {
return false;
}
@@ -374,19 +382,6 @@ bool MemTableListVersion::TrimHistory(autovector<ReadOnlyMemTable*>* to_delete,
return ret;
}
const Slice& MemTableListVersion::GetNewestUDT() const {
static Slice kEmptySlice;
for (auto it = memlist_.begin(); it != memlist_.end(); ++it) {
ReadOnlyMemTable* m = *it;
Slice timestamp = m->GetNewestUDT();
assert(!timestamp.empty() || m->IsEmpty());
if (!timestamp.empty()) {
return m->GetNewestUDT();
}
}
return kEmptySlice;
}
// Returns true if there is at least one memtable on which flush has
// not yet started.
bool MemTableList::IsFlushPending() const {
+5 -6
View File
@@ -45,6 +45,7 @@ class MemTableListVersion {
explicit MemTableListVersion(size_t* parent_memtable_list_memory_usage,
const MemTableListVersion& old);
explicit MemTableListVersion(size_t* parent_memtable_list_memory_usage,
int max_write_buffer_number_to_maintain,
int64_t max_write_buffer_size_to_maintain);
void Ref();
@@ -149,12 +150,6 @@ class MemTableListVersion {
int NumFlushed() const { return static_cast<int>(memlist_history_.size()); }
// Gets the newest user defined timestamps from the immutable memtables.
// This returns the newest user defined timestamp found in the most recent
// immutable memtable. This should only be called when user defined timestamp
// is enabled.
const Slice& GetNewestUDT() const;
private:
friend class MemTableList;
@@ -214,6 +209,8 @@ class MemTableListVersion {
// (used during Transaction validation)
std::list<ReadOnlyMemTable*> memlist_history_;
// Maximum number of MemTables to keep in memory (including both flushed
const int max_write_buffer_number_to_maintain_;
// Maximum size of MemTables to keep in memory (including both flushed
// and not-yet-flushed tables).
const int64_t max_write_buffer_size_to_maintain_;
@@ -241,11 +238,13 @@ class MemTableList {
public:
// A list of memtables.
explicit MemTableList(int min_write_buffer_number_to_merge,
int max_write_buffer_number_to_maintain,
int64_t max_write_buffer_size_to_maintain)
: imm_flush_needed(false),
imm_trim_needed(false),
min_write_buffer_number_to_merge_(min_write_buffer_number_to_merge),
current_(new MemTableListVersion(&current_memory_usage_,
max_write_buffer_number_to_maintain,
max_write_buffer_size_to_maintain)),
num_flush_not_started_(0),
commit_in_progress_(false),
+11 -1
View File
@@ -220,7 +220,7 @@ class MemTableListTest : public testing::Test {
TEST_F(MemTableListTest, Empty) {
// Create an empty MemTableList and validate basic functions.
MemTableList list(1, 0);
MemTableList list(1, 0, 0);
ASSERT_EQ(0, list.NumNotFlushed());
ASSERT_FALSE(list.imm_flush_needed.load(std::memory_order_acquire));
@@ -239,8 +239,10 @@ TEST_F(MemTableListTest, Empty) {
TEST_F(MemTableListTest, GetTest) {
// Create MemTableList
int min_write_buffer_number_to_merge = 2;
int max_write_buffer_number_to_maintain = 0;
int64_t max_write_buffer_size_to_maintain = 0;
MemTableList list(min_write_buffer_number_to_merge,
max_write_buffer_number_to_maintain,
max_write_buffer_size_to_maintain);
SequenceNumber seq = 1;
@@ -405,8 +407,10 @@ TEST_F(MemTableListTest, GetTest) {
TEST_F(MemTableListTest, GetFromHistoryTest) {
// Create MemTableList
int min_write_buffer_number_to_merge = 2;
int max_write_buffer_number_to_maintain = 2;
int64_t max_write_buffer_size_to_maintain = 2 * Arena::kInlineSize;
MemTableList list(min_write_buffer_number_to_merge,
max_write_buffer_number_to_maintain,
max_write_buffer_size_to_maintain);
SequenceNumber seq = 1;
@@ -649,9 +653,11 @@ TEST_F(MemTableListTest, FlushPendingTest) {
// Create MemTableList
int min_write_buffer_number_to_merge = 3;
int max_write_buffer_number_to_maintain = 7;
int64_t max_write_buffer_size_to_maintain =
7 * static_cast<int>(options.write_buffer_size);
MemTableList list(min_write_buffer_number_to_merge,
max_write_buffer_number_to_maintain,
max_write_buffer_size_to_maintain);
// Create some MemTables
@@ -943,11 +949,13 @@ TEST_F(MemTableListTest, AtomicFlushTest) {
// Create MemTableLists
int min_write_buffer_number_to_merge = 3;
int max_write_buffer_number_to_maintain = 7;
int64_t max_write_buffer_size_to_maintain =
7 * static_cast<int64_t>(options.write_buffer_size);
autovector<MemTableList*> lists;
for (int i = 0; i != num_cfs; ++i) {
lists.emplace_back(new MemTableList(min_write_buffer_number_to_merge,
max_write_buffer_number_to_maintain,
max_write_buffer_size_to_maintain));
}
@@ -1096,9 +1104,11 @@ TEST_F(MemTableListWithTimestampTest, GetTableNewestUDT) {
// Create MemTableList
int min_write_buffer_number_to_merge = 1;
int max_write_buffer_number_to_maintain = 4;
int64_t max_write_buffer_size_to_maintain =
4 * static_cast<int>(options.write_buffer_size);
MemTableList list(min_write_buffer_number_to_merge,
max_write_buffer_number_to_maintain,
max_write_buffer_size_to_maintain);
// Create some MemTables
+13 -10
View File
@@ -1339,7 +1339,11 @@ TEST_P(PlainTableDBTest, AdaptiveTable) {
INSTANTIATE_TEST_CASE_P(PlainTableDBTest, PlainTableDBTest, ::testing::Bool());
TEST_P(PlainTableDBTest, DeleteRangeNotSupported) {
for (bool use_write_batch : {false, true}) {
// XXX: After attempting DeleteRange with PlainTable, Writes will permanently
// fail. Even if re-opening the DB, if WAL is used, the WAL is not recoverable
// (without manual intervention). Furthermore, a partial write batch can
// be exposed to readers, breaking WriteBatch atomicity.
for (bool use_write_batch : {/*false, */ true}) {
DestroyAndReopen();
ASSERT_OK(Put("a0001111", "1"));
@@ -1358,7 +1362,12 @@ TEST_P(PlainTableDBTest, DeleteRangeNotSupported) {
ASSERT_EQ(Get("a0001111"), "1");
ASSERT_EQ(Get("b0001111"), "2");
ASSERT_EQ(Get("c0001111"), "3");
ASSERT_EQ(Get("d0001111"), "NOT_FOUND"); // expect WriteBatch atomicity
if (use_write_batch) {
// XXX: broken WriteBatch atomicity
ASSERT_EQ(Get("d0001111"), "4");
} else {
ASSERT_EQ(Get("d0001111"), "NOT_FOUND");
}
ASSERT_EQ(Get("e0001111"), "NOT_FOUND");
ASSERT_EQ(Put("e0001111", "5").code(), Status::Code::kNotSupported);
@@ -1368,14 +1377,8 @@ TEST_P(PlainTableDBTest, DeleteRangeNotSupported) {
ASSERT_EQ(dbfull()->TEST_FlushMemTable().code(),
Status::Code::kNotSupported);
// WAL is recoverable (at least in standard configurations)
ASSERT_OK(TryReopen());
ASSERT_EQ(Get("a0001111"), "1");
ASSERT_EQ(Get("b0001111"), "2");
ASSERT_EQ(Get("c0001111"), "3");
ASSERT_EQ(Get("d0001111"), "NOT_FOUND");
ASSERT_EQ(Get("e0001111"), "NOT_FOUND");
// XXX: WAL is not recoverable
ASSERT_EQ(TryReopen().code(), Status::Code::kNotSupported);
}
}
+8 -1
View File
@@ -578,7 +578,14 @@ class Repairer {
static_cast<bool>(props->user_defined_timestamps_persisted);
}
if (status.ok()) {
uint64_t tail_size = FileMetaData::CalculateTailSize(file_size, *props);
uint64_t tail_size = 0;
bool contain_no_data_blocks =
props->num_entries > 0 &&
(props->num_entries == props->num_range_deletions);
if (props->tail_start_offset > 0 || contain_no_data_blocks) {
assert(props->tail_start_offset <= file_size);
tail_size = file_size - props->tail_start_offset;
}
t->meta.tail_size = tail_size;
}
ColumnFamilyData* cfd = nullptr;
-27
View File
@@ -380,33 +380,6 @@ struct FileMetaData {
assert(!res || fd.smallest_seqno == fd.largest_seqno);
return res;
}
static uint64_t CalculateTailSize(uint64_t file_size,
const TableProperties& props) {
#ifndef NDEBUG
bool skip = false;
TEST_SYNC_POINT_CALLBACK("FileMetaData::CalculateTailSize", &skip);
if (skip) {
return 0;
}
#endif // NDEBUG
uint64_t tail_size = 0;
// Differentiate between a file with no data blocks (tail_start_offset = 0)
// and a file with unknown tail_start_offset (also set to 0 due to
// non-negative integer storage limitation)
bool contain_no_data_blocks =
props.num_entries == 0 ||
(props.num_entries > 0 &&
(props.num_entries == props.num_range_deletions));
if (props.tail_start_offset > 0 || contain_no_data_blocks) {
assert(props.tail_start_offset <= file_size);
tail_size = file_size - props.tail_start_offset;
}
return tail_size;
}
};
// A compressed copy of file meta data that just contain minimum data needed
+1 -15
View File
@@ -1002,8 +1002,7 @@ class LevelIterator final : public InternalIterator {
skip_filters_(skip_filters),
allow_unprepared_value_(allow_unprepared_value),
is_next_read_sequential_(false),
to_return_sentinel_(false),
scan_opts_(nullptr) {
to_return_sentinel_(false) {
// Empty level is not supported.
assert(flevel_ != nullptr && flevel_->num_files > 0);
if (range_tombstone_iter_ptr_) {
@@ -1099,13 +1098,6 @@ class LevelIterator final : public InternalIterator {
read_seq_ = read_seq;
}
void Prepare(const std::vector<ScanOptions>* scan_opts) override {
scan_opts_ = scan_opts;
if (file_iter_.iter()) {
file_iter_.Prepare(scan_opts_);
}
}
private:
// Return true if at least one invalid file is seen and skipped.
bool SkipEmptyFileForward();
@@ -1231,7 +1223,6 @@ class LevelIterator final : public InternalIterator {
bool prefix_exhausted_ = false;
// Whether next/prev key is a sentinel key.
bool to_return_sentinel_ = false;
const std::vector<ScanOptions>* scan_opts_;
// Sets flags for if we should return the sentinel key next.
// The condition for returning sentinel is reaching the end of current
@@ -1542,11 +1533,6 @@ void LevelIterator::SetFileIterator(InternalIterator* iter) {
}
InternalIterator* old_iter = file_iter_.Set(iter);
// Since this is a new table iterator, no need to call Prepare() if
// scan_opts_ is null
if (iter && scan_opts_) {
file_iter_.Prepare(scan_opts_);
}
// Update the read pattern for PrefetchBuffer.
if (is_next_read_sequential_) {
+3 -3
View File
@@ -132,7 +132,7 @@ class WriteThread {
size_t protection_bytes_per_key;
PreReleaseCallback* pre_release_callback;
PostMemTableCallback* post_memtable_callback;
uint64_t wal_used; // log number that this batch was inserted into
uint64_t log_used; // log number that this batch was inserted into
uint64_t log_ref; // log number that memtable insert should reference
WriteCallback* callback;
UserWriteCallback* user_write_cb;
@@ -161,7 +161,7 @@ class WriteThread {
protection_bytes_per_key(0),
pre_release_callback(nullptr),
post_memtable_callback(nullptr),
wal_used(0),
log_used(0),
log_ref(0),
callback(nullptr),
user_write_cb(nullptr),
@@ -190,7 +190,7 @@ class WriteThread {
protection_bytes_per_key(_batch->GetProtectionBytesPerKey()),
pre_release_callback(_pre_release_callback),
post_memtable_callback(_post_memtable_callback),
wal_used(0),
log_used(0),
log_ref(_log_ref),
callback(_callback),
user_write_cb(_user_write_cb),
+2 -2
View File
@@ -106,6 +106,7 @@ DECLARE_uint64(db_write_buffer_size);
DECLARE_int32(write_buffer_size);
DECLARE_int32(max_write_buffer_number);
DECLARE_int32(min_write_buffer_number_to_merge);
DECLARE_int32(max_write_buffer_number_to_maintain);
DECLARE_int64(max_write_buffer_size_to_maintain);
DECLARE_bool(use_write_buffer_manager);
DECLARE_double(memtable_prefix_bloom_size_ratio);
@@ -320,6 +321,7 @@ DECLARE_int32(approximate_size_one_in);
DECLARE_bool(best_efforts_recovery);
DECLARE_bool(skip_verifydb);
DECLARE_bool(paranoid_file_checks);
DECLARE_bool(fail_if_options_file_error);
DECLARE_uint64(batch_protection_bytes_per_key);
DECLARE_uint32(memtable_protection_bytes_per_key);
DECLARE_uint32(block_protection_bytes_per_key);
@@ -422,8 +424,6 @@ DECLARE_uint32(commit_bypass_memtable_one_in);
DECLARE_bool(track_and_verify_wals);
DECLARE_bool(enable_remote_compaction);
DECLARE_bool(auto_refresh_iterator_with_snapshot);
DECLARE_uint32(memtable_op_scan_flush_trigger);
DECLARE_uint32(ingest_wbwi_one_in);
constexpr long KB = 1024;
constexpr int kRandomValueMaxFactor = 3;
+18 -10
View File
@@ -168,6 +168,20 @@ DEFINE_int32(min_write_buffer_number_to_merge,
"writing less data to storage if there are duplicate records in"
" each of these individual write buffers.");
DEFINE_int32(max_write_buffer_number_to_maintain,
ROCKSDB_NAMESPACE::Options().max_write_buffer_number_to_maintain,
"The total maximum number of write buffers to maintain in memory "
"including copies of buffers that have already been flushed. "
"Unlike max_write_buffer_number, this parameter does not affect "
"flushing. This controls the minimum amount of write history "
"that will be available in memory for conflict checking when "
"Transactions are used. If this value is too low, some "
"transactions may fail at commit time due to not being able to "
"determine whether there were any write conflicts. Setting this "
"value to 0 will cause write buffers to be freed immediately "
"after they are flushed. If this value is set to -1, "
"'max_write_buffer_number' will be used.");
DEFINE_int64(max_write_buffer_size_to_maintain,
ROCKSDB_NAMESPACE::Options().max_write_buffer_size_to_maintain,
"The total maximum size of write buffers to maintain in memory "
@@ -842,11 +856,6 @@ DEFINE_bool(track_and_verify_wals,
DEFINE_bool(enable_remote_compaction, false,
"Enable (simulated) Remote Compaction");
DEFINE_uint32(ingest_wbwi_one_in, 0,
"If set, will call"
"IngestWriteBatchWithIndex() instead of regular write operations "
"once every N writes.");
static bool ValidateInt32Percent(const char* flagname, int32_t value) {
if (value < 0 || value > 100) {
fprintf(stderr, "Invalid value for --%s: %d, 0<= pct <=100 \n", flagname,
@@ -1089,6 +1098,10 @@ DEFINE_bool(paranoid_file_checks, true,
"After writing every SST file, reopen it and read all the keys "
"and validate checksums");
DEFINE_bool(fail_if_options_file_error, false,
"Fail operations that fail to detect or properly persist options "
"file.");
DEFINE_uint64(batch_protection_bytes_per_key, 0,
"If nonzero, enables integrity protection in `WriteBatch` at the "
"specified number of bytes per key. Currently the only supported "
@@ -1474,9 +1487,4 @@ DEFINE_bool(
ROCKSDB_NAMESPACE::ReadOptions().auto_refresh_iterator_with_snapshot,
"ReadOptions.auto_refresh_iterator_with_snapshot");
DEFINE_uint32(
memtable_op_scan_flush_trigger,
ROCKSDB_NAMESPACE::ColumnFamilyOptions().memtable_op_scan_flush_trigger,
"Sets CF option memtable_op_scan_flush_trigger.");
#endif // GFLAGS
+2 -2
View File
@@ -265,7 +265,7 @@ class DbStressListener : public EventListener {
fault_fs_guard->DisableAllThreadLocalErrorInjection();
// TODO(hx235): only exempt the flush thread during error recovery instead
// of all the flush threads from error injection
fault_fs_guard->SetIOActivitiesExcludedFromFaultInjection(
fault_fs_guard->SetIOActivtiesExcludedFromFaultInjection(
{Env::IOActivity::kFlush});
}
}
@@ -275,7 +275,7 @@ class DbStressListener : public EventListener {
RandomSleep();
if (FLAGS_error_recovery_with_no_fault_injection && fault_fs_guard) {
fault_fs_guard->EnableAllThreadLocalErrorInjection();
fault_fs_guard->SetIOActivitiesExcludedFromFaultInjection({});
fault_fs_guard->SetIOActivtiesExcludedFromFaultInjection({});
}
}
+5 -2
View File
@@ -3376,6 +3376,8 @@ void StressTest::PrintEnv() const {
FLAGS_sync_fault_injection);
fprintf(stdout, "Best efforts recovery : %d\n",
static_cast<int>(FLAGS_best_efforts_recovery));
fprintf(stdout, "Fail if OPTIONS file error: %d\n",
static_cast<int>(FLAGS_fail_if_options_file_error));
fprintf(stdout, "User timestamp size bytes : %d\n",
static_cast<int>(FLAGS_user_timestamp_size));
fprintf(stdout, "Persist user defined timestamps : %d\n",
@@ -4045,6 +4047,8 @@ void InitializeOptionsFromFlags(
options.max_write_buffer_number = FLAGS_max_write_buffer_number;
options.min_write_buffer_number_to_merge =
FLAGS_min_write_buffer_number_to_merge;
options.max_write_buffer_number_to_maintain =
FLAGS_max_write_buffer_number_to_maintain;
options.max_write_buffer_size_to_maintain =
FLAGS_max_write_buffer_size_to_maintain;
options.memtable_prefix_bloom_size_ratio =
@@ -4253,6 +4257,7 @@ void InitializeOptionsFromFlags(
options.best_efforts_recovery = FLAGS_best_efforts_recovery;
options.paranoid_file_checks = FLAGS_paranoid_file_checks;
options.fail_if_options_file_error = FLAGS_fail_if_options_file_error;
if (FLAGS_user_timestamp_size > 0) {
CheckAndSetOptionsForUserTimestamp(options);
@@ -4316,8 +4321,6 @@ void InitializeOptionsFromFlags(
if (FLAGS_enable_remote_compaction) {
options.compaction_service = std::make_shared<DbStressCompactionService>();
}
options.memtable_op_scan_flush_trigger = FLAGS_memtable_op_scan_flush_trigger;
}
void InitializeOptionsGeneral(
+4 -44
View File
@@ -1845,17 +1845,7 @@ class NonBatchedOpsStressTest : public StressTest {
} else if (FLAGS_use_merge) {
if (!FLAGS_use_txn) {
if (FLAGS_user_timestamp_size == 0) {
if (FLAGS_ingest_wbwi_one_in &&
thread->rand.OneIn(FLAGS_ingest_wbwi_one_in)) {
auto wbwi = std::make_shared<WriteBatchWithIndex>(
options_.comparator, 0, /*overwrite_key=*/true);
s = wbwi->Merge(cfh, k, v);
if (s.ok()) {
s = db_->IngestWriteBatchWithIndex(write_opts, wbwi);
}
} else {
s = db_->Merge(write_opts, cfh, k, v);
}
s = db_->Merge(write_opts, cfh, k, v);
} else {
s = db_->Merge(write_opts, cfh, k, write_ts, v);
}
@@ -1867,17 +1857,7 @@ class NonBatchedOpsStressTest : public StressTest {
} else {
if (!FLAGS_use_txn) {
if (FLAGS_user_timestamp_size == 0) {
if (FLAGS_ingest_wbwi_one_in &&
thread->rand.OneIn(FLAGS_ingest_wbwi_one_in)) {
auto wbwi = std::make_shared<WriteBatchWithIndex>(
options_.comparator, 0, /*overwrite_key=*/true);
s = wbwi->Put(cfh, k, v);
if (s.ok()) {
s = db_->IngestWriteBatchWithIndex(write_opts, wbwi);
}
} else {
s = db_->Put(write_opts, cfh, k, v);
}
s = db_->Put(write_opts, cfh, k, v);
} else {
s = db_->Put(write_opts, cfh, k, write_ts, v);
}
@@ -1969,17 +1949,7 @@ class NonBatchedOpsStressTest : public StressTest {
}
if (!FLAGS_use_txn) {
if (FLAGS_user_timestamp_size == 0) {
if (FLAGS_ingest_wbwi_one_in &&
thread->rand.OneIn(FLAGS_ingest_wbwi_one_in)) {
auto wbwi = std::make_shared<WriteBatchWithIndex>(
options_.comparator, 0, /*overwrite_key=*/true);
s = wbwi->Delete(cfh, key);
if (s.ok()) {
s = db_->IngestWriteBatchWithIndex(write_opts, wbwi);
}
} else {
s = db_->Delete(write_opts, cfh, key);
}
s = db_->Delete(write_opts, cfh, key);
} else {
s = db_->Delete(write_opts, cfh, key, write_ts);
}
@@ -2036,17 +2006,7 @@ class NonBatchedOpsStressTest : public StressTest {
}
if (!FLAGS_use_txn) {
if (FLAGS_user_timestamp_size == 0) {
if (FLAGS_ingest_wbwi_one_in &&
thread->rand.OneIn(FLAGS_ingest_wbwi_one_in)) {
auto wbwi = std::make_shared<WriteBatchWithIndex>(
options_.comparator, 0, /*overwrite_key=*/true);
s = wbwi->SingleDelete(cfh, key);
if (s.ok()) {
s = db_->IngestWriteBatchWithIndex(write_opts, wbwi);
}
} else {
s = db_->SingleDelete(write_opts, cfh, key);
}
s = db_->SingleDelete(write_opts, cfh, key);
} else {
s = db_->SingleDelete(write_opts, cfh, key, write_ts);
}
+10 -20
View File
@@ -322,17 +322,8 @@ class PosixFileSystem : public FileSystem {
if (options.use_mmap_writes) {
MaybeForceDisableMmap(fd);
}
uint64_t initial_file_size = 0;
if (reopen) {
s = GetFileSize(fname, IOOptions(), &initial_file_size, nullptr);
if (!s.ok()) {
close(fd);
return s;
}
}
if (options.use_mmap_writes && !forceMmapOff_) {
result->reset(
new PosixMmapFile(fname, fd, page_size_, options, initial_file_size));
result->reset(new PosixMmapFile(fname, fd, page_size_, options));
} else if (options.use_direct_writes && !options.use_mmap_writes) {
#ifdef OS_MACOSX
if (fcntl(fd, F_NOCACHE, 1) == -1) {
@@ -352,7 +343,7 @@ class PosixFileSystem : public FileSystem {
#endif
result->reset(new PosixWritableFile(
fname, fd, GetLogicalBlockSizeForWriteIfNeeded(options, fname, fd),
options, initial_file_size));
options));
} else {
// disable mmap writes
EnvOptions no_mmap_writes_options = options;
@@ -361,7 +352,7 @@ class PosixFileSystem : public FileSystem {
new PosixWritableFile(fname, fd,
GetLogicalBlockSizeForWriteIfNeeded(
no_mmap_writes_options, fname, fd),
no_mmap_writes_options, initial_file_size));
no_mmap_writes_options));
}
return s;
}
@@ -427,8 +418,7 @@ class PosixFileSystem : public FileSystem {
MaybeForceDisableMmap(fd);
}
if (options.use_mmap_writes && !forceMmapOff_) {
result->reset(new PosixMmapFile(fname, fd, page_size_, options,
/*initial_file_size=*/0));
result->reset(new PosixMmapFile(fname, fd, page_size_, options));
} else if (options.use_direct_writes && !options.use_mmap_writes) {
#ifdef OS_MACOSX
if (fcntl(fd, F_NOCACHE, 1) == -1) {
@@ -448,16 +438,16 @@ class PosixFileSystem : public FileSystem {
#endif
result->reset(new PosixWritableFile(
fname, fd, GetLogicalBlockSizeForWriteIfNeeded(options, fname, fd),
options, /*initial_file_size=*/0));
options));
} else {
// disable mmap writes
FileOptions no_mmap_writes_options = options;
no_mmap_writes_options.use_mmap_writes = false;
result->reset(new PosixWritableFile(
fname, fd,
GetLogicalBlockSizeForWriteIfNeeded(no_mmap_writes_options, fname,
fd),
no_mmap_writes_options, /*initial_file_size=*/0));
result->reset(
new PosixWritableFile(fname, fd,
GetLogicalBlockSizeForWriteIfNeeded(
no_mmap_writes_options, fname, fd),
no_mmap_writes_options));
}
return s;
}
+4 -6
View File
@@ -1138,8 +1138,7 @@ IOStatus PosixMmapFile::Msync() {
}
PosixMmapFile::PosixMmapFile(const std::string& fname, int fd, size_t page_size,
const EnvOptions& options,
uint64_t initial_file_size)
const EnvOptions& options)
: filename_(fname),
fd_(fd),
page_size_(page_size),
@@ -1148,7 +1147,7 @@ PosixMmapFile::PosixMmapFile(const std::string& fname, int fd, size_t page_size,
limit_(nullptr),
dst_(nullptr),
last_sync_(nullptr),
file_offset_(initial_file_size) {
file_offset_(0) {
#ifdef ROCKSDB_FALLOCATE_PRESENT
allow_fallocate_ = options.allow_fallocate;
fallocate_with_keep_size_ = options.fallocate_with_keep_size;
@@ -1318,13 +1317,12 @@ IOStatus PosixMmapFile::Allocate(uint64_t offset, uint64_t len,
*/
PosixWritableFile::PosixWritableFile(const std::string& fname, int fd,
size_t logical_block_size,
const EnvOptions& options,
uint64_t initial_file_size)
const EnvOptions& options)
: FSWritableFile(options),
filename_(fname),
use_direct_io_(options.use_direct_writes),
fd_(fd),
filesize_(initial_file_size),
filesize_(0),
logical_sector_size_(logical_block_size) {
#ifdef ROCKSDB_FALLOCATE_PRESENT
allow_fallocate_ = options.allow_fallocate;
+2 -3
View File
@@ -374,8 +374,7 @@ class PosixWritableFile : public FSWritableFile {
public:
explicit PosixWritableFile(const std::string& fname, int fd,
size_t logical_block_size,
const EnvOptions& options,
uint64_t initial_file_size);
const EnvOptions& options);
virtual ~PosixWritableFile();
// Need to implement this so the file is truncated correctly
@@ -470,7 +469,7 @@ class PosixMmapFile : public FSWritableFile {
public:
PosixMmapFile(const std::string& fname, int fd, size_t page_size,
const EnvOptions& options, uint64_t initial_file_size);
const EnvOptions& options);
~PosixMmapFile();
// Means Close() will properly take care of truncate
+1 -5
View File
@@ -126,8 +126,6 @@ Status FilePrefetchBuffer::Read(BufferInfo* buf, const IOOptions& opts,
if (usage_ == FilePrefetchBufferUsage::kUserScanPrefetch) {
RecordTick(stats_, PREFETCH_BYTES, read_len);
} else if (usage_ == FilePrefetchBufferUsage::kCompactionPrefetch) {
RecordInHistogram(stats_, COMPACTION_PREFETCH_BYTES, read_len);
}
if (!use_fs_buffer) {
// Update the buffer size.
@@ -156,9 +154,7 @@ Status FilePrefetchBuffer::ReadAsync(BufferInfo* buf, const IOOptions& opts,
&(buf->del_fn_), /*aligned_buf =*/nullptr);
req.status.PermitUncheckedError();
if (s.ok()) {
if (usage_ == FilePrefetchBufferUsage::kUserScanPrefetch) {
RecordTick(stats_, PREFETCH_BYTES, read_len);
}
RecordTick(stats_, PREFETCH_BYTES, read_len);
buf->async_read_in_progress_ = true;
}
return s;
-4
View File
@@ -134,7 +134,6 @@ struct BufferInfo {
enum class FilePrefetchBufferUsage {
kTableOpenPrefetchTail,
kUserScanPrefetch,
kCompactionPrefetch,
kUnknown,
};
@@ -575,9 +574,6 @@ class FilePrefetchBuffer {
size_t& read_len, uint64_t& aligned_useful_len);
void UpdateStats(bool found_in_buffer, size_t length_found) {
if (usage_ != FilePrefetchBufferUsage::kUserScanPrefetch) {
return;
}
if (found_in_buffer) {
RecordTick(stats_, PREFETCH_HITS);
}
+5 -31
View File
@@ -299,18 +299,9 @@ TEST_P(PrefetchTest, Basic) {
const uint64_t prev_table_open_prefetch_tail_hit =
options.statistics->getTickerCount(TABLE_OPEN_PREFETCH_TAIL_HIT);
HistogramData pre_compaction_prefetch_bytes;
options.statistics->histogramData(COMPACTION_PREFETCH_BYTES,
&pre_compaction_prefetch_bytes);
ASSERT_EQ(pre_compaction_prefetch_bytes.count, 0);
// commenting out the line below causes the example to work correctly
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), &least, &greatest));
HistogramData post_compaction_prefetch_bytes;
options.statistics->histogramData(COMPACTION_PREFETCH_BYTES,
&post_compaction_prefetch_bytes);
HistogramData cur_table_open_prefetch_tail_read;
options.statistics->histogramData(TABLE_OPEN_PREFETCH_TAIL_READ_BYTES,
&cur_table_open_prefetch_tail_read);
@@ -327,7 +318,6 @@ TEST_P(PrefetchTest, Basic) {
ASSERT_GT(fs->GetPrefetchCount(), 1);
ASSERT_EQ(0, buff_prefetch_count);
fs->ClearPrefetchCount();
ASSERT_EQ(post_compaction_prefetch_bytes.count, 0);
} else {
ASSERT_FALSE(fs->IsPrefetchCalled());
// To rule out false positive by the SST file tail prefetch during
@@ -341,20 +331,6 @@ TEST_P(PrefetchTest, Basic) {
prev_table_open_prefetch_tail_hit);
ASSERT_GE(cur_table_open_prefetch_tail_miss,
prev_table_open_prefetch_tail_miss);
ASSERT_GT(post_compaction_prefetch_bytes.count, 0);
// Not an exact match due to potential roundup/down for alignment
auto expected_compaction_readahead_size =
Options().compaction_readahead_size;
ASSERT_LE(post_compaction_prefetch_bytes.max,
expected_compaction_readahead_size * 1.1);
ASSERT_GE(post_compaction_prefetch_bytes.max,
expected_compaction_readahead_size * 0.9);
ASSERT_LE(post_compaction_prefetch_bytes.average,
expected_compaction_readahead_size * 1.1);
ASSERT_GE(post_compaction_prefetch_bytes.average,
expected_compaction_readahead_size * 0.9);
}
for (bool disable_io : {false, true}) {
@@ -3275,9 +3251,8 @@ TEST_F(FilePrefetchBufferTest, SyncReadaheadStats) {
ReadaheadParams readahead_params;
readahead_params.initial_readahead_size = 8192;
readahead_params.max_readahead_size = 8192;
FilePrefetchBuffer fpb(
readahead_params, true, false, fs(), nullptr, stats.get(),
nullptr /* cb */, FilePrefetchBufferUsage::kUserScanPrefetch /* usage */);
FilePrefetchBuffer fpb(readahead_params, true, false, fs(), nullptr,
stats.get());
Slice result;
// Simulate a seek of 4096 bytes at offset 0. Due to the readahead settings,
// it will do a read of offset 0 and length - (4096 + 8192) 12288.
@@ -3522,10 +3497,9 @@ TEST_P(FSBufferPrefetchTest, FSBufferPrefetchStatsInternals) {
size_t num_buffers = use_async_prefetch ? 2 : 1;
readahead_params.num_buffers = num_buffers;
FilePrefetchBuffer fpb(
readahead_params, true /* enable */, false /* track_min_offset */, fs(),
clock(), stats.get(), nullptr /* cb */,
FilePrefetchBufferUsage::kUserScanPrefetch /* usage */);
FilePrefetchBuffer fpb(readahead_params, true /* enable */,
false /* track_min_offset */, fs(), clock(),
stats.get());
int overlap_buffer_write_ct = 0;
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
-36
View File
@@ -1,36 +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
#include "rocksdb/slice.h"
namespace ROCKSDB_NAMESPACE {
enum class IterBoundCheck : char {
kUnknown = 0,
kOutOfBound,
kInbound,
};
// This structure encapsulates the result of NextAndGetResult()
struct IterateResult {
// The lifetime of key is guaranteed until Next()/NextAndGetResult() is
// called.
Slice key;
// If the iterator becomes invalid after a NextAndGetResult(), the table
// iterator should set this to indicate whether it became invalid due
// to the next key being out of bound (kOutOfBound) or it reached end
// of file (kUnknown). If the iiterator is still valid, this should
// be set to kInbound.
IterBoundCheck bound_check_result = IterBoundCheck::kUnknown;
// If false, PrepareValue() needs to be called before value()
// This is useful if the table reader wants to materialize the value in a
// lazy manner. In that case, it can set this to false and RocksDB
// guarantees that it'll call PrepareValue() before calling value().
bool value_prepared = true;
};
} // namespace ROCKSDB_NAMESPACE
+9 -14
View File
@@ -171,6 +171,15 @@ struct AdvancedColumnFamilyOptions {
// Default: 1
int min_write_buffer_number_to_merge = 1;
// DEPRECATED
// The total maximum number of write buffers to maintain in memory including
// copies of buffers that have already been flushed. Unlike
// max_write_buffer_number, this parameter does not affect flushing.
// This parameter is being replaced by max_write_buffer_size_to_maintain.
// If both parameters are set to non-zero values, this parameter will be
// ignored.
int max_write_buffer_number_to_maintain = 0;
// The target number of write history bytes to hold in memory. Write history
// comprises the latest write buffers (memtables). To reach the target, write
// buffers that were most recently flushed to SST files may be retained in
@@ -1096,20 +1105,6 @@ struct AdvancedColumnFamilyOptions {
// additional key comparison during memtable lookup.
bool paranoid_memory_checks = false;
// When an iterator scans this number of invisible entries (tombstones or
// hidden puts) from the active memtable during a single iterator operation,
// we will attempt to flush the memtable. Currently only forward scans are
// supported (SeekToFirst(), Seek() and Next()).
// This option helps to reduce the overhead of scanning through a
// large number of entries in memtable.
// Users should consider enable deletion-triggered-compaction (see
// CompactOnDeletionCollectorFactory) together with this option to compact
// away tombstones after the memtable is flushed.
//
// Default: 0 (disabled)
// Dynamically changeable through the SetOptions() API.
uint32_t memtable_op_scan_flush_trigger = 0;
// Create ColumnFamilyOptions with default values for all fields
AdvancedColumnFamilyOptions();
// Create ColumnFamilyOptions from Options
+5 -5
View File
@@ -1341,11 +1341,6 @@ extern ROCKSDB_LIBRARY_API void rocksdb_options_set_periodic_compaction_seconds(
rocksdb_options_t*, uint64_t);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_options_get_periodic_compaction_seconds(rocksdb_options_t*);
extern ROCKSDB_LIBRARY_API void
rocksdb_options_set_memtable_op_scan_flush_trigger(rocksdb_options_t*,
uint32_t);
extern ROCKSDB_LIBRARY_API uint32_t
rocksdb_options_get_memtable_op_scan_flush_trigger(rocksdb_options_t*);
enum {
rocksdb_statistics_level_disable_all = 0,
@@ -1453,6 +1448,11 @@ rocksdb_options_set_min_write_buffer_number_to_merge(rocksdb_options_t*, int);
extern ROCKSDB_LIBRARY_API int
rocksdb_options_get_min_write_buffer_number_to_merge(rocksdb_options_t*);
extern ROCKSDB_LIBRARY_API void
rocksdb_options_set_max_write_buffer_number_to_maintain(rocksdb_options_t*,
int);
extern ROCKSDB_LIBRARY_API int
rocksdb_options_get_max_write_buffer_number_to_maintain(rocksdb_options_t*);
extern ROCKSDB_LIBRARY_API void
rocksdb_options_set_max_write_buffer_size_to_maintain(rocksdb_options_t*,
int64_t);
extern ROCKSDB_LIBRARY_API int64_t
+5 -56
View File
@@ -22,7 +22,6 @@
#include "rocksdb/iterator.h"
#include "rocksdb/listener.h"
#include "rocksdb/metadata.h"
#include "rocksdb/multi_scan.h"
#include "rocksdb/options.h"
#include "rocksdb/snapshot.h"
#include "rocksdb/sst_file_writer.h"
@@ -31,7 +30,6 @@
#include "rocksdb/types.h"
#include "rocksdb/user_write_callback.h"
#include "rocksdb/utilities/table_properties_collectors.h"
#include "rocksdb/utilities/write_batch_with_index.h"
#include "rocksdb/version.h"
#include "rocksdb/wide_columns.h"
@@ -618,7 +616,7 @@ class DB {
const Slice& /*key*/, const Slice& /*ts*/,
const Slice& /*value*/);
// Apply the specified updates atomically to the database.
// Apply the specified updates to the database.
// If `updates` contains no update, WAL will still be synced if
// options.sync=true.
// Returns OK on success, non-OK on failure.
@@ -634,21 +632,6 @@ class DB {
"WriteWithCallback not implemented for this interface.");
}
// EXPERIMENTAL, subject to change
// Ingest a WriteBatchWithIndex into DB, bypassing memtable writes for better
// write performance. Useful when there is a large number of updates
// in the write batch.
// The WriteBatchWithIndex must be created with overwrite_key=true.
// Currently this requires WriteOptions::disableWAL=true.
// The following options are currently not supported:
// - unordered_write
// - enable_pipelined_write
virtual Status IngestWriteBatchWithIndex(
const WriteOptions& /*options*/,
std::shared_ptr<WriteBatchWithIndex> /*wbwi*/) {
return Status::NotSupported("IngestWriteBatchWithIndex not implemented.");
}
// If the column family specified by "column_family" contains an entry for
// "key", return the corresponding value in "*value". If the entry is a plain
// key-value, return the value as-is; if it is a wide-column entity, return
@@ -1090,18 +1073,6 @@ class DB {
const ReadOptions& options,
const std::vector<ColumnFamilyHandle*>& column_families) = 0;
// Get an iterator that scans multiple key ranges. The scan ranges should
// be in increasing order of start key. See multi_scan_iterator.h for more
// details.
virtual std::unique_ptr<MultiScan> NewMultiScan(
const ReadOptions& /*options*/, ColumnFamilyHandle* /*column_family*/,
const std::vector<ScanOptions>& /*scan_opts*/) {
std::unique_ptr<Iterator> iter(NewErrorIterator(Status::NotSupported()));
std::unique_ptr<MultiScan> ms_iter =
std::make_unique<MultiScan>(std::move(iter));
return ms_iter;
}
// Return a handle to the current DB state. Iterators created with
// this handle will all observe a stable snapshot of the current DB
// state. The caller must call ReleaseSnapshot(result) when the
@@ -1687,12 +1658,9 @@ class DB {
virtual int NumberLevels(ColumnFamilyHandle* column_family) = 0;
virtual int NumberLevels() { return NumberLevels(DefaultColumnFamily()); }
// DEPRECATED:
// Maximum level to which a new compacted memtable is pushed if it
// does not create overlap.
virtual int MaxMemCompactionLevel(ColumnFamilyHandle* /*column_family*/) {
return 0;
}
virtual int MaxMemCompactionLevel(ColumnFamilyHandle* column_family) = 0;
virtual int MaxMemCompactionLevel() {
return MaxMemCompactionLevel(DefaultColumnFamily());
}
@@ -1798,25 +1766,6 @@ class DB {
virtual Status GetFullHistoryTsLow(ColumnFamilyHandle* column_family,
std::string* ts_low) = 0;
// EXPERIMENTAL
// Get the newest timestamp of the column family. This is only for when the
// column family enables user defined timestamp and when timestamps are not
// persisted in SST files, a.k.a `persist_user_defined_timestamps=false`.
// This checks the mutable memtable, the immutable memtable and the SST files,
// and returns the first newest user defined timestamp found.
// When user defined timestamp is not persisted in SST files, metadata in
// MANIFEST tracks the most recently seen timestamp for SST files, so the
// newest timestamp in SST files can be found.
// OK status is returned if finding the newest timestamp succeeds, if
// `newest_timestamp` is empty, it means the column family hasn't seen any
// timestamp. The returned timestamp is encoded, util method `DecodeU64Ts` can
// be used to decode it into uint64_t.
// User-defined timestamp is required to be increasing per key, the return
// value of this API would be most useful if the user-defined timestamp is
// monotonically increasing across keys.
virtual Status GetNewestUserDefinedTimestamp(
ColumnFamilyHandle* column_family, std::string* newest_timestamp) = 0;
// Suspend deleting obsolete files. Compactions will continue to occur,
// but no obsolete files will be deleted. To resume file deletions, each
// call to DisableFileDeletions() must be matched by a subsequent call to
@@ -1928,12 +1877,12 @@ class DB {
// Retrieve information about the current wal file
//
// Note that the log might have rolled after this call in which case
// the current_wal_file would not point to the current log file.
// the current_log_file would not point to the current log file.
//
// Additionally, for the sake of optimization current_wal_file->StartSequence
// Additionally, for the sake of optimization current_log_file->StartSequence
// would always be set to 0
virtual Status GetCurrentWalFile(
std::unique_ptr<WalFile>* current_wal_file) = 0;
std::unique_ptr<WalFile>* current_log_file) = 0;
// IngestExternalFile() will load a list of external SST files (1) into the DB
// Two primary modes are supported:
-5
View File
@@ -21,11 +21,6 @@ Status SuggestCompactRange(DB* db, ColumnFamilyHandle* column_family,
const Slice* begin, const Slice* end);
Status SuggestCompactRange(DB* db, const Slice* begin, const Slice* end);
// DEPRECATED: this API may be removed in a future release.
// This operation can be done through CompactRange() by setting
// CompactRangeOptions::bottommost_level_compaction set to
// BottommostLevelCompaction::kSkip and setting target level.
//
// Move all L0 files to target_level skipping compaction.
// This operation succeeds only if the files in L0 have disjoint ranges; this
// is guaranteed to happen, for instance, if keys are inserted in sorted
+6 -74
View File
@@ -5,11 +5,9 @@
#pragma once
#include "rocksdb/advanced_iterator.h"
#include "rocksdb/customizable.h"
#include "rocksdb/file_checksum.h"
#include "rocksdb/file_system.h"
#include "rocksdb/iterator_base.h"
#include "rocksdb/iterator.h"
#include "rocksdb/options.h"
#include "rocksdb/status.h"
@@ -60,47 +58,6 @@ class ExternalTableFactory;
// the external table implementation.
// TODO: Specify which options are relevant
class ExternalTableIterator : public IteratorBase {
public:
virtual ~ExternalTableIterator() {}
// This can optionally be called to prepare the iterator for a series
// of scans. The scan_opts parameter specifies the order of scans to
// follow, as well as the limits for those scans. After calling this,
// the caller will Seek() the iterator to successive start keys in scan_opts.
//
// If Prepare() is called again with a different scan_opts pointer, it
// means the iterator will be reused for a new multi scan. If scan_opts
// is null, then the previous Prepare() can be discarded.
//
// The caller guarantees the lifetime of scan_opts until its either cleared
// or replaced by another Prepare().
// TODO: Update the contract to trim the scan_opts range to only include
// scans that potentially intersect the file key range.
//
// If the sequence of Seeks is interrupted by seeking to some other target
// key, then the iterator is free to discard anything done during Prepare.
virtual void Prepare(const ScanOptions scan_opts[], size_t num_opts) = 0;
// Similar to Next(), except it also fills the result and returns whether
// the iterator is on a valid key or not
virtual bool NextAndGetResult(IterateResult* result) = 0;
// Prepares the value if its lazily materialized. The implementation can
// request that this be called by setting value_prepared to false in
// IterateResult. Next() should always implicitly materialize the
// value.
bool PrepareValue() override = 0;
// Return the current key's value
virtual Slice value() const = 0;
// Return the current position bounds check result - kInbound if the
// position is a valid key, kOutOfBound if the key is out of bound (i.e
// scan has terminated), or kUnknown if end of file.
virtual IterBoundCheck UpperBoundCheckResult() = 0;
};
class ExternalTableReader {
public:
virtual ~ExternalTableReader() {}
@@ -108,9 +65,8 @@ class ExternalTableReader {
// Return an Iterator that can be used to scan the table file.
// The read_options can optionally contain the upper bound
// key (exclusive) of the scan in iterate_upper_bound.
virtual ExternalTableIterator* NewIterator(
const ReadOptions& read_options,
const SliceTransform* prefix_extractor) = 0;
virtual Iterator* NewIterator(const ReadOptions& read_options,
const SliceTransform* prefix_extractor) = 0;
// Point lookup the given key and return its value
virtual Status Get(const ReadOptions& read_options, const Slice& key,
@@ -125,17 +81,6 @@ class ExternalTableReader {
std::vector<std::string>* values,
std::vector<Status>* statuses) = 0;
// Allocate and return the contents of the properties block. If the builder
// supports PutPropertiesBlock(), then this must be supported. The
// properties block should be written to the table file as is (no
// compression or mutation of any kind), and its offset in the file
// should be returned in file_offset.
virtual Status GetPropertiesBlock(std::unique_ptr<char[]>* /*property_block*/,
uint64_t* /*size*/,
uint64_t* /*file_offset*/) {
return Status::NotSupported();
}
// Return TableProperties for the file. At a minimum, the following
// properties need to be returned -
// comparator_name
@@ -190,11 +135,6 @@ class ExternalTableBuilder {
// Finish().
virtual uint64_t FileSize() const = 0;
// Write the raw properties block as is in the table file
virtual Status PutPropertiesBlock(const Slice& /*property_block*/) {
return Status::NotSupported();
}
// As mentioned in earlier comments, the following table properties must be
// returned at a minimum -
// comparator_name
@@ -213,17 +153,11 @@ class ExternalTableBuilder {
struct ExternalTableOptions {
const std::shared_ptr<const SliceTransform>& prefix_extractor;
const Comparator* comparator;
const std::shared_ptr<FileSystem>& fs;
const FileOptions& file_options;
ExternalTableOptions(
const std::shared_ptr<const SliceTransform>& _prefix_extractor,
const Comparator* _comparator, const std::shared_ptr<FileSystem>& _fs,
const FileOptions& _file_options)
: prefix_extractor(_prefix_extractor),
comparator(_comparator),
fs(_fs),
file_options(_file_options) {}
const Comparator* _comparator)
: prefix_extractor(_prefix_extractor), comparator(_comparator) {}
};
struct ExternalTableBuilderOptions {
@@ -260,11 +194,9 @@ class ExternalTableFactory : public Customizable {
const ExternalTableOptions& table_options,
std::unique_ptr<ExternalTableReader>* table_reader) const = 0;
// The table builder should use the file pointer to append to the file.
// Do not sync or close the file after finishing. RocksDB will do that.
virtual ExternalTableBuilder* NewTableBuilder(
const ExternalTableBuilderOptions& builder_options,
const std::string& file_path, FSWritableFile* file) const = 0;
const std::string& file_path) const = 0;
};
// Allocate a TableFactory that wraps around an ExternalTableFactory. Use this
-13
View File
@@ -21,7 +21,6 @@
#include <string>
#include "rocksdb/iterator_base.h"
#include "rocksdb/options.h"
#include "rocksdb/wide_columns.h"
namespace ROCKSDB_NAMESPACE {
@@ -94,18 +93,6 @@ class Iterator : public IteratorBase {
assert(false);
return Slice();
}
// RocksDB Internal - DO NOT USE
// Prepare the iterator to scan the ranges specified in scan_opts. The
// upper bound and other table specific limits may be specified. This will
// typically be followed by Seeks to the start keys in the order they're
// specified in scan_opts. If the user does a Seek to some other target key,
// the iterator should disregard the scan_opts from that point onwards and
// behave like a normal iterator. Its the user's responsibility to again
// call Prepare().
// If Prepare() is called, it overrides the iterate_upper_bound in
// ReadOptions
virtual void Prepare(const std::vector<ScanOptions>& /*scan_opts*/) {}
};
// Return an empty iterator (yields nothing).
-237
View File
@@ -1,237 +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
#include "rocksdb/iterator.h"
#include "rocksdb/options.h"
namespace ROCKSDB_NAMESPACE {
// EXPERIMENTAL
//
// An iterator that returns results from multiple scan ranges. The ranges are
// expected to be in increasing sorted order.
// The results are returned in nested container objects that can be iterated
// using an std::input_iterator.
//
// MultiScan
// |
// ---
// |
// MultiScanIterator <-- std::input_iterator (returns a Scan object for each
// | scan range)
// ---
// |
// Scan
// |
// ---
// |
// ScanIterator <-- std::input_iterator (returns the KVs of a single
// scan range)
//
// The application on top of RocksDB
// would use this as follows -
//
// std::vector<ScanOptions> scans{{.start = Slice("bar")},
// {.start = Slice("foo")}};
// std::unique_ptr<MultiScan> iter.reset(
// db->NewMultiScan());
// try {
// for (auto scan : *iter) {
// for (auto it : scan) {
// // Do something with key - it.first
// // Do something with value - it.second
// }
// }
// } catch (MultiScanException& ex) {
// // Check ex.status()
// } catch (std::logic_error& ex) {
// // Check ex.what()
// }
class MultiScanException : public std::runtime_error {
public:
explicit MultiScanException(Status& s)
: std::runtime_error(s.ToString()), s_(s) {}
Status& status() { return s_; }
private:
Status s_;
};
// A container object encapsulating a single scan range. It supports an
// std::input_iterator for a single pass iteration of the KVs in the range.
// A Status exception is thrown if there is an error in scanning the range.
class Scan {
public:
class ScanIterator;
explicit Scan(Iterator* db_iter) : db_iter_(db_iter) {}
ScanIterator begin() { return ScanIterator(db_iter_); }
std::nullptr_t end() { return nullptr; }
class ScanIterator {
public:
using self_type = ScanIterator;
using value_type = std::pair<Slice, Slice>;
using reference = std::pair<Slice, Slice>&;
using pointer = std::pair<Slice, Slice>*;
using difference_type = int;
using iterator_category = std::input_iterator_tag;
explicit ScanIterator(Iterator* db_iter) : db_iter_(db_iter) {
valid_ = db_iter_->Valid();
if (valid_) {
result_ = value_type(db_iter_->key(), db_iter_->value());
}
}
ScanIterator() : db_iter_(nullptr), valid_(false) {}
~ScanIterator() { assert(status_.ok()); }
ScanIterator& operator++() {
if (!valid_) {
throw std::logic_error("Trying to advance invalid iterator");
} else {
db_iter_->Next();
status_ = db_iter_->status();
if (!status_.ok()) {
throw MultiScanException(status_);
} else {
valid_ = db_iter_->Valid();
if (valid_) {
result_ = value_type(db_iter_->key(), db_iter_->value());
}
}
}
return *this;
}
bool operator==(std::nullptr_t /*other*/) const { return !valid_; }
bool operator!=(std::nullptr_t /*other*/) const { return valid_; }
reference operator*() {
if (!valid_) {
throw std::logic_error("Trying to deref invalid iterator");
}
return result_;
}
reference operator->() {
if (!valid_) {
throw std::logic_error("Trying to deref invalid iterator");
}
return result_;
}
private:
Iterator* db_iter_;
bool valid_;
Status status_;
value_type result_;
};
private:
Iterator* db_iter_;
};
// A container object encapsulating the scan ranges for a multi scan.
// It supports an std::input_iterator for a single pass iteration of the
// ScanOptions in scan_opts, which can be dereferenced to get the container
// (Scan) for a single range.
// A Status exception is thrown if there is an error.
class MultiScan {
public:
MultiScan(const std::vector<ScanOptions>& scan_opts,
std::unique_ptr<Iterator>&& db_iter)
: scan_opts_(scan_opts), db_iter_(std::move(db_iter)) {}
explicit MultiScan(std::unique_ptr<Iterator>&& db_iter)
: db_iter_(std::move(db_iter)) {}
class MultiScanIterator {
public:
MultiScanIterator(const MultiScanIterator&) = delete;
MultiScanIterator operator=(MultiScanIterator&) = delete;
using self_type = MultiScanIterator;
using value_type = Scan;
using reference = Scan&;
using pointer = Scan*;
using difference_type = int;
using iterator_category = std::input_iterator_tag;
MultiScanIterator(const std::vector<ScanOptions>& scan_opts,
Iterator* db_iter)
: scan_opts_(scan_opts), idx_(0), db_iter_(db_iter), scan_(db_iter_) {
if (scan_opts_.empty()) {
throw std::logic_error("Zero scans in multi-scan");
}
db_iter_->Seek(*scan_opts_[idx_].range.start);
status_ = db_iter_->status();
if (!status_.ok()) {
throw MultiScanException(status_);
}
}
explicit MultiScanIterator(const std::vector<ScanOptions>& scan_opts)
: scan_opts_(scan_opts),
idx_(scan_opts_.size()),
db_iter_(nullptr),
scan_(nullptr) {}
~MultiScanIterator() { assert(status_.ok()); }
MultiScanIterator& operator++() {
if (idx_ >= scan_opts_.size()) {
throw std::logic_error("Index out of range");
}
idx_++;
if (idx_ < scan_opts_.size()) {
db_iter_->Seek(*scan_opts_[idx_].range.start);
status_ = db_iter_->status();
if (!status_.ok()) {
throw MultiScanException(status_);
}
}
return *this;
}
bool operator==(std::nullptr_t /*other*/) const {
return idx_ >= scan_opts_.size();
}
bool operator!=(std::nullptr_t /*other*/) const {
return idx_ < scan_opts_.size();
}
reference operator*() { return scan_; }
reference operator->() { return scan_; }
private:
const std::vector<ScanOptions>& scan_opts_;
size_t idx_;
Iterator* db_iter_;
Status status_;
Scan scan_;
};
MultiScanIterator begin() {
return MultiScanIterator(scan_opts_, db_iter_.get());
}
std::nullptr_t end() { return nullptr; }
private:
const std::vector<ScanOptions> scan_opts_;
std::unique_ptr<Iterator> db_iter_;
};
} // namespace ROCKSDB_NAMESPACE
+55 -76
View File
@@ -477,19 +477,12 @@ struct CompactionServiceJobInfo {
bool is_manual_compaction;
bool bottommost_level;
// the smallest input level of the compaction.
// (same as Compaction::start_level and CompactionJobInfo::base_input_level)
int base_input_level;
// the output level of the compaction.
int output_level;
CompactionServiceJobInfo(std::string db_name_, std::string db_id_,
std::string db_session_id_, uint64_t job_id_,
Env::Priority priority_,
CompactionReason compaction_reason_,
bool is_full_compaction_, bool is_manual_compaction_,
bool bottommost_level_, int base_input_level_,
int output_level_)
bool bottommost_level_)
: db_name(std::move(db_name_)),
db_id(std::move(db_id_)),
db_session_id(std::move(db_session_id_)),
@@ -498,9 +491,7 @@ struct CompactionServiceJobInfo {
compaction_reason(compaction_reason_),
is_full_compaction(is_full_compaction_),
is_manual_compaction(is_manual_compaction_),
bottommost_level(bottommost_level_),
base_input_level(base_input_level_),
output_level(output_level_) {}
bottommost_level(bottommost_level_) {}
};
struct CompactionServiceScheduleResponse {
@@ -824,7 +815,6 @@ struct DBOptions {
// If it is non empty, the log files will be in the specified dir,
// and the db data dir's absolute path will be used as the log file
// name's prefix.
// NOTE: not for WALs
std::string db_log_dir = "";
// This specifies the absolute dir path for write-ahead logs (WAL).
@@ -905,24 +895,21 @@ struct DBOptions {
// be created.
// If max_log_file_size == 0, all logs will be written to one
// log file.
// NOTE: not for WALs
size_t max_log_file_size = 0;
// Time for the info log file to roll (in seconds).
// If specified with non-zero value, log file will be rolled
// if it has been active longer than `log_file_time_to_roll`.
// Default: 0 (disabled)
// NOTE: not for WALs
size_t log_file_time_to_roll = 0;
// Maximal info log files to be kept.
// Default: 1000
// NOTE: not for WALs
size_t keep_log_file_num = 1000;
// Recycle WAL files.
// If non-zero, we will reuse previously written WAL files for new
// WALs, overwriting the old data. The value indicates how many
// Recycle log files.
// If non-zero, we will reuse previously written log files for new
// logs, overwriting the old data. The value indicates how many
// such files we will keep around at any point in time for later
// use. This is more efficient because the blocks are already
// allocated and fdatasync does not need to update the inode after
@@ -1310,6 +1297,14 @@ struct DBOptions {
// currently.
WalFilter* wal_filter = nullptr;
// DEPRECATED: This option might be removed in a future release.
//
// If true, then DB::Open, CreateColumnFamily, DropColumnFamily, and
// SetOptions will fail if options file is not properly persisted.
//
// DEFAULT: true
bool fail_if_options_file_error = true;
// If true, then print malloc stats together with rocksdb.stats
// when printing to LOG.
// DEFAULT: false
@@ -1428,10 +1423,9 @@ struct DBOptions {
// prefix_same_as_start=true can take advantage of prefix seek optimizations.
bool prefix_seek_opt_in_only = false;
// The number of bytes to prefetch when reading the DB manifest and WAL files
// during DB::Open (and variants). This is mostly useful for reading a
// remotely located log, as it can save the number of round-trips. If 0, then
// the prefetching is disabled.
// The number of bytes to prefetch when reading the log. This is mostly useful
// for reading a remotely located log, as it can save the number of
// round-trips. If 0, then the prefetching is disabled.
//
// Default: 0
size_t log_readahead_size = 0;
@@ -1709,50 +1703,6 @@ enum ReadTier {
kMemtableTier = 0x3 // data in memtable. used for memtable-only iterators.
};
// A range of keys. In case of user_defined timestamp, if enabled, `start` and
// `limit` should point to key without timestamp part.
struct Range {
Slice start;
Slice limit;
Range() {}
Range(const Slice& s, const Slice& l) : start(s), limit(l) {}
};
// A key range with optional endpoints. In case of user_defined timestamp, if
// enabled, `start` and `limit` should point to key without timestamp part.
struct RangeOpt {
// When start.has_value() == false, refers to starting before every key
OptSlice start;
// When limit.has_value() == false, refers to ending after every key
OptSlice limit;
RangeOpt() {}
RangeOpt(const OptSlice& s, const OptSlice& l) : start(s), limit(l) {}
};
// EXPERIMENTAL
//
// Options for a RocksDB scan request. Only forward scans for now.
// We may add other options such as prefix scan in the future.
struct ScanOptions {
// The scan range. Mandatory for start to be set, limit is optional
RangeOpt range;
// A map of name,value pairs that can be passed by the user to an
// external table reader. This is completely opaque to RocksDB and is
// ignored by the natively supported table readers like block based and plain
// table. This is only useful for Iterator.
std::optional<std::unordered_map<std::string, std::string>> property_bag;
// An unbounded scan with a start key
explicit ScanOptions(const Slice& _start) : range(_start, OptSlice()) {}
// A bounded scan with a start key and upper bound
ScanOptions(const Slice& _start, const Slice& _upper_bound)
: range(_start, _upper_bound) {}
};
// Options that control read operations
struct ReadOptions {
// *** BEGIN options relevant to point lookups as well as scans ***
@@ -1834,10 +1784,6 @@ struct ReadOptions {
// block cache.
bool fill_cache = true;
// DEPRECATED: This option might be removed in a future release.
// There should be no noticeable performance difference whether this option
// is turned on or off when a DB does not use DeleteRange().
//
// If true, range tombstones handling will be skipped in key lookup paths.
// For DB instances that don't use DeleteRange() calls, this setting can
// be used to optimize the read performance.
@@ -2050,6 +1996,22 @@ struct ReadOptions {
// EXPERIMENTAL
Env::IOActivity io_activity = Env::IOActivity::kUnknown;
// EXPERIMENTAL
// An optional weight of values to be returned by a scan. Once the
// weight is reached or exceeded the scan is terminated (i.e Next()
// invalidates the iterator). In the case of a DB with one of the built-in
// table formats, such as BlockBasedTable, the weight is simply the number
// of key-value pairs. In the case of an ExternalTableReader, the weight is
// passed through to the table reader and the interpretation is upto the
// reader implementation.
uint64_t weight = 0;
// A map of name,value pairs that can be passed by the user to an
// external table reader. This is completely opaque to RocksDB and is
// ignored by the natively supported table readers like block based and plain
// table. This is only useful for Iterator.
std::optional<std::unordered_map<std::string, std::string>> property_bag;
// *** END options for RocksDB internal use only ***
ReadOptions() {}
@@ -2283,6 +2245,29 @@ struct CompactRangeOptions {
double blob_garbage_collection_age_cutoff = -1;
};
// A range of keys. In case of user_defined timestamp, if enabled, `start` and
// `limit` should point to key without timestamp part.
struct Range {
Slice start;
Slice limit;
Range() {}
Range(const Slice& s, const Slice& l) : start(s), limit(l) {}
};
// A key range with optional endpoints. In case of user_defined timestamp, if
// enabled, `start` and `limit` should point to key without timestamp part.
struct RangeOpt {
// When start.has_value() == false, refers to starting before every key
OptSlice start;
// When limit.has_value() == false, refers to ending after every key
OptSlice limit;
RangeOpt() {}
RangeOpt(const OptSlice& s, const OptSlice& l) : start(s), limit(l) {}
// RangeOpt(const Slice& s, const Slice& l) : start(s), limit(l) {}
};
// IngestExternalFileOptions is used by IngestExternalFile()
struct IngestExternalFileOptions {
// Can be set to true to move the files instead of copying them.
@@ -2515,16 +2500,10 @@ struct CompactionServiceOptionsOverride {
// to set it here.
std::shared_ptr<Statistics> statistics = nullptr;
// Info Log. If not overriden, default one will be used.
std::shared_ptr<Logger> info_log = nullptr;
// Only compaction generated SST files use this user defined table properties
// collector.
std::vector<std::shared_ptr<TablePropertiesCollectorFactory>>
table_properties_collector_factories;
// All other options to override. Unknown options will be ignored.
std::unordered_map<std::string, std::string> options_map;
};
struct OpenAndCompactOptions {
+3 -8
View File
@@ -520,11 +520,10 @@ enum Tickers : uint32_t {
// Number of bytes prefetched during user initiated scan
PREFETCH_BYTES,
// Number of prefetched bytes that were actually useful during user initiated
// scan
// Number of prefetched bytes that were actually useful
PREFETCH_BYTES_USEFUL,
// Number of FS reads avoided due to prefetching during user initiated scan
// Number of FS reads avoided due to scan prefetching
PREFETCH_HITS,
// Footer corruption detected when opening an SST file for reading
@@ -658,17 +657,13 @@ enum Histograms : uint32_t {
ASYNC_READ_BYTES,
POLL_WAIT_MICROS,
// Number of bytes for RocksDB's prefetching (as opposed to file
// system's prefetch) on SST file during compaction read
COMPACTION_PREFETCH_BYTES,
// Number of prefetched bytes discarded by RocksDB.
PREFETCHED_BYTES_DISCARDED,
// Wait time for aborting async read in FilePrefetchBuffer destructor
ASYNC_PREFETCH_ABORT_MICROS,
// Number of bytes for RocksDB's prefetching contents (as opposed to file
// Number of bytes read for RocksDB's prefetching contents (as opposed to file
// system's prefetch) from the end of SST table during block based table open
TABLE_OPEN_PREFETCH_TAIL_READ_BYTES,
+2 -14
View File
@@ -289,13 +289,6 @@ class StackableDB : public DB {
return db_->NewAttributeGroupIterator(options, column_families);
}
using DB::NewMultiScan;
std::unique_ptr<MultiScan> NewMultiScan(
const ReadOptions& opts, ColumnFamilyHandle* column_family,
const std::vector<ScanOptions>& scan_opts) override {
return db_->NewMultiScan(opts, column_family, scan_opts);
}
const Snapshot* GetSnapshot() override { return db_->GetSnapshot(); }
void ReleaseSnapshot(const Snapshot* snapshot) override {
@@ -512,18 +505,13 @@ class StackableDB : public DB {
return db_->GetFullHistoryTsLow(column_family, ts_low);
}
Status GetNewestUserDefinedTimestamp(ColumnFamilyHandle* column_family,
std::string* newest_timestamp) override {
return db_->GetNewestUserDefinedTimestamp(column_family, newest_timestamp);
}
Status GetSortedWalFiles(VectorWalPtr& files) override {
return db_->GetSortedWalFiles(files);
}
Status GetCurrentWalFile(
std::unique_ptr<WalFile>* current_wal_file) override {
return db_->GetCurrentWalFile(current_wal_file);
std::unique_ptr<WalFile>* current_log_file) override {
return db_->GetCurrentWalFile(current_log_file);
}
Status GetCreationTimeOfOldestFile(uint64_t* creation_time) override {
+3 -12
View File
@@ -24,16 +24,9 @@ class SecondaryIndex;
class TransactionDBMutexFactory;
enum TxnDBWritePolicy {
// Write data at transaction commit time
WRITE_COMMITTED = 0,
// EXPERIMENTAL: The remaining write policies are not as mature, well
// validated, nor as compatible with other features as WRITE_COMMITTED.
// Write data after the prepare phase of 2pc
WRITE_PREPARED,
// Write data before the prepare phase of 2pc
WRITE_UNPREPARED
WRITE_COMMITTED = 0, // write only the committed data
WRITE_PREPARED, // write data after the prepare phase of 2pc
WRITE_UNPREPARED // write data before the prepare phase of 2pc
};
constexpr uint32_t kInitialMaxDeadlocks = 5;
@@ -368,8 +361,6 @@ struct TransactionOptions {
// Only supports write-committed policy. If set to true, the transaction will
// skip memtable write and ingest into the DB directly during Commit(). This
// makes Commit() much faster for transactions with many operations.
// Transaction neeeds to call Prepare() before Commit() for this option to
// take effect.
// Transactions with Merge() or PutEntity() is not supported yet.
//
// Note that the transaction will be ingested as an immutable memtable for
@@ -90,8 +90,6 @@ class WBWIIterator {
// Returns n where the current entry is the n-th update to the current key.
// The update count starts from 1.
// Only valid if WBWI is created with overwrite_key = true.
// With overwrite_key=false, update count for each entry is not maintained,
// see UpdateExistingEntryWithCfId().
virtual uint32_t GetUpdateCount() const { return 0; }
};
@@ -376,6 +374,9 @@ class WriteBatchWithIndex : public WriteBatchBase {
uint32_t entry_count = 0;
uint32_t overwritten_sd_count = 0;
};
// Will track CF ID, per CF entry count and overwritten sd count.
// Should be enabled when WBWI is empty for correct tracking.
void SetTrackPerCFStat(bool track);
const std::unordered_map<uint32_t, CFStat>& GetCFStats() const;
bool GetOverwriteKey() const;
+1 -1
View File
@@ -13,7 +13,7 @@
// minor or major version number planned for release.
#define ROCKSDB_MAJOR 10
#define ROCKSDB_MINOR 2
#define ROCKSDB_PATCH 3
#define ROCKSDB_PATCH 0
// 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
+1 -1
View File
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.11)
cmake_minimum_required(VERSION 3.4)
set(JAVA_JUNIT_VERSION "4.13.1")
set(JAVA_HAMCR_VERSION "2.2")
+91
View File
@@ -2055,6 +2055,29 @@ void Java_org_rocksdb_Options_setWalFilter(JNIEnv*, jclass, jlong jhandle,
opt->wal_filter = wal_filter;
}
/*
* Class: org_rocksdb_Options
* Method: setFailIfOptionsFileError
* Signature: (JZ)V
*/
void Java_org_rocksdb_Options_setFailIfOptionsFileError(
JNIEnv*, jclass, jlong jhandle, jboolean jfail_if_options_file_error) {
auto* opt = reinterpret_cast<ROCKSDB_NAMESPACE::Options*>(jhandle);
opt->fail_if_options_file_error =
static_cast<bool>(jfail_if_options_file_error);
}
/*
* Class: org_rocksdb_Options
* Method: failIfOptionsFileError
* Signature: (J)Z
*/
jboolean Java_org_rocksdb_Options_failIfOptionsFileError(JNIEnv*, jclass,
jlong jhandle) {
auto* opt = reinterpret_cast<ROCKSDB_NAMESPACE::Options*>(jhandle);
return static_cast<jboolean>(opt->fail_if_options_file_error);
}
/*
* Class: org_rocksdb_Options
* Method: setDumpMallocStats
@@ -2433,6 +2456,28 @@ void Java_org_rocksdb_Options_setMinWriteBufferNumberToMerge(
->min_write_buffer_number_to_merge =
static_cast<int>(jmin_write_buffer_number_to_merge);
}
/*
* Class: org_rocksdb_Options
* Method: maxWriteBufferNumberToMaintain
* Signature: (J)I
*/
jint Java_org_rocksdb_Options_maxWriteBufferNumberToMaintain(JNIEnv*, jclass,
jlong jhandle) {
return reinterpret_cast<ROCKSDB_NAMESPACE::Options*>(jhandle)
->max_write_buffer_number_to_maintain;
}
/*
* Class: org_rocksdb_Options
* Method: setMaxWriteBufferNumberToMaintain
* Signature: (JI)V
*/
void Java_org_rocksdb_Options_setMaxWriteBufferNumberToMaintain(
JNIEnv*, jclass, jlong jhandle, jint jmax_write_buffer_number_to_maintain) {
reinterpret_cast<ROCKSDB_NAMESPACE::Options*>(jhandle)
->max_write_buffer_number_to_maintain =
static_cast<int>(jmax_write_buffer_number_to_maintain);
}
/*
* Class: org_rocksdb_Options
@@ -4451,6 +4496,29 @@ void Java_org_rocksdb_ColumnFamilyOptions_setMinWriteBufferNumberToMerge(
static_cast<int>(jmin_write_buffer_number_to_merge);
}
/*
* Class: org_rocksdb_ColumnFamilyOptions
* Method: maxWriteBufferNumberToMaintain
* Signature: (J)I
*/
jint Java_org_rocksdb_ColumnFamilyOptions_maxWriteBufferNumberToMaintain(
JNIEnv*, jclass, jlong jhandle) {
return reinterpret_cast<ROCKSDB_NAMESPACE::ColumnFamilyOptions*>(jhandle)
->max_write_buffer_number_to_maintain;
}
/*
* Class: org_rocksdb_ColumnFamilyOptions
* Method: setMaxWriteBufferNumberToMaintain
* Signature: (JI)V
*/
void Java_org_rocksdb_ColumnFamilyOptions_setMaxWriteBufferNumberToMaintain(
JNIEnv*, jclass, jlong jhandle, jint jmax_write_buffer_number_to_maintain) {
reinterpret_cast<ROCKSDB_NAMESPACE::ColumnFamilyOptions*>(jhandle)
->max_write_buffer_number_to_maintain =
static_cast<int>(jmax_write_buffer_number_to_maintain);
}
/*
* Class: org_rocksdb_ColumnFamilyOptions
* Method: setCompressionType
@@ -7456,6 +7524,29 @@ void Java_org_rocksdb_DBOptions_setWalFilter(JNIEnv*, jclass, jlong jhandle,
opt->wal_filter = wal_filter;
}
/*
* Class: org_rocksdb_DBOptions
* Method: setFailIfOptionsFileError
* Signature: (JZ)V
*/
void Java_org_rocksdb_DBOptions_setFailIfOptionsFileError(
JNIEnv*, jclass, jlong jhandle, jboolean jfail_if_options_file_error) {
auto* opt = reinterpret_cast<ROCKSDB_NAMESPACE::DBOptions*>(jhandle);
opt->fail_if_options_file_error =
static_cast<bool>(jfail_if_options_file_error);
}
/*
* Class: org_rocksdb_DBOptions
* Method: failIfOptionsFileError
* Signature: (J)Z
*/
jboolean Java_org_rocksdb_DBOptions_failIfOptionsFileError(JNIEnv*, jclass,
jlong jhandle) {
auto* opt = reinterpret_cast<ROCKSDB_NAMESPACE::DBOptions*>(jhandle);
return static_cast<jboolean>(opt->fail_if_options_file_error);
}
/*
* Class: org_rocksdb_DBOptions
* Method: setDumpMallocStats
+2 -8
View File
@@ -5889,11 +5889,8 @@ class HistogramTypeJni {
return 0x3C;
case ROCKSDB_NAMESPACE::Histograms::TABLE_OPEN_PREFETCH_TAIL_READ_BYTES:
return 0x3D;
case ROCKSDB_NAMESPACE::Histograms::COMPACTION_PREFETCH_BYTES:
return 0x3F;
case ROCKSDB_NAMESPACE::Histograms::HISTOGRAM_ENUM_MAX:
// 0x3E is reserved for backwards compatibility on current minor
// version.
// 0x3D for backwards compatibility on current minor version.
return 0x3E;
default:
// undefined/default
@@ -6036,11 +6033,8 @@ class HistogramTypeJni {
case 0x3D:
return ROCKSDB_NAMESPACE::Histograms::
TABLE_OPEN_PREFETCH_TAIL_READ_BYTES;
case 0x3F:
return ROCKSDB_NAMESPACE::Histograms::COMPACTION_PREFETCH_BYTES;
case 0x3E:
// 0x3E is reserved for backwards compatibility on current minor
// version.
// 0x1F for backwards compatibility on current minor version.
return ROCKSDB_NAMESPACE::Histograms::HISTOGRAM_ENUM_MAX;
default:
@@ -44,6 +44,53 @@ public interface AdvancedColumnFamilyOptionsInterface<
*/
int minWriteBufferNumberToMerge();
/**
* The total maximum number of write buffers to maintain in memory including
* copies of buffers that have already been flushed. Unlike
* {@link AdvancedMutableColumnFamilyOptionsInterface#maxWriteBufferNumber()},
* this parameter does not affect flushing.
* This controls the minimum amount of write history that will be available
* in memory for conflict checking when Transactions are used.
* <p>
* When using an OptimisticTransactionDB:
* If this value is too low, some transactions may fail at commit time due
* to not being able to determine whether there were any write conflicts.
* <p>
* When using a TransactionDB:
* If Transaction::SetSnapshot is used, TransactionDB will read either
* in-memory write buffers or SST files to do write-conflict checking.
* Increasing this value can reduce the number of reads to SST files
* done for conflict detection.
* <p>
* Setting this value to 0 will cause write buffers to be freed immediately
* after they are flushed.
* If this value is set to -1,
* {@link AdvancedMutableColumnFamilyOptionsInterface#maxWriteBufferNumber()}
* will be used.
* <p>
* Default:
* If using a TransactionDB/OptimisticTransactionDB, the default value will
* be set to the value of
* {@link AdvancedMutableColumnFamilyOptionsInterface#maxWriteBufferNumber()}
* if it is not explicitly set by the user. Otherwise, the default is 0.
*
* @param maxWriteBufferNumberToMaintain The maximum number of write
* buffers to maintain
*
* @return the reference to the current options.
*/
T setMaxWriteBufferNumberToMaintain(
int maxWriteBufferNumberToMaintain);
/**
* The total maximum number of write buffers to maintain in memory including
* copies of buffers that have already been flushed.
*
* @return maxWriteBufferNumberToMaintain The maximum number of write buffers
* to maintain
*/
int maxWriteBufferNumberToMaintain();
/**
* Allows thread-safe inplace updates.
* If inplace_callback function is not set,
@@ -835,6 +835,19 @@ public class ColumnFamilyOptions
return paranoidFileChecks(nativeHandle_);
}
@Override
public ColumnFamilyOptions setMaxWriteBufferNumberToMaintain(
final int maxWriteBufferNumberToMaintain) {
setMaxWriteBufferNumberToMaintain(
nativeHandle_, maxWriteBufferNumberToMaintain);
return this;
}
@Override
public int maxWriteBufferNumberToMaintain() {
return maxWriteBufferNumberToMaintain(nativeHandle_);
}
@Override
public ColumnFamilyOptions setCompactionPriority(
final CompactionPriority compactionPriority) {
@@ -1454,6 +1467,9 @@ public class ColumnFamilyOptions
private static native int[] maxBytesForLevelMultiplierAdditional(long handle);
private static native void setParanoidFileChecks(long handle, boolean paranoidFileChecks);
private static native boolean paranoidFileChecks(long handle);
private static native void setMaxWriteBufferNumberToMaintain(
final long handle, final int maxWriteBufferNumberToMaintain);
private static native int maxWriteBufferNumberToMaintain(final long handle);
private static native void setCompactionPriority(
final long handle, final byte compactionPriority);
private static native byte compactionPriority(final long handle);
@@ -210,9 +210,7 @@ public enum HistogramType {
*/
TABLE_OPEN_PREFETCH_TAIL_READ_BYTES((byte) 0x3D),
COMPACTION_PREFETCH_BYTES((byte) 0x3F),
// 0x3E is reserved for backwards compatibility on current minor version.
// 0x3E for backwards compatibility on current minor version.
HISTOGRAM_ENUM_MAX((byte) 0x3E);
private final byte value;
@@ -1762,6 +1762,19 @@ public class Options extends RocksObject
return paranoidFileChecks(nativeHandle_);
}
@Override
public Options setMaxWriteBufferNumberToMaintain(
final int maxWriteBufferNumberToMaintain) {
setMaxWriteBufferNumberToMaintain(
nativeHandle_, maxWriteBufferNumberToMaintain);
return this;
}
@Override
public int maxWriteBufferNumberToMaintain() {
return maxWriteBufferNumberToMaintain(nativeHandle_);
}
@Override
public Options setCompactionPriority(
final CompactionPriority compactionPriority) {
@@ -2430,6 +2443,9 @@ public class Options extends RocksObject
private static native int[] maxBytesForLevelMultiplierAdditional(long handle);
private static native void setParanoidFileChecks(long handle, boolean paranoidFileChecks);
private static native boolean paranoidFileChecks(long handle);
private static native void setMaxWriteBufferNumberToMaintain(
final long handle, final int maxWriteBufferNumberToMaintain);
private static native int maxWriteBufferNumberToMaintain(final long handle);
private static native void setCompactionPriority(
final long handle, final byte compactionPriority);
private static native byte compactionPriority(final long handle);
@@ -398,10 +398,7 @@ public class ReadOptions extends RocksObject {
* Default: false
*
* @return true if keys deleted using the DeleteRange() API will be visible
*
* @deprecated This option may be remove in a future release.
*/
@Deprecated
public boolean ignoreRangeDeletions() {
assert(isOwningHandle());
return ignoreRangeDeletions(nativeHandle_);
@@ -417,10 +414,7 @@ public class ReadOptions extends RocksObject {
* @param ignoreRangeDeletions true if keys deleted using the DeleteRange()
* API should be visible
* @return the reference to the current ReadOptions.
*
* @deprecated This option may be remove in a future release.
*/
@Deprecated
public ReadOptions setIgnoreRangeDeletions(final boolean ignoreRangeDeletions) {
assert(isOwningHandle());
setIgnoreRangeDeletions(nativeHandle_, ignoreRangeDeletions);
+4 -10
View File
@@ -4126,7 +4126,6 @@ public class RocksDB extends RocksObject {
*
* @return the maximum level
*/
@Deprecated
public int maxMemCompactionLevel() {
return maxMemCompactionLevel(null);
}
@@ -4634,13 +4633,10 @@ public class RocksDB extends RocksObject {
* @param targetLevel the target level for L0
*
* @throws RocksDBException if an error occurs whilst promoting L0
*
* @deprecated this API may be removed in a future release.
*/
@Deprecated
public void promoteL0(
/* @Nullable */ final ColumnFamilyHandle columnFamilyHandle, final int targetLevel)
throws RocksDBException {
/* @Nullable */final ColumnFamilyHandle columnFamilyHandle,
final int targetLevel) throws RocksDBException {
promoteL0(nativeHandle_,
columnFamilyHandle == null ? 0 : columnFamilyHandle.nativeHandle_,
targetLevel);
@@ -4652,11 +4648,9 @@ public class RocksDB extends RocksObject {
* @param targetLevel the target level for L0
*
* @throws RocksDBException if an error occurs whilst promoting L0
*
* @deprecated this API may be removed in a future release.
*/
@Deprecated
public void promoteL0(final int targetLevel) throws RocksDBException {
public void promoteL0(final int targetLevel)
throws RocksDBException {
promoteL0(null, targetLevel);
}
+51 -26
View File
@@ -203,7 +203,7 @@ public class Transaction extends RocksObject {
* Status::Busy() may be returned if the transaction could not guarantee
* that there are no write conflicts. Status::TryAgain() may be returned
* if the memtable history size is not large enough
* (See max_write_buffer_size_to_maintain).
* (See max_write_buffer_number_to_maintain).
* <p>
* If this transaction was created by a {@link TransactionDB},
* Status::Expired() may be returned if this transaction has lived for
@@ -689,7 +689,8 @@ public class Transaction extends RocksObject {
* {@link Status.Code#Busy} if there is a write conflict,
* {@link Status.Code#TimedOut} if a lock could not be acquired,
* {@link Status.Code#TryAgain} if the memtable history size is not large
* enough.
* enough. See
* {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
* {@link Status.Code#MergeInProgress} if merge operations cannot be
* resolved.
*
@@ -769,7 +770,8 @@ public class Transaction extends RocksObject {
* {@link Status.Code#Busy} if there is a write conflict,
* {@link Status.Code#TimedOut} if a lock could not be acquired,
* {@link Status.Code#TryAgain} if the memtable history size is not large
* enough.
* enough. See
* {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
* {@link Status.Code#MergeInProgress} if merge operations cannot be
* resolved.
*
@@ -819,7 +821,8 @@ public class Transaction extends RocksObject {
* {@link Status.Code#Busy} if there is a write conflict,
* {@link Status.Code#TimedOut} if a lock could not be acquired,
* {@link Status.Code#TryAgain} if the memtable history size is not large
* enough.
* enough. See
* {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
* {@link Status.Code#MergeInProgress} if merge operations cannot be
* resolved.
*
@@ -877,7 +880,8 @@ public class Transaction extends RocksObject {
* {@link Status.Code#Busy} if there is a write conflict,
* {@link Status.Code#TimedOut} if a lock could not be acquired,
* {@link Status.Code#TryAgain} if the memtable history size is not large
* enough.
* enough. See
* {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
* {@link Status.Code#MergeInProgress} if merge operations cannot be
* resolved.
*
@@ -929,7 +933,8 @@ public class Transaction extends RocksObject {
* {@link Status.Code#Busy} if there is a write conflict,
* {@link Status.Code#TimedOut} if a lock could not be acquired,
* {@link Status.Code#TryAgain} if the memtable history size is not large
* enough.
* enough. See
* {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
* {@link Status.Code#MergeInProgress} if merge operations cannot be
* resolved.
*
@@ -983,7 +988,8 @@ public class Transaction extends RocksObject {
* {@link Status.Code#Busy} if there is a write conflict,
* {@link Status.Code#TimedOut} if a lock could not be acquired,
* {@link Status.Code#TryAgain} if the memtable history size is not large
* enough.
* enough. See
* {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
* {@link Status.Code#MergeInProgress} if merge operations cannot be
* resolved.
*
@@ -1044,7 +1050,8 @@ public class Transaction extends RocksObject {
* {@link Status.Code#Busy} if there is a write conflict,
* {@link Status.Code#TimedOut} if a lock could not be acquired,
* {@link Status.Code#TryAgain} if the memtable history size is not large
* enough.
* enough. See
* {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
* {@link Status.Code#MergeInProgress} if merge operations cannot be
* resolved.
*
@@ -1099,7 +1106,8 @@ public class Transaction extends RocksObject {
* {@link Status.Code#Busy} if there is a write conflict,
* {@link Status.Code#TimedOut} if a lock could not be acquired,
* {@link Status.Code#TryAgain} if the memtable history size is not large
* enough.
* enough. See
* {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
* {@link Status.Code#MergeInProgress} if merge operations cannot be
* resolved.
*
@@ -1385,7 +1393,8 @@ public class Transaction extends RocksObject {
* {@link Status.Code#Busy} if there is a write conflict,
* {@link Status.Code#TimedOut} if a lock could not be acquired,
* {@link Status.Code#TryAgain} if the memtable history size is not large
* enough.
* enough. See
* {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
*
* @param columnFamilyHandle The column family to put the key/value into
* @param key the specified key to be inserted.
@@ -1421,7 +1430,8 @@ public class Transaction extends RocksObject {
* {@link Status.Code#Busy} if there is a write conflict,
* {@link Status.Code#TimedOut} if a lock could not be acquired,
* {@link Status.Code#TryAgain} if the memtable history size is not large
* enough.
* enough. See
* {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
*
* @param columnFamilyHandle The column family to put the key/value into
* @param key the specified key to be inserted.
@@ -1450,7 +1460,8 @@ public class Transaction extends RocksObject {
* {@link Status.Code#Busy} if there is a write conflict,
* {@link Status.Code#TimedOut} if a lock could not be acquired,
* {@link Status.Code#TryAgain} if the memtable history size is not large
* enough.
* enough. See
* {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
*
* @param key the specified key to be inserted.
* @param value the value associated with the specified key.
@@ -1525,7 +1536,8 @@ public class Transaction extends RocksObject {
* {@link Status.Code#Busy} if there is a write conflict,
* {@link Status.Code#TimedOut} if a lock could not be acquired,
* {@link Status.Code#TryAgain} if the memtable history size is not large
* enough.
* enough. See
* {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
*
* @param key the specified key to be inserted.
* @param value the value associated with the specified key.
@@ -1563,7 +1575,8 @@ public class Transaction extends RocksObject {
* {@link Status.Code#Busy} if there is a write conflict,
* {@link Status.Code#TimedOut} if a lock could not be acquired,
* {@link Status.Code#TryAgain} if the memtable history size is not large
* enough.
* enough. See
* {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
*
* @param columnFamilyHandle The column family to put the key/value into
* @param key the specified key to be inserted.
@@ -1632,7 +1645,8 @@ public class Transaction extends RocksObject {
* {@link Status.Code#Busy} if there is a write conflict,
* {@link Status.Code#TimedOut} if a lock could not be acquired,
* {@link Status.Code#TryAgain} if the memtable history size is not large
* enough.
* enough. See
* {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
*
* @param columnFamilyHandle The column family to merge the key/value into
* @param key the specified key to be merged.
@@ -1669,7 +1683,8 @@ public class Transaction extends RocksObject {
* {@link Status.Code#Busy} if there is a write conflict,
* {@link Status.Code#TimedOut} if a lock could not be acquired,
* {@link Status.Code#TryAgain} if the memtable history size is not large
* enough.
* enough. See
* {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
*
* @param columnFamilyHandle The column family to merge the key/value into
* @param key the specified key to be merged.
@@ -1698,7 +1713,8 @@ public class Transaction extends RocksObject {
* {@link Status.Code#Busy} if there is a write conflict,
* {@link Status.Code#TimedOut} if a lock could not be acquired,
* {@link Status.Code#TryAgain} if the memtable history size is not large
* enough.
* enough. See
* {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
*
* @param key the specified key to be merged.
* @param value the value associated with the specified key.
@@ -1725,7 +1741,8 @@ public class Transaction extends RocksObject {
* {@link Status.Code#Busy} if there is a write conflict,
* {@link Status.Code#TimedOut} if a lock could not be acquired,
* {@link Status.Code#TryAgain} if the memtable history size is not large
* enough.
* enough. See
* {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
*
* @param key the specified key to be merged.
* @param value the value associated with the specified key.
@@ -1761,7 +1778,8 @@ public class Transaction extends RocksObject {
* {@link Status.Code#Busy} if there is a write conflict,
* {@link Status.Code#TimedOut} if a lock could not be acquired,
* {@link Status.Code#TryAgain} if the memtable history size is not large
* enough.
* enough. See
* {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
*
* @param columnFamilyHandle in which to apply the merge
* @param key the specified key to be merged.
@@ -1803,7 +1821,8 @@ public class Transaction extends RocksObject {
* {@link Status.Code#Busy} if there is a write conflict,
* {@link Status.Code#TimedOut} if a lock could not be acquired,
* {@link Status.Code#TryAgain} if the memtable history size is not large
* enough.
* enough. See
* {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
*
* @param columnFamilyHandle in which to apply the merge
* @param key the specified key to be merged.
@@ -1830,7 +1849,8 @@ public class Transaction extends RocksObject {
* {@link Status.Code#Busy} if there is a write conflict,
* {@link Status.Code#TimedOut} if a lock could not be acquired,
* {@link Status.Code#TryAgain} if the memtable history size is not large
* enough.
* enough. See
* {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
*
* @param columnFamilyHandle The column family to delete the key/value from
* @param key the specified key to be deleted.
@@ -1865,7 +1885,8 @@ public class Transaction extends RocksObject {
* {@link Status.Code#Busy} if there is a write conflict,
* {@link Status.Code#TimedOut} if a lock could not be acquired,
* {@link Status.Code#TryAgain} if the memtable history size is not large
* enough.
* enough. See
* {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
*
* @param columnFamilyHandle The column family to delete the key/value from
* @param key the specified key to be deleted.
@@ -1893,7 +1914,8 @@ public class Transaction extends RocksObject {
* {@link Status.Code#Busy} if there is a write conflict,
* {@link Status.Code#TimedOut} if a lock could not be acquired,
* {@link Status.Code#TryAgain} if the memtable history size is not large
* enough.
* enough. See
* {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
*
* @param key the specified key to be deleted.
*
@@ -1979,7 +2001,8 @@ public class Transaction extends RocksObject {
* {@link Status.Code#Busy} if there is a write conflict,
* {@link Status.Code#TimedOut} if a lock could not be acquired,
* {@link Status.Code#TryAgain} if the memtable history size is not large
* enough.
* enough. See
* {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
*
* @param columnFamilyHandle The column family to delete the key/value from
* @param key the specified key to be deleted.
@@ -2015,7 +2038,8 @@ public class Transaction extends RocksObject {
* {@link Status.Code#Busy} if there is a write conflict,
* {@link Status.Code#TimedOut} if a lock could not be acquired,
* {@link Status.Code#TryAgain} if the memtable history size is not large
* enough.
* enough. See
* {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
*
* @param columnFamilyHandle The column family to delete the key/value from
* @param key the specified key to be deleted.
@@ -2044,7 +2068,8 @@ public class Transaction extends RocksObject {
* {@link Status.Code#Busy} if there is a write conflict,
* {@link Status.Code#TimedOut} if a lock could not be acquired,
* {@link Status.Code#TryAgain} if the memtable history size is not large
* enough.
* enough. See
* {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
*
* @param key the specified key to be deleted.
*
@@ -561,6 +561,19 @@ public class ColumnFamilyOptionsTest {
}
}
@Test
public void maxWriteBufferNumberToMaintain() {
try (final ColumnFamilyOptions opt = new ColumnFamilyOptions()) {
int intValue = rand.nextInt();
// Size has to be positive
intValue = (intValue < 0) ? -intValue : intValue;
intValue = (intValue == 0) ? intValue + 1 : intValue;
opt.setMaxWriteBufferNumberToMaintain(intValue);
assertThat(opt.maxWriteBufferNumberToMaintain()).
isEqualTo(intValue);
}
}
@Test
public void compactionPriorities() {
try (final ColumnFamilyOptions opt = new ColumnFamilyOptions()) {
@@ -656,6 +656,15 @@ public class DBOptionsTest {
}
}
@Test
public void failIfOptionsFileError() {
try (final DBOptions opt = new DBOptions()) {
final boolean boolValue = rand.nextBoolean();
opt.setFailIfOptionsFileError(boolValue);
assertThat(opt.failIfOptionsFileError()).isEqualTo(boolValue);
}
}
@Test
public void dumpMallocStats() {
try (final DBOptions opt = new DBOptions()) {
@@ -96,54 +96,30 @@ public class MutableColumnFamilyOptionsTest {
public void mutableColumnFamilyOptions_parse_getOptions_output() {
final String optionsString =
"bottommost_compression=kDisableCompressionOption; sample_for_compression=0; "
+ "blob_garbage_collection_age_cutoff=0.250000; "
+ "blob_garbage_collection_force_threshold=0.800000;"
+ "arena_block_size=1048576; enable_blob_garbage_collection=false; "
+ "level0_stop_writes_trigger=36; min_blob_size=65536;"
+ "blob_compaction_readahead_size=262144; blob_file_starting_level=5; "
+ "prepopulate_blob_cache=kDisable;"
+ "compaction_options_universal={allow_trivial_move=false;stop_style="
+ "kCompactionStopStyleTotalSize;min_merge_width=2;"
+ "compression_size_percent=-1;max_size_amplification_percent=200;max_merge_width="
+ "4294967295;size_ratio=1;}; "
+ "target_file_size_base=67108864; max_bytes_for_level_base=268435456; "
+ "memtable_whole_key_filtering=false; "
+ "soft_pending_compaction_bytes_limit=68719476736; blob_compression_type=kNoCompression; "
+ " max_write_buffer_number=2; "
+ "ttl=2592000; "
+ "compaction_options_fifo={allow_compaction=false;age_for_warm=0;max_table_files_size="
+ "1073741824;}; "
+ "check_flush_compaction_key_order=true; max_successive_merges=0; "
+ "inplace_update_num_locks=10000; "
+ "bottommost_compression_opts={enabled=false;parallel_threads=1;zstd_max_train_bytes=0;"
+ "max_dict_bytes=0;"
+ "blob_garbage_collection_age_cutoff=0.250000; blob_garbage_collection_force_threshold=0.800000;"
+ "arena_block_size=1048576; enable_blob_garbage_collection=false; level0_stop_writes_trigger=36; min_blob_size=65536;"
+ "blob_compaction_readahead_size=262144; blob_file_starting_level=5; prepopulate_blob_cache=kDisable;"
+ "compaction_options_universal={allow_trivial_move=false;stop_style=kCompactionStopStyleTotalSize;min_merge_width=2;"
+ "compression_size_percent=-1;max_size_amplification_percent=200;max_merge_width=4294967295;size_ratio=1;}; "
+ "target_file_size_base=67108864; max_bytes_for_level_base=268435456; memtable_whole_key_filtering=false; "
+ "soft_pending_compaction_bytes_limit=68719476736; blob_compression_type=kNoCompression; max_write_buffer_number=2; "
+ "ttl=2592000; compaction_options_fifo={allow_compaction=false;age_for_warm=0;max_table_files_size=1073741824;}; "
+ "check_flush_compaction_key_order=true; max_successive_merges=0; inplace_update_num_locks=10000; "
+ "bottommost_compression_opts={enabled=false;parallel_threads=1;zstd_max_train_bytes=0;max_dict_bytes=0;"
+ "strategy=0;max_dict_buffer_bytes=0;level=32767;window_bits=-14;}; "
+ "target_file_size_multiplier=1; "
+ "max_bytes_for_level_multiplier_additional=5:{7}:{9}:{11}:{13}:{15}:{17}; "
+ "enable_blob_files=true; level0_slowdown_writes_trigger=20; "
+ "compression=kLZ4HCCompression; level0_file_num_compaction_trigger=4; "
+ "blob_file_size=268435456; prefix_extractor=nullptr; "
+ "max_bytes_for_level_multiplier=10.000000; write_buffer_size=67108864; "
+ "disable_auto_compactions=false; max_compaction_bytes=1677721600; "
+ "memtable_huge_page_size=0; "
+ "compression_opts={enabled=false;parallel_threads=1;zstd_max_train_bytes=0;max_dict_"
+ "bytes=0;strategy=0;max_dict_buffer_bytes=0;"
+ "target_file_size_multiplier=1; max_bytes_for_level_multiplier_additional=5:{7}:{9}:{11}:{13}:{15}:{17}; "
+ "enable_blob_files=true; level0_slowdown_writes_trigger=20; compression=kLZ4HCCompression; level0_file_num_compaction_trigger=4; "
+ "blob_file_size=268435456; prefix_extractor=nullptr; max_bytes_for_level_multiplier=10.000000; write_buffer_size=67108864; "
+ "disable_auto_compactions=false; max_compaction_bytes=1677721600; memtable_huge_page_size=0; "
+ "compression_opts={enabled=false;parallel_threads=1;zstd_max_train_bytes=0;max_dict_bytes=0;strategy=0;max_dict_buffer_bytes=0;"
+ "level=32767;window_bits=-14;}; "
+ "hard_pending_compaction_bytes_limit=274877906944; periodic_compaction_seconds=0; "
+ "paranoid_file_checks=true; "
+ "memtable_prefix_bloom_size_ratio=7.500000; max_sequential_skip_in_iterations=8; "
+ "report_bg_io_stats=true; "
+ "compaction_pri=kMinOverlappingRatio; compaction_style=kCompactionStyleLevel; "
+ "memtable_factory=SkipListFactory; "
+ "comparator=leveldb.BytewiseComparator; bloom_locality=0; "
+ "compaction_filter_factory=nullptr; "
+ "min_write_buffer_number_to_merge=1; compaction_filter=nullptr; "
+ "merge_operator=nullptr; "
+ "num_levels=7; optimize_filters_for_hits=false; force_consistency_checks=true; "
+ "table_factory=BlockBasedTable; "
+ "max_write_buffer_size_to_maintain=0; "
+ "memtable_insert_with_hint_prefix_extractor=nullptr; "
+ "level_compaction_dynamic_level_bytes=false; "
+ "hard_pending_compaction_bytes_limit=274877906944; periodic_compaction_seconds=0; paranoid_file_checks=true; "
+ "memtable_prefix_bloom_size_ratio=7.500000; max_sequential_skip_in_iterations=8; report_bg_io_stats=true; "
+ "compaction_pri=kMinOverlappingRatio; compaction_style=kCompactionStyleLevel; memtable_factory=SkipListFactory; "
+ "comparator=leveldb.BytewiseComparator; bloom_locality=0; compaction_filter_factory=nullptr; "
+ "min_write_buffer_number_to_merge=1; max_write_buffer_number_to_maintain=0; compaction_filter=nullptr; merge_operator=nullptr; "
+ "num_levels=7; optimize_filters_for_hits=false; force_consistency_checks=true; table_factory=BlockBasedTable; "
+ "max_write_buffer_size_to_maintain=0; memtable_insert_with_hint_prefix_extractor=nullptr; level_compaction_dynamic_level_bytes=false; "
+ "inplace_update_support=false; experimental_mempurge_threshold=0.003";
final MutableColumnFamilyOptions.MutableColumnFamilyOptionsBuilder cf =
@@ -902,6 +902,15 @@ public class OptionsTest {
}
}
@Test
public void failIfOptionsFileError() {
try (final Options opt = new Options()) {
final boolean boolValue = rand.nextBoolean();
opt.setFailIfOptionsFileError(boolValue);
assertThat(opt.failIfOptionsFileError()).isEqualTo(boolValue);
}
}
@Test
public void dumpMallocStats() {
try (final Options opt = new Options()) {
@@ -1192,6 +1201,19 @@ public class OptionsTest {
}
}
@Test
public void maxWriteBufferNumberToMaintain() {
try (final Options options = new Options()) {
int intValue = rand.nextInt();
// Size has to be positive
intValue = (intValue < 0) ? -intValue : intValue;
intValue = (intValue == 0) ? intValue + 1 : intValue;
options.setMaxWriteBufferNumberToMaintain(intValue);
assertThat(options.maxWriteBufferNumberToMaintain()).
isEqualTo(intValue);
}
}
@Test
public void compactionPriorities() {
try (final Options options = new Options()) {
@@ -1563,6 +1563,16 @@ public class RocksDBTest {
}
}
@Test
public void maxMemCompactionLevel() throws RocksDBException {
try (final Options options = new Options().setCreateIfMissing(true)) {
final String dbPath = dbFolder.getRoot().getAbsolutePath();
try (final RocksDB db = RocksDB.open(options, dbPath)) {
assertThat(db.maxMemCompactionLevel()).isEqualTo(0);
}
}
}
@Test
public void level0StopWriteTrigger() throws RocksDBException {
try (final Options options = new Options().setCreateIfMissing(true)) {
+1 -1
View File
@@ -235,7 +235,7 @@ class WBWIMemTable final : public ReadOnlyMemTable {
uint64_t num_entries_;
// WBWI can contains updates to multiple CFs. `cf_id_` determines which CF
// this memtable is for.
const uint32_t cf_id_;
uint32_t cf_id_;
};
class WBWIMemTableIterator final : public InternalIterator {
-1
View File
@@ -336,7 +336,6 @@ const std::vector<std::pair<Histograms, std::string>> HistogramsNameMap = {
"rocksdb.error.handler.autoresume.retry.count"},
{ASYNC_READ_BYTES, "rocksdb.async.read.bytes"},
{POLL_WAIT_MICROS, "rocksdb.poll.wait.micros"},
{COMPACTION_PREFETCH_BYTES, "rocksdb.compaction.prefetch.bytes"},
{PREFETCHED_BYTES_DISCARDED, "rocksdb.prefetched.bytes.discarded"},
{ASYNC_PREFETCH_ABORT_MICROS, "rocksdb.async.prefetch.abort.micros"},
{TABLE_OPEN_PREFETCH_TAIL_READ_BYTES,
+1 -1
View File
@@ -616,7 +616,7 @@ TEST_F(StatsHistoryTest, ForceManualFlushStatsCF) {
// LogNumbers: default: 16, stats: 10, pikachu: 5
// Since in recovery process, cfd_stats column is created after WAL is
// created, synced and MANIFEST is persisted, its log number which depends on
// cur_wal_number_ will be different. Since "pikachu" is never flushed, thus
// logfile_number_ will be different. Since "pikachu" is never flushed, thus
// its log_number should be the smallest of the three.
ASSERT_OK(Flush());
ASSERT_LT(cfd_test->GetLogNumber(), cfd_stats->GetLogNumber());
+6 -7
View File
@@ -694,10 +694,7 @@ static std::unordered_map<std::string, OptionTypeInfo>
{offsetof(struct MutableCFOptions, memtable_max_range_deletions),
OptionType::kUInt32T, OptionVerificationType::kNormal,
OptionTypeFlags::kMutable}},
{"memtable_op_scan_flush_trigger",
{offsetof(struct MutableCFOptions, memtable_op_scan_flush_trigger),
OptionType::kUInt32T, OptionVerificationType::kNormal,
OptionTypeFlags::kMutable}},
};
static std::unordered_map<std::string, OptionTypeInfo>
@@ -752,7 +749,9 @@ static std::unordered_map<std::string, OptionTypeInfo>
{0, OptionType::kInt, OptionVerificationType::kDeprecated,
OptionTypeFlags::kNone}},
{"max_write_buffer_number_to_maintain",
{0, OptionType::kInt, OptionVerificationType::kDeprecated,
{offsetof(struct ImmutableCFOptions,
max_write_buffer_number_to_maintain),
OptionType::kInt, OptionVerificationType::kNormal,
OptionTypeFlags::kNone, nullptr}},
{"max_write_buffer_size_to_maintain",
{offsetof(struct ImmutableCFOptions,
@@ -988,6 +987,8 @@ ImmutableCFOptions::ImmutableCFOptions(const ColumnFamilyOptions& cf_options)
compaction_filter_factory(cf_options.compaction_filter_factory),
min_write_buffer_number_to_merge(
cf_options.min_write_buffer_number_to_merge),
max_write_buffer_number_to_maintain(
cf_options.max_write_buffer_number_to_maintain),
max_write_buffer_size_to_maintain(
cf_options.max_write_buffer_size_to_maintain),
inplace_update_support(cf_options.inplace_update_support),
@@ -1179,8 +1180,6 @@ void MutableCFOptions::Dump(Logger* log) const {
bottommost_file_compaction_delay);
ROCKS_LOG_INFO(log, " uncache_aggressiveness: %" PRIu32,
uncache_aggressiveness);
ROCKS_LOG_INFO(log, " memtable_op_scan_flush_trigger: %" PRIu32,
memtable_op_scan_flush_trigger);
// Universal Compaction Options
ROCKS_LOG_INFO(log, "compaction_options_universal.size_ratio : %d",
+4 -5
View File
@@ -40,6 +40,8 @@ struct ImmutableCFOptions {
int min_write_buffer_number_to_merge;
int max_write_buffer_number_to_maintain;
int64_t max_write_buffer_size_to_maintain;
bool inplace_update_support;
@@ -173,8 +175,7 @@ struct MutableCFOptions {
memtable_max_range_deletions(options.memtable_max_range_deletions),
bottommost_file_compaction_delay(
options.bottommost_file_compaction_delay),
uncache_aggressiveness(options.uncache_aggressiveness),
memtable_op_scan_flush_trigger(options.memtable_op_scan_flush_trigger) {
uncache_aggressiveness(options.uncache_aggressiveness) {
RefreshDerivedOptions(options.num_levels, options.compaction_style);
}
@@ -229,8 +230,7 @@ struct MutableCFOptions {
sample_for_compression(0),
memtable_max_range_deletions(0),
bottommost_file_compaction_delay(0),
uncache_aggressiveness(0),
memtable_op_scan_flush_trigger(0) {}
uncache_aggressiveness(0) {}
explicit MutableCFOptions(const Options& options);
@@ -338,7 +338,6 @@ struct MutableCFOptions {
uint32_t memtable_max_range_deletions;
uint32_t bottommost_file_compaction_delay;
uint32_t uncache_aggressiveness;
uint32_t memtable_op_scan_flush_trigger;
// Derived options
// Per-level target file size.
+3 -1
View File
@@ -319,7 +319,8 @@ static std::unordered_map<std::string, OptionTypeInfo>
OptionType::kBoolean, OptionVerificationType::kNormal,
OptionTypeFlags::kNone}},
{"fail_if_options_file_error",
{0, OptionType::kBoolean, OptionVerificationType::kDeprecated,
{offsetof(struct ImmutableDBOptions, fail_if_options_file_error),
OptionType::kBoolean, OptionVerificationType::kNormal,
OptionTypeFlags::kNone}},
{"enable_pipelined_write",
{offsetof(struct ImmutableDBOptions, enable_pipelined_write),
@@ -771,6 +772,7 @@ ImmutableDBOptions::ImmutableDBOptions(const DBOptions& options)
allow_2pc(options.allow_2pc),
row_cache(options.row_cache),
wal_filter(options.wal_filter),
fail_if_options_file_error(options.fail_if_options_file_error),
dump_malloc_stats(options.dump_malloc_stats),
avoid_flush_during_recovery(options.avoid_flush_during_recovery),
allow_ingest_behind(options.allow_ingest_behind),
+1
View File
@@ -77,6 +77,7 @@ struct ImmutableDBOptions {
bool allow_2pc;
std::shared_ptr<Cache> row_cache;
WalFilter* wal_filter;
bool fail_if_options_file_error;
bool dump_malloc_stats;
bool avoid_flush_during_recovery;
bool allow_ingest_behind;
+5 -5
View File
@@ -43,6 +43,8 @@ AdvancedColumnFamilyOptions::AdvancedColumnFamilyOptions(const Options& options)
: max_write_buffer_number(options.max_write_buffer_number),
min_write_buffer_number_to_merge(
options.min_write_buffer_number_to_merge),
max_write_buffer_number_to_maintain(
options.max_write_buffer_number_to_maintain),
max_write_buffer_size_to_maintain(
options.max_write_buffer_size_to_maintain),
inplace_update_support(options.inplace_update_support),
@@ -111,8 +113,7 @@ AdvancedColumnFamilyOptions::AdvancedColumnFamilyOptions(const Options& options)
blob_file_starting_level(options.blob_file_starting_level),
blob_cache(options.blob_cache),
prepopulate_blob_cache(options.prepopulate_blob_cache),
persist_user_defined_timestamps(options.persist_user_defined_timestamps),
memtable_op_scan_flush_trigger(options.memtable_op_scan_flush_trigger) {
persist_user_defined_timestamps(options.persist_user_defined_timestamps) {
assert(memtable_factory.get() != nullptr);
if (max_bytes_for_level_multiplier_additional.size() <
static_cast<unsigned int>(num_levels)) {
@@ -191,6 +192,8 @@ void ColumnFamilyOptions::Dump(Logger* log) const {
ROCKS_LOG_HEADER(log, " Options.num_levels: %d", num_levels);
ROCKS_LOG_HEADER(log, " Options.min_write_buffer_number_to_merge: %d",
min_write_buffer_number_to_merge);
ROCKS_LOG_HEADER(log, " Options.max_write_buffer_number_to_maintain: %d",
max_write_buffer_number_to_maintain);
ROCKS_LOG_HEADER(log,
" Options.max_write_buffer_size_to_maintain: %" PRIu64,
max_write_buffer_size_to_maintain);
@@ -284,9 +287,6 @@ void ColumnFamilyOptions::Dump(Logger* log) const {
ROCKS_LOG_HEADER(log,
" Options.max_sequential_skip_in_iterations: %" PRIu64,
max_sequential_skip_in_iterations);
ROCKS_LOG_HEADER(
log, " Options.memtable_op_scan_flush_trigger: %" PRIu32,
memtable_op_scan_flush_trigger);
ROCKS_LOG_HEADER(log,
" Options.max_compaction_bytes: %" PRIu64,
max_compaction_bytes);
+4 -2
View File
@@ -153,6 +153,8 @@ void BuildDBOptions(const ImmutableDBOptions& immutable_db_options,
options.allow_2pc = immutable_db_options.allow_2pc;
options.row_cache = immutable_db_options.row_cache;
options.wal_filter = immutable_db_options.wal_filter;
options.fail_if_options_file_error =
immutable_db_options.fail_if_options_file_error;
options.dump_malloc_stats = immutable_db_options.dump_malloc_stats;
options.avoid_flush_during_recovery =
immutable_db_options.avoid_flush_during_recovery;
@@ -299,8 +301,6 @@ void UpdateColumnFamilyOptions(const MutableCFOptions& moptions,
cf_opts->default_write_temperature = moptions.default_write_temperature;
cf_opts->memtable_max_range_deletions = moptions.memtable_max_range_deletions;
cf_opts->uncache_aggressiveness = moptions.uncache_aggressiveness;
cf_opts->memtable_op_scan_flush_trigger =
moptions.memtable_op_scan_flush_trigger;
}
void UpdateColumnFamilyOptions(const ImmutableCFOptions& ioptions,
@@ -313,6 +313,8 @@ void UpdateColumnFamilyOptions(const ImmutableCFOptions& ioptions,
cf_opts->compaction_filter_factory = ioptions.compaction_filter_factory;
cf_opts->min_write_buffer_number_to_merge =
ioptions.min_write_buffer_number_to_merge;
cf_opts->max_write_buffer_number_to_maintain =
ioptions.max_write_buffer_number_to_maintain;
cf_opts->max_write_buffer_size_to_maintain =
ioptions.max_write_buffer_size_to_maintain;
cf_opts->inplace_update_support = ioptions.inplace_update_support;
Loaded 100 of 132 files, more files were not shown because too many files have changed in this diff. Show more