@nxtedition/rocksdb 8.0.3 → 8.0.5

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 (59) hide show
  1. package/BUILDING.md +2 -2
  2. package/binding.cc +7 -2
  3. package/deps/rocksdb/rocksdb/CMakeLists.txt +7 -0
  4. package/deps/rocksdb/rocksdb/Makefile +13 -1
  5. package/deps/rocksdb/rocksdb/db/builder.cc +13 -4
  6. package/deps/rocksdb/rocksdb/db/builder.h +2 -1
  7. package/deps/rocksdb/rocksdb/db/c.cc +6 -0
  8. package/deps/rocksdb/rocksdb/db/column_family.cc +1 -0
  9. package/deps/rocksdb/rocksdb/db/compaction/compaction.cc +18 -4
  10. package/deps/rocksdb/rocksdb/db/compaction/compaction_job.cc +2 -0
  11. package/deps/rocksdb/rocksdb/db/compaction/compaction_job_test.cc +2 -1
  12. package/deps/rocksdb/rocksdb/db/compaction/compaction_outputs.cc +39 -19
  13. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker.cc +5 -1
  14. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_level.cc +14 -14
  15. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_test.cc +1 -2
  16. package/deps/rocksdb/rocksdb/db/db_bloom_filter_test.cc +2 -3
  17. package/deps/rocksdb/rocksdb/db/db_compaction_test.cc +289 -0
  18. package/deps/rocksdb/rocksdb/db/db_impl/db_impl.cc +8 -9
  19. package/deps/rocksdb/rocksdb/db/db_impl/db_impl.h +0 -8
  20. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_compaction_flush.cc +118 -26
  21. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_experimental.cc +2 -1
  22. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_open.cc +12 -8
  23. package/deps/rocksdb/rocksdb/db/db_range_del_test.cc +115 -2
  24. package/deps/rocksdb/rocksdb/db/experimental.cc +2 -1
  25. package/deps/rocksdb/rocksdb/db/external_sst_file_basic_test.cc +1 -0
  26. package/deps/rocksdb/rocksdb/db/external_sst_file_ingestion_job.cc +88 -12
  27. package/deps/rocksdb/rocksdb/db/external_sst_file_ingestion_job.h +38 -1
  28. package/deps/rocksdb/rocksdb/db/external_sst_file_test.cc +14 -110
  29. package/deps/rocksdb/rocksdb/db/flush_job.cc +2 -3
  30. package/deps/rocksdb/rocksdb/db/import_column_family_job.cc +1 -1
  31. package/deps/rocksdb/rocksdb/db/range_tombstone_fragmenter_test.cc +1 -1
  32. package/deps/rocksdb/rocksdb/db/repair.cc +2 -1
  33. package/deps/rocksdb/rocksdb/db/version_builder_test.cc +41 -39
  34. package/deps/rocksdb/rocksdb/db/version_edit.cc +12 -0
  35. package/deps/rocksdb/rocksdb/db/version_edit.h +18 -6
  36. package/deps/rocksdb/rocksdb/db/version_edit_test.cc +9 -9
  37. package/deps/rocksdb/rocksdb/db/version_set.cc +12 -6
  38. package/deps/rocksdb/rocksdb/db/version_set_test.cc +23 -9
  39. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_common.h +1 -0
  40. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_env_wrapper.h +8 -6
  41. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_gflags.cc +4 -0
  42. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_test_base.cc +11 -4
  43. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_tool.cc +12 -13
  44. package/deps/rocksdb/rocksdb/db_stress_tool/no_batched_ops_stress.cc +13 -1
  45. package/deps/rocksdb/rocksdb/file/file_prefetch_buffer.cc +14 -1
  46. package/deps/rocksdb/rocksdb/include/rocksdb/c.h +4 -0
  47. package/deps/rocksdb/rocksdb/include/rocksdb/listener.h +7 -1
  48. package/deps/rocksdb/rocksdb/include/rocksdb/options.h +2 -1
  49. package/deps/rocksdb/rocksdb/include/rocksdb/utilities/backup_engine.h +69 -9
  50. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader_impl.h +6 -2
  51. package/deps/rocksdb/rocksdb/utilities/backup/backup_engine.cc +245 -74
  52. package/deps/rocksdb/rocksdb/utilities/backup/backup_engine_test.cc +195 -4
  53. package/deps/rocksdb/rocksdb/utilities/fault_injection_fs.cc +39 -0
  54. package/deps/rocksdb/rocksdb/utilities/fault_injection_fs.h +9 -0
  55. package/max_rev_operator.h +100 -0
  56. package/package.json +1 -1
  57. package/prebuilds/darwin-arm64/node.napi.node +0 -0
  58. package/prebuilds/darwin-x64/node.napi.node +0 -0
  59. package/prebuilds/linux-x64/node.napi.node +0 -0
