@nxtedition/rocksdb 13.1.4 → 13.2.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 (237) hide show
  1. package/binding.cc +43 -16
  2. package/deps/rocksdb/rocksdb/{TARGETS → BUCK} +27 -0
  3. package/deps/rocksdb/rocksdb/CMakeLists.txt +3 -1
  4. package/deps/rocksdb/rocksdb/Makefile +2 -2
  5. package/deps/rocksdb/rocksdb/cache/cache.cc +3 -1
  6. package/deps/rocksdb/rocksdb/db/arena_wrapped_db_iter.h +2 -0
  7. package/deps/rocksdb/rocksdb/db/attribute_group_iterator_impl.h +34 -9
  8. package/deps/rocksdb/rocksdb/db/blob/blob_source.cc +7 -6
  9. package/deps/rocksdb/rocksdb/db/blob/blob_source.h +5 -1
  10. package/deps/rocksdb/rocksdb/db/blob/blob_source_test.cc +22 -14
  11. package/deps/rocksdb/rocksdb/db/blob/db_blob_basic_test.cc +149 -0
  12. package/deps/rocksdb/rocksdb/db/builder.cc +13 -24
  13. package/deps/rocksdb/rocksdb/db/coalescing_iterator.h +35 -10
  14. package/deps/rocksdb/rocksdb/db/column_family.cc +21 -10
  15. package/deps/rocksdb/rocksdb/db/column_family.h +15 -8
  16. package/deps/rocksdb/rocksdb/db/column_family_test.cc +98 -7
  17. package/deps/rocksdb/rocksdb/db/compaction/compaction.cc +126 -16
  18. package/deps/rocksdb/rocksdb/db/compaction/compaction.h +51 -5
  19. package/deps/rocksdb/rocksdb/db/compaction/compaction_iterator.cc +2 -2
  20. package/deps/rocksdb/rocksdb/db/compaction/compaction_iterator.h +2 -8
  21. package/deps/rocksdb/rocksdb/db/compaction/compaction_iterator_test.cc +24 -0
  22. package/deps/rocksdb/rocksdb/db/compaction/compaction_job.cc +52 -22
  23. package/deps/rocksdb/rocksdb/db/compaction/compaction_job.h +9 -7
  24. package/deps/rocksdb/rocksdb/db/compaction/compaction_job_test.cc +36 -9
  25. package/deps/rocksdb/rocksdb/db/compaction/compaction_outputs.h +6 -0
  26. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker.cc +30 -17
  27. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker.h +26 -23
  28. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_fifo.cc +43 -33
  29. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_fifo.h +6 -5
  30. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_level.cc +19 -9
  31. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_level.h +6 -5
  32. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_test.cc +632 -411
  33. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_universal.cc +171 -51
  34. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_universal.h +7 -5
  35. package/deps/rocksdb/rocksdb/db/compaction/compaction_service_job.cc +37 -10
  36. package/deps/rocksdb/rocksdb/db/compaction/compaction_service_test.cc +51 -11
  37. package/deps/rocksdb/rocksdb/db/compaction/subcompaction_state.cc +10 -3
  38. package/deps/rocksdb/rocksdb/db/compaction/tiered_compaction_test.cc +350 -154
  39. package/deps/rocksdb/rocksdb/db/convenience.cc +1 -1
  40. package/deps/rocksdb/rocksdb/db/db_block_cache_test.cc +62 -27
  41. package/deps/rocksdb/rocksdb/db/db_bloom_filter_test.cc +68 -1
  42. package/deps/rocksdb/rocksdb/db/db_compaction_test.cc +91 -0
  43. package/deps/rocksdb/rocksdb/db/db_impl/db_impl.cc +134 -70
  44. package/deps/rocksdb/rocksdb/db/db_impl/db_impl.h +71 -23
  45. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_compaction_flush.cc +43 -16
  46. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_debug.cc +47 -33
  47. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_files.cc +27 -19
  48. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_open.cc +38 -25
  49. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_readonly.cc +3 -3
  50. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_secondary.cc +7 -4
  51. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_write.cc +258 -42
  52. package/deps/rocksdb/rocksdb/db/db_io_failure_test.cc +161 -9
  53. package/deps/rocksdb/rocksdb/db/db_iter.cc +118 -86
  54. package/deps/rocksdb/rocksdb/db/db_iter.h +44 -17
  55. package/deps/rocksdb/rocksdb/db/db_options_test.cc +27 -6
  56. package/deps/rocksdb/rocksdb/db/db_test.cc +48 -16
  57. package/deps/rocksdb/rocksdb/db/db_test2.cc +60 -15
  58. package/deps/rocksdb/rocksdb/db/db_test_util.cc +97 -44
  59. package/deps/rocksdb/rocksdb/db/db_test_util.h +7 -1
  60. package/deps/rocksdb/rocksdb/db/dbformat.cc +15 -5
  61. package/deps/rocksdb/rocksdb/db/dbformat.h +137 -55
  62. package/deps/rocksdb/rocksdb/db/event_helpers.cc +1 -0
  63. package/deps/rocksdb/rocksdb/db/experimental.cc +54 -0
  64. package/deps/rocksdb/rocksdb/db/external_sst_file_basic_test.cc +663 -8
  65. package/deps/rocksdb/rocksdb/db/external_sst_file_ingestion_job.cc +152 -91
  66. package/deps/rocksdb/rocksdb/db/external_sst_file_ingestion_job.h +134 -11
  67. package/deps/rocksdb/rocksdb/db/external_sst_file_test.cc +55 -9
  68. package/deps/rocksdb/rocksdb/db/flush_job.cc +52 -29
  69. package/deps/rocksdb/rocksdb/db/flush_job.h +5 -3
  70. package/deps/rocksdb/rocksdb/db/flush_job_test.cc +18 -12
  71. package/deps/rocksdb/rocksdb/db/forward_iterator.cc +23 -29
  72. package/deps/rocksdb/rocksdb/db/import_column_family_job.cc +3 -2
  73. package/deps/rocksdb/rocksdb/db/import_column_family_test.cc +2 -0
  74. package/deps/rocksdb/rocksdb/db/internal_stats.cc +9 -6
  75. package/deps/rocksdb/rocksdb/db/internal_stats.h +54 -0
  76. package/deps/rocksdb/rocksdb/db/job_context.h +1 -1
  77. package/deps/rocksdb/rocksdb/db/log_reader.cc +6 -7
  78. package/deps/rocksdb/rocksdb/db/manifest_ops.cc +47 -0
  79. package/deps/rocksdb/rocksdb/db/manifest_ops.h +20 -0
  80. package/deps/rocksdb/rocksdb/db/memtable.cc +165 -64
  81. package/deps/rocksdb/rocksdb/db/memtable.h +422 -243
  82. package/deps/rocksdb/rocksdb/db/memtable_list.cc +99 -68
  83. package/deps/rocksdb/rocksdb/db/memtable_list.h +63 -38
  84. package/deps/rocksdb/rocksdb/db/memtable_list_test.cc +28 -25
  85. package/deps/rocksdb/rocksdb/db/multi_cf_iterator_impl.h +118 -60
  86. package/deps/rocksdb/rocksdb/db/multi_cf_iterator_test.cc +344 -89
  87. package/deps/rocksdb/rocksdb/db/range_tombstone_fragmenter.h +2 -3
  88. package/deps/rocksdb/rocksdb/db/repair.cc +15 -14
  89. package/deps/rocksdb/rocksdb/db/repair_test.cc +0 -13
  90. package/deps/rocksdb/rocksdb/db/snapshot_checker.h +7 -0
  91. package/deps/rocksdb/rocksdb/db/table_cache.cc +62 -65
  92. package/deps/rocksdb/rocksdb/db/table_cache.h +70 -76
  93. package/deps/rocksdb/rocksdb/db/table_cache_sync_and_async.h +5 -6
  94. package/deps/rocksdb/rocksdb/db/table_properties_collector_test.cc +1 -1
  95. package/deps/rocksdb/rocksdb/db/transaction_log_impl.cc +8 -7
  96. package/deps/rocksdb/rocksdb/db/version_builder.cc +17 -19
  97. package/deps/rocksdb/rocksdb/db/version_builder.h +13 -12
  98. package/deps/rocksdb/rocksdb/db/version_edit.h +30 -0
  99. package/deps/rocksdb/rocksdb/db/version_edit_handler.cc +3 -5
  100. package/deps/rocksdb/rocksdb/db/version_set.cc +89 -129
  101. package/deps/rocksdb/rocksdb/db/version_set.h +12 -4
  102. package/deps/rocksdb/rocksdb/db/version_set_sync_and_async.h +1 -2
  103. package/deps/rocksdb/rocksdb/db/version_set_test.cc +12 -8
  104. package/deps/rocksdb/rocksdb/db/wide/wide_column_serialization.cc +0 -15
  105. package/deps/rocksdb/rocksdb/db/wide/wide_column_serialization.h +0 -2
  106. package/deps/rocksdb/rocksdb/db/wide/wide_column_serialization_test.cc +9 -7
  107. package/deps/rocksdb/rocksdb/db/wide/wide_columns_helper.cc +0 -8
  108. package/deps/rocksdb/rocksdb/db/wide/wide_columns_helper.h +28 -2
  109. package/deps/rocksdb/rocksdb/db/write_batch.cc +32 -10
  110. package/deps/rocksdb/rocksdb/db/write_batch_internal.h +9 -0
  111. package/deps/rocksdb/rocksdb/db/write_batch_test.cc +2 -1
  112. package/deps/rocksdb/rocksdb/db/write_thread.cc +3 -1
  113. package/deps/rocksdb/rocksdb/db/write_thread.h +6 -2
  114. package/deps/rocksdb/rocksdb/db_stress_tool/batched_ops_stress.cc +15 -0
  115. package/deps/rocksdb/rocksdb/db_stress_tool/cf_consistency_stress.cc +7 -0
  116. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_common.h +4 -0
  117. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_gflags.cc +18 -2
  118. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_test_base.cc +100 -22
  119. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_test_base.h +15 -4
  120. package/deps/rocksdb/rocksdb/db_stress_tool/multi_ops_txns_stress.cc +34 -8
  121. package/deps/rocksdb/rocksdb/db_stress_tool/no_batched_ops_stress.cc +223 -78
  122. package/deps/rocksdb/rocksdb/env/file_system.cc +6 -1
  123. package/deps/rocksdb/rocksdb/env/fs_posix.cc +53 -0
  124. package/deps/rocksdb/rocksdb/env/io_posix.cc +63 -17
  125. package/deps/rocksdb/rocksdb/env/io_posix.h +30 -1
  126. package/deps/rocksdb/rocksdb/file/file_prefetch_buffer.cc +132 -48
  127. package/deps/rocksdb/rocksdb/file/file_prefetch_buffer.h +92 -24
  128. package/deps/rocksdb/rocksdb/file/prefetch_test.cc +727 -109
  129. package/deps/rocksdb/rocksdb/file/random_access_file_reader.cc +3 -4
  130. package/deps/rocksdb/rocksdb/file/random_access_file_reader.h +1 -1
  131. package/deps/rocksdb/rocksdb/file/writable_file_writer.cc +8 -0
  132. package/deps/rocksdb/rocksdb/include/rocksdb/attribute_groups.h +20 -1
  133. package/deps/rocksdb/rocksdb/include/rocksdb/compaction_job_stats.h +9 -0
  134. package/deps/rocksdb/rocksdb/include/rocksdb/configurable.h +9 -5
  135. package/deps/rocksdb/rocksdb/include/rocksdb/convenience.h +2 -0
  136. package/deps/rocksdb/rocksdb/include/rocksdb/db.h +10 -2
  137. package/deps/rocksdb/rocksdb/include/rocksdb/env.h +1 -0
  138. package/deps/rocksdb/rocksdb/include/rocksdb/experimental.h +7 -0
  139. package/deps/rocksdb/rocksdb/include/rocksdb/file_system.h +34 -37
  140. package/deps/rocksdb/rocksdb/include/rocksdb/iterator_base.h +21 -0
  141. package/deps/rocksdb/rocksdb/include/rocksdb/options.h +56 -28
  142. package/deps/rocksdb/rocksdb/include/rocksdb/sst_file_writer.h +3 -0
  143. package/deps/rocksdb/rocksdb/include/rocksdb/table.h +36 -28
  144. package/deps/rocksdb/rocksdb/include/rocksdb/table_properties.h +11 -0
  145. package/deps/rocksdb/rocksdb/include/rocksdb/thread_status.h +1 -0
  146. package/deps/rocksdb/rocksdb/include/rocksdb/utilities/options_type.h +84 -60
  147. package/deps/rocksdb/rocksdb/include/rocksdb/utilities/secondary_index.h +102 -0
  148. package/deps/rocksdb/rocksdb/include/rocksdb/utilities/table_properties_collectors.h +89 -2
  149. package/deps/rocksdb/rocksdb/include/rocksdb/utilities/transaction.h +32 -0
  150. package/deps/rocksdb/rocksdb/include/rocksdb/utilities/transaction_db.h +30 -1
  151. package/deps/rocksdb/rocksdb/include/rocksdb/utilities/write_batch_with_index.h +23 -2
  152. package/deps/rocksdb/rocksdb/include/rocksdb/version.h +2 -2
  153. package/deps/rocksdb/rocksdb/include/rocksdb/write_batch.h +2 -0
  154. package/deps/rocksdb/rocksdb/memtable/inlineskiplist.h +79 -21
  155. package/deps/rocksdb/rocksdb/memtable/skiplist.h +41 -18
  156. package/deps/rocksdb/rocksdb/memtable/skiplistrep.cc +1 -5
  157. package/deps/rocksdb/rocksdb/memtable/wbwi_memtable.cc +169 -0
  158. package/deps/rocksdb/rocksdb/memtable/wbwi_memtable.h +400 -0
  159. package/deps/rocksdb/rocksdb/monitoring/thread_status_util_debug.cc +2 -0
  160. package/deps/rocksdb/rocksdb/options/cf_options.cc +137 -82
  161. package/deps/rocksdb/rocksdb/options/cf_options.h +18 -6
  162. package/deps/rocksdb/rocksdb/options/configurable.cc +31 -17
  163. package/deps/rocksdb/rocksdb/options/configurable_helper.h +7 -6
  164. package/deps/rocksdb/rocksdb/options/options_helper.cc +10 -8
  165. package/deps/rocksdb/rocksdb/options/options_parser.cc +74 -54
  166. package/deps/rocksdb/rocksdb/options/options_settable_test.cc +89 -0
  167. package/deps/rocksdb/rocksdb/options/options_test.cc +112 -26
  168. package/deps/rocksdb/rocksdb/port/port.h +5 -9
  169. package/deps/rocksdb/rocksdb/src.mk +8 -0
  170. package/deps/rocksdb/rocksdb/table/adaptive/adaptive_table_factory.h +4 -0
  171. package/deps/rocksdb/rocksdb/table/block_based/block.h +1 -7
  172. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_builder.cc +2 -0
  173. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_factory.cc +62 -80
  174. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_factory.h +13 -3
  175. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_iterator.cc +16 -5
  176. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_iterator.h +38 -7
  177. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader.cc +12 -4
  178. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader.h +4 -1
  179. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader_sync_and_async.h +4 -1
  180. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader_test.cc +204 -1
  181. package/deps/rocksdb/rocksdb/table/block_based/data_block_hash_index_test.cc +3 -3
  182. package/deps/rocksdb/rocksdb/table/block_fetcher_test.cc +2 -1
  183. package/deps/rocksdb/rocksdb/table/cuckoo/cuckoo_table_factory.h +4 -0
  184. package/deps/rocksdb/rocksdb/table/format.cc +3 -3
  185. package/deps/rocksdb/rocksdb/table/meta_blocks.cc +4 -1
  186. package/deps/rocksdb/rocksdb/table/mock_table.cc +0 -50
  187. package/deps/rocksdb/rocksdb/table/mock_table.h +53 -0
  188. package/deps/rocksdb/rocksdb/table/plain/plain_table_factory.h +4 -0
  189. package/deps/rocksdb/rocksdb/table/sst_file_dumper.cc +1 -1
  190. package/deps/rocksdb/rocksdb/table/sst_file_writer.cc +10 -5
  191. package/deps/rocksdb/rocksdb/table/table_builder.h +3 -1
  192. package/deps/rocksdb/rocksdb/table/table_properties.cc +181 -0
  193. package/deps/rocksdb/rocksdb/table/table_reader_bench.cc +5 -5
  194. package/deps/rocksdb/rocksdb/table/table_test.cc +71 -64
  195. package/deps/rocksdb/rocksdb/tools/block_cache_analyzer/block_cache_pysim.py +45 -45
  196. package/deps/rocksdb/rocksdb/tools/block_cache_analyzer/block_cache_pysim_test.py +35 -35
  197. package/deps/rocksdb/rocksdb/tools/block_cache_analyzer/block_cache_trace_analyzer_plot.py +43 -43
  198. package/deps/rocksdb/rocksdb/tools/db_bench_tool.cc +41 -4
  199. package/deps/rocksdb/rocksdb/tools/ldb_cmd.cc +1 -0
  200. package/deps/rocksdb/rocksdb/tools/sst_dump_test.cc +1 -1
  201. package/deps/rocksdb/rocksdb/unreleased_history/add.sh +13 -0
  202. package/deps/rocksdb/rocksdb/util/aligned_buffer.h +24 -5
  203. package/deps/rocksdb/rocksdb/util/compaction_job_stats_impl.cc +7 -0
  204. package/deps/rocksdb/rocksdb/util/file_checksum_helper.cc +0 -52
  205. package/deps/rocksdb/rocksdb/util/file_checksum_helper.h +1 -10
  206. package/deps/rocksdb/rocksdb/util/file_reader_writer_test.cc +92 -0
  207. package/deps/rocksdb/rocksdb/util/thread_operation.h +1 -0
  208. package/deps/rocksdb/rocksdb/util/udt_util.cc +50 -4
  209. package/deps/rocksdb/rocksdb/util/udt_util.h +24 -11
  210. package/deps/rocksdb/rocksdb/util/udt_util_test.cc +26 -13
  211. package/deps/rocksdb/rocksdb/utilities/memory/memory_test.cc +1 -16
  212. package/deps/rocksdb/rocksdb/utilities/options/options_util_test.cc +2 -0
  213. package/deps/rocksdb/rocksdb/utilities/secondary_index/faiss_ivf_index.cc +214 -0
  214. package/deps/rocksdb/rocksdb/utilities/secondary_index/faiss_ivf_index.h +60 -0
  215. package/deps/rocksdb/rocksdb/utilities/secondary_index/faiss_ivf_index_test.cc +124 -0
  216. package/deps/rocksdb/rocksdb/utilities/secondary_index/secondary_index_mixin.h +441 -0
  217. package/deps/rocksdb/rocksdb/utilities/table_properties_collectors/compact_for_tiering_collector.cc +34 -3
  218. package/deps/rocksdb/rocksdb/utilities/table_properties_collectors/compact_for_tiering_collector.h +7 -2
  219. package/deps/rocksdb/rocksdb/utilities/transactions/optimistic_transaction_test.cc +437 -0
  220. package/deps/rocksdb/rocksdb/utilities/transactions/pessimistic_transaction.cc +34 -11
  221. package/deps/rocksdb/rocksdb/utilities/transactions/pessimistic_transaction.h +14 -7
  222. package/deps/rocksdb/rocksdb/utilities/transactions/pessimistic_transaction_db.cc +7 -1
  223. package/deps/rocksdb/rocksdb/utilities/transactions/snapshot_checker.cc +17 -0
  224. package/deps/rocksdb/rocksdb/utilities/transactions/transaction_base.cc +69 -0
  225. package/deps/rocksdb/rocksdb/utilities/transactions/transaction_base.h +20 -0
  226. package/deps/rocksdb/rocksdb/utilities/transactions/transaction_test.cc +1290 -0
  227. package/deps/rocksdb/rocksdb/utilities/transactions/write_committed_transaction_ts_test.cc +324 -0
  228. package/deps/rocksdb/rocksdb/utilities/transactions/write_prepared_txn.cc +18 -1
  229. package/deps/rocksdb/rocksdb/utilities/transactions/write_prepared_txn.h +8 -1
  230. package/deps/rocksdb/rocksdb/utilities/write_batch_with_index/write_batch_with_index.cc +57 -12
  231. package/deps/rocksdb/rocksdb/utilities/write_batch_with_index/write_batch_with_index_internal.cc +32 -3
  232. package/deps/rocksdb/rocksdb/utilities/write_batch_with_index/write_batch_with_index_internal.h +33 -2
  233. package/deps/rocksdb/rocksdb/utilities/write_batch_with_index/write_batch_with_index_test.cc +721 -9
  234. package/deps/rocksdb/rocksdb.gyp +2 -0
  235. package/package.json +1 -1
  236. package/prebuilds/darwin-arm64/@nxtedition+rocksdb.node +0 -0
  237. package/prebuilds/linux-x64/@nxtedition+rocksdb.node +0 -0
