@nxtedition/rocksdb 7.0.39 → 7.0.42

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 (64) hide show
  1. package/binding.cc +59 -30
  2. package/deps/rocksdb/rocksdb/cache/cache_bench_tool.cc +27 -11
  3. package/deps/rocksdb/rocksdb/cache/clock_cache.cc +310 -337
  4. package/deps/rocksdb/rocksdb/cache/clock_cache.h +394 -352
  5. package/deps/rocksdb/rocksdb/db/blob/blob_file_reader.cc +1 -1
  6. package/deps/rocksdb/rocksdb/db/column_family.cc +2 -2
  7. package/deps/rocksdb/rocksdb/db/column_family_test.cc +1 -1
  8. package/deps/rocksdb/rocksdb/db/compaction/compaction.cc +13 -3
  9. package/deps/rocksdb/rocksdb/db/compaction/compaction_job.cc +273 -134
  10. package/deps/rocksdb/rocksdb/db/compaction/compaction_job.h +33 -2
  11. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker.cc +11 -3
  12. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker.h +2 -1
  13. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_fifo.cc +2 -2
  14. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_level.cc +133 -5
  15. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_test.cc +130 -1
  16. package/deps/rocksdb/rocksdb/db/compaction/compaction_service_job.cc +8 -4
  17. package/deps/rocksdb/rocksdb/db/compaction/subcompaction_state.h +11 -9
  18. package/deps/rocksdb/rocksdb/db/db_compaction_test.cc +209 -12
  19. package/deps/rocksdb/rocksdb/db/db_impl/db_impl.cc +54 -39
  20. package/deps/rocksdb/rocksdb/db/db_impl/db_impl.h +102 -19
  21. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_compaction_flush.cc +30 -11
  22. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_debug.cc +1 -1
  23. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_files.cc +28 -25
  24. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_open.cc +0 -14
  25. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_write.cc +63 -54
  26. package/deps/rocksdb/rocksdb/db/db_test.cc +6 -6
  27. package/deps/rocksdb/rocksdb/db/error_handler.cc +7 -0
  28. package/deps/rocksdb/rocksdb/db/error_handler.h +10 -9
  29. package/deps/rocksdb/rocksdb/db/log_test.cc +13 -6
  30. package/deps/rocksdb/rocksdb/db/perf_context_test.cc +1 -1
  31. package/deps/rocksdb/rocksdb/db/table_cache.cc +21 -0
  32. package/deps/rocksdb/rocksdb/db/table_cache.h +5 -0
  33. package/deps/rocksdb/rocksdb/db/version_set.cc +3 -2
  34. package/deps/rocksdb/rocksdb/db/version_set.h +6 -4
  35. package/deps/rocksdb/rocksdb/db/version_set_test.cc +8 -6
  36. package/deps/rocksdb/rocksdb/db/wal_edit.cc +22 -15
  37. package/deps/rocksdb/rocksdb/db/wal_edit.h +10 -0
  38. package/deps/rocksdb/rocksdb/db/wal_edit_test.cc +4 -5
  39. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_common.cc +0 -36
  40. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_driver.cc +1 -12
  41. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_test_base.cc +23 -29
  42. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_test_base.h +0 -5
  43. package/deps/rocksdb/rocksdb/db_stress_tool/multi_ops_txns_stress.cc +7 -0
  44. package/deps/rocksdb/rocksdb/env/env_test.cc +0 -5
  45. package/deps/rocksdb/rocksdb/env/io_posix.cc +1 -7
  46. package/deps/rocksdb/rocksdb/memtable/hash_linklist_rep.cc +100 -78
  47. package/deps/rocksdb/rocksdb/options/options_test.cc +16 -0
  48. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader.cc +51 -0
  49. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader.h +3 -0
  50. package/deps/rocksdb/rocksdb/table/table_reader.h +14 -0
  51. package/deps/rocksdb/rocksdb/table/table_test.cc +52 -0
  52. package/deps/rocksdb/rocksdb/tools/db_bench_tool.cc +8 -38
  53. package/deps/rocksdb/rocksdb/util/rate_limiter.cc +27 -21
  54. package/deps/rocksdb/rocksdb/util/rate_limiter.h +12 -10
  55. package/deps/rocksdb/rocksdb/util/rate_limiter_test.cc +11 -8
  56. package/deps/rocksdb/rocksdb/utilities/backup/backup_engine_test.cc +2 -1
  57. package/deps/rocksdb/rocksdb/utilities/transactions/pessimistic_transaction_db.cc +59 -0
  58. package/deps/rocksdb/rocksdb/utilities/transactions/pessimistic_transaction_db.h +12 -0
  59. package/deps/rocksdb/rocksdb/utilities/transactions/transaction_test.cc +31 -0
  60. package/deps/rocksdb/rocksdb/utilities/transactions/write_prepared_transaction_test.cc +0 -3
  61. package/max_rev_operator.h +101 -0
  62. package/package.json +1 -1
  63. package/prebuilds/darwin-arm64/node.napi.node +0 -0
  64. package/prebuilds/linux-x64/node.napi.node +0 -0
