@nxtedition/rocksdb 8.0.0 → 8.0.2

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.
Files changed (144) hide show
  1. package/BUILDING.md +2 -2
  2. package/binding.cc +2 -7
  3. package/deps/rocksdb/rocksdb/CMakeLists.txt +10 -9
  4. package/deps/rocksdb/rocksdb/Makefile +2 -2
  5. package/deps/rocksdb/rocksdb/TARGETS +4 -2
  6. package/deps/rocksdb/rocksdb/cache/cache_bench_tool.cc +0 -5
  7. package/deps/rocksdb/rocksdb/cache/cache_test.cc +8 -29
  8. package/deps/rocksdb/rocksdb/cache/clock_cache.cc +146 -0
  9. package/deps/rocksdb/rocksdb/cache/clock_cache.h +13 -1
  10. package/deps/rocksdb/rocksdb/cache/lru_cache_test.cc +57 -146
  11. package/deps/rocksdb/rocksdb/cache/secondary_cache.cc +32 -0
  12. package/deps/rocksdb/rocksdb/db/blob/blob_counting_iterator.h +11 -0
  13. package/deps/rocksdb/rocksdb/db/column_family.cc +11 -9
  14. package/deps/rocksdb/rocksdb/db/column_family.h +20 -0
  15. package/deps/rocksdb/rocksdb/db/compaction/clipping_iterator.h +5 -0
  16. package/deps/rocksdb/rocksdb/db/compaction/compaction.cc +13 -33
  17. package/deps/rocksdb/rocksdb/db/compaction/compaction.h +5 -0
  18. package/deps/rocksdb/rocksdb/db/compaction/compaction_iterator.cc +27 -8
  19. package/deps/rocksdb/rocksdb/db/compaction/compaction_iterator.h +17 -1
  20. package/deps/rocksdb/rocksdb/db/compaction/compaction_job.cc +2 -1
  21. package/deps/rocksdb/rocksdb/db/compaction/compaction_job.h +4 -2
  22. package/deps/rocksdb/rocksdb/db/compaction/compaction_job_test.cc +8 -6
  23. package/deps/rocksdb/rocksdb/db/compaction/compaction_outputs.cc +65 -7
  24. package/deps/rocksdb/rocksdb/db/compaction/compaction_outputs.h +5 -0
  25. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker.cc +10 -32
  26. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker.h +28 -47
  27. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_fifo.cc +28 -22
  28. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_fifo.h +8 -14
  29. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_level.cc +8 -8
  30. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_level.h +5 -4
  31. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_test.cc +170 -140
  32. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_universal.cc +5 -1
  33. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_universal.h +5 -4
  34. package/deps/rocksdb/rocksdb/db/compaction/compaction_service_job.cc +8 -2
  35. package/deps/rocksdb/rocksdb/db/compaction/subcompaction_state.h +8 -0
  36. package/deps/rocksdb/rocksdb/db/compaction/tiered_compaction_test.cc +266 -138
  37. package/deps/rocksdb/rocksdb/db/corruption_test.cc +86 -1
  38. package/deps/rocksdb/rocksdb/db/db_basic_test.cc +72 -5
  39. package/deps/rocksdb/rocksdb/db/db_block_cache_test.cc +119 -10
  40. package/deps/rocksdb/rocksdb/db/db_compaction_test.cc +585 -264
  41. package/deps/rocksdb/rocksdb/db/db_impl/db_impl.cc +46 -18
  42. package/deps/rocksdb/rocksdb/db/db_impl/db_impl.h +5 -1
  43. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_compaction_flush.cc +6 -15
  44. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_debug.cc +1 -1
  45. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_experimental.cc +1 -1
  46. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_files.cc +3 -0
  47. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_open.cc +8 -8
  48. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_write.cc +10 -0
  49. package/deps/rocksdb/rocksdb/db/db_iter.cc +57 -36
  50. package/deps/rocksdb/rocksdb/db/db_iter.h +2 -1
  51. package/deps/rocksdb/rocksdb/db/db_range_del_test.cc +250 -2
  52. package/deps/rocksdb/rocksdb/db/db_test.cc +3 -0
  53. package/deps/rocksdb/rocksdb/db/db_test2.cc +307 -8
  54. package/deps/rocksdb/rocksdb/db/db_wal_test.cc +129 -0
  55. package/deps/rocksdb/rocksdb/db/db_with_timestamp_compaction_test.cc +21 -0
  56. package/deps/rocksdb/rocksdb/db/dbformat.cc +25 -0
  57. package/deps/rocksdb/rocksdb/db/dbformat.h +2 -0
  58. package/deps/rocksdb/rocksdb/db/experimental.cc +1 -1
  59. package/deps/rocksdb/rocksdb/db/external_sst_file_ingestion_job.cc +5 -2
  60. package/deps/rocksdb/rocksdb/db/flush_job.cc +5 -2
  61. package/deps/rocksdb/rocksdb/db/history_trimming_iterator.h +4 -0
  62. package/deps/rocksdb/rocksdb/db/import_column_family_job.cc +56 -53
  63. package/deps/rocksdb/rocksdb/db/import_column_family_test.cc +3 -4
  64. package/deps/rocksdb/rocksdb/db/memtable.cc +55 -9
  65. package/deps/rocksdb/rocksdb/db/merge_helper.cc +76 -102
  66. package/deps/rocksdb/rocksdb/db/merge_helper.h +2 -11
  67. package/deps/rocksdb/rocksdb/db/periodic_task_scheduler_test.cc +10 -10
  68. package/deps/rocksdb/rocksdb/db/repair.cc +64 -22
  69. package/deps/rocksdb/rocksdb/db/repair_test.cc +54 -0
  70. package/deps/rocksdb/rocksdb/db/seqno_time_test.cc +26 -26
  71. package/deps/rocksdb/rocksdb/db/table_cache.cc +2 -0
  72. package/deps/rocksdb/rocksdb/db/table_properties_collector.h +3 -1
  73. package/deps/rocksdb/rocksdb/db/version_builder.cc +90 -43
  74. package/deps/rocksdb/rocksdb/db/version_builder.h +20 -0
  75. package/deps/rocksdb/rocksdb/db/version_builder_test.cc +190 -67
  76. package/deps/rocksdb/rocksdb/db/version_edit.cc +15 -1
  77. package/deps/rocksdb/rocksdb/db/version_edit.h +16 -4
  78. package/deps/rocksdb/rocksdb/db/version_edit_handler.cc +41 -11
  79. package/deps/rocksdb/rocksdb/db/version_edit_handler.h +27 -12
  80. package/deps/rocksdb/rocksdb/db/version_edit_test.cc +18 -16
  81. package/deps/rocksdb/rocksdb/db/version_set.cc +219 -38
  82. package/deps/rocksdb/rocksdb/db/version_set.h +34 -4
  83. package/deps/rocksdb/rocksdb/db/version_set_test.cc +45 -25
  84. package/deps/rocksdb/rocksdb/db/wide/db_wide_basic_test.cc +122 -61
  85. package/deps/rocksdb/rocksdb/db/write_thread.cc +5 -2
  86. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_common.h +0 -1
  87. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_gflags.cc +0 -4
  88. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_test_base.cc +12 -17
  89. package/deps/rocksdb/rocksdb/db_stress_tool/no_batched_ops_stress.cc +6 -4
  90. package/deps/rocksdb/rocksdb/file/file_prefetch_buffer.cc +1 -1
  91. package/deps/rocksdb/rocksdb/file/file_prefetch_buffer.h +1 -0
  92. package/deps/rocksdb/rocksdb/file/prefetch_test.cc +0 -48
  93. package/deps/rocksdb/rocksdb/file/random_access_file_reader.cc +8 -0
  94. package/deps/rocksdb/rocksdb/include/rocksdb/cache.h +196 -171
  95. package/deps/rocksdb/rocksdb/include/rocksdb/db.h +6 -0
  96. package/deps/rocksdb/rocksdb/include/rocksdb/metadata.h +9 -3
  97. package/deps/rocksdb/rocksdb/include/rocksdb/options.h +25 -18
  98. package/deps/rocksdb/rocksdb/include/rocksdb/secondary_cache.h +27 -5
  99. package/deps/rocksdb/rocksdb/include/rocksdb/statistics.h +5 -0
  100. package/deps/rocksdb/rocksdb/include/rocksdb/status.h +3 -0
  101. package/deps/rocksdb/rocksdb/include/rocksdb/table.h +3 -0
  102. package/deps/rocksdb/rocksdb/include/rocksdb/version.h +1 -1
  103. package/deps/rocksdb/rocksdb/logging/logging.h +13 -19
  104. package/deps/rocksdb/rocksdb/memory/arena.cc +4 -3
  105. package/deps/rocksdb/rocksdb/memory/arena_test.cc +30 -0
  106. package/deps/rocksdb/rocksdb/monitoring/statistics.cc +3 -1
  107. package/deps/rocksdb/rocksdb/monitoring/stats_history_test.cc +26 -26
  108. package/deps/rocksdb/rocksdb/src.mk +2 -1
  109. package/deps/rocksdb/rocksdb/table/adaptive/adaptive_table_factory.cc +3 -2
  110. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_builder.cc +2 -10
  111. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader.cc +12 -29
  112. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader_test.cc +1 -1
  113. package/deps/rocksdb/rocksdb/table/block_based/block_like_traits.h +0 -39
  114. package/deps/rocksdb/rocksdb/table/block_based/filter_block_reader_common.cc +0 -1
  115. package/deps/rocksdb/rocksdb/table/block_fetcher_test.cc +3 -3
  116. package/deps/rocksdb/rocksdb/table/compaction_merging_iterator.cc +142 -0
  117. package/deps/rocksdb/rocksdb/table/compaction_merging_iterator.h +241 -0
  118. package/deps/rocksdb/rocksdb/table/format.cc +24 -20
  119. package/deps/rocksdb/rocksdb/table/format.h +5 -2
  120. package/deps/rocksdb/rocksdb/table/get_context.cc +52 -11
  121. package/deps/rocksdb/rocksdb/table/merging_iterator.cc +97 -115
  122. package/deps/rocksdb/rocksdb/table/merging_iterator.h +82 -1
  123. package/deps/rocksdb/rocksdb/table/meta_blocks.cc +2 -2
  124. package/deps/rocksdb/rocksdb/table/sst_file_dumper.cc +1 -1
  125. package/deps/rocksdb/rocksdb/table/table_test.cc +7 -6
  126. package/deps/rocksdb/rocksdb/test_util/testutil.h +10 -0
  127. package/deps/rocksdb/rocksdb/tools/db_bench_tool.cc +0 -6
  128. package/deps/rocksdb/rocksdb/trace_replay/block_cache_tracer.h +2 -2
  129. package/deps/rocksdb/rocksdb/util/bloom_test.cc +1 -1
  130. package/deps/rocksdb/rocksdb/util/crc32c.cc +1 -1
  131. package/deps/rocksdb/rocksdb/util/status.cc +7 -0
  132. package/deps/rocksdb/rocksdb/utilities/backup/backup_engine.cc +5 -0
  133. package/deps/rocksdb/rocksdb/utilities/backup/backup_engine_test.cc +4 -0
  134. package/deps/rocksdb/rocksdb/utilities/cache_dump_load_impl.cc +7 -67
  135. package/deps/rocksdb/rocksdb/utilities/cache_dump_load_impl.h +1 -3
  136. package/deps/rocksdb/rocksdb/utilities/checkpoint/checkpoint_impl.cc +1 -0
  137. package/deps/rocksdb/rocksdb/utilities/transactions/transaction_test.cc +59 -0
  138. package/deps/rocksdb/rocksdb.gyp +2 -1
  139. package/package.json +1 -1
  140. package/prebuilds/darwin-arm64/node.napi.node +0 -0
  141. package/prebuilds/linux-x64/node.napi.node +0 -0
  142. package/deps/rocksdb/rocksdb/cache/fast_lru_cache.cc +0 -580
  143. package/deps/rocksdb/rocksdb/cache/fast_lru_cache.h +0 -476
  144. package/max_rev_operator.h +0 -100
