| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884 |
- // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
- // This source code is licensed under both the GPLv2 (found in the
- // COPYING file in the root directory) and Apache 2.0 License
- // (found in the LICENSE.Apache file in the root directory).
- //
- // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file. See the AUTHORS file for names of contributors.
- #include "db/db_test_util.h"
- #include "cache/cache_reservation_manager.h"
- #include "db/forward_iterator.h"
- #include "env/fs_readonly.h"
- #include "env/mock_env.h"
- #include "port/lang.h"
- #include "rocksdb/cache.h"
- #include "rocksdb/convenience.h"
- #include "rocksdb/env_encryption.h"
- #include "rocksdb/unique_id.h"
- #include "rocksdb/utilities/object_registry.h"
- #include "table/format.h"
- #include "util/random.h"
- namespace ROCKSDB_NAMESPACE {
- namespace {
- int64_t MaybeCurrentTime(Env* env) {
- int64_t time = 1337346000; // arbitrary fallback default
- env->GetCurrentTime(&time).PermitUncheckedError();
- return time;
- }
- } // anonymous namespace
- // Special Env used to delay background operations
- SpecialEnv::SpecialEnv(Env* base, bool time_elapse_only_sleep)
- : EnvWrapper(base),
- maybe_starting_time_(MaybeCurrentTime(base)),
- rnd_(301),
- sleep_counter_(this),
- time_elapse_only_sleep_(time_elapse_only_sleep),
- no_slowdown_(time_elapse_only_sleep) {
- delay_sstable_sync_.store(false, std::memory_order_release);
- drop_writes_.store(false, std::memory_order_release);
- no_space_.store(false, std::memory_order_release);
- non_writable_.store(false, std::memory_order_release);
- count_random_reads_ = false;
- count_sequential_reads_ = false;
- manifest_sync_error_.store(false, std::memory_order_release);
- manifest_write_error_.store(false, std::memory_order_release);
- log_write_error_.store(false, std::memory_order_release);
- no_file_overwrite_.store(false, std::memory_order_release);
- random_file_open_counter_.store(0, std::memory_order_relaxed);
- delete_count_.store(0, std::memory_order_relaxed);
- num_open_wal_file_.store(0);
- log_write_slowdown_ = 0;
- bytes_written_ = 0;
- sync_counter_ = 0;
- non_writeable_rate_ = 0;
- new_writable_count_ = 0;
- non_writable_count_ = 0;
- table_write_callback_ = nullptr;
- }
- DBTestBase::DBTestBase(const std::string path, bool env_do_fsync)
- : mem_env_(nullptr), encrypted_env_(nullptr), option_config_(kDefault) {
- Env* base_env = Env::Default();
- ConfigOptions config_options;
- EXPECT_OK(test::CreateEnvFromSystem(config_options, &base_env, &env_guard_));
- EXPECT_NE(nullptr, base_env);
- if (getenv("MEM_ENV")) {
- mem_env_ = MockEnv::Create(base_env, base_env->GetSystemClock());
- }
- if (auto ee = getenv("ENCRYPTED_ENV")) {
- std::shared_ptr<EncryptionProvider> provider;
- std::string provider_id = ee;
- if (provider_id.find('=') == std::string::npos &&
- !EndsWith(provider_id, "://test")) {
- provider_id = provider_id + "://test";
- }
- EXPECT_OK(EncryptionProvider::CreateFromString(ConfigOptions(), provider_id,
- &provider));
- encrypted_env_ = NewEncryptedEnv(mem_env_ ? mem_env_ : base_env, provider);
- }
- env_ = new SpecialEnv(encrypted_env_ ? encrypted_env_
- : (mem_env_ ? mem_env_ : base_env));
- env_->SetBackgroundThreads(1, Env::LOW);
- env_->SetBackgroundThreads(1, Env::HIGH);
- env_->skip_fsync_ = !env_do_fsync;
- dbname_ = test::PerThreadDBPath(env_, path);
- alternative_wal_dir_ = dbname_ + "/wal";
- alternative_db_log_dir_ = dbname_ + "/db_log_dir";
- auto options = CurrentOptions();
- options.env = env_;
- auto delete_options = options;
- delete_options.wal_dir = alternative_wal_dir_;
- EXPECT_OK(DestroyDB(dbname_, delete_options));
- // Destroy it for not alternative WAL dir is used.
- EXPECT_OK(DestroyDB(dbname_, options));
- db_ = nullptr;
- Reopen(options);
- Random::GetTLSInstance()->Reset(0xdeadbeef);
- }
- DBTestBase::~DBTestBase() {
- ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
- ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency({});
- ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks();
- Close();
- Options options;
- options.db_paths.emplace_back(dbname_, 0);
- options.db_paths.emplace_back(dbname_ + "_2", 0);
- options.db_paths.emplace_back(dbname_ + "_3", 0);
- options.db_paths.emplace_back(dbname_ + "_4", 0);
- options.env = env_;
- if (getenv("KEEP_DB")) {
- printf("DB is still at %s\n", dbname_.c_str());
- } else {
- EXPECT_OK(DestroyDB(dbname_, options));
- }
- delete env_;
- }
- bool DBTestBase::ShouldSkipOptions(int option_config, int skip_mask) {
- if ((skip_mask & kSkipUniversalCompaction) &&
- (option_config == kUniversalCompaction ||
- option_config == kUniversalCompactionMultiLevel ||
- option_config == kUniversalSubcompactions)) {
- return true;
- }
- if ((skip_mask & kSkipMergePut) && option_config == kMergePut) {
- return true;
- }
- if ((skip_mask & kSkipNoSeekToLast) &&
- (option_config == kHashLinkList || option_config == kHashSkipList)) {
- return true;
- }
- if ((skip_mask & kSkipPlainTable) &&
- (option_config == kPlainTableAllBytesPrefix ||
- option_config == kPlainTableFirstBytePrefix ||
- option_config == kPlainTableCappedPrefix ||
- option_config == kPlainTableCappedPrefixNonMmap)) {
- return true;
- }
- if ((skip_mask & kSkipHashIndex) &&
- (option_config == kBlockBasedTableWithPrefixHashIndex ||
- option_config == kBlockBasedTableWithWholeKeyHashIndex)) {
- return true;
- }
- if ((skip_mask & kSkipFIFOCompaction) && option_config == kFIFOCompaction) {
- return true;
- }
- if ((skip_mask & kSkipMmapReads) && option_config == kWalDirAndMmapReads) {
- return true;
- }
- if ((skip_mask & kSkipRowCache) && option_config == kRowCache) {
- return true;
- }
- return false;
- }
- // Switch to a fresh database with the next option configuration to
- // test. Return false if there are no more configurations to test.
- bool DBTestBase::ChangeOptions(int skip_mask) {
- for (option_config_++; option_config_ < kEnd; option_config_++) {
- if (ShouldSkipOptions(option_config_, skip_mask)) {
- continue;
- }
- break;
- }
- if (option_config_ >= kEnd) {
- Destroy(last_options_);
- return false;
- } else {
- auto options = CurrentOptions();
- options.create_if_missing = true;
- DestroyAndReopen(options);
- return true;
- }
- }
- // Switch between different compaction styles.
- bool DBTestBase::ChangeCompactOptions() {
- if (option_config_ == kDefault) {
- option_config_ = kUniversalCompaction;
- Destroy(last_options_);
- auto options = CurrentOptions();
- options.create_if_missing = true;
- Reopen(options);
- return true;
- } else if (option_config_ == kUniversalCompaction) {
- option_config_ = kUniversalCompactionMultiLevel;
- Destroy(last_options_);
- auto options = CurrentOptions();
- options.create_if_missing = true;
- Reopen(options);
- return true;
- } else if (option_config_ == kUniversalCompactionMultiLevel) {
- option_config_ = kLevelSubcompactions;
- Destroy(last_options_);
- auto options = CurrentOptions();
- assert(options.max_subcompactions > 1);
- Reopen(options);
- return true;
- } else if (option_config_ == kLevelSubcompactions) {
- option_config_ = kUniversalSubcompactions;
- Destroy(last_options_);
- auto options = CurrentOptions();
- assert(options.max_subcompactions > 1);
- Reopen(options);
- return true;
- } else {
- return false;
- }
- }
- // Switch between different WAL settings
- bool DBTestBase::ChangeWalOptions() {
- if (option_config_ == kDefault) {
- option_config_ = kDBLogDir;
- Destroy(last_options_);
- auto options = CurrentOptions();
- Destroy(options);
- options.create_if_missing = true;
- Reopen(options);
- return true;
- } else if (option_config_ == kDBLogDir) {
- option_config_ = kWalDirAndMmapReads;
- Destroy(last_options_);
- auto options = CurrentOptions();
- Destroy(options);
- options.create_if_missing = true;
- Reopen(options);
- return true;
- } else if (option_config_ == kWalDirAndMmapReads) {
- option_config_ = kRecycleLogFiles;
- Destroy(last_options_);
- auto options = CurrentOptions();
- Destroy(options);
- Reopen(options);
- return true;
- } else {
- return false;
- }
- }
- // Switch between different filter policy
- // Jump from kDefault to kFilter to kFullFilter
- bool DBTestBase::ChangeFilterOptions() {
- if (option_config_ == kDefault) {
- option_config_ = kFilter;
- } else if (option_config_ == kFilter) {
- option_config_ = kFullFilterWithNewTableReaderForCompactions;
- } else if (option_config_ == kFullFilterWithNewTableReaderForCompactions) {
- option_config_ = kPartitionedFilterWithNewTableReaderForCompactions;
- } else {
- return false;
- }
- Destroy(last_options_);
- auto options = CurrentOptions();
- options.create_if_missing = true;
- EXPECT_OK(TryReopen(options));
- return true;
- }
- // Switch between different DB options for file ingestion tests.
- bool DBTestBase::ChangeOptionsForFileIngestionTest() {
- if (option_config_ == kDefault) {
- option_config_ = kUniversalCompaction;
- Destroy(last_options_);
- auto options = CurrentOptions();
- options.create_if_missing = true;
- EXPECT_OK(TryReopen(options));
- return true;
- } else if (option_config_ == kUniversalCompaction) {
- option_config_ = kUniversalCompactionMultiLevel;
- Destroy(last_options_);
- auto options = CurrentOptions();
- options.create_if_missing = true;
- EXPECT_OK(TryReopen(options));
- return true;
- } else if (option_config_ == kUniversalCompactionMultiLevel) {
- option_config_ = kLevelSubcompactions;
- Destroy(last_options_);
- auto options = CurrentOptions();
- assert(options.max_subcompactions > 1);
- EXPECT_OK(TryReopen(options));
- return true;
- } else if (option_config_ == kLevelSubcompactions) {
- option_config_ = kUniversalSubcompactions;
- Destroy(last_options_);
- auto options = CurrentOptions();
- assert(options.max_subcompactions > 1);
- EXPECT_OK(TryReopen(options));
- return true;
- } else if (option_config_ == kUniversalSubcompactions) {
- option_config_ = kDirectIO;
- Destroy(last_options_);
- auto options = CurrentOptions();
- EXPECT_OK(TryReopen(options));
- return true;
- } else {
- return false;
- }
- }
- // Return the current option configuration.
- Options DBTestBase::CurrentOptions(
- const anon::OptionsOverride& options_override) const {
- return GetOptions(option_config_, GetDefaultOptions(), options_override);
- }
- Options DBTestBase::CurrentOptions(
- const Options& default_options,
- const anon::OptionsOverride& options_override) const {
- return GetOptions(option_config_, default_options, options_override);
- }
- Options DBTestBase::GetDefaultOptions() const {
- Options options;
- options.write_buffer_size = 4090 * 4096;
- options.target_file_size_base = 2 * 1024 * 1024;
- options.max_bytes_for_level_base = 10 * 1024 * 1024;
- options.max_open_files = 5000;
- options.wal_recovery_mode = WALRecoveryMode::kTolerateCorruptedTailRecords;
- options.compaction_pri = CompactionPri::kByCompensatedSize;
- // The original default value for this option is false,
- // and many unit tests assume this value. It also makes
- // it easier to create desired LSM shape in unit tests.
- // Unit tests for this option sets level_compaction_dynamic_level_bytes=true
- // explicitly.
- options.level_compaction_dynamic_level_bytes = false;
- options.env = env_;
- if (!env_->skip_fsync_) {
- options.track_and_verify_wals_in_manifest = true;
- }
- return options;
- }
- Options DBTestBase::GetOptions(
- int option_config, const Options& default_options,
- const anon::OptionsOverride& options_override) const {
- // this redundant copy is to minimize code change w/o having lint error.
- Options options = default_options;
- BlockBasedTableOptions table_options;
- bool set_block_based_table_factory = true;
- #if !defined(OS_MACOSX) && !defined(OS_WIN) && !defined(OS_SOLARIS) && \
- !defined(OS_AIX)
- ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearCallBack(
- "NewRandomAccessFile:O_DIRECT");
- ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearCallBack(
- "NewWritableFile:O_DIRECT");
- #endif
- // kMustFreeHeapAllocations -> indicates ASAN build
- if (kMustFreeHeapAllocations && !options_override.full_block_cache) {
- // Detecting block cache use-after-free is normally difficult in unit
- // tests, because as a cache, it tends to keep unreferenced entries in
- // memory, and we normally want unit tests to take advantage of block
- // cache for speed. However, we also want a strong chance of detecting
- // block cache use-after-free in unit tests in ASAN builds, so for ASAN
- // builds we use a trivially small block cache to which entries can be
- // added but are immediately freed on no more references.
- table_options.block_cache = NewLRUCache(/* too small */ 1);
- }
- bool can_allow_mmap = IsMemoryMappedAccessSupported();
- switch (option_config) {
- case kHashSkipList:
- options.prefix_extractor.reset(NewFixedPrefixTransform(1));
- options.memtable_factory.reset(NewHashSkipListRepFactory(16));
- options.allow_concurrent_memtable_write = false;
- options.unordered_write = false;
- break;
- case kPlainTableFirstBytePrefix:
- options.table_factory.reset(NewPlainTableFactory());
- options.prefix_extractor.reset(NewFixedPrefixTransform(1));
- options.allow_mmap_reads = can_allow_mmap;
- options.max_sequential_skip_in_iterations = 999999;
- set_block_based_table_factory = false;
- break;
- case kPlainTableCappedPrefix:
- options.table_factory.reset(NewPlainTableFactory());
- options.prefix_extractor.reset(NewCappedPrefixTransform(8));
- options.allow_mmap_reads = can_allow_mmap;
- options.max_sequential_skip_in_iterations = 999999;
- set_block_based_table_factory = false;
- break;
- case kPlainTableCappedPrefixNonMmap:
- options.table_factory.reset(NewPlainTableFactory());
- options.prefix_extractor.reset(NewCappedPrefixTransform(8));
- options.allow_mmap_reads = false;
- options.max_sequential_skip_in_iterations = 999999;
- set_block_based_table_factory = false;
- break;
- case kPlainTableAllBytesPrefix:
- options.table_factory.reset(NewPlainTableFactory());
- options.prefix_extractor.reset(NewNoopTransform());
- options.allow_mmap_reads = can_allow_mmap;
- options.max_sequential_skip_in_iterations = 999999;
- set_block_based_table_factory = false;
- break;
- case kVectorRep:
- options.memtable_factory.reset(new VectorRepFactory(100));
- options.allow_concurrent_memtable_write = false;
- options.unordered_write = false;
- break;
- case kHashLinkList:
- options.prefix_extractor.reset(NewFixedPrefixTransform(1));
- options.memtable_factory.reset(
- NewHashLinkListRepFactory(4, 0, 3, true, 4));
- options.allow_concurrent_memtable_write = false;
- options.unordered_write = false;
- break;
- case kDirectIO: {
- options.use_direct_reads = true;
- options.use_direct_io_for_flush_and_compaction = true;
- options.compaction_readahead_size = 2 * 1024 * 1024;
- SetupSyncPointsToMockDirectIO();
- break;
- }
- case kMergePut:
- options.merge_operator = MergeOperators::CreatePutOperator();
- break;
- case kFilter:
- table_options.filter_policy.reset(NewBloomFilterPolicy(10, true));
- break;
- case kFullFilterWithNewTableReaderForCompactions:
- table_options.filter_policy.reset(NewBloomFilterPolicy(10, false));
- options.compaction_readahead_size = 10 * 1024 * 1024;
- break;
- case kPartitionedFilterWithNewTableReaderForCompactions:
- table_options.filter_policy.reset(NewBloomFilterPolicy(10, false));
- table_options.partition_filters = true;
- table_options.index_type =
- BlockBasedTableOptions::IndexType::kTwoLevelIndexSearch;
- options.compaction_readahead_size = 10 * 1024 * 1024;
- break;
- case kUncompressed:
- options.compression = kNoCompression;
- break;
- case kNumLevel_3:
- options.num_levels = 3;
- break;
- case kDBLogDir:
- options.db_log_dir = alternative_db_log_dir_;
- break;
- case kWalDirAndMmapReads:
- options.wal_dir = alternative_wal_dir_;
- // mmap reads should be orthogonal to WalDir setting, so we piggyback to
- // this option config to test mmap reads as well
- options.allow_mmap_reads = can_allow_mmap;
- break;
- case kManifestFileSize:
- options.max_manifest_file_size = 50; // 50 bytes
- break;
- case kPerfOptions:
- options.delayed_write_rate = 8 * 1024 * 1024;
- options.report_bg_io_stats = true;
- // TODO(3.13) -- test more options
- break;
- case kUniversalCompaction:
- options.compaction_style = kCompactionStyleUniversal;
- options.num_levels = 1;
- break;
- case kUniversalCompactionMultiLevel:
- options.compaction_style = kCompactionStyleUniversal;
- options.num_levels = 8;
- break;
- case kInfiniteMaxOpenFiles:
- options.max_open_files = -1;
- break;
- case kCRC32cChecksum: {
- // Old default was CRC32c, but XXH3 (new default) is faster on common
- // hardware
- table_options.checksum = kCRC32c;
- // Thrown in here for basic coverage:
- options.DisableExtraChecks();
- break;
- }
- case kFIFOCompaction: {
- options.compaction_style = kCompactionStyleFIFO;
- options.max_open_files = -1;
- break;
- }
- case kBlockBasedTableWithPrefixHashIndex: {
- table_options.index_type = BlockBasedTableOptions::kHashSearch;
- options.prefix_extractor.reset(NewFixedPrefixTransform(1));
- break;
- }
- case kBlockBasedTableWithWholeKeyHashIndex: {
- table_options.index_type = BlockBasedTableOptions::kHashSearch;
- options.prefix_extractor.reset(NewNoopTransform());
- break;
- }
- case kBlockBasedTableWithPartitionedIndex: {
- table_options.format_version = 3;
- table_options.index_type = BlockBasedTableOptions::kTwoLevelIndexSearch;
- options.prefix_extractor.reset(NewNoopTransform());
- break;
- }
- case kBlockBasedTableWithPartitionedIndexFormat4: {
- table_options.format_version = 4;
- // Format 4 changes the binary index format. Since partitioned index is a
- // super-set of simple indexes, we are also using kTwoLevelIndexSearch to
- // test this format.
- table_options.index_type = BlockBasedTableOptions::kTwoLevelIndexSearch;
- // The top-level index in partition filters are also affected by format 4.
- table_options.filter_policy.reset(NewBloomFilterPolicy(10, false));
- table_options.partition_filters = true;
- table_options.index_block_restart_interval = 8;
- break;
- }
- case kBlockBasedTableWithIndexRestartInterval: {
- table_options.index_block_restart_interval = 8;
- break;
- }
- case kBlockBasedTableWithLatestFormat: {
- // In case different from default
- table_options.format_version = kLatestFormatVersion;
- break;
- }
- case kOptimizeFiltersForHits: {
- options.optimize_filters_for_hits = true;
- set_block_based_table_factory = true;
- break;
- }
- case kRowCache: {
- options.row_cache = NewLRUCache(1024 * 1024);
- break;
- }
- case kRecycleLogFiles: {
- options.recycle_log_file_num = 2;
- break;
- }
- case kLevelSubcompactions: {
- options.max_subcompactions = 4;
- break;
- }
- case kUniversalSubcompactions: {
- options.compaction_style = kCompactionStyleUniversal;
- options.num_levels = 8;
- options.max_subcompactions = 4;
- break;
- }
- case kConcurrentSkipList: {
- options.allow_concurrent_memtable_write = true;
- options.enable_write_thread_adaptive_yield = true;
- break;
- }
- case kPipelinedWrite: {
- options.enable_pipelined_write = true;
- break;
- }
- case kConcurrentWALWrites: {
- // This options optimize 2PC commit path
- options.two_write_queues = true;
- options.manual_wal_flush = true;
- break;
- }
- case kUnorderedWrite: {
- options.allow_concurrent_memtable_write = false;
- options.unordered_write = false;
- break;
- }
- case kBlockBasedTableWithBinarySearchWithFirstKeyIndex: {
- table_options.index_type =
- BlockBasedTableOptions::kBinarySearchWithFirstKey;
- break;
- }
- default:
- break;
- }
- if (options_override.filter_policy) {
- table_options.filter_policy = options_override.filter_policy;
- table_options.partition_filters = options_override.partition_filters;
- table_options.metadata_block_size = options_override.metadata_block_size;
- }
- if (set_block_based_table_factory) {
- options.table_factory.reset(NewBlockBasedTableFactory(table_options));
- }
- options.level_compaction_dynamic_level_bytes =
- options_override.level_compaction_dynamic_level_bytes;
- options.env = env_;
- options.create_if_missing = true;
- return options;
- }
- void DBTestBase::CreateColumnFamilies(const std::vector<std::string>& cfs,
- const Options& options) {
- ColumnFamilyOptions cf_opts(options);
- size_t cfi = handles_.size();
- handles_.resize(cfi + cfs.size());
- for (const auto& cf : cfs) {
- Status s = db_->CreateColumnFamily(cf_opts, cf, &handles_[cfi++]);
- ASSERT_OK(s);
- }
- }
- void DBTestBase::CreateAndReopenWithCF(const std::vector<std::string>& cfs,
- const Options& options) {
- CreateColumnFamilies(cfs, options);
- std::vector<std::string> cfs_plus_default = cfs;
- cfs_plus_default.insert(cfs_plus_default.begin(), kDefaultColumnFamilyName);
- ReopenWithColumnFamilies(cfs_plus_default, options);
- }
- void DBTestBase::ReopenWithColumnFamilies(const std::vector<std::string>& cfs,
- const std::vector<Options>& options) {
- ASSERT_OK(TryReopenWithColumnFamilies(cfs, options));
- }
- void DBTestBase::ReopenWithColumnFamilies(const std::vector<std::string>& cfs,
- const Options& options) {
- ASSERT_OK(TryReopenWithColumnFamilies(cfs, options));
- }
- void DBTestBase::SetTimeElapseOnlySleepOnReopen(DBOptions* options) {
- time_elapse_only_sleep_on_reopen_ = true;
- // Need to disable stats dumping and persisting which also use
- // RepeatableThread, which uses InstrumentedCondVar::TimedWaitInternal.
- // With time_elapse_only_sleep_, this can hang on some platforms (MacOS)
- // because (a) on some platforms, pthread_cond_timedwait does not appear
- // to release the lock for other threads to operate if the deadline time
- // is already passed, and (b) TimedWait calls are currently a bad abstraction
- // because the deadline parameter is usually computed from Env time,
- // but is interpreted in real clock time.
- options->stats_dump_period_sec = 0;
- options->stats_persist_period_sec = 0;
- }
- void DBTestBase::MaybeInstallTimeElapseOnlySleep(const DBOptions& options) {
- if (time_elapse_only_sleep_on_reopen_) {
- assert(options.env == env_ ||
- static_cast_with_check<CompositeEnvWrapper>(options.env)
- ->env_target() == env_);
- assert(options.stats_dump_period_sec == 0);
- assert(options.stats_persist_period_sec == 0);
- // We cannot set these before destroying the last DB because they might
- // cause a deadlock or similar without the appropriate options set in
- // the DB.
- env_->time_elapse_only_sleep_ = true;
- env_->no_slowdown_ = true;
- } else {
- // Going back in same test run is not yet supported, so no
- // reset in this case.
- }
- }
- Status DBTestBase::TryReopenWithColumnFamilies(
- const std::vector<std::string>& cfs, const std::vector<Options>& options) {
- Close();
- EXPECT_EQ(cfs.size(), options.size());
- std::vector<ColumnFamilyDescriptor> column_families;
- for (size_t i = 0; i < cfs.size(); ++i) {
- column_families.emplace_back(cfs[i], options[i]);
- }
- DBOptions db_opts = DBOptions(options[0]);
- last_options_ = options[0];
- MaybeInstallTimeElapseOnlySleep(db_opts);
- return DB::Open(db_opts, dbname_, column_families, &handles_, &db_);
- }
- Status DBTestBase::TryReopenWithColumnFamilies(
- const std::vector<std::string>& cfs, const Options& options) {
- Close();
- std::vector<Options> v_opts(cfs.size(), options);
- return TryReopenWithColumnFamilies(cfs, v_opts);
- }
- void DBTestBase::Reopen(const Options& options) {
- ASSERT_OK(TryReopen(options));
- }
- void DBTestBase::Close() {
- for (auto h : handles_) {
- EXPECT_OK(db_->DestroyColumnFamilyHandle(h));
- }
- handles_.clear();
- delete db_;
- db_ = nullptr;
- }
- void DBTestBase::DestroyAndReopen(const Options& options) {
- // Destroy using last options
- Destroy(last_options_);
- Reopen(options);
- }
- void DBTestBase::Destroy(const Options& options, bool delete_cf_paths) {
- std::vector<ColumnFamilyDescriptor> column_families;
- if (delete_cf_paths) {
- for (size_t i = 0; i < handles_.size(); ++i) {
- ColumnFamilyDescriptor cfdescriptor;
- handles_[i]->GetDescriptor(&cfdescriptor).PermitUncheckedError();
- column_families.push_back(cfdescriptor);
- }
- }
- Close();
- ASSERT_OK(DestroyDB(dbname_, options, column_families));
- }
- Status DBTestBase::ReadOnlyReopen(const Options& options) {
- Close();
- MaybeInstallTimeElapseOnlySleep(options);
- return DB::OpenForReadOnly(options, dbname_, &db_);
- }
- Status DBTestBase::EnforcedReadOnlyReopen(const Options& options) {
- Close();
- Options options_copy = options;
- MaybeInstallTimeElapseOnlySleep(options_copy);
- auto fs_read_only =
- std::make_shared<ReadOnlyFileSystem>(env_->GetFileSystem());
- env_read_only_ = std::make_shared<CompositeEnvWrapper>(env_, fs_read_only);
- options_copy.env = env_read_only_.get();
- return DB::OpenForReadOnly(options_copy, dbname_, &db_);
- }
- Status DBTestBase::TryReopen(const Options& options) {
- Close();
- last_options_.table_factory.reset();
- // Note: operator= is an unsafe approach here since it destructs
- // std::shared_ptr in the same order of their creation, in contrast to
- // destructors which destructs them in the opposite order of creation. One
- // particular problem is that the cache destructor might invoke callback
- // functions that use Option members such as statistics. To work around this
- // problem, we manually call destructor of table_factory which eventually
- // clears the block cache.
- last_options_ = options;
- MaybeInstallTimeElapseOnlySleep(options);
- return DB::Open(options, dbname_, &db_);
- }
- bool DBTestBase::IsDirectIOSupported() {
- return test::IsDirectIOSupported(env_, dbname_);
- }
- bool DBTestBase::IsMemoryMappedAccessSupported() const {
- return (!encrypted_env_);
- }
- Status DBTestBase::Flush(int cf) {
- if (cf == 0) {
- return db_->Flush(FlushOptions());
- } else {
- return db_->Flush(FlushOptions(), handles_[cf]);
- }
- }
- Status DBTestBase::Flush(const std::vector<int>& cf_ids) {
- std::vector<ColumnFamilyHandle*> cfhs;
- std::for_each(cf_ids.begin(), cf_ids.end(),
- [&cfhs, this](int id) { cfhs.emplace_back(handles_[id]); });
- return db_->Flush(FlushOptions(), cfhs);
- }
- Status DBTestBase::Put(const Slice& k, const Slice& v, WriteOptions wo) {
- if (kMergePut == option_config_) {
- return db_->Merge(wo, k, v);
- } else {
- return db_->Put(wo, k, v);
- }
- }
- Status DBTestBase::Put(int cf, const Slice& k, const Slice& v,
- WriteOptions wo) {
- if (kMergePut == option_config_) {
- return db_->Merge(wo, handles_[cf], k, v);
- } else {
- return db_->Put(wo, handles_[cf], k, v);
- }
- }
- Status DBTestBase::TimedPut(const Slice& k, const Slice& v,
- uint64_t write_unix_time, WriteOptions wo) {
- return TimedPut(0, k, v, write_unix_time, wo);
- }
- Status DBTestBase::TimedPut(int cf, const Slice& k, const Slice& v,
- uint64_t write_unix_time, WriteOptions wo) {
- WriteBatch wb(/*reserved_bytes=*/0, /*max_bytes=*/0,
- wo.protection_bytes_per_key,
- /*default_cf_ts_sz=*/0);
- ColumnFamilyHandle* cfh;
- if (cf != 0) {
- cfh = handles_[cf];
- } else {
- cfh = db_->DefaultColumnFamily();
- }
- EXPECT_OK(wb.TimedPut(cfh, k, v, write_unix_time));
- return db_->Write(wo, &wb);
- }
- Status DBTestBase::Merge(const Slice& k, const Slice& v, WriteOptions wo) {
- return db_->Merge(wo, k, v);
- }
- Status DBTestBase::Merge(int cf, const Slice& k, const Slice& v,
- WriteOptions wo) {
- return db_->Merge(wo, handles_[cf], k, v);
- }
- Status DBTestBase::Delete(const std::string& k) {
- return db_->Delete(WriteOptions(), k);
- }
- Status DBTestBase::Delete(int cf, const std::string& k) {
- return db_->Delete(WriteOptions(), handles_[cf], k);
- }
- Status DBTestBase::SingleDelete(const std::string& k) {
- return db_->SingleDelete(WriteOptions(), k);
- }
- Status DBTestBase::SingleDelete(int cf, const std::string& k) {
- return db_->SingleDelete(WriteOptions(), handles_[cf], k);
- }
- std::string DBTestBase::Get(const std::string& k, const Snapshot* snapshot) {
- ReadOptions options;
- options.verify_checksums = true;
- options.snapshot = snapshot;
- std::string result;
- Status s = db_->Get(options, k, &result);
- if (s.IsNotFound()) {
- result = "NOT_FOUND";
- } else if (!s.ok()) {
- result = s.ToString();
- }
- return result;
- }
- std::string DBTestBase::Get(int cf, const std::string& k,
- const Snapshot* snapshot) {
- ReadOptions options;
- options.verify_checksums = true;
- options.snapshot = snapshot;
- std::string result;
- Status s = db_->Get(options, handles_[cf], k, &result);
- if (s.IsNotFound()) {
- result = "NOT_FOUND";
- } else if (!s.ok()) {
- result = s.ToString();
- }
- return result;
- }
- std::vector<std::string> DBTestBase::MultiGet(std::vector<int> cfs,
- const std::vector<std::string>& k,
- const Snapshot* snapshot,
- const bool batched,
- const bool async) {
- ReadOptions options;
- options.verify_checksums = true;
- options.snapshot = snapshot;
- options.async_io = async;
- std::vector<ColumnFamilyHandle*> handles;
- std::vector<Slice> keys;
- std::vector<std::string> result;
- for (unsigned int i = 0; i < cfs.size(); ++i) {
- handles.push_back(handles_[cfs[i]]);
- keys.emplace_back(k[i]);
- }
- std::vector<Status> s;
- if (!batched) {
- s = db_->MultiGet(options, handles, keys, &result);
- for (size_t i = 0; i < s.size(); ++i) {
- if (s[i].IsNotFound()) {
- result[i] = "NOT_FOUND";
- } else if (!s[i].ok()) {
- result[i] = s[i].ToString();
- }
- }
- } else {
- std::vector<PinnableSlice> pin_values(cfs.size());
- result.resize(cfs.size());
- s.resize(cfs.size());
- db_->MultiGet(options, cfs.size(), handles.data(), keys.data(),
- pin_values.data(), s.data());
- for (size_t i = 0; i < s.size(); ++i) {
- if (s[i].IsNotFound()) {
- result[i] = "NOT_FOUND";
- } else if (!s[i].ok()) {
- result[i] = s[i].ToString();
- } else {
- result[i].assign(pin_values[i].data(), pin_values[i].size());
- // Increase likelihood of detecting potential use-after-free bugs with
- // PinnableSlices tracking the same resource
- pin_values[i].Reset();
- }
- }
- }
- return result;
- }
- std::vector<std::string> DBTestBase::MultiGet(const std::vector<std::string>& k,
- const Snapshot* snapshot,
- const bool async) {
- ReadOptions options;
- options.verify_checksums = true;
- options.snapshot = snapshot;
- options.async_io = async;
- std::vector<Slice> keys;
- std::vector<std::string> result(k.size());
- std::vector<Status> statuses(k.size());
- std::vector<PinnableSlice> pin_values(k.size());
- for (size_t i = 0; i < k.size(); ++i) {
- keys.emplace_back(k[i]);
- }
- db_->MultiGet(options, dbfull()->DefaultColumnFamily(), keys.size(),
- keys.data(), pin_values.data(), statuses.data());
- for (size_t i = 0; i < statuses.size(); ++i) {
- if (statuses[i].IsNotFound()) {
- result[i] = "NOT_FOUND";
- } else if (!statuses[i].ok()) {
- result[i] = statuses[i].ToString();
- } else {
- result[i].assign(pin_values[i].data(), pin_values[i].size());
- // Increase likelihood of detecting potential use-after-free bugs with
- // PinnableSlices tracking the same resource
- pin_values[i].Reset();
- }
- }
- return result;
- }
- Status DBTestBase::Get(const std::string& k, PinnableSlice* v) {
- ReadOptions options;
- options.verify_checksums = true;
- Status s = dbfull()->Get(options, dbfull()->DefaultColumnFamily(), k, v);
- return s;
- }
- Status DBTestBase::CompactRange(const CompactRangeOptions& options,
- std::optional<Slice> begin,
- std::optional<Slice> end) {
- return db_->CompactRange(options, begin ? &begin.value() : nullptr,
- end ? &end.value() : nullptr);
- }
- uint64_t DBTestBase::GetNumSnapshots() {
- uint64_t int_num;
- EXPECT_TRUE(dbfull()->GetIntProperty("rocksdb.num-snapshots", &int_num));
- return int_num;
- }
- uint64_t DBTestBase::GetTimeOldestSnapshots() {
- uint64_t int_num;
- EXPECT_TRUE(
- dbfull()->GetIntProperty("rocksdb.oldest-snapshot-time", &int_num));
- return int_num;
- }
- uint64_t DBTestBase::GetSequenceOldestSnapshots() {
- uint64_t int_num;
- EXPECT_TRUE(
- dbfull()->GetIntProperty("rocksdb.oldest-snapshot-sequence", &int_num));
- return int_num;
- }
- // Return a string that contains all key,value pairs in order,
- // formatted like "(k1->v1)(k2->v2)".
- std::string DBTestBase::Contents(int cf) {
- std::vector<std::string> forward;
- std::string result;
- Iterator* iter = (cf == 0) ? db_->NewIterator(ReadOptions())
- : db_->NewIterator(ReadOptions(), handles_[cf]);
- for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
- std::string s = IterStatus(iter);
- result.push_back('(');
- result.append(s);
- result.push_back(')');
- forward.push_back(s);
- }
- // Check reverse iteration results are the reverse of forward results
- unsigned int matched = 0;
- for (iter->SeekToLast(); iter->Valid(); iter->Prev()) {
- EXPECT_LT(matched, forward.size());
- EXPECT_EQ(IterStatus(iter), forward[forward.size() - matched - 1]);
- matched++;
- }
- EXPECT_OK(iter->status());
- EXPECT_EQ(matched, forward.size());
- delete iter;
- return result;
- }
- void DBTestBase::CheckAllEntriesWithFifoReopen(
- const std::string& expected_value, const Slice& user_key, int cf,
- const std::vector<std::string>& cfs, const Options& options) {
- ASSERT_EQ(AllEntriesFor(user_key, cf), expected_value);
- std::vector<std::string> cfs_plus_default = cfs;
- cfs_plus_default.insert(cfs_plus_default.begin(), kDefaultColumnFamilyName);
- Options fifo_options(options);
- fifo_options.compaction_style = kCompactionStyleFIFO;
- fifo_options.max_open_files = -1;
- fifo_options.disable_auto_compactions = true;
- ASSERT_OK(TryReopenWithColumnFamilies(cfs_plus_default, fifo_options));
- ASSERT_EQ(AllEntriesFor(user_key, cf), expected_value);
- ASSERT_OK(TryReopenWithColumnFamilies(cfs_plus_default, options));
- ASSERT_EQ(AllEntriesFor(user_key, cf), expected_value);
- }
- std::string DBTestBase::AllEntriesFor(const Slice& user_key, int cf) {
- Arena arena;
- auto options = CurrentOptions();
- InternalKeyComparator icmp(options.comparator);
- ReadOptions read_options;
- ScopedArenaPtr<InternalIterator> iter;
- if (cf == 0) {
- iter.reset(dbfull()->NewInternalIterator(read_options, &arena,
- kMaxSequenceNumber));
- } else {
- iter.reset(dbfull()->NewInternalIterator(read_options, &arena,
- kMaxSequenceNumber, handles_[cf]));
- }
- InternalKey target(user_key, kMaxSequenceNumber, kTypeValue);
- iter->Seek(target.Encode());
- std::string result;
- if (!iter->status().ok()) {
- result = iter->status().ToString();
- } else {
- result = "[ ";
- bool first = true;
- while (iter->Valid()) {
- ParsedInternalKey ikey(Slice(), 0, kTypeValue);
- if (ParseInternalKey(iter->key(), &ikey, true /* log_err_key */) !=
- Status::OK()) {
- result += "CORRUPTED";
- } else {
- if (!last_options_.comparator->Equal(ikey.user_key, user_key)) {
- break;
- }
- if (!first) {
- result += ", ";
- }
- first = false;
- switch (ikey.type) {
- case kTypeValue:
- result += iter->value().ToString();
- break;
- case kTypeMerge:
- // keep it the same as kTypeValue for testing kMergePut
- result += iter->value().ToString();
- break;
- case kTypeDeletion:
- result += "DEL";
- break;
- case kTypeSingleDeletion:
- result += "SDEL";
- break;
- default:
- assert(false);
- break;
- }
- }
- iter->Next();
- }
- if (!first) {
- result += " ";
- }
- result += "]";
- }
- return result;
- }
- int DBTestBase::NumSortedRuns(int cf) {
- ColumnFamilyMetaData cf_meta;
- if (cf == 0) {
- db_->GetColumnFamilyMetaData(&cf_meta);
- } else {
- db_->GetColumnFamilyMetaData(handles_[cf], &cf_meta);
- }
- int num_sr = static_cast<int>(cf_meta.levels[0].files.size());
- for (size_t i = 1U; i < cf_meta.levels.size(); i++) {
- if (cf_meta.levels[i].files.size() > 0) {
- num_sr++;
- }
- }
- return num_sr;
- }
- uint64_t DBTestBase::TotalSize(int cf) {
- ColumnFamilyMetaData cf_meta;
- if (cf == 0) {
- db_->GetColumnFamilyMetaData(&cf_meta);
- } else {
- db_->GetColumnFamilyMetaData(handles_[cf], &cf_meta);
- }
- return cf_meta.size;
- }
- uint64_t DBTestBase::SizeAtLevel(int level) {
- std::vector<LiveFileMetaData> metadata;
- db_->GetLiveFilesMetaData(&metadata);
- uint64_t sum = 0;
- for (const auto& m : metadata) {
- if (m.level == level) {
- sum += m.size;
- }
- }
- return sum;
- }
- size_t DBTestBase::TotalLiveFiles(int cf) {
- ColumnFamilyMetaData cf_meta;
- if (cf == 0) {
- db_->GetColumnFamilyMetaData(&cf_meta);
- } else {
- db_->GetColumnFamilyMetaData(handles_[cf], &cf_meta);
- }
- size_t num_files = 0;
- for (auto& level : cf_meta.levels) {
- num_files += level.files.size();
- }
- return num_files;
- }
- size_t DBTestBase::TotalLiveFilesAtPath(int cf, const std::string& path) {
- ColumnFamilyMetaData cf_meta;
- if (cf == 0) {
- db_->GetColumnFamilyMetaData(&cf_meta);
- } else {
- db_->GetColumnFamilyMetaData(handles_[cf], &cf_meta);
- }
- size_t num_files = 0;
- for (auto& level : cf_meta.levels) {
- for (auto& f : level.files) {
- if (f.directory == path) {
- num_files++;
- }
- }
- }
- return num_files;
- }
- size_t DBTestBase::CountLiveFiles() {
- std::vector<LiveFileMetaData> metadata;
- db_->GetLiveFilesMetaData(&metadata);
- return metadata.size();
- }
- int DBTestBase::NumTableFilesAtLevel(int level, int cf) {
- return NumTableFilesAtLevel(level,
- cf ? handles_[cf] : db_->DefaultColumnFamily());
- }
- int DBTestBase::NumTableFilesAtLevel(int level, ColumnFamilyHandle* cfh,
- DB* db) {
- if (!db) {
- db = db_;
- }
- std::string property;
- EXPECT_TRUE(db->GetProperty(
- cfh, "rocksdb.num-files-at-level" + std::to_string(level), &property));
- return atoi(property.c_str());
- }
- double DBTestBase::CompressionRatioAtLevel(int level, int cf) {
- std::string property;
- if (cf == 0) {
- // default cfd
- EXPECT_TRUE(db_->GetProperty(
- "rocksdb.compression-ratio-at-level" + std::to_string(level),
- &property));
- } else {
- EXPECT_TRUE(db_->GetProperty(
- handles_[cf],
- "rocksdb.compression-ratio-at-level" + std::to_string(level),
- &property));
- }
- return std::stod(property);
- }
- int DBTestBase::TotalTableFiles(int cf, int levels) {
- if (levels == -1) {
- levels = (cf == 0) ? db_->NumberLevels() : db_->NumberLevels(handles_[1]);
- }
- int result = 0;
- for (int level = 0; level < levels; level++) {
- result += NumTableFilesAtLevel(level, cf);
- }
- return result;
- }
- // Return spread of files per level
- std::string DBTestBase::FilesPerLevel(int cf) {
- if (cf == 0) {
- return FilesPerLevel(db_->DefaultColumnFamily());
- } else {
- return FilesPerLevel(handles_[cf]);
- }
- }
- std::string DBTestBase::FilesPerLevel(ColumnFamilyHandle* cfh, DB* db) {
- if (!db) {
- db = db_;
- }
- int num_levels = db->NumberLevels(cfh);
- std::string result;
- size_t last_non_zero_offset = 0;
- for (int level = 0; level < num_levels; level++) {
- int f = NumTableFilesAtLevel(level, cfh, db);
- char buf[100];
- snprintf(buf, sizeof(buf), "%s%d", (level ? "," : ""), f);
- result += buf;
- if (f > 0) {
- last_non_zero_offset = result.size();
- }
- }
- result.resize(last_non_zero_offset);
- return result;
- }
- std::vector<uint64_t> DBTestBase::GetBlobFileNumbers() {
- VersionSet* const versions = dbfull()->GetVersionSet();
- assert(versions);
- ColumnFamilyData* const cfd = versions->GetColumnFamilySet()->GetDefault();
- assert(cfd);
- Version* const current = cfd->current();
- assert(current);
- const VersionStorageInfo* const storage_info = current->storage_info();
- assert(storage_info);
- const auto& blob_files = storage_info->GetBlobFiles();
- std::vector<uint64_t> result;
- result.reserve(blob_files.size());
- for (const auto& blob_file : blob_files) {
- assert(blob_file);
- result.emplace_back(blob_file->GetBlobFileNumber());
- }
- return result;
- }
- size_t DBTestBase::CountFiles() {
- size_t count = 0;
- std::vector<std::string> files;
- if (env_->GetChildren(dbname_, &files).ok()) {
- count += files.size();
- }
- if (dbname_ != last_options_.wal_dir) {
- if (env_->GetChildren(last_options_.wal_dir, &files).ok()) {
- count += files.size();
- }
- }
- return count;
- };
- Status DBTestBase::CountFiles(size_t* count) {
- std::vector<std::string> files;
- Status s = env_->GetChildren(dbname_, &files);
- if (!s.ok()) {
- return s;
- }
- size_t files_count = files.size();
- if (dbname_ != last_options_.wal_dir) {
- s = env_->GetChildren(last_options_.wal_dir, &files);
- if (!s.ok()) {
- return s;
- }
- *count = files_count + files.size();
- }
- return Status::OK();
- }
- std::vector<FileMetaData*> DBTestBase::GetLevelFileMetadatas(int level,
- int cf) {
- VersionSet* const versions = dbfull()->GetVersionSet();
- assert(versions);
- ColumnFamilyData* const cfd =
- versions->GetColumnFamilySet()->GetColumnFamily(cf);
- assert(cfd);
- Version* const current = cfd->current();
- assert(current);
- VersionStorageInfo* const storage_info = current->storage_info();
- assert(storage_info);
- return storage_info->LevelFiles(level);
- }
- Status DBTestBase::Size(const Slice& start, const Slice& limit, int cf,
- uint64_t* size) {
- Range r(start, limit);
- if (cf == 0) {
- return db_->GetApproximateSizes(&r, 1, size);
- } else {
- return db_->GetApproximateSizes(handles_[1], &r, 1, size);
- }
- }
- void DBTestBase::Compact(int cf, const Slice& start, const Slice& limit,
- uint32_t target_path_id) {
- CompactRangeOptions compact_options;
- compact_options.target_path_id = target_path_id;
- ASSERT_OK(db_->CompactRange(compact_options, handles_[cf], &start, &limit));
- }
- void DBTestBase::Compact(int cf, const Slice& start, const Slice& limit) {
- ASSERT_OK(
- db_->CompactRange(CompactRangeOptions(), handles_[cf], &start, &limit));
- }
- void DBTestBase::Compact(const Slice& start, const Slice& limit) {
- ASSERT_OK(db_->CompactRange(CompactRangeOptions(), &start, &limit));
- }
- // Do n memtable compactions, each of which produces an sstable
- // covering the range [small,large].
- void DBTestBase::MakeTables(int n, const std::string& small,
- const std::string& large, int cf) {
- for (int i = 0; i < n; i++) {
- ASSERT_OK(Put(cf, small, "begin"));
- ASSERT_OK(Put(cf, large, "end"));
- ASSERT_OK(Flush(cf));
- MoveFilesToLevel(n - i - 1, cf);
- }
- }
- // Prevent pushing of new sstables into deeper levels by adding
- // tables that cover a specified range to all levels.
- void DBTestBase::FillLevels(const std::string& smallest,
- const std::string& largest, int cf) {
- MakeTables(db_->NumberLevels(handles_[cf]), smallest, largest, cf);
- }
- void DBTestBase::MoveFilesToLevel(int level, int cf) {
- MoveFilesToLevel(level, cf ? handles_[cf] : db_->DefaultColumnFamily());
- }
- void DBTestBase::MoveFilesToLevel(int level, ColumnFamilyHandle* column_family,
- DB* db) {
- DBImpl* db_impl = db ? static_cast<DBImpl*>(db) : dbfull();
- for (int l = 0; l < level; ++l) {
- EXPECT_OK(db_impl->TEST_CompactRange(l, nullptr, nullptr, column_family));
- }
- }
- void DBTestBase::DumpFileCounts(const char* label) {
- fprintf(stderr, "---\n%s:\n", label);
- fprintf(stderr, "maxoverlap: %" PRIu64 "\n",
- dbfull()->TEST_MaxNextLevelOverlappingBytes());
- for (int level = 0; level < db_->NumberLevels(); level++) {
- int num = NumTableFilesAtLevel(level);
- if (num > 0) {
- fprintf(stderr, " level %3d : %d files\n", level, num);
- }
- }
- }
- std::string DBTestBase::DumpSSTableList() {
- std::string property;
- db_->GetProperty("rocksdb.sstables", &property);
- return property;
- }
- void DBTestBase::GetSstFiles(Env* env, std::string path,
- std::vector<std::string>* files) {
- EXPECT_OK(env->GetChildren(path, files));
- files->erase(std::remove_if(files->begin(), files->end(),
- [](std::string name) {
- uint64_t number;
- FileType type;
- return !(ParseFileName(name, &number, &type) &&
- type == kTableFile);
- }),
- files->end());
- }
- int DBTestBase::GetSstFileCount(std::string path) {
- std::vector<std::string> files;
- DBTestBase::GetSstFiles(env_, path, &files);
- return static_cast<int>(files.size());
- }
- // this will generate non-overlapping files since it keeps increasing key_idx
- void DBTestBase::GenerateNewFile(int cf, Random* rnd, int* key_idx,
- bool nowait) {
- for (int i = 0; i < KNumKeysByGenerateNewFile; i++) {
- ASSERT_OK(Put(cf, Key(*key_idx), rnd->RandomString((i == 99) ? 1 : 990)));
- (*key_idx)++;
- }
- if (!nowait) {
- ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
- ASSERT_OK(dbfull()->TEST_WaitForCompact());
- }
- }
- // this will generate non-overlapping files since it keeps increasing key_idx
- void DBTestBase::GenerateNewFile(Random* rnd, int* key_idx, bool nowait) {
- for (int i = 0; i < KNumKeysByGenerateNewFile; i++) {
- ASSERT_OK(Put(Key(*key_idx), rnd->RandomString((i == 99) ? 1 : 990)));
- (*key_idx)++;
- }
- if (!nowait) {
- ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
- ASSERT_OK(dbfull()->TEST_WaitForCompact());
- }
- }
- const int DBTestBase::kNumKeysByGenerateNewRandomFile = 51;
- void DBTestBase::GenerateNewRandomFile(Random* rnd, bool nowait) {
- for (int i = 0; i < kNumKeysByGenerateNewRandomFile; i++) {
- ASSERT_OK(Put("key" + rnd->RandomString(7), rnd->RandomString(2000)));
- }
- ASSERT_OK(Put("key" + rnd->RandomString(7), rnd->RandomString(200)));
- if (!nowait) {
- ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
- ASSERT_OK(dbfull()->TEST_WaitForCompact());
- }
- }
- std::string DBTestBase::IterStatus(Iterator* iter) {
- std::string result;
- if (iter->Valid()) {
- result = iter->key().ToString() + "->" + iter->value().ToString();
- } else {
- EXPECT_OK(iter->status());
- result = "(invalid)";
- }
- return result;
- }
- Options DBTestBase::OptionsForLogIterTest() {
- Options options = CurrentOptions();
- options.create_if_missing = true;
- options.WAL_ttl_seconds = 1000;
- return options;
- }
- std::string DBTestBase::DummyString(size_t len, char c) {
- return std::string(len, c);
- }
- void DBTestBase::VerifyIterLast(std::string expected_key, int cf) {
- Iterator* iter;
- ReadOptions ro;
- if (cf == 0) {
- iter = db_->NewIterator(ro);
- } else {
- iter = db_->NewIterator(ro, handles_[cf]);
- }
- iter->SeekToLast();
- ASSERT_EQ(IterStatus(iter), expected_key);
- delete iter;
- }
- // Used to test InplaceUpdate
- // If previous value is nullptr or delta is > than previous value,
- // sets newValue with delta
- // If previous value is not empty,
- // updates previous value with 'b' string of previous value size - 1.
- UpdateStatus DBTestBase::updateInPlaceSmallerSize(char* prevValue,
- uint32_t* prevSize,
- Slice delta,
- std::string* newValue) {
- if (prevValue == nullptr) {
- *newValue = std::string(delta.size(), 'c');
- return UpdateStatus::UPDATED;
- } else {
- *prevSize = *prevSize - 1;
- std::string str_b = std::string(*prevSize, 'b');
- memcpy(prevValue, str_b.c_str(), str_b.size());
- return UpdateStatus::UPDATED_INPLACE;
- }
- }
- UpdateStatus DBTestBase::updateInPlaceSmallerVarintSize(char* prevValue,
- uint32_t* prevSize,
- Slice delta,
- std::string* newValue) {
- if (prevValue == nullptr) {
- *newValue = std::string(delta.size(), 'c');
- return UpdateStatus::UPDATED;
- } else {
- *prevSize = 1;
- std::string str_b = std::string(*prevSize, 'b');
- memcpy(prevValue, str_b.c_str(), str_b.size());
- return UpdateStatus::UPDATED_INPLACE;
- }
- }
- UpdateStatus DBTestBase::updateInPlaceLargerSize(char* /*prevValue*/,
- uint32_t* /*prevSize*/,
- Slice delta,
- std::string* newValue) {
- *newValue = std::string(delta.size(), 'c');
- return UpdateStatus::UPDATED;
- }
- UpdateStatus DBTestBase::updateInPlaceNoAction(char* /*prevValue*/,
- uint32_t* /*prevSize*/,
- Slice /*delta*/,
- std::string* /*newValue*/) {
- return UpdateStatus::UPDATE_FAILED;
- }
- // Utility method to test InplaceUpdate
- void DBTestBase::validateNumberOfEntries(int numValues, int cf) {
- Arena arena;
- auto options = CurrentOptions();
- InternalKeyComparator icmp(options.comparator);
- ReadOptions read_options;
- ScopedArenaPtr<InternalIterator> iter;
- if (cf != 0) {
- iter.reset(dbfull()->NewInternalIterator(read_options, &arena,
- kMaxSequenceNumber, handles_[cf]));
- } else {
- iter.reset(dbfull()->NewInternalIterator(read_options, &arena,
- kMaxSequenceNumber));
- }
- iter->SeekToFirst();
- ASSERT_OK(iter->status());
- int seq = numValues;
- while (iter->Valid()) {
- ParsedInternalKey ikey;
- ikey.clear();
- ASSERT_OK(ParseInternalKey(iter->key(), &ikey, true /* log_err_key */));
- // checks sequence number for updates
- ASSERT_EQ(ikey.sequence, (unsigned)seq--);
- iter->Next();
- }
- ASSERT_EQ(0, seq);
- }
- void DBTestBase::CopyFile(const std::string& source,
- const std::string& destination, uint64_t size) {
- const EnvOptions soptions;
- std::unique_ptr<SequentialFile> srcfile;
- ASSERT_OK(env_->NewSequentialFile(source, &srcfile, soptions));
- std::unique_ptr<WritableFile> destfile;
- ASSERT_OK(env_->NewWritableFile(destination, &destfile, soptions));
- if (size == 0) {
- // default argument means copy everything
- ASSERT_OK(env_->GetFileSize(source, &size));
- }
- char buffer[4096];
- Slice slice;
- while (size > 0) {
- uint64_t one = std::min(uint64_t(sizeof(buffer)), size);
- ASSERT_OK(srcfile->Read(one, &slice, buffer));
- ASSERT_OK(destfile->Append(slice));
- size -= slice.size();
- }
- ASSERT_OK(destfile->Close());
- }
- Status DBTestBase::GetAllDataFiles(
- const FileType file_type, std::unordered_map<std::string, uint64_t>* files,
- uint64_t* total_size /* = nullptr */) {
- if (total_size) {
- *total_size = 0;
- }
- std::vector<std::string> children;
- Status s = env_->GetChildren(dbname_, &children);
- if (s.ok()) {
- for (auto& file_name : children) {
- uint64_t number;
- FileType type;
- if (ParseFileName(file_name, &number, &type) && type == file_type) {
- std::string file_path = dbname_ + "/" + file_name;
- uint64_t file_size = 0;
- s = env_->GetFileSize(file_path, &file_size);
- if (!s.ok()) {
- break;
- }
- (*files)[file_path] = file_size;
- if (total_size) {
- *total_size += file_size;
- }
- }
- }
- }
- return s;
- }
- std::vector<std::uint64_t> DBTestBase::ListTableFiles(Env* env,
- const std::string& path) {
- std::vector<std::string> files;
- std::vector<uint64_t> file_numbers;
- EXPECT_OK(env->GetChildren(path, &files));
- uint64_t number;
- FileType type;
- for (size_t i = 0; i < files.size(); ++i) {
- if (ParseFileName(files[i], &number, &type)) {
- if (type == kTableFile) {
- file_numbers.push_back(number);
- }
- }
- }
- return file_numbers;
- }
- void DBTestBase::VerifyDBFromMap(
- std::map<std::string, std::string> true_data, size_t* total_reads_res,
- bool tailing_iter, ReadOptions* ro, ColumnFamilyHandle* cf,
- std::unordered_set<std::string>* not_found) const {
- ReadOptions temp_ro;
- if (!ro) {
- ro = &temp_ro;
- ro->verify_checksums = true;
- }
- if (!cf) {
- cf = db_->DefaultColumnFamily();
- }
- // Get
- size_t total_reads = 0;
- std::string result;
- for (auto& [k, v] : true_data) {
- ASSERT_OK(db_->Get(*ro, cf, k, &result)) << "key is " << k;
- ASSERT_EQ(v, result);
- total_reads++;
- }
- if (not_found) {
- for (const auto& k : *not_found) {
- ASSERT_TRUE(db_->Get(*ro, cf, k, &result).IsNotFound())
- << "key is " << k << " val is " << result;
- }
- }
- // MultiGet
- std::vector<Slice> key_slice;
- for (const auto& [k, _] : true_data) {
- key_slice.emplace_back(k);
- }
- std::vector<std::string> values;
- std::vector<ColumnFamilyHandle*> cfs(key_slice.size(), cf);
- std::vector<Status> status = db_->MultiGet(*ro, cfs, key_slice, &values);
- total_reads += key_slice.size();
- auto data_iter = true_data.begin();
- for (size_t i = 0; i < key_slice.size(); ++i, ++data_iter) {
- ASSERT_OK(status[i]);
- ASSERT_EQ(values[i], data_iter->second);
- }
- // MultiGet - not found
- if (not_found) {
- key_slice.clear();
- for (const auto& k : *not_found) {
- key_slice.emplace_back(k);
- }
- cfs = std::vector<ColumnFamilyHandle*>(key_slice.size(), cf);
- values.clear();
- status = db_->MultiGet(*ro, cfs, key_slice, &values);
- for (const auto& s : status) {
- ASSERT_TRUE(s.IsNotFound());
- }
- }
- // Normal Iterator
- {
- int iter_cnt = 0;
- ReadOptions ro_ = *ro;
- ro_.total_order_seek = true;
- Iterator* iter = db_->NewIterator(ro_, cf);
- // Verify Iterator::Next()
- iter_cnt = 0;
- data_iter = true_data.begin();
- for (iter->SeekToFirst(); iter->Valid(); iter->Next(), ++data_iter) {
- ASSERT_EQ(iter->key().ToString(), data_iter->first);
- ASSERT_EQ(iter->value().ToString(), data_iter->second);
- iter_cnt++;
- total_reads++;
- }
- ASSERT_OK(iter->status());
- ASSERT_EQ(data_iter, true_data.end())
- << iter_cnt << " / " << true_data.size();
- delete iter;
- // Verify Iterator::Prev()
- // Use a new iterator to make sure its status is clean.
- iter = db_->NewIterator(ro_, cf);
- iter_cnt = 0;
- auto data_rev = true_data.rbegin();
- for (iter->SeekToLast(); iter->Valid(); iter->Prev(), data_rev++) {
- ASSERT_EQ(iter->key().ToString(), data_rev->first);
- ASSERT_EQ(iter->value().ToString(), data_rev->second);
- iter_cnt++;
- total_reads++;
- }
- ASSERT_OK(iter->status());
- ASSERT_EQ(data_rev, true_data.rend())
- << iter_cnt << " / " << true_data.size();
- // Verify Iterator::Seek() and SeekForPrev()
- for (const auto& [k, v] : true_data) {
- for (bool prev : {false, true}) {
- if (prev) {
- iter->SeekForPrev(k);
- } else {
- iter->Seek(k);
- }
- ASSERT_TRUE(iter->Valid());
- ASSERT_OK(iter->status());
- ASSERT_EQ(iter->key(), k);
- ASSERT_EQ(iter->value(), v);
- ++total_reads;
- }
- }
- delete iter;
- }
- if (tailing_iter) {
- // Tailing iterator
- int iter_cnt = 0;
- ReadOptions ro_ = *ro;
- ro_.tailing = true;
- ro_.total_order_seek = true;
- Iterator* iter = db_->NewIterator(ro_, cf);
- // Verify ForwardIterator::Next()
- iter_cnt = 0;
- data_iter = true_data.begin();
- for (iter->SeekToFirst(); iter->Valid(); iter->Next(), data_iter++) {
- ASSERT_EQ(iter->key().ToString(), data_iter->first);
- ASSERT_EQ(iter->value().ToString(), data_iter->second);
- iter_cnt++;
- total_reads++;
- }
- ASSERT_EQ(data_iter, true_data.end())
- << iter_cnt << " / " << true_data.size();
- // Verify ForwardIterator::Seek()
- for (const auto& kv : true_data) {
- iter->Seek(kv.first);
- ASSERT_EQ(kv.first, iter->key().ToString());
- ASSERT_EQ(kv.second, iter->value().ToString());
- total_reads++;
- }
- delete iter;
- }
- if (total_reads_res) {
- *total_reads_res = total_reads;
- }
- }
- void DBTestBase::VerifyDBInternal(
- std::vector<std::pair<std::string, std::string>> true_data) {
- Arena arena;
- InternalKeyComparator icmp(last_options_.comparator);
- ReadOptions read_options;
- auto iter =
- dbfull()->NewInternalIterator(read_options, &arena, kMaxSequenceNumber);
- iter->SeekToFirst();
- for (const auto& p : true_data) {
- ASSERT_TRUE(iter->Valid());
- ParsedInternalKey ikey;
- ASSERT_OK(ParseInternalKey(iter->key(), &ikey, true /* log_err_key */));
- ASSERT_EQ(p.first, ikey.user_key);
- ASSERT_EQ(p.second, iter->value());
- iter->Next();
- };
- ASSERT_FALSE(iter->Valid());
- iter->~InternalIterator();
- }
- uint64_t DBTestBase::GetNumberOfSstFilesForColumnFamily(
- DB* db, std::string column_family_name) {
- std::vector<LiveFileMetaData> metadata;
- db->GetLiveFilesMetaData(&metadata);
- uint64_t result = 0;
- for (auto& fileMetadata : metadata) {
- result += (fileMetadata.column_family_name == column_family_name);
- }
- return result;
- }
- uint64_t DBTestBase::GetSstSizeHelper(Temperature temperature) {
- std::string prop;
- EXPECT_TRUE(dbfull()->GetProperty(
- DB::Properties::kLiveSstFilesSizeAtTemperature +
- std::to_string(static_cast<uint8_t>(temperature)),
- &prop));
- return static_cast<uint64_t>(std::atoi(prop.c_str()));
- }
- void VerifySstUniqueIds(const TablePropertiesCollection& props) {
- ASSERT_FALSE(props.empty()); // suspicious test if empty
- std::unordered_set<std::string> seen;
- for (auto& pair : props) {
- std::string id;
- ASSERT_OK(GetUniqueIdFromTableProperties(*pair.second, &id));
- ASSERT_TRUE(seen.insert(id).second);
- }
- }
- template <CacheEntryRole R>
- TargetCacheChargeTrackingCache<R>::TargetCacheChargeTrackingCache(
- std::shared_ptr<Cache> target)
- : CacheWrapper(std::move(target)),
- cur_cache_charge_(0),
- cache_charge_peak_(0),
- cache_charge_increment_(0),
- last_peak_tracked_(false),
- cache_charge_increments_sum_(0) {}
- template <CacheEntryRole R>
- Status TargetCacheChargeTrackingCache<R>::Insert(
- const Slice& key, ObjectPtr value, const CacheItemHelper* helper,
- size_t charge, Handle** handle, Priority priority, const Slice& compressed,
- CompressionType type) {
- Status s = target_->Insert(key, value, helper, charge, handle, priority,
- compressed, type);
- if (helper == kCrmHelper) {
- if (last_peak_tracked_) {
- cache_charge_peak_ = 0;
- cache_charge_increment_ = 0;
- last_peak_tracked_ = false;
- }
- if (s.ok()) {
- cur_cache_charge_ += charge;
- }
- cache_charge_peak_ = std::max(cache_charge_peak_, cur_cache_charge_);
- cache_charge_increment_ += charge;
- }
- return s;
- }
- template <CacheEntryRole R>
- bool TargetCacheChargeTrackingCache<R>::Release(Handle* handle,
- bool erase_if_last_ref) {
- auto helper = GetCacheItemHelper(handle);
- if (helper == kCrmHelper) {
- if (!last_peak_tracked_) {
- cache_charge_peaks_.push_back(cache_charge_peak_);
- cache_charge_increments_sum_ += cache_charge_increment_;
- last_peak_tracked_ = true;
- }
- cur_cache_charge_ -= GetCharge(handle);
- }
- bool is_successful = target_->Release(handle, erase_if_last_ref);
- return is_successful;
- }
- template <CacheEntryRole R>
- const Cache::CacheItemHelper* TargetCacheChargeTrackingCache<R>::kCrmHelper =
- CacheReservationManagerImpl<R>::TEST_GetCacheItemHelperForRole();
- template class TargetCacheChargeTrackingCache<
- CacheEntryRole::kFilterConstruction>;
- template class TargetCacheChargeTrackingCache<
- CacheEntryRole::kBlockBasedTableReader>;
- template class TargetCacheChargeTrackingCache<CacheEntryRole::kFileMetadata>;
- const std::vector<Temperature> kKnownTemperatures = {
- Temperature::kHot, Temperature::kWarm, Temperature::kCool,
- Temperature::kCold, Temperature::kIce};
- Temperature RandomKnownTemperature() {
- return kKnownTemperatures[Random::GetTLSInstance()->Uniform(
- static_cast<int>(kKnownTemperatures.size()))];
- }
- } // namespace ROCKSDB_NAMESPACE
|