@nxtedition/rocksdb 7.1.3 → 7.1.6

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 (185) hide show
  1. package/binding.cc +32 -14
  2. package/deps/rocksdb/iostats.patch +19 -0
  3. package/deps/rocksdb/rocksdb/CMakeLists.txt +15 -1
  4. package/deps/rocksdb/rocksdb/cache/cache.cc +4 -0
  5. package/deps/rocksdb/rocksdb/cache/cache_bench_tool.cc +6 -8
  6. package/deps/rocksdb/rocksdb/cache/cache_key.cc +184 -164
  7. package/deps/rocksdb/rocksdb/cache/cache_key.h +38 -29
  8. package/deps/rocksdb/rocksdb/cache/cache_reservation_manager_test.cc +4 -4
  9. package/deps/rocksdb/rocksdb/cache/cache_test.cc +93 -58
  10. package/deps/rocksdb/rocksdb/cache/clock_cache.cc +92 -42
  11. package/deps/rocksdb/rocksdb/cache/clock_cache.h +57 -32
  12. package/deps/rocksdb/rocksdb/cache/compressed_secondary_cache.cc +114 -37
  13. package/deps/rocksdb/rocksdb/cache/compressed_secondary_cache.h +34 -2
  14. package/deps/rocksdb/rocksdb/cache/compressed_secondary_cache_test.cc +187 -38
  15. package/deps/rocksdb/rocksdb/cache/fast_lru_cache.cc +3 -1
  16. package/deps/rocksdb/rocksdb/cache/lru_cache.cc +88 -19
  17. package/deps/rocksdb/rocksdb/cache/lru_cache.h +48 -8
  18. package/deps/rocksdb/rocksdb/cache/lru_cache_test.cc +481 -224
  19. package/deps/rocksdb/rocksdb/crash_test.mk +15 -1
  20. package/deps/rocksdb/rocksdb/db/arena_wrapped_db_iter.cc +2 -2
  21. package/deps/rocksdb/rocksdb/db/blob/blob_file_builder.cc +3 -7
  22. package/deps/rocksdb/rocksdb/db/blob/blob_index.h +1 -1
  23. package/deps/rocksdb/rocksdb/db/blob/blob_log_format.cc +3 -5
  24. package/deps/rocksdb/rocksdb/db/blob/blob_log_writer.cc +25 -19
  25. package/deps/rocksdb/rocksdb/db/blob/blob_source.cc +4 -5
  26. package/deps/rocksdb/rocksdb/db/blob/blob_source.h +2 -3
  27. package/deps/rocksdb/rocksdb/db/blob/blob_source_test.cc +12 -4
  28. package/deps/rocksdb/rocksdb/db/blob/db_blob_basic_test.cc +149 -0
  29. package/deps/rocksdb/rocksdb/db/blob/db_blob_compaction_test.cc +105 -0
  30. package/deps/rocksdb/rocksdb/db/column_family.cc +2 -15
  31. package/deps/rocksdb/rocksdb/db/column_family_test.cc +17 -4
  32. package/deps/rocksdb/rocksdb/db/compact_files_test.cc +8 -8
  33. package/deps/rocksdb/rocksdb/db/compaction/compaction.cc +0 -7
  34. package/deps/rocksdb/rocksdb/db/compaction/compaction.h +5 -0
  35. package/deps/rocksdb/rocksdb/db/compaction/compaction_iterator.cc +56 -53
  36. package/deps/rocksdb/rocksdb/db/compaction/compaction_iterator.h +33 -11
  37. package/deps/rocksdb/rocksdb/db/compaction/compaction_job.cc +45 -11
  38. package/deps/rocksdb/rocksdb/db/compaction/compaction_job_test.cc +1 -2
  39. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_test.cc +143 -2
  40. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_universal.cc +43 -18
  41. package/deps/rocksdb/rocksdb/db/compaction/tiered_compaction_test.cc +48 -65
  42. package/deps/rocksdb/rocksdb/db/corruption_test.cc +1 -0
  43. package/deps/rocksdb/rocksdb/db/db_basic_test.cc +73 -4
  44. package/deps/rocksdb/rocksdb/db/db_block_cache_test.cc +239 -190
  45. package/deps/rocksdb/rocksdb/db/db_compaction_test.cc +71 -2
  46. package/deps/rocksdb/rocksdb/db/db_impl/db_impl.cc +144 -33
  47. package/deps/rocksdb/rocksdb/db/db_impl/db_impl.h +18 -35
  48. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_compaction_flush.cc +11 -5
  49. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_experimental.cc +7 -7
  50. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_open.cc +15 -8
  51. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_readonly.cc +2 -1
  52. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_secondary.cc +3 -1
  53. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_write.cc +11 -0
  54. package/deps/rocksdb/rocksdb/db/db_iter.cc +69 -11
  55. package/deps/rocksdb/rocksdb/db/db_iter.h +16 -0
  56. package/deps/rocksdb/rocksdb/db/db_kv_checksum_test.cc +239 -23
  57. package/deps/rocksdb/rocksdb/db/db_memtable_test.cc +2 -1
  58. package/deps/rocksdb/rocksdb/db/db_merge_operand_test.cc +42 -0
  59. package/deps/rocksdb/rocksdb/db/db_test.cc +61 -28
  60. package/deps/rocksdb/rocksdb/db/db_test2.cc +24 -9
  61. package/deps/rocksdb/rocksdb/db/db_wal_test.cc +17 -0
  62. package/deps/rocksdb/rocksdb/db/db_with_timestamp_compaction_test.cc +61 -0
  63. package/deps/rocksdb/rocksdb/db/db_write_test.cc +130 -0
  64. package/deps/rocksdb/rocksdb/db/event_helpers.cc +2 -1
  65. package/deps/rocksdb/rocksdb/db/experimental.cc +7 -8
  66. package/deps/rocksdb/rocksdb/db/external_sst_file_ingestion_job.cc +1 -2
  67. package/deps/rocksdb/rocksdb/db/flush_job.cc +11 -7
  68. package/deps/rocksdb/rocksdb/db/flush_job_test.cc +7 -1
  69. package/deps/rocksdb/rocksdb/db/forward_iterator.cc +4 -2
  70. package/deps/rocksdb/rocksdb/db/import_column_family_job.cc +7 -1
  71. package/deps/rocksdb/rocksdb/db/import_column_family_job.h +6 -0
  72. package/deps/rocksdb/rocksdb/db/import_column_family_test.cc +6 -0
  73. package/deps/rocksdb/rocksdb/db/kv_checksum.h +8 -4
  74. package/deps/rocksdb/rocksdb/db/log_reader.cc +48 -11
  75. package/deps/rocksdb/rocksdb/db/log_reader.h +8 -2
  76. package/deps/rocksdb/rocksdb/db/log_test.cc +10 -1
  77. package/deps/rocksdb/rocksdb/db/log_writer.cc +7 -1
  78. package/deps/rocksdb/rocksdb/db/manual_compaction_test.cc +4 -4
  79. package/deps/rocksdb/rocksdb/db/memtable.cc +222 -47
  80. package/deps/rocksdb/rocksdb/db/memtable.h +70 -14
  81. package/deps/rocksdb/rocksdb/db/memtable_list.cc +14 -8
  82. package/deps/rocksdb/rocksdb/db/memtable_list_test.cc +30 -10
  83. package/deps/rocksdb/rocksdb/db/perf_context_test.cc +5 -5
  84. package/deps/rocksdb/rocksdb/db/pinned_iterators_manager.h +5 -0
  85. package/deps/rocksdb/rocksdb/db/repair.cc +2 -3
  86. package/deps/rocksdb/rocksdb/db/seqno_time_test.cc +3 -7
  87. package/deps/rocksdb/rocksdb/db/table_cache.cc +72 -0
  88. package/deps/rocksdb/rocksdb/db/table_cache.h +19 -1
  89. package/deps/rocksdb/rocksdb/db/table_cache_sync_and_async.h +10 -15
  90. package/deps/rocksdb/rocksdb/db/table_properties_collector_test.cc +2 -2
  91. package/deps/rocksdb/rocksdb/db/version_builder_test.cc +35 -64
  92. package/deps/rocksdb/rocksdb/db/version_edit.cc +3 -32
  93. package/deps/rocksdb/rocksdb/db/version_edit.h +2 -12
  94. package/deps/rocksdb/rocksdb/db/version_edit_test.cc +10 -23
  95. package/deps/rocksdb/rocksdb/db/version_set.cc +71 -28
  96. package/deps/rocksdb/rocksdb/db/version_set.h +3 -3
  97. package/deps/rocksdb/rocksdb/db/version_set_sync_and_async.h +7 -7
  98. package/deps/rocksdb/rocksdb/db/version_set_test.cc +17 -15
  99. package/deps/rocksdb/rocksdb/db/wal_manager.cc +0 -4
  100. package/deps/rocksdb/rocksdb/db/wal_manager_test.cc +2 -1
  101. package/deps/rocksdb/rocksdb/db/wide/db_wide_basic_test.cc +137 -42
  102. package/deps/rocksdb/rocksdb/db/wide/wide_column_serialization.cc +21 -0
  103. package/deps/rocksdb/rocksdb/db/wide/wide_column_serialization.h +1 -0
  104. package/deps/rocksdb/rocksdb/db/write_batch_test.cc +2 -1
  105. package/deps/rocksdb/rocksdb/db/write_callback_test.cc +4 -4
  106. package/deps/rocksdb/rocksdb/db/write_thread.cc +51 -46
  107. package/deps/rocksdb/rocksdb/db/write_thread.h +0 -4
  108. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_common.h +5 -0
  109. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_gflags.cc +12 -0
  110. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_test_base.cc +8 -0
  111. package/deps/rocksdb/rocksdb/env/env_posix.cc +1 -1
  112. package/deps/rocksdb/rocksdb/env/env_test.cc +38 -8
  113. package/deps/rocksdb/rocksdb/env/file_system.cc +20 -0
  114. package/deps/rocksdb/rocksdb/env/fs_posix.cc +2 -46
  115. package/deps/rocksdb/rocksdb/env/io_posix.cc +1 -0
  116. package/deps/rocksdb/rocksdb/file/writable_file_writer.cc +110 -5
  117. package/deps/rocksdb/rocksdb/file/writable_file_writer.h +7 -0
  118. package/deps/rocksdb/rocksdb/include/rocksdb/advanced_options.h +29 -1
  119. package/deps/rocksdb/rocksdb/include/rocksdb/cache.h +31 -6
  120. package/deps/rocksdb/rocksdb/include/rocksdb/db.h +4 -0
  121. package/deps/rocksdb/rocksdb/include/rocksdb/file_system.h +1 -1
  122. package/deps/rocksdb/rocksdb/include/rocksdb/iostats_context.h +7 -0
  123. package/deps/rocksdb/rocksdb/include/rocksdb/options.h +10 -3
  124. package/deps/rocksdb/rocksdb/include/rocksdb/slice.h +3 -1
  125. package/deps/rocksdb/rocksdb/include/rocksdb/status.h +1 -1
  126. package/deps/rocksdb/rocksdb/include/rocksdb/wide_columns.h +2 -0
  127. package/deps/rocksdb/rocksdb/logging/auto_roll_logger.cc +12 -0
  128. package/deps/rocksdb/rocksdb/logging/auto_roll_logger_test.cc +9 -13
  129. package/deps/rocksdb/rocksdb/logging/env_logger.h +39 -13
  130. package/deps/rocksdb/rocksdb/memory/memory_allocator_test.cc +1 -1
  131. package/deps/rocksdb/rocksdb/memtable/inlineskiplist.h +1 -1
  132. package/deps/rocksdb/rocksdb/memtable/write_buffer_manager_test.cc +1 -1
  133. package/deps/rocksdb/rocksdb/microbench/db_basic_bench.cc +6 -0
  134. package/deps/rocksdb/rocksdb/monitoring/iostats_context_imp.h +4 -1
  135. package/deps/rocksdb/rocksdb/options/cf_options.cc +10 -3
  136. package/deps/rocksdb/rocksdb/options/cf_options.h +10 -5
  137. package/deps/rocksdb/rocksdb/options/options_helper.cc +4 -1
  138. package/deps/rocksdb/rocksdb/options/options_settable_test.cc +3 -1
  139. package/deps/rocksdb/rocksdb/options/options_test.cc +4 -2
  140. package/deps/rocksdb/rocksdb/port/util_logger.h +1 -3
  141. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_builder.cc +2 -6
  142. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_factory.cc +1 -0
  143. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader.cc +52 -12
  144. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader.h +5 -7
  145. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader_sync_and_async.h +9 -1
  146. package/deps/rocksdb/rocksdb/table/block_based/block_like_traits.h +28 -10
  147. package/deps/rocksdb/rocksdb/table/block_based/data_block_hash_index_test.cc +1 -1
  148. package/deps/rocksdb/rocksdb/table/block_based/partitioned_filter_block.cc +5 -2
  149. package/deps/rocksdb/rocksdb/table/block_based/partitioned_filter_block.h +1 -0
  150. package/deps/rocksdb/rocksdb/table/get_context.cc +16 -6
  151. package/deps/rocksdb/rocksdb/table/table_reader.h +9 -0
  152. package/deps/rocksdb/rocksdb/table/table_test.cc +2 -1
  153. package/deps/rocksdb/rocksdb/table/unique_id.cc +22 -24
  154. package/deps/rocksdb/rocksdb/table/unique_id_impl.h +2 -1
  155. package/deps/rocksdb/rocksdb/tools/block_cache_analyzer/block_cache_trace_analyzer_plot.py +7 -0
  156. package/deps/rocksdb/rocksdb/tools/db_bench_tool.cc +41 -4
  157. package/deps/rocksdb/rocksdb/tools/db_sanity_test.cc +5 -2
  158. package/deps/rocksdb/rocksdb/tools/ldb_cmd.cc +7 -8
  159. package/deps/rocksdb/rocksdb/tools/ldb_cmd_test.cc +6 -6
  160. package/deps/rocksdb/rocksdb/tools/reduce_levels_test.cc +1 -1
  161. package/deps/rocksdb/rocksdb/util/async_file_reader.cc +2 -1
  162. package/deps/rocksdb/rocksdb/util/async_file_reader.h +3 -3
  163. package/deps/rocksdb/rocksdb/util/coro_utils.h +2 -1
  164. package/deps/rocksdb/rocksdb/util/file_reader_writer_test.cc +2 -0
  165. package/deps/rocksdb/rocksdb/util/hash_test.cc +67 -0
  166. package/deps/rocksdb/rocksdb/util/math.h +41 -0
  167. package/deps/rocksdb/rocksdb/util/math128.h +6 -0
  168. package/deps/rocksdb/rocksdb/util/single_thread_executor.h +2 -1
  169. package/deps/rocksdb/rocksdb/util/stderr_logger.h +13 -0
  170. package/deps/rocksdb/rocksdb/utilities/backup/backup_engine_test.cc +55 -46
  171. package/deps/rocksdb/rocksdb/utilities/cache_dump_load_impl.cc +3 -6
  172. package/deps/rocksdb/rocksdb/utilities/cassandra/cassandra_functional_test.cc +2 -1
  173. package/deps/rocksdb/rocksdb/utilities/counted_fs.cc +10 -0
  174. package/deps/rocksdb/rocksdb/utilities/transactions/lock/point/point_lock_manager_test.h +5 -0
  175. package/deps/rocksdb/rocksdb/utilities/transactions/lock/range/range_lock_manager.h +6 -0
  176. package/deps/rocksdb/rocksdb/utilities/transactions/lock/range/range_locking_test.cc +2 -2
  177. package/deps/rocksdb/rocksdb/utilities/transactions/optimistic_transaction_test.cc +2 -2
  178. package/deps/rocksdb/rocksdb/utilities/ttl/ttl_test.cc +2 -2
  179. package/deps/rocksdb/rocksdb/utilities/write_batch_with_index/write_batch_with_index_test.cc +2 -2
  180. package/index.js +17 -8
  181. package/package.json +1 -1
  182. package/prebuilds/darwin-arm64/node.napi.node +0 -0
  183. package/prebuilds/darwin-x64/node.napi.node +0 -0
  184. package/prebuilds/linux-x64/node.napi.node +0 -0
  185. package/deps/rocksdb/rocksdb/logging/posix_logger.h +0 -179