@@ -164,7 +164,9 @@ class CompactionJob {
164
164
  const std::atomic<bool>& manual_compaction_canceled,
165
165
  const std::string& db_id = "", const std::string& db_session_id = "",
166
166
  std::string full_history_ts_low = "", std::string trim_ts = "",
167
- BlobFileCompletionCallback* blob_callback = nullptr);
167
+ BlobFileCompletionCallback* blob_callback = nullptr,
168
+ int* bg_compaction_scheduled = nullptr,
169
+ int* bg_bottom_compaction_scheduled = nullptr);
168
170
 
169
171
  virtual ~CompactionJob();
170
172
 
@@ -225,6 +227,26 @@ class CompactionJob {
225
227
  // consecutive groups such that each group has a similar size.
226
228
  void GenSubcompactionBoundaries();
227
229
 
230
+ // Get the number of planned subcompactions based on max_subcompactions and
231
+ // extra reserved resources
232
+ uint64_t GetSubcompactionsLimit();
233
+
234
+ // Additional reserved threads are reserved and the number is stored in
235
+ // extra_num_subcompaction_threads_reserved__. For now, this happens only if
236
+ // the compaction priority is round-robin and max_subcompactions is not
237
+ // sufficient (extra resources may be needed)
238
+ void AcquireSubcompactionResources(int num_extra_required_subcompactions);
239
+
240
+ // Additional threads may be reserved during IncreaseSubcompactionResources()
241
+ // if num_actual_subcompactions is less than num_planned_subcompactions.
242
+ // Additional threads will be released and the bg_compaction_scheduled_ or
243
+ // bg_bottom_compaction_scheduled_ will be updated if they are used.
244
+ // DB Mutex lock is required.
245
+ void ShrinkSubcompactionResources(uint64_t num_extra_resources);
246
+
247
+ // Release all reserved threads and update the compaction limits.
248
+ void ReleaseSubcompactionResources();
249
+
228
250
  CompactionServiceJobStatus ProcessKeyValueCompactionWithCompactionService(
229
251
  SubcompactionState* sub_compact);
230
252
 
@@ -292,13 +314,22 @@ class CompactionJob {
292
314
  bool paranoid_file_checks_;
293
315
  bool measure_io_stats_;
294
316
  // Stores the Slices that designate the boundaries for each subcompaction
295
- std::vector<Slice> boundaries_;
317
+ std::vector<std::string> boundaries_;
296
318
  Env::Priority thread_pri_;
297
319
  std::string full_history_ts_low_;
298
320
  std::string trim_ts_;
299
321
  BlobFileCompletionCallback* blob_callback_;
300
322
 
301
323
  uint64_t GetCompactionId(SubcompactionState* sub_compact) const;
324
+ // Stores the number of reserved threads in shared env_ for the number of
325
+ // extra subcompaction in kRoundRobin compaction priority
326
+ int extra_num_subcompaction_threads_reserved_;
327
+
328
+ // Stores the pointer to bg_compaction_scheduled_,
329
+ // bg_bottom_compaction_scheduled_ in DBImpl. Mutex is required when accessing
330
+ // or updating it.
331
+ int* bg_compaction_scheduled_;
332
+ int* bg_bottom_compaction_scheduled_;
302
333
 
303
334
  // Stores the sequence number to time mapping gathered from all input files
304
335
  // it also collects the smallest_seqno -> oldest_ancester_time from the SST.
@@ -462,7 +462,7 @@ bool CompactionPicker::SetupOtherInputs(
462
462
  const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
463
463
  VersionStorageInfo* vstorage, CompactionInputFiles* inputs,
464
464
  CompactionInputFiles* output_level_inputs, int* parent_index,
465
- int base_index) {
465
+ int base_index, bool only_expand_towards_right) {
466
466
  assert(!inputs->empty());
467
467
  assert(output_level_inputs->empty());
468
468
  const int input_level = inputs->level;
@@ -515,8 +515,16 @@ bool CompactionPicker::SetupOtherInputs(
515
515
  InternalKey all_start, all_limit;
516
516
  GetRange(*inputs, *output_level_inputs, &all_start, &all_limit);
517
517
  bool try_overlapping_inputs = true;
518
- vstorage->GetOverlappingInputs(input_level, &all_start, &all_limit,
519
- &expanded_inputs.files, base_index, nullptr);
518
+ if (only_expand_towards_right) {
519
+ // Round-robin compaction only allows expansion towards the larger side.
520
+ vstorage->GetOverlappingInputs(input_level, &smallest, &all_limit,
521
+ &expanded_inputs.files, base_index,
522
+ nullptr);
523
+ } else {
524
+ vstorage->GetOverlappingInputs(input_level, &all_start, &all_limit,
525
+ &expanded_inputs.files, base_index,
526
+ nullptr);
527
+ }
520
528
  uint64_t expanded_inputs_size =
521
529
  TotalCompensatedFileSize(expanded_inputs.files);
522
530
  if (!ExpandInputsToCleanCut(cf_name, vstorage, &expanded_inputs)) {
@@ -189,7 +189,8 @@ class CompactionPicker {
189
189
  VersionStorageInfo* vstorage,
190
190
  CompactionInputFiles* inputs,
191
191
  CompactionInputFiles* output_level_inputs,
192
- int* parent_index, int base_index);
192
+ int* parent_index, int base_index,
193
+ bool only_expand_towards_right = false);
193
194
 
194
195
  void GetGrandparents(VersionStorageInfo* vstorage,
195
196
  const CompactionInputFiles& inputs,
@@ -83,7 +83,7 @@ Compaction* FIFOCompactionPicker::PickTTLCompaction(
83
83
  break;
84
84
  }
85
85
  }
86
- total_size -= f->compensated_file_size;
86
+ total_size -= f->fd.file_size;
87
87
  inputs[0].files.push_back(f);
88
88
  }
89
89
  }
@@ -191,7 +191,7 @@ Compaction* FIFOCompactionPicker::PickSizeCompaction(
191
191
 
192
192
  for (auto ritr = level_files.rbegin(); ritr != level_files.rend(); ++ritr) {
193
193
  auto f = *ritr;
194
- total_size -= f->compensated_file_size;
194
+ total_size -= f->fd.file_size;
195
195
  inputs[0].files.push_back(f);
196
196
  char tmp_fsize[16];
197
197
  AppendHumanBytes(f->fd.GetFileSize(), tmp_fsize, sizeof(tmp_fsize));
@@ -76,6 +76,9 @@ class LevelCompactionBuilder {
76
76
  // files if needed.
77
77
  bool SetupOtherL0FilesIfNeeded();
78
78
 
79
+ // Compaction with round-robin compaction priority allows more files to be
80
+ // picked to form a large compaction
81
+ void SetupOtherFilesWithRoundRobinExpansion();
79
82
  // Based on initial files, setup other files need to be compacted
80
83
  // in this compaction, accordingly.
81
84
  bool SetupOtherInputsIfNeeded();
@@ -84,7 +87,9 @@ class LevelCompactionBuilder {
84
87
 
85
88
  // For the specfied level, pick a file that we want to compact.
86
89
  // Returns false if there is no file to compact.
87
- // If it returns true, inputs->files.size() will be exactly one.
90
+ // If it returns true, inputs->files.size() will be exactly one for
91
+ // all compaction priorities except round-robin. For round-robin,
92
+ // multiple consecutive files may be put into inputs->files.
88
93
  // If level is 0 and there is already a compaction on that level, this
89
94
  // function will return false.
90
95
  bool PickFileToCompact();
@@ -278,16 +283,141 @@ bool LevelCompactionBuilder::SetupOtherL0FilesIfNeeded() {
278
283
  return true;
279
284
  }
280
285
 
286
+ void LevelCompactionBuilder::SetupOtherFilesWithRoundRobinExpansion() {
287
+ // We only expand when the start level is not L0 under round robin
288
+ assert(start_level_ >= 1);
289
+
290
+ // For round-robin compaction priority, we have 3 constraints when picking
291
+ // multiple files.
292
+ // Constraint 1: We can only pick consecutive files
293
+ // -> Constraint 1a: When a file is being compacted (or some input files
294
+ // are being compacted after expanding, we cannot
295
+ // choose it and have to stop choosing more files
296
+ // -> Constraint 1b: When we reach the last file (with largest keys), we
297
+ // cannot choose more files (the next file will be the
298
+ // first one)
299
+ // Constraint 2: We should ensure the total compaction bytes (including the
300
+ // overlapped files from the next level) is no more than
301
+ // mutable_cf_options_.max_compaction_bytes
302
+ // Constraint 3: We try our best to pick as many files as possible so that
303
+ // the post-compaction level size is less than
304
+ // MaxBytesForLevel(start_level_)
305
+ // Constraint 4: We do not expand if it is possible to apply a trivial move
306
+ // Constraint 5 (TODO): Try to pick minimal files to split into the target
307
+ // number of subcompactions
308
+ TEST_SYNC_POINT("LevelCompactionPicker::RoundRobin");
309
+
310
+ // Only expand the inputs when we have selected a file in start_level_inputs_
311
+ if (start_level_inputs_.size() == 0) return;
312
+
313
+ uint64_t start_lvl_bytes_no_compacting = 0;
314
+ uint64_t curr_bytes_to_compact = 0;
315
+ uint64_t start_lvl_max_bytes_to_compact = 0;
316
+ const std::vector<FileMetaData*>& level_files =
317
+ vstorage_->LevelFiles(start_level_);
318
+ // Constraint 3 (pre-calculate the ideal max bytes to compact)
319
+ for (auto f : level_files) {
320
+ if (!f->being_compacted) {
321
+ start_lvl_bytes_no_compacting += f->compensated_file_size;
322
+ }
323
+ }
324
+ if (start_lvl_bytes_no_compacting >
325
+ vstorage_->MaxBytesForLevel(start_level_)) {
326
+ start_lvl_max_bytes_to_compact = start_lvl_bytes_no_compacting -
327
+ vstorage_->MaxBytesForLevel(start_level_);
328
+ }
329
+
330
+ size_t start_index = vstorage_->FilesByCompactionPri(start_level_)[0];
331
+ InternalKey smallest, largest;
332
+ // Constraint 4 (No need to check again later)
333
+ compaction_picker_->GetRange(start_level_inputs_, &smallest, &largest);
334
+ CompactionInputFiles output_level_inputs;
335
+ output_level_inputs.level = output_level_;
336
+ vstorage_->GetOverlappingInputs(output_level_, &smallest, &largest,
337
+ &output_level_inputs.files);
338
+ if (output_level_inputs.empty()) {
339
+ if (TryExtendNonL0TrivialMove((int)start_index)) {
340
+ return;
341
+ }
342
+ }
343
+ // Constraint 3
344
+ if (start_level_inputs_[0]->compensated_file_size >=
345
+ start_lvl_max_bytes_to_compact) {
346
+ return;
347
+ }
348
+ CompactionInputFiles tmp_start_level_inputs;
349
+ tmp_start_level_inputs = start_level_inputs_;
350
+ // TODO (zichen): Future parallel round-robin may also need to update this
351
+ // Constraint 1b (only expand till the end)
352
+ for (size_t i = start_index + 1; i < level_files.size(); i++) {
353
+ auto* f = level_files[i];
354
+ if (f->being_compacted) {
355
+ // Constraint 1a
356
+ return;
357
+ }
358
+
359
+ tmp_start_level_inputs.files.push_back(f);
360
+ if (!compaction_picker_->ExpandInputsToCleanCut(cf_name_, vstorage_,
361
+ &tmp_start_level_inputs) ||
362
+ compaction_picker_->FilesRangeOverlapWithCompaction(
363
+ {tmp_start_level_inputs}, output_level_)) {
364
+ // Constraint 1a
365
+ tmp_start_level_inputs.clear();
366
+ return;
367
+ }
368
+
369
+ curr_bytes_to_compact = 0;
370
+ for (auto start_lvl_f : tmp_start_level_inputs.files) {
371
+ curr_bytes_to_compact += start_lvl_f->compensated_file_size;
372
+ }
373
+
374
+ // Check whether any output level files are locked
375
+ compaction_picker_->GetRange(tmp_start_level_inputs, &smallest, &largest);
376
+ vstorage_->GetOverlappingInputs(output_level_, &smallest, &largest,
377
+ &output_level_inputs.files);
378
+ if (!output_level_inputs.empty() &&
379
+ !compaction_picker_->ExpandInputsToCleanCut(cf_name_, vstorage_,
380
+ &output_level_inputs)) {
381
+ // Constraint 1a
382
+ tmp_start_level_inputs.clear();
383
+ return;
384
+ }
385
+
386
+ uint64_t start_lvl_curr_bytes_to_compact = curr_bytes_to_compact;
387
+ for (auto output_lvl_f : output_level_inputs.files) {
388
+ curr_bytes_to_compact += output_lvl_f->compensated_file_size;
389
+ }
390
+ if (curr_bytes_to_compact > mutable_cf_options_.max_compaction_bytes) {
391
+ // Constraint 2
392
+ tmp_start_level_inputs.clear();
393
+ return;
394
+ }
395
+
396
+ start_level_inputs_.files = tmp_start_level_inputs.files;
397
+ // Constraint 3
398
+ if (start_lvl_curr_bytes_to_compact > start_lvl_max_bytes_to_compact) {
399
+ return;
400
+ }
401
+ }
402
+ }
403
+
281
404
  bool LevelCompactionBuilder::SetupOtherInputsIfNeeded() {
282
405
  // Setup input files from output level. For output to L0, we only compact
283
406
  // spans of files that do not interact with any pending compactions, so don't
284
407
  // need to consider other levels.
285
408
  if (output_level_ != 0) {
286
409
  output_level_inputs_.level = output_level_;
410
+ bool round_robin_expanding =
411
+ ioptions_.compaction_pri == kRoundRobin &&
412
+ compaction_reason_ == CompactionReason::kLevelMaxLevelSize;
413
+ if (round_robin_expanding) {
414
+ SetupOtherFilesWithRoundRobinExpansion();
415
+ }
287
416
  if (!is_l0_trivial_move_ &&
288
417
  !compaction_picker_->SetupOtherInputs(
289
418
  cf_name_, mutable_cf_options_, vstorage_, &start_level_inputs_,
290
- &output_level_inputs_, &parent_index_, base_index_)) {
419
+ &output_level_inputs_, &parent_index_, base_index_,
420
+ round_robin_expanding)) {
291
421
  return false;
292
422
  }
293
423
 
@@ -606,9 +736,6 @@ bool LevelCompactionBuilder::PickFileToCompact() {
606
736
  // user-key overlap.
607
737
  start_level_inputs_.clear();
608
738
 
609
- // To ensure every file is selcted in a round-robin manner, we cannot
610
- // skip the current file. So we return false and wait for the next time
611
- // we can pick this file to compact
612
739
  if (ioptions_.compaction_pri == kRoundRobin) {
613
740
  return false;
614
741
  }
@@ -641,6 +768,7 @@ bool LevelCompactionBuilder::PickFileToCompact() {
641
768
  continue;
642
769
  }
643
770
  }
771
+
644
772
  base_index_ = index;
645
773
  break;
646
774
  }
@@ -1318,7 +1318,7 @@ TEST_F(CompactionPickerTest, CompactionPriRoundRobin) {
1318
1318
  std::vector<uint32_t> selected_files = {8U, 6U, 6U};
1319
1319
 
1320
1320
  ioptions_.compaction_pri = kRoundRobin;
1321
- mutable_cf_options_.max_bytes_for_level_base = 10000000;
1321
+ mutable_cf_options_.max_bytes_for_level_base = 12000000;
1322
1322
  mutable_cf_options_.max_bytes_for_level_multiplier = 10;
1323
1323
  for (size_t i = 0; i < test_cursors.size(); i++) {
1324
1324
  // start a brand new version in each test.
@@ -1342,6 +1342,9 @@ TEST_F(CompactionPickerTest, CompactionPriRoundRobin) {
1342
1342
  cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
1343
1343
  &log_buffer_));
1344
1344
  ASSERT_TRUE(compaction.get() != nullptr);
1345
+ // Since the max bytes for level 2 is 120M, picking one file to compact
1346
+ // makes the post-compaction level size less than 120M, there is exactly one
1347
+ // file picked for round-robin compaction
1345
1348
  ASSERT_EQ(1U, compaction->num_input_files(0));
1346
1349
  ASSERT_EQ(selected_files[i], compaction->input(0, 0)->fd.GetNumber());
1347
1350
  // release the version storage
@@ -1349,6 +1352,132 @@ TEST_F(CompactionPickerTest, CompactionPriRoundRobin) {
1349
1352
  }
1350
1353
  }
1351
1354
 
1355
+ TEST_F(CompactionPickerTest, CompactionPriMultipleFilesRoundRobin1) {
1356
+ ioptions_.compaction_pri = kRoundRobin;
1357
+ mutable_cf_options_.max_compaction_bytes = 100000000u;
1358
+ mutable_cf_options_.max_bytes_for_level_base = 120;
1359
+ mutable_cf_options_.max_bytes_for_level_multiplier = 10;
1360
+ // start a brand new version in each test.
1361
+ NewVersionStorage(6, kCompactionStyleLevel);
1362
+ vstorage_->ResizeCompactCursors(6);
1363
+ // Set the cursor (file picking should start with 7U)
1364
+ vstorage_->AddCursorForOneLevel(2, InternalKey("199", 100, kTypeValue));
1365
+ Add(2, 6U, "150", "199", 500U);
1366
+ Add(2, 7U, "200", "249", 500U);
1367
+ Add(2, 8U, "300", "600", 500U);
1368
+ Add(2, 9U, "700", "800", 500U);
1369
+ Add(2, 10U, "850", "950", 500U);
1370
+
1371
+ Add(3, 26U, "130", "165", 600U);
1372
+ Add(3, 27U, "166", "170", 600U);
1373
+ Add(3, 28U, "270", "340", 600U);
1374
+ Add(3, 29U, "401", "500", 600U);
1375
+ Add(3, 30U, "601", "800", 600U);
1376
+ Add(3, 31U, "830", "890", 600U);
1377
+ UpdateVersionStorageInfo();
1378
+ LevelCompactionPicker local_level_compaction_picker =
1379
+ LevelCompactionPicker(ioptions_, &icmp_);
1380
+ std::unique_ptr<Compaction> compaction(
1381
+ local_level_compaction_picker.PickCompaction(
1382
+ cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
1383
+ &log_buffer_));
1384
+ ASSERT_TRUE(compaction.get() != nullptr);
1385
+
1386
+ // The maximum compaction bytes is very large in this case so we can igore its
1387
+ // constraint in this test case. The maximum bytes for level 2 is 1200
1388
+ // bytes, and thus at least 3 files should be picked so that the bytes in
1389
+ // level 2 is less than the maximum
1390
+ ASSERT_EQ(3U, compaction->num_input_files(0));
1391
+ ASSERT_EQ(7U, compaction->input(0, 0)->fd.GetNumber());
1392
+ ASSERT_EQ(8U, compaction->input(0, 1)->fd.GetNumber());
1393
+ ASSERT_EQ(9U, compaction->input(0, 2)->fd.GetNumber());
1394
+ // release the version storage
1395
+ DeleteVersionStorage();
1396
+ }
1397
+
1398
+ TEST_F(CompactionPickerTest, CompactionPriMultipleFilesRoundRobin2) {
1399
+ ioptions_.compaction_pri = kRoundRobin;
1400
+ mutable_cf_options_.max_compaction_bytes = 2500u;
1401
+ mutable_cf_options_.max_bytes_for_level_base = 120;
1402
+ mutable_cf_options_.max_bytes_for_level_multiplier = 10;
1403
+ // start a brand new version in each test.
1404
+ NewVersionStorage(6, kCompactionStyleLevel);
1405
+ vstorage_->ResizeCompactCursors(6);
1406
+ // Set the cursor (file picking should start with 6U)
1407
+ vstorage_->AddCursorForOneLevel(2, InternalKey("1000", 100, kTypeValue));
1408
+ Add(2, 6U, "150", "199", 500U); // Overlap with 26U, 27U
1409
+ Add(2, 7U, "200", "249", 500U); // Overlap with 27U
1410
+ Add(2, 8U, "300", "600", 500U); // Overlap with 28U, 29U
1411
+ Add(2, 9U, "700", "800", 500U);
1412
+ Add(2, 10U, "850", "950", 500U);
1413
+
1414
+ Add(3, 26U, "130", "165", 600U);
1415
+ Add(3, 27U, "166", "230", 600U);
1416
+ Add(3, 28U, "270", "340", 600U);
1417
+ Add(3, 29U, "401", "500", 600U);
1418
+ Add(3, 30U, "601", "800", 600U);
1419
+ Add(3, 31U, "830", "890", 600U);
1420
+ UpdateVersionStorageInfo();
1421
+ LevelCompactionPicker local_level_compaction_picker =
1422
+ LevelCompactionPicker(ioptions_, &icmp_);
1423
+ std::unique_ptr<Compaction> compaction(
1424
+ local_level_compaction_picker.PickCompaction(
1425
+ cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
1426
+ &log_buffer_));
1427
+ ASSERT_TRUE(compaction.get() != nullptr);
1428
+
1429
+ // The maximum compaction bytes is only 2500 bytes now. Even though we are
1430
+ // required to choose 3 files so that the post-compaction level size is less
1431
+ // than 1200 bytes. We cannot pick 3 files to compact since the maximum
1432
+ // compaction size is 2500. After picking files 6U and 7U, the number of
1433
+ // compaction bytes has reached 2200, and thus no more space to add another
1434
+ // input file with 50M bytes.
1435
+ ASSERT_EQ(2U, compaction->num_input_files(0));
1436
+ ASSERT_EQ(6U, compaction->input(0, 0)->fd.GetNumber());
1437
+ ASSERT_EQ(7U, compaction->input(0, 1)->fd.GetNumber());
1438
+ // release the version storage
1439
+ DeleteVersionStorage();
1440
+ }
1441
+
1442
+ TEST_F(CompactionPickerTest, CompactionPriMultipleFilesRoundRobin3) {
1443
+ ioptions_.compaction_pri = kRoundRobin;
1444
+ mutable_cf_options_.max_compaction_bytes = 1000000u;
1445
+ mutable_cf_options_.max_bytes_for_level_base = 120;
1446
+ mutable_cf_options_.max_bytes_for_level_multiplier = 10;
1447
+ // start a brand new version in each test.
1448
+ NewVersionStorage(6, kCompactionStyleLevel);
1449
+ vstorage_->ResizeCompactCursors(6);
1450
+ // Set the cursor (file picking should start with 9U)
1451
+ vstorage_->AddCursorForOneLevel(2, InternalKey("700", 100, kTypeValue));
1452
+ Add(2, 6U, "150", "199", 500U);
1453
+ Add(2, 7U, "200", "249", 500U);
1454
+ Add(2, 8U, "300", "600", 500U);
1455
+ Add(2, 9U, "700", "800", 500U);
1456
+ Add(2, 10U, "850", "950", 500U);
1457
+
1458
+ Add(3, 26U, "130", "165", 600U);
1459
+ Add(3, 27U, "166", "170", 600U);
1460
+ Add(3, 28U, "270", "340", 600U);
1461
+ Add(3, 29U, "401", "500", 600U);
1462
+ Add(3, 30U, "601", "800", 600U);
1463
+ Add(3, 31U, "830", "890", 600U);
1464
+ UpdateVersionStorageInfo();
1465
+ LevelCompactionPicker local_level_compaction_picker =
1466
+ LevelCompactionPicker(ioptions_, &icmp_);
1467
+ std::unique_ptr<Compaction> compaction(
1468
+ local_level_compaction_picker.PickCompaction(
1469
+ cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
1470
+ &log_buffer_));
1471
+ ASSERT_TRUE(compaction.get() != nullptr);
1472
+
1473
+ // Cannot pick more files since we reach the last file in level 2
1474
+ ASSERT_EQ(2U, compaction->num_input_files(0));
1475
+ ASSERT_EQ(9U, compaction->input(0, 0)->fd.GetNumber());
1476
+ ASSERT_EQ(10U, compaction->input(0, 1)->fd.GetNumber());
1477
+ // release the version storage
1478
+ DeleteVersionStorage();
1479
+ }
1480
+
1352
1481
  TEST_F(CompactionPickerTest, CompactionPriMinOverlappingManyFiles) {
1353
1482
  NewVersionStorage(6, kCompactionStyleLevel);
1354
1483
  ioptions_.compaction_pri = kMinOverlappingRatio;
@@ -47,10 +47,10 @@ CompactionJob::ProcessKeyValueCompactionWithCompactionService(
47
47
  compaction_input.db_options =
48
48
  BuildDBOptions(db_options_, mutable_db_options_copy_);
49
49
  compaction_input.snapshots = existing_snapshots_;
50
- compaction_input.has_begin = sub_compact->start;
50
+ compaction_input.has_begin = sub_compact->start.has_value();
51
51
  compaction_input.begin =
52
52
  compaction_input.has_begin ? sub_compact->start->ToString() : "";
53
- compaction_input.has_end = sub_compact->end;
53
+ compaction_input.has_end = sub_compact->end.has_value();
54
54
  compaction_input.end =
55
55
  compaction_input.has_end ? sub_compact->end->ToString() : "";
56
56
 
@@ -264,8 +264,12 @@ Status CompactionServiceCompactionJob::Run() {
264
264
  Slice begin = compaction_input_.begin;
265
265
  Slice end = compaction_input_.end;
266
266
  compact_->sub_compact_states.emplace_back(
267
- c, compaction_input_.has_begin ? &begin : nullptr,
268
- compaction_input_.has_end ? &end : nullptr, /*sub_job_id*/ 0);
267
+ c,
268
+ compaction_input_.has_begin ? std::optional<Slice>(begin)
269
+ : std::optional<Slice>(),
270
+ compaction_input_.has_end ? std::optional<Slice>(end)
271
+ : std::optional<Slice>(),
272
+ /*sub_job_id*/ 0);
269
273
 
270
274
  log_buffer_->FlushBufferToLog();
271
275
  LogCompaction();
@@ -10,6 +10,8 @@
10
10
 
11
11
  #pragma once
12
12
 
13
+ #include <optional>
14
+
13
15
  #include "db/blob/blob_file_addition.h"
14
16
  #include "db/blob/blob_garbage_meter.h"
15
17
  #include "db/compaction/compaction.h"
@@ -52,7 +54,7 @@ class SubcompactionState {
52
54
  // The boundaries of the key-range this compaction is interested in. No two
53
55
  // sub-compactions may have overlapping key-ranges.
54
56
  // 'start' is inclusive, 'end' is exclusive, and nullptr means unbounded
55
- const Slice *start, *end;
57
+ const std::optional<Slice> start, end;
56
58
 
57
59
  // The return status of this sub-compaction
58
60
  Status status;
@@ -117,8 +119,8 @@ class SubcompactionState {
117
119
  SubcompactionState(const SubcompactionState&) = delete;
118
120
  SubcompactionState& operator=(const SubcompactionState&) = delete;
119
121
 
120
- SubcompactionState(Compaction* c, Slice* _start, Slice* _end,
121
- uint32_t _sub_job_id)
122
+ SubcompactionState(Compaction* c, const std::optional<Slice> _start,
123
+ const std::optional<Slice> _end, uint32_t _sub_job_id)
122
124
  : compaction(c),
123
125
  start(_start),
124
126
  end(_end),
@@ -132,12 +134,12 @@ class SubcompactionState {
132
134
  // Invalid output_split_key indicates that we do not need to split
133
135
  if (output_split_key != nullptr) {
134
136
  // We may only split the output when the cursor is in the range. Split
135
- if ((end == nullptr || icmp->user_comparator()->Compare(
136
- ExtractUserKey(output_split_key->Encode()),
137
- ExtractUserKey(*end)) < 0) &&
138
- (start == nullptr || icmp->user_comparator()->Compare(
139
- ExtractUserKey(output_split_key->Encode()),
140
- ExtractUserKey(*start)) > 0)) {
137
+ if ((!end.has_value() ||
138
+ icmp->user_comparator()->Compare(
139
+ ExtractUserKey(output_split_key->Encode()), end.value()) < 0) &&
140
+ (!start.has_value() || icmp->user_comparator()->Compare(
141
+ ExtractUserKey(output_split_key->Encode()),
142
+ start.value()) > 0)) {
141
143
  local_output_split_key_ = output_split_key;
142
144
  }
143
145
  }