@nxtedition/rocksdb 10.1.5 → 10.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (254) hide show
  1. package/binding.cc +5 -7
  2. package/deps/rocksdb/rocksdb/CMakeLists.txt +16 -5
  3. package/deps/rocksdb/rocksdb/Makefile +38 -15
  4. package/deps/rocksdb/rocksdb/TARGETS +10 -0
  5. package/deps/rocksdb/rocksdb/cache/cache_test.cc +58 -0
  6. package/deps/rocksdb/rocksdb/db/arena_wrapped_db_iter.cc +4 -4
  7. package/deps/rocksdb/rocksdb/db/arena_wrapped_db_iter.h +4 -2
  8. package/deps/rocksdb/rocksdb/db/builder.cc +2 -2
  9. package/deps/rocksdb/rocksdb/db/builder.h +1 -1
  10. package/deps/rocksdb/rocksdb/db/c.cc +205 -6
  11. package/deps/rocksdb/rocksdb/db/c_test.c +189 -1
  12. package/deps/rocksdb/rocksdb/db/column_family.cc +28 -0
  13. package/deps/rocksdb/rocksdb/db/column_family.h +17 -0
  14. package/deps/rocksdb/rocksdb/db/column_family_test.cc +234 -60
  15. package/deps/rocksdb/rocksdb/db/compaction/compaction.cc +8 -1
  16. package/deps/rocksdb/rocksdb/db/compaction/compaction.h +11 -9
  17. package/deps/rocksdb/rocksdb/db/compaction/compaction_iterator.cc +4 -4
  18. package/deps/rocksdb/rocksdb/db/compaction/compaction_iterator.h +2 -0
  19. package/deps/rocksdb/rocksdb/db/compaction/compaction_iterator_test.cc +1 -0
  20. package/deps/rocksdb/rocksdb/db/compaction/compaction_job.cc +22 -25
  21. package/deps/rocksdb/rocksdb/db/compaction/compaction_job.h +2 -0
  22. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_test.cc +112 -0
  23. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_universal.cc +72 -21
  24. package/deps/rocksdb/rocksdb/db/compaction/compaction_service_job.cc +2 -0
  25. package/deps/rocksdb/rocksdb/db/compaction/tiered_compaction_test.cc +77 -0
  26. package/deps/rocksdb/rocksdb/db/convenience.cc +3 -0
  27. package/deps/rocksdb/rocksdb/db/db_block_cache_test.cc +269 -112
  28. package/deps/rocksdb/rocksdb/db/db_bloom_filter_test.cc +107 -43
  29. package/deps/rocksdb/rocksdb/db/db_filesnapshot.cc +93 -24
  30. package/deps/rocksdb/rocksdb/db/db_flush_test.cc +5 -5
  31. package/deps/rocksdb/rocksdb/db/db_impl/db_impl.cc +157 -68
  32. package/deps/rocksdb/rocksdb/db/db_impl/db_impl.h +56 -15
  33. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_compaction_flush.cc +78 -105
  34. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_files.cc +39 -9
  35. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_follower.cc +1 -0
  36. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_open.cc +21 -14
  37. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_write.cc +107 -63
  38. package/deps/rocksdb/rocksdb/db/db_properties_test.cc +43 -2
  39. package/deps/rocksdb/rocksdb/db/db_range_del_test.cc +4 -0
  40. package/deps/rocksdb/rocksdb/db/db_rate_limiter_test.cc +6 -0
  41. package/deps/rocksdb/rocksdb/db/db_test.cc +10 -2
  42. package/deps/rocksdb/rocksdb/db/db_test2.cc +1 -1
  43. package/deps/rocksdb/rocksdb/db/db_test_util.cc +5 -0
  44. package/deps/rocksdb/rocksdb/db/db_test_util.h +7 -6
  45. package/deps/rocksdb/rocksdb/db/db_wal_test.cc +92 -2
  46. package/deps/rocksdb/rocksdb/db/error_handler.cc +34 -39
  47. package/deps/rocksdb/rocksdb/db/error_handler.h +3 -4
  48. package/deps/rocksdb/rocksdb/db/error_handler_fs_test.cc +8 -4
  49. package/deps/rocksdb/rocksdb/db/event_helpers.cc +6 -3
  50. package/deps/rocksdb/rocksdb/db/external_sst_file_ingestion_job.cc +71 -15
  51. package/deps/rocksdb/rocksdb/db/external_sst_file_ingestion_job.h +11 -0
  52. package/deps/rocksdb/rocksdb/db/external_sst_file_test.cc +383 -4
  53. package/deps/rocksdb/rocksdb/db/fault_injection_test.cc +88 -72
  54. package/deps/rocksdb/rocksdb/db/flush_job.cc +30 -3
  55. package/deps/rocksdb/rocksdb/db/flush_job.h +14 -0
  56. package/deps/rocksdb/rocksdb/db/internal_stats.cc +60 -1
  57. package/deps/rocksdb/rocksdb/db/internal_stats.h +20 -1
  58. package/deps/rocksdb/rocksdb/db/log_writer.cc +24 -0
  59. package/deps/rocksdb/rocksdb/db/log_writer.h +5 -0
  60. package/deps/rocksdb/rocksdb/db/memtable.cc +6 -4
  61. package/deps/rocksdb/rocksdb/db/memtable.h +10 -10
  62. package/deps/rocksdb/rocksdb/db/memtable_list.cc +4 -4
  63. package/deps/rocksdb/rocksdb/db/multi_cf_iterator_impl.h +10 -3
  64. package/deps/rocksdb/rocksdb/db/range_tombstone_fragmenter.h +8 -10
  65. package/deps/rocksdb/rocksdb/db/repair.cc +4 -3
  66. package/deps/rocksdb/rocksdb/db/seqno_to_time_mapping.cc +30 -0
  67. package/deps/rocksdb/rocksdb/db/seqno_to_time_mapping.h +9 -0
  68. package/deps/rocksdb/rocksdb/db/table_cache.cc +17 -2
  69. package/deps/rocksdb/rocksdb/db/table_cache.h +9 -1
  70. package/deps/rocksdb/rocksdb/db/table_properties_collector.h +9 -2
  71. package/deps/rocksdb/rocksdb/db/table_properties_collector_test.cc +3 -1
  72. package/deps/rocksdb/rocksdb/db/transaction_log_impl.cc +3 -3
  73. package/deps/rocksdb/rocksdb/db/transaction_log_impl.h +7 -7
  74. package/deps/rocksdb/rocksdb/db/version_edit.cc +0 -1
  75. package/deps/rocksdb/rocksdb/db/version_edit_handler.h +7 -6
  76. package/deps/rocksdb/rocksdb/db/version_set.cc +54 -31
  77. package/deps/rocksdb/rocksdb/db/version_set.h +14 -7
  78. package/deps/rocksdb/rocksdb/db/wal_manager.cc +37 -29
  79. package/deps/rocksdb/rocksdb/db/wal_manager.h +6 -5
  80. package/deps/rocksdb/rocksdb/db/wide/wide_columns_helper.cc +6 -0
  81. package/deps/rocksdb/rocksdb/db/write_batch.cc +54 -23
  82. package/deps/rocksdb/rocksdb/db/write_callback_test.cc +46 -5
  83. package/deps/rocksdb/rocksdb/db/write_thread.cc +53 -5
  84. package/deps/rocksdb/rocksdb/db/write_thread.h +36 -4
  85. package/deps/rocksdb/rocksdb/db_stress_tool/CMakeLists.txt +1 -0
  86. package/deps/rocksdb/rocksdb/db_stress_tool/batched_ops_stress.cc +5 -0
  87. package/deps/rocksdb/rocksdb/db_stress_tool/cf_consistency_stress.cc +57 -17
  88. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_common.cc +11 -3
  89. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_common.h +8 -4
  90. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_driver.cc +10 -25
  91. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_env_wrapper.h +25 -88
  92. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_filters.cc +93 -0
  93. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_filters.h +16 -0
  94. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_gflags.cc +43 -0
  95. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_listener.h +109 -21
  96. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_shared_state.h +8 -0
  97. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_test_base.cc +666 -205
  98. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_test_base.h +55 -10
  99. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_tool.cc +18 -16
  100. package/deps/rocksdb/rocksdb/db_stress_tool/multi_ops_txns_stress.cc +19 -0
  101. package/deps/rocksdb/rocksdb/db_stress_tool/multi_ops_txns_stress.h +5 -0
  102. package/deps/rocksdb/rocksdb/db_stress_tool/no_batched_ops_stress.cc +782 -494
  103. package/deps/rocksdb/rocksdb/env/composite_env_wrapper.h +21 -0
  104. package/deps/rocksdb/rocksdb/env/env.cc +6 -0
  105. package/deps/rocksdb/rocksdb/env/io_posix.cc +0 -1
  106. package/deps/rocksdb/rocksdb/file/file_util.cc +8 -2
  107. package/deps/rocksdb/rocksdb/file/prefetch_test.cc +34 -19
  108. package/deps/rocksdb/rocksdb/file/writable_file_writer.cc +29 -32
  109. package/deps/rocksdb/rocksdb/file/writable_file_writer.h +41 -15
  110. package/deps/rocksdb/rocksdb/include/rocksdb/advanced_options.h +4 -2
  111. package/deps/rocksdb/rocksdb/include/rocksdb/c.h +63 -0
  112. package/deps/rocksdb/rocksdb/include/rocksdb/db.h +16 -5
  113. package/deps/rocksdb/rocksdb/include/rocksdb/env.h +5 -0
  114. package/deps/rocksdb/rocksdb/include/rocksdb/iterator.h +0 -16
  115. package/deps/rocksdb/rocksdb/include/rocksdb/iterator_base.h +16 -0
  116. package/deps/rocksdb/rocksdb/include/rocksdb/listener.h +21 -0
  117. package/deps/rocksdb/rocksdb/include/rocksdb/options.h +76 -3
  118. package/deps/rocksdb/rocksdb/include/rocksdb/table_properties.h +17 -0
  119. package/deps/rocksdb/rocksdb/include/rocksdb/transaction_log.h +12 -6
  120. package/deps/rocksdb/rocksdb/include/rocksdb/universal_compaction.h +31 -0
  121. package/deps/rocksdb/rocksdb/include/rocksdb/user_write_callback.h +29 -0
  122. package/deps/rocksdb/rocksdb/include/rocksdb/utilities/checkpoint.h +4 -2
  123. package/deps/rocksdb/rocksdb/include/rocksdb/utilities/customizable_util.h +0 -1
  124. package/deps/rocksdb/rocksdb/include/rocksdb/utilities/ldb_cmd.h +17 -8
  125. package/deps/rocksdb/rocksdb/include/rocksdb/utilities/stackable_db.h +2 -2
  126. package/deps/rocksdb/rocksdb/include/rocksdb/utilities/table_properties_collectors.h +46 -0
  127. package/deps/rocksdb/rocksdb/include/rocksdb/utilities/transaction.h +7 -0
  128. package/deps/rocksdb/rocksdb/include/rocksdb/version.h +2 -2
  129. package/deps/rocksdb/rocksdb/options/cf_options.cc +13 -2
  130. package/deps/rocksdb/rocksdb/options/cf_options.h +6 -2
  131. package/deps/rocksdb/rocksdb/options/db_options.cc +8 -0
  132. package/deps/rocksdb/rocksdb/options/db_options.h +9 -5
  133. package/deps/rocksdb/rocksdb/options/options.cc +3 -0
  134. package/deps/rocksdb/rocksdb/options/options_helper.cc +1 -0
  135. package/deps/rocksdb/rocksdb/options/options_settable_test.cc +3 -1
  136. package/deps/rocksdb/rocksdb/port/jemalloc_helper.h +2 -2
  137. package/deps/rocksdb/rocksdb/port/stack_trace.cc +1 -0
  138. package/deps/rocksdb/rocksdb/port/win/port_win.cc +3 -2
  139. package/deps/rocksdb/rocksdb/src.mk +4 -0
  140. package/deps/rocksdb/rocksdb/table/block_based/binary_search_index_reader.cc +1 -2
  141. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_builder.cc +4 -2
  142. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_iterator.cc +15 -0
  143. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader.cc +102 -41
  144. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader.h +15 -7
  145. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader_impl.h +1 -3
  146. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader_sync_and_async.h +5 -6
  147. package/deps/rocksdb/rocksdb/table/block_based/block_cache.h +31 -0
  148. package/deps/rocksdb/rocksdb/table/block_based/block_prefetcher.cc +6 -0
  149. package/deps/rocksdb/rocksdb/table/block_based/cachable_entry.h +10 -5
  150. package/deps/rocksdb/rocksdb/table/block_based/filter_block.h +11 -15
  151. package/deps/rocksdb/rocksdb/table/block_based/filter_block_reader_common.cc +17 -11
  152. package/deps/rocksdb/rocksdb/table/block_based/filter_block_reader_common.h +5 -2
  153. package/deps/rocksdb/rocksdb/table/block_based/full_filter_block.cc +28 -21
  154. package/deps/rocksdb/rocksdb/table/block_based/full_filter_block.h +9 -11
  155. package/deps/rocksdb/rocksdb/table/block_based/full_filter_block_test.cc +16 -16
  156. package/deps/rocksdb/rocksdb/table/block_based/hash_index_reader.cc +1 -2
  157. package/deps/rocksdb/rocksdb/table/block_based/index_reader_common.cc +14 -9
  158. package/deps/rocksdb/rocksdb/table/block_based/index_reader_common.h +4 -1
  159. package/deps/rocksdb/rocksdb/table/block_based/partitioned_filter_block.cc +82 -41
  160. package/deps/rocksdb/rocksdb/table/block_based/partitioned_filter_block.h +13 -14
  161. package/deps/rocksdb/rocksdb/table/block_based/partitioned_filter_block_test.cc +18 -22
  162. package/deps/rocksdb/rocksdb/table/block_based/partitioned_index_reader.cc +51 -13
  163. package/deps/rocksdb/rocksdb/table/block_based/partitioned_index_reader.h +2 -0
  164. package/deps/rocksdb/rocksdb/table/block_based/uncompression_dict_reader.cc +3 -11
  165. package/deps/rocksdb/rocksdb/table/block_based/uncompression_dict_reader.h +2 -3
  166. package/deps/rocksdb/rocksdb/table/compaction_merging_iterator.cc +9 -10
  167. package/deps/rocksdb/rocksdb/table/compaction_merging_iterator.h +3 -2
  168. package/deps/rocksdb/rocksdb/table/format.cc +1 -2
  169. package/deps/rocksdb/rocksdb/table/merging_iterator.cc +18 -13
  170. package/deps/rocksdb/rocksdb/table/merging_iterator.h +5 -3
  171. package/deps/rocksdb/rocksdb/table/plain/plain_table_builder.cc +2 -2
  172. package/deps/rocksdb/rocksdb/table/sst_file_reader.cc +1 -1
  173. package/deps/rocksdb/rocksdb/table/sst_file_writer_collectors.h +3 -1
  174. package/deps/rocksdb/rocksdb/table/table_builder.h +8 -7
  175. package/deps/rocksdb/rocksdb/table/table_reader.h +9 -0
  176. package/deps/rocksdb/rocksdb/test_util/testutil.cc +1 -0
  177. package/deps/rocksdb/rocksdb/test_util/testutil.h +6 -0
  178. package/deps/rocksdb/rocksdb/tools/db_bench_tool.cc +19 -0
  179. package/deps/rocksdb/rocksdb/tools/ldb_cmd.cc +434 -110
  180. package/deps/rocksdb/rocksdb/tools/ldb_cmd_impl.h +3 -1
  181. package/deps/rocksdb/rocksdb/tools/ldb_tool.cc +3 -0
  182. package/deps/rocksdb/rocksdb/util/aligned_storage.h +24 -0
  183. package/deps/rocksdb/rocksdb/util/filter_bench.cc +1 -1
  184. package/deps/rocksdb/rocksdb/util/random.cc +2 -1
  185. package/deps/rocksdb/rocksdb/util/stderr_logger.h +1 -1
  186. package/deps/rocksdb/rocksdb/util/udt_util.cc +33 -0
  187. package/deps/rocksdb/rocksdb/util/udt_util.h +7 -0
  188. package/deps/rocksdb/rocksdb/util/udt_util_test.cc +33 -0
  189. package/deps/rocksdb/rocksdb/util/write_batch_util.h +5 -0
  190. package/deps/rocksdb/rocksdb/util/xxhash.h +10 -3
  191. package/deps/rocksdb/rocksdb/utilities/backup/backup_engine_test.cc +13 -13
  192. package/deps/rocksdb/rocksdb/utilities/checkpoint/checkpoint_test.cc +104 -48
  193. package/deps/rocksdb/rocksdb/utilities/debug.cc +16 -4
  194. package/deps/rocksdb/rocksdb/utilities/fault_injection_fs.cc +647 -235
  195. package/deps/rocksdb/rocksdb/utilities/fault_injection_fs.h +274 -157
  196. package/deps/rocksdb/rocksdb/utilities/table_properties_collectors/compact_for_tiering_collector.cc +144 -0
  197. package/deps/rocksdb/rocksdb/utilities/table_properties_collectors/compact_for_tiering_collector.h +45 -0
  198. package/deps/rocksdb/rocksdb/utilities/table_properties_collectors/compact_for_tiering_collector_test.cc +139 -0
  199. package/deps/rocksdb/rocksdb/utilities/table_properties_collectors/compact_on_deletion_collector.cc +12 -0
  200. package/deps/rocksdb/rocksdb/utilities/table_properties_collectors/compact_on_deletion_collector_test.cc +3 -0
  201. package/deps/rocksdb/rocksdb/utilities/transactions/optimistic_transaction_test.cc +105 -6
  202. package/deps/rocksdb/rocksdb/utilities/transactions/pessimistic_transaction.cc +64 -8
  203. package/deps/rocksdb/rocksdb/utilities/transactions/pessimistic_transaction.h +5 -0
  204. package/deps/rocksdb/rocksdb/utilities/transactions/transaction_base.cc +43 -5
  205. package/deps/rocksdb/rocksdb/utilities/transactions/transaction_base.h +5 -0
  206. package/deps/rocksdb/rocksdb/utilities/transactions/transaction_test.cc +154 -6
  207. package/deps/rocksdb/rocksdb/utilities/transactions/transaction_test.h +1 -1
  208. package/deps/rocksdb/rocksdb/utilities/transactions/write_committed_transaction_ts_test.cc +158 -2
  209. package/deps/rocksdb/rocksdb/utilities/transactions/write_prepared_txn.cc +16 -11
  210. package/deps/rocksdb/rocksdb/utilities/transactions/write_prepared_txn_db.cc +4 -4
  211. package/deps/rocksdb/rocksdb/utilities/transactions/write_unprepared_txn.cc +9 -8
  212. package/deps/rocksdb/rocksdb/utilities/transactions/write_unprepared_txn_db.cc +2 -1
  213. package/deps/rocksdb/rocksdb/utilities/write_batch_with_index/write_batch_with_index.cc +43 -7
  214. package/deps/rocksdb/rocksdb/utilities/write_batch_with_index/write_batch_with_index_internal.cc +2 -0
  215. package/deps/rocksdb/rocksdb/utilities/write_batch_with_index/write_batch_with_index_internal.h +1 -1
  216. package/package.json +1 -1
  217. package/prebuilds/darwin-arm64/@nxtedition+rocksdb.node +0 -0
  218. package/.tap/test-results/node_modules/abstract-level/test/chained-batch-test.js.tap +0 -0
  219. package/.tap/test-results/node_modules/abstract-level/test/get-test.js.tap +0 -0
  220. package/.tap/test-results/test/abstract-level-test.js.tap +0 -1077
  221. package/.tap/test-results/test/batch-test.js.tap +0 -12
  222. package/.tap/test-results/test/chained-batch-gc-test.js.tap +0 -11
  223. package/.tap/test-results/test/cleanup-hanging-iterators-test.js.tap +0 -135
  224. package/.tap/test-results/test/clear-gc-test.js.tap +0 -13
  225. package/.tap/test-results/test/column-test.js.tap +0 -55
  226. package/.tap/test-results/test/common.js.tap +0 -0
  227. package/.tap/test-results/test/compression-test.js.tap +0 -30
  228. package/.tap/test-results/test/db-identity.js.tap +0 -12
  229. package/.tap/test-results/test/electron.js.tap +0 -0
  230. package/.tap/test-results/test/env-cleanup-hook-test.js.tap +0 -40
  231. package/.tap/test-results/test/env-cleanup-hook.js.tap +0 -0
  232. package/.tap/test-results/test/gc.js.tap +0 -0
  233. package/.tap/test-results/test/getproperty-test.js.tap +0 -29
  234. package/.tap/test-results/test/iterator-gc-test.js.tap +0 -15
  235. package/.tap/test-results/test/iterator-hwm-test.js.tap +0 -131
  236. package/.tap/test-results/test/iterator-recursion-test.js.tap +0 -12
  237. package/.tap/test-results/test/iterator-starvation-test.js.tap +0 -73
  238. package/.tap/test-results/test/iterator-test.js.tap +0 -6
  239. package/.tap/test-results/test/leak-tester-batch.js.tap +0 -0
  240. package/.tap/test-results/test/leak-tester-iterator.js.tap +0 -0
  241. package/.tap/test-results/test/leak-tester.js.tap +0 -0
  242. package/.tap/test-results/test/lock-test.js.tap +0 -18
  243. package/.tap/test-results/test/lock.js.tap +0 -0
  244. package/.tap/test-results/test/make.js.tap +0 -0
  245. package/.tap/test-results/test/max-rev-merge.js.tap +0 -0
  246. package/.tap/test-results/test/merge-operator-test.js.tap +0 -12
  247. package/.tap/test-results/test/mkdir-test.js.tap +0 -15
  248. package/.tap/test-results/test/segfault-test.js.tap +0 -76
  249. package/.tap/test-results/test/stack-blower.js.tap +0 -0
  250. package/deps/rocksdb/rocksdb/README.md +0 -29
  251. package/deps/rocksdb/rocksdb/microbench/README.md +0 -60
  252. package/deps/rocksdb/rocksdb/plugin/README.md +0 -43
  253. package/deps/rocksdb/rocksdb/port/README +0 -10
  254. package/deps/rocksdb/rocksdb/utilities/transactions/lock/range/range_tree/lib/README +0 -13