@@ -11,6 +11,7 @@
11
11
  #ifdef GFLAGS
12
12
  #include "tools/io_tracer_parser_tool.h"
13
13
  #endif
14
+ #include "rocksdb/flush_block_policy.h"
14
15
  #include "util/random.h"
15
16
 
16
17
  namespace {
@@ -121,6 +122,81 @@ class PrefetchTest
121
122
  table_options.index_type =
122
123
  BlockBasedTableOptions::IndexType::kTwoLevelIndexSearch;
123
124
  }
125
+
126
+ void VerifyScan(ReadOptions& iter_ro, ReadOptions& cmp_iter_ro,
127
+ const Slice* seek_key, const Slice* iterate_upper_bound,
128
+ bool prefix_same_as_start) const {
129
+ assert(!(seek_key == nullptr));
130
+ iter_ro.iterate_upper_bound = cmp_iter_ro.iterate_upper_bound =
131
+ iterate_upper_bound;
132
+ iter_ro.prefix_same_as_start = cmp_iter_ro.prefix_same_as_start =
133
+ prefix_same_as_start;
134
+
135
+ auto iter = std::unique_ptr<Iterator>(db_->NewIterator(iter_ro));
136
+ auto cmp_iter = std::unique_ptr<Iterator>(db_->NewIterator(cmp_iter_ro));
137
+
138
+ iter->Seek(*seek_key);
139
+ cmp_iter->Seek(*seek_key);
140
+
141
+ while (iter->Valid() && cmp_iter->Valid()) {
142
+ if (iter->key() != cmp_iter->key()) {
143
+ // Error
144
+ ASSERT_TRUE(false);
145
+ }
146
+ iter->Next();
147
+ cmp_iter->Next();
148
+ }
149
+
150
+ ASSERT_TRUE(!cmp_iter->Valid() && !iter->Valid());
151
+ ASSERT_TRUE(cmp_iter->status().ok() && iter->status().ok());
152
+ }
153
+
154
+ void VerifySeekPrevSeek(ReadOptions& iter_ro, ReadOptions& cmp_iter_ro,
155
+ const Slice* seek_key,
156
+ const Slice* iterate_upper_bound,
157
+ bool prefix_same_as_start) {
158
+ assert(!(seek_key == nullptr));
159
+ iter_ro.iterate_upper_bound = cmp_iter_ro.iterate_upper_bound =
160
+ iterate_upper_bound;
161
+ iter_ro.prefix_same_as_start = cmp_iter_ro.prefix_same_as_start =
162
+ prefix_same_as_start;
163
+
164
+ auto iter = std::unique_ptr<Iterator>(db_->NewIterator(iter_ro));
165
+ auto cmp_iter = std::unique_ptr<Iterator>(db_->NewIterator(cmp_iter_ro));
166
+
167
+ // Seek
168
+ cmp_iter->Seek(*seek_key);
169
+ ASSERT_TRUE(cmp_iter->Valid());
170
+ ASSERT_OK(cmp_iter->status());
171
+
172
+ iter->Seek(*seek_key);
173
+ ASSERT_TRUE(iter->Valid());
174
+ ASSERT_OK(iter->status());
175
+
176
+ ASSERT_EQ(iter->key(), cmp_iter->key());
177
+
178
+ // Prev op should pass
179
+ cmp_iter->Prev();
180
+ ASSERT_TRUE(cmp_iter->Valid());
181
+ ASSERT_OK(cmp_iter->status());
182
+
183
+ iter->Prev();
184
+ ASSERT_TRUE(iter->Valid());
185
+ ASSERT_OK(iter->status());
186
+
187
+ ASSERT_EQ(iter->key(), cmp_iter->key());
188
+
189
+ // Reseek would follow as usual
190
+ cmp_iter->Seek(*seek_key);
191
+ ASSERT_TRUE(cmp_iter->Valid());
192
+ ASSERT_OK(cmp_iter->status());
193
+
194
+ iter->Seek(*seek_key);
195
+ ASSERT_TRUE(iter->Valid());
196
+ ASSERT_OK(iter->status());
197
+
198
+ ASSERT_EQ(iter->key(), cmp_iter->key());
199
+ }
124
200
  };