@@ -77,7 +77,7 @@ TEST_F(CompactFilesTest, L0ConflictsFiles) {
77
77
  options.compression = kNoCompression;
78
78
 
79
79
  DB* db = nullptr;
80
- DestroyDB(db_name_, options);
80
+ ASSERT_OK(DestroyDB(db_name_, options));
81
81
  Status s = DB::Open(options, db_name_, &db);
82
82
  assert(s.ok());
83
83
  assert(db);
@@ -128,7 +128,7 @@ TEST_F(CompactFilesTest, MultipleLevel) {
128
128
  options.listeners.emplace_back(collector);
129
129
 
130
130
  DB* db = nullptr;
131
- DestroyDB(db_name_, options);
131
+ ASSERT_OK(DestroyDB(db_name_, options));
132
132
  Status s = DB::Open(options, db_name_, &db);
133
133
  ASSERT_OK(s);
134
134
  ASSERT_NE(db, nullptr);
@@ -211,7 +211,7 @@ TEST_F(CompactFilesTest, ObsoleteFiles) {
211
211
  options.listeners.emplace_back(collector);
212
212
 
213
213
  DB* db = nullptr;
214
- DestroyDB(db_name_, options);
214
+ ASSERT_OK(DestroyDB(db_name_, options));
215
215
  Status s = DB::Open(options, db_name_, &db);
216
216
  ASSERT_OK(s);
217
217
  ASSERT_NE(db, nullptr);
@@ -250,7 +250,7 @@ TEST_F(CompactFilesTest, NotCutOutputOnLevel0) {
250
250
  options.listeners.emplace_back(collector);
251
251
 
252
252
  DB* db = nullptr;
253
- DestroyDB(db_name_, options);
253
+ ASSERT_OK(DestroyDB(db_name_, options));
254
254
  Status s = DB::Open(options, db_name_, &db);
255
255
  assert(s.ok());
256
256
  assert(db);
@@ -288,7 +288,7 @@ TEST_F(CompactFilesTest, CapturingPendingFiles) {
288
288
  options.listeners.emplace_back(collector);
289
289
 
290
290
  DB* db = nullptr;
291
- DestroyDB(db_name_, options);
291
+ ASSERT_OK(DestroyDB(db_name_, options));
292
292
  Status s = DB::Open(options, db_name_, &db);
293
293
  ASSERT_OK(s);
294
294
  assert(db);
@@ -366,7 +366,7 @@ TEST_F(CompactFilesTest, CompactionFilterWithGetSv) {
366
366
  options.compaction_filter = cf.get();
367
367
 
368
368
  DB* db = nullptr;
369
- DestroyDB(db_name_, options);
369
+ ASSERT_OK(DestroyDB(db_name_, options));
370
370
  Status s = DB::Open(options, db_name_, &db);
371
371
  ASSERT_OK(s);
372
372
 
@@ -404,7 +404,7 @@ TEST_F(CompactFilesTest, SentinelCompressionType) {
404
404
  {CompactionStyle::kCompactionStyleLevel,
405
405
  CompactionStyle::kCompactionStyleUniversal,
406
406
  CompactionStyle::kCompactionStyleNone}) {
407
- DestroyDB(db_name_, Options());
407
+ ASSERT_OK(DestroyDB(db_name_, Options()));
408
408
  Options options;
409
409
  options.compaction_style = compaction_style;
410
410
  // L0: Snappy, L1: ZSTD, L2: Snappy
@@ -458,7 +458,7 @@ TEST_F(CompactFilesTest, GetCompactionJobInfo) {
458
458
  options.listeners.emplace_back(collector);
459
459
 
460
460
  DB* db = nullptr;
461
- DestroyDB(db_name_, options);
461
+ ASSERT_OK(DestroyDB(db_name_, options));
462
462
  Status s = DB::Open(options, db_name_, &db);
463
463
  ASSERT_OK(s);
464
464
  assert(db);
@@ -664,13 +664,6 @@ bool Compaction::ShouldFormSubcompactions() const {
664
664
  return false;
665
665
  }
666
666
 
667
- // Note: the subcompaction boundary picking logic does not currently guarantee
668
- // that all user keys that differ only by timestamp get processed by the same
669
- // subcompaction.
670
- if (cfd_->user_comparator()->timestamp_size() > 0) {
671
- return false;
672
- }
673
-
674
667
  // Round-Robin pri under leveled compaction allows subcompactions by default
675
668
  // and the number of subcompactions can be larger than max_subcompactions_
676
669
  if (cfd_->ioptions()->compaction_pri == kRoundRobin &&
@@ -212,6 +212,11 @@ class Compaction {
212
212
  // Is this compaction creating a file in the bottom most level?
213
213
  bool bottommost_level() const { return bottommost_level_; }
214
214
 
215
+ // Is the compaction compact to the last level
216
+ bool is_last_level() const {
217
+ return output_level_ == immutable_options_.num_levels - 1;
218
+ }
219
+
215
220
  // Does this compaction include all sst files?
216
221
  bool is_full_compaction() const { return is_full_compaction_; }
217
222
 
@@ -80,6 +80,15 @@ CompactionIterator::CompactionIterator(
80
80
  compaction_filter_(compaction_filter),
81
81
  shutting_down_(shutting_down),
82
82
  manual_compaction_canceled_(manual_compaction_canceled),
83
+ bottommost_level_(!compaction_ ? false
84
+ : compaction_->bottommost_level() &&
85
+ !compaction_->allow_ingest_behind()),
86
+ // snapshots_ cannot be nullptr, but we will assert later in the body of
87
+ // the constructor.
88
+ visible_at_tip_(snapshots_ ? snapshots_->empty() : false),
89
+ earliest_snapshot_(!snapshots_ || snapshots_->empty()
90
+ ? kMaxSequenceNumber
91
+ : snapshots_->at(0)),
83
92
  info_log_(info_log),
84
93
  allow_data_in_errors_(allow_data_in_errors),
85
94
  enforce_single_del_contracts_(enforce_single_del_contracts),
@@ -98,25 +107,10 @@ CompactionIterator::CompactionIterator(
98
107
  level_(compaction_ == nullptr ? 0 : compaction_->level()),
99
108
  penultimate_level_cutoff_seqno_(penultimate_level_cutoff_seqno) {
100
109
  assert(snapshots_ != nullptr);
101
- bottommost_level_ = compaction_ == nullptr
102
- ? false
103
- : compaction_->bottommost_level() &&
104
- !compaction_->allow_ingest_behind();
110
+
105
111
  if (compaction_ != nullptr) {
106
112
  level_ptrs_ = std::vector<size_t>(compaction_->number_levels(), 0);
107
113
  }
108
- if (snapshots_->size() == 0) {
109
- // optimize for fast path if there are no snapshots
110
- visible_at_tip_ = true;
111
- earliest_snapshot_iter_ = snapshots_->end();
112
- earliest_snapshot_ = kMaxSequenceNumber;
113
- latest_snapshot_ = 0;
114
- } else {
115
- visible_at_tip_ = false;
116
- earliest_snapshot_iter_ = snapshots_->begin();
117
- earliest_snapshot_ = snapshots_->at(0);
118
- latest_snapshot_ = snapshots_->back();
119
- }
120
114
  #ifndef NDEBUG
121
115
  // findEarliestVisibleSnapshot assumes this ordering.
122
116
  for (size_t i = 1; i < snapshots_->size(); ++i) {
@@ -173,7 +167,7 @@ void CompactionIterator::Next() {
173
167
  current_key_.UpdateInternalKey(ikey_.sequence, ikey_.type);
174
168
  key_ = current_key_.GetInternalKey();
175
169
  ikey_.user_key = current_key_.GetUserKey();
176
- valid_ = true;
170
+ validity_info_.SetValid(ValidContext::kMerge1);
177
171
  } else {
178
172
  // We consumed all pinned merge operands, release pinned iterators
179
173
  pinned_iters_mgr_.ReleasePinnedData();
@@ -191,7 +185,7 @@ void CompactionIterator::Next() {
191
185
  NextFromInput();
192
186
  }
193
187
 
194
- if (valid_) {
188
+ if (Valid()) {
195
189
  // Record that we've outputted a record for the current key.
196
190
  has_outputted_key_ = true;
197
191
  }
@@ -228,7 +222,6 @@ bool CompactionIterator::InvokeFilterIfNeeded(bool* need_skip,
228
222
  {
229
223
  StopWatchNano timer(clock_, report_detailed_time_);
230
224
  if (kTypeBlobIndex == ikey_.type) {
231
- blob_value_.Reset();
232
225
  filter = compaction_filter_->FilterBlobByKey(
233
226
  level_, filter_key, &compaction_filter_value_,
234
227
  compaction_filter_skip_until_.rep());
@@ -237,7 +230,7 @@ bool CompactionIterator::InvokeFilterIfNeeded(bool* need_skip,
237
230
  if (compaction_ == nullptr) {
238
231
  status_ =
239
232
  Status::Corruption("Unexpected blob index outside of compaction");
240
- valid_ = false;
233
+ validity_info_.Invalidate();
241
234
  return false;
242
235
  }
243
236
 
@@ -252,7 +245,7 @@ bool CompactionIterator::InvokeFilterIfNeeded(bool* need_skip,
252
245
  Status s = blob_index.DecodeFrom(value_);
253
246
  if (!s.ok()) {
254
247
  status_ = s;
255
- valid_ = false;
248
+ validity_info_.Invalidate();
256
249
  return false;
257
250
  }
258
251
 
@@ -270,7 +263,7 @@ bool CompactionIterator::InvokeFilterIfNeeded(bool* need_skip,
270
263
  &bytes_read);
271
264
  if (!s.ok()) {
272
265
  status_ = s;
273
- valid_ = false;
266
+ validity_info_.Invalidate();
274
267
  return false;
275
268
  }
276
269
 
@@ -294,7 +287,7 @@ bool CompactionIterator::InvokeFilterIfNeeded(bool* need_skip,
294
287
  // Should not reach here, since FilterV2 should never return kUndetermined.
295
288
  status_ =
296
289
  Status::NotSupported("FilterV2() should never return kUndetermined");
297
- valid_ = false;
290
+ validity_info_.Invalidate();
298
291
  return false;
299
292
  }
300
293
 
@@ -343,7 +336,7 @@ bool CompactionIterator::InvokeFilterIfNeeded(bool* need_skip,
343
336
  status_ = Status::NotSupported(
344
337
  "Only stacked BlobDB's internal compaction filter can return "
345
338
  "kChangeBlobIndex.");
346
- valid_ = false;
339
+ validity_info_.Invalidate();
347
340
  return false;
348
341
  }
349
342
  if (ikey_.type == kTypeValue) {
@@ -356,7 +349,7 @@ bool CompactionIterator::InvokeFilterIfNeeded(bool* need_skip,
356
349
  if (!compaction_filter_->IsStackedBlobDbInternalCompactionFilter()) {
357
350
  status_ = Status::NotSupported(
358
351
  "CompactionFilter for integrated BlobDB should not return kIOError");
359
- valid_ = false;
352
+ validity_info_.Invalidate();
360
353
  return false;
361
354
  }
362
355
  status_ = Status::IOError("Failed to access blob during compaction filter");
@@ -367,12 +360,13 @@ bool CompactionIterator::InvokeFilterIfNeeded(bool* need_skip,
367
360
 
368
361
  void CompactionIterator::NextFromInput() {
369
362
  at_next_ = false;
370
- valid_ = false;
363
+ validity_info_.Invalidate();
371
364
 
372
- while (!valid_ && input_.Valid() && !IsPausingManualCompaction() &&
365
+ while (!Valid() && input_.Valid() && !IsPausingManualCompaction() &&
373
366
  !IsShuttingDown()) {
374
367
  key_ = input_.key();
375
368
  value_ = input_.value();
369
+ blob_value_.Reset();
376
370
  iter_stats_.num_input_records++;
377
371
 
378
372
  Status pik_status = ParseInternalKey(key_, &ikey_, allow_data_in_errors_);
@@ -389,7 +383,7 @@ void CompactionIterator::NextFromInput() {
389
383
  has_current_user_key_ = false;
390
384
  current_user_key_sequence_ = kMaxSequenceNumber;
391
385
  current_user_key_snapshot_ = 0;
392
- valid_ = true;
386
+ validity_info_.SetValid(ValidContext::kParseKeyError);
393
387
  break;
394
388
  }
395
389
  TEST_SYNC_POINT_CALLBACK("CompactionIterator:ProcessKV", &ikey_);
@@ -502,7 +496,7 @@ void CompactionIterator::NextFromInput() {
502
496
 
503
497
  if (UNLIKELY(!current_key_committed_)) {
504
498
  assert(snapshot_checker_ != nullptr);
505
- valid_ = true;
499
+ validity_info_.SetValid(ValidContext::kCurrentKeyUncommitted);
506
500
  break;
507
501
  }
508
502
 
@@ -545,7 +539,7 @@ void CompactionIterator::NextFromInput() {
545
539
  }
546
540
 
547
541
  value_.clear();
548
- valid_ = true;
542
+ validity_info_.SetValid(ValidContext::kKeepSDAndClearPut);
549
543
  clear_and_output_next_key_ = false;
550
544
  } else if (ikey_.type == kTypeSingleDeletion) {
551
545
  // We can compact out a SingleDelete if:
@@ -669,7 +663,7 @@ void CompactionIterator::NextFromInput() {
669
663
  ++iter_stats_.num_single_del_mismatch;
670
664
  if (enforce_single_del_contracts_) {
671
665
  ROCKS_LOG_ERROR(info_log_, "%s", oss.str().c_str());
672
- valid_ = false;
666
+ validity_info_.Invalidate();
673
667
  status_ = Status::Corruption(oss.str());
674
668
  return;
675
669
  }
@@ -678,7 +672,7 @@ void CompactionIterator::NextFromInput() {
678
672
  // We cannot drop the SingleDelete as timestamp is enabled, and
679
673
  // timestamp of this key is greater than or equal to
680
674
  // *full_history_ts_low_. We will output the SingleDelete.
681
- valid_ = true;
675
+ validity_info_.SetValid(ValidContext::kKeepTsHistory);
682
676
  } else if (has_outputted_key_ ||
683
677
  DefinitelyInSnapshot(ikey_.sequence,
684
678
  earliest_write_conflict_snapshot_) ||
@@ -713,7 +707,7 @@ void CompactionIterator::NextFromInput() {
713
707
  // outputted on the next iteration.)
714
708
 
715
709
  // Setting valid_ to true will output the current SingleDelete
716
- valid_ = true;
710
+ validity_info_.SetValid(ValidContext::kKeepSDForConflictCheck);
717
711
 
718
712
  // Set up the Put to be outputted in the next iteration.
719
713
  // (Optimization 3).
@@ -725,7 +719,7 @@ void CompactionIterator::NextFromInput() {
725
719
  } else {
726
720
  // We hit the next snapshot without hitting a put, so the iterator
727
721
  // returns the single delete.
728
- valid_ = true;
722
+ validity_info_.SetValid(ValidContext::kKeepSDForSnapshot);
729
723
  TEST_SYNC_POINT_CALLBACK(
730
724
  "CompactionIterator::NextFromInput:SingleDelete:3",
731
725
  const_cast<Compaction*>(c));
@@ -758,11 +752,11 @@ void CompactionIterator::NextFromInput() {
758
752
  assert(bottommost_level_);
759
753
  } else {
760
754
  // Output SingleDelete
761
- valid_ = true;
755
+ validity_info_.SetValid(ValidContext::kKeepSD);
762
756
  }
763
757
  }
764
758
 
765
- if (valid_) {
759
+ if (Valid()) {
766
760
  at_next_ = true;
767
761
  }
768
762
  } else if (last_snapshot == current_user_key_snapshot_ ||
@@ -861,7 +855,7 @@ void CompactionIterator::NextFromInput() {
861
855
  (ParseInternalKey(input_.key(), &next_ikey, allow_data_in_errors_)
862
856
  .ok()) &&
863
857
  cmp_->EqualWithoutTimestamp(ikey_.user_key, next_ikey.user_key)) {
864
- valid_ = true;
858
+ validity_info_.SetValid(ValidContext::kKeepDel);
865
859
  at_next_ = true;
866
860
  }
867
861
  } else if (ikey_.type == kTypeMerge) {
@@ -905,7 +899,7 @@ void CompactionIterator::NextFromInput() {
905
899
  current_key_.UpdateInternalKey(ikey_.sequence, ikey_.type);
906
900
  key_ = current_key_.GetInternalKey();
907
901
  ikey_.user_key = current_key_.GetUserKey();
908
- valid_ = true;
902
+ validity_info_.SetValid(ValidContext::kMerge2);
909
903
  } else {
910
904
  // all merge operands were filtered out. reset the user key, since the
911
905
  // batch consumed by the merge operator should not shadow any keys
@@ -927,7 +921,7 @@ void CompactionIterator::NextFromInput() {
927
921
  ++iter_stats_.num_record_drop_range_del;
928
922
  AdvanceInputIter();
929
923
  } else {
930
- valid_ = true;
924
+ validity_info_.SetValid(ValidContext::kNewUserKey);
931
925
  }
932
926
  }
933
927
 
@@ -936,13 +930,18 @@ void CompactionIterator::NextFromInput() {
936
930
  }
937
931
  }
938
932
 
939
- if (!valid_ && IsShuttingDown()) {
933
+ if (!Valid() && IsShuttingDown()) {
940
934
  status_ = Status::ShutdownInProgress();
941
935
  }
942
936
 
943
937
  if (IsPausingManualCompaction()) {
944
938
  status_ = Status::Incomplete(Status::SubCode::kManualCompactionPaused);
945
939
  }
940
+
941
+ // Propagate corruption status from memtable itereator
942
+ if (!input_.Valid() && input_.status().IsCorruption()) {
943
+ status_ = input_.status();
944
+ }
946
945
  }
947
946
 
948
947
  bool CompactionIterator::ExtractLargeValueIfNeededImpl() {
@@ -955,7 +954,7 @@ bool CompactionIterator::ExtractLargeValueIfNeededImpl() {
955
954
 
956
955
  if (!s.ok()) {
957
956
  status_ = s;
958
- valid_ = false;
957
+ validity_info_.Invalidate();
959
958
 
960
959
  return false;
961
960
  }
@@ -1000,7 +999,7 @@ void CompactionIterator::GarbageCollectBlobIfNeeded() {
1000
999
 
1001
1000
  if (!s.ok()) {
1002
1001
  status_ = s;
1003
- valid_ = false;
1002
+ validity_info_.Invalidate();
1004
1003
 
1005
1004
  return;
1006
1005
  }
@@ -1026,7 +1025,7 @@ void CompactionIterator::GarbageCollectBlobIfNeeded() {
1026
1025
 
1027
1026
  if (!s.ok()) {
1028
1027
  status_ = s;
1029
- valid_ = false;
1028
+ validity_info_.Invalidate();
1030
1029
 
1031
1030
  return;
1032
1031
  }
@@ -1059,14 +1058,14 @@ void CompactionIterator::GarbageCollectBlobIfNeeded() {
1059
1058
  if (blob_decision == CompactionFilter::BlobDecision::kCorruption) {
1060
1059
  status_ =
1061
1060
  Status::Corruption("Corrupted blob reference encountered during GC");
1062
- valid_ = false;
1061
+ validity_info_.Invalidate();
1063
1062
 
1064
1063
  return;
1065
1064
  }
1066
1065
 
1067
1066
  if (blob_decision == CompactionFilter::BlobDecision::kIOError) {
1068
1067
  status_ = Status::IOError("Could not relocate blob during GC");
1069
- valid_ = false;
1068
+ validity_info_.Invalidate();
1070
1069
 
1071
1070
  return;
1072
1071
  }
@@ -1107,13 +1106,13 @@ void CompactionIterator::DecideOutputLevel() {
1107
1106
  compaction_->WithinPenultimateLevelOutputRange(ikey_.user_key);
1108
1107
  if (!safe_to_penultimate_level) {
1109
1108
  output_to_penultimate_level_ = false;
1110
- // It could happen when disable/enable `bottommost_temperature` while
1111
- // holding a snapshot. When `bottommost_temperature` is not set
1109
+ // It could happen when disable/enable `last_level_temperature` while
1110
+ // holding a snapshot. When `last_level_temperature` is not set
1112
1111
  // (==kUnknown), the data newer than any snapshot is pushed to the last
1113
1112
  // level, but when the per_key_placement feature is enabled on the fly,
1114
1113
  // the data later than the snapshot has to be moved to the penultimate
1115
1114
  // level, which may or may not be safe. So the user needs to make sure all
1116
- // snapshot is released before enabling `bottommost_temperature` feature
1115
+ // snapshot is released before enabling `last_level_temperature` feature
1117
1116
  // We will migrate the feature to `last_level_temperature` and maybe make
1118
1117
  // it not dynamically changeable.
1119
1118
  if (ikey_.sequence > earliest_snapshot_) {
@@ -1126,7 +1125,7 @@ void CompactionIterator::DecideOutputLevel() {
1126
1125
  }
1127
1126
 
1128
1127
  void CompactionIterator::PrepareOutput() {
1129
- if (valid_) {
1128
+ if (Valid()) {
1130
1129
  if (ikey_.type == kTypeValue) {
1131
1130
  ExtractLargeValueIfNeeded();
1132
1131
  } else if (ikey_.type == kTypeBlobIndex) {
@@ -1148,7 +1147,7 @@ void CompactionIterator::PrepareOutput() {
1148
1147
  //
1149
1148
  // Can we do the same for levels above bottom level as long as
1150
1149
  // KeyNotExistsBeyondOutputLevel() return true?
1151
- if (valid_ && compaction_ != nullptr &&
1150
+ if (Valid() && compaction_ != nullptr &&
1152
1151
  !compaction_->allow_ingest_behind() && bottommost_level_ &&
1153
1152
  DefinitelyInSnapshot(ikey_.sequence, earliest_snapshot_) &&
1154
1153
  ikey_.type != kTypeMerge && current_key_committed_ &&
@@ -1162,13 +1161,14 @@ void CompactionIterator::PrepareOutput() {
1162
1161
  "earliest_snapshot %" PRIu64
1163
1162
  ", earliest_write_conflict_snapshot %" PRIu64
1164
1163
  " job_snapshot %" PRIu64
1165
- ". timestamp_size: %d full_history_ts_low_ %s",
1164
+ ". timestamp_size: %d full_history_ts_low_ %s. validity %x",
1166
1165
  ikey_.DebugString(allow_data_in_errors_, true).c_str(),
1167
1166
  earliest_snapshot_, earliest_write_conflict_snapshot_,
1168
1167
  job_snapshot_, static_cast<int>(timestamp_size_),
1169
1168
  full_history_ts_low_ != nullptr
1170
1169
  ? Slice(*full_history_ts_low_).ToString(true).c_str()
1171
- : "null");
1170
+ : "null",
1171
+ validity_info_.rep);
1172
1172
  assert(false);
1173
1173
  }
1174
1174
  ikey_.sequence = 0;
@@ -1284,7 +1284,10 @@ std::unique_ptr<BlobFetcher> CompactionIterator::CreateBlobFetcherIfNeeded(
1284
1284
  return nullptr;
1285
1285
  }
1286
1286
 
1287
- return std::unique_ptr<BlobFetcher>(new BlobFetcher(version, ReadOptions()));
1287
+ ReadOptions read_options;
1288
+ read_options.fill_cache = false;
1289
+
1290
+ return std::unique_ptr<BlobFetcher>(new BlobFetcher(version, read_options));
1288
1291
  }
1289
1292
 
1290
1293
  std::unique_ptr<PrefetchBufferCollection>
@@ -235,7 +235,7 @@ class CompactionIterator {
235
235
  const Slice& value() const { return value_; }
236
236
  const Status& status() const { return status_; }
237
237
  const ParsedInternalKey& ikey() const { return ikey_; }
238
- bool Valid() const { return valid_; }
238
+ inline bool Valid() const { return validity_info_.IsValid(); }
239
239
  const Slice& user_key() const { return current_user_key_; }
240
240
  const CompactionIterationStats& iter_stats() const { return iter_stats_; }
241
241
  uint64_t num_input_entry_scanned() const { return input_.num_itered(); }
@@ -332,29 +332,26 @@ class CompactionIterator {
332
332
  // earliest visible snapshot of an older value.
333
333
  // See WritePreparedTransactionTest::ReleaseSnapshotDuringCompaction3.
334
334
  std::unordered_set<SequenceNumber> released_snapshots_;
335
- std::vector<SequenceNumber>::const_iterator earliest_snapshot_iter_;
336
335
  const SequenceNumber earliest_write_conflict_snapshot_;
337
336
  const SequenceNumber job_snapshot_;
338
337
  const SnapshotChecker* const snapshot_checker_;
339
338
  Env* env_;
340
339
  SystemClock* clock_;
341
- bool report_detailed_time_;
342
- bool expect_valid_internal_key_;
340
+ const bool report_detailed_time_;
341
+ const bool expect_valid_internal_key_;
343
342
  CompactionRangeDelAggregator* range_del_agg_;
344
343
  BlobFileBuilder* blob_file_builder_;
345
344
  std::unique_ptr<CompactionProxy> compaction_;
346
345
  const CompactionFilter* compaction_filter_;
347
346
  const std::atomic<bool>* shutting_down_;
348
347
  const std::atomic<bool>& manual_compaction_canceled_;
349
- bool bottommost_level_;
350
- bool valid_ = false;
351
- bool visible_at_tip_;
352
- SequenceNumber earliest_snapshot_;
353
- SequenceNumber latest_snapshot_;
348
+ const bool bottommost_level_;
349
+ const bool visible_at_tip_;
350
+ const SequenceNumber earliest_snapshot_;
354
351
 
355
352
  std::shared_ptr<Logger> info_log_;
356
353
 
357
- bool allow_data_in_errors_;
354
+ const bool allow_data_in_errors_;
358
355
 
359
356
  const bool enforce_single_del_contracts_;
360
357
 
@@ -370,8 +367,33 @@ class CompactionIterator {
370
367
 
371
368
  // State
372
369
  //
370
+ enum ValidContext : uint8_t {
371
+ kMerge1 = 0,
372
+ kMerge2 = 1,
373
+ kParseKeyError = 2,
374
+ kCurrentKeyUncommitted = 3,
375
+ kKeepSDAndClearPut = 4,
376
+ kKeepTsHistory = 5,
377
+ kKeepSDForConflictCheck = 6,
378
+ kKeepSDForSnapshot = 7,
379
+ kKeepSD = 8,
380
+ kKeepDel = 9,
381
+ kNewUserKey = 10,
382
+ };
383
+
384
+ struct ValidityInfo {
385
+ inline bool IsValid() const { return rep & 1; }
386
+ ValidContext GetContext() const {
387
+ return static_cast<ValidContext>(rep >> 1);
388
+ }
389
+ inline void SetValid(uint8_t ctx) { rep = (ctx << 1) | 1; }
390
+ inline void Invalidate() { rep = 0; }
391
+
392
+ uint8_t rep{0};
393
+ } validity_info_;
394
+
373
395
  // Points to a copy of the current compaction iterator output (current_key_)
374
- // if valid_.
396
+ // if valid.
375
397
  Slice key_;
376
398
  // Points to the value in the underlying iterator that corresponds to the
377
399
  // current output.
@@ -240,8 +240,8 @@ void CompactionJob::Prepare() {
240
240
  bottommost_level_ = c->bottommost_level();
241
241
 
242
242
  if (c->ShouldFormSubcompactions()) {
243
- StopWatch sw(db_options_.clock, stats_, SUBCOMPACTION_SETUP_TIME);
244
- GenSubcompactionBoundaries();
243
+ StopWatch sw(db_options_.clock, stats_, SUBCOMPACTION_SETUP_TIME);
244
+ GenSubcompactionBoundaries();
245
245
  }
246
246
  if (boundaries_.size() > 1) {
247
247
  for (size_t i = 0; i <= boundaries_.size(); i++) {
@@ -250,6 +250,11 @@ void CompactionJob::Prepare() {
250
250
  (i != boundaries_.size()) ? std::optional<Slice>(boundaries_[i])
251
251
  : std::nullopt,
252
252
  static_cast<uint32_t>(i));
253
+ // assert to validate that boundaries don't have same user keys (without
254
+ // timestamp part).
255
+ assert(i == 0 || i == boundaries_.size() ||
256
+ cfd->user_comparator()->CompareWithoutTimestamp(
257
+ boundaries_[i - 1], true, boundaries_[i], true) < 0);
253
258
  }
254
259
  RecordInHistogram(stats_, NUM_SUBCOMPACTIONS_SCHEDULED,
255
260
  compact_->sub_compact_states.size());
@@ -479,9 +484,20 @@ void CompactionJob::GenSubcompactionBoundaries() {
479
484
  std::sort(
480
485
  all_anchors.begin(), all_anchors.end(),
481
486
  [cfd_comparator](TableReader::Anchor& a, TableReader::Anchor& b) -> bool {
482
- return cfd_comparator->Compare(a.user_key, b.user_key) < 0;
487
+ return cfd_comparator->CompareWithoutTimestamp(a.user_key, true,
488
+ b.user_key, true) < 0;
483
489
  });
484
490
 
491
+ // Remove duplicated entries from boundaries.
492
+ all_anchors.erase(
493
+ std::unique(all_anchors.begin(), all_anchors.end(),
494
+ [cfd_comparator](TableReader::Anchor& a,
495
+ TableReader::Anchor& b) -> bool {
496
+ return cfd_comparator->CompareWithoutTimestamp(
497
+ a.user_key, true, b.user_key, true) == 0;
498
+ }),
499
+ all_anchors.end());
500
+
485
501
  // Get the number of planned subcompactions, may update reserve threads
486
502
  // and update extra_num_subcompaction_threads_reserved_ for round-robin
487
503
  uint64_t num_planned_subcompactions;
@@ -508,6 +524,8 @@ void CompactionJob::GenSubcompactionBoundaries() {
508
524
  // of planned subcompactions
509
525
  num_planned_subcompactions =
510
526
  std::min(num_planned_subcompactions, GetSubcompactionsLimit());
527
+ } else {
528
+ num_planned_subcompactions = max_subcompactions_limit;
511
529
  }
512
530
  } else {
513
531
  num_planned_subcompactions = GetSubcompactionsLimit();
@@ -1022,6 +1040,9 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) {
1022
1040
  const std::optional<Slice> start = sub_compact->start;
1023
1041
  const std::optional<Slice> end = sub_compact->end;
1024
1042
 
1043
+ std::optional<Slice> start_without_ts;
1044
+ std::optional<Slice> end_without_ts;
1045
+
1025
1046
  ReadOptions read_options;
1026
1047
  read_options.verify_checksums = true;
1027
1048
  read_options.fill_cache = false;
@@ -1032,15 +1053,22 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) {
1032
1053
  // (b) CompactionFilter::Decision::kRemoveAndSkipUntil.
1033
1054
  read_options.total_order_seek = true;
1034
1055
 
1035
- // Note: if we're going to support subcompactions for user-defined timestamps,
1036
- // the timestamp part will have to be stripped from the bounds here.
1037
- assert((!start.has_value() && !end.has_value()) ||
1038
- cfd->user_comparator()->timestamp_size() == 0);
1056
+ // Remove the timestamps from boundaries because boundaries created in
1057
+ // GenSubcompactionBoundaries doesn't strip away the timestamp.
1058
+ size_t ts_sz = cfd->user_comparator()->timestamp_size();
1039
1059
  if (start.has_value()) {
1040
1060
  read_options.iterate_lower_bound = &start.value();
1061
+ if (ts_sz > 0) {
1062
+ start_without_ts = StripTimestampFromUserKey(start.value(), ts_sz);
1063
+ read_options.iterate_lower_bound = &start_without_ts.value();
1064
+ }
1041
1065
  }
1042
1066
  if (end.has_value()) {
1043
1067
  read_options.iterate_upper_bound = &end.value();
1068
+ if (ts_sz > 0) {
1069
+ end_without_ts = StripTimestampFromUserKey(end.value(), ts_sz);
1070
+ read_options.iterate_upper_bound = &end_without_ts.value();
1071
+ }
1044
1072
  }
1045
1073
 
1046
1074
  // Although the v2 aggregator is what the level iterator(s) know about,
@@ -1688,13 +1716,16 @@ Status CompactionJob::OpenCompactionOutputFile(SubcompactionState* sub_compact,
1688
1716
  &syncpoint_arg);
1689
1717
  #endif
1690
1718
 
1691
- // Pass temperature of botommost files to FileSystem.
1719
+ // Pass temperature of the last level files to FileSystem.
1692
1720
  FileOptions fo_copy = file_options_;
1693
1721
  Temperature temperature = sub_compact->compaction->output_temperature();
1694
- if (temperature == Temperature::kUnknown && bottommost_level_ &&
1722
+ // only set for the last level compaction and also it's not output to
1723
+ // penultimate level (when preclude_last_level feature is enabled)
1724
+ if (temperature == Temperature::kUnknown &&
1725
+ sub_compact->compaction->is_last_level() &&
1695
1726
  !sub_compact->IsCurrentPenultimateLevel()) {
1696
1727
  temperature =
1697
- sub_compact->compaction->mutable_cf_options()->bottommost_temperature;
1728
+ sub_compact->compaction->mutable_cf_options()->last_level_temperature;
1698
1729
  }
1699
1730
  fo_copy.temperature = temperature;
1700
1731
 
@@ -1930,7 +1961,10 @@ void CompactionJob::LogCompaction() {
1930
1961
  stream.EndArray();
1931
1962
  }
1932
1963
  stream << "score" << compaction->score() << "input_data_size"
1933
- << compaction->CalculateTotalInputSize();
1964
+ << compaction->CalculateTotalInputSize() << "oldest_snapshot_seqno"
1965
+ << (existing_snapshots_.empty()
1966
+ ? int64_t{-1} // Use -1 for "none"
1967
+ : static_cast<int64_t>(existing_snapshots_[0]));
1934
1968
  }
1935
1969
  }
1936
1970
 
@@ -372,8 +372,7 @@ class CompactionJobTestBase : public testing::Test {
372
372
  smallest_seqno, largest_seqno, false, Temperature::kUnknown,
373
373
  oldest_blob_file_number, kUnknownOldestAncesterTime,
374
374
  kUnknownFileCreationTime, kUnknownFileChecksum,
375
- kUnknownFileChecksumFuncName, kDisableUserTimestamp,
376
- kDisableUserTimestamp, kNullUniqueId64x2);
375
+ kUnknownFileChecksumFuncName, kNullUniqueId64x2);
377
376
 
378
377
  mutex_.Lock();
379
378
  EXPECT_OK(