@@ -17,12 +17,16 @@
17
17
  #include "utilities/fault_injection_fs.h"
18
18
 
19
19
  #include <algorithm>
20
+ #include <cstdio>
20
21
  #include <functional>
21
22
  #include <utility>
22
23
 
23
24
  #include "env/composite_env_wrapper.h"
24
25
  #include "port/lang.h"
25
26
  #include "port/stack_trace.h"
27
+ #include "rocksdb/env.h"
28
+ #include "rocksdb/io_status.h"
29
+ #include "rocksdb/types.h"
26
30
  #include "test_util/sync_point.h"
27
31
  #include "util/coding.h"
28
32
  #include "util/crc32c.h"
@@ -92,20 +96,15 @@ IOStatus TestFSDirectory::Fsync(const IOOptions& options, IODebugContext* dbg) {
92
96
  if (!fs_->IsFilesystemActive()) {
93
97
  return fs_->GetError();
94
98
  }
95
- {
96
- IOStatus in_s = fs_->InjectMetadataWriteError();
97
- if (!in_s.ok()) {
98
- return in_s;
99
- }
99
+
100
+ IOStatus s = fs_->MaybeInjectThreadLocalError(
101
+ FaultInjectionIOType::kMetadataWrite, options);
102
+ if (!s.ok()) {
103
+ return s;
100
104
  }
105
+
101
106
  fs_->SyncDir(dirname_);
102
- IOStatus s = dir_->Fsync(options, dbg);
103
- {
104
- IOStatus in_s = fs_->InjectMetadataWriteError();
105
- if (!in_s.ok()) {
106
- return in_s;
107
- }
108
- }
107
+ s = dir_->Fsync(options, dbg);
109
108
  return s;
110
109
  }
111
110
 
@@ -113,7 +112,14 @@ IOStatus TestFSDirectory::Close(const IOOptions& options, IODebugContext* dbg) {
113
112
  if (!fs_->IsFilesystemActive()) {
114
113
  return fs_->GetError();
115
114
  }
116
- IOStatus s = dir_->Close(options, dbg);
115
+
116
+ IOStatus s = fs_->MaybeInjectThreadLocalError(
117
+ FaultInjectionIOType::kMetadataWrite, options);
118
+ if (!s.ok()) {
119
+ return s;
120
+ }
121
+
122
+ s = dir_->Close(options, dbg);
117
123
  return s;
118
124
  }
119
125
 
@@ -123,20 +129,14 @@ IOStatus TestFSDirectory::FsyncWithDirOptions(
123
129
  if (!fs_->IsFilesystemActive()) {
124
130
  return fs_->GetError();
125
131
  }
126
- {
127
- IOStatus in_s = fs_->InjectMetadataWriteError();
128
- if (!in_s.ok()) {
129
- return in_s;
130
- }
132
+ IOStatus s = fs_->MaybeInjectThreadLocalError(
133
+ FaultInjectionIOType::kMetadataWrite, options);
134
+ if (!s.ok()) {
135
+ return s;
131
136
  }
137
+
132
138
  fs_->SyncDir(dirname_);
133
- IOStatus s = dir_->FsyncWithDirOptions(options, dbg, dir_fsync_options);
134
- {
135
- IOStatus in_s = fs_->InjectMetadataWriteError();
136
- if (!in_s.ok()) {
137
- return in_s;
138
- }
139
- }
139
+ s = dir_->FsyncWithDirOptions(options, dbg, dir_fsync_options);
140
140
  return s;
141
141
  }
142
142
 
@@ -148,9 +148,11 @@ TestFSWritableFile::TestFSWritableFile(const std::string& fname,
148
148
  file_opts_(file_opts),
149
149
  target_(std::move(f)),
150
150
  writable_file_opened_(true),
151
- fs_(fs) {
151
+ fs_(fs),
152
+ unsync_data_loss_(fs_->InjectUnsyncedDataLoss()) {
152
153
  assert(target_ != nullptr);
153
- state_.pos_ = 0;
154
+ assert(state_.pos_at_last_append_ == 0);
155
+ assert(state_.pos_at_last_sync_ == 0);
154
156
  }
155
157
 
156
158
  TestFSWritableFile::~TestFSWritableFile() {
@@ -165,15 +167,27 @@ IOStatus TestFSWritableFile::Append(const Slice& data, const IOOptions& options,
165
167
  if (!fs_->IsFilesystemActive()) {
166
168
  return fs_->GetError();
167
169
  }
168
- if (target_->use_direct_io()) {
169
- target_->Append(data, options, dbg).PermitUncheckedError();
170
+
171
+ IOStatus s = fs_->MaybeInjectThreadLocalError(FaultInjectionIOType::kWrite,
172
+ options, state_.filename_);
173
+ if (!s.ok()) {
174
+ return s;
175
+ }
176
+
177
+ if (target_->use_direct_io() || !unsync_data_loss_) {
178
+ // TODO(hx235): buffer data for direct IO write to simulate data loss like
179
+ // non-direct IO write
180
+ s = target_->Append(data, options, dbg);
170
181
  } else {
171
182
  state_.buffer_.append(data.data(), data.size());
172
- state_.pos_ += data.size();
183
+ }
184
+
185
+ if (s.ok()) {
186
+ state_.pos_at_last_append_ += data.size();
173
187
  fs_->WritableFileAppended(state_);
174
188
  }
175
- IOStatus io_s = fs_->InjectWriteError(state_.filename_);
176
- return io_s;
189
+
190
+ return s;
177
191
  }
178
192
 
179
193
  // By setting the IngestDataCorruptionBeforeWrite(), the data corruption is
@@ -189,6 +203,12 @@ IOStatus TestFSWritableFile::Append(
189
203
  return IOStatus::Corruption("Data is corrupted!");
190
204
  }
191
205
 
206
+ IOStatus s = fs_->MaybeInjectThreadLocalError(FaultInjectionIOType::kWrite,
207
+ options, state_.filename_);
208
+ if (!s.ok()) {
209
+ return s;
210
+ }
211
+
192
212
  // Calculate the checksum
193
213
  std::string checksum;
194
214
  CalculateTypedChecksum(fs_->GetChecksumHandoffFuncType(), data.data(),
@@ -201,15 +221,65 @@ IOStatus TestFSWritableFile::Append(
201
221
  "current data checksum: " + Slice(checksum).ToString(true);
202
222
  return IOStatus::Corruption(msg);
203
223
  }
204
- if (target_->use_direct_io()) {
205
- target_->Append(data, options, dbg).PermitUncheckedError();
224
+
225
+ if (target_->use_direct_io() || !unsync_data_loss_) {
226
+ // TODO(hx235): buffer data for direct IO write to simulate data loss like
227
+ // non-direct IO write
228
+ s = target_->Append(data, options, dbg);
206
229
  } else {
207
230
  state_.buffer_.append(data.data(), data.size());
208
- state_.pos_ += data.size();
231
+ }
232
+ if (s.ok()) {
233
+ state_.pos_at_last_append_ += data.size();
209
234
  fs_->WritableFileAppended(state_);
210
235
  }
211
- IOStatus io_s = fs_->InjectWriteError(state_.filename_);
212
- return io_s;
236
+ return s;
237
+ }
238
+
239
+ IOStatus TestFSWritableFile::Truncate(uint64_t size, const IOOptions& options,
240
+ IODebugContext* dbg) {
241
+ MutexLock l(&mutex_);
242
+ if (!fs_->IsFilesystemActive()) {
243
+ return fs_->GetError();
244
+ }
245
+ IOStatus s = fs_->MaybeInjectThreadLocalError(FaultInjectionIOType::kWrite,
246
+ options, state_.filename_);
247
+ if (!s.ok()) {
248
+ return s;
249
+ }
250
+
251
+ s = target_->Truncate(size, options, dbg);
252
+ if (s.ok()) {
253
+ state_.pos_at_last_append_ = size;
254
+ }
255
+ return s;
256
+ }
257
+
258
+ IOStatus TestFSWritableFile::PositionedAppend(const Slice& data,
259
+ uint64_t offset,
260
+ const IOOptions& options,
261
+ IODebugContext* dbg) {
262
+ MutexLock l(&mutex_);
263
+ if (!fs_->IsFilesystemActive()) {
264
+ return fs_->GetError();
265
+ }
266
+ if (fs_->ShouldDataCorruptionBeforeWrite()) {
267
+ return IOStatus::Corruption("Data is corrupted!");
268
+ }
269
+ IOStatus s = fs_->MaybeInjectThreadLocalError(FaultInjectionIOType::kWrite,
270
+ options, state_.filename_);
271
+ if (!s.ok()) {
272
+ return s;
273
+ }
274
+
275
+ // TODO(hx235): buffer data for direct IO write to simulate data loss like
276
+ // non-direct IO write
277
+ s = target_->PositionedAppend(data, offset, options, dbg);
278
+ if (s.ok()) {
279
+ state_.pos_at_last_append_ = offset + data.size();
280
+ fs_->WritableFileAppended(state_);
281
+ }
282
+ return s;
213
283
  }
214
284
 
215
285
  IOStatus TestFSWritableFile::PositionedAppend(
@@ -222,6 +292,11 @@ IOStatus TestFSWritableFile::PositionedAppend(
222
292
  if (fs_->ShouldDataCorruptionBeforeWrite()) {
223
293
  return IOStatus::Corruption("Data is corrupted!");
224
294
  }
295
+ IOStatus s = fs_->MaybeInjectThreadLocalError(FaultInjectionIOType::kWrite,
296
+ options, state_.filename_);
297
+ if (!s.ok()) {
298
+ return s;
299
+ }
225
300
 
226
301
  // Calculate the checksum
227
302
  std::string checksum;
@@ -235,9 +310,14 @@ IOStatus TestFSWritableFile::PositionedAppend(
235
310
  "current data checksum: " + Slice(checksum).ToString(true);
236
311
  return IOStatus::Corruption(msg);
237
312
  }
238
- target_->PositionedAppend(data, offset, options, dbg);
239
- IOStatus io_s = fs_->InjectWriteError(state_.filename_);
240
- return io_s;
313
+ // TODO(hx235): buffer data for direct IO write to simulate data loss like
314
+ // non-direct IO write
315
+ s = target_->PositionedAppend(data, offset, options, dbg);
316
+ if (s.ok()) {
317
+ state_.pos_at_last_append_ = offset + data.size();
318
+ fs_->WritableFileAppended(state_);
319
+ }
320
+ return s;
241
321
  }
242
322
 
243
323
  IOStatus TestFSWritableFile::Close(const IOOptions& options,
@@ -247,24 +327,17 @@ IOStatus TestFSWritableFile::Close(const IOOptions& options,
247
327
  if (!fs_->IsFilesystemActive()) {
248
328
  return fs_->GetError();
249
329
  }
250
- {
251
- IOStatus in_s = fs_->InjectMetadataWriteError();
252
- if (!in_s.ok()) {
253
- return in_s;
254
- }
330
+ IOStatus io_s = fs_->MaybeInjectThreadLocalError(
331
+ FaultInjectionIOType::kMetadataWrite, options);
332
+ if (!io_s.ok()) {
333
+ return io_s;
255
334
  }
256
335
  writable_file_opened_ = false;
257
- IOStatus io_s;
336
+
258
337
  // Drop buffered data that was never synced because close is not a syncing
259
338
  // mechanism in POSIX file semantics.
260
339
  state_.buffer_.resize(0);
261
340
  io_s = target_->Close(options, dbg);
262
- if (io_s.ok()) {
263
- IOStatus in_s = fs_->InjectMetadataWriteError();
264
- if (!in_s.ok()) {
265
- return in_s;
266
- }
267
- }
268
341
  return io_s;
269
342
  }
270
343
 
@@ -273,9 +346,6 @@ IOStatus TestFSWritableFile::Flush(const IOOptions&, IODebugContext*) {
273
346
  if (!fs_->IsFilesystemActive()) {
274
347
  return fs_->GetError();
275
348
  }
276
- if (fs_->IsFilesystemActive()) {
277
- state_.pos_at_last_flush_ = state_.pos_;
278
- }
279
349
  return IOStatus::OK();
280
350
  }
281
351
 
@@ -294,7 +364,7 @@ IOStatus TestFSWritableFile::Sync(const IOOptions& options,
294
364
  state_.buffer_.resize(0);
295
365
  // Ignore sync errors
296
366
  target_->Sync(options, dbg).PermitUncheckedError();
297
- state_.pos_at_last_sync_ = state_.pos_;
367
+ state_.pos_at_last_sync_ = state_.pos_at_last_append_;
298
368
  fs_->WritableFileSynced(state_);
299
369
  return io_s;
300
370
  }
@@ -308,15 +378,13 @@ IOStatus TestFSWritableFile::RangeSync(uint64_t offset, uint64_t nbytes,
308
378
  }
309
379
  // Assumes caller passes consecutive byte ranges.
310
380
  uint64_t sync_limit = offset + nbytes;
311
- uint64_t buf_begin =
312
- state_.pos_at_last_sync_ < 0 ? 0 : state_.pos_at_last_sync_;
313
381
 
314
382
  IOStatus io_s;
315
- if (sync_limit < buf_begin) {
383
+ if (sync_limit < state_.pos_at_last_sync_) {
316
384
  return io_s;
317
385
  }
318
386
  uint64_t num_to_sync = std::min(static_cast<uint64_t>(state_.buffer_.size()),
319
- sync_limit - buf_begin);
387
+ sync_limit - state_.pos_at_last_sync_);
320
388
  Slice buf_to_sync(state_.buffer_.data(), num_to_sync);
321
389
  io_s = target_->Append(buf_to_sync, options, dbg);
322
390
  state_.buffer_ = state_.buffer_.substr(num_to_sync);
@@ -355,6 +423,7 @@ IOStatus TestFSRandomRWFile::Read(uint64_t offset, size_t n,
355
423
  if (!fs_->IsFilesystemActive()) {
356
424
  return fs_->GetError();
357
425
  }
426
+ // TODO (low priority): fs_->ReadUnsyncedData()
358
427
  return target_->Read(offset, n, options, result, scratch, dbg);
359
428
  }
360
429
 
@@ -398,15 +467,17 @@ IOStatus TestFSRandomAccessFile::Read(uint64_t offset, size_t n,
398
467
  if (!fs_->IsFilesystemActive()) {
399
468
  return fs_->GetError();
400
469
  }
401
- IOStatus s = target_->Read(offset, n, options, result, scratch, dbg);
402
- if (s.ok()) {
403
- s = fs_->InjectThreadSpecificReadError(
404
- FaultInjectionTestFS::ErrorOperation::kRead, result, use_direct_io(),
405
- scratch, /*need_count_increase=*/true, /*fault_injected=*/nullptr);
406
- }
407
- if (s.ok() && fs_->ShouldInjectRandomReadError()) {
408
- return IOStatus::IOError("injected read error");
470
+ IOStatus s = fs_->MaybeInjectThreadLocalError(
471
+ FaultInjectionIOType::kRead, options, "",
472
+ FaultInjectionTestFS::ErrorOperation::kRead, result, use_direct_io(),
473
+ scratch, /*need_count_increase=*/true,
474
+ /*fault_injected=*/nullptr);
475
+ if (!s.ok()) {
476
+ return s;
409
477
  }
478
+
479
+ s = target_->Read(offset, n, options, result, scratch, dbg);
480
+ // TODO (low priority): fs_->ReadUnsyncedData()
410
481
  return s;
411
482
  }
412
483
 
@@ -414,28 +485,35 @@ IOStatus TestFSRandomAccessFile::ReadAsync(
414
485
  FSReadRequest& req, const IOOptions& opts,
415
486
  std::function<void(FSReadRequest&, void*)> cb, void* cb_arg,
416
487
  void** io_handle, IOHandleDeleter* del_fn, IODebugContext* /*dbg*/) {
417
- IOStatus ret;
418
- IOStatus s;
488
+ IOStatus res_status;
419
489
  FSReadRequest res;
490
+ IOStatus s;
420
491
  if (!fs_->IsFilesystemActive()) {
421
- ret = fs_->GetError();
422
- } else {
423
- ret = fs_->InjectThreadSpecificReadError(
492
+ res_status = fs_->GetError();
493
+ }
494
+ if (res_status.ok()) {
495
+ res_status = fs_->MaybeInjectThreadLocalError(
496
+ FaultInjectionIOType::kRead, opts, "",
424
497
  FaultInjectionTestFS::ErrorOperation::kRead, &res.result,
425
498
  use_direct_io(), req.scratch, /*need_count_increase=*/true,
426
499
  /*fault_injected=*/nullptr);
427
500
  }
428
- if (ret.ok()) {
429
- if (fs_->ShouldInjectRandomReadError()) {
430
- ret = IOStatus::IOError("injected read error");
431
- } else {
432
- s = target_->ReadAsync(req, opts, cb, cb_arg, io_handle, del_fn, nullptr);
433
- }
434
- }
435
- if (!ret.ok()) {
436
- res.status = ret;
501
+ if (res_status.ok()) {
502
+ s = target_->ReadAsync(req, opts, cb, cb_arg, io_handle, del_fn, nullptr);
503
+ // TODO (low priority): fs_->ReadUnsyncedData()
504
+ } else {
505
+ // If there’s no injected error, then cb will be called asynchronously when
506
+ // target_ actually finishes the read. But if there’s an injected error, it
507
+ // needs to immediately call cb(res, cb_arg) s since target_->ReadAsync()
508
+ // isn’t invoked at all.
509
+ res.status = res_status;
437
510
  cb(res, cb_arg);
438
511
  }
512
+ // We return ReadAsync()'s status intead of injected error status here since
513
+ // the return status is not supposed to be the status of the actual IO (i.e,
514
+ // the actual async read). The actual status of the IO will be passed to cb()
515
+ // callback upon the actual read finishes or like above when injected error
516
+ // happens.
439
517
  return s;
440
518
  }
441
519
 
@@ -446,6 +524,7 @@ IOStatus TestFSRandomAccessFile::MultiRead(FSReadRequest* reqs, size_t num_reqs,
446
524
  return fs_->GetError();
447
525
  }
448
526
  IOStatus s = target_->MultiRead(reqs, num_reqs, options, dbg);
527
+ // TODO (low priority): fs_->ReadUnsyncedData()
449
528
  bool injected_error = false;
450
529
  for (size_t i = 0; i < num_reqs; i++) {
451
530
  if (!reqs[i].status.ok()) {
@@ -453,7 +532,8 @@ IOStatus TestFSRandomAccessFile::MultiRead(FSReadRequest* reqs, size_t num_reqs,
453
532
  break;
454
533
  }
455
534
  bool this_injected_error;
456
- reqs[i].status = fs_->InjectThreadSpecificReadError(
535
+ reqs[i].status = fs_->MaybeInjectThreadLocalError(
536
+ FaultInjectionIOType::kRead, options, "",
457
537
  FaultInjectionTestFS::ErrorOperation::kRead, &(reqs[i].result),
458
538
  use_direct_io(), reqs[i].scratch,
459
539
  /*need_count_increase=*/true,
@@ -461,14 +541,12 @@ IOStatus TestFSRandomAccessFile::MultiRead(FSReadRequest* reqs, size_t num_reqs,
461
541
  injected_error |= this_injected_error;
462
542
  }
463
543
  if (s.ok()) {
464
- s = fs_->InjectThreadSpecificReadError(
544
+ s = fs_->MaybeInjectThreadLocalError(
545
+ FaultInjectionIOType::kRead, options, "",
465
546
  FaultInjectionTestFS::ErrorOperation::kMultiRead, nullptr,
466
547
  use_direct_io(), nullptr, /*need_count_increase=*/!injected_error,
467
548
  /*fault_injected=*/nullptr);
468
549
  }
469
- if (s.ok() && fs_->ShouldInjectRandomReadError()) {
470
- return IOStatus::IOError("injected read error");
471
- }
472
550
  return s;
473
551
  }
474
552
 
@@ -479,13 +557,196 @@ size_t TestFSRandomAccessFile::GetUniqueId(char* id, size_t max_size) const {
479
557
  return target_->GetUniqueId(id, max_size);
480
558
  }
481
559
  }
560
+
561
+ namespace {
562
+ // Modifies `result` to start at the beginning of `scratch` if not already,
563
+ // copying data there if needed.
564
+ void MoveToScratchIfNeeded(Slice* result, char* scratch) {
565
+ if (result->data() != scratch) {
566
+ // NOTE: might overlap, where result is later in scratch
567
+ std::copy(result->data(), result->data() + result->size(), scratch);
568
+ *result = Slice(scratch, result->size());
569
+ }
570
+ }
571
+ } // namespace
572
+
573
+ void FaultInjectionTestFS::ReadUnsynced(const std::string& fname,
574
+ uint64_t offset, size_t n,
575
+ Slice* result, char* scratch,
576
+ int64_t* pos_at_last_sync) {
577
+ *result = Slice(scratch, 0); // default empty result
578
+ assert(*pos_at_last_sync == -1); // default "unknown"
579
+
580
+ MutexLock l(&mutex_);
581
+ auto it = db_file_state_.find(fname);
582
+ if (it != db_file_state_.end()) {
583
+ auto& st = it->second;
584
+ *pos_at_last_sync = static_cast<int64_t>(st.pos_at_last_sync_);
585
+ // Find overlap between [offset, offset + n) and
586
+ // [*pos_at_last_sync, *pos_at_last_sync + st.buffer_.size())
587
+ int64_t begin = std::max(static_cast<int64_t>(offset), *pos_at_last_sync);
588
+ int64_t end =
589
+ std::min(static_cast<int64_t>(offset + n),
590
+ *pos_at_last_sync + static_cast<int64_t>(st.buffer_.size()));
591
+
592
+ // Copy and return overlap if there is any
593
+ if (begin < end) {
594
+ size_t offset_in_buffer = static_cast<size_t>(begin - *pos_at_last_sync);
595
+ size_t offset_in_scratch = static_cast<size_t>(begin - offset);
596
+ std::copy_n(st.buffer_.data() + offset_in_buffer, end - begin,
597
+ scratch + offset_in_scratch);
598
+ *result = Slice(scratch + offset_in_scratch, end - begin);
599
+ }
600
+ }
601
+ }
602
+
482
603
  IOStatus TestFSSequentialFile::Read(size_t n, const IOOptions& options,
483
604
  Slice* result, char* scratch,
484
605
  IODebugContext* dbg) {
485
- IOStatus s = target()->Read(n, options, result, scratch, dbg);
486
- if (s.ok() && fs_->ShouldInjectRandomReadError()) {
487
- return IOStatus::IOError("injected seq read error");
606
+ IOStatus s = fs_->MaybeInjectThreadLocalError(
607
+ FaultInjectionIOType::kRead, options, "",
608
+ FaultInjectionTestFS::ErrorOperation::kRead, result, use_direct_io(),
609
+ scratch, true /*need_count_increase=*/, nullptr /* fault_injected*/);
610
+ if (!s.ok()) {
611
+ return s;
612
+ }
613
+
614
+ // Some complex logic is needed to deal with concurrent write to the same
615
+ // file, while keeping good performance (e.g. not holding FS mutex during
616
+ // I/O op), especially in common cases.
617
+
618
+ if (read_pos_ == target_read_pos_) {
619
+ // Normal case: start by reading from underlying file
620
+ s = target()->Read(n, options, result, scratch, dbg);
621
+ if (!s.ok()) {
622
+ return s;
623
+ }
624
+ target_read_pos_ += result->size();
625
+ } else {
626
+ // We must have previously read buffered data (unsynced) not written to
627
+ // target. Deal with this case (and more) below.
628
+ *result = {};
629
+ }
630
+
631
+ if (fs_->ReadUnsyncedData() && result->size() < n) {
632
+ // We need to check if there's unsynced data to fill out the rest of the
633
+ // read.
634
+
635
+ // First, ensure target read data is in scratch for easy handling.
636
+ MoveToScratchIfNeeded(result, scratch);
637
+ assert(result->data() == scratch);
638
+
639
+ // If we just did a target Read, we only want unsynced data after it
640
+ // (target_read_pos_). Otherwise (e.g. if target is behind because of
641
+ // unsynced data) we want unsynced data starting at the current read pos
642
+ // (read_pos_, not yet updated).
643
+ const uint64_t unsynced_read_pos = std::max(target_read_pos_, read_pos_);
644
+ const size_t offset_from_read_pos =
645
+ static_cast<size_t>(unsynced_read_pos - read_pos_);
646
+ Slice unsynced_result;
647
+ int64_t pos_at_last_sync = -1;
648
+ fs_->ReadUnsynced(fname_, unsynced_read_pos, n - offset_from_read_pos,
649
+ &unsynced_result, scratch + offset_from_read_pos,
650
+ &pos_at_last_sync);
651
+ assert(unsynced_result.data() >= scratch + offset_from_read_pos);
652
+ assert(unsynced_result.data() < scratch + n);
653
+ // Now, there are several cases to consider (some grouped together):
654
+ if (pos_at_last_sync <= static_cast<int64_t>(unsynced_read_pos)) {
655
+ // 1. We didn't get any unsynced data because nothing has been written
656
+ // to the file beyond unsynced_read_pos (including untracked
657
+ // pos_at_last_sync == -1)
658
+ // 2. We got some unsynced data starting at unsynced_read_pos (possibly
659
+ // on top of some synced data from target). We don't need to try reading
660
+ // any more from target because we established a "point in time" for
661
+ // completing this Read in which we read as much tail data (unsynced) as
662
+ // we could.
663
+
664
+ // We got pos_at_last_sync info if we got any unsynced data.
665
+ assert(pos_at_last_sync >= 0 || unsynced_result.size() == 0);
666
+
667
+ // Combined data is already lined up in scratch.
668
+ assert(result->data() + result->size() == unsynced_result.data());
669
+ assert(result->size() + unsynced_result.size() <= n);
670
+ // Combine results
671
+ *result = Slice(result->data(), result->size() + unsynced_result.size());
672
+ } else {
673
+ // 3. Any unsynced data we got was after unsynced_read_pos because the
674
+ // file was synced some time since our last target Read (either from this
675
+ // Read or a prior Read). We need to read more data from target to ensure
676
+ // this Read is filled out, even though we might have already read some
677
+ // (but not all due to a race). This code handles:
678
+ //
679
+ // * Catching up target after prior read(s) of unsynced data
680
+ // * Racing Sync in another thread since we called target Read above
681
+ //
682
+ // And merging potentially three results together for this Read:
683
+ // * The original target Read above
684
+ // * The following (non-throw-away) target Read
685
+ // * The ReadUnsynced above, which is always last if it returned data,
686
+ // so that we have a "point in time" for completing this Read in which we
687
+ // read as much tail data (unsynced) as we could.
688
+ //
689
+ // Deeper note about the race: we cannot just treat the original target
690
+ // Read as a "point in time" view of available data in the file, because
691
+ // there might have been unsynced data at that time, which became synced
692
+ // data by the time we read unsynced data. That is the race we are
693
+ // resolving with this "double check"-style code.
694
+ const size_t supplemental_read_pos = unsynced_read_pos;
695
+
696
+ // First, if there's any data from target that we know we would need to
697
+ // throw away to catch up, try to do it.
698
+ if (target_read_pos_ < supplemental_read_pos) {
699
+ Slice throw_away_result;
700
+ size_t throw_away_n = supplemental_read_pos - target_read_pos_;
701
+ std::unique_ptr<char[]> throw_away_scratch{new char[throw_away_n]};
702
+ s = target()->Read(throw_away_n, options, &throw_away_result,
703
+ throw_away_scratch.get(), dbg);
704
+ if (!s.ok()) {
705
+ read_pos_ += result->size();
706
+ return s;
707
+ }
708
+ target_read_pos_ += throw_away_result.size();
709
+ if (target_read_pos_ < supplemental_read_pos) {
710
+ // Because of pos_at_last_sync > supplemental_read_pos, we should
711
+ // have been able to catch up
712
+ read_pos_ += result->size();
713
+ return IOStatus::IOError(
714
+ "Unexpected truncation or short read of file " + fname_);
715
+ }
716
+ }
717
+ // Now we can do a productive supplemental Read from target
718
+ assert(target_read_pos_ == supplemental_read_pos);
719
+ Slice supplemental_result;
720
+ size_t supplemental_n =
721
+ unsynced_result.size() == 0
722
+ ? n - offset_from_read_pos
723
+ : unsynced_result.data() - (scratch + offset_from_read_pos);
724
+ s = target()->Read(supplemental_n, options, &supplemental_result,
725
+ scratch + offset_from_read_pos, dbg);
726
+ if (!s.ok()) {
727
+ read_pos_ += result->size();
728
+ return s;
729
+ }
730
+ target_read_pos_ += supplemental_result.size();
731
+ MoveToScratchIfNeeded(&supplemental_result,
732
+ scratch + offset_from_read_pos);
733
+
734
+ // Combined data is already lined up in scratch.
735
+ assert(result->data() + result->size() == supplemental_result.data());
736
+ assert(unsynced_result.size() == 0 ||
737
+ supplemental_result.data() + supplemental_result.size() ==
738
+ unsynced_result.data());
739
+ assert(result->size() + supplemental_result.size() +
740
+ unsynced_result.size() <=
741
+ n);
742
+ // Combine results
743
+ *result =
744
+ Slice(result->data(), result->size() + supplemental_result.size() +
745
+ unsynced_result.size());
746
+ }
488
747
  }
748
+ read_pos_ += result->size();
749
+
489
750
  return s;
490
751
  }
491
752
 
@@ -493,11 +754,16 @@ IOStatus TestFSSequentialFile::PositionedRead(uint64_t offset, size_t n,
493
754
  const IOOptions& options,
494
755
  Slice* result, char* scratch,
495
756
  IODebugContext* dbg) {
496
- IOStatus s =
497
- target()->PositionedRead(offset, n, options, result, scratch, dbg);
498
- if (s.ok() && fs_->ShouldInjectRandomReadError()) {
499
- return IOStatus::IOError("injected seq positioned read error");
757
+ IOStatus s = fs_->MaybeInjectThreadLocalError(
758
+ FaultInjectionIOType::kRead, options, "",
759
+ FaultInjectionTestFS::ErrorOperation::kRead, result, use_direct_io(),
760
+ scratch, true /*need_count_increase=*/, nullptr /* fault_injected */);
761
+ if (!s.ok()) {
762
+ return s;
500
763
  }
764
+
765
+ s = target()->PositionedRead(offset, n, options, result, scratch, dbg);
766
+ // TODO (low priority): fs_->ReadUnsyncedData()
501
767
  return s;
502
768
  }
503
769
 
@@ -514,24 +780,76 @@ IOStatus FaultInjectionTestFS::NewDirectory(
514
780
  return IOStatus::OK();
515
781
  }
516
782
 
783
+ IOStatus FaultInjectionTestFS::FileExists(const std::string& fname,
784
+ const IOOptions& options,
785
+ IODebugContext* dbg) {
786
+ if (!IsFilesystemActive()) {
787
+ return GetError();
788
+ }
789
+
790
+ IOStatus io_s =
791
+ MaybeInjectThreadLocalError(FaultInjectionIOType::kMetadataRead, options);
792
+ if (!io_s.ok()) {
793
+ return io_s;
794
+ }
795
+
796
+ io_s = target()->FileExists(fname, options, dbg);
797
+ return io_s;
798
+ }
799
+
800
+ IOStatus FaultInjectionTestFS::GetChildren(const std::string& dir,
801
+ const IOOptions& options,
802
+ std::vector<std::string>* result,
803
+ IODebugContext* dbg) {
804
+ if (!IsFilesystemActive()) {
805
+ return GetError();
806
+ }
807
+
808
+ IOStatus io_s =
809
+ MaybeInjectThreadLocalError(FaultInjectionIOType::kMetadataRead, options);
810
+ if (!io_s.ok()) {
811
+ return io_s;
812
+ }
813
+
814
+ io_s = target()->GetChildren(dir, options, result, dbg);
815
+ return io_s;
816
+ }
817
+
818
+ IOStatus FaultInjectionTestFS::GetChildrenFileAttributes(
819
+ const std::string& dir, const IOOptions& options,
820
+ std::vector<FileAttributes>* result, IODebugContext* dbg) {
821
+ if (!IsFilesystemActive()) {
822
+ return GetError();
823
+ }
824
+
825
+ IOStatus io_s =
826
+ MaybeInjectThreadLocalError(FaultInjectionIOType::kMetadataRead, options);
827
+ if (!io_s.ok()) {
828
+ return io_s;
829
+ }
830
+
831
+ io_s = target()->GetChildrenFileAttributes(dir, options, result, dbg);
832
+ return io_s;
833
+ }
834
+
517
835
  IOStatus FaultInjectionTestFS::NewWritableFile(
518
836
  const std::string& fname, const FileOptions& file_opts,
519
837
  std::unique_ptr<FSWritableFile>* result, IODebugContext* dbg) {
520
838
  if (!IsFilesystemActive()) {
521
839
  return GetError();
522
840
  }
523
- {
524
- IOStatus in_s = InjectMetadataWriteError();
525
- if (!in_s.ok()) {
526
- return in_s;
527
- }
528
- }
529
841
 
530
- if (ShouldUseDiretWritable(fname)) {
842
+ if (IsFilesystemDirectWritable()) {
531
843
  return target()->NewWritableFile(fname, file_opts, result, dbg);
532
844
  }
533
845
 
534
- IOStatus io_s = target()->NewWritableFile(fname, file_opts, result, dbg);
846
+ IOStatus io_s = MaybeInjectThreadLocalError(FaultInjectionIOType::kWrite,
847
+ file_opts.io_options, fname);
848
+ if (!io_s.ok()) {
849
+ return io_s;
850
+ }
851
+
852
+ io_s = target()->NewWritableFile(fname, file_opts, result, dbg);
535
853
  if (io_s.ok()) {
536
854
  result->reset(
537
855
  new TestFSWritableFile(fname, file_opts, std::move(*result), this));
@@ -548,12 +866,6 @@ IOStatus FaultInjectionTestFS::NewWritableFile(
548
866
  // dropping unsynced files.
549
867
  list[dir_and_name.second] = kNewFileNoOverwrite;
550
868
  }
551
- {
552
- IOStatus in_s = InjectMetadataWriteError();
553
- if (!in_s.ok()) {
554
- return in_s;
555
- }
556
- }
557
869
  }
558
870
  return io_s;
559
871
  }
@@ -564,19 +876,18 @@ IOStatus FaultInjectionTestFS::ReopenWritableFile(
564
876
  if (!IsFilesystemActive()) {
565
877
  return GetError();
566
878
  }
567
- if (ShouldUseDiretWritable(fname)) {
879
+ if (IsFilesystemDirectWritable()) {
568
880
  return target()->ReopenWritableFile(fname, file_opts, result, dbg);
569
881
  }
570
- {
571
- IOStatus in_s = InjectMetadataWriteError();
572
- if (!in_s.ok()) {
573
- return in_s;
574
- }
882
+ IOStatus io_s = MaybeInjectThreadLocalError(FaultInjectionIOType::kWrite,
883
+ file_opts.io_options, fname);
884
+ if (!io_s.ok()) {
885
+ return io_s;
575
886
  }
576
887
 
577
888
  bool exists;
578
- IOStatus io_s,
579
- exists_s = target()->FileExists(fname, IOOptions(), nullptr /* dbg */);
889
+ IOStatus exists_s =
890
+ target()->FileExists(fname, IOOptions(), nullptr /* dbg */);
580
891
  if (exists_s.IsNotFound()) {
581
892
  exists = false;
582
893
  } else if (exists_s.ok()) {
@@ -586,10 +897,12 @@ IOStatus FaultInjectionTestFS::ReopenWritableFile(
586
897
  exists = false;
587
898
  }
588
899
 
589
- if (io_s.ok()) {
590
- io_s = target()->ReopenWritableFile(fname, file_opts, result, dbg);
900
+ if (!io_s.ok()) {
901
+ return io_s;
591
902
  }
592
903
 
904
+ io_s = target()->ReopenWritableFile(fname, file_opts, result, dbg);
905
+
593
906
  // Only track files we created. Files created outside of this
594
907
  // `FaultInjectionTestFS` are not eligible for tracking/data dropping
595
908
  // (for example, they may contain data a previous db_stress run expects to
@@ -618,12 +931,6 @@ IOStatus FaultInjectionTestFS::ReopenWritableFile(
618
931
  result->reset(
619
932
  new TestFSWritableFile(fname, file_opts, std::move(*result), this));
620
933
  }
621
- {
622
- IOStatus in_s = InjectMetadataWriteError();
623
- if (!in_s.ok()) {
624
- return in_s;
625
- }
626
- }
627
934
  }
628
935
  return io_s;
629
936
  }
@@ -645,16 +952,17 @@ IOStatus FaultInjectionTestFS::NewRandomRWFile(
645
952
  if (!IsFilesystemActive()) {
646
953
  return GetError();
647
954
  }
648
- if (ShouldUseDiretWritable(fname)) {
955
+ if (IsFilesystemDirectWritable()) {
649
956
  return target()->NewRandomRWFile(fname, file_opts, result, dbg);
650
957
  }
651
- {
652
- IOStatus in_s = InjectMetadataWriteError();
653
- if (!in_s.ok()) {
654
- return in_s;
655
- }
958
+ IOStatus io_s = MaybeInjectThreadLocalError(FaultInjectionIOType::kWrite,
959
+ file_opts.io_options, fname);
960
+ if (!io_s.ok()) {
961
+ return io_s;
656
962
  }
657
- IOStatus io_s = target()->NewRandomRWFile(fname, file_opts, result, dbg);
963
+
964
+ io_s = target()->NewRandomRWFile(fname, file_opts, result, dbg);
965
+
658
966
  if (io_s.ok()) {
659
967
  result->reset(new TestFSRandomRWFile(fname, std::move(*result), this));
660
968
  // WritableFileWriter* file is opened
@@ -669,12 +977,6 @@ IOStatus FaultInjectionTestFS::NewRandomRWFile(
669
977
  // implementation by ignoring it.
670
978
  list[dir_and_name.second] = kNewFileNoOverwrite;
671
979
  }
672
- {
673
- IOStatus in_s = InjectMetadataWriteError();
674
- if (!in_s.ok()) {
675
- return in_s;
676
- }
677
- }
678
980
  }
679
981
  return io_s;
680
982
  }
@@ -685,16 +987,17 @@ IOStatus FaultInjectionTestFS::NewRandomAccessFile(
685
987
  if (!IsFilesystemActive()) {
686
988
  return GetError();
687
989
  }
688
- if (ShouldInjectRandomReadError()) {
689
- return IOStatus::IOError("injected error when open random access file");
690
- }
691
- IOStatus io_s = InjectThreadSpecificReadError(ErrorOperation::kOpen, nullptr,
692
- false, nullptr,
693
- /*need_count_increase=*/true,
694
- /*fault_injected=*/nullptr);
695
- if (io_s.ok()) {
696
- io_s = target()->NewRandomAccessFile(fname, file_opts, result, dbg);
990
+ IOStatus io_s = MaybeInjectThreadLocalError(
991
+ FaultInjectionIOType::kRead, file_opts.io_options, fname,
992
+ ErrorOperation::kOpen, nullptr /* result */, false /* direct_io */,
993
+ nullptr /* scratch */, true /*need_count_increase*/,
994
+ nullptr /*fault_injected*/);
995
+ if (!io_s.ok()) {
996
+ return io_s;
697
997
  }
998
+
999
+ io_s = target()->NewRandomAccessFile(fname, file_opts, result, dbg);
1000
+
698
1001
  if (io_s.ok()) {
699
1002
  result->reset(new TestFSRandomAccessFile(fname, std::move(*result), this));
700
1003
  }
@@ -707,13 +1010,19 @@ IOStatus FaultInjectionTestFS::NewSequentialFile(
707
1010
  if (!IsFilesystemActive()) {
708
1011
  return GetError();
709
1012
  }
710
-
711
- if (ShouldInjectRandomReadError()) {
712
- return IOStatus::IOError("injected read error when creating seq file");
1013
+ IOStatus io_s = MaybeInjectThreadLocalError(
1014
+ FaultInjectionIOType::kRead, file_opts.io_options, fname,
1015
+ ErrorOperation::kOpen, nullptr /* result */, false /* direct_io */,
1016
+ nullptr /* scratch */, true /*need_count_increase*/,
1017
+ nullptr /*fault_injected*/);
1018
+ if (!io_s.ok()) {
1019
+ return io_s;
713
1020
  }
714
- IOStatus io_s = target()->NewSequentialFile(fname, file_opts, result, dbg);
1021
+
1022
+ io_s = target()->NewSequentialFile(fname, file_opts, result, dbg);
1023
+
715
1024
  if (io_s.ok()) {
716
- result->reset(new TestFSSequentialFile(std::move(*result), this));
1025
+ result->reset(new TestFSSequentialFile(std::move(*result), this, fname));
717
1026
  }
718
1027
  return io_s;
719
1028
  }
@@ -724,25 +1033,66 @@ IOStatus FaultInjectionTestFS::DeleteFile(const std::string& f,
724
1033
  if (!IsFilesystemActive()) {
725
1034
  return GetError();
726
1035
  }
727
- {
728
- IOStatus in_s = InjectMetadataWriteError();
729
- if (!in_s.ok()) {
730
- return in_s;
731
- }
1036
+ IOStatus io_s = MaybeInjectThreadLocalError(
1037
+ FaultInjectionIOType::kMetadataWrite, options);
1038
+ if (!io_s.ok()) {
1039
+ return io_s;
732
1040
  }
733
- IOStatus io_s = FileSystemWrapper::DeleteFile(f, options, dbg);
1041
+
1042
+ io_s = FileSystemWrapper::DeleteFile(f, options, dbg);
1043
+
734
1044
  if (io_s.ok()) {
735
1045
  UntrackFile(f);
736
- {
737
- IOStatus in_s = InjectMetadataWriteError();
738
- if (!in_s.ok()) {
739
- return in_s;
740
- }
1046
+ }
1047
+ return io_s;
1048
+ }
1049
+
1050
+ IOStatus FaultInjectionTestFS::GetFileSize(const std::string& f,
1051
+ const IOOptions& options,
1052
+ uint64_t* file_size,
1053
+ IODebugContext* dbg) {
1054
+ if (!IsFilesystemActive()) {
1055
+ return GetError();
1056
+ }
1057
+ IOStatus io_s =
1058
+ MaybeInjectThreadLocalError(FaultInjectionIOType::kMetadataRead, options);
1059
+ if (!io_s.ok()) {
1060
+ return io_s;
1061
+ }
1062
+
1063
+ io_s = target()->GetFileSize(f, options, file_size, dbg);
1064
+ if (!io_s.ok()) {
1065
+ return io_s;
1066
+ }
1067
+
1068
+ if (ReadUnsyncedData()) {
1069
+ // Need to report flushed size, not synced size
1070
+ MutexLock l(&mutex_);
1071
+ auto it = db_file_state_.find(f);
1072
+ if (it != db_file_state_.end()) {
1073
+ *file_size = it->second.pos_at_last_append_;
741
1074
  }
742
1075
  }
743
1076
  return io_s;
744
1077
  }
745
1078
 
1079
+ IOStatus FaultInjectionTestFS::GetFileModificationTime(const std::string& fname,
1080
+ const IOOptions& options,
1081
+ uint64_t* file_mtime,
1082
+ IODebugContext* dbg) {
1083
+ if (!IsFilesystemActive()) {
1084
+ return GetError();
1085
+ }
1086
+ IOStatus io_s =
1087
+ MaybeInjectThreadLocalError(FaultInjectionIOType::kMetadataRead, options);
1088
+ if (!io_s.ok()) {
1089
+ return io_s;
1090
+ }
1091
+
1092
+ io_s = target()->GetFileModificationTime(fname, options, file_mtime, dbg);
1093
+ return io_s;
1094
+ }
1095
+
746
1096
  IOStatus FaultInjectionTestFS::RenameFile(const std::string& s,
747
1097
  const std::string& t,
748
1098
  const IOOptions& options,
@@ -750,11 +1100,10 @@ IOStatus FaultInjectionTestFS::RenameFile(const std::string& s,
750
1100
  if (!IsFilesystemActive()) {
751
1101
  return GetError();
752
1102
  }
753
- {
754
- IOStatus in_s = InjectMetadataWriteError();
755
- if (!in_s.ok()) {
756
- return in_s;
757
- }
1103
+ IOStatus io_s = MaybeInjectThreadLocalError(
1104
+ FaultInjectionIOType::kMetadataWrite, options);
1105
+ if (!io_s.ok()) {
1106
+ return io_s;
758
1107
  }
759
1108
 
760
1109
  // We preserve contents of overwritten files up to a size threshold.
@@ -769,7 +1118,7 @@ IOStatus FaultInjectionTestFS::RenameFile(const std::string& s,
769
1118
  ReadFileToString(target(), t, &previous_contents).PermitUncheckedError();
770
1119
  }
771
1120
  }
772
- IOStatus io_s = FileSystemWrapper::RenameFile(s, t, options, dbg);
1121
+ io_s = FileSystemWrapper::RenameFile(s, t, options, dbg);
773
1122
 
774
1123
  if (io_s.ok()) {
775
1124
  {
@@ -783,16 +1132,10 @@ IOStatus FaultInjectionTestFS::RenameFile(const std::string& s,
783
1132
  auto tdn = TestFSGetDirAndName(t);
784
1133
  if (dir_to_new_files_since_last_sync_[sdn.first].erase(sdn.second) != 0) {
785
1134
  auto& tlist = dir_to_new_files_since_last_sync_[tdn.first];
786
- assert(tlist.find(tdn.second) == tlist.end());
787
1135
  tlist[tdn.second] = previous_contents;
788
1136
  }
789
1137
  }
790
- IOStatus in_s = InjectMetadataWriteError();
791
- if (!in_s.ok()) {
792
- return in_s;
793
- }
794
1138
  }
795
-
796
1139
  return io_s;
797
1140
  }
798
1141
 
@@ -803,22 +1146,27 @@ IOStatus FaultInjectionTestFS::LinkFile(const std::string& s,
803
1146
  if (!IsFilesystemActive()) {
804
1147
  return GetError();
805
1148
  }
806
- {
807
- IOStatus in_s = InjectMetadataWriteError();
808
- if (!in_s.ok()) {
809
- return in_s;
810
- }
1149
+ IOStatus io_s = MaybeInjectThreadLocalError(
1150
+ FaultInjectionIOType::kMetadataWrite, options);
1151
+ if (!io_s.ok()) {
1152
+ return io_s;
811
1153
  }
812
1154
 
813
1155
  // Using the value in `dir_to_new_files_since_last_sync_` for the source file
814
1156
  // may be a more reasonable choice.
815
1157
  std::string previous_contents = kNewFileNoOverwrite;
816
1158
 
817
- IOStatus io_s = FileSystemWrapper::LinkFile(s, t, options, dbg);
1159
+ io_s = FileSystemWrapper::LinkFile(s, t, options, dbg);
818
1160
 
819
1161
  if (io_s.ok()) {
820
1162
  {
821
1163
  MutexLock l(&mutex_);
1164
+ if (!allow_link_open_file_ &&
1165
+ open_managed_files_.find(s) != open_managed_files_.end()) {
1166
+ fprintf(stderr, "Attempt to LinkFile while open for write: %s\n",
1167
+ s.c_str());
1168
+ abort();
1169
+ }
822
1170
  if (db_file_state_.find(s) != db_file_state_.end()) {
823
1171
  db_file_state_[t] = db_file_state_[s];
824
1172
  }
@@ -832,12 +1180,74 @@ IOStatus FaultInjectionTestFS::LinkFile(const std::string& s,
832
1180
  tlist[tdn.second] = previous_contents;
833
1181
  }
834
1182
  }
835
- IOStatus in_s = InjectMetadataWriteError();
836
- if (!in_s.ok()) {
837
- return in_s;
838
- }
839
1183
  }
1184
+ return io_s;
1185
+ }
840
1186
 
1187
+ IOStatus FaultInjectionTestFS::NumFileLinks(const std::string& fname,
1188
+ const IOOptions& options,
1189
+ uint64_t* count,
1190
+ IODebugContext* dbg) {
1191
+ if (!IsFilesystemActive()) {
1192
+ return GetError();
1193
+ }
1194
+ IOStatus io_s =
1195
+ MaybeInjectThreadLocalError(FaultInjectionIOType::kMetadataRead, options);
1196
+ if (!io_s.ok()) {
1197
+ return io_s;
1198
+ }
1199
+
1200
+ io_s = target()->NumFileLinks(fname, options, count, dbg);
1201
+ return io_s;
1202
+ }
1203
+
1204
+ IOStatus FaultInjectionTestFS::AreFilesSame(const std::string& first,
1205
+ const std::string& second,
1206
+ const IOOptions& options, bool* res,
1207
+ IODebugContext* dbg) {
1208
+ if (!IsFilesystemActive()) {
1209
+ return GetError();
1210
+ }
1211
+ IOStatus io_s =
1212
+ MaybeInjectThreadLocalError(FaultInjectionIOType::kMetadataRead, options);
1213
+ if (!io_s.ok()) {
1214
+ return io_s;
1215
+ }
1216
+
1217
+ io_s = target()->AreFilesSame(first, second, options, res, dbg);
1218
+ return io_s;
1219
+ }
1220
+
1221
+ IOStatus FaultInjectionTestFS::GetAbsolutePath(const std::string& db_path,
1222
+ const IOOptions& options,
1223
+ std::string* output_path,
1224
+ IODebugContext* dbg) {
1225
+ if (!IsFilesystemActive()) {
1226
+ return GetError();
1227
+ }
1228
+ IOStatus io_s =
1229
+ MaybeInjectThreadLocalError(FaultInjectionIOType::kMetadataRead, options);
1230
+ if (!io_s.ok()) {
1231
+ return io_s;
1232
+ }
1233
+
1234
+ io_s = target()->GetAbsolutePath(db_path, options, output_path, dbg);
1235
+ return io_s;
1236
+ }
1237
+
1238
+ IOStatus FaultInjectionTestFS::IsDirectory(const std::string& path,
1239
+ const IOOptions& options,
1240
+ bool* is_dir, IODebugContext* dgb) {
1241
+ if (!IsFilesystemActive()) {
1242
+ return GetError();
1243
+ }
1244
+ IOStatus io_s =
1245
+ MaybeInjectThreadLocalError(FaultInjectionIOType::kMetadataRead, options);
1246
+ if (!io_s.ok()) {
1247
+ return io_s;
1248
+ }
1249
+
1250
+ io_s = target()->IsDirectory(path, options, is_dir, dgb);
841
1251
  return io_s;
842
1252
  }
843
1253
 
@@ -954,14 +1364,17 @@ void FaultInjectionTestFS::UntrackFile(const std::string& f) {
954
1364
  open_managed_files_.erase(f);
955
1365
  }
956
1366
 
957
- IOStatus FaultInjectionTestFS::InjectThreadSpecificReadError(
958
- ErrorOperation op, Slice* result, bool direct_io, char* scratch,
959
- bool need_count_increase, bool* fault_injected) {
1367
+ IOStatus FaultInjectionTestFS::MaybeInjectThreadLocalReadError(
1368
+ const IOOptions& io_options, ErrorOperation op, Slice* result,
1369
+ bool direct_io, char* scratch, bool need_count_increase,
1370
+ bool* fault_injected) {
960
1371
  bool dummy_bool;
961
1372
  bool& ret_fault_injected = fault_injected ? *fault_injected : dummy_bool;
962
1373
  ret_fault_injected = false;
963
- ErrorContext* ctx = static_cast<ErrorContext*>(thread_local_error_->Get());
964
- if (ctx == nullptr || !ctx->enable_error_injection || !ctx->one_in) {
1374
+ ErrorContext* ctx =
1375
+ static_cast<ErrorContext*>(injected_thread_local_read_error_.Get());
1376
+ if (ctx == nullptr || !ctx->enable_error_injection || !ctx->one_in ||
1377
+ ShouldIOActivtiesExcludedFromFaultInjection(io_options.io_activity)) {
965
1378
  return IOStatus::OK();
966
1379
  }
967
1380
 
@@ -1013,9 +1426,9 @@ IOStatus FaultInjectionTestFS::InjectThreadSpecificReadError(
1013
1426
  ret = IOStatus::IOError(ctx->message);
1014
1427
  }
1015
1428
  }
1016
- if (ctx->retryable) {
1017
- ret.SetRetryable(true);
1018
- }
1429
+
1430
+ ret.SetRetryable(ctx->retryable);
1431
+ ret.SetDataLoss(ctx->has_data_loss);
1019
1432
  return ret;
1020
1433
  }
1021
1434
 
@@ -1026,59 +1439,58 @@ bool FaultInjectionTestFS::TryParseFileName(const std::string& file_name,
1026
1439
  return ParseFileName(file, number, type);
1027
1440
  }
1028
1441
 
1029
- IOStatus FaultInjectionTestFS::InjectWriteError(const std::string& file_name) {
1030
- MutexLock l(&mutex_);
1031
- if (!enable_write_error_injection_ || !write_error_one_in_) {
1442
+ IOStatus FaultInjectionTestFS::MaybeInjectThreadLocalError(
1443
+ FaultInjectionIOType type, const IOOptions& io_options,
1444
+ const std::string& file_name, ErrorOperation op, Slice* result,
1445
+ bool direct_io, char* scratch, bool need_count_increase,
1446
+ bool* fault_injected) {
1447
+ if (type == FaultInjectionIOType::kRead) {
1448
+ return MaybeInjectThreadLocalReadError(io_options, op, result, direct_io,
1449
+ scratch, need_count_increase,
1450
+ fault_injected);
1451
+ }
1452
+
1453
+ ErrorContext* ctx = GetErrorContextFromFaultInjectionIOType(type);
1454
+ if (ctx == nullptr || !ctx->enable_error_injection || !ctx->one_in ||
1455
+ ShouldIOActivtiesExcludedFromFaultInjection(io_options.io_activity) ||
1456
+ (type == FaultInjectionIOType::kWrite &&
1457
+ ShouldExcludeFromWriteFaultInjection(file_name))) {
1032
1458
  return IOStatus::OK();
1033
1459
  }
1034
- bool allowed_type = false;
1035
-
1036
- if (inject_for_all_file_types_) {
1037
- allowed_type = true;
1038
- } else {
1039
- uint64_t number;
1040
- FileType cur_type = kTempFile;
1041
- if (TryParseFileName(file_name, &number, &cur_type)) {
1042
- for (const auto& type : write_error_allowed_types_) {
1043
- if (cur_type == type) {
1044
- allowed_type = true;
1045
- }
1046
- }
1047
- }
1048
- }
1049
1460
 
1050
- if (allowed_type) {
1051
- if (write_error_rand_.OneIn(write_error_one_in_)) {
1052
- return GetError();
1461
+ IOStatus ret;
1462
+ if (ctx->rand.OneIn(ctx->one_in)) {
1463
+ ctx->count++;
1464
+ if (ctx->callstack) {
1465
+ free(ctx->callstack);
1053
1466
  }
1054
- }
1055
- return IOStatus::OK();
1056
- }
1057
-
1058
- IOStatus FaultInjectionTestFS::InjectMetadataWriteError() {
1059
- {
1060
- MutexLock l(&mutex_);
1061
- if (!enable_metadata_write_error_injection_ ||
1062
- !metadata_write_error_one_in_ ||
1063
- !write_error_rand_.OneIn(metadata_write_error_one_in_)) {
1064
- return IOStatus::OK();
1467
+ ctx->callstack = port::SaveStack(&ctx->frames);
1468
+ ctx->message = GetErrorMessageFromFaultInjectionIOType(type);
1469
+ ret = IOStatus::IOError(ctx->message);
1470
+ ret.SetRetryable(ctx->retryable);
1471
+ ret.SetDataLoss(ctx->has_data_loss);
1472
+ if (type == FaultInjectionIOType::kWrite) {
1473
+ TEST_SYNC_POINT(
1474
+ "FaultInjectionTestFS::InjectMetadataWriteError:Injected");
1065
1475
  }
1066
1476
  }
1067
- TEST_SYNC_POINT("FaultInjectionTestFS::InjectMetadataWriteError:Injected");
1068
- return IOStatus::IOError("injected metadata write error");
1477
+ return ret;
1069
1478
  }
1070
1479
 
1071
- void FaultInjectionTestFS::PrintFaultBacktrace() {
1480
+ void FaultInjectionTestFS::PrintInjectedThreadLocalErrorBacktrace(
1481
+ FaultInjectionIOType type) {
1072
1482
  #if defined(OS_LINUX)
1073
- ErrorContext* ctx = static_cast<ErrorContext*>(thread_local_error_->Get());
1074
- if (ctx == nullptr) {
1075
- return;
1483
+ ErrorContext* ctx = GetErrorContextFromFaultInjectionIOType(type);
1484
+ if (ctx) {
1485
+ if (type == FaultInjectionIOType::kRead) {
1486
+ fprintf(stderr, "Injected read error type = %d\n", ctx->type);
1487
+ }
1488
+ fprintf(stderr, "Message: %s\n", ctx->message.c_str());
1489
+ port::PrintAndFreeStack(ctx->callstack, ctx->frames);
1490
+ ctx->callstack = nullptr;
1076
1491
  }
1077
- fprintf(stderr, "Injected error type = %d\n", ctx->type);
1078
- fprintf(stderr, "Message: %s\n", ctx->message.c_str());
1079
- port::PrintAndFreeStack(ctx->callstack, ctx->frames);
1080
- ctx->callstack = nullptr;
1492
+ #else
1493
+ (void)type;
1081
1494
  #endif
1082
1495
  }
1083
-
1084
1496
  } // namespace ROCKSDB_NAMESPACE