package/BUILDING.md CHANGED
@@ -10,9 +10,9 @@
10
10
  - Copy `libfolly.a` to `/usr/lib/x86_64-linux-gnu`.
11
11
  - Copy headers to `/usr/lib/x86_64-linux-gnu/include`.
12
12
  - Copy boost headers from folly scratchpad to `/usr/lib/x86_64-linux-gnu/include`.
13
- - `JOBS=8 npx prebuildify -t 18.11.0 --napi --strip --arch x64`
13
+ - `JONS=16 npx prebuildify -t 18.11.0 --napi --strip --arch x64`
14
14
 
15
15
  # OSX
16
16
 
17
17
  - `brew install zstd`
18
- - `JOBS=8 npx prebuildify -t 18.11.0 --napi --strip --arch arm64`
18
+ - `JONS=16 npx prebuildify -t 18.11.0 --napi --strip --arch arm64`
package/binding.cc CHANGED
@@ -26,6 +26,7 @@
26
26
  #include <thread>
27
27
  #include <vector>
28
28
 
29
+ #include "max_rev_operator.h"
29
30
  #include "util.h"
30
31
 
31
32
  class NullLogger : public rocksdb::Logger {
@@ -556,8 +557,12 @@ napi_status InitOptions(napi_env env, T& columnOptions, const U& options) {
556
557
  std::optional<std::string> mergeOperatorOpt;
557
558
  NAPI_STATUS_RETURN(GetProperty(env, options, "mergeOperator", mergeOperatorOpt));
558
559
  if (mergeOperatorOpt) {
559
- ROCKS_STATUS_RETURN_NAPI(
560
- rocksdb::MergeOperator::CreateFromString(configOptions, *mergeOperatorOpt, &columnOptions.merge_operator));
560
+ if (*mergeOperatorOpt == "maxRev") {
561
+ columnOptions.merge_operator = std::make_shared<MaxRevOperator>();
562
+ } else {
563
+ ROCKS_STATUS_RETURN_NAPI(
564
+ rocksdb::MergeOperator::CreateFromString(configOptions, *mergeOperatorOpt, &columnOptions.merge_operator));
565
+ }
561
566
  }
562
567
 
563
568
  std::optional<std::string> compactionPriority;
@@ -980,6 +980,12 @@ if ( ROCKSDB_PLUGINS )
980
980
  plugin/${plugin}/${src}
981
981
  PROPERTIES COMPILE_FLAGS "${${plugin}_COMPILE_FLAGS}")
982
982
  endforeach()
983
+ foreach (test ${${plugin}_TESTS})
984
+ list(APPEND PLUGIN_TESTS plugin/${plugin}/${test})
985
+ set_source_files_properties(
986
+ plugin/${plugin}/${test}
987
+ PROPERTIES COMPILE_FLAGS "${${plugin}_COMPILE_FLAGS}")
988
+ endforeach()
983
989
  foreach (path ${${plugin}_INCLUDE_PATHS})
984
990
  include_directories(${path})
985
991
  endforeach()
@@ -1471,6 +1477,7 @@ if(WITH_TESTS)
1471
1477
  utilities/ttl/ttl_test.cc
1472
1478
  utilities/util_merge_operators_test.cc
1473
1479
  utilities/write_batch_with_index/write_batch_with_index_test.cc
1480
+ ${PLUGIN_TESTS}
1474
1481
  )
