@nxtedition/rocksdb 8.0.1 → 8.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/deps/rocksdb/rocksdb/CMakeLists.txt +2 -1
- package/deps/rocksdb/rocksdb/Makefile +2 -2
- package/deps/rocksdb/rocksdb/TARGETS +4 -2
- package/deps/rocksdb/rocksdb/cache/cache_bench_tool.cc +0 -5
- package/deps/rocksdb/rocksdb/cache/cache_test.cc +8 -29
- package/deps/rocksdb/rocksdb/cache/clock_cache.cc +146 -0
- package/deps/rocksdb/rocksdb/cache/clock_cache.h +13 -1
- package/deps/rocksdb/rocksdb/cache/lru_cache_test.cc +20 -146
- package/deps/rocksdb/rocksdb/cache/secondary_cache.cc +32 -0
- package/deps/rocksdb/rocksdb/db/blob/blob_counting_iterator.h +11 -0
- package/deps/rocksdb/rocksdb/db/column_family.cc +11 -9
- package/deps/rocksdb/rocksdb/db/column_family.h +20 -0
- package/deps/rocksdb/rocksdb/db/compaction/clipping_iterator.h +5 -0
- package/deps/rocksdb/rocksdb/db/compaction/compaction.cc +13 -33
- package/deps/rocksdb/rocksdb/db/compaction/compaction.h +5 -0
- package/deps/rocksdb/rocksdb/db/compaction/compaction_iterator.cc +27 -8
- package/deps/rocksdb/rocksdb/db/compaction/compaction_iterator.h +17 -1
- package/deps/rocksdb/rocksdb/db/compaction/compaction_job.cc +2 -1
- package/deps/rocksdb/rocksdb/db/compaction/compaction_job.h +4 -2
- package/deps/rocksdb/rocksdb/db/compaction/compaction_job_test.cc +8 -6
- package/deps/rocksdb/rocksdb/db/compaction/compaction_outputs.cc +65 -7
- package/deps/rocksdb/rocksdb/db/compaction/compaction_outputs.h +5 -0
- package/deps/rocksdb/rocksdb/db/compaction/compaction_picker.cc +10 -32
- package/deps/rocksdb/rocksdb/db/compaction/compaction_picker.h +28 -47
- package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_fifo.cc +28 -22
- package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_fifo.h +8 -14
- package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_level.cc +8 -8
- package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_level.h +5 -4
- package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_test.cc +170 -140
- package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_universal.cc +5 -1
- package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_universal.h +5 -4
- package/deps/rocksdb/rocksdb/db/compaction/compaction_service_job.cc +8 -2
- package/deps/rocksdb/rocksdb/db/compaction/subcompaction_state.h +8 -0
- package/deps/rocksdb/rocksdb/db/compaction/tiered_compaction_test.cc +266 -138
- package/deps/rocksdb/rocksdb/db/corruption_test.cc +86 -1
- package/deps/rocksdb/rocksdb/db/db_basic_test.cc +72 -5
- package/deps/rocksdb/rocksdb/db/db_block_cache_test.cc +119 -10
- package/deps/rocksdb/rocksdb/db/db_compaction_test.cc +585 -264
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl.cc +46 -18
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl.h +5 -1
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl_compaction_flush.cc +6 -15
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl_debug.cc +1 -1
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl_experimental.cc +1 -1
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl_files.cc +3 -0
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl_open.cc +8 -8
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl_write.cc +10 -0
- package/deps/rocksdb/rocksdb/db/db_range_del_test.cc +250 -2
- package/deps/rocksdb/rocksdb/db/db_test.cc +3 -0
- package/deps/rocksdb/rocksdb/db/db_test2.cc +307 -8
- package/deps/rocksdb/rocksdb/db/db_wal_test.cc +129 -0
- package/deps/rocksdb/rocksdb/db/db_with_timestamp_compaction_test.cc +21 -0
- package/deps/rocksdb/rocksdb/db/dbformat.cc +25 -0
- package/deps/rocksdb/rocksdb/db/dbformat.h +2 -0
- package/deps/rocksdb/rocksdb/db/experimental.cc +1 -1
- package/deps/rocksdb/rocksdb/db/external_sst_file_ingestion_job.cc +5 -2
- package/deps/rocksdb/rocksdb/db/flush_job.cc +5 -2
- package/deps/rocksdb/rocksdb/db/history_trimming_iterator.h +4 -0
- package/deps/rocksdb/rocksdb/db/import_column_family_job.cc +56 -53
- package/deps/rocksdb/rocksdb/db/import_column_family_test.cc +3 -4
- package/deps/rocksdb/rocksdb/db/merge_helper.cc +4 -0
- package/deps/rocksdb/rocksdb/db/periodic_task_scheduler_test.cc +10 -10
- package/deps/rocksdb/rocksdb/db/repair.cc +64 -22
- package/deps/rocksdb/rocksdb/db/repair_test.cc +54 -0
- package/deps/rocksdb/rocksdb/db/seqno_time_test.cc +26 -26
- package/deps/rocksdb/rocksdb/db/table_cache.cc +2 -0
- package/deps/rocksdb/rocksdb/db/table_properties_collector.h +3 -1
- package/deps/rocksdb/rocksdb/db/version_builder.cc +90 -43
- package/deps/rocksdb/rocksdb/db/version_builder.h +20 -0
- package/deps/rocksdb/rocksdb/db/version_builder_test.cc +190 -67
- package/deps/rocksdb/rocksdb/db/version_edit.cc +15 -1
- package/deps/rocksdb/rocksdb/db/version_edit.h +16 -4
- package/deps/rocksdb/rocksdb/db/version_edit_handler.cc +41 -11
- package/deps/rocksdb/rocksdb/db/version_edit_handler.h +27 -12
- package/deps/rocksdb/rocksdb/db/version_edit_test.cc +18 -16
- package/deps/rocksdb/rocksdb/db/version_set.cc +212 -35
- package/deps/rocksdb/rocksdb/db/version_set.h +34 -4
- package/deps/rocksdb/rocksdb/db/version_set_test.cc +45 -25
- package/deps/rocksdb/rocksdb/db/write_thread.cc +5 -2
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_common.h +0 -1
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_gflags.cc +0 -4
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_test_base.cc +12 -17
- package/deps/rocksdb/rocksdb/db_stress_tool/no_batched_ops_stress.cc +6 -4
- package/deps/rocksdb/rocksdb/file/file_prefetch_buffer.h +1 -0
- package/deps/rocksdb/rocksdb/file/prefetch_test.cc +0 -48
- package/deps/rocksdb/rocksdb/file/random_access_file_reader.cc +8 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/cache.h +196 -171
- package/deps/rocksdb/rocksdb/include/rocksdb/db.h +6 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/metadata.h +9 -3
- package/deps/rocksdb/rocksdb/include/rocksdb/options.h +25 -18
- package/deps/rocksdb/rocksdb/include/rocksdb/secondary_cache.h +27 -5
- package/deps/rocksdb/rocksdb/include/rocksdb/statistics.h +5 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/status.h +3 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/version.h +1 -1
- package/deps/rocksdb/rocksdb/logging/logging.h +13 -19
- package/deps/rocksdb/rocksdb/memory/arena.cc +4 -3
- package/deps/rocksdb/rocksdb/memory/arena_test.cc +30 -0
- package/deps/rocksdb/rocksdb/monitoring/statistics.cc +3 -1
- package/deps/rocksdb/rocksdb/monitoring/stats_history_test.cc +26 -26
- package/deps/rocksdb/rocksdb/src.mk +2 -1
- package/deps/rocksdb/rocksdb/table/adaptive/adaptive_table_factory.cc +3 -2
- package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader.cc +3 -2
- package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader_test.cc +1 -1
- package/deps/rocksdb/rocksdb/table/block_fetcher_test.cc +3 -3
- package/deps/rocksdb/rocksdb/table/compaction_merging_iterator.cc +142 -0
- package/deps/rocksdb/rocksdb/table/compaction_merging_iterator.h +241 -0
- package/deps/rocksdb/rocksdb/table/format.cc +24 -20
- package/deps/rocksdb/rocksdb/table/format.h +5 -2
- package/deps/rocksdb/rocksdb/table/merging_iterator.cc +97 -115
- package/deps/rocksdb/rocksdb/table/merging_iterator.h +82 -1
- package/deps/rocksdb/rocksdb/table/meta_blocks.cc +2 -2
- package/deps/rocksdb/rocksdb/table/sst_file_dumper.cc +1 -1
- package/deps/rocksdb/rocksdb/table/table_test.cc +7 -6
- package/deps/rocksdb/rocksdb/test_util/testutil.h +10 -0
- package/deps/rocksdb/rocksdb/tools/db_bench_tool.cc +0 -6
- package/deps/rocksdb/rocksdb/trace_replay/block_cache_tracer.h +2 -2
- package/deps/rocksdb/rocksdb/util/bloom_test.cc +1 -1
- package/deps/rocksdb/rocksdb/util/status.cc +7 -0
- package/deps/rocksdb/rocksdb/utilities/backup/backup_engine.cc +5 -0
- package/deps/rocksdb/rocksdb/utilities/backup/backup_engine_test.cc +4 -0
- package/deps/rocksdb/rocksdb/utilities/cache_dump_load_impl.cc +7 -67
- package/deps/rocksdb/rocksdb/utilities/cache_dump_load_impl.h +1 -3
- package/deps/rocksdb/rocksdb/utilities/checkpoint/checkpoint_impl.cc +1 -0
- package/deps/rocksdb/rocksdb/utilities/transactions/transaction_test.cc +59 -0
- package/deps/rocksdb/rocksdb.gyp +2 -1
- package/package.json +1 -1
- package/prebuilds/darwin-arm64/node.napi.node +0 -0
- package/prebuilds/linux-x64/node.napi.node +0 -0
- package/deps/rocksdb/rocksdb/cache/fast_lru_cache.cc +0 -580
- package/deps/rocksdb/rocksdb/cache/fast_lru_cache.h +0 -476
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
#include "db/db_test_util.h"
|
|
16
16
|
#include "db/read_callback.h"
|
|
17
|
+
#include "db/version_edit.h"
|
|
17
18
|
#include "options/options_helper.h"
|
|
18
19
|
#include "port/port.h"
|
|
19
20
|
#include "port/stack_trace.h"
|
|
@@ -33,6 +34,18 @@ namespace ROCKSDB_NAMESPACE {
|
|
|
33
34
|
class DBTest2 : public DBTestBase {
|
|
34
35
|
public:
|
|
35
36
|
DBTest2() : DBTestBase("db_test2", /*env_do_fsync=*/true) {}
|
|
37
|
+
std::vector<FileMetaData*> GetLevelFileMetadatas(int level, int cf = 0) {
|
|
38
|
+
VersionSet* const versions = dbfull()->GetVersionSet();
|
|
39
|
+
assert(versions);
|
|
40
|
+
ColumnFamilyData* const cfd =
|
|
41
|
+
versions->GetColumnFamilySet()->GetColumnFamily(cf);
|
|
42
|
+
assert(cfd);
|
|
43
|
+
Version* const current = cfd->current();
|
|
44
|
+
assert(current);
|
|
45
|
+
VersionStorageInfo* const storage_info = current->storage_info();
|
|
46
|
+
assert(storage_info);
|
|
47
|
+
return storage_info->LevelFiles(level);
|
|
48
|
+
}
|
|
36
49
|
};
|
|
37
50
|
|
|
38
51
|
#ifndef ROCKSDB_LITE
|
|
@@ -4523,7 +4536,7 @@ TEST_F(DBTest2, TraceAndReplay) {
|
|
|
4523
4536
|
ASSERT_OK(replayer->Prepare());
|
|
4524
4537
|
// Replay using 1 thread, 1x speed.
|
|
4525
4538
|
ASSERT_OK(replayer->Replay(ReplayOptions(1, 1.0), res_cb));
|
|
4526
|
-
|
|
4539
|
+
ASSERT_GE(res_handler.GetAvgLatency(), 0.0);
|
|
4527
4540
|
ASSERT_EQ(res_handler.GetNumWrites(), 8);
|
|
4528
4541
|
ASSERT_EQ(res_handler.GetNumGets(), 3);
|
|
4529
4542
|
ASSERT_EQ(res_handler.GetNumIterSeeks(), 2);
|
|
@@ -4549,7 +4562,7 @@ TEST_F(DBTest2, TraceAndReplay) {
|
|
|
4549
4562
|
// Re-replay using 2 threads, 2x speed.
|
|
4550
4563
|
ASSERT_OK(replayer->Prepare());
|
|
4551
4564
|
ASSERT_OK(replayer->Replay(ReplayOptions(2, 2.0), res_cb));
|
|
4552
|
-
|
|
4565
|
+
ASSERT_GE(res_handler.GetAvgLatency(), 0.0);
|
|
4553
4566
|
ASSERT_EQ(res_handler.GetNumWrites(), 8);
|
|
4554
4567
|
ASSERT_EQ(res_handler.GetNumGets(), 3);
|
|
4555
4568
|
ASSERT_EQ(res_handler.GetNumIterSeeks(), 2);
|
|
@@ -4559,7 +4572,7 @@ TEST_F(DBTest2, TraceAndReplay) {
|
|
|
4559
4572
|
// Re-replay using 2 threads, 1/2 speed.
|
|
4560
4573
|
ASSERT_OK(replayer->Prepare());
|
|
4561
4574
|
ASSERT_OK(replayer->Replay(ReplayOptions(2, 0.5), res_cb));
|
|
4562
|
-
|
|
4575
|
+
ASSERT_GE(res_handler.GetAvgLatency(), 0.0);
|
|
4563
4576
|
ASSERT_EQ(res_handler.GetNumWrites(), 8);
|
|
4564
4577
|
ASSERT_EQ(res_handler.GetNumGets(), 3);
|
|
4565
4578
|
ASSERT_EQ(res_handler.GetNumIterSeeks(), 2);
|
|
@@ -4757,7 +4770,7 @@ TEST_F(DBTest2, TraceAndManualReplay) {
|
|
|
4757
4770
|
// end, or Prepare() was not called.
|
|
4758
4771
|
ASSERT_TRUE(s.IsIncomplete());
|
|
4759
4772
|
ASSERT_TRUE(replayer->Next(nullptr).IsIncomplete());
|
|
4760
|
-
|
|
4773
|
+
ASSERT_GE(res_handler.GetAvgLatency(), 0.0);
|
|
4761
4774
|
ASSERT_EQ(res_handler.GetNumWrites(), 9);
|
|
4762
4775
|
ASSERT_EQ(res_handler.GetNumGets(), 3);
|
|
4763
4776
|
ASSERT_EQ(res_handler.GetNumIterSeeks(), 8);
|
|
@@ -4791,7 +4804,7 @@ TEST_F(DBTest2, TraceAndManualReplay) {
|
|
|
4791
4804
|
ASSERT_EQ("write1", value);
|
|
4792
4805
|
ASSERT_OK(db2->Get(ro, handles[0], "trace-record-write2", &value));
|
|
4793
4806
|
ASSERT_EQ("write2", value);
|
|
4794
|
-
|
|
4807
|
+
ASSERT_GE(res_handler.GetAvgLatency(), 0.0);
|
|
4795
4808
|
ASSERT_EQ(res_handler.GetNumWrites(), 1);
|
|
4796
4809
|
ASSERT_EQ(res_handler.GetNumGets(), 0);
|
|
4797
4810
|
ASSERT_EQ(res_handler.GetNumIterSeeks(), 0);
|
|
@@ -4816,7 +4829,7 @@ TEST_F(DBTest2, TraceAndManualReplay) {
|
|
|
4816
4829
|
record.reset(new GetQueryTraceRecord(invalid_cf_id, "whatever", fake_ts++));
|
|
4817
4830
|
ASSERT_TRUE(replayer->Execute(record, &result).IsCorruption());
|
|
4818
4831
|
ASSERT_TRUE(result == nullptr);
|
|
4819
|
-
|
|
4832
|
+
ASSERT_GE(res_handler.GetAvgLatency(), 0.0);
|
|
4820
4833
|
ASSERT_EQ(res_handler.GetNumWrites(), 0);
|
|
4821
4834
|
ASSERT_EQ(res_handler.GetNumGets(), 2);
|
|
4822
4835
|
ASSERT_EQ(res_handler.GetNumIterSeeks(), 0);
|
|
@@ -4845,7 +4858,7 @@ TEST_F(DBTest2, TraceAndManualReplay) {
|
|
|
4845
4858
|
ASSERT_TRUE(replayer->Execute(record, &result).IsCorruption());
|
|
4846
4859
|
ASSERT_TRUE(result == nullptr);
|
|
4847
4860
|
}
|
|
4848
|
-
|
|
4861
|
+
ASSERT_GE(res_handler.GetAvgLatency(), 0.0);
|
|
4849
4862
|
ASSERT_EQ(res_handler.GetNumWrites(), 0);
|
|
4850
4863
|
ASSERT_EQ(res_handler.GetNumGets(), 0);
|
|
4851
4864
|
ASSERT_EQ(res_handler.GetNumIterSeeks(), 4); // Seek x 2 in two iterations
|
|
@@ -4900,7 +4913,7 @@ TEST_F(DBTest2, TraceAndManualReplay) {
|
|
|
4900
4913
|
std::vector<std::string>({"a"}), fake_ts++));
|
|
4901
4914
|
ASSERT_TRUE(replayer->Execute(record, &result).IsInvalidArgument());
|
|
4902
4915
|
ASSERT_TRUE(result == nullptr);
|
|
4903
|
-
|
|
4916
|
+
ASSERT_GE(res_handler.GetAvgLatency(), 0.0);
|
|
4904
4917
|
ASSERT_EQ(res_handler.GetNumWrites(), 0);
|
|
4905
4918
|
ASSERT_EQ(res_handler.GetNumGets(), 0);
|
|
4906
4919
|
ASSERT_EQ(res_handler.GetNumIterSeeks(), 0);
|
|
@@ -7325,6 +7338,218 @@ TEST_F(DBTest2, PointInTimeRecoveryWithSyncFailureInCFCreation) {
|
|
|
7325
7338
|
ReopenWithColumnFamilies({"default", "test1", "test2"}, options);
|
|
7326
7339
|
}
|
|
7327
7340
|
|
|
7341
|
+
#ifndef ROCKSDB_LITE
|
|
7342
|
+
TEST_F(DBTest2, SortL0FilesByEpochNumber) {
|
|
7343
|
+
Options options = CurrentOptions();
|
|
7344
|
+
options.num_levels = 1;
|
|
7345
|
+
options.compaction_style = kCompactionStyleUniversal;
|
|
7346
|
+
DestroyAndReopen(options);
|
|
7347
|
+
|
|
7348
|
+
// Set up L0 files to be sorted by their epoch_number
|
|
7349
|
+
ASSERT_OK(Put("key1", "seq1"));
|
|
7350
|
+
|
|
7351
|
+
SstFileWriter sst_file_writer{EnvOptions(), options};
|
|
7352
|
+
std::string external_file1 = dbname_ + "/test_files1.sst";
|
|
7353
|
+
std::string external_file2 = dbname_ + "/test_files2.sst";
|
|
7354
|
+
ASSERT_OK(sst_file_writer.Open(external_file1));
|
|
7355
|
+
ASSERT_OK(sst_file_writer.Put("key2", "seq0"));
|
|
7356
|
+
ASSERT_OK(sst_file_writer.Finish());
|
|
7357
|
+
ASSERT_OK(sst_file_writer.Open(external_file2));
|
|
7358
|
+
ASSERT_OK(sst_file_writer.Put("key3", "seq0"));
|
|
7359
|
+
ASSERT_OK(sst_file_writer.Finish());
|
|
7360
|
+
|
|
7361
|
+
ASSERT_OK(Put("key4", "seq2"));
|
|
7362
|
+
ASSERT_OK(Flush());
|
|
7363
|
+
|
|
7364
|
+
auto* handle = db_->DefaultColumnFamily();
|
|
7365
|
+
ASSERT_OK(db_->IngestExternalFile(handle, {external_file1, external_file2},
|
|
7366
|
+
IngestExternalFileOptions()));
|
|
7367
|
+
|
|
7368
|
+
// To verify L0 files are sorted by epoch_number in descending order
|
|
7369
|
+
// instead of largest_seqno
|
|
7370
|
+
std::vector<FileMetaData*> level0_files = GetLevelFileMetadatas(0 /* level*/);
|
|
7371
|
+
ASSERT_EQ(level0_files.size(), 3);
|
|
7372
|
+
|
|
7373
|
+
EXPECT_EQ(level0_files[0]->epoch_number, 3);
|
|
7374
|
+
EXPECT_EQ(level0_files[0]->fd.largest_seqno, 0);
|
|
7375
|
+
ASSERT_EQ(level0_files[0]->num_entries, 1);
|
|
7376
|
+
ASSERT_TRUE(level0_files[0]->largest.user_key() == Slice("key3"));
|
|
7377
|
+
|
|
7378
|
+
EXPECT_EQ(level0_files[1]->epoch_number, 2);
|
|
7379
|
+
EXPECT_EQ(level0_files[1]->fd.largest_seqno, 0);
|
|
7380
|
+
ASSERT_EQ(level0_files[1]->num_entries, 1);
|
|
7381
|
+
ASSERT_TRUE(level0_files[1]->largest.user_key() == Slice("key2"));
|
|
7382
|
+
|
|
7383
|
+
EXPECT_EQ(level0_files[2]->epoch_number, 1);
|
|
7384
|
+
EXPECT_EQ(level0_files[2]->fd.largest_seqno, 2);
|
|
7385
|
+
ASSERT_EQ(level0_files[2]->num_entries, 2);
|
|
7386
|
+
ASSERT_TRUE(level0_files[2]->largest.user_key() == Slice("key4"));
|
|
7387
|
+
ASSERT_TRUE(level0_files[2]->smallest.user_key() == Slice("key1"));
|
|
7388
|
+
|
|
7389
|
+
// To verify compacted file is assigned with the minimum epoch_number
|
|
7390
|
+
// among input files'
|
|
7391
|
+
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
|
7392
|
+
|
|
7393
|
+
level0_files = GetLevelFileMetadatas(0 /* level*/);
|
|
7394
|
+
ASSERT_EQ(level0_files.size(), 1);
|
|
7395
|
+
EXPECT_EQ(level0_files[0]->epoch_number, 1);
|
|
7396
|
+
ASSERT_EQ(level0_files[0]->num_entries, 4);
|
|
7397
|
+
ASSERT_TRUE(level0_files[0]->largest.user_key() == Slice("key4"));
|
|
7398
|
+
ASSERT_TRUE(level0_files[0]->smallest.user_key() == Slice("key1"));
|
|
7399
|
+
}
|
|
7400
|
+
|
|
7401
|
+
TEST_F(DBTest2, SameEpochNumberAfterCompactRangeChangeLevel) {
|
|
7402
|
+
Options options = CurrentOptions();
|
|
7403
|
+
options.num_levels = 7;
|
|
7404
|
+
options.compaction_style = CompactionStyle::kCompactionStyleLevel;
|
|
7405
|
+
options.disable_auto_compactions = true;
|
|
7406
|
+
DestroyAndReopen(options);
|
|
7407
|
+
|
|
7408
|
+
// Set up the file in L1 to be moved to L0 in later step of CompactRange()
|
|
7409
|
+
ASSERT_OK(Put("key1", "seq1"));
|
|
7410
|
+
ASSERT_OK(Flush());
|
|
7411
|
+
MoveFilesToLevel(1, 0);
|
|
7412
|
+
std::vector<FileMetaData*> level0_files = GetLevelFileMetadatas(0 /* level*/);
|
|
7413
|
+
ASSERT_EQ(level0_files.size(), 0);
|
|
7414
|
+
std::vector<FileMetaData*> level1_files = GetLevelFileMetadatas(1 /* level*/);
|
|
7415
|
+
ASSERT_EQ(level1_files.size(), 1);
|
|
7416
|
+
std::vector<FileMetaData*> level2_files = GetLevelFileMetadatas(2 /* level*/);
|
|
7417
|
+
ASSERT_EQ(level2_files.size(), 0);
|
|
7418
|
+
|
|
7419
|
+
ASSERT_EQ(level1_files[0]->epoch_number, 1);
|
|
7420
|
+
|
|
7421
|
+
// To verify CompactRange() moving file to L0 still keeps the file's
|
|
7422
|
+
// epoch_number
|
|
7423
|
+
CompactRangeOptions croptions;
|
|
7424
|
+
croptions.change_level = true;
|
|
7425
|
+
croptions.target_level = 0;
|
|
7426
|
+
ASSERT_OK(db_->CompactRange(croptions, nullptr, nullptr));
|
|
7427
|
+
level0_files = GetLevelFileMetadatas(0 /* level*/);
|
|
7428
|
+
level1_files = GetLevelFileMetadatas(1 /* level*/);
|
|
7429
|
+
ASSERT_EQ(level0_files.size(), 1);
|
|
7430
|
+
ASSERT_EQ(level1_files.size(), 0);
|
|
7431
|
+
|
|
7432
|
+
EXPECT_EQ(level0_files[0]->epoch_number, 1);
|
|
7433
|
+
|
|
7434
|
+
ASSERT_EQ(level0_files[0]->num_entries, 1);
|
|
7435
|
+
ASSERT_TRUE(level0_files[0]->largest.user_key() == Slice("key1"));
|
|
7436
|
+
}
|
|
7437
|
+
|
|
7438
|
+
TEST_F(DBTest2, RecoverEpochNumber) {
|
|
7439
|
+
for (bool allow_ingest_behind : {true, false}) {
|
|
7440
|
+
Options options = CurrentOptions();
|
|
7441
|
+
options.allow_ingest_behind = allow_ingest_behind;
|
|
7442
|
+
options.num_levels = 7;
|
|
7443
|
+
options.compaction_style = kCompactionStyleLevel;
|
|
7444
|
+
options.disable_auto_compactions = true;
|
|
7445
|
+
DestroyAndReopen(options);
|
|
7446
|
+
CreateAndReopenWithCF({"cf1"}, options);
|
|
7447
|
+
VersionSet* versions = dbfull()->GetVersionSet();
|
|
7448
|
+
assert(versions);
|
|
7449
|
+
const ColumnFamilyData* default_cf =
|
|
7450
|
+
versions->GetColumnFamilySet()->GetDefault();
|
|
7451
|
+
const ColumnFamilyData* cf1 =
|
|
7452
|
+
versions->GetColumnFamilySet()->GetColumnFamily("cf1");
|
|
7453
|
+
|
|
7454
|
+
// Set up files in default CF to recover in later step
|
|
7455
|
+
ASSERT_OK(Put("key1", "epoch1"));
|
|
7456
|
+
ASSERT_OK(Flush());
|
|
7457
|
+
MoveFilesToLevel(1 /* level*/, 0 /* cf*/);
|
|
7458
|
+
ASSERT_OK(Put("key2", "epoch2"));
|
|
7459
|
+
ASSERT_OK(Flush());
|
|
7460
|
+
|
|
7461
|
+
std::vector<FileMetaData*> level0_files =
|
|
7462
|
+
GetLevelFileMetadatas(0 /* level*/);
|
|
7463
|
+
ASSERT_EQ(level0_files.size(), 1);
|
|
7464
|
+
ASSERT_EQ(level0_files[0]->epoch_number,
|
|
7465
|
+
allow_ingest_behind
|
|
7466
|
+
? 2 + kReservedEpochNumberForFileIngestedBehind
|
|
7467
|
+
: 2);
|
|
7468
|
+
ASSERT_EQ(level0_files[0]->num_entries, 1);
|
|
7469
|
+
ASSERT_TRUE(level0_files[0]->largest.user_key() == Slice("key2"));
|
|
7470
|
+
|
|
7471
|
+
std::vector<FileMetaData*> level1_files =
|
|
7472
|
+
GetLevelFileMetadatas(1 /* level*/);
|
|
7473
|
+
ASSERT_EQ(level1_files.size(), 1);
|
|
7474
|
+
ASSERT_EQ(level1_files[0]->epoch_number,
|
|
7475
|
+
allow_ingest_behind
|
|
7476
|
+
? 1 + kReservedEpochNumberForFileIngestedBehind
|
|
7477
|
+
: 1);
|
|
7478
|
+
ASSERT_EQ(level1_files[0]->num_entries, 1);
|
|
7479
|
+
ASSERT_TRUE(level1_files[0]->largest.user_key() == Slice("key1"));
|
|
7480
|
+
|
|
7481
|
+
// Set up files in cf1 to recover in later step
|
|
7482
|
+
ASSERT_OK(Put(1 /* cf */, "cf1_key1", "epoch1"));
|
|
7483
|
+
ASSERT_OK(Flush(1 /* cf */));
|
|
7484
|
+
|
|
7485
|
+
std::vector<FileMetaData*> level0_files_cf1 =
|
|
7486
|
+
GetLevelFileMetadatas(0 /* level*/, 1 /* cf*/);
|
|
7487
|
+
ASSERT_EQ(level0_files_cf1.size(), 1);
|
|
7488
|
+
ASSERT_EQ(level0_files_cf1[0]->epoch_number,
|
|
7489
|
+
allow_ingest_behind
|
|
7490
|
+
? 1 + kReservedEpochNumberForFileIngestedBehind
|
|
7491
|
+
: 1);
|
|
7492
|
+
ASSERT_EQ(level0_files_cf1[0]->num_entries, 1);
|
|
7493
|
+
ASSERT_TRUE(level0_files_cf1[0]->largest.user_key() == Slice("cf1_key1"));
|
|
7494
|
+
|
|
7495
|
+
ASSERT_EQ(default_cf->GetNextEpochNumber(),
|
|
7496
|
+
allow_ingest_behind
|
|
7497
|
+
? 3 + kReservedEpochNumberForFileIngestedBehind
|
|
7498
|
+
: 3);
|
|
7499
|
+
ASSERT_EQ(cf1->GetNextEpochNumber(),
|
|
7500
|
+
allow_ingest_behind
|
|
7501
|
+
? 2 + kReservedEpochNumberForFileIngestedBehind
|
|
7502
|
+
: 2);
|
|
7503
|
+
|
|
7504
|
+
// To verify epoch_number of files of different levels/CFs are
|
|
7505
|
+
// persisted and recovered correctly
|
|
7506
|
+
ReopenWithColumnFamilies({"default", "cf1"}, options);
|
|
7507
|
+
versions = dbfull()->GetVersionSet();
|
|
7508
|
+
assert(versions);
|
|
7509
|
+
default_cf = versions->GetColumnFamilySet()->GetDefault();
|
|
7510
|
+
cf1 = versions->GetColumnFamilySet()->GetColumnFamily("cf1");
|
|
7511
|
+
|
|
7512
|
+
level0_files = GetLevelFileMetadatas(0 /* level*/);
|
|
7513
|
+
ASSERT_EQ(level0_files.size(), 1);
|
|
7514
|
+
EXPECT_EQ(level0_files[0]->epoch_number,
|
|
7515
|
+
allow_ingest_behind
|
|
7516
|
+
? 2 + kReservedEpochNumberForFileIngestedBehind
|
|
7517
|
+
: 2);
|
|
7518
|
+
ASSERT_EQ(level0_files[0]->num_entries, 1);
|
|
7519
|
+
ASSERT_TRUE(level0_files[0]->largest.user_key() == Slice("key2"));
|
|
7520
|
+
|
|
7521
|
+
level1_files = GetLevelFileMetadatas(1 /* level*/);
|
|
7522
|
+
ASSERT_EQ(level1_files.size(), 1);
|
|
7523
|
+
EXPECT_EQ(level1_files[0]->epoch_number,
|
|
7524
|
+
allow_ingest_behind
|
|
7525
|
+
? 1 + kReservedEpochNumberForFileIngestedBehind
|
|
7526
|
+
: 1);
|
|
7527
|
+
ASSERT_EQ(level1_files[0]->num_entries, 1);
|
|
7528
|
+
ASSERT_TRUE(level1_files[0]->largest.user_key() == Slice("key1"));
|
|
7529
|
+
|
|
7530
|
+
level0_files_cf1 = GetLevelFileMetadatas(0 /* level*/, 1 /* cf*/);
|
|
7531
|
+
ASSERT_EQ(level0_files_cf1.size(), 1);
|
|
7532
|
+
EXPECT_EQ(level0_files_cf1[0]->epoch_number,
|
|
7533
|
+
allow_ingest_behind
|
|
7534
|
+
? 1 + kReservedEpochNumberForFileIngestedBehind
|
|
7535
|
+
: 1);
|
|
7536
|
+
ASSERT_EQ(level0_files_cf1[0]->num_entries, 1);
|
|
7537
|
+
ASSERT_TRUE(level0_files_cf1[0]->largest.user_key() == Slice("cf1_key1"));
|
|
7538
|
+
|
|
7539
|
+
// To verify next epoch number is recovered correctly
|
|
7540
|
+
EXPECT_EQ(default_cf->GetNextEpochNumber(),
|
|
7541
|
+
allow_ingest_behind
|
|
7542
|
+
? 3 + kReservedEpochNumberForFileIngestedBehind
|
|
7543
|
+
: 3);
|
|
7544
|
+
EXPECT_EQ(cf1->GetNextEpochNumber(),
|
|
7545
|
+
allow_ingest_behind
|
|
7546
|
+
? 2 + kReservedEpochNumberForFileIngestedBehind
|
|
7547
|
+
: 2);
|
|
7548
|
+
}
|
|
7549
|
+
}
|
|
7550
|
+
|
|
7551
|
+
#endif // ROCKSDB_LITE
|
|
7552
|
+
|
|
7328
7553
|
TEST_F(DBTest2, RenameDirectory) {
|
|
7329
7554
|
Options options = CurrentOptions();
|
|
7330
7555
|
DestroyAndReopen(options);
|
|
@@ -7509,6 +7734,80 @@ TEST_F(DBTest2, SstUniqueIdVerifyMultiCFs) {
|
|
|
7509
7734
|
ASSERT_TRUE(s.IsCorruption());
|
|
7510
7735
|
}
|
|
7511
7736
|
|
|
7737
|
+
TEST_F(DBTest2, BestEffortsRecoveryWithSstUniqueIdVerification) {
|
|
7738
|
+
const auto tamper_with_uniq_id = [&](void* arg) {
|
|
7739
|
+
auto props = static_cast<TableProperties*>(arg);
|
|
7740
|
+
assert(props);
|
|
7741
|
+
// update table property session_id to a different one
|
|
7742
|
+
props->db_session_id = DBImpl::GenerateDbSessionId(nullptr);
|
|
7743
|
+
};
|
|
7744
|
+
|
|
7745
|
+
const auto assert_db = [&](size_t expected_count,
|
|
7746
|
+
const std::string& expected_v) {
|
|
7747
|
+
std::unique_ptr<Iterator> it(db_->NewIterator(ReadOptions()));
|
|
7748
|
+
size_t cnt = 0;
|
|
7749
|
+
for (it->SeekToFirst(); it->Valid(); it->Next(), ++cnt) {
|
|
7750
|
+
ASSERT_EQ(std::to_string(cnt), it->key());
|
|
7751
|
+
ASSERT_EQ(expected_v, it->value());
|
|
7752
|
+
}
|
|
7753
|
+
ASSERT_EQ(expected_count, cnt);
|
|
7754
|
+
};
|
|
7755
|
+
|
|
7756
|
+
const int num_l0_compaction_trigger = 8;
|
|
7757
|
+
const int num_l0 = num_l0_compaction_trigger - 1;
|
|
7758
|
+
Options options = CurrentOptions();
|
|
7759
|
+
options.level0_file_num_compaction_trigger = num_l0_compaction_trigger;
|
|
7760
|
+
|
|
7761
|
+
for (int k = 0; k < num_l0; ++k) {
|
|
7762
|
+
// Allow mismatch for now
|
|
7763
|
+
options.verify_sst_unique_id_in_manifest = false;
|
|
7764
|
+
|
|
7765
|
+
DestroyAndReopen(options);
|
|
7766
|
+
|
|
7767
|
+
constexpr size_t num_keys_per_file = 10;
|
|
7768
|
+
for (int i = 0; i < num_l0; ++i) {
|
|
7769
|
+
for (size_t j = 0; j < num_keys_per_file; ++j) {
|
|
7770
|
+
ASSERT_OK(Put(std::to_string(j), "v" + std::to_string(i)));
|
|
7771
|
+
}
|
|
7772
|
+
if (i == k) {
|
|
7773
|
+
SyncPoint::GetInstance()->DisableProcessing();
|
|
7774
|
+
SyncPoint::GetInstance()->SetCallBack(
|
|
7775
|
+
"PropertyBlockBuilder::AddTableProperty:Start",
|
|
7776
|
+
tamper_with_uniq_id);
|
|
7777
|
+
SyncPoint::GetInstance()->EnableProcessing();
|
|
7778
|
+
}
|
|
7779
|
+
ASSERT_OK(Flush());
|
|
7780
|
+
}
|
|
7781
|
+
|
|
7782
|
+
options.verify_sst_unique_id_in_manifest = true;
|
|
7783
|
+
Status s = TryReopen(options);
|
|
7784
|
+
ASSERT_TRUE(s.IsCorruption());
|
|
7785
|
+
|
|
7786
|
+
options.best_efforts_recovery = true;
|
|
7787
|
+
Reopen(options);
|
|
7788
|
+
assert_db(k == 0 ? 0 : num_keys_per_file, "v" + std::to_string(k - 1));
|
|
7789
|
+
|
|
7790
|
+
// Reopen with regular recovery
|
|
7791
|
+
options.best_efforts_recovery = false;
|
|
7792
|
+
Reopen(options);
|
|
7793
|
+
assert_db(k == 0 ? 0 : num_keys_per_file, "v" + std::to_string(k - 1));
|
|
7794
|
+
|
|
7795
|
+
SyncPoint::GetInstance()->DisableProcessing();
|
|
7796
|
+
SyncPoint::GetInstance()->ClearAllCallBacks();
|
|
7797
|
+
|
|
7798
|
+
for (size_t i = 0; i < num_keys_per_file; ++i) {
|
|
7799
|
+
ASSERT_OK(Put(std::to_string(i), "v"));
|
|
7800
|
+
}
|
|
7801
|
+
ASSERT_OK(Flush());
|
|
7802
|
+
Reopen(options);
|
|
7803
|
+
{
|
|
7804
|
+
for (size_t i = 0; i < num_keys_per_file; ++i) {
|
|
7805
|
+
ASSERT_EQ("v", Get(std::to_string(i)));
|
|
7806
|
+
}
|
|
7807
|
+
}
|
|
7808
|
+
}
|
|
7809
|
+
}
|
|
7810
|
+
|
|
7512
7811
|
#ifndef ROCKSDB_LITE
|
|
7513
7812
|
TEST_F(DBTest2, GetLatestSeqAndTsForKey) {
|
|
7514
7813
|
Destroy(last_options_);
|
|
@@ -610,6 +610,52 @@ TEST_F(DBWALTest, WALWithChecksumHandoff) {
|
|
|
610
610
|
#endif // ROCKSDB_ASSERT_STATUS_CHECKED
|
|
611
611
|
}
|
|
612
612
|
|
|
613
|
+
#ifndef ROCKSDB_LITE
|
|
614
|
+
TEST_F(DBWALTest, LockWal) {
|
|
615
|
+
do {
|
|
616
|
+
Options options = CurrentOptions();
|
|
617
|
+
options.create_if_missing = true;
|
|
618
|
+
DestroyAndReopen(options);
|
|
619
|
+
SyncPoint::GetInstance()->DisableProcessing();
|
|
620
|
+
SyncPoint::GetInstance()->LoadDependency(
|
|
621
|
+
{{"DBWALTest::LockWal:AfterGetSortedWal",
|
|
622
|
+
"DBWALTest::LockWal:BeforeFlush:1"}});
|
|
623
|
+
SyncPoint::GetInstance()->EnableProcessing();
|
|
624
|
+
|
|
625
|
+
ASSERT_OK(Put("foo", "v"));
|
|
626
|
+
ASSERT_OK(Put("bar", "v"));
|
|
627
|
+
port::Thread worker([&]() {
|
|
628
|
+
TEST_SYNC_POINT("DBWALTest::LockWal:BeforeFlush:1");
|
|
629
|
+
Status tmp_s = db_->Flush(FlushOptions());
|
|
630
|
+
ASSERT_OK(tmp_s);
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
ASSERT_OK(db_->LockWAL());
|
|
634
|
+
// Verify writes are stopped
|
|
635
|
+
WriteOptions wopts;
|
|
636
|
+
wopts.no_slowdown = true;
|
|
637
|
+
Status s = db_->Put(wopts, "foo", "dontcare");
|
|
638
|
+
ASSERT_TRUE(s.IsIncomplete());
|
|
639
|
+
{
|
|
640
|
+
VectorLogPtr wals;
|
|
641
|
+
ASSERT_OK(db_->GetSortedWalFiles(wals));
|
|
642
|
+
ASSERT_FALSE(wals.empty());
|
|
643
|
+
}
|
|
644
|
+
TEST_SYNC_POINT("DBWALTest::LockWal:AfterGetSortedWal");
|
|
645
|
+
FlushOptions flush_opts;
|
|
646
|
+
flush_opts.wait = false;
|
|
647
|
+
s = db_->Flush(flush_opts);
|
|
648
|
+
ASSERT_TRUE(s.IsTryAgain());
|
|
649
|
+
ASSERT_OK(db_->UnlockWAL());
|
|
650
|
+
ASSERT_OK(db_->Put(WriteOptions(), "foo", "dontcare"));
|
|
651
|
+
|
|
652
|
+
worker.join();
|
|
653
|
+
|
|
654
|
+
SyncPoint::GetInstance()->DisableProcessing();
|
|
655
|
+
} while (ChangeWalOptions());
|
|
656
|
+
}
|
|
657
|
+
#endif //! ROCKSDB_LITE
|
|
658
|
+
|
|
613
659
|
class DBRecoveryTestBlobError
|
|
614
660
|
: public DBWALTest,
|
|
615
661
|
public testing::WithParamInterface<std::string> {
|
|
@@ -1599,6 +1645,89 @@ TEST_F(DBWALTest, RaceInstallFlushResultsWithWalObsoletion) {
|
|
|
1599
1645
|
delete db1;
|
|
1600
1646
|
}
|
|
1601
1647
|
|
|
1648
|
+
TEST_F(DBWALTest, FixSyncWalOnObseletedWalWithNewManifestCausingMissingWAL) {
|
|
1649
|
+
Options options = CurrentOptions();
|
|
1650
|
+
options.track_and_verify_wals_in_manifest = true;
|
|
1651
|
+
DestroyAndReopen(options);
|
|
1652
|
+
|
|
1653
|
+
// Accumulate memtable m1 and create the 1st wal (i.e, 4.log)
|
|
1654
|
+
ASSERT_OK(Put(Key(1), ""));
|
|
1655
|
+
ASSERT_OK(Put(Key(2), ""));
|
|
1656
|
+
ASSERT_OK(Put(Key(3), ""));
|
|
1657
|
+
|
|
1658
|
+
const std::string wal_file_path = db_->GetName() + "/000004.log";
|
|
1659
|
+
|
|
1660
|
+
// Coerce the following sequence of events:
|
|
1661
|
+
// (1) Flush() marks 4.log to be obsoleted, 8.log to be the latest (i.e,
|
|
1662
|
+
// active) log and release the lock
|
|
1663
|
+
// (2) SyncWAL() proceeds with the lock. It
|
|
1664
|
+
// creates a new manifest and syncs all the inactive wals before the latest
|
|
1665
|
+
// (i.e, active log), which is 4.log. Note that SyncWAL() is not aware of the
|
|
1666
|
+
// fact that 4.log has marked as to be obseleted. Prior to the fix, such wal
|
|
1667
|
+
// sync will then add a WAL addition record of 4.log to the new manifest
|
|
1668
|
+
// without any special treatment.
|
|
1669
|
+
// (3) BackgroundFlush() will eventually purge 4.log.
|
|
1670
|
+
bool wal_synced = false;
|
|
1671
|
+
SyncPoint::GetInstance()->SetCallBack(
|
|
1672
|
+
"FindObsoleteFiles::PostMutexUnlock", [&](void*) {
|
|
1673
|
+
ASSERT_OK(env_->FileExists(wal_file_path));
|
|
1674
|
+
|
|
1675
|
+
SyncPoint::GetInstance()->SetCallBack(
|
|
1676
|
+
"VersionSet::ProcessManifestWrites:"
|
|
1677
|
+
"PostDecidingCreateNewManifestOrNot",
|
|
1678
|
+
[&](void* arg) {
|
|
1679
|
+
bool* new_descriptor_log = (bool*)arg;
|
|
1680
|
+
*new_descriptor_log = true;
|
|
1681
|
+
});
|
|
1682
|
+
|
|
1683
|
+
ASSERT_OK(db_->SyncWAL());
|
|
1684
|
+
wal_synced = true;
|
|
1685
|
+
});
|
|
1686
|
+
|
|
1687
|
+
SyncPoint::GetInstance()->SetCallBack(
|
|
1688
|
+
"DBImpl::DeleteObsoleteFileImpl:AfterDeletion2", [&](void* arg) {
|
|
1689
|
+
std::string* file_name = (std::string*)arg;
|
|
1690
|
+
if (*file_name == wal_file_path) {
|
|
1691
|
+
TEST_SYNC_POINT(
|
|
1692
|
+
"DBWALTest::"
|
|
1693
|
+
"FixSyncWalOnObseletedWalWithNewManifestCausingMissingWAL::"
|
|
1694
|
+
"PostDeleteWAL");
|
|
1695
|
+
}
|
|
1696
|
+
});
|
|
1697
|
+
|
|
1698
|
+
SyncPoint::GetInstance()->LoadDependency(
|
|
1699
|
+
{{"DBImpl::BackgroundCallFlush:FilesFound",
|
|
1700
|
+
"PreConfrimObsoletedWALSynced"},
|
|
1701
|
+
{"DBWALTest::FixSyncWalOnObseletedWalWithNewManifestCausingMissingWAL::"
|
|
1702
|
+
"PostDeleteWAL",
|
|
1703
|
+
"PreConfrimWALDeleted"}});
|
|
1704
|
+
|
|
1705
|
+
SyncPoint::GetInstance()->EnableProcessing();
|
|
1706
|
+
|
|
1707
|
+
ASSERT_OK(Flush());
|
|
1708
|
+
|
|
1709
|
+
TEST_SYNC_POINT("PreConfrimObsoletedWALSynced");
|
|
1710
|
+
ASSERT_TRUE(wal_synced);
|
|
1711
|
+
|
|
1712
|
+
TEST_SYNC_POINT("PreConfrimWALDeleted");
|
|
1713
|
+
// BackgroundFlush() purged 4.log
|
|
1714
|
+
// because the memtable associated with the WAL was flushed and new WAL was
|
|
1715
|
+
// created (i.e, 8.log)
|
|
1716
|
+
ASSERT_TRUE(env_->FileExists(wal_file_path).IsNotFound());
|
|
1717
|
+
|
|
1718
|
+
SyncPoint::GetInstance()->ClearAllCallBacks();
|
|
1719
|
+
SyncPoint::GetInstance()->DisableProcessing();
|
|
1720
|
+
|
|
1721
|
+
// To verify the corruption of "Missing WAL with log number: 4" under
|
|
1722
|
+
// `options.track_and_verify_wals_in_manifest = true` is fixed.
|
|
1723
|
+
//
|
|
1724
|
+
// Before the fix, `db_->SyncWAL()` will sync and record WAL addtion of the
|
|
1725
|
+
// obseleted WAL 4.log in a new manifest without any special treament.
|
|
1726
|
+
// This will result in missing-wal corruption in DB::Reopen().
|
|
1727
|
+
Status s = TryReopen(options);
|
|
1728
|
+
EXPECT_OK(s);
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1602
1731
|
// Test scope:
|
|
1603
1732
|
// - We expect to open data store under all circumstances
|
|
1604
1733
|
// - We expect only data upto the point where the first error was encountered
|
|
@@ -323,6 +323,27 @@ TEST_F(TimestampCompatibleCompactionTest, CompactFilesRangeCheckL1) {
|
|
|
323
323
|
static_cast<int>(compaction_job_info.input_files.size()));
|
|
324
324
|
}
|
|
325
325
|
}
|
|
326
|
+
|
|
327
|
+
TEST_F(TimestampCompatibleCompactionTest, EmptyCompactionOutput) {
|
|
328
|
+
Options options = CurrentOptions();
|
|
329
|
+
options.env = env_;
|
|
330
|
+
options.comparator = test::BytewiseComparatorWithU64TsWrapper();
|
|
331
|
+
DestroyAndReopen(options);
|
|
332
|
+
|
|
333
|
+
std::string ts_str = Timestamp(1);
|
|
334
|
+
WriteOptions wopts;
|
|
335
|
+
ASSERT_OK(
|
|
336
|
+
db_->DeleteRange(wopts, db_->DefaultColumnFamily(), "k1", "k3", ts_str));
|
|
337
|
+
ASSERT_OK(Flush());
|
|
338
|
+
|
|
339
|
+
ts_str = Timestamp(3);
|
|
340
|
+
Slice ts = ts_str;
|
|
341
|
+
CompactRangeOptions cro;
|
|
342
|
+
// range tombstone will be dropped during compaction
|
|
343
|
+
cro.full_history_ts_low = &ts;
|
|
344
|
+
cro.bottommost_level_compaction = BottommostLevelCompaction::kForce;
|
|
345
|
+
ASSERT_OK(db_->CompactRange(cro, nullptr, nullptr));
|
|
346
|
+
}
|
|
326
347
|
#endif // !ROCKSDB_LITE
|
|
327
348
|
|
|
328
349
|
} // namespace ROCKSDB_NAMESPACE
|
|
@@ -150,6 +150,31 @@ int InternalKeyComparator::Compare(const ParsedInternalKey& a,
|
|
|
150
150
|
return r;
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
+
int InternalKeyComparator::Compare(const Slice& a,
|
|
154
|
+
const ParsedInternalKey& b) const {
|
|
155
|
+
// Order by:
|
|
156
|
+
// increasing user key (according to user-supplied comparator)
|
|
157
|
+
// decreasing sequence number
|
|
158
|
+
// decreasing type (though sequence# should be enough to disambiguate)
|
|
159
|
+
int r = user_comparator_.Compare(ExtractUserKey(a), b.user_key);
|
|
160
|
+
if (r == 0) {
|
|
161
|
+
const uint64_t anum =
|
|
162
|
+
DecodeFixed64(a.data() + a.size() - kNumInternalBytes);
|
|
163
|
+
const uint64_t bnum = (b.sequence << 8) | b.type;
|
|
164
|
+
if (anum > bnum) {
|
|
165
|
+
r = -1;
|
|
166
|
+
} else if (anum < bnum) {
|
|
167
|
+
r = +1;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return r;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
int InternalKeyComparator::Compare(const ParsedInternalKey& a,
|
|
174
|
+
const Slice& b) const {
|
|
175
|
+
return -Compare(b, a);
|
|
176
|
+
}
|
|
177
|
+
|
|
153
178
|
LookupKey::LookupKey(const Slice& _user_key, SequenceNumber s,
|
|
154
179
|
const Slice* ts) {
|
|
155
180
|
size_t usize = _user_key.size();
|
|
@@ -283,6 +283,8 @@ class InternalKeyComparator
|
|
|
283
283
|
|
|
284
284
|
int Compare(const InternalKey& a, const InternalKey& b) const;
|
|
285
285
|
int Compare(const ParsedInternalKey& a, const ParsedInternalKey& b) const;
|
|
286
|
+
int Compare(const Slice& a, const ParsedInternalKey& b) const;
|
|
287
|
+
int Compare(const ParsedInternalKey& a, const Slice& b) const;
|
|
286
288
|
// In this `Compare()` overload, the sequence numbers provided in
|
|
287
289
|
// `a_global_seqno` and `b_global_seqno` override the sequence numbers in `a`
|
|
288
290
|
// and `b`, respectively. To disable sequence number override(s), provide the
|
|
@@ -112,7 +112,7 @@ Status UpdateManifestForFilesState(
|
|
|
112
112
|
lf->smallest, lf->largest, lf->fd.smallest_seqno,
|
|
113
113
|
lf->fd.largest_seqno, lf->marked_for_compaction, temp,
|
|
114
114
|
lf->oldest_blob_file_number, lf->oldest_ancester_time,
|
|
115
|
-
lf->file_creation_time, lf->file_checksum,
|
|
115
|
+
lf->file_creation_time, lf->epoch_number, lf->file_checksum,
|
|
116
116
|
lf->file_checksum_func_name, lf->unique_id);
|
|
117
117
|
}
|
|
118
118
|
}
|
|
@@ -469,8 +469,11 @@ Status ExternalSstFileIngestionJob::Run() {
|
|
|
469
469
|
f.fd.GetNumber(), f.fd.GetPathId(), f.fd.GetFileSize(),
|
|
470
470
|
f.smallest_internal_key, f.largest_internal_key, f.assigned_seqno,
|
|
471
471
|
f.assigned_seqno, false, f.file_temperature, kInvalidBlobFileNumber,
|
|
472
|
-
oldest_ancester_time, current_time,
|
|
473
|
-
|
|
472
|
+
oldest_ancester_time, current_time,
|
|
473
|
+
ingestion_options_.ingest_behind
|
|
474
|
+
? kReservedEpochNumberForFileIngestedBehind
|
|
475
|
+
: cfd_->NewEpochNumber(),
|
|
476
|
+
f.file_checksum, f.file_checksum_func_name, f.unique_id);
|
|
474
477
|
f_metadata.temperature = f.file_temperature;
|
|
475
478
|
edit_.AddFile(f.picked_level, f_metadata);
|
|
476
479
|
}
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
#include "db/memtable_list.h"
|
|
24
24
|
#include "db/merge_context.h"
|
|
25
25
|
#include "db/range_tombstone_fragmenter.h"
|
|
26
|
+
#include "db/version_edit.h"
|
|
26
27
|
#include "db/version_set.h"
|
|
27
28
|
#include "file/file_util.h"
|
|
28
29
|
#include "file/filename.h"
|
|
@@ -199,6 +200,7 @@ void FlushJob::PickMemTable() {
|
|
|
199
200
|
|
|
200
201
|
// path 0 for level 0 file.
|
|
201
202
|
meta_.fd = FileDescriptor(versions_->NewFileNumber(), 0, 0);
|
|
203
|
+
meta_.epoch_number = cfd_->NewEpochNumber();
|
|
202
204
|
|
|
203
205
|
base_ = cfd_->current();
|
|
204
206
|
base_->Ref(); // it is likely that we do not need this reference
|
|
@@ -999,8 +1001,9 @@ Status FlushJob::WriteLevel0Table() {
|
|
|
999
1001
|
meta_.fd.smallest_seqno, meta_.fd.largest_seqno,
|
|
1000
1002
|
meta_.marked_for_compaction, meta_.temperature,
|
|
1001
1003
|
meta_.oldest_blob_file_number, meta_.oldest_ancester_time,
|
|
1002
|
-
meta_.file_creation_time, meta_.
|
|
1003
|
-
meta_.
|
|
1004
|
+
meta_.file_creation_time, meta_.epoch_number,
|
|
1005
|
+
meta_.file_checksum, meta_.file_checksum_func_name,
|
|
1006
|
+
meta_.unique_id);
|
|
1004
1007
|
|
|
1005
1008
|
edit_->SetBlobFileAdditions(std::move(blob_file_additions));
|
|
1006
1009
|
}
|
|
@@ -82,6 +82,10 @@ class HistoryTrimmingIterator : public InternalIterator {
|
|
|
82
82
|
|
|
83
83
|
bool IsValuePinned() const override { return input_->IsValuePinned(); }
|
|
84
84
|
|
|
85
|
+
bool IsDeleteRangeSentinelKey() const override {
|
|
86
|
+
return input_->IsDeleteRangeSentinelKey();
|
|
87
|
+
}
|
|
88
|
+
|
|
85
89
|
private:
|
|
86
90
|
InternalIterator* input_;
|
|
87
91
|
const std::string filter_ts_;
|