125
201
 
126
202
  INSTANTIATE_TEST_CASE_P(PrefetchTest, PrefetchTest,
@@ -599,6 +675,8 @@ TEST_P(PrefetchTest, ConfigureAutoMaxReadaheadSize) {
599
675
  default:
600
676
  assert(false);
601
677
  }
678
+ ASSERT_OK(iter->status());
679
+ ASSERT_OK(iter->Refresh()); // Update to latest mutable options
602
680
 
603
681
  for (int i = 0; i < num_keys_per_level; ++i) {
604
682
  iter->Seek(Key(key_count++));
@@ -726,6 +804,8 @@ TEST_P(PrefetchTest, ConfigureInternalAutoReadaheadSize) {
726
804
  default:
727
805
  assert(false);
728
806
  }
807
+ ASSERT_OK(iter->status());
808
+ ASSERT_OK(iter->Refresh()); // Update to latest mutable options
729
809
 
730
810
  for (int i = 0; i < num_keys_per_level; ++i) {
731
811
  iter->Seek(Key(key_count++));
@@ -1262,6 +1342,8 @@ TEST_P(PrefetchTest, PrefetchWithBlockLookupAutoTuneTest) {
1262
1342
  Options options;
1263
1343
  SetGenericOptions(env.get(), /*use_direct_io=*/false, options);
1264
1344
  options.statistics = CreateDBStatistics();
1345
+ const std::string prefix = "my_key_";
1346
+ options.prefix_extractor.reset(NewFixedPrefixTransform(prefix.size()));
1265
1347
  BlockBasedTableOptions table_options;
1266
1348
  SetBlockBasedTableOptions(table_options);
1267
1349
  options.table_factory.reset(NewBlockBasedTableFactory(table_options));
@@ -1272,8 +1354,9 @@ TEST_P(PrefetchTest, PrefetchWithBlockLookupAutoTuneTest) {
1272
1354
  Random rnd(309);
1273
1355
  WriteBatch batch;
1274
1356
 
1357
+ // Create the DB with keys from "my_key_aaaaaaaaaa" to "my_key_zzzzzzzzzz"
1275
1358
  for (int i = 0; i < 26; i++) {
1276
- std::string key = "my_key_";
1359
+ std::string key = prefix;
1277
1360
 
1278
1361
  for (int j = 0; j < 10; j++) {
1279
1362
  key += char('a' + i);
@@ -1282,9 +1365,9 @@ TEST_P(PrefetchTest, PrefetchWithBlockLookupAutoTuneTest) {
1282
1365
  }
1283
1366
  ASSERT_OK(db_->Write(WriteOptions(), &batch));
1284
1367
 
1285
- std::string start_key = "my_key_a";
1368
+ std::string start_key = prefix + "a";
1286
1369
 
1287
- std::string end_key = "my_key_";
1370
+ std::string end_key = prefix;
1288
1371
  for (int j = 0; j < 10; j++) {
1289
1372
  end_key += char('a' + 25);
1290
1373
  }
@@ -1309,32 +1392,30 @@ TEST_P(PrefetchTest, PrefetchWithBlockLookupAutoTuneTest) {
1309
1392
  {
1310
1393
  auto iter = std::unique_ptr<Iterator>(db_->NewIterator(ReadOptions()));
1311
1394
 
1312
- iter->Seek("my_key_bbb");
1395
+ iter->Seek(prefix + "bbb");
1313
1396
  ASSERT_TRUE(iter->Valid());
1314
1397
 
1315
- iter->Seek("my_key_ccccccccc");
1398
+ iter->Seek(prefix + "ccccccccc");
1316
1399
  ASSERT_TRUE(iter->Valid());
1317
1400
 
1318
- iter->Seek("my_key_ddd");
1401
+ iter->Seek(prefix + "ddd");
1319
1402
  ASSERT_TRUE(iter->Valid());
1320
1403
 
1321
- iter->Seek("my_key_ddddddd");
1404
+ iter->Seek(prefix + "ddddddd");
1322
1405
  ASSERT_TRUE(iter->Valid());
1323
1406
 
1324
- iter->Seek("my_key_e");
1407
+ iter->Seek(prefix + "e");
1325
1408
  ASSERT_TRUE(iter->Valid());
1326
1409
 
1327
- iter->Seek("my_key_eeeee");
1410
+ iter->Seek(prefix + "eeeee");
1328
1411
  ASSERT_TRUE(iter->Valid());
1329
1412
 
1330
- iter->Seek("my_key_eeeeeeeee");
1413
+ iter->Seek(prefix + "eeeeeeeee");
1331
1414
  ASSERT_TRUE(iter->Valid());
1332
1415
  }
1333
1416
 
1334
1417
  ReadOptions ropts;
1335
- ropts.auto_readahead_size = true;
1336
1418
  ReadOptions cmp_ro;
1337
- cmp_ro.auto_readahead_size = false;
1338
1419
 
1339
1420
  if (std::get<0>(GetParam())) {
1340
1421
  ropts.readahead_size = cmp_ro.readahead_size = 32768;
@@ -1345,61 +1426,31 @@ TEST_P(PrefetchTest, PrefetchWithBlockLookupAutoTuneTest) {
1345
1426
  }
1346
1427
 
1347
1428
  // With and without tuning readahead_size.
1348
- {
1349
- ASSERT_OK(options.statistics->Reset());
1350
- // Seek.
1351
- {
1352
- Slice ub = Slice("my_key_uuu");
1353
- Slice* ub_ptr = &ub;
1354
- cmp_ro.iterate_upper_bound = ub_ptr;
1355
- ropts.iterate_upper_bound = ub_ptr;
1356
-
1357
- auto iter = std::unique_ptr<Iterator>(db_->NewIterator(ropts));
1358
- auto cmp_iter = std::unique_ptr<Iterator>(db_->NewIterator(cmp_ro));
1359
-
1360
- Slice seek_key = Slice("my_key_aaa");
1361
- iter->Seek(seek_key);
1362
- cmp_iter->Seek(seek_key);
1363
-
1364
- while (iter->Valid() && cmp_iter->Valid()) {
1365
- if (iter->key() != cmp_iter->key()) {
1366
- // Error
1367
- ASSERT_TRUE(false);
1368
- }
1369
- iter->Next();
1370
- cmp_iter->Next();
1371
- }
1372
-
1373
- ASSERT_OK(cmp_iter->status());
1374
- ASSERT_OK(iter->status());
1375
- }
1376
-
1377
- // Reseek with new upper_bound_iterator.
1378
- {
1379
- Slice ub = Slice("my_key_y");
1380
- ropts.iterate_upper_bound = &ub;
1381
- cmp_ro.iterate_upper_bound = &ub;
1382
-
1383
- auto iter = std::unique_ptr<Iterator>(db_->NewIterator(ropts));
1384
- auto cmp_iter = std::unique_ptr<Iterator>(db_->NewIterator(cmp_ro));
1385
-
1386
- Slice reseek_key = Slice("my_key_v");
1387
- iter->Seek(reseek_key);
1388
- cmp_iter->Seek(reseek_key);
1389
-
1390
- while (iter->Valid() && cmp_iter->Valid()) {
1391
- if (iter->key() != cmp_iter->key()) {
1392
- // Error
1393
- ASSERT_TRUE(false);
1394
- }
1395
- iter->Next();
1396
- cmp_iter->Next();
1397
- }
1398
-
1399
- ASSERT_OK(cmp_iter->status());
1400
- ASSERT_OK(iter->status());
1401
- }
1402
- }
1429
+ ropts.auto_readahead_size = true;
1430
+ cmp_ro.auto_readahead_size = false;
1431
+ ASSERT_OK(options.statistics->Reset());
1432
+ // Seek with a upper bound
1433
+ const std::string seek_key_str = prefix + "aaa";
1434
+ const Slice seek_key(seek_key_str);
1435
+ const std::string ub_str = prefix + "uuu";
1436
+ const Slice ub(ub_str);
1437
+ VerifyScan(ropts /* iter_ro */, cmp_ro /* cmp_iter_ro */,
1438
+ &seek_key /* seek_key */, &ub /* iterate_upper_bound */,
1439
+ false /* prefix_same_as_start */);
1440
+
1441
+ // Seek with a new seek key and upper bound
1442
+ const std::string seek_key_new_str = prefix + "v";
1443
+ const Slice seek_key_new(seek_key_new_str);
1444
+ const std::string ub_new_str = prefix + "y";
1445
+ const Slice ub_new(ub_new_str);
1446
+ VerifyScan(ropts /* iter_ro */, cmp_ro /* cmp_iter_ro */,
1447
+ &seek_key_new /* seek_key */, &ub_new /* iterate_upper_bound */,
1448
+ false /* prefix_same_as_start */);
1449
+
1450
+ // Seek with no upper bound, prefix_same_as_start = true
1451
+ VerifyScan(ropts /* iter_ro */, cmp_ro /* cmp_iter_ro */,
1452
+ &seek_key /* seek_key */, nullptr /* iterate_upper_bound */,
1453
+ true /* prefix_same_as_start */);
1403
1454
  Close();
1404
1455
  }
1405
1456
  }
@@ -1418,6 +1469,8 @@ TEST_F(PrefetchTest, PrefetchWithBlockLookupAutoTuneWithPrev) {
1418
1469
  Options options;
1419
1470
  SetGenericOptions(env.get(), /*use_direct_io=*/false, options);
1420
1471
  options.statistics = CreateDBStatistics();
1472
+ const std::string prefix = "my_key_";
1473
+ options.prefix_extractor.reset(NewFixedPrefixTransform(prefix.size()));
1421
1474
  BlockBasedTableOptions table_options;
1422
1475
  SetBlockBasedTableOptions(table_options);
1423
1476
  std::shared_ptr<Cache> cache = NewLRUCache(1024 * 1024, 2);
@@ -1432,7 +1485,7 @@ TEST_F(PrefetchTest, PrefetchWithBlockLookupAutoTuneWithPrev) {
1432
1485
  WriteBatch batch;
1433
1486
 
1434
1487
  for (int i = 0; i < 26; i++) {
1435
- std::string key = "my_key_";
1488
+ std::string key = prefix;
1436
1489
 
1437
1490
  for (int j = 0; j < 10; j++) {
1438
1491
  key += char('a' + i);
@@ -1441,9 +1494,9 @@ TEST_F(PrefetchTest, PrefetchWithBlockLookupAutoTuneWithPrev) {
1441
1494
  }
1442
1495
  ASSERT_OK(db_->Write(WriteOptions(), &batch));
1443
1496
 
1444
- std::string start_key = "my_key_a";
1497
+ std::string start_key = prefix + "a";
1445
1498
 
1446
- std::string end_key = "my_key_";
1499
+ std::string end_key = prefix;
1447
1500
  for (int j = 0; j < 10; j++) {
1448
1501
  end_key += char('a' + 25);
1449
1502
  }
@@ -1455,58 +1508,147 @@ TEST_F(PrefetchTest, PrefetchWithBlockLookupAutoTuneWithPrev) {
1455
1508
 
1456
1509
  ReadOptions ropts;
1457
1510
  ropts.auto_readahead_size = true;
1511
+ ReadOptions cmp_readopts = ropts;
1512
+ cmp_readopts.auto_readahead_size = false;
1513
+
1514
+ const std::string seek_key_str = prefix + "bbb";
1515
+ const Slice seek_key(seek_key_str);
1516
+ const std::string ub_key = prefix + "uuu";
1517
+ const Slice ub(ub_key);
1518
+
1519
+ VerifySeekPrevSeek(ropts /* iter_ro */, cmp_readopts /* cmp_iter_ro */,
1520
+ &seek_key /* seek_key */, &ub /* iterate_upper_bound */,
1521
+ false /* prefix_same_as_start */);
1522
+
1523
+ VerifySeekPrevSeek(ropts /* iter_ro */, cmp_readopts /* cmp_iter_ro */,
1524
+ &seek_key /* seek_key */,
1525
+ nullptr /* iterate_upper_bound */,
1526
+ true /* prefix_same_as_start */);
1527
+ Close();
1528
+ }
1458
1529
 
1459
- {
1460
- // Seek.
1461
- Slice ub = Slice("my_key_uuu");
1462
- Slice* ub_ptr = &ub;
1463
- ropts.iterate_upper_bound = ub_ptr;
1464
- ropts.auto_readahead_size = true;
1530
+ class PrefetchTrimReadaheadTestParam
1531
+ : public DBTestBase,
1532
+ public ::testing::WithParamInterface<
1533
+ std::tuple<BlockBasedTableOptions::IndexShorteningMode, bool>> {
1534
+ public:
1535
+ const std::string kPrefix = "a_prefix_";
1536
+ Random rnd = Random(309);
1465
1537
 
1466
- ReadOptions cmp_readopts = ropts;
1467
- cmp_readopts.auto_readahead_size = false;
1538
+ PrefetchTrimReadaheadTestParam()
1539
+ : DBTestBase("prefetch_trim_readahead_test_param", true) {}
1540
+ virtual void SetGenericOptions(Env* env, Options& options) {
1541
+ options = CurrentOptions();
1542
+ options.env = env;
1543
+ options.create_if_missing = true;
1544
+ options.disable_auto_compactions = true;
1545
+ options.statistics = CreateDBStatistics();
1468
1546
 
1469
- auto iter = std::unique_ptr<Iterator>(db_->NewIterator(ropts));
1470
- auto cmp_iter = std::unique_ptr<Iterator>(db_->NewIterator(cmp_readopts));
1547
+ // To make all the data bocks fit in one file for testing purpose
1548
+ options.write_buffer_size = 1024 * 1024 * 1024;
1549
+ options.prefix_extractor.reset(NewFixedPrefixTransform(kPrefix.size()));
1550
+ }
1471
1551
 
1472
- Slice seek_key = Slice("my_key_bbb");
1473
- {
1474
- cmp_iter->Seek(seek_key);
1475
- ASSERT_TRUE(cmp_iter->Valid());
1476
- ASSERT_OK(cmp_iter->status());
1552
+ void SetBlockBasedTableOptions(BlockBasedTableOptions& table_options) {
1553
+ table_options.no_block_cache = false;
1554
+ table_options.index_shortening = std::get<0>(GetParam());
1477
1555
 
1478
- iter->Seek(seek_key);
1479
- ASSERT_TRUE(iter->Valid());
1480
- ASSERT_OK(iter->status());
1556
+ // To force keys with different prefixes are in different data blocks of the
1557
+ // file for testing purpose
1558
+ table_options.block_size = 1;
1559
+ table_options.flush_block_policy_factory.reset(
1560
+ new FlushBlockBySizePolicyFactory());
1561
+ }
1562
+ };
1481
1563
 
1482
- ASSERT_EQ(iter->key(), cmp_iter->key());
1483
- }
1564
+ INSTANTIATE_TEST_CASE_P(
1565
+ PrefetchTrimReadaheadTestParam, PrefetchTrimReadaheadTestParam,
1566
+ ::testing::Combine(
1567
+ // Params are as follows -
1568
+ // Param 0 - TableOptions::index_shortening
1569
+ // Param 2 - ReadOptinos::auto_readahead_size
1570
+ ::testing::Values(
1571
+ BlockBasedTableOptions::IndexShorteningMode::kNoShortening,
1572
+ BlockBasedTableOptions::IndexShorteningMode::kShortenSeparators,
1573
+ BlockBasedTableOptions::IndexShorteningMode::
1574
+ kShortenSeparatorsAndSuccessor),
1575
+ ::testing::Bool()));
1576
+
1577
+ TEST_P(PrefetchTrimReadaheadTestParam, PrefixSameAsStart) {
1578
+ if (mem_env_ || encrypted_env_) {
1579
+ ROCKSDB_GTEST_SKIP("Test requires non-mem or non-encrypted environment");
1580
+ return;
1581
+ }
1582
+ const bool auto_readahead_size = std::get<1>(GetParam());
1484
1583
 
1485
- // Prev op should pass with auto tuning of readahead_size.
1486
- {
1487
- cmp_iter->Prev();
1488
- ASSERT_TRUE(cmp_iter->Valid());
1489
- ASSERT_OK(cmp_iter->status());
1584
+ std::shared_ptr<MockFS> fs = std::make_shared<MockFS>(
1585
+ FileSystem::Default(), false /* support_prefetch */,
1586
+ true /* small_buffer_alignment */);
1587
+ std::unique_ptr<Env> env(new CompositeEnvWrapper(env_, fs));
1588
+ Options options;
1589
+ SetGenericOptions(env.get(), options);
1590
+ BlockBasedTableOptions table_optoins;
1591
+ SetBlockBasedTableOptions(table_optoins);
1592
+ options.table_factory.reset(NewBlockBasedTableFactory(table_optoins));
1490
1593
 
1491
- iter->Prev();
1492
- ASSERT_OK(iter->status());
1493
- ASSERT_TRUE(iter->Valid());
1594
+ Status s = TryReopen(options);
1595
+ ASSERT_OK(s);
1494
1596
 
1495
- ASSERT_EQ(iter->key(), cmp_iter->key());
1496
- }
1597
+ // To create a DB with data block layout (denoted as "[...]" below ) as the
1598
+ // following:
1599
+ // ["a_prefix_0": random value]
1600
+ // ["a_prefix_1": random value]
1601
+ // ...
1602
+ // ["a_prefix_9": random value]
1603
+ // ["c_prefix_0": random value]
1604
+ // ["d_prefix_1": random value]
1605
+ // ...
1606
+ // ["l_prefix_9": random value]
1607
+ //
1608
+ // We want to verify keys not with prefix "a_prefix_" are not prefetched due
1609
+ // to trimming
1610
+ WriteBatch prefix_batch;
1611
+ for (int i = 0; i < 10; i++) {
1612
+ std::string key = kPrefix + std::to_string(i);
1613
+ ASSERT_OK(prefix_batch.Put(key, rnd.RandomString(100)));
1614
+ }
1615
+ ASSERT_OK(db_->Write(WriteOptions(), &prefix_batch));
1616
+
1617
+ WriteBatch diff_prefix_batch;
1618
+ for (int i = 0; i < 10; i++) {
1619
+ std::string diff_prefix = std::string(1, char('c' + i)) + kPrefix.substr(1);
1620
+ std::string key = diff_prefix + std::to_string(i);
1621
+ ASSERT_OK(diff_prefix_batch.Put(key, rnd.RandomString(100)));
1622
+ }
1623
+ ASSERT_OK(db_->Write(WriteOptions(), &diff_prefix_batch));
1497
1624
 
1498
- // Reseek would follow as usual.
1499
- {
1500
- cmp_iter->Seek(seek_key);
1501
- ASSERT_TRUE(cmp_iter->Valid());
1502
- ASSERT_OK(cmp_iter->status());
1625
+ ASSERT_OK(db_->Flush(FlushOptions()));
1503
1626
 
1504
- iter->Seek(seek_key);
1505
- ASSERT_OK(iter->status());
1506
- ASSERT_TRUE(iter->Valid());
1507
- ASSERT_EQ(iter->key(), cmp_iter->key());
1627
+ // To verify readahead is trimmed based on prefix by checking the counter
1628
+ // READAHEAD_TRIMMED
1629
+ ReadOptions ro;
1630
+ ro.prefix_same_as_start = true;
1631
+ ro.auto_readahead_size = auto_readahead_size;
1632
+ // Set a large readahead size to introduce readahead waste when without
1633
+ // trimming based on prefix
1634
+ ro.readahead_size = 1024 * 1024 * 1024;
1635
+
1636
+ ASSERT_OK(options.statistics->Reset());
1637
+ {
1638
+ auto iter = std::unique_ptr<Iterator>(db_->NewIterator(ro));
1639
+ for (iter->Seek(kPrefix); iter->status().ok() && iter->Valid();
1640
+ iter->Next()) {
1508
1641
  }
1509
1642
  }
1643
+
1644
+ auto readahead_trimmed =
1645
+ options.statistics->getTickerCount(READAHEAD_TRIMMED);
1646
+
1647
+ if (auto_readahead_size) {
1648
+ ASSERT_GT(readahead_trimmed, 0);
1649
+ } else {
1650
+ ASSERT_EQ(readahead_trimmed, 0);
1651
+ }
1510
1652
  Close();
1511
1653
  }
1512
1654
 
@@ -3148,6 +3290,482 @@ TEST_F(FilePrefetchBufferTest, SyncReadaheadStats) {
3148
3290
  /* 24576(end offset of the buffer) - 16000(requested offset) =*/8576);
3149
3291
  }
3150
3292
 
3293
+ class FSBufferPrefetchTest : public testing::Test,
3294
+ public ::testing::WithParamInterface<bool> {
3295
+ public:
3296
+ // Mock file system supporting the kFSBuffer buffer reuse operation
3297
+ class BufferReuseFS : public FileSystemWrapper {
3298
+ public:
3299
+ explicit BufferReuseFS(const std::shared_ptr<FileSystem>& _target)
3300
+ : FileSystemWrapper(_target) {}
3301
+ ~BufferReuseFS() override {}
3302
+ const char* Name() const override { return "BufferReuseFS"; }
3303
+
3304
+ IOStatus NewRandomAccessFile(const std::string& fname,
3305
+ const FileOptions& opts,
3306
+ std::unique_ptr<FSRandomAccessFile>* result,
3307
+ IODebugContext* dbg) override {
3308
+ class WrappedRandomAccessFile : public FSRandomAccessFileOwnerWrapper {
3309
+ public:
3310
+ explicit WrappedRandomAccessFile(
3311
+ std::unique_ptr<FSRandomAccessFile>& file)
3312
+ : FSRandomAccessFileOwnerWrapper(std::move(file)) {}
3313
+
3314
+ IOStatus MultiRead(FSReadRequest* reqs, size_t num_reqs,
3315
+ const IOOptions& options,
3316
+ IODebugContext* dbg) override {
3317
+ for (size_t i = 0; i < num_reqs; ++i) {
3318
+ FSReadRequest& req = reqs[i];
3319
+ FSAllocationPtr buffer(new char[req.len], [](void* ptr) {
3320
+ delete[] static_cast<char*>(ptr);
3321
+ });
3322
+ req.fs_scratch = std::move(buffer);
3323
+ req.status = Read(req.offset, req.len, options, &req.result,
3324
+ static_cast<char*>(req.fs_scratch.get()), dbg);
3325
+ }
3326
+ return IOStatus::OK();
3327
+ }
3328
+ };
3329
+
3330
+ std::unique_ptr<FSRandomAccessFile> file;
3331
+ IOStatus s = target()->NewRandomAccessFile(fname, opts, &file, dbg);
3332
+ EXPECT_OK(s);
3333
+ result->reset(new WrappedRandomAccessFile(file));
3334
+ return s;
3335
+ }
3336
+
3337
+ void SupportedOps(int64_t& supported_ops) override {
3338
+ supported_ops = 1 << FSSupportedOps::kAsyncIO;
3339
+ supported_ops |= 1 << FSSupportedOps::kFSBuffer;
3340
+ }
3341
+ };
3342
+
3343
+ void SetUp() override {
3344
+ SetupSyncPointsToMockDirectIO();
3345
+ env_ = Env::Default();
3346
+ bool use_async_prefetch = GetParam();
3347
+ if (use_async_prefetch) {
3348
+ fs_ = FileSystem::Default();
3349
+ } else {
3350
+ fs_ = std::make_shared<BufferReuseFS>(FileSystem::Default());
3351
+ }
3352
+
3353
+ test_dir_ = test::PerThreadDBPath("fs_buffer_prefetch_test");
3354
+ ASSERT_OK(fs_->CreateDir(test_dir_, IOOptions(), nullptr));
3355
+ stats_ = CreateDBStatistics();
3356
+ }
3357
+
3358
+ void TearDown() override { EXPECT_OK(DestroyDir(env_, test_dir_)); }
3359
+
3360
+ void Write(const std::string& fname, const std::string& content) {
3361
+ std::unique_ptr<FSWritableFile> f;
3362
+ ASSERT_OK(fs_->NewWritableFile(Path(fname), FileOptions(), &f, nullptr));
3363
+ ASSERT_OK(f->Append(content, IOOptions(), nullptr));
3364
+ ASSERT_OK(f->Close(IOOptions(), nullptr));
3365
+ }
3366
+
3367
+ void Read(const std::string& fname, const FileOptions& opts,
3368
+ std::unique_ptr<RandomAccessFileReader>* reader) {
3369
+ std::string fpath = Path(fname);
3370
+ std::unique_ptr<FSRandomAccessFile> f;
3371
+ ASSERT_OK(fs_->NewRandomAccessFile(fpath, opts, &f, nullptr));
3372
+ reader->reset(new RandomAccessFileReader(
3373
+ std::move(f), fpath, env_->GetSystemClock().get(),
3374
+ /*io_tracer=*/nullptr, stats_.get()));
3375
+ }
3376
+
3377
+ FileSystem* fs() { return fs_.get(); }
3378
+ Statistics* stats() { return stats_.get(); }
3379
+ SystemClock* clock() { return env_->GetSystemClock().get(); }
3380
+
3381
+ private:
3382
+ Env* env_;
3383
+ std::shared_ptr<FileSystem> fs_;
3384
+ std::string test_dir_;
3385
+ std::shared_ptr<Statistics> stats_;
3386
+
3387
+ std::string Path(const std::string& fname) { return test_dir_ + "/" + fname; }
3388
+ };
3389
+
3390
+ INSTANTIATE_TEST_CASE_P(FSBufferPrefetchTest, FSBufferPrefetchTest,
3391
+ ::testing::Bool());
3392
+
3393
+ TEST_P(FSBufferPrefetchTest, FSBufferPrefetchStatsInternals) {
3394
+ // Check that the main buffer, the overlap_buf_, and the secondary buffer (in
3395
+ // the case of num_buffers_ > 1) are populated correctly while reading a 32
3396
+ // KiB file
3397
+ std::string fname = "fs-buffer-prefetch-stats-internals";
3398
+ Random rand(0);
3399
+ std::string content = rand.RandomString(32768);
3400
+ Write(fname, content);
3401
+
3402
+ FileOptions opts;
3403
+ std::unique_ptr<RandomAccessFileReader> r;
3404
+ Read(fname, opts, &r);
3405
+
3406
+ std::shared_ptr<Statistics> stats = CreateDBStatistics();
3407
+ ReadaheadParams readahead_params;
3408
+ readahead_params.initial_readahead_size = 8192;
3409
+ readahead_params.max_readahead_size = 8192;
3410
+ bool use_async_prefetch = GetParam();
3411
+ size_t num_buffers = use_async_prefetch ? 2 : 1;
3412
+ readahead_params.num_buffers = num_buffers;
3413
+
3414
+ FilePrefetchBuffer fpb(readahead_params, true, false, fs(), clock(),
3415
+ stats.get());
3416
+
3417
+ int overlap_buffer_write_ct = 0;
3418
+ ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
3419
+ "FilePrefetchBuffer::CopyDataToOverlapBuffer:Complete",
3420
+ [&](void* /*arg*/) { overlap_buffer_write_ct++; });
3421
+ SyncPoint::GetInstance()->EnableProcessing();
3422
+
3423
+ Slice result;
3424
+ // Read 4096 bytes at offset 0.
3425
+ Status s;
3426
+ std::vector<std::tuple<uint64_t, size_t, bool>> buffer_info(num_buffers);
3427
+ std::pair<uint64_t, size_t> overlap_buffer_info;
3428
+ bool could_read_from_cache =
3429
+ fpb.TryReadFromCache(IOOptions(), r.get(), 0, 4096, &result, &s);
3430
+ // Platforms that don't have IO uring may not support async IO.
3431
+ if (use_async_prefetch && s.IsNotSupported()) {
3432
+ return;
3433
+ }
3434
+ ASSERT_TRUE(could_read_from_cache);
3435
+ ASSERT_EQ(s, Status::OK());
3436
+ ASSERT_EQ(stats->getAndResetTickerCount(PREFETCH_HITS), 0);
3437
+ ASSERT_EQ(stats->getAndResetTickerCount(PREFETCH_BYTES_USEFUL), 0);
3438
+ ASSERT_EQ(strncmp(result.data(), content.substr(0, 4096).c_str(), 4096), 0);
3439
+ fpb.TEST_GetOverlapBufferOffsetandSize(overlap_buffer_info);
3440
+ fpb.TEST_GetBufferOffsetandSize(buffer_info);
3441
+ if (use_async_prefetch) {
3442
+ // Cut the readahead of 8192 in half.
3443
+ // Overlap buffer is not used
3444
+ ASSERT_EQ(overlap_buffer_info.first, 0);
3445
+ ASSERT_EQ(overlap_buffer_info.second, 0);
3446
+ // Buffers: 0-8192, 8192-12288
3447
+ ASSERT_EQ(std::get<0>(buffer_info[0]), 0);
3448
+ ASSERT_EQ(std::get<1>(buffer_info[0]), 4096 + 8192 / 2);
3449
+ ASSERT_EQ(std::get<0>(buffer_info[1]), 4096 + 8192 / 2);
3450
+ ASSERT_EQ(std::get<1>(buffer_info[1]), 8192 / 2);
3451
+ } else {
3452
+ // Read at offset 0 with length 4096 + 8192 = 12288.
3453
+ // Overlap buffer is not used
3454
+ ASSERT_EQ(overlap_buffer_info.first, 0);
3455
+ ASSERT_EQ(overlap_buffer_info.second, 0);
3456
+ // Main buffer contains the requested data + the 8192 of prefetched data
3457
+ ASSERT_EQ(std::get<0>(buffer_info[0]), 0);
3458
+ ASSERT_EQ(std::get<1>(buffer_info[0]), 4096 + 8192);
3459
+ }
3460
+
3461
+ // Simulate a block cache hit
3462
+ fpb.UpdateReadPattern(4096, 4096, false);
3463
+ ASSERT_TRUE(
3464
+ fpb.TryReadFromCache(IOOptions(), r.get(), 8192, 8192, &result, &s));
3465
+ ASSERT_EQ(s, Status::OK());
3466
+ ASSERT_EQ(stats->getAndResetTickerCount(PREFETCH_HITS), 0);
3467
+ ASSERT_EQ(stats->getAndResetTickerCount(PREFETCH_BYTES_USEFUL),
3468
+ 4096); // 8192-12288
3469
+ ASSERT_EQ(strncmp(result.data(), content.substr(8192, 8192).c_str(), 8192),
3470
+ 0);
3471
+ fpb.TEST_GetOverlapBufferOffsetandSize(overlap_buffer_info);
3472
+ fpb.TEST_GetBufferOffsetandSize(buffer_info);
3473
+
3474
+ if (use_async_prefetch) {
3475
+ // Our buffers were 0-8192, 8192-12288 at the start so we had some
3476
+ // overlapping data in the second buffer
3477
+ // We clean up outdated buffers so 0-8192 gets freed for more prefetching.
3478
+ // Our remaining buffer 8192-12288 has data that we want, so we can reuse it
3479
+ // We end up with: 8192-20480, 20480-24576
3480
+ ASSERT_EQ(overlap_buffer_info.first, 0);
3481
+ ASSERT_EQ(overlap_buffer_info.second, 0);
3482
+ ASSERT_EQ(std::get<0>(buffer_info[0]), 8192);
3483
+ ASSERT_EQ(std::get<1>(buffer_info[0]), 8192 + 8192 / 2);
3484
+ ASSERT_EQ(std::get<0>(buffer_info[1]), 8192 + (8192 + 8192 / 2));
3485
+ ASSERT_EQ(std::get<1>(buffer_info[1]), 8192 / 2);
3486
+ } else {
3487
+ // We only have 0-12288 cached, so reading from 8192-16384 will trigger a
3488
+ // prefetch up through 16384 + 8192 = 24576.
3489
+ // Overlap buffer reuses bytes 8192 to 12288
3490
+ ASSERT_EQ(overlap_buffer_info.first, 8192);
3491
+ ASSERT_EQ(overlap_buffer_info.second, 8192);
3492
+ ASSERT_EQ(overlap_buffer_write_ct, 2);
3493
+ // We spill to the overlap buffer so the remaining buffer only has the
3494
+ // missing and prefetched part
3495
+ ASSERT_EQ(std::get<0>(buffer_info[0]), 12288);
3496
+ ASSERT_EQ(std::get<1>(buffer_info[0]), 12288);
3497
+ }
3498
+
3499
+ ASSERT_TRUE(
3500
+ fpb.TryReadFromCache(IOOptions(), r.get(), 12288, 4096, &result, &s));
3501
+ ASSERT_EQ(s, Status::OK());
3502
+ ASSERT_EQ(stats->getAndResetTickerCount(PREFETCH_HITS), 1);
3503
+ ASSERT_EQ(stats->getAndResetTickerCount(PREFETCH_BYTES_USEFUL),
3504
+ 4096); // 12288-16384
3505
+ ASSERT_EQ(strncmp(result.data(), content.substr(12288, 4096).c_str(), 4096),
3506
+ 0);
3507
+ fpb.TEST_GetOverlapBufferOffsetandSize(overlap_buffer_info);
3508
+ fpb.TEST_GetBufferOffsetandSize(buffer_info);
3509
+
3510
+ if (use_async_prefetch) {
3511
+ // Same as before: 8192-20480, 20480-24576 (cache hit in first buffer)
3512
+ ASSERT_EQ(overlap_buffer_info.first, 0);
3513
+ ASSERT_EQ(overlap_buffer_info.second, 0);
3514
+ ASSERT_EQ(std::get<0>(buffer_info[0]), 8192);
3515
+ ASSERT_EQ(std::get<1>(buffer_info[0]), 8192 + 8192 / 2);
3516
+ ASSERT_EQ(std::get<0>(buffer_info[1]), 8192 + (8192 + 8192 / 2));
3517
+ ASSERT_EQ(std::get<1>(buffer_info[1]), 8192 / 2);
3518
+ } else {
3519
+ // The main buffer has 12288-24576, so 12288-16384 is a cache hit.
3520
+ // Overlap buffer does not get used
3521
+ fpb.TEST_GetOverlapBufferOffsetandSize(overlap_buffer_info);
3522
+ ASSERT_EQ(overlap_buffer_info.first, 8192);
3523
+ ASSERT_EQ(overlap_buffer_info.second, 8192);
3524
+ ASSERT_EQ(overlap_buffer_write_ct, 2);
3525
+ // Main buffer stays the same
3526
+ ASSERT_EQ(std::get<0>(buffer_info[0]), 12288);
3527
+ ASSERT_EQ(std::get<1>(buffer_info[0]), 12288);
3528
+ }
3529
+
3530
+ // Read from 16000-26000 (start and end do not meet normal alignment)
3531
+ ASSERT_TRUE(
3532
+ fpb.TryReadFromCache(IOOptions(), r.get(), 16000, 10000, &result, &s));
3533
+ ASSERT_EQ(s, Status::OK());
3534
+ ASSERT_EQ(stats->getAndResetTickerCount(PREFETCH_HITS), 0);
3535
+ ASSERT_EQ(
3536
+ stats->getAndResetTickerCount(PREFETCH_BYTES_USEFUL),
3537
+ /* 24576(end offset of the buffer) - 16000(requested offset) =*/8576);
3538
+ ASSERT_EQ(strncmp(result.data(), content.substr(16000, 10000).c_str(), 10000),
3539
+ 0);
3540
+ fpb.TEST_GetOverlapBufferOffsetandSize(overlap_buffer_info);
3541
+ fpb.TEST_GetBufferOffsetandSize(buffer_info);
3542
+ if (use_async_prefetch) {
3543
+ // Overlap buffer reuses bytes 16000 to 20480
3544
+ ASSERT_EQ(overlap_buffer_info.first, 16000);
3545
+ ASSERT_EQ(overlap_buffer_info.second, 10000);
3546
+ // First 2 writes are reusing existing 2 buffers. Last write fills in
3547
+ // what could not be found in either.
3548
+ ASSERT_EQ(overlap_buffer_write_ct, 3);
3549
+ ASSERT_EQ(std::get<0>(buffer_info[0]), 24576);
3550
+ ASSERT_EQ(std::get<1>(buffer_info[0]), 32768 - 24576);
3551
+ ASSERT_EQ(std::get<0>(buffer_info[1]), 32768);
3552
+ ASSERT_EQ(std::get<1>(buffer_info[1]), 4096);
3553
+ ASSERT_TRUE(std::get<2>(
3554
+ buffer_info[1])); // in progress async request (otherwise we should not
3555
+ // be getting 4096 for the size)
3556
+ } else {
3557
+ // Overlap buffer reuses bytes 16000 to 24576
3558
+ ASSERT_EQ(overlap_buffer_info.first, 16000);
3559
+ ASSERT_EQ(overlap_buffer_info.second, 10000);
3560
+ ASSERT_EQ(overlap_buffer_write_ct, 4);
3561
+ // Even if you try to readahead to offset 16000 + 10000 + 8192, there are
3562
+ // only 32768 bytes in the original file
3563
+ ASSERT_EQ(std::get<0>(buffer_info[0]), 12288 + 12288);
3564
+ ASSERT_EQ(std::get<1>(buffer_info[0]), 8192);
3565
+ }
3566
+ }
3567
+
3568
+ TEST_P(FSBufferPrefetchTest, FSBufferPrefetchUnalignedReads) {
3569
+ // Check that the main buffer, the overlap_buf_, and the secondary buffer (in
3570
+ // the case of num_buffers_ > 1) are populated correctly
3571
+ // while reading with no regard to alignment
3572
+ std::string fname = "fs-buffer-prefetch-unaligned-reads";
3573
+ Random rand(0);
3574
+ std::string content = rand.RandomString(1000);
3575
+ Write(fname, content);
3576
+
3577
+ FileOptions opts;
3578
+ std::unique_ptr<RandomAccessFileReader> r;
3579
+ Read(fname, opts, &r);
3580
+
3581
+ std::shared_ptr<Statistics> stats = CreateDBStatistics();
3582
+ ReadaheadParams readahead_params;
3583
+ // Readahead size will double each time
3584
+ readahead_params.initial_readahead_size = 5;
3585
+ readahead_params.max_readahead_size = 100;
3586
+ bool use_async_prefetch = GetParam();
3587
+ size_t num_buffers = use_async_prefetch ? 2 : 1;
3588
+ readahead_params.num_buffers = num_buffers;
3589
+ FilePrefetchBuffer fpb(readahead_params, true, false, fs(), clock(),
3590
+ stats.get());
3591
+
3592
+ int overlap_buffer_write_ct = 0;
3593
+ ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
3594
+ "FilePrefetchBuffer::CopyDataToOverlapBuffer:Complete",
3595
+ [&](void* /*arg*/) { overlap_buffer_write_ct++; });
3596
+ SyncPoint::GetInstance()->EnableProcessing();
3597
+
3598
+ Slice result;
3599
+ // Read 3 bytes at offset 5
3600
+ Status s;
3601
+ std::vector<std::tuple<uint64_t, size_t, bool>> buffer_info(num_buffers);
3602
+ std::pair<uint64_t, size_t> overlap_buffer_info;
3603
+ bool could_read_from_cache =
3604
+ fpb.TryReadFromCache(IOOptions(), r.get(), 5, 3, &result, &s);
3605
+ // Platforms that don't have IO uring may not support async IO.
3606
+ if (use_async_prefetch && s.IsNotSupported()) {
3607
+ return;
3608
+ }
3609
+ ASSERT_TRUE(could_read_from_cache);
3610
+ ASSERT_EQ(s, Status::OK());
3611
+ ASSERT_EQ(strncmp(result.data(), content.substr(5, 3).c_str(), 3), 0);
3612
+ fpb.TEST_GetOverlapBufferOffsetandSize(overlap_buffer_info);
3613
+ fpb.TEST_GetBufferOffsetandSize(buffer_info);
3614
+ if (use_async_prefetch) {
3615
+ // Overlap buffer is not used
3616
+ ASSERT_EQ(overlap_buffer_info.first, 0);
3617
+ ASSERT_EQ(overlap_buffer_info.second, 0);
3618
+ // With async prefetching, we still try to align to 4096 bytes, so
3619
+ // our main buffer read and secondary buffer prefetch are rounded up
3620
+ ASSERT_EQ(std::get<0>(buffer_info[0]), 0);
3621
+ ASSERT_EQ(std::get<1>(buffer_info[0]), 1000);
3622
+ // This buffer won't actually get filled up with data since there is nothing
3623
+ // after 1000
3624
+ ASSERT_EQ(std::get<0>(buffer_info[1]), 4096);
3625
+ ASSERT_EQ(std::get<1>(buffer_info[1]), 4096);
3626
+ ASSERT_TRUE(std::get<2>(buffer_info[1])); // in progress async request
3627
+ } else {
3628
+ // Overlap buffer is not used
3629
+ ASSERT_EQ(overlap_buffer_info.first, 0);
3630
+ ASSERT_EQ(overlap_buffer_info.second, 0);
3631
+ // Main buffer contains the requested data + 5 of prefetched data (5 - 13)
3632
+ ASSERT_EQ(std::get<0>(buffer_info[0]), 5);
3633
+ ASSERT_EQ(std::get<1>(buffer_info[0]), 3 + 5);
3634
+ }
3635
+
3636
+ ASSERT_TRUE(fpb.TryReadFromCache(IOOptions(), r.get(), 16, 7, &result, &s));
3637
+ ASSERT_EQ(s, Status::OK());
3638
+ ASSERT_EQ(strncmp(result.data(), content.substr(16, 7).c_str(), 7), 0);
3639
+ fpb.TEST_GetOverlapBufferOffsetandSize(overlap_buffer_info);
3640
+ fpb.TEST_GetBufferOffsetandSize(buffer_info);
3641
+ if (use_async_prefetch) {
3642
+ // Complete hit since we have the entire file loaded in the main buffer
3643
+ // The remaining requests will be the same when use_async_prefetch is true
3644
+ ASSERT_EQ(overlap_buffer_info.first, 0);
3645
+ ASSERT_EQ(overlap_buffer_info.second, 0);
3646
+ ASSERT_EQ(std::get<0>(buffer_info[0]), 0);
3647
+ ASSERT_EQ(std::get<1>(buffer_info[0]), 1000);
3648
+ } else {
3649
+ // Complete miss: read 7 bytes at offset 16
3650
+ // Overlap buffer is not used (no partial hit)
3651
+ ASSERT_EQ(overlap_buffer_info.first, 0);
3652
+ ASSERT_EQ(overlap_buffer_info.second, 0);
3653
+ // Main buffer contains the requested data + 10 of prefetched data (16 - 33)
3654
+ ASSERT_EQ(std::get<0>(buffer_info[0]), 16);
3655
+ ASSERT_EQ(std::get<1>(buffer_info[0]), 7 + 10);
3656
+ }
3657
+
3658
+ // Go backwards
3659
+ if (use_async_prefetch) {
3660
+ ASSERT_TRUE(fpb.TryReadFromCache(IOOptions(), r.get(), 10, 8, &result, &s));
3661
+ } else {
3662
+ // TryReadFromCacheUntracked returns false since the offset
3663
+ // requested is less than the start of our buffer
3664
+ ASSERT_FALSE(
3665
+ fpb.TryReadFromCache(IOOptions(), r.get(), 10, 8, &result, &s));
3666
+ }
3667
+ ASSERT_EQ(s, Status::OK());
3668
+
3669
+ ASSERT_TRUE(fpb.TryReadFromCache(IOOptions(), r.get(), 27, 6, &result, &s));
3670
+ ASSERT_EQ(s, Status::OK());
3671
+ ASSERT_EQ(strncmp(result.data(), content.substr(27, 6).c_str(), 6), 0);
3672
+ fpb.TEST_GetOverlapBufferOffsetandSize(overlap_buffer_info);
3673
+ fpb.TEST_GetBufferOffsetandSize(buffer_info);
3674
+ if (use_async_prefetch) {
3675
+ // Complete hit since we have the entire file loaded in the main buffer
3676
+ ASSERT_EQ(overlap_buffer_info.first, 0);
3677
+ ASSERT_EQ(overlap_buffer_info.second, 0);
3678
+ ASSERT_EQ(std::get<0>(buffer_info[0]), 0);
3679
+ ASSERT_EQ(std::get<1>(buffer_info[0]), 1000);
3680
+ } else {
3681
+ // Complete hit
3682
+ // Overlap buffer still not used
3683
+ ASSERT_EQ(overlap_buffer_info.first, 0);
3684
+ ASSERT_EQ(overlap_buffer_info.second, 0);
3685
+ // Main buffer unchanged
3686
+ ASSERT_EQ(std::get<0>(buffer_info[0]), 16);
3687
+ ASSERT_EQ(std::get<1>(buffer_info[0]), 7 + 10);
3688
+ }
3689
+
3690
+ ASSERT_TRUE(fpb.TryReadFromCache(IOOptions(), r.get(), 30, 20, &result, &s));
3691
+ ASSERT_EQ(s, Status::OK());
3692
+ ASSERT_EQ(strncmp(result.data(), content.substr(30, 20).c_str(), 20), 0);
3693
+ fpb.TEST_GetOverlapBufferOffsetandSize(overlap_buffer_info);
3694
+ fpb.TEST_GetBufferOffsetandSize(buffer_info);
3695
+ if (use_async_prefetch) {
3696
+ // Complete hit since we have the entire file loaded in the main buffer
3697
+ ASSERT_EQ(overlap_buffer_info.first, 0);
3698
+ ASSERT_EQ(overlap_buffer_info.second, 0);
3699
+ ASSERT_EQ(std::get<0>(buffer_info[0]), 0);
3700
+ ASSERT_EQ(std::get<1>(buffer_info[0]), 1000);
3701
+ } else {
3702
+ // Partial hit (overlapping with end of main buffer)
3703
+ // Overlap buffer is used because we already had 30-33
3704
+ ASSERT_EQ(overlap_buffer_info.first, 30);
3705
+ ASSERT_EQ(overlap_buffer_info.second, 20);
3706
+ ASSERT_EQ(overlap_buffer_write_ct, 2);
3707
+ // Main buffer has up to offset 50 + 20 of prefetched data
3708
+ ASSERT_EQ(std::get<0>(buffer_info[0]), 33);
3709
+ ASSERT_EQ(std::get<1>(buffer_info[0]), (50 - 33) + 20);
3710
+ }
3711
+ }
3712
+
3713
+ TEST_P(FSBufferPrefetchTest, FSBufferPrefetchForCompaction) {
3714
+ // Quick test to make sure file system buffer reuse is disabled for compaction
3715
+ // reads. Will update once it is re-enabled
3716
+ // Primarily making sure we do not hit unsigned integer overflow issues
3717
+ std::string fname = "fs-buffer-prefetch-for-compaction";
3718
+ Random rand(0);
3719
+ std::string content = rand.RandomString(32768);
3720
+ Write(fname, content);
3721
+
3722
+ FileOptions opts;
3723
+ std::unique_ptr<RandomAccessFileReader> r;
3724
+ Read(fname, opts, &r);
3725
+
3726
+ std::shared_ptr<Statistics> stats = CreateDBStatistics();
3727
+ ReadaheadParams readahead_params;
3728
+ readahead_params.initial_readahead_size = 8192;
3729
+ readahead_params.max_readahead_size = 8192;
3730
+ bool use_async_prefetch = GetParam();
3731
+ // Async IO is not enabled for compaction prefetching
3732
+ if (use_async_prefetch) {
3733
+ return;
3734
+ }
3735
+ readahead_params.num_buffers = 1;
3736
+
3737
+ FilePrefetchBuffer fpb(readahead_params, true, false, fs(), clock(),
3738
+ stats.get());
3739
+
3740
+ Slice result;
3741
+ Status s;
3742
+ ASSERT_TRUE(
3743
+ fpb.TryReadFromCache(IOOptions(), r.get(), 0, 4096, &result, &s, true));
3744
+ ASSERT_EQ(s, Status::OK());
3745
+ ASSERT_EQ(strncmp(result.data(), content.substr(0, 4096).c_str(), 4096), 0);
3746
+
3747
+ fpb.UpdateReadPattern(4096, 4096, false);
3748
+
3749
+ ASSERT_TRUE(fpb.TryReadFromCache(IOOptions(), r.get(), 8192, 8192, &result,
3750
+ &s, true));
3751
+ ASSERT_EQ(s, Status::OK());
3752
+ ASSERT_EQ(strncmp(result.data(), content.substr(8192, 8192).c_str(), 8192),
3753
+ 0);
3754
+
3755
+ ASSERT_TRUE(fpb.TryReadFromCache(IOOptions(), r.get(), 12288, 4096, &result,
3756
+ &s, true));
3757
+ ASSERT_EQ(s, Status::OK());
3758
+ ASSERT_EQ(strncmp(result.data(), content.substr(12288, 4096).c_str(), 4096),
3759
+ 0);
3760
+
3761
+ // Read from 16000-26000 (start and end do not meet normal alignment)
3762
+ ASSERT_TRUE(fpb.TryReadFromCache(IOOptions(), r.get(), 16000, 10000, &result,
3763
+ &s, true));
3764
+ ASSERT_EQ(s, Status::OK());
3765
+ ASSERT_EQ(strncmp(result.data(), content.substr(16000, 10000).c_str(), 10000),
3766
+ 0);
3767
+ }
3768
+
3151
3769
  } // namespace ROCKSDB_NAMESPACE
3152
3770
 
3153
3771
  int main(int argc, char** argv) {