@nxtedition/rocksdb 13.5.12 → 14.0.0

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 (232) hide show
  1. package/binding.cc +33 -2
  2. package/binding.gyp +2 -2
  3. package/chained-batch.js +9 -16
  4. package/deps/rocksdb/rocksdb/BUCK +18 -1
  5. package/deps/rocksdb/rocksdb/CMakeLists.txt +10 -3
  6. package/deps/rocksdb/rocksdb/Makefile +20 -9
  7. package/deps/rocksdb/rocksdb/cache/cache_bench_tool.cc +90 -13
  8. package/deps/rocksdb/rocksdb/cache/clock_cache.cc +88 -75
  9. package/deps/rocksdb/rocksdb/cache/clock_cache.h +44 -36
  10. package/deps/rocksdb/rocksdb/cache/compressed_secondary_cache.cc +184 -148
  11. package/deps/rocksdb/rocksdb/cache/compressed_secondary_cache.h +5 -11
  12. package/deps/rocksdb/rocksdb/cache/compressed_secondary_cache_test.cc +116 -47
  13. package/deps/rocksdb/rocksdb/cache/lru_cache_test.cc +1 -1
  14. package/deps/rocksdb/rocksdb/cache/secondary_cache_adapter.cc +3 -6
  15. package/deps/rocksdb/rocksdb/db/arena_wrapped_db_iter.h +1 -1
  16. package/deps/rocksdb/rocksdb/db/builder.cc +4 -2
  17. package/deps/rocksdb/rocksdb/db/c.cc +207 -0
  18. package/deps/rocksdb/rocksdb/db/c_test.c +72 -0
  19. package/deps/rocksdb/rocksdb/db/column_family.cc +3 -2
  20. package/deps/rocksdb/rocksdb/db/column_family.h +5 -0
  21. package/deps/rocksdb/rocksdb/db/compact_files_test.cc +4 -0
  22. package/deps/rocksdb/rocksdb/db/compaction/compaction.cc +2 -0
  23. package/deps/rocksdb/rocksdb/db/compaction/compaction_iterator.cc +51 -38
  24. package/deps/rocksdb/rocksdb/db/compaction/compaction_iterator.h +29 -12
  25. package/deps/rocksdb/rocksdb/db/compaction/compaction_iterator_test.cc +5 -10
  26. package/deps/rocksdb/rocksdb/db/compaction/compaction_job.cc +566 -366
  27. package/deps/rocksdb/rocksdb/db/compaction/compaction_job.h +131 -4
  28. package/deps/rocksdb/rocksdb/db/compaction/compaction_outputs.cc +1 -0
  29. package/deps/rocksdb/rocksdb/db/compaction/compaction_outputs.h +7 -0
  30. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker.cc +4 -4
  31. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker.h +13 -14
  32. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_fifo.cc +12 -7
  33. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_fifo.h +8 -10
  34. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_test.cc +97 -76
  35. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_universal.cc +11 -14
  36. package/deps/rocksdb/rocksdb/db/compaction/compaction_service_job.cc +1 -1
  37. package/deps/rocksdb/rocksdb/db/compaction/subcompaction_state.h +8 -0
  38. package/deps/rocksdb/rocksdb/db/compaction/tiered_compaction_test.cc +16 -3
  39. package/deps/rocksdb/rocksdb/db/db_basic_test.cc +1 -0
  40. package/deps/rocksdb/rocksdb/db/db_compaction_test.cc +448 -1
  41. package/deps/rocksdb/rocksdb/db/db_impl/db_impl.cc +22 -20
  42. package/deps/rocksdb/rocksdb/db/db_impl/db_impl.h +4 -1
  43. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_compaction_flush.cc +5 -5
  44. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_open.cc +7 -3
  45. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_secondary.cc +1 -1
  46. package/deps/rocksdb/rocksdb/db/db_iter.cc +104 -0
  47. package/deps/rocksdb/rocksdb/db/db_iter.h +4 -11
  48. package/deps/rocksdb/rocksdb/db/db_iterator_test.cc +331 -58
  49. package/deps/rocksdb/rocksdb/db/db_memtable_test.cc +129 -0
  50. package/deps/rocksdb/rocksdb/db/db_sst_test.cc +64 -0
  51. package/deps/rocksdb/rocksdb/db/db_table_properties_test.cc +40 -0
  52. package/deps/rocksdb/rocksdb/db/db_test2.cc +25 -15
  53. package/deps/rocksdb/rocksdb/db/db_test_util.cc +42 -24
  54. package/deps/rocksdb/rocksdb/db/db_test_util.h +29 -14
  55. package/deps/rocksdb/rocksdb/db/db_universal_compaction_test.cc +69 -36
  56. package/deps/rocksdb/rocksdb/db/db_with_timestamp_basic_test.cc +0 -1
  57. package/deps/rocksdb/rocksdb/db/event_helpers.cc +1 -0
  58. package/deps/rocksdb/rocksdb/db/experimental.cc +5 -4
  59. package/deps/rocksdb/rocksdb/db/external_sst_file_basic_test.cc +8 -1
  60. package/deps/rocksdb/rocksdb/db/external_sst_file_ingestion_job.cc +275 -79
  61. package/deps/rocksdb/rocksdb/db/external_sst_file_ingestion_job.h +23 -5
  62. package/deps/rocksdb/rocksdb/db/external_sst_file_test.cc +591 -175
  63. package/deps/rocksdb/rocksdb/db/flush_job.cc +3 -4
  64. package/deps/rocksdb/rocksdb/db/log_reader.cc +5 -2
  65. package/deps/rocksdb/rocksdb/db/memtable.cc +84 -35
  66. package/deps/rocksdb/rocksdb/db/memtable.h +39 -34
  67. package/deps/rocksdb/rocksdb/db/merge_helper.cc +1 -0
  68. package/deps/rocksdb/rocksdb/db/merge_operator.cc +1 -1
  69. package/deps/rocksdb/rocksdb/db/multi_scan.cc +11 -5
  70. package/deps/rocksdb/rocksdb/db/version_edit.cc +1 -1
  71. package/deps/rocksdb/rocksdb/db/version_edit.h +1 -1
  72. package/deps/rocksdb/rocksdb/db/version_edit_handler.cc +34 -14
  73. package/deps/rocksdb/rocksdb/db/version_edit_handler.h +28 -5
  74. package/deps/rocksdb/rocksdb/db/version_set.cc +159 -14
  75. package/deps/rocksdb/rocksdb/db/version_set.h +2 -0
  76. package/deps/rocksdb/rocksdb/db_stress_tool/CMakeLists.txt +1 -1
  77. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_common.cc +60 -0
  78. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_common.h +16 -1
  79. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_compaction_service.h +75 -10
  80. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_compression_manager.cc +28 -0
  81. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_compression_manager.h +2 -0
  82. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_driver.cc +31 -1
  83. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_gflags.cc +50 -2
  84. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_shared_state.h +57 -0
  85. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_stat.h +0 -4
  86. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_test_base.cc +266 -35
  87. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_test_base.h +5 -0
  88. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_tool.cc +0 -6
  89. package/deps/rocksdb/rocksdb/db_stress_tool/no_batched_ops_stress.cc +18 -2
  90. package/deps/rocksdb/rocksdb/env/env.cc +12 -0
  91. package/deps/rocksdb/rocksdb/env/env_test.cc +18 -0
  92. package/deps/rocksdb/rocksdb/env/file_system_tracer.cc +2 -0
  93. package/deps/rocksdb/rocksdb/env/fs_posix.cc +9 -5
  94. package/deps/rocksdb/rocksdb/env/io_posix.cc +4 -2
  95. package/deps/rocksdb/rocksdb/file/random_access_file_reader.cc +19 -0
  96. package/deps/rocksdb/rocksdb/include/rocksdb/advanced_compression.h +33 -31
  97. package/deps/rocksdb/rocksdb/include/rocksdb/advanced_options.h +42 -9
  98. package/deps/rocksdb/rocksdb/include/rocksdb/c.h +93 -0
  99. package/deps/rocksdb/rocksdb/include/rocksdb/cache.h +43 -49
  100. package/deps/rocksdb/rocksdb/include/rocksdb/compaction_job_stats.h +4 -3
  101. package/deps/rocksdb/rocksdb/include/rocksdb/compression_type.h +8 -6
  102. package/deps/rocksdb/rocksdb/include/rocksdb/data_structure.h +487 -0
  103. package/deps/rocksdb/rocksdb/include/rocksdb/db.h +11 -12
  104. package/deps/rocksdb/rocksdb/include/rocksdb/env.h +135 -1
  105. package/deps/rocksdb/rocksdb/include/rocksdb/file_system.h +5 -0
  106. package/deps/rocksdb/rocksdb/include/rocksdb/iostats_context.h +12 -0
  107. package/deps/rocksdb/rocksdb/include/rocksdb/iterator.h +1 -1
  108. package/deps/rocksdb/rocksdb/include/rocksdb/ldb_tool.h +8 -0
  109. package/deps/rocksdb/rocksdb/include/rocksdb/memtablerep.h +12 -8
  110. package/deps/rocksdb/rocksdb/include/rocksdb/metadata.h +3 -0
  111. package/deps/rocksdb/rocksdb/include/rocksdb/multi_scan.h +19 -9
  112. package/deps/rocksdb/rocksdb/include/rocksdb/options.h +219 -24
  113. package/deps/rocksdb/rocksdb/include/rocksdb/point_lock_bench_tool.h +14 -0
  114. package/deps/rocksdb/rocksdb/include/rocksdb/secondary_cache.h +2 -2
  115. package/deps/rocksdb/rocksdb/include/rocksdb/slice.h +1 -1
  116. package/deps/rocksdb/rocksdb/include/rocksdb/statistics.h +7 -0
  117. package/deps/rocksdb/rocksdb/include/rocksdb/status.h +16 -0
  118. package/deps/rocksdb/rocksdb/include/rocksdb/table.h +16 -4
  119. package/deps/rocksdb/rocksdb/include/rocksdb/table_properties.h +13 -0
  120. package/deps/rocksdb/rocksdb/include/rocksdb/types.h +4 -0
  121. package/deps/rocksdb/rocksdb/include/rocksdb/universal_compaction.h +0 -2
  122. package/deps/rocksdb/rocksdb/include/rocksdb/user_defined_index.h +45 -0
  123. package/deps/rocksdb/rocksdb/include/rocksdb/utilities/cache_dump_load.h +1 -1
  124. package/deps/rocksdb/rocksdb/include/rocksdb/utilities/stackable_db.h +1 -1
  125. package/deps/rocksdb/rocksdb/include/rocksdb/utilities/transaction.h +6 -1
  126. package/deps/rocksdb/rocksdb/include/rocksdb/utilities/transaction_db.h +21 -0
  127. package/deps/rocksdb/rocksdb/include/rocksdb/version.h +2 -2
  128. package/deps/rocksdb/rocksdb/memory/memory_allocator_impl.h +3 -3
  129. package/deps/rocksdb/rocksdb/memtable/inlineskiplist.h +77 -51
  130. package/deps/rocksdb/rocksdb/memtable/skiplist.h +10 -13
  131. package/deps/rocksdb/rocksdb/memtable/skiplistrep.cc +16 -7
  132. package/deps/rocksdb/rocksdb/memtable/vectorrep.cc +9 -4
  133. package/deps/rocksdb/rocksdb/monitoring/iostats_context.cc +2 -0
  134. package/deps/rocksdb/rocksdb/monitoring/statistics.cc +6 -0
  135. package/deps/rocksdb/rocksdb/options/cf_options.cc +13 -1
  136. package/deps/rocksdb/rocksdb/options/cf_options.h +6 -2
  137. package/deps/rocksdb/rocksdb/options/options.cc +2 -0
  138. package/deps/rocksdb/rocksdb/options/options_helper.cc +9 -8
  139. package/deps/rocksdb/rocksdb/options/options_settable_test.cc +9 -5
  140. package/deps/rocksdb/rocksdb/port/mmap.cc +1 -1
  141. package/deps/rocksdb/rocksdb/port/win/xpress_win.cc +51 -0
  142. package/deps/rocksdb/rocksdb/port/win/xpress_win.h +4 -0
  143. package/deps/rocksdb/rocksdb/src.mk +8 -2
  144. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_builder.cc +1125 -765
  145. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_builder.h +35 -24
  146. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_factory.cc +29 -4
  147. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_iterator.cc +732 -256
  148. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_iterator.h +225 -16
  149. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader.cc +102 -26
  150. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader.h +1 -1
  151. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader_sync_and_async.h +2 -75
  152. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader_test.cc +433 -141
  153. package/deps/rocksdb/rocksdb/table/block_based/block_builder.h +2 -0
  154. package/deps/rocksdb/rocksdb/table/block_based/flush_block_policy.cc +17 -10
  155. package/deps/rocksdb/rocksdb/table/block_based/flush_block_policy_impl.h +20 -0
  156. package/deps/rocksdb/rocksdb/table/block_based/index_builder.cc +112 -85
  157. package/deps/rocksdb/rocksdb/table/block_based/index_builder.h +191 -36
  158. package/deps/rocksdb/rocksdb/table/block_based/partitioned_filter_block.cc +2 -2
  159. package/deps/rocksdb/rocksdb/table/block_based/partitioned_filter_block_test.cc +1 -1
  160. package/deps/rocksdb/rocksdb/table/block_based/user_defined_index_wrapper.h +108 -31
  161. package/deps/rocksdb/rocksdb/table/external_table.cc +7 -3
  162. package/deps/rocksdb/rocksdb/table/format.cc +6 -12
  163. package/deps/rocksdb/rocksdb/table/format.h +10 -0
  164. package/deps/rocksdb/rocksdb/table/internal_iterator.h +1 -1
  165. package/deps/rocksdb/rocksdb/table/iterator_wrapper.h +1 -1
  166. package/deps/rocksdb/rocksdb/table/merging_iterator.cc +1 -1
  167. package/deps/rocksdb/rocksdb/table/meta_blocks.cc +5 -0
  168. package/deps/rocksdb/rocksdb/table/multiget_context.h +3 -1
  169. package/deps/rocksdb/rocksdb/table/sst_file_dumper.cc +118 -46
  170. package/deps/rocksdb/rocksdb/table/sst_file_dumper.h +9 -8
  171. package/deps/rocksdb/rocksdb/table/table_builder.h +5 -0
  172. package/deps/rocksdb/rocksdb/table/table_properties.cc +16 -0
  173. package/deps/rocksdb/rocksdb/table/table_test.cc +1540 -155
  174. package/deps/rocksdb/rocksdb/test_util/testutil.h +21 -5
  175. package/deps/rocksdb/rocksdb/tools/db_bench_tool.cc +26 -5
  176. package/deps/rocksdb/rocksdb/tools/ldb.cc +1 -2
  177. package/deps/rocksdb/rocksdb/tools/ldb_cmd.cc +2 -0
  178. package/deps/rocksdb/rocksdb/tools/ldb_tool.cc +9 -3
  179. package/deps/rocksdb/rocksdb/tools/sst_dump_test.cc +133 -165
  180. package/deps/rocksdb/rocksdb/tools/sst_dump_tool.cc +173 -64
  181. package/deps/rocksdb/rocksdb/util/aligned_buffer.h +69 -0
  182. package/deps/rocksdb/rocksdb/util/atomic.h +6 -0
  183. package/deps/rocksdb/rocksdb/util/auto_tune_compressor.cc +29 -20
  184. package/deps/rocksdb/rocksdb/util/auto_tune_compressor.h +10 -6
  185. package/deps/rocksdb/rocksdb/util/bit_fields.h +338 -0
  186. package/deps/rocksdb/rocksdb/util/coding.h +3 -3
  187. package/deps/rocksdb/rocksdb/util/compaction_job_stats_impl.cc +2 -2
  188. package/deps/rocksdb/rocksdb/util/compression.cc +777 -82
  189. package/deps/rocksdb/rocksdb/util/compression.h +5 -0
  190. package/deps/rocksdb/rocksdb/util/compression_test.cc +5 -3
  191. package/deps/rocksdb/rocksdb/util/dynamic_bloom.cc +2 -2
  192. package/deps/rocksdb/rocksdb/util/dynamic_bloom.h +15 -14
  193. package/deps/rocksdb/rocksdb/util/interval_test.cc +102 -0
  194. package/deps/rocksdb/rocksdb/util/semaphore.h +164 -0
  195. package/deps/rocksdb/rocksdb/util/simple_mixed_compressor.cc +10 -6
  196. package/deps/rocksdb/rocksdb/util/simple_mixed_compressor.h +4 -2
  197. package/deps/rocksdb/rocksdb/util/slice_test.cc +136 -0
  198. package/deps/rocksdb/rocksdb/util/status.cc +1 -0
  199. package/deps/rocksdb/rocksdb/util/string_util.cc +2 -16
  200. package/deps/rocksdb/rocksdb/utilities/cache_dump_load_impl.cc +1 -1
  201. package/deps/rocksdb/rocksdb/utilities/cache_dump_load_impl.h +1 -1
  202. package/deps/rocksdb/rocksdb/utilities/fault_injection_fs.cc +7 -4
  203. package/deps/rocksdb/rocksdb/utilities/fault_injection_fs.h +35 -14
  204. package/deps/rocksdb/rocksdb/utilities/persistent_cache/hash_table_test.cc +2 -0
  205. package/deps/rocksdb/rocksdb/utilities/transactions/lock/lock_manager.cc +5 -2
  206. package/deps/rocksdb/rocksdb/utilities/transactions/lock/point/any_lock_manager_test.h +244 -0
  207. package/deps/rocksdb/rocksdb/utilities/transactions/lock/point/point_lock_bench.cc +18 -0
  208. package/deps/rocksdb/rocksdb/utilities/transactions/lock/point/point_lock_bench_tool.cc +159 -0
  209. package/deps/rocksdb/rocksdb/utilities/transactions/lock/point/point_lock_manager.cc +1244 -161
  210. package/deps/rocksdb/rocksdb/utilities/transactions/lock/point/point_lock_manager.h +66 -12
  211. package/deps/rocksdb/rocksdb/utilities/transactions/lock/point/point_lock_manager_stress_test.cc +103 -0
  212. package/deps/rocksdb/rocksdb/utilities/transactions/lock/point/point_lock_manager_test.cc +1275 -8
  213. package/deps/rocksdb/rocksdb/utilities/transactions/lock/point/point_lock_manager_test.h +40 -262
  214. package/deps/rocksdb/rocksdb/utilities/transactions/lock/point/point_lock_manager_test_common.h +78 -0
  215. package/deps/rocksdb/rocksdb/utilities/transactions/lock/point/point_lock_validation_test_runner.h +469 -0
  216. package/deps/rocksdb/rocksdb/utilities/transactions/lock/range/range_locking_test.cc +2 -6
  217. package/deps/rocksdb/rocksdb/utilities/transactions/pessimistic_transaction.cc +4 -0
  218. package/deps/rocksdb/rocksdb/utilities/transactions/pessimistic_transaction.h +9 -1
  219. package/deps/rocksdb/rocksdb/utilities/transactions/timestamped_snapshot_test.cc +18 -9
  220. package/deps/rocksdb/rocksdb/utilities/transactions/transaction_base.h +2 -0
  221. package/deps/rocksdb/rocksdb/utilities/transactions/transaction_db_mutex_impl.cc +2 -1
  222. package/deps/rocksdb/rocksdb/utilities/transactions/transaction_test.cc +72 -44
  223. package/deps/rocksdb/rocksdb/utilities/transactions/transaction_test.h +92 -15
  224. package/deps/rocksdb/rocksdb/utilities/transactions/write_committed_transaction_ts_test.cc +6 -20
  225. package/deps/rocksdb/rocksdb/utilities/transactions/write_prepared_transaction_test.cc +143 -112
  226. package/deps/rocksdb/rocksdb/utilities/transactions/write_unprepared_transaction_test.cc +23 -16
  227. package/index.js +3 -3
  228. package/package.json +1 -1
  229. package/prebuilds/darwin-arm64/@nxtedition+rocksdb.node +0 -0
  230. package/prebuilds/linux-x64/@nxtedition+rocksdb.node +0 -0
  231. package/util.h +38 -12
  232. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_stat.cc +0 -17