@@ -293,7 +293,7 @@ bool UniversalCompactionPicker::NeedsCompaction(
293
293
  Compaction* UniversalCompactionPicker::PickCompaction(
294
294
  const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
295
295
  const MutableDBOptions& mutable_db_options, VersionStorageInfo* vstorage,
296
- LogBuffer* log_buffer, const SequenceNumber /* earliest_mem_seqno */) {
296
+ LogBuffer* log_buffer) {
297
297
  UniversalCompactionBuilder builder(ioptions_, icmp_, cf_name,
298
298
  mutable_cf_options, mutable_db_options,
299
299
  vstorage, this, log_buffer);
@@ -400,6 +400,7 @@ Compaction* UniversalCompactionBuilder::PickCompaction() {
400
400
  if (!vstorage_->FilesMarkedForPeriodicCompaction().empty()) {
401
401
  // Always need to do a full compaction for periodic compaction.
402
402
  c = PickPeriodicCompaction();
403
+ TEST_SYNC_POINT_CALLBACK("PostPickPeriodicCompaction", c);
403
404
  }
404
405
 
405
406
  // Check for size amplification.
@@ -408,6 +409,7 @@ Compaction* UniversalCompactionBuilder::PickCompaction() {
408
409
  static_cast<size_t>(
409
410
  mutable_cf_options_.level0_file_num_compaction_trigger)) {
410
411
  if ((c = PickCompactionToReduceSizeAmp()) != nullptr) {
412
+ TEST_SYNC_POINT("PickCompactionToReduceSizeAmpReturnNonnullptr");
411
413
  ROCKS_LOG_BUFFER(log_buffer_, "[%s] Universal: compacting for size amp\n",
412
414
  cf_name_.c_str());
413
415
  } else {
@@ -417,6 +419,7 @@ Compaction* UniversalCompactionBuilder::PickCompaction() {
417
419
  mutable_cf_options_.compaction_options_universal.size_ratio;
418
420
 
419
421
  if ((c = PickCompactionToReduceSortedRuns(ratio, UINT_MAX)) != nullptr) {
422
+ TEST_SYNC_POINT("PickCompactionToReduceSortedRunsReturnNonnullptr");
420
423
  ROCKS_LOG_BUFFER(log_buffer_,
421
424
  "[%s] Universal: compacting for size ratio\n",
422
425
  cf_name_.c_str());
@@ -457,6 +460,7 @@ Compaction* UniversalCompactionBuilder::PickCompaction() {
457
460
 
458
461
  if (c == nullptr) {
459
462
  if ((c = PickDeleteTriggeredCompaction()) != nullptr) {
463
+ TEST_SYNC_POINT("PickDeleteTriggeredCompactionReturnNonnullptr");
460
464
  ROCKS_LOG_BUFFER(log_buffer_,
461
465
  "[%s] Universal: delete triggered compaction\n",
462
466
  cf_name_.c_str());
@@ -18,10 +18,11 @@ class UniversalCompactionPicker : public CompactionPicker {
18
18
  UniversalCompactionPicker(const ImmutableOptions& ioptions,
19
19
  const InternalKeyComparator* icmp)
20
20
  : CompactionPicker(ioptions, icmp) {}
21
- virtual Compaction* PickCompaction(
22
- const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
23
- const MutableDBOptions& mutable_db_options, VersionStorageInfo* vstorage,
24
- LogBuffer* log_buffer, const SequenceNumber earliest_mem_seqno) override;
21
+ virtual Compaction* PickCompaction(const std::string& cf_name,
22
+ const MutableCFOptions& mutable_cf_options,
23
+ const MutableDBOptions& mutable_db_options,
24
+ VersionStorageInfo* vstorage,
25
+ LogBuffer* log_buffer) override;
25
26
  virtual int MaxOutputLevel() const override { return NumberLevels() - 1; }
26
27
 
27
28
  virtual bool NeedsCompaction(
@@ -190,6 +190,7 @@ CompactionJob::ProcessKeyValueCompactionWithCompactionService(
190
190
  meta.largest.DecodeFrom(file.largest_internal_key);
191
191
  meta.oldest_ancester_time = file.oldest_ancester_time;
192
192
  meta.file_creation_time = file.file_creation_time;
193
+ meta.epoch_number = file.epoch_number;
193
194
  meta.marked_for_compaction = file.marked_for_compaction;
194
195
  meta.unique_id = file.unique_id;
195
196
 
@@ -333,8 +334,9 @@ Status CompactionServiceCompactionJob::Run() {
333
334
  MakeTableFileName(meta.fd.GetNumber()), meta.fd.smallest_seqno,
334
335
  meta.fd.largest_seqno, meta.smallest.Encode().ToString(),
335
336
  meta.largest.Encode().ToString(), meta.oldest_ancester_time,
336
- meta.file_creation_time, output_file.validator.GetHash(),
337
- meta.marked_for_compaction, meta.unique_id);
337
+ meta.file_creation_time, meta.epoch_number,
338
+ output_file.validator.GetHash(), meta.marked_for_compaction,
339
+ meta.unique_id);
338
340
  }
339
341
  InternalStats::CompactionStatsFull compaction_stats;
340
342
  sub_compact->AggregateCompactionStats(compaction_stats);
@@ -489,6 +491,10 @@ static std::unordered_map<std::string, OptionTypeInfo>
489
491
  {offsetof(struct CompactionServiceOutputFile, file_creation_time),
490
492
  OptionType::kUInt64T, OptionVerificationType::kNormal,
491
493
  OptionTypeFlags::kNone}},
494
+ {"epoch_number",
495
+ {offsetof(struct CompactionServiceOutputFile, epoch_number),
496
+ OptionType::kUInt64T, OptionVerificationType::kNormal,
497
+ OptionTypeFlags::kNone}},
492
498
  {"paranoid_hash",
493
499
  {offsetof(struct CompactionServiceOutputFile, paranoid_hash),
494
500
  OptionType::kUInt64T, OptionVerificationType::kNormal,
@@ -84,6 +84,11 @@ class SubcompactionState {
84
84
  // Assign range dels aggregator, for each range_del, it can only be assigned
85
85
  // to one output level, for per_key_placement, it's going to be the
86
86
  // penultimate level.
87
+ // TODO: This does not work for per_key_placement + user-defined timestamp +
88
+ // DeleteRange() combo. If user-defined timestamp is enabled,
89
+ // it is possible for a range tombstone to belong to bottommost level (
90
+ // seqno < earliest snapshot) without being dropped (garbage collection
91
+ // for user-defined timestamp).
87
92
  void AssignRangeDelAggregator(
88
93
  std::unique_ptr<CompactionRangeDelAggregator>&& range_del_agg) {
89
94
  if (compaction->SupportsPerKeyPlacement()) {
@@ -196,8 +201,11 @@ class SubcompactionState {
196
201
  const CompactionFileCloseFunc& close_file_func) {
197
202
  // Call FinishCompactionOutputFile() even if status is not ok: it needs to
198
203
  // close the output file.
204
+ // CloseOutput() may open new compaction output files.
205
+ is_current_penultimate_level_ = true;
199
206
  Status s = penultimate_level_outputs_.CloseOutput(
200
207
  curr_status, open_file_func, close_file_func);
208
+ is_current_penultimate_level_ = false;
201
209
  s = compaction_outputs_.CloseOutput(s, open_file_func, close_file_func);
202
210
  return s;
203
211
  }
@@ -663,8 +663,19 @@ TEST_P(TieredCompactionTest, LevelOutofBoundaryRangeDelete) {
663
663
  cro.bottommost_level_compaction = BottommostLevelCompaction::kForce;
664
664
  ASSERT_OK(db_->CompactRange(cro, nullptr, nullptr));
665
665
 
666
- ASSERT_EQ(GetSstSizeHelper(Temperature::kUnknown),
667
- 0); // tombstone has no size, even it's in hot tier
666
+ // range tombstone is not in cold tier
667
+ ASSERT_GT(GetSstSizeHelper(Temperature::kUnknown), 0);
668
+ std::vector<std::vector<FileMetaData>> level_to_files;
669
+ dbfull()->TEST_GetFilesMetaData(dbfull()->DefaultColumnFamily(),
670
+ &level_to_files);
671
+ // range tombstone is in the penultimate level
672
+ const int penultimate_level = kNumLevels - 2;
673
+ ASSERT_EQ(level_to_files[penultimate_level].size(), 1);
674
+ ASSERT_EQ(level_to_files[penultimate_level][0].num_entries, 1);
675
+ ASSERT_EQ(level_to_files[penultimate_level][0].num_deletions, 1);
676
+ ASSERT_EQ(level_to_files[penultimate_level][0].temperature,
677
+ Temperature::kUnknown);
678
+
668
679
  ASSERT_GT(GetSstSizeHelper(Temperature::kCold), 0);
669
680
  ASSERT_EQ("0,1,10",
670
681
  FilesPerLevel()); // one file is at the penultimate level which
@@ -1240,7 +1251,7 @@ TEST_F(PrecludeLastLevelTest, MigrationFromPreserveTimeManualCompaction) {
1240
1251
 
1241
1252
  // pass some time first, otherwise the first a few keys write time are going
1242
1253
  // to be zero, and internally zero has special meaning: kUnknownSeqnoTime
1243
- dbfull()->TEST_WaitForPeridicTaskRun(
1254
+ dbfull()->TEST_WaitForPeriodicTaskRun(
1244
1255
  [&] { mock_clock_->MockSleepForSeconds(static_cast<int>(kKeyPerSec)); });
1245
1256
 
1246
1257
  int sst_num = 0;
@@ -1248,7 +1259,7 @@ TEST_F(PrecludeLastLevelTest, MigrationFromPreserveTimeManualCompaction) {
1248
1259
  for (; sst_num < kNumTrigger; sst_num++) {
1249
1260
  for (int i = 0; i < kNumKeys; i++) {
1250
1261
  ASSERT_OK(Put(Key(sst_num * (kNumKeys - 1) + i), "value"));
1251
- dbfull()->TEST_WaitForPeridicTaskRun([&] {
1262
+ dbfull()->TEST_WaitForPeriodicTaskRun([&] {
1252
1263
  mock_clock_->MockSleepForSeconds(static_cast<int>(kKeyPerSec));
1253
1264
  });
1254
1265
  }
@@ -1302,7 +1313,7 @@ TEST_F(PrecludeLastLevelTest, MigrationFromPreserveTimeAutoCompaction) {
1302
1313
 
1303
1314
  // pass some time first, otherwise the first a few keys write time are going
1304
1315
  // to be zero, and internally zero has special meaning: kUnknownSeqnoTime
1305
- dbfull()->TEST_WaitForPeridicTaskRun(
1316
+ dbfull()->TEST_WaitForPeriodicTaskRun(
1306
1317
  [&] { mock_clock_->MockSleepForSeconds(static_cast<int>(kKeyPerSec)); });
1307
1318
 
1308
1319
  int sst_num = 0;
@@ -1310,7 +1321,7 @@ TEST_F(PrecludeLastLevelTest, MigrationFromPreserveTimeAutoCompaction) {
1310
1321
  for (; sst_num < kNumTrigger; sst_num++) {
1311
1322
  for (int i = 0; i < kNumKeys; i++) {
1312
1323
  ASSERT_OK(Put(Key(sst_num * (kNumKeys - 1) + i), "value"));
1313
- dbfull()->TEST_WaitForPeridicTaskRun([&] {
1324
+ dbfull()->TEST_WaitForPeriodicTaskRun([&] {
1314
1325
  mock_clock_->MockSleepForSeconds(static_cast<int>(kKeyPerSec));
1315
1326
  });
1316
1327
  }
@@ -1344,7 +1355,7 @@ TEST_F(PrecludeLastLevelTest, MigrationFromPreserveTimeAutoCompaction) {
1344
1355
  for (int i = 0; i < kNumKeys; i++) {
1345
1356
  // the value needs to be big enough to trigger full compaction
1346
1357
  ASSERT_OK(Put(Key(sst_num * (kNumKeys - 1) + i), rnd.RandomString(100)));
1347
- dbfull()->TEST_WaitForPeridicTaskRun([&] {
1358
+ dbfull()->TEST_WaitForPeriodicTaskRun([&] {
1348
1359
  mock_clock_->MockSleepForSeconds(static_cast<int>(kKeyPerSec));
1349
1360
  });
1350
1361
  }
@@ -1378,7 +1389,7 @@ TEST_F(PrecludeLastLevelTest, MigrationFromPreserveTimePartial) {
1378
1389
 
1379
1390
  // pass some time first, otherwise the first a few keys write time are going
1380
1391
  // to be zero, and internally zero has special meaning: kUnknownSeqnoTime
1381
- dbfull()->TEST_WaitForPeridicTaskRun(
1392
+ dbfull()->TEST_WaitForPeriodicTaskRun(
1382
1393
  [&] { mock_clock_->MockSleepForSeconds(static_cast<int>(kKeyPerSec)); });
1383
1394
 
1384
1395
  int sst_num = 0;
@@ -1386,7 +1397,7 @@ TEST_F(PrecludeLastLevelTest, MigrationFromPreserveTimePartial) {
1386
1397
  for (; sst_num < kNumTrigger; sst_num++) {
1387
1398
  for (int i = 0; i < kNumKeys; i++) {
1388
1399
  ASSERT_OK(Put(Key(sst_num * (kNumKeys - 1) + i), "value"));
1389
- dbfull()->TEST_WaitForPeridicTaskRun([&] {
1400
+ dbfull()->TEST_WaitForPeriodicTaskRun([&] {
1390
1401
  mock_clock_->MockSleepForSeconds(static_cast<int>(kKeyPerSec));
1391
1402
  });
1392
1403
  }
@@ -1452,13 +1463,13 @@ TEST_F(PrecludeLastLevelTest, SmallPrecludeTime) {
1452
1463
 
1453
1464
  Random rnd(301);
1454
1465
 
1455
- dbfull()->TEST_WaitForPeridicTaskRun([&] {
1466
+ dbfull()->TEST_WaitForPeriodicTaskRun([&] {
1456
1467
  mock_clock_->MockSleepForSeconds(static_cast<int>(rnd.Uniform(10) + 1));
1457
1468
  });
1458
1469
 
1459
1470
  for (int i = 0; i < kNumKeys; i++) {
1460
1471
  ASSERT_OK(Put(Key(i), rnd.RandomString(100)));
1461
- dbfull()->TEST_WaitForPeridicTaskRun([&] {
1472
+ dbfull()->TEST_WaitForPeriodicTaskRun([&] {
1462
1473
  mock_clock_->MockSleepForSeconds(static_cast<int>(rnd.Uniform(2)));
1463
1474
  });
1464
1475
  }
@@ -1505,7 +1516,7 @@ TEST_F(PrecludeLastLevelTest, LastLevelOnlyCompactionPartial) {
1505
1516
 
1506
1517
  // pass some time first, otherwise the first a few keys write time are going
1507
1518
  // to be zero, and internally zero has special meaning: kUnknownSeqnoTime
1508
- dbfull()->TEST_WaitForPeridicTaskRun(
1519
+ dbfull()->TEST_WaitForPeriodicTaskRun(
1509
1520
  [&] { mock_clock_->MockSleepForSeconds(static_cast<int>(kKeyPerSec)); });
1510
1521
 
1511
1522
  int sst_num = 0;
@@ -1513,7 +1524,7 @@ TEST_F(PrecludeLastLevelTest, LastLevelOnlyCompactionPartial) {
1513
1524
  for (; sst_num < kNumTrigger; sst_num++) {
1514
1525
  for (int i = 0; i < kNumKeys; i++) {
1515
1526
  ASSERT_OK(Put(Key(sst_num * (kNumKeys - 1) + i), "value"));
1516
- dbfull()->TEST_WaitForPeridicTaskRun([&] {
1527
+ dbfull()->TEST_WaitForPeriodicTaskRun([&] {
1517
1528
  mock_clock_->MockSleepForSeconds(static_cast<int>(kKeyPerSec));
1518
1529
  });
1519
1530
  }
@@ -1583,7 +1594,7 @@ TEST_P(PrecludeLastLevelTestWithParms, LastLevelOnlyCompactionNoPreclude) {
1583
1594
 
1584
1595
  // pass some time first, otherwise the first a few keys write time are going
1585
1596
  // to be zero, and internally zero has special meaning: kUnknownSeqnoTime
1586
- dbfull()->TEST_WaitForPeridicTaskRun(
1597
+ dbfull()->TEST_WaitForPeriodicTaskRun(
1587
1598
  [&] { mock_clock_->MockSleepForSeconds(static_cast<int>(kKeyPerSec)); });
1588
1599
 
1589
1600
  Random rnd(301);
@@ -1592,7 +1603,7 @@ TEST_P(PrecludeLastLevelTestWithParms, LastLevelOnlyCompactionNoPreclude) {
1592
1603
  for (; sst_num < kNumTrigger; sst_num++) {
1593
1604
  for (int i = 0; i < kNumKeys; i++) {
1594
1605
  ASSERT_OK(Put(Key(sst_num * (kNumKeys - 1) + i), rnd.RandomString(100)));
1595
- dbfull()->TEST_WaitForPeridicTaskRun([&] {
1606
+ dbfull()->TEST_WaitForPeriodicTaskRun([&] {
1596
1607
  mock_clock_->MockSleepForSeconds(static_cast<int>(kKeyPerSec));
1597
1608
  });
1598
1609
  }
@@ -1685,7 +1696,7 @@ TEST_P(PrecludeLastLevelTestWithParms, LastLevelOnlyCompactionNoPreclude) {
1685
1696
  for (int i = 0; i < kNumKeys; i++) {
1686
1697
  // the value needs to be big enough to trigger full compaction
1687
1698
  ASSERT_OK(Put(Key(sst_num * (kNumKeys - 1) + i), "value"));
1688
- dbfull()->TEST_WaitForPeridicTaskRun([&] {
1699
+ dbfull()->TEST_WaitForPeriodicTaskRun([&] {
1689
1700
  mock_clock_->MockSleepForSeconds(static_cast<int>(kKeyPerSec));
1690
1701
  });
1691
1702
  }
@@ -1710,6 +1721,133 @@ TEST_P(PrecludeLastLevelTestWithParms, LastLevelOnlyCompactionNoPreclude) {
1710
1721
  Close();
1711
1722
  }
1712
1723
 
1724
+ TEST_P(PrecludeLastLevelTestWithParms, PeriodicCompactionToPenultimateLevel) {
1725
+ // Test the last level only periodic compaction should also be blocked by an
1726
+ // ongoing compaction in penultimate level if tiered compaction is enabled
1727
+ // otherwise, the periodic compaction should just run for the last level.
1728
+ const int kNumTrigger = 4;
1729
+ const int kNumLevels = 7;
1730
+ const int kPenultimateLevel = kNumLevels - 2;
1731
+ const int kKeyPerSec = 1;
1732
+ const int kNumKeys = 100;
1733
+
1734
+ bool enable_preclude_last_level = GetParam();
1735
+
1736
+ Options options = CurrentOptions();
1737
+ options.compaction_style = kCompactionStyleUniversal;
1738
+ options.preserve_internal_time_seconds = 20000;
1739
+ options.env = mock_env_.get();
1740
+ options.level0_file_num_compaction_trigger = kNumTrigger;
1741
+ options.num_levels = kNumLevels;
1742
+ options.ignore_max_compaction_bytes_for_input = false;
1743
+ options.periodic_compaction_seconds = 10000;
1744
+ DestroyAndReopen(options);
1745
+
1746
+ Random rnd(301);
1747
+
1748
+ for (int i = 0; i < 3 * kNumKeys; i++) {
1749
+ ASSERT_OK(Put(Key(i), rnd.RandomString(100)));
1750
+ dbfull()->TEST_WaitForPeriodicTaskRun(
1751
+ [&] { mock_clock_->MockSleepForSeconds(kKeyPerSec); });
1752
+ }
1753
+ ASSERT_OK(Flush());
1754
+ CompactRangeOptions cro;
1755
+ cro.bottommost_level_compaction = BottommostLevelCompaction::kForce;
1756
+
1757
+ ASSERT_OK(db_->CompactRange(cro, nullptr, nullptr));
1758
+
1759
+ // make sure all data is compacted to the last level
1760
+ ASSERT_EQ("0,0,0,0,0,0,1", FilesPerLevel());
1761
+
1762
+ // enable preclude feature
1763
+ if (enable_preclude_last_level) {
1764
+ options.preclude_last_level_data_seconds = 20000;
1765
+ }
1766
+ options.max_background_jobs = 8;
1767
+ options.last_level_temperature = Temperature::kCold;
1768
+ Reopen(options);
1769
+
1770
+ std::atomic_bool is_size_ratio_compaction_running = false;
1771
+ std::atomic_bool verified_last_level_compaction = false;
1772
+
1773
+ SyncPoint::GetInstance()->SetCallBack(
1774
+ "CompactionJob::ProcessKeyValueCompaction()::Processing", [&](void* arg) {
1775
+ auto compaction = static_cast<Compaction*>(arg);
1776
+ if (compaction->output_level() == kPenultimateLevel) {
1777
+ is_size_ratio_compaction_running = true;
1778
+ TEST_SYNC_POINT(
1779
+ "PrecludeLastLevelTest::PeriodicCompactionToPenultimateLevel:"
1780
+ "SizeRatioCompaction1");
1781
+ TEST_SYNC_POINT(
1782
+ "PrecludeLastLevelTest::PeriodicCompactionToPenultimateLevel:"
1783
+ "SizeRatioCompaction2");
1784
+ is_size_ratio_compaction_running = false;
1785
+ }
1786
+ });
1787
+
1788
+ SyncPoint::GetInstance()->SetCallBack(
1789
+ "UniversalCompactionBuilder::PickCompaction:Return", [&](void* arg) {
1790
+ auto compaction = static_cast<Compaction*>(arg);
1791
+
1792
+ if (is_size_ratio_compaction_running) {
1793
+ if (enable_preclude_last_level) {
1794
+ ASSERT_TRUE(compaction == nullptr);
1795
+ } else {
1796
+ ASSERT_TRUE(compaction != nullptr);
1797
+ ASSERT_EQ(compaction->compaction_reason(),
1798
+ CompactionReason::kPeriodicCompaction);
1799
+ ASSERT_EQ(compaction->start_level(), kNumLevels - 1);
1800
+ }
1801
+ verified_last_level_compaction = true;
1802
+ }
1803
+ TEST_SYNC_POINT(
1804
+ "PrecludeLastLevelTest::PeriodicCompactionToPenultimateLevel:"
1805
+ "AutoCompactionPicked");
1806
+ });
1807
+
1808
+ SyncPoint::GetInstance()->LoadDependency({
1809
+ {"PrecludeLastLevelTest::PeriodicCompactionToPenultimateLevel:"
1810
+ "SizeRatioCompaction1",
1811
+ "PrecludeLastLevelTest::PeriodicCompactionToPenultimateLevel:DoneWrite"},
1812
+ {"PrecludeLastLevelTest::PeriodicCompactionToPenultimateLevel:"
1813
+ "AutoCompactionPicked",
1814
+ "PrecludeLastLevelTest::PeriodicCompactionToPenultimateLevel:"
1815
+ "SizeRatioCompaction2"},
1816
+ });
1817
+
1818
+ auto stop_token =
1819
+ dbfull()->TEST_write_controler().GetCompactionPressureToken();
1820
+
1821
+ for (int i = 0; i < kNumTrigger - 1; i++) {
1822
+ for (int j = 0; j < kNumKeys; j++) {
1823
+ ASSERT_OK(Put(Key(i * (kNumKeys - 1) + i), rnd.RandomString(10)));
1824
+ dbfull()->TEST_WaitForPeriodicTaskRun(
1825
+ [&] { mock_clock_->MockSleepForSeconds(kKeyPerSec); });
1826
+ }
1827
+ ASSERT_OK(Flush());
1828
+ }
1829
+
1830
+ TEST_SYNC_POINT(
1831
+ "PrecludeLastLevelTest::PeriodicCompactionToPenultimateLevel:DoneWrite");
1832
+
1833
+ // wait for periodic compaction time and flush to trigger the periodic
1834
+ // compaction, which should be blocked by ongoing compaction in the
1835
+ // penultimate level
1836
+ mock_clock_->MockSleepForSeconds(10000);
1837
+ for (int i = 0; i < 3 * kNumKeys; i++) {
1838
+ ASSERT_OK(Put(Key(i), rnd.RandomString(10)));
1839
+ dbfull()->TEST_WaitForPeriodicTaskRun(
1840
+ [&] { mock_clock_->MockSleepForSeconds(kKeyPerSec); });
1841
+ }
1842
+ ASSERT_OK(Flush());
1843
+
1844
+ ASSERT_OK(dbfull()->WaitForCompact(true));
1845
+
1846
+ stop_token.reset();
1847
+
1848
+ Close();
1849
+ }
1850
+
1713
1851
  INSTANTIATE_TEST_CASE_P(PrecludeLastLevelTestWithParms,
1714
1852
  PrecludeLastLevelTestWithParms, testing::Bool());
1715
1853
 
@@ -1770,14 +1908,14 @@ TEST_F(PrecludeLastLevelTest, PartialPenultimateLevelCompaction) {
1770
1908
 
1771
1909
  // pass some time first, otherwise the first a few keys write time are going
1772
1910
  // to be zero, and internally zero has special meaning: kUnknownSeqnoTime
1773
- dbfull()->TEST_WaitForPeridicTaskRun(
1911
+ dbfull()->TEST_WaitForPeriodicTaskRun(
1774
1912
  [&] { mock_clock_->MockSleepForSeconds(static_cast<int>(10)); });
1775
1913
 
1776
1914
  Random rnd(301);
1777
1915
 
1778
1916
  for (int i = 0; i < 300; i++) {
1779
1917
  ASSERT_OK(Put(Key(i), rnd.RandomString(100)));
1780
- dbfull()->TEST_WaitForPeridicTaskRun(
1918
+ dbfull()->TEST_WaitForPeriodicTaskRun(
1781
1919
  [&] { mock_clock_->MockSleepForSeconds(kKeyPerSec); });
1782
1920
  }
1783
1921
  ASSERT_OK(Flush());
@@ -1858,155 +1996,145 @@ TEST_F(PrecludeLastLevelTest, PartialPenultimateLevelCompaction) {
1858
1996
  Close();
1859
1997
  }
1860
1998
 
1861
- struct TestPropertiesCollector : public TablePropertiesCollector {
1862
- Status AddUserKey(const Slice& key, const Slice& /*value*/,
1863
- EntryType /*type*/, SequenceNumber /*seq*/,
1864
- uint64_t /*file_size*/) override {
1865
- if (cmp->Compare(key, DBTestBase::Key(100)) == 0) {
1866
- has_key_100 = true;
1867
- }
1868
- if (cmp->Compare(key, DBTestBase::Key(200)) == 0) {
1869
- has_key_200 = true;
1870
- }
1871
-
1872
- return Status::OK();
1873
- }
1874
-
1875
- const char* Name() const override { return "TestTablePropertiesCollector"; }
1876
-
1877
- UserCollectedProperties GetReadableProperties() const override {
1878
- UserCollectedProperties ret;
1879
- return ret;
1880
- }
1881
-
1882
- Status Finish(UserCollectedProperties* /*properties*/) override {
1883
- // The LSM tree would be like:
1884
- // L5: [0,19] [20,39] [40,299]
1885
- // L6: [0, 299]
1886
- // the 3rd file @L5 has both 100 and 200, which will be marked for
1887
- // compaction
1888
- // Also avoid marking flushed SST for compaction, which won't have both 100
1889
- // and 200
1890
- if (has_key_100 && has_key_200) {
1891
- need_compact_ = true;
1892
- } else {
1893
- need_compact_ = false;
1894
- }
1895
- has_key_100 = false;
1896
- has_key_200 = false;
1897
- return Status::OK();
1898
- }
1899
-
1900
- bool NeedCompact() const override { return need_compact_; }
1901
-
1902
- const Comparator* cmp = BytewiseComparator();
1903
-
1904
- private:
1905
- bool has_key_100 = false;
1906
- bool has_key_200 = false;
1907
-
1908
- bool need_compact_ = false;
1909
- };
1910
-
1911
- class TestPropertiesCollectorFactory : public TablePropertiesCollectorFactory {
1912
- public:
1913
- TablePropertiesCollector* CreateTablePropertiesCollector(
1914
- TablePropertiesCollectorFactory::Context /*context*/) override {
1915
- return new TestPropertiesCollector;
1916
- }
1917
- const char* Name() const override { return "TestTablePropertiesCollector"; }
1918
- };
1919
-
1920
- TEST_F(PrecludeLastLevelTest, PartialPenultimateLevelCompactionWithRangeDel) {
1921
- const int kNumTrigger = 4;
1999
+ TEST_F(PrecludeLastLevelTest, RangeDelsCauseFileEndpointsToOverlap) {
1922
2000
  const int kNumLevels = 7;
1923
- const int kKeyPerSec = 10;
2001
+ const int kSecondsPerKey = 10;
2002
+ const int kNumFiles = 3;
2003
+ const int kValueBytes = 4 << 10;
2004
+ const int kFileBytes = 4 * kValueBytes;
2005
+ // `kNumKeysPerFile == 5` is determined by the current file cutting heuristics
2006
+ // for this choice of `kValueBytes` and `kFileBytes`.
2007
+ const int kNumKeysPerFile = 5;
2008
+ const int kNumKeys = kNumFiles * kNumKeysPerFile;
1924
2009
 
1925
2010
  Options options = CurrentOptions();
1926
2011
  options.compaction_style = kCompactionStyleUniversal;
1927
2012
  options.env = mock_env_.get();
1928
- options.level0_file_num_compaction_trigger = kNumTrigger;
1929
- options.preserve_internal_time_seconds = 10000;
2013
+ options.last_level_temperature = Temperature::kCold;
2014
+ options.preserve_internal_time_seconds = 600;
2015
+ options.preclude_last_level_data_seconds = 1;
1930
2016
  options.num_levels = kNumLevels;
1931
- // set a small max_compaction_bytes to avoid input level expansion
1932
- options.max_compaction_bytes = 30000;
1933
- options.ignore_max_compaction_bytes_for_input = false;
2017
+ options.target_file_size_base = kFileBytes;
1934
2018
  DestroyAndReopen(options);
1935
2019
 
1936
2020
  // pass some time first, otherwise the first a few keys write time are going
1937
2021
  // to be zero, and internally zero has special meaning: kUnknownSeqnoTime
1938
- dbfull()->TEST_WaitForPeridicTaskRun(
1939
- [&] { mock_clock_->MockSleepForSeconds(static_cast<int>(10)); });
2022
+ dbfull()->TEST_WaitForPeriodicTaskRun([&] {
2023
+ mock_clock_->MockSleepForSeconds(static_cast<int>(kSecondsPerKey));
2024
+ });
1940
2025
 
2026
+ // Flush an L0 file with the following contents (new to old):
2027
+ //
2028
+ // Range deletions [4, 6) [7, 8) [9, 11)
2029
+ // --- snap2 ---
2030
+ // Key(0) .. Key(14)
2031
+ // --- snap1 ---
2032
+ // Key(3) .. Key(17)
2033
+ const auto verify_db = [&]() {
2034
+ for (int i = 0; i < kNumKeys; i++) {
2035
+ std::string value;
2036
+ auto s = db_->Get(ReadOptions(), Key(i), &value);
2037
+ if (i == 4 || i == 5 || i == 7 || i == 9 || i == 10) {
2038
+ ASSERT_TRUE(s.IsNotFound());
2039
+ } else {
2040
+ ASSERT_OK(s);
2041
+ }
2042
+ }
2043
+ };
1941
2044
  Random rnd(301);
1942
-
1943
- for (int i = 0; i < 300; i++) {
1944
- ASSERT_OK(Put(Key(i), rnd.RandomString(100)));
1945
- dbfull()->TEST_WaitForPeridicTaskRun(
1946
- [&] { mock_clock_->MockSleepForSeconds(kKeyPerSec); });
2045
+ for (int i = 0; i < kNumKeys; i++) {
2046
+ ASSERT_OK(Put(Key(i + 3), rnd.RandomString(kValueBytes)));
2047
+ dbfull()->TEST_WaitForPeriodicTaskRun(
2048
+ [&] { mock_clock_->MockSleepForSeconds(kSecondsPerKey); });
1947
2049
  }
1948
- ASSERT_OK(Flush());
1949
- CompactRangeOptions cro;
1950
- cro.bottommost_level_compaction = BottommostLevelCompaction::kForce;
1951
-
1952
- ASSERT_OK(db_->CompactRange(cro, nullptr, nullptr));
1953
-
1954
- // make sure all data is compacted to the last level
1955
- ASSERT_EQ("0,0,0,0,0,0,1", FilesPerLevel());
1956
-
1957
- // Create 3 L5 files
1958
- auto factory = std::make_shared<ThreeRangesPartitionerFactory>();
1959
- options.sst_partitioner_factory = factory;
1960
-
1961
- // the user defined properties_collector will mark the 3rd file for compaction
1962
- auto collector_factory = std::make_shared<TestPropertiesCollectorFactory>();
1963
- options.table_properties_collector_factories.resize(1);
1964
- options.table_properties_collector_factories[0] = collector_factory;
1965
- // enable tiered storage feature
1966
- options.preclude_last_level_data_seconds = 10000;
1967
- options.last_level_temperature = Temperature::kCold;
1968
- Reopen(options);
1969
-
1970
- for (int i = 0; i < kNumTrigger - 2; i++) {
1971
- for (int j = 0; j < 100; j++) {
1972
- ASSERT_OK(Put(Key(i * 100 + j), rnd.RandomString(10)));
1973
- }
1974
- ASSERT_OK(Flush());
2050
+ auto* snap1 = db_->GetSnapshot();
2051
+ for (int i = 0; i < kNumKeys; i++) {
2052
+ ASSERT_OK(Put(Key(i), rnd.RandomString(kValueBytes)));
2053
+ dbfull()->TEST_WaitForPeriodicTaskRun(
2054
+ [&] { mock_clock_->MockSleepForSeconds(kSecondsPerKey); });
1975
2055
  }
2056
+ auto* snap2 = db_->GetSnapshot();
2057
+ ASSERT_OK(db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(),
2058
+ Key(kNumKeysPerFile - 1),
2059
+ Key(kNumKeysPerFile + 1)));
2060
+ ASSERT_OK(db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(),
2061
+ Key(kNumKeysPerFile + 2),
2062
+ Key(kNumKeysPerFile + 3)));
2063
+ ASSERT_OK(db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(),
2064
+ Key(2 * kNumKeysPerFile - 1),
2065
+ Key(2 * kNumKeysPerFile + 1)));
2066
+ ASSERT_OK(Flush());
2067
+ dbfull()->TEST_WaitForPeriodicTaskRun(
2068
+ [&] { mock_clock_->MockSleepForSeconds(kSecondsPerKey); });
2069
+ verify_db();
1976
2070
 
1977
- // make sure there is one and only one compaction supports per-key placement
1978
- // but has the penultimate level output disabled.
2071
+ // Count compactions supporting per-key placement
1979
2072
  std::atomic_int per_key_comp_num = 0;
1980
2073
  SyncPoint::GetInstance()->SetCallBack(
1981
2074
  "UniversalCompactionBuilder::PickCompaction:Return", [&](void* arg) {
1982
2075
  auto compaction = static_cast<Compaction*>(arg);
1983
2076
  if (compaction->SupportsPerKeyPlacement()) {
1984
2077
  ASSERT_EQ(compaction->GetPenultimateOutputRangeType(),
1985
- Compaction::PenultimateOutputRangeType::kDisabled);
2078
+ Compaction::PenultimateOutputRangeType::kNonLastRange);
1986
2079
  per_key_comp_num++;
1987
2080
  }
1988
2081
  });
1989
-
1990
2082
  SyncPoint::GetInstance()->EnableProcessing();
1991
2083
 
1992
- for (int j = 0; j < 100; j++) {
1993
- ASSERT_OK(Put(Key(200 + j), rnd.RandomString(10)));
1994
- }
1995
- ASSERT_OK(db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(),
1996
- Key(32), Key(40)));
1997
- ASSERT_OK(Flush());
1998
-
1999
- // Before the per-key placement compaction, the LSM tress should be like:
2000
- // L5: [0,19] [20,40] [40,299]
2001
- // L6: [0, 299]
2002
- // The 2nd file @L5 has the largest key 40 because of range del
2003
-
2084
+ // The `CompactRange()` writes the following files to L5.
2085
+ //
2086
+ // [key000000#16,kTypeValue,
2087
+ // key000005#kMaxSequenceNumber,kTypeRangeDeletion]
2088
+ // [key000005#21,kTypeValue,
2089
+ // key000010#kMaxSequenceNumber,kTypeRangeDeletion]
2090
+ // [key000010#26,kTypeValue, key000014#30,kTypeValue]
2091
+ //
2092
+ // And it writes the following files to L6.
2093
+ //
2094
+ // [key000003#1,kTypeValue, key000007#5,kTypeValue]
2095
+ // [key000008#6,kTypeValue, key000012#10,kTypeValue]
2096
+ // [key000013#11,kTypeValue, key000017#15,kTypeValue]
2097
+ CompactRangeOptions cro;
2098
+ cro.bottommost_level_compaction = BottommostLevelCompaction::kForce;
2099
+ ASSERT_OK(db_->CompactRange(cro, nullptr, nullptr));
2100
+ ASSERT_EQ("0,0,0,0,0,3,3", FilesPerLevel());
2101
+ verify_db();
2102
+
2103
+ // Rewrite the middle file only. File endpoints should not change.
2104
+ std::string begin_key_buf = Key(kNumKeysPerFile + 1),
2105
+ end_key_buf = Key(kNumKeysPerFile + 2);
2106
+ Slice begin_key(begin_key_buf), end_key(end_key_buf);
2107
+ ASSERT_OK(db_->SuggestCompactRange(db_->DefaultColumnFamily(), &begin_key,
2108
+ &end_key));
2004
2109
  ASSERT_OK(dbfull()->WaitForCompact(true));
2110
+ ASSERT_EQ("0,0,0,0,0,3,3", FilesPerLevel());
2111
+ ASSERT_EQ(1, per_key_comp_num);
2112
+ verify_db();
2005
2113
 
2006
- ASSERT_EQ(per_key_comp_num, 1);
2007
-
2008
- // the compaction won't move any data to the penultimate level
2114
+ // Rewrite the middle file again after releasing snap2. Still file endpoints
2115
+ // should not change.
2116
+ db_->ReleaseSnapshot(snap2);
2117
+ ASSERT_OK(db_->SuggestCompactRange(db_->DefaultColumnFamily(), &begin_key,
2118
+ &end_key));
2119
+ ASSERT_OK(dbfull()->WaitForCompact(true));
2120
+ ASSERT_EQ("0,0,0,0,0,3,3", FilesPerLevel());
2121
+ ASSERT_EQ(2, per_key_comp_num);
2122
+ verify_db();
2123
+
2124
+ // Middle file once more after releasing snap1. This time the data in the
2125
+ // middle L5 file can all be compacted to the last level.
2126
+ db_->ReleaseSnapshot(snap1);
2127
+ ASSERT_OK(db_->SuggestCompactRange(db_->DefaultColumnFamily(), &begin_key,
2128
+ &end_key));
2129
+ ASSERT_OK(dbfull()->WaitForCompact(true));
2009
2130
  ASSERT_EQ("0,0,0,0,0,2,3", FilesPerLevel());
2131
+ ASSERT_EQ(3, per_key_comp_num);
2132
+ verify_db();
2133
+
2134
+ // Finish off the penultimate level.
2135
+ ASSERT_OK(db_->CompactRange(cro, nullptr, nullptr));
2136
+ ASSERT_EQ("0,0,0,0,0,0,3", FilesPerLevel());
2137
+ verify_db();
2010
2138
 
2011
2139
  Close();
2012
2140
  }