1475
1482
  endif()
1476
1483
 
@@ -266,6 +266,7 @@ ROCKSDB_PLUGIN_EXTERNS = $(foreach p, $(ROCKSDB_PLUGIN_W_FUNCS), int $($(p)_FUNC
266
266
  ROCKSDB_PLUGIN_BUILTINS = $(foreach p, $(ROCKSDB_PLUGIN_W_FUNCS), {\"$(p)\"\, $($(p)_FUNC)}\,)
267
267
  ROCKSDB_PLUGIN_LDFLAGS = $(foreach plugin, $(ROCKSDB_PLUGINS), $($(plugin)_LDFLAGS))
268
268
  ROCKSDB_PLUGIN_PKGCONFIG_REQUIRES = $(foreach plugin, $(ROCKSDB_PLUGINS), $($(plugin)_PKGCONFIG_REQUIRES))
269
+ ROCKSDB_PLUGIN_TESTS = $(foreach p, $(ROCKSDB_PLUGINS), $(foreach test, $($(p)_TESTS), plugin/$(p)/$(test)))
269
270
 
270
271
  CXXFLAGS += $(foreach plugin, $(ROCKSDB_PLUGINS), $($(plugin)_CXXFLAGS))
271
272
  PLATFORM_LDFLAGS += $(ROCKSDB_PLUGIN_LDFLAGS)
@@ -647,10 +648,12 @@ STRESS_OBJECTS = $(patsubst %.cc, $(OBJ_DIR)/%.o, $(STRESS_LIB_SOURCES))
647
648
  ALL_SOURCES = $(filter-out util/build_version.cc, $(LIB_SOURCES)) $(TEST_LIB_SOURCES) $(MOCK_LIB_SOURCES) $(GTEST_DIR)/gtest/gtest-all.cc
648
649
  ALL_SOURCES += $(TOOL_LIB_SOURCES) $(BENCH_LIB_SOURCES) $(CACHE_BENCH_LIB_SOURCES) $(ANALYZER_LIB_SOURCES) $(STRESS_LIB_SOURCES)
649
650
  ALL_SOURCES += $(TEST_MAIN_SOURCES) $(TOOL_MAIN_SOURCES) $(BENCH_MAIN_SOURCES)
650
- ALL_SOURCES += $(ROCKSDB_PLUGIN_SOURCES)
651
+ ALL_SOURCES += $(ROCKSDB_PLUGIN_SOURCES) $(ROCKSDB_PLUGIN_TESTS)
651
652
 
653
+ PLUGIN_TESTS = $(patsubst %.cc, %, $(notdir $(ROCKSDB_PLUGIN_TESTS)))
652
654
  TESTS = $(patsubst %.cc, %, $(notdir $(TEST_MAIN_SOURCES)))
653
655
  TESTS += $(patsubst %.c, %, $(notdir $(TEST_MAIN_SOURCES_C)))
656
+ TESTS += $(PLUGIN_TESTS)
654
657
 
655
658
  # `make check-headers` to very that each header file includes its own
656
659
  # dependencies
@@ -702,6 +705,7 @@ NON_PARALLEL_TEST = \
702
705
  env_test \
703
706
  deletefile_test \
704
707
  db_bloom_filter_test \
708
+ $(PLUGIN_TESTS) \
705
709
 
706
710
  PARALLEL_TEST = $(filter-out $(NON_PARALLEL_TEST), $(TESTS))
707
711
 
@@ -1355,6 +1359,14 @@ db_sanity_test: $(OBJ_DIR)/tools/db_sanity_test.o $(LIBRARY)
1355
1359
  db_repl_stress: $(OBJ_DIR)/tools/db_repl_stress.o $(LIBRARY)
1356
1360
  $(AM_LINK)
1357
1361
 
1362
+ define MakeTestRule
1363
+ $(notdir $(1:%.cc=%)): $(1:%.cc=$$(OBJ_DIR)/%.o) $$(TEST_LIBRARY) $$(LIBRARY)
1364
+ $$(AM_LINK)
1365
+ endef
1366
+
1367
+ # For each PLUGIN test, create a rule to generate the test executable
1368
+ $(foreach test, $(ROCKSDB_PLUGIN_TESTS), $(eval $(call MakeTestRule, $(test))))
1369
+
1358
1370
  arena_test: $(OBJ_DIR)/memory/arena_test.o $(TEST_LIBRARY) $(LIBRARY)
1359
1371
  $(AM_LINK)
1360
1372
 
@@ -71,8 +71,9 @@ Status BuildTable(
71
71
  int job_id, const Env::IOPriority io_priority,
72
72
  TableProperties* table_properties, Env::WriteLifeTimeHint write_hint,
73
73
  const std::string* full_history_ts_low,
74
- BlobFileCompletionCallback* blob_callback, uint64_t* num_input_entries,
75
- uint64_t* memtable_payload_bytes, uint64_t* memtable_garbage_bytes) {
74
+ BlobFileCompletionCallback* blob_callback, Version* version,
75
+ uint64_t* num_input_entries, uint64_t* memtable_payload_bytes,
76
+ uint64_t* memtable_garbage_bytes) {
76
77
  assert((tboptions.column_family_id ==
77
78
  TablePropertiesCollectorFactory::Context::kUnknownColumnFamily) ==
78
79
  tboptions.column_family_name.empty());
@@ -246,9 +247,17 @@ Status BuildTable(
246
247
  auto tombstone = range_del_it->Tombstone();
247
248
  auto kv = tombstone.Serialize();
248
249
  builder->Add(kv.first.Encode(), kv.second);
249
- meta->UpdateBoundariesForRange(kv.first, tombstone.SerializeEndKey(),
250
- tombstone.seq_,
250
+ InternalKey tombstone_end = tombstone.SerializeEndKey();
251
+ meta->UpdateBoundariesForRange(kv.first, tombstone_end, tombstone.seq_,
251
252
  tboptions.internal_comparator);
253
+ if (version) {
254
+ SizeApproximationOptions approx_opts;
255
+ approx_opts.files_size_error_margin = 0.1;
256
+ meta->compensated_range_deletion_size += versions->ApproximateSize(
257
+ approx_opts, version, kv.first.Encode(), tombstone_end.Encode(),
258
+ 0 /* start_level */, -1 /* end_level */,
259
+ TableReaderCaller::kFlush);
260
+ }
252
261
  }
253
262
  }
254
263
 
@@ -13,6 +13,7 @@
13
13
  #include "db/range_tombstone_fragmenter.h"
14
14
  #include "db/seqno_to_time_mapping.h"
15
15
  #include "db/table_properties_collector.h"
16
+ #include "db/version_set.h"
16
17
  #include "logging/event_logger.h"
17
18
  #include "options/cf_options.h"
18
19
  #include "rocksdb/comparator.h"
@@ -70,7 +71,7 @@ extern Status BuildTable(
70
71
  Env::WriteLifeTimeHint write_hint = Env::WLTH_NOT_SET,
71
72
  const std::string* full_history_ts_low = nullptr,
72
73
  BlobFileCompletionCallback* blob_callback = nullptr,
73
- uint64_t* num_input_entries = nullptr,
74
+ Version* version = nullptr, uint64_t* num_input_entries = nullptr,
74
75
  uint64_t* memtable_payload_bytes = nullptr,
75
76
  uint64_t* memtable_garbage_bytes = nullptr);
76
77
 
@@ -2588,6 +2588,12 @@ void rocksdb_block_based_options_set_partition_filters(
2588
2588
  options->rep.partition_filters = partition_filters;
2589
2589
  }
2590
2590
 
2591
+ void rocksdb_block_based_options_set_optimize_filters_for_memory(
2592
+ rocksdb_block_based_table_options_t* options,
2593
+ unsigned char optimize_filters_for_memory) {
2594
+ options->rep.optimize_filters_for_memory = optimize_filters_for_memory;
2595
+ }
2596
+
2591
2597
  void rocksdb_block_based_options_set_use_delta_encoding(
2592
2598
  rocksdb_block_based_table_options_t* options,
2593
2599
  unsigned char use_delta_encoding) {
@@ -1218,6 +1218,7 @@ Compaction* ColumnFamilyData::CompactRange(
1218
1218
  if (result != nullptr) {
1219
1219
  result->SetInputVersion(current_);
1220
1220
  }
1221
+ TEST_SYNC_POINT("ColumnFamilyData::CompactRange:Return");
1221
1222
  return result;
1222
1223
  }
1223
1224
 
@@ -235,12 +235,19 @@ Compaction::Compaction(
235
235
  inputs_(PopulateWithAtomicBoundaries(vstorage, std::move(_inputs))),
236
236
  grandparents_(std::move(_grandparents)),
237
237
  score_(_score),
238
- bottommost_level_(IsBottommostLevel(output_level_, vstorage, inputs_)),
238
+ bottommost_level_(
239
+ // For simplicity, we don't support the concept of "bottommost level"
240
+ // with
241
+ // `CompactionReason::kExternalSstIngestion` and
242
+ // `CompactionReason::kRefitLevel`
243
+ (_compaction_reason == CompactionReason::kExternalSstIngestion ||
244
+ _compaction_reason == CompactionReason::kRefitLevel)
245
+ ? false
246
+ : IsBottommostLevel(output_level_, vstorage, inputs_)),
239
247
  is_full_compaction_(IsFullCompaction(vstorage, inputs_)),
240
248
  is_manual_compaction_(_manual_compaction),
241
249
  trim_ts_(_trim_ts),
242
250
  is_trivial_move_(false),
243
-
244
251
  compaction_reason_(_compaction_reason),
245
252
  notify_on_compaction_completion_(false),
246
253
  enable_blob_garbage_collection_(
@@ -255,8 +262,15 @@ Compaction::Compaction(
255
262
  _blob_garbage_collection_age_cutoff > 1
256
263
  ? mutable_cf_options()->blob_garbage_collection_age_cutoff
257
264
  : _blob_garbage_collection_age_cutoff),
258
- penultimate_level_(EvaluatePenultimateLevel(
259
- vstorage, immutable_options_, start_level_, output_level_)) {
265
+ penultimate_level_(
266
+ // For simplicity, we don't support the concept of "penultimate level"
267
+ // with `CompactionReason::kExternalSstIngestion` and
268
+ // `CompactionReason::kRefitLevel`
269
+ _compaction_reason == CompactionReason::kExternalSstIngestion ||
270
+ _compaction_reason == CompactionReason::kRefitLevel
271
+ ? Compaction::kInvalidLevel
272
+ : EvaluatePenultimateLevel(vstorage, immutable_options_,
273
+ start_level_, output_level_)) {
260
274
  MarkFilesBeingCompacted(true);
261
275
  if (is_manual_compaction_) {
262
276
  compaction_reason_ = CompactionReason::kManualCompaction;
@@ -99,6 +99,8 @@ const char* GetCompactionReasonString(CompactionReason compaction_reason) {
99
99
  return "ForcedBlobGC";
100
100
  case CompactionReason::kRoundRobinTtl:
101
101
  return "RoundRobinTtl";
102
+ case CompactionReason::kRefitLevel:
103
+ return "RefitLevel";
102
104
  case CompactionReason::kNumOfReasons:
103
105
  // fall through
104
106
  default:
@@ -386,7 +386,8 @@ class CompactionJobTestBase : public testing::Test {
386
386
  oldest_blob_file_number, kUnknownOldestAncesterTime,
387
387
  kUnknownFileCreationTime,
388
388
  versions_->GetColumnFamilySet()->GetDefault()->NewEpochNumber(),
389
- kUnknownFileChecksum, kUnknownFileChecksumFuncName, kNullUniqueId64x2);
389
+ kUnknownFileChecksum, kUnknownFileChecksumFuncName, kNullUniqueId64x2,
390
+ 0);
390
391
 
391
392
  mutex_.Lock();
392
393
  EXPECT_OK(
@@ -525,30 +525,26 @@ Status CompactionOutputs::AddRangeDels(
525
525
  ucmp->CompareWithoutTimestamp(*lower_bound, kv.second) < 0);
526
526
  // Range tombstone is not supported by output validator yet.
527
527
  builder_->Add(kv.first.Encode(), kv.second);
528
- InternalKey smallest_candidate = std::move(kv.first);
528
+ InternalKey tombstone_start = std::move(kv.first);
529
+ InternalKey smallest_candidate{tombstone_start};
529
530
  if (lower_bound != nullptr &&
530
531
  ucmp->CompareWithoutTimestamp(smallest_candidate.user_key(),
531
532
  *lower_bound) <= 0) {
532
533
  // Pretend the smallest key has the same user key as lower_bound
533
534
  // (the max key in the previous table or subcompaction) in order for
534
535
  // files to appear key-space partitioned.
535
- //
536
- // When lower_bound is chosen by a subcompaction, we know that
537
- // subcompactions over smaller keys cannot contain any keys at
538
- // lower_bound. We also know that smaller subcompactions exist,
539
- // because otherwise the subcompaction woud be unbounded on the left.
540
- // As a result, we know that no other files on the output level will
541
- // contain actual keys at lower_bound (an output file may have a
542
- // largest key of lower_bound@kMaxSequenceNumber, but this only
543
- // indicates a large range tombstone was truncated). Therefore, it is
544
- // safe to use the tombstone's sequence number, to ensure that keys at
545
- // lower_bound at lower levels are covered by truncated tombstones.
546
- //
547
- // If lower_bound was chosen by the smallest data key in the file,
548
- // choose lowest seqnum so this file's smallest internal key comes
549
- // after the previous file's largest. The fake seqnum is OK because
550
- // the read path's file-picking code only considers user key.
551
536
  if (lower_bound_from_sub_compact) {
537
+ // When lower_bound is chosen by a subcompaction
538
+ // (lower_bound_from_sub_compact), we know that subcompactions over
539
+ // smaller keys cannot contain any keys at lower_bound. We also know
540
+ // that smaller subcompactions exist, because otherwise the
541
+ // subcompaction woud be unbounded on the left. As a result, we know
542
+ // that no other files on the output level will contain actual keys at
543
+ // lower_bound (an output file may have a largest key of
544
+ // lower_bound@kMaxSequenceNumber, but this only indicates a large range
545
+ // tombstone was truncated). Therefore, it is safe to use the
546
+ // tombstone's sequence number, to ensure that keys at lower_bound at
547
+ // lower levels are covered by truncated tombstones.
552
548
  if (ts_sz) {
553
549
  assert(tombstone.ts_.size() == ts_sz);
554
550
  smallest_candidate = InternalKey(*lower_bound, tombstone.seq_,
@@ -558,6 +554,7 @@ Status CompactionOutputs::AddRangeDels(
558
554
  InternalKey(*lower_bound, tombstone.seq_, kTypeRangeDeletion);
559
555
  }
560
556
  } else if (lower_bound_from_range_tombstone) {
557
+ // When lower_bound is chosen from a range tombtone start key:
561
558
  // Range tombstone keys can be truncated at file boundaries of the files
562
559
  // that contain them.
563
560
  //
@@ -591,10 +588,15 @@ Status CompactionOutputs::AddRangeDels(
591
588
  smallest_candidate = range_tombstone_lower_bound_;
592
589
  }
593
590
  } else {
591
+ // If lower_bound was chosen by the smallest data key in the file,
592
+ // choose lowest seqnum so this file's smallest internal key comes
593
+ // after the previous file's largest. The fake seqnum is OK because
594
+ // the read path's file-picking code only considers user key.
594
595
  smallest_candidate = InternalKey(*lower_bound, 0, kTypeRangeDeletion);
595
596
  }
596
597
  }
597
- InternalKey largest_candidate = tombstone.SerializeEndKey();
598
+ InternalKey tombstone_end = tombstone.SerializeEndKey();
599
+ InternalKey largest_candidate{tombstone_end};
598
600
  if (upper_bound != nullptr &&
599
601
  ucmp->CompareWithoutTimestamp(*upper_bound,
600
602
  largest_candidate.user_key()) <= 0) {
@@ -636,11 +638,29 @@ Status CompactionOutputs::AddRangeDels(
636
638
  #endif
637
639
  meta.UpdateBoundariesForRange(smallest_candidate, largest_candidate,
638
640
  tombstone.seq_, icmp);
641
+ if (!bottommost_level) {
642
+ // Range tombstones are truncated at file boundaries
643
+ if (icmp.Compare(tombstone_start, meta.smallest) < 0) {
644
+ tombstone_start = meta.smallest;
645
+ }
646
+ if (icmp.Compare(tombstone_end, meta.largest) > 0) {
647
+ tombstone_end = meta.largest;
648
+ }
649
+ SizeApproximationOptions approx_opts;
650
+ approx_opts.files_size_error_margin = 0.1;
651
+ auto approximate_covered_size =
652
+ compaction_->input_version()->version_set()->ApproximateSize(
653
+ approx_opts, compaction_->input_version(),
654
+ tombstone_start.Encode(), tombstone_end.Encode(),
655
+ compaction_->output_level() + 1 /* start_level */,
656
+ -1 /* end_level */, kCompaction);
657
+ meta.compensated_range_deletion_size += approximate_covered_size;
658
+ }
639
659
  // The smallest key in a file is used for range tombstone truncation, so
640
660
  // it cannot have a seqnum of 0 (unless the smallest data key in a file
641
661
  // has a seqnum of 0). Otherwise, the truncated tombstone may expose
642
662
  // deleted keys at lower levels.
643
- assert(smallest_ikey_seqnum == 0 ||
663
+ assert(smallest_ikey_seqnum == 0 || lower_bound_from_range_tombstone ||
644
664
  ExtractInternalKeyFooter(meta.smallest.Encode()) !=
645
665
  PackSequenceAndType(0, kTypeRangeDeletion));
646
666
  }
@@ -1126,7 +1126,11 @@ void CompactionPicker::RegisterCompaction(Compaction* c) {
1126
1126
  c->output_level() == 0 ||
1127
1127
  !FilesRangeOverlapWithCompaction(*c->inputs(), c->output_level(),
1128
1128
  c->GetPenultimateLevel()));
1129
- if (c->start_level() == 0 ||
1129
+ // CompactionReason::kExternalSstIngestion's start level is just a placeholder
1130
+ // number without actual meaning as file ingestion technically does not have
1131
+ // an input level like other compactions
1132
+ if ((c->start_level() == 0 &&
1133
+ c->compaction_reason() != CompactionReason::kExternalSstIngestion) ||
1130
1134
  ioptions_.compaction_style == kCompactionStyleUniversal) {
1131
1135
  level0_compactions_in_progress_.insert(c);
1132
1136
  }
@@ -447,21 +447,21 @@ bool LevelCompactionBuilder::SetupOtherInputsIfNeeded() {
447
447
  compaction_inputs_.push_back(output_level_inputs_);
448
448
  }
449
449
 
450
+ // In some edge cases we could pick a compaction that will be compacting
451
+ // a key range that overlap with another running compaction, and both
452
+ // of them have the same output level. This could happen if
453
+ // (1) we are running a non-exclusive manual compaction
454
+ // (2) AddFile ingest a new file into the LSM tree
455
+ // We need to disallow this from happening.
456
+ if (compaction_picker_->FilesRangeOverlapWithCompaction(
457
+ compaction_inputs_, output_level_,
458
+ Compaction::EvaluatePenultimateLevel(
459
+ vstorage_, ioptions_, start_level_, output_level_))) {
460
+ // This compaction output could potentially conflict with the output
461
+ // of a currently running compaction, we cannot run it.
462
+ return false;
463
+ }
450
464
  if (!is_l0_trivial_move_) {
451
- // In some edge cases we could pick a compaction that will be compacting
452
- // a key range that overlap with another running compaction, and both
453
- // of them have the same output level. This could happen if
454
- // (1) we are running a non-exclusive manual compaction
455
- // (2) AddFile ingest a new file into the LSM tree
456
- // We need to disallow this from happening.
457
- if (compaction_picker_->FilesRangeOverlapWithCompaction(
458
- compaction_inputs_, output_level_,
459
- Compaction::EvaluatePenultimateLevel(
460
- vstorage_, ioptions_, start_level_, output_level_))) {
461
- // This compaction output could potentially conflict with the output
462
- // of a currently running compaction, we cannot run it.
463
- return false;
464
- }
465
465
  compaction_picker_->GetGrandparents(vstorage_, start_level_inputs_,
466
466
  output_level_inputs_, &grandparents_);
467
467
  }
@@ -148,7 +148,7 @@ class CompactionPickerTestBase : public testing::Test {
148
148
  smallest_seq, largest_seq, marked_for_compact, temperature,
149
149
  kInvalidBlobFileNumber, kUnknownOldestAncesterTime,
150
150
  kUnknownFileCreationTime, epoch_number, kUnknownFileChecksum,
151
- kUnknownFileChecksumFuncName, kNullUniqueId64x2);
151
+ kUnknownFileChecksumFuncName, kNullUniqueId64x2, 0);
152
152
  f->compensated_file_size =
153
153
  (compensated_file_size != 0) ? compensated_file_size : file_size;
154
154
  f->oldest_ancester_time = oldest_ancestor_time;
@@ -2873,7 +2873,6 @@ TEST_F(CompactionPickerTest, IntraL0MaxCompactionBytesHit) {
2873
2873
  ASSERT_EQ(0, compaction->output_level());
2874
2874
  }
2875
2875
 
2876
-
2877
2876
  #ifndef ROCKSDB_LITE
2878
2877
  TEST_F(CompactionPickerTest, UniversalMarkedCompactionFullOverlap) {
2879
2878
  const uint64_t kFileSize = 100000;
@@ -1229,7 +1229,7 @@ TEST_P(ChargeFilterConstructionTestWithParam, Basic) {
1229
1229
  *
1230
1230
  * The test is designed in a way such that the reservation for (p1 - b')
1231
1231
  * will trigger at least another dummy entry insertion
1232
- * (or equivelantly to saying, creating another peak).
1232
+ * (or equivalently to saying, creating another peak).
1233
1233
  *
1234
1234
  * kStandard128Ribbon + FullFilter +
1235
1235
  * detect_filter_construct_corruption
@@ -2618,8 +2618,7 @@ TEST_F(DBBloomFilterTest, OptimizeFiltersForHits) {
2618
2618
  BottommostLevelCompaction::kSkip;
2619
2619
  compact_options.change_level = true;
2620
2620
  compact_options.target_level = 7;
2621
- ASSERT_TRUE(db_->CompactRange(compact_options, handles_[1], nullptr, nullptr)
2622
- .IsNotSupported());
2621
+ ASSERT_OK(db_->CompactRange(compact_options, handles_[1], nullptr, nullptr));
2623
2622
 
2624
2623
  ASSERT_EQ(trivial_move, 1);
2625
2624
  ASSERT_EQ(non_trivial_move, 0);