@@ -4142,13 +4142,18 @@ TEST_P(DBIteratorTest, AverageMemtableOpsScanFlushTriggerByOverwrites) {
4142
4142
  ASSERT_EQ(1, NumTableFilesAtLevel(0));
4143
4143
  }
4144
4144
 
4145
- class DBMultiScanIteratorTest : public DBTestBase {
4145
+ class DBMultiScanIteratorTest : public DBTestBase,
4146
+ public ::testing::WithParamInterface<bool> {
4146
4147
  public:
4147
4148
  DBMultiScanIteratorTest()
4148
4149
  : DBTestBase("db_multi_scan_iterator_test", /*env_do_fsync=*/true) {}
4149
4150
  };
4150
4151
 
4151
- TEST_F(DBMultiScanIteratorTest, BasicTest) {
4152
+ // Param 0: ReadOptions::fill_cache
4153
+ INSTANTIATE_TEST_CASE_P(DBMultiScanIteratorTest, DBMultiScanIteratorTest,
4154
+ ::testing::Bool());
4155
+
4156
+ TEST_P(DBMultiScanIteratorTest, BasicTest) {
4152
4157
  // Create a file
4153
4158
  for (int i = 0; i < 100; ++i) {
4154
4159
  std::stringstream ss;
@@ -4159,9 +4164,10 @@ TEST_F(DBMultiScanIteratorTest, BasicTest) {
4159
4164
 
4160
4165
  std::vector<std::string> key_ranges({"k03", "k10", "k25", "k50"});
4161
4166
  ReadOptions ro;
4162
- std::vector<ScanOptions> scan_options(
4163
- {ScanOptions(key_ranges[0], key_ranges[1]),
4164
- ScanOptions(key_ranges[2], key_ranges[3])});
4167
+ ro.fill_cache = GetParam();
4168
+ MultiScanArgs scan_options(BytewiseComparator());
4169
+ scan_options.insert(key_ranges[0], key_ranges[1]);
4170
+ scan_options.insert(key_ranges[2], key_ranges[3]);
4165
4171
  ColumnFamilyHandle* cfh = dbfull()->DefaultColumnFamily();
4166
4172
  std::unique_ptr<MultiScan> iter =
4167
4173
  dbfull()->NewMultiScan(ro, cfh, scan_options);
@@ -4187,23 +4193,48 @@ TEST_F(DBMultiScanIteratorTest, BasicTest) {
4187
4193
  abort();
4188
4194
  }
4189
4195
  iter.reset();
4196
+ }
4190
4197
 
4191
- // Test the overlapping scan case
4192
- key_ranges[1] = "k30";
4193
- scan_options[0] = ScanOptions(key_ranges[0], key_ranges[1]);
4194
- iter = dbfull()->NewMultiScan(ro, cfh, scan_options);
4198
+ TEST_P(DBMultiScanIteratorTest, MixedBoundsTest) {
4199
+ // Create a file
4200
+ for (int i = 0; i < 100; ++i) {
4201
+ std::stringstream ss;
4202
+ ss << std::setw(2) << std::setfill('0') << i;
4203
+ ASSERT_OK(Put("k" + ss.str(), "val" + ss.str()));
4204
+ }
4205
+ ASSERT_OK(Flush());
4206
+
4207
+ std::vector<std::string> key_ranges(
4208
+ {"k03", "k10", "k25", "k50", "k75", "k90"});
4209
+ ReadOptions ro;
4210
+ ro.fill_cache = GetParam();
4211
+ MultiScanArgs scan_options(BytewiseComparator());
4212
+ scan_options.insert(key_ranges[0], key_ranges[1]);
4213
+ scan_options.insert(key_ranges[2]);
4214
+ scan_options.insert(key_ranges[4], key_ranges[5]);
4215
+ ColumnFamilyHandle* cfh = dbfull()->DefaultColumnFamily();
4216
+ std::unique_ptr<MultiScan> iter =
4217
+ dbfull()->NewMultiScan(ro, cfh, scan_options);
4195
4218
  try {
4196
4219
  int idx = 0;
4197
4220
  int count = 0;
4198
4221
  for (auto range : *iter) {
4199
4222
  for (auto it : range) {
4200
- ASSERT_GE(it.first.ToString().compare(key_ranges[idx]), 0);
4201
- ASSERT_LT(it.first.ToString().compare(key_ranges[idx + 1]), 0);
4223
+ ASSERT_GE(
4224
+ it.first.ToString().compare(
4225
+ scan_options.GetScanRanges()[idx].range.start->ToString()),
4226
+ 0);
4227
+ if (scan_options.GetScanRanges()[idx].range.limit) {
4228
+ ASSERT_LT(
4229
+ it.first.ToString().compare(
4230
+ scan_options.GetScanRanges()[idx].range.limit->ToString()),
4231
+ 0);
4232
+ }
4202
4233
  count++;
4203
4234
  }
4204
- idx += 2;
4235
+ idx++;
4205
4236
  }
4206
- ASSERT_EQ(count, 52);
4237
+ ASSERT_EQ(count, 97);
4207
4238
  } catch (MultiScanException& ex) {
4208
4239
  // Make sure exception contains the status
4209
4240
  ASSERT_NOK(ex.status());
@@ -4214,25 +4245,31 @@ TEST_F(DBMultiScanIteratorTest, BasicTest) {
4214
4245
  abort();
4215
4246
  }
4216
4247
  iter.reset();
4217
-
4218
- // Test the no limit scan case
4219
- scan_options[0] = ScanOptions(key_ranges[0]);
4220
- scan_options[1] = ScanOptions(key_ranges[2]);
4248
+ scan_options = MultiScanArgs(BytewiseComparator());
4249
+ scan_options.insert(key_ranges[0]);
4250
+ scan_options.insert(key_ranges[2], key_ranges[3]);
4251
+ scan_options.insert(key_ranges[4]);
4221
4252
  iter = dbfull()->NewMultiScan(ro, cfh, scan_options);
4222
4253
  try {
4223
4254
  int idx = 0;
4224
4255
  int count = 0;
4225
4256
  for (auto range : *iter) {
4226
4257
  for (auto it : range) {
4227
- ASSERT_GE(it.first.ToString().compare(key_ranges[idx]), 0);
4228
- if (it.first.ToString().compare(key_ranges[idx + 1]) == 0) {
4229
- break;
4258
+ ASSERT_GE(
4259
+ it.first.ToString().compare(
4260
+ scan_options.GetScanRanges()[idx].range.start->ToString()),
4261
+ 0);
4262
+ if (scan_options.GetScanRanges()[idx].range.limit) {
4263
+ ASSERT_LT(
4264
+ it.first.ToString().compare(
4265
+ scan_options.GetScanRanges()[idx].range.limit->ToString()),
4266
+ 0);
4230
4267
  }
4231
4268
  count++;
4232
4269
  }
4233
- idx += 2;
4270
+ idx++;
4234
4271
  }
4235
- ASSERT_EQ(count, 52);
4272
+ ASSERT_EQ(count, 147);
4236
4273
  } catch (MultiScanException& ex) {
4237
4274
  // Make sure exception contains the status
4238
4275
  ASSERT_NOK(ex.status());
@@ -4245,42 +4282,150 @@ TEST_F(DBMultiScanIteratorTest, BasicTest) {
4245
4282
  iter.reset();
4246
4283
  }
4247
4284
 
4248
- TEST_F(DBMultiScanIteratorTest, MixedBoundsTest) {
4285
+ TEST_P(DBMultiScanIteratorTest, RangeAcrossFiles) {
4286
+ auto options = CurrentOptions();
4287
+ options.target_file_size_base = 100 << 10; // 20KB
4288
+ options.compaction_style = kCompactionStyleUniversal;
4289
+ options.num_levels = 50;
4290
+ options.compression = kNoCompression;
4291
+ DestroyAndReopen(options);
4292
+
4293
+ auto rnd = Random::GetTLSInstance();
4294
+ // Write ~200KB data
4295
+ for (int i = 0; i < 100; ++i) {
4296
+ ASSERT_OK(Put(Key(i), rnd->RandomString(2 << 10)));
4297
+ }
4298
+ ASSERT_OK(Flush());
4299
+
4300
+ ASSERT_OK(db_->CompactRange({}, nullptr, nullptr));
4301
+ ASSERT_EQ(2, NumTableFilesAtLevel(49));
4302
+ std::vector<std::string> key_ranges({Key(10), Key(90)});
4303
+ ReadOptions ro;
4304
+ ro.fill_cache = GetParam();
4305
+ MultiScanArgs scan_options(BytewiseComparator());
4306
+ scan_options.insert(key_ranges[0], key_ranges[1]);
4307
+ ColumnFamilyHandle* cfh = dbfull()->DefaultColumnFamily();
4308
+ std::unique_ptr<MultiScan> iter =
4309
+ dbfull()->NewMultiScan(ro, cfh, scan_options);
4310
+ try {
4311
+ int i = 10;
4312
+ for (auto range : *iter) {
4313
+ for (auto it : range) {
4314
+ ASSERT_EQ(it.first.ToString(), Key(i));
4315
+ ++i;
4316
+ }
4317
+ }
4318
+ ASSERT_EQ(i, 90);
4319
+ } catch (MultiScanException& ex) {
4320
+ // Make sure exception contains the status
4321
+ ASSERT_NOK(ex.status());
4322
+ std::cerr << "Iterator returned status " << ex.what();
4323
+ abort();
4324
+ } catch (std::logic_error& ex) {
4325
+ std::cerr << "Iterator returned logic error " << ex.what();
4326
+ abort();
4327
+ }
4328
+ iter.reset();
4329
+ }
4330
+
4331
+ TEST_P(DBMultiScanIteratorTest, FailureTest) {
4332
+ auto options = CurrentOptions();
4333
+ options.compression = kNoCompression;
4334
+ DestroyAndReopen(options);
4335
+
4336
+ Random rnd(301);
4249
4337
  // Create a file
4250
4338
  for (int i = 0; i < 100; ++i) {
4251
4339
  std::stringstream ss;
4252
4340
  ss << std::setw(2) << std::setfill('0') << i;
4253
- ASSERT_OK(Put("k" + ss.str(), "val" + ss.str()));
4341
+ ASSERT_OK(Put("k" + ss.str(), rnd.RandomString(1024)));
4254
4342
  }
4255
4343
  ASSERT_OK(Flush());
4256
4344
 
4257
- std::vector<std::string> key_ranges(
4258
- {"k03", "k10", "k25", "k50", "k75", "k90"});
4345
+ std::vector<std::string> key_ranges({"k04", "k06", "k12", "k14"});
4346
+ ReadOptions ro;
4347
+ Slice ub;
4348
+ ro.iterate_upper_bound = &ub;
4349
+ ro.fill_cache = GetParam();
4350
+ MultiScanArgs scan_options(BytewiseComparator());
4351
+ scan_options.insert(key_ranges[0], key_ranges[1]);
4352
+ scan_options.insert(key_ranges[2], key_ranges[3]);
4353
+ scan_options.max_prefetch_size = 4500;
4354
+ ColumnFamilyHandle* cfh = dbfull()->DefaultColumnFamily();
4355
+ std::unique_ptr<Iterator> iter(dbfull()->NewIterator(ro, cfh));
4356
+ ASSERT_NE(iter, nullptr);
4357
+ iter->Prepare(scan_options);
4358
+ int count = 0;
4359
+ ub = key_ranges[1];
4360
+ iter->Seek(key_ranges[0]);
4361
+ while (iter->status().ok() && iter->Valid()) {
4362
+ ASSERT_GE(iter->key().compare(key_ranges[0]), 0);
4363
+ ASSERT_LT(iter->key().compare(key_ranges[1]), 0);
4364
+ count++;
4365
+ iter->Next();
4366
+ }
4367
+ ASSERT_OK(iter->status()) << iter->status().ToString();
4368
+ ASSERT_EQ(count, 2);
4369
+
4370
+ // Second seek should hit the max_prefetch_size limit
4371
+ ub = key_ranges[3];
4372
+ iter->Seek(key_ranges[2]);
4373
+ ASSERT_NOK(iter->status());
4374
+ iter.reset();
4375
+
4376
+ // Test the case of unexpected Seek key
4377
+ iter.reset(dbfull()->NewIterator(ro, cfh));
4378
+ ASSERT_NE(iter, nullptr);
4379
+ scan_options.max_prefetch_size = 0;
4380
+ iter->Prepare(scan_options);
4381
+ ub = key_ranges[3];
4382
+ iter->Seek(key_ranges[2]);
4383
+ ASSERT_NOK(iter->status());
4384
+ iter.reset();
4385
+ }
4386
+
4387
+ TEST_P(DBMultiScanIteratorTest, RangeBetweenFiles) {
4388
+ auto options = CurrentOptions();
4389
+ options.target_file_size_base = 100 << 10; // 20KB
4390
+ options.compaction_style = kCompactionStyleUniversal;
4391
+ options.num_levels = 50;
4392
+ options.compression = kNoCompression;
4393
+ DestroyAndReopen(options);
4394
+
4395
+ auto rnd = Random::GetTLSInstance();
4396
+ // Write ~200KB data
4397
+ for (int i = 0; i < 100; ++i) {
4398
+ ASSERT_OK(Put(Key(i), rnd->RandomString(2 << 10)));
4399
+ }
4400
+ ASSERT_OK(Flush());
4401
+
4402
+ ASSERT_OK(db_->CompactRange({}, nullptr, nullptr));
4403
+ ASSERT_EQ(2, NumTableFilesAtLevel(49));
4404
+
4405
+ // Test with a scan range that overlaps an entire file, with upper bound
4406
+ // between 2 files
4407
+ std::vector<LiveFileMetaData> file_meta;
4408
+ dbfull()->GetLiveFilesMetaData(&file_meta);
4409
+ ASSERT_EQ(file_meta.size(), 2);
4410
+ std::vector<std::string> key_ranges(4);
4411
+ key_ranges[0] = file_meta[0].smallestkey;
4412
+ key_ranges[1] = file_meta[0].largestkey + "0";
4413
+ key_ranges[2] = file_meta[1].smallestkey + "0";
4414
+ key_ranges[3] = file_meta[1].largestkey;
4259
4415
  ReadOptions ro;
4260
- std::vector<ScanOptions> scan_options(
4261
- {ScanOptions(key_ranges[0], key_ranges[1]), ScanOptions(key_ranges[2]),
4262
- ScanOptions(key_ranges[4], key_ranges[5])});
4416
+ ro.fill_cache = GetParam();
4417
+ MultiScanArgs scan_options(BytewiseComparator());
4418
+ scan_options.insert(key_ranges[0], key_ranges[1]);
4419
+ scan_options.insert(key_ranges[2], key_ranges[3]);
4263
4420
  ColumnFamilyHandle* cfh = dbfull()->DefaultColumnFamily();
4264
4421
  std::unique_ptr<MultiScan> iter =
4265
4422
  dbfull()->NewMultiScan(ro, cfh, scan_options);
4266
4423
  try {
4267
- int idx = 0;
4268
- int count = 0;
4269
4424
  for (auto range : *iter) {
4270
4425
  for (auto it : range) {
4271
- ASSERT_GE(it.first.ToString().compare(
4272
- scan_options[idx].range.start->ToString()),
4273
- 0);
4274
- if (scan_options[idx].range.limit) {
4275
- ASSERT_LT(it.first.ToString().compare(
4276
- scan_options[idx].range.limit->ToString()),
4277
- 0);
4278
- }
4279
- count++;
4426
+ ASSERT_GE(it.first.ToString(), key_ranges[0]);
4280
4427
  }
4281
- idx++;
4282
4428
  }
4283
- ASSERT_EQ(count, 97);
4284
4429
  } catch (MultiScanException& ex) {
4285
4430
  // Make sure exception contains the status
4286
4431
  ASSERT_NOK(ex.status());
@@ -4292,28 +4437,21 @@ TEST_F(DBMultiScanIteratorTest, MixedBoundsTest) {
4292
4437
  }
4293
4438
  iter.reset();
4294
4439
 
4295
- scan_options[0] = ScanOptions(key_ranges[0]);
4296
- scan_options[1] = ScanOptions(key_ranges[2], key_ranges[3]);
4297
- scan_options[2] = ScanOptions(key_ranges[4]);
4440
+ // Test multiscan with a range entirely between adjacent files
4441
+ key_ranges[0] = file_meta[0].largestkey + "0";
4442
+ key_ranges[1] = file_meta[0].largestkey + "1";
4443
+ key_ranges[2] = file_meta[1].smallestkey + "0";
4444
+ key_ranges[3] = file_meta[1].largestkey;
4445
+ (*scan_options).clear();
4446
+ scan_options.insert(key_ranges[0], key_ranges[1]);
4447
+ scan_options.insert(key_ranges[2], key_ranges[3]);
4298
4448
  iter = dbfull()->NewMultiScan(ro, cfh, scan_options);
4299
4449
  try {
4300
- int idx = 0;
4301
- int count = 0;
4302
4450
  for (auto range : *iter) {
4303
4451
  for (auto it : range) {
4304
- ASSERT_GE(it.first.ToString().compare(
4305
- scan_options[idx].range.start->ToString()),
4306
- 0);
4307
- if (scan_options[idx].range.limit) {
4308
- ASSERT_LT(it.first.ToString().compare(
4309
- scan_options[idx].range.limit->ToString()),
4310
- 0);
4311
- }
4312
- count++;
4452
+ ASSERT_GE(it.first.ToString(), key_ranges[0]);
4313
4453
  }
4314
- idx++;
4315
4454
  }
4316
- ASSERT_EQ(count, 147);
4317
4455
  } catch (MultiScanException& ex) {
4318
4456
  // Make sure exception contains the status
4319
4457
  ASSERT_NOK(ex.status());
@@ -4325,6 +4463,141 @@ TEST_F(DBMultiScanIteratorTest, MixedBoundsTest) {
4325
4463
  }
4326
4464
  iter.reset();
4327
4465
  }
4466
+
4467
+ // This test case tests multiscan in the presence of fragmented range
4468
+ // tombstones in the LSM.
4469
+ TEST_P(DBMultiScanIteratorTest, FragmentedRangeTombstones) {
4470
+ auto options = CurrentOptions();
4471
+ // Compaction may create files 2x the target_file_size_base,
4472
+ // so set this to 50KB so we atleast end up with 2 files of
4473
+ // 100KB
4474
+ options.target_file_size_base = 50 << 10; // 50KB
4475
+ options.compaction_style = kCompactionStyleUniversal;
4476
+ options.num_levels = 50;
4477
+ options.compression = kNoCompression;
4478
+ DestroyAndReopen(options);
4479
+
4480
+ // Setup the LSM as follows -
4481
+ // 1. Ingest a file with 100 keys
4482
+ // 2. Ingest a file with one overlapping key
4483
+ // 3. Do a Put and flush a file to L0 with one overlapping key
4484
+ // 4. Ingest a standalone delete range file that covers the full key space
4485
+ // and a file with the same 100 keys with new values. This will ingest
4486
+ // into L0 due to the presence of an existing file in L0
4487
+ // The final LSM will have an SST in Lmax with 100 keys, and 2 SST files
4488
+ // in Lmax-1 with half the keys each and completely overlapping delete ranges
4489
+ std::unordered_map<std::string, std::string> kvs;
4490
+ auto rnd = Random::GetTLSInstance();
4491
+ auto create_ingestion_data_file_and_update_key_value =
4492
+ [&](const std::string& filename, int start_key, int end_key) {
4493
+ std::unique_ptr<SstFileWriter> writer;
4494
+ writer.reset(new SstFileWriter(EnvOptions(), options));
4495
+ ASSERT_OK(writer->Open(filename));
4496
+ for (int i = start_key; i < end_key; ++i) {
4497
+ auto kiter = kvs.find(Key(i));
4498
+ if (kiter != kvs.end()) {
4499
+ kvs.erase(kiter);
4500
+ }
4501
+ auto res =
4502
+ kvs.emplace(std::make_pair(Key(i), rnd->RandomString(2 << 10)));
4503
+ ASSERT_OK(writer->Put(res.first->first, res.first->second));
4504
+ }
4505
+ ASSERT_OK(writer->Finish());
4506
+ writer.reset();
4507
+ };
4508
+
4509
+ CreateColumnFamilies({"new_cf"}, options);
4510
+ std::string ingest_file = dbname_ + "test.sst";
4511
+ // Write ~200KB data
4512
+ create_ingestion_data_file_and_update_key_value(ingest_file + "_0", 0, 100);
4513
+ create_ingestion_data_file_and_update_key_value(ingest_file + "_1", 50, 51);
4514
+ ColumnFamilyHandle* cfh = handles_[0];
4515
+ IngestExternalFileOptions ifo;
4516
+ Status s = dbfull()->IngestExternalFile(
4517
+ cfh, {ingest_file + "_0", ingest_file + "_1"}, ifo);
4518
+ ASSERT_OK(s);
4519
+
4520
+ ASSERT_OK(Put(0, Key(50), rnd->RandomString(2 << 10)));
4521
+ ASSERT_OK(Flush());
4522
+
4523
+ {
4524
+ std::unique_ptr<SstFileWriter> writer;
4525
+ writer.reset(new SstFileWriter(EnvOptions(), options));
4526
+ ASSERT_OK(writer->Open(ingest_file + "_2"));
4527
+ ASSERT_OK(writer->DeleteRange("a", "z"));
4528
+ ASSERT_OK(writer->Finish());
4529
+ writer.reset();
4530
+ }
4531
+ create_ingestion_data_file_and_update_key_value(ingest_file + "_3", 0, 100);
4532
+ s = dbfull()->IngestExternalFile(
4533
+ cfh, {ingest_file + "_2", ingest_file + "_3"}, ifo);
4534
+ ASSERT_OK(s);
4535
+
4536
+ ASSERT_OK(dbfull()->TEST_WaitForCompact());
4537
+
4538
+ // The first scan range overlaps the DB key range, while the second extends
4539
+ // beyond but overlaps the delete range
4540
+ std::vector<std::string> key_ranges({"key000085", "key000090", "l", "n"});
4541
+ ReadOptions ro;
4542
+ ro.fill_cache = GetParam();
4543
+ MultiScanArgs scan_options(BytewiseComparator());
4544
+ scan_options.insert(key_ranges[0], key_ranges[1]);
4545
+ scan_options.insert(key_ranges[2], key_ranges[3]);
4546
+ std::unique_ptr<MultiScan> iter =
4547
+ dbfull()->NewMultiScan(ro, cfh, scan_options);
4548
+ try {
4549
+ int i = 0;
4550
+ int count = 0;
4551
+ for (auto range : *iter) {
4552
+ for (auto it : range) {
4553
+ ASSERT_GE(it.first.ToString(), key_ranges[i]);
4554
+ ASSERT_LT(it.first.ToString(), key_ranges[i + 1]);
4555
+ auto kiter = kvs.find(it.first.ToString());
4556
+ ASSERT_NE(kiter, kvs.end());
4557
+ ASSERT_EQ(kiter->second, it.second.ToString());
4558
+ count++;
4559
+ }
4560
+ i += 2;
4561
+ }
4562
+ ASSERT_EQ(i, 4);
4563
+ ASSERT_EQ(count, 5);
4564
+ } catch (MultiScanException& ex) {
4565
+ ASSERT_OK(ex.status());
4566
+ }
4567
+ iter.reset();
4568
+
4569
+ // The second scan range start overlaps the delete range in the first file
4570
+ // in Lmax-1, while the end overlaps the keys in the second file
4571
+ (*scan_options).clear();
4572
+ key_ranges[0] = "key000010";
4573
+ key_ranges[1] = "key000020";
4574
+ key_ranges[2] = "key0000500";
4575
+ key_ranges[3] = "key000060";
4576
+ scan_options.insert(key_ranges[0], key_ranges[1]);
4577
+ scan_options.insert(key_ranges[2], key_ranges[3]);
4578
+ iter = dbfull()->NewMultiScan(ro, cfh, scan_options);
4579
+ try {
4580
+ int i = 0;
4581
+ int count = 0;
4582
+ for (auto range : *iter) {
4583
+ for (auto it : range) {
4584
+ ASSERT_GE(it.first.ToString(), key_ranges[i]);
4585
+ ASSERT_LT(it.first.ToString(), key_ranges[i + 1]);
4586
+ auto kiter = kvs.find(it.first.ToString());
4587
+ ASSERT_NE(kiter, kvs.end());
4588
+ ASSERT_EQ(kiter->second, it.second.ToString());
4589
+ count++;
4590
+ }
4591
+ i += 2;
4592
+ }
4593
+ ASSERT_EQ(i, 4);
4594
+ ASSERT_EQ(count, 19);
4595
+ } catch (MultiScanException& ex) {
4596
+ ASSERT_OK(ex.status());
4597
+ }
4598
+ iter.reset();
4599
+ }
4600
+
4328
4601
  } // namespace ROCKSDB_NAMESPACE
4329
4602
 
4330
4603
  int main(int argc, char** argv) {
@@ -339,6 +339,135 @@ TEST_F(DBMemTableTest, ColumnFamilyId) {
339
339
  }
340
340
  }
341
341
 
342
+ class DBMemTableTestForSeek : public DBMemTableTest,
343
+ virtual public ::testing::WithParamInterface<
344
+ std::tuple<bool, bool, bool>> {};
345
+
346
+ TEST_P(DBMemTableTestForSeek, IntegrityChecks) {
347
+ // Validate key corruption could be detected during seek.
348
+ // We insert many keys into skiplist. Then we corrupt the each key one at a
349
+ // time. With memtable_veirfy_per_key_checksum_on_seek enabled, when the
350
+ // corrupted key is searched, the checksum of every key visited during the
351
+ // seek is validated. It will report data corruption. Otherwise seek returns
352
+ // not found.
353
+ auto allow_data_in_error = std::get<0>(GetParam());
354
+ Options options = CurrentOptions();
355
+ options.allow_data_in_errors = allow_data_in_error;
356
+ options.paranoid_memory_checks = std::get<1>(GetParam());
357
+ options.memtable_veirfy_per_key_checksum_on_seek = std::get<2>(GetParam());
358
+ options.memtable_protection_bytes_per_key = 8;
359
+ DestroyAndReopen(options);
360
+
361
+ // capture the data pointer of all of the keys
362
+ std::vector<char*> raw_data_pointer;
363
+
364
+ // Insert enough keys, so memtable would create multiple levels.
365
+ auto key_count = 100;
366
+ for (int i = 0; i < key_count; i++) {
367
+ // The last digit of the key will be corrupted from value 0 to value 5
368
+ ASSERT_OK(Put(Key(i * 10), "val0"));
369
+ }
370
+
371
+ ReadOptions rops;
372
+
373
+ // Iterate all the keys to get key pointers
374
+ SyncPoint::GetInstance()->DisableProcessing();
375
+ SyncPoint::GetInstance()->SetCallBack("InlineSkipList::Iterator::Next::key",
376
+ [&raw_data_pointer](void* key) {
377
+ auto p = static_cast<char*>(key);
378
+ raw_data_pointer.push_back(p);
379
+ });
380
+ SyncPoint::GetInstance()->EnableProcessing();
381
+
382
+ {
383
+ std::unique_ptr<Iterator> iter{db_->NewIterator(rops)};
384
+ iter->Seek(Key(0));
385
+ while (iter->Valid()) {
386
+ ASSERT_OK(iter->status());
387
+ iter->Next();
388
+ }
389
+ // check status after valid returned false.
390
+ auto status = iter->status();
391
+ ASSERT_TRUE(status.ok());
392
+ }
393
+
394
+ SyncPoint::GetInstance()->DisableProcessing();
395
+ SyncPoint::GetInstance()->ClearAllCallBacks();
396
+
397
+ ASSERT_EQ(raw_data_pointer.size(), key_count);
398
+
399
+ bool enable_key_validation_on_seek =
400
+ options.memtable_veirfy_per_key_checksum_on_seek;
401
+
402
+ // For each key, corrupt it, validate corruption is detected correctly, then
403
+ // revert it.
404
+ for (int i = 0; i < key_count; i++) {
405
+ std::string key_to_corrupt = Key(i * 10);
406
+ raw_data_pointer[i][key_to_corrupt.size()] = '5';
407
+
408
+ auto corrupted_key = key_to_corrupt;
409
+ corrupted_key.data()[key_to_corrupt.size() - 1] = '5';
410
+ auto corrupted_key_slice =
411
+ Slice(corrupted_key.data(), corrupted_key.length());
412
+ auto corrupted_key_hex = corrupted_key_slice.ToString(/*hex=*/true);
413
+
414
+ {
415
+ // Test Get API
416
+ std::string val;
417
+ auto status = db_->Get(rops, key_to_corrupt, &val);
418
+ if (enable_key_validation_on_seek) {
419
+ ASSERT_TRUE(status.IsCorruption()) << key_to_corrupt;
420
+ ASSERT_EQ(
421
+ status.ToString().find(corrupted_key_hex) != std::string::npos,
422
+ allow_data_in_error)
423
+ << status.ToString() << "\n"
424
+ << corrupted_key_hex;
425
+ } else {
426
+ ASSERT_TRUE(status.IsNotFound());
427
+ }
428
+ }
429
+
430
+ {
431
+ // Test MultiGet API
432
+ std::vector<std::string> vals;
433
+ std::vector<Status> statuses = db_->MultiGet(
434
+ rops, {db_->DefaultColumnFamily()}, {key_to_corrupt}, &vals, nullptr);
435
+ if (enable_key_validation_on_seek) {
436
+ ASSERT_TRUE(statuses[0].IsCorruption());
437
+ ASSERT_EQ(
438
+ statuses[0].ToString().find(corrupted_key_hex) != std::string::npos,
439
+ allow_data_in_error);
440
+ } else {
441
+ ASSERT_TRUE(statuses[0].IsNotFound());
442
+ }
443
+ }
444
+
445
+ {
446
+ // Test Iterator Seek API
447
+ std::unique_ptr<Iterator> iter{db_->NewIterator(rops)};
448
+ ASSERT_OK(iter->status());
449
+ iter->Seek(key_to_corrupt);
450
+ auto status = iter->status();
451
+ if (enable_key_validation_on_seek) {
452
+ ASSERT_TRUE(status.IsCorruption());
453
+ ASSERT_EQ(
454
+ status.ToString().find(corrupted_key_hex) != std::string::npos,
455
+ allow_data_in_error);
456
+ } else {
457
+ ASSERT_FALSE(iter->Valid());
458
+ ASSERT_FALSE(status.ok());
459
+ }
460
+ }
461
+
462
+ // revert the key corruption.
463
+ raw_data_pointer[i][key_to_corrupt.size()] = '0';
464
+ }
465
+ }
466
+
467
+ INSTANTIATE_TEST_CASE_P(DBMemTableTestForSeek, DBMemTableTestForSeek,
468
+ ::testing::Combine(::testing::Bool(), ::testing::Bool(),
469
+ ::testing::Bool()));
470
+
342
471
  TEST_F(DBMemTableTest, IntegrityChecks) {
343
472
  // We insert keys key000000, key000001 and key000002 into skiplist at fixed
344
473
  // height 1 (smallest height). Then we corrupt the second key to aey000001 to
@@ -1937,6 +1937,70 @@ TEST_F(DBSSTTest, DBWithSFMForBlobFilesAtomicFlush) {
1937
1937
  ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks();
1938
1938
  }
1939
1939
 
1940
+ TEST_F(DBSSTTest, SstGetFileSizeFails) {
1941
+ // Build an SST file
1942
+ ASSERT_OK(Put("x", "zaphod"));
1943
+ ASSERT_OK(Flush());
1944
+ std::vector<LiveFileMetaData> metadata;
1945
+ db_->GetLiveFilesMetaData(&metadata);
1946
+ ASSERT_EQ(1U, metadata.size());
1947
+ std::string filename = dbname_ + metadata[0].name;
1948
+
1949
+ // Prepare for fault injection
1950
+ std::shared_ptr<FaultInjectionTestFS> fault_fs =
1951
+ std::make_shared<FaultInjectionTestFS>(
1952
+ CurrentOptions().env->GetFileSystem());
1953
+ std::unique_ptr<Env> fault_fs_env(NewCompositeEnv(fault_fs));
1954
+ Options options = CurrentOptions();
1955
+ options.env = fault_fs_env.get();
1956
+ options.paranoid_checks = false; // don't check file sizes on open
1957
+
1958
+ for (int i = 0; i < 4; i++) {
1959
+ SCOPED_TRACE("Iteration = " + std::to_string(i));
1960
+ fault_fs->SetFailRandomAccessGetFileSizeSst(false);
1961
+ fault_fs->SetFailFilesystemGetFileSizeSst(false);
1962
+ Close();
1963
+
1964
+ if (i == 1) {
1965
+ // Just FSRandomAccessFile::GetFileSize fails, which should be worked
1966
+ // around
1967
+ fault_fs->SetFailRandomAccessGetFileSizeSst(true);
1968
+ } else if (i == 2) {
1969
+ // FileSystem::GetFileSize fails, which should be worked around if
1970
+ // FSRandomAccessFile::GetFileSize is supported
1971
+ fault_fs->SetFailFilesystemGetFileSizeSst(true);
1972
+ } else if (i == 3) {
1973
+ // Both GetFileSize APIs fail with an IOError
1974
+ fault_fs->SetFailRandomAccessGetFileSizeSst(true);
1975
+ fault_fs->SetFailFilesystemGetFileSizeSst(true);
1976
+ }
1977
+
1978
+ ASSERT_OK(TryReopen(options));
1979
+ std::string value;
1980
+ Status get_status = db_->Get({}, "x", &value);
1981
+ if (i < 2) {
1982
+ ASSERT_OK(get_status);
1983
+ } else if (i == 2) {
1984
+ if (encrypted_env_) {
1985
+ // Can't recover because RandomAccessFile::GetFileSize is not supported
1986
+ // on EncryptedEnv
1987
+ // Fail with propagated IOError. (Not Corruption nor NotSupported!)
1988
+ ASSERT_EQ(get_status.code(), Status::Code::kIOError);
1989
+ ASSERT_STREQ(get_status.getState(), "FileSystem::GetFileSize failed");
1990
+ } else {
1991
+ // Never sees the FileSystem::GetFileSize failure
1992
+ ASSERT_OK(get_status);
1993
+ }
1994
+ } else {
1995
+ ASSERT_EQ(i, 3);
1996
+ // Fail with propagated IOError. (Not Corruption nor NotSupported!)
1997
+ ASSERT_EQ(get_status.code(), Status::Code::kIOError);
1998
+ ASSERT_STREQ(get_status.getState(), "FileSystem::GetFileSize failed");
1999
+ }
2000
+ }
2001
+ Close();
2002
+ }
2003
+
1940
2004
  } // namespace ROCKSDB_NAMESPACE
1941
2005
 
1942
2006
  int main(int argc, char** argv) {