@nxtedition/rocksdb 10.1.5 → 10.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 (255) hide show
  1. package/binding.cc +19 -11
  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/prebuilds/linux-x64/@nxtedition+rocksdb.node +0 -0
  219. package/.tap/test-results/node_modules/abstract-level/test/chained-batch-test.js.tap +0 -0
  220. package/.tap/test-results/node_modules/abstract-level/test/get-test.js.tap +0 -0
  221. package/.tap/test-results/test/abstract-level-test.js.tap +0 -1077
  222. package/.tap/test-results/test/batch-test.js.tap +0 -12
  223. package/.tap/test-results/test/chained-batch-gc-test.js.tap +0 -11
  224. package/.tap/test-results/test/cleanup-hanging-iterators-test.js.tap +0 -135
  225. package/.tap/test-results/test/clear-gc-test.js.tap +0 -13
  226. package/.tap/test-results/test/column-test.js.tap +0 -55
  227. package/.tap/test-results/test/common.js.tap +0 -0
  228. package/.tap/test-results/test/compression-test.js.tap +0 -30
  229. package/.tap/test-results/test/db-identity.js.tap +0 -12
  230. package/.tap/test-results/test/electron.js.tap +0 -0
  231. package/.tap/test-results/test/env-cleanup-hook-test.js.tap +0 -40
  232. package/.tap/test-results/test/env-cleanup-hook.js.tap +0 -0
  233. package/.tap/test-results/test/gc.js.tap +0 -0
  234. package/.tap/test-results/test/getproperty-test.js.tap +0 -29
  235. package/.tap/test-results/test/iterator-gc-test.js.tap +0 -15
  236. package/.tap/test-results/test/iterator-hwm-test.js.tap +0 -131
  237. package/.tap/test-results/test/iterator-recursion-test.js.tap +0 -12
  238. package/.tap/test-results/test/iterator-starvation-test.js.tap +0 -73
  239. package/.tap/test-results/test/iterator-test.js.tap +0 -6
  240. package/.tap/test-results/test/leak-tester-batch.js.tap +0 -0
  241. package/.tap/test-results/test/leak-tester-iterator.js.tap +0 -0
  242. package/.tap/test-results/test/leak-tester.js.tap +0 -0
  243. package/.tap/test-results/test/lock-test.js.tap +0 -18
  244. package/.tap/test-results/test/lock.js.tap +0 -0
  245. package/.tap/test-results/test/make.js.tap +0 -0
  246. package/.tap/test-results/test/max-rev-merge.js.tap +0 -0
  247. package/.tap/test-results/test/merge-operator-test.js.tap +0 -12
  248. package/.tap/test-results/test/mkdir-test.js.tap +0 -15
  249. package/.tap/test-results/test/segfault-test.js.tap +0 -76
  250. package/.tap/test-results/test/stack-blower.js.tap +0 -0
  251. package/deps/rocksdb/rocksdb/README.md +0 -29
  252. package/deps/rocksdb/rocksdb/microbench/README.md +0 -60
  253. package/deps/rocksdb/rocksdb/plugin/README.md +0 -43
  254. package/deps/rocksdb/rocksdb/port/README +0 -10
  255. package/deps/rocksdb/rocksdb/utilities/transactions/lock/range/range_tree/lib/README +0 -13
@@ -7,7 +7,11 @@
7
7
  // Use of this source code is governed by a BSD-style license that can be
8
8
  // found in the LICENSE file. See the AUTHORS file for names of contributors.
9
9
 
10
+ #include "db/dbformat.h"
11
+ #include "db_stress_tool/db_stress_listener.h"
12
+ #include "db_stress_tool/db_stress_shared_state.h"
10
13
  #include "db_stress_tool/expected_state.h"
14
+ #include "rocksdb/status.h"
11
15
  #ifdef GFLAGS
12
16
  #include "db/wide/wide_columns_helper.h"
13
17
  #include "db_stress_tool/db_stress_common.h"
@@ -507,12 +511,6 @@ class NonBatchedOpsStressTest : public StressTest {
507
511
  std::string key_str = Key(rand_keys[0]);
508
512
  Slice key = key_str;
509
513
  std::string from_db;
510
- int error_count = 0;
511
-
512
- if (fault_fs_guard) {
513
- fault_fs_guard->EnableErrorInjection();
514
- SharedState::ignore_read_error = false;
515
- }
516
514
 
517
515
  ReadOptions read_opts_copy = read_opts;
518
516
  std::string read_ts_str;
@@ -525,26 +523,43 @@ class NonBatchedOpsStressTest : public StressTest {
525
523
  bool read_older_ts = MaybeUseOlderTimestampForPointLookup(
526
524
  thread, read_ts_str, read_ts_slice, read_opts_copy);
527
525
 
526
+ if (fault_fs_guard) {
527
+ fault_fs_guard->GetAndResetInjectedThreadLocalErrorCount(
528
+ FaultInjectionIOType::kRead);
529
+ fault_fs_guard->GetAndResetInjectedThreadLocalErrorCount(
530
+ FaultInjectionIOType::kMetadataRead);
531
+ SharedState::ignore_read_error = false;
532
+ }
533
+
528
534
  const ExpectedValue pre_read_expected_value =
529
535
  thread->shared->Get(rand_column_families[0], rand_keys[0]);
530
536
  Status s = db_->Get(read_opts_copy, cfh, key, &from_db);
531
537
  const ExpectedValue post_read_expected_value =
532
538
  thread->shared->Get(rand_column_families[0], rand_keys[0]);
539
+
540
+ int injected_error_count = 0;
533
541
  if (fault_fs_guard) {
534
- error_count = fault_fs_guard->GetAndResetErrorCount();
542
+ injected_error_count = GetMinInjectedErrorCount(
543
+ fault_fs_guard->GetAndResetInjectedThreadLocalErrorCount(
544
+ FaultInjectionIOType::kRead),
545
+ fault_fs_guard->GetAndResetInjectedThreadLocalErrorCount(
546
+ FaultInjectionIOType::kMetadataRead));
547
+ if (!SharedState::ignore_read_error && injected_error_count > 0 &&
548
+ (s.ok() || s.IsNotFound())) {
549
+ // Grab mutex so multiple thread don't try to print the
550
+ // stack trace at the same time
551
+ MutexLock l(thread->shared->GetMutex());
552
+ fprintf(stderr, "Didn't get expected error from Get\n");
553
+ fprintf(stderr, "Callstack that injected the fault\n");
554
+ fault_fs_guard->PrintInjectedThreadLocalErrorBacktrace(
555
+ FaultInjectionIOType::kRead);
556
+ fault_fs_guard->PrintInjectedThreadLocalErrorBacktrace(
557
+ FaultInjectionIOType::kMetadataRead);
558
+ std::terminate();
559
+ }
535
560
  }
561
+
536
562
  if (s.ok()) {
537
- if (fault_fs_guard) {
538
- if (error_count && !SharedState::ignore_read_error) {
539
- // Grab mutex so multiple thread don't try to print the
540
- // stack trace at the same time
541
- MutexLock l(thread->shared->GetMutex());
542
- fprintf(stderr, "Didn't get expected error from Get\n");
543
- fprintf(stderr, "Callstack that injected the fault\n");
544
- fault_fs_guard->PrintFaultBacktrace();
545
- std::terminate();
546
- }
547
- }
548
563
  // found case
549
564
  thread->stats.AddGets(1, 1);
550
565
  // we only have the latest expected state
@@ -584,16 +599,10 @@ class NonBatchedOpsStressTest : public StressTest {
584
599
  key.ToString(true).c_str());
585
600
  }
586
601
  }
587
- } else {
588
- if (error_count == 0) {
589
- // errors case
590
- thread->stats.AddErrors(1);
591
- } else {
592
- thread->stats.AddVerifiedErrors(1);
593
- }
594
- }
595
- if (fault_fs_guard) {
596
- fault_fs_guard->DisableErrorInjection();
602
+ } else if (injected_error_count == 0 || !IsErrorInjectedAndRetryable(s)) {
603
+ thread->shared->SetVerificationFailure();
604
+ fprintf(stderr, "error : Get() returns %s for key: %s.\n",
605
+ s.ToString().c_str(), key.ToString(true).c_str());
597
606
  }
598
607
  return s;
599
608
  }
@@ -610,14 +619,13 @@ class NonBatchedOpsStressTest : public StressTest {
610
619
  std::vector<PinnableSlice> values(num_keys);
611
620
  std::vector<Status> statuses(num_keys);
612
621
  // When Flags_use_txn is enabled, we also do a read your write check.
613
- std::vector<std::optional<ExpectedValue>> ryw_expected_values;
614
- ryw_expected_values.reserve(num_keys);
622
+ std::unordered_map<std::string, ExpectedValue> ryw_expected_values;
615
623
 
616
624
  SharedState* shared = thread->shared;
625
+ assert(shared);
617
626
 
618
627
  int column_family = rand_column_families[0];
619
628
  ColumnFamilyHandle* cfh = column_families_[column_family];
620
- int error_count = 0;
621
629
 
622
630
  bool do_consistency_check = FLAGS_check_multiget_consistency;
623
631
 
@@ -643,6 +651,13 @@ class NonBatchedOpsStressTest : public StressTest {
643
651
  // will be rolled back once MultiGet returns.
644
652
  std::unique_ptr<Transaction> txn;
645
653
  if (use_txn) {
654
+ // TODO(hx235): test fault injection with MultiGet() with transactions
655
+ if (fault_fs_guard) {
656
+ fault_fs_guard->DisableThreadLocalErrorInjection(
657
+ FaultInjectionIOType::kRead);
658
+ fault_fs_guard->DisableThreadLocalErrorInjection(
659
+ FaultInjectionIOType::kMetadataRead);
660
+ }
646
661
  WriteOptions wo;
647
662
  if (FLAGS_rate_limit_auto_wal_flush) {
648
663
  wo.rate_limiter_priority = Env::IO_USER;
@@ -650,7 +665,7 @@ class NonBatchedOpsStressTest : public StressTest {
650
665
  Status s = NewTxn(wo, &txn);
651
666
  if (!s.ok()) {
652
667
  fprintf(stderr, "NewTxn error: %s\n", s.ToString().c_str());
653
- thread->shared->SafeTerminate();
668
+ shared->SafeTerminate();
654
669
  }
655
670
  }
656
671
  for (size_t i = 0; i < num_keys; ++i) {
@@ -658,66 +673,54 @@ class NonBatchedOpsStressTest : public StressTest {
658
673
  key_str.emplace_back(Key(rand_key));
659
674
  keys.emplace_back(key_str.back());
660
675
  if (use_txn) {
661
- if (!shared->AllowsOverwrite(rand_key) &&
662
- shared->Exists(column_family, rand_key)) {
663
- // Just do read your write checks for keys that allow overwrites.
664
- ryw_expected_values.emplace_back(std::nullopt);
665
- continue;
666
- }
667
- // With a 1 in 10 probability, insert the just added key in the batch
668
- // into the transaction. This will create an overlap with the MultiGet
669
- // keys and exercise some corner cases in the code
670
- if (thread->rand.OneIn(10)) {
671
- int op = thread->rand.Uniform(2);
672
- Status s;
673
- assert(txn);
674
- switch (op) {
675
- case 0:
676
- case 1: {
677
- ExpectedValue put_value;
678
- put_value.Put(false /* pending */);
679
- ryw_expected_values.emplace_back(put_value);
680
- char value[100];
681
- size_t sz =
682
- GenerateValue(put_value.GetValueBase(), value, sizeof(value));
683
- Slice v(value, sz);
684
- if (op == 0) {
685
- s = txn->Put(cfh, keys.back(), v);
686
- } else {
687
- s = txn->Merge(cfh, keys.back(), v);
688
- }
689
- break;
690
- }
691
- case 2: {
692
- ExpectedValue delete_value;
693
- delete_value.Delete(false /* pending */);
694
- ryw_expected_values.emplace_back(delete_value);
695
- s = txn->Delete(cfh, keys.back());
696
- break;
697
- }
698
- default:
699
- assert(false);
700
- }
701
- if (!s.ok()) {
702
- fprintf(stderr, "Transaction put error: %s\n",
703
- s.ToString().c_str());
704
- thread->shared->SafeTerminate();
705
- }
706
- } else {
707
- ryw_expected_values.emplace_back(std::nullopt);
708
- }
676
+ MaybeAddKeyToTxnForRYW(thread, column_family, rand_key, txn.get(),
677
+ ryw_expected_values);
709
678
  }
710
679
  }
711
680
 
681
+ int injected_error_count = 0;
682
+
712
683
  if (!use_txn) {
713
684
  if (fault_fs_guard) {
714
- fault_fs_guard->EnableErrorInjection();
685
+ fault_fs_guard->GetAndResetInjectedThreadLocalErrorCount(
686
+ FaultInjectionIOType::kRead);
687
+ fault_fs_guard->GetAndResetInjectedThreadLocalErrorCount(
688
+ FaultInjectionIOType::kMetadataRead);
715
689
  SharedState::ignore_read_error = false;
716
690
  }
717
691
  db_->MultiGet(readoptionscopy, cfh, num_keys, keys.data(), values.data(),
718
692
  statuses.data());
719
693
  if (fault_fs_guard) {
720
- error_count = fault_fs_guard->GetAndResetErrorCount();
694
+ injected_error_count = GetMinInjectedErrorCount(
695
+ fault_fs_guard->GetAndResetInjectedThreadLocalErrorCount(
696
+ FaultInjectionIOType::kRead),
697
+ fault_fs_guard->GetAndResetInjectedThreadLocalErrorCount(
698
+ FaultInjectionIOType::kMetadataRead));
699
+
700
+ if (injected_error_count > 0) {
701
+ int stat_nok_nfound = 0;
702
+ for (const auto& s : statuses) {
703
+ if (!s.ok() && !s.IsNotFound()) {
704
+ stat_nok_nfound++;
705
+ }
706
+ }
707
+ if (!SharedState::ignore_read_error &&
708
+ stat_nok_nfound < injected_error_count) {
709
+ // Grab mutex so multiple thread don't try to print the
710
+ // stack trace at the same time
711
+ MutexLock l(shared->GetMutex());
712
+ fprintf(stderr, "Didn't get expected error from MultiGet. \n");
713
+ fprintf(stderr,
714
+ "num_keys %zu Expected %d errors, seen at least %d\n",
715
+ num_keys, injected_error_count, stat_nok_nfound);
716
+ fprintf(stderr, "Callstack that injected the fault\n");
717
+ fault_fs_guard->PrintInjectedThreadLocalErrorBacktrace(
718
+ FaultInjectionIOType::kRead);
719
+ fault_fs_guard->PrintInjectedThreadLocalErrorBacktrace(
720
+ FaultInjectionIOType::kMetadataRead);
721
+ std::terminate();
722
+ }
723
+ }
721
724
  }
722
725
  } else {
723
726
  assert(txn);
@@ -725,30 +728,6 @@ class NonBatchedOpsStressTest : public StressTest {
725
728
  statuses.data());
726
729
  }
727
730
 
728
- if (fault_fs_guard && error_count && !SharedState::ignore_read_error) {
729
- int stat_nok = 0;
730
- for (const auto& s : statuses) {
731
- if (!s.ok() && !s.IsNotFound()) {
732
- stat_nok++;
733
- }
734
- }
735
-
736
- if (stat_nok < error_count) {
737
- // Grab mutex so multiple thread don't try to print the
738
- // stack trace at the same time
739
- MutexLock l(thread->shared->GetMutex());
740
- fprintf(stderr, "Didn't get expected error from MultiGet. \n");
741
- fprintf(stderr, "num_keys %zu Expected %d errors, seen %d\n", num_keys,
742
- error_count, stat_nok);
743
- fprintf(stderr, "Callstack that injected the fault\n");
744
- fault_fs_guard->PrintFaultBacktrace();
745
- std::terminate();
746
- }
747
- }
748
- if (fault_fs_guard) {
749
- fault_fs_guard->DisableErrorInjection();
750
- }
751
-
752
731
  auto ryw_check =
753
732
  [](const Slice& key, const PinnableSlice& value, const Status& s,
754
733
  const std::optional<ExpectedValue>& ryw_expected_value) -> bool {
@@ -803,63 +782,69 @@ class NonBatchedOpsStressTest : public StressTest {
803
782
  [&](const Slice& key, const PinnableSlice& expected_value,
804
783
  const Status& s,
805
784
  const std::optional<ExpectedValue>& ryw_expected_value) -> bool {
785
+ // Temporarily disable error injection for verification
786
+ if (fault_fs_guard) {
787
+ fault_fs_guard->DisableThreadLocalErrorInjection(
788
+ FaultInjectionIOType::kRead);
789
+ fault_fs_guard->DisableThreadLocalErrorInjection(
790
+ FaultInjectionIOType::kMetadataRead);
791
+ }
792
+
793
+ bool check_multiget_res = true;
806
794
  bool is_consistent = true;
807
795
  bool is_ryw_correct = true;
808
- // Only do the consistency check if no error was injected and
809
- // MultiGet didn't return an unexpected error. If test does not use
810
- // transaction, the consistency check for each key included check results
811
- // from db `Get` and db `MultiGet` are consistent.
796
+
797
+ // If test does not use transaction, the consistency check for each key
798
+ // included check results from db `Get` and db `MultiGet` are consistent.
812
799
  // If test use transaction, after consistency check, also do a read your
813
800
  // own write check.
814
- if (do_consistency_check && !error_count && (s.ok() || s.IsNotFound())) {
815
- Status tmp_s;
816
- std::string value;
801
+ Status tmp_s;
802
+ std::string value;
817
803
 
818
- if (use_txn) {
819
- assert(txn);
820
- ThreadStatusUtil::SetThreadOperation(
821
- ThreadStatus::OperationType::OP_GET);
822
- tmp_s = txn->Get(readoptionscopy, cfh, key, &value);
823
- ThreadStatusUtil::SetThreadOperation(
824
- ThreadStatus::OperationType::OP_MULTIGET);
825
- } else {
826
- ThreadStatusUtil::SetThreadOperation(
827
- ThreadStatus::OperationType::OP_GET);
828
- tmp_s = db_->Get(readoptionscopy, cfh, key, &value);
829
- ThreadStatusUtil::SetThreadOperation(
830
- ThreadStatus::OperationType::OP_MULTIGET);
831
- }
832
- if (!tmp_s.ok() && !tmp_s.IsNotFound()) {
833
- fprintf(stderr, "Get error: %s\n", s.ToString().c_str());
834
- is_consistent = false;
835
- } else if (!s.ok() && tmp_s.ok()) {
836
- fprintf(stderr,
837
- "MultiGet(%d) returned different results with key %s. "
838
- "Snapshot Seq No: %" PRIu64 "\n",
839
- column_family, key.ToString(true).c_str(),
840
- readoptionscopy.snapshot->GetSequenceNumber());
841
- fprintf(stderr, "Get returned ok, MultiGet returned not found\n");
842
- is_consistent = false;
843
- } else if (s.ok() && tmp_s.IsNotFound()) {
844
- fprintf(stderr,
845
- "MultiGet(%d) returned different results with key %s. "
846
- "Snapshot Seq No: %" PRIu64 "\n",
847
- column_family, key.ToString(true).c_str(),
848
- readoptionscopy.snapshot->GetSequenceNumber());
849
- fprintf(stderr, "MultiGet returned ok, Get returned not found\n");
850
- is_consistent = false;
851
- } else if (s.ok() && value != expected_value.ToString()) {
852
- fprintf(stderr,
853
- "MultiGet(%d) returned different results with key %s. "
854
- "Snapshot Seq No: %" PRIu64 "\n",
855
- column_family, key.ToString(true).c_str(),
856
- readoptionscopy.snapshot->GetSequenceNumber());
857
- fprintf(stderr, "MultiGet returned value %s\n",
858
- expected_value.ToString(true).c_str());
859
- fprintf(stderr, "Get returned value %s\n",
860
- Slice(value).ToString(true /* hex */).c_str());
861
- is_consistent = false;
862
- }
804
+ if (use_txn) {
805
+ assert(txn);
806
+ ThreadStatusUtil::SetThreadOperation(
807
+ ThreadStatus::OperationType::OP_GET);
808
+ tmp_s = txn->Get(readoptionscopy, cfh, key, &value);
809
+ ThreadStatusUtil::SetThreadOperation(
810
+ ThreadStatus::OperationType::OP_MULTIGET);
811
+ } else {
812
+ ThreadStatusUtil::SetThreadOperation(
813
+ ThreadStatus::OperationType::OP_GET);
814
+ tmp_s = db_->Get(readoptionscopy, cfh, key, &value);
815
+ ThreadStatusUtil::SetThreadOperation(
816
+ ThreadStatus::OperationType::OP_MULTIGET);
817
+ }
818
+ if (!tmp_s.ok() && !tmp_s.IsNotFound()) {
819
+ fprintf(stderr, "Get error: %s\n", s.ToString().c_str());
820
+ is_consistent = false;
821
+ } else if (!s.ok() && tmp_s.ok()) {
822
+ fprintf(stderr,
823
+ "MultiGet(%d) returned different results with key %s. "
824
+ "Snapshot Seq No: %" PRIu64 "\n",
825
+ column_family, key.ToString(true).c_str(),
826
+ readoptionscopy.snapshot->GetSequenceNumber());
827
+ fprintf(stderr, "Get returned ok, MultiGet returned not found\n");
828
+ is_consistent = false;
829
+ } else if (s.ok() && tmp_s.IsNotFound()) {
830
+ fprintf(stderr,
831
+ "MultiGet(%d) returned different results with key %s. "
832
+ "Snapshot Seq No: %" PRIu64 "\n",
833
+ column_family, key.ToString(true).c_str(),
834
+ readoptionscopy.snapshot->GetSequenceNumber());
835
+ fprintf(stderr, "MultiGet returned ok, Get returned not found\n");
836
+ is_consistent = false;
837
+ } else if (s.ok() && value != expected_value.ToString()) {
838
+ fprintf(stderr,
839
+ "MultiGet(%d) returned different results with key %s. "
840
+ "Snapshot Seq No: %" PRIu64 "\n",
841
+ column_family, key.ToString(true).c_str(),
842
+ readoptionscopy.snapshot->GetSequenceNumber());
843
+ fprintf(stderr, "MultiGet returned value %s\n",
844
+ expected_value.ToString(true).c_str());
845
+ fprintf(stderr, "Get returned value %s\n",
846
+ Slice(value).ToString(true /* hex */).c_str());
847
+ is_consistent = false;
863
848
  }
864
849
 
865
850
  // If test uses transaction, continue to do a read your own write check.
@@ -870,15 +855,15 @@ class NonBatchedOpsStressTest : public StressTest {
870
855
  if (!is_consistent) {
871
856
  fprintf(stderr, "TestMultiGet error: is_consistent is false\n");
872
857
  thread->stats.AddErrors(1);
858
+ check_multiget_res = false;
873
859
  // Fail fast to preserve the DB state
874
- thread->shared->SetVerificationFailure();
875
- return false;
860
+ shared->SetVerificationFailure();
876
861
  } else if (!is_ryw_correct) {
877
862
  fprintf(stderr, "TestMultiGet error: is_ryw_correct is false\n");
878
863
  thread->stats.AddErrors(1);
864
+ check_multiget_res = false;
879
865
  // Fail fast to preserve the DB state
880
- thread->shared->SetVerificationFailure();
881
- return false;
866
+ shared->SetVerificationFailure();
882
867
  } else if (s.ok()) {
883
868
  // found case
884
869
  thread->stats.AddGets(1, 1);
@@ -888,33 +873,46 @@ class NonBatchedOpsStressTest : public StressTest {
888
873
  } else if (s.IsMergeInProgress() && use_txn) {
889
874
  // With txn this is sometimes expected.
890
875
  thread->stats.AddGets(1, 1);
891
- } else {
892
- if (error_count == 0) {
893
- // errors case
894
- fprintf(stderr, "MultiGet error: %s\n", s.ToString().c_str());
895
- thread->stats.AddErrors(1);
896
- } else {
897
- thread->stats.AddVerifiedErrors(1);
898
- }
876
+ } else if (injected_error_count == 0 || !IsErrorInjectedAndRetryable(s)) {
877
+ fprintf(stderr, "MultiGet error: %s\n", s.ToString().c_str());
878
+ thread->stats.AddErrors(1);
879
+ shared->SetVerificationFailure();
899
880
  }
900
- return true;
901
- };
902
881
 
903
- size_t num_of_keys = keys.size();
904
- assert(values.size() == num_of_keys);
905
- assert(statuses.size() == num_of_keys);
906
- for (size_t i = 0; i < num_of_keys; ++i) {
907
- bool check_result = true;
908
- if (use_txn) {
909
- assert(ryw_expected_values.size() == num_of_keys);
910
- check_result = check_multiget(keys[i], values[i], statuses[i],
911
- ryw_expected_values[i]);
912
- } else {
913
- check_result = check_multiget(keys[i], values[i], statuses[i],
914
- std::nullopt /* ryw_expected_value */);
882
+ // Enable back error injection disbled for checking results
883
+ if (fault_fs_guard) {
884
+ fault_fs_guard->DisableThreadLocalErrorInjection(
885
+ FaultInjectionIOType::kRead);
886
+ fault_fs_guard->DisableThreadLocalErrorInjection(
887
+ FaultInjectionIOType::kMetadataRead);
915
888
  }
916
- if (!check_result) {
917
- break;
889
+ return check_multiget_res;
890
+ };
891
+
892
+ // Consistency check
893
+ if (do_consistency_check && injected_error_count == 0) {
894
+ size_t num_of_keys = keys.size();
895
+ assert(values.size() == num_of_keys);
896
+ assert(statuses.size() == num_of_keys);
897
+ for (size_t i = 0; i < num_of_keys; ++i) {
898
+ bool check_result = true;
899
+ if (use_txn) {
900
+ std::optional<ExpectedValue> ryw_expected_value;
901
+
902
+ const auto it = ryw_expected_values.find(key_str[i]);
903
+ if (it != ryw_expected_values.end()) {
904
+ ryw_expected_value = it->second;
905
+ }
906
+
907
+ check_result = check_multiget(keys[i], values[i], statuses[i],
908
+ ryw_expected_value);
909
+ } else {
910
+ check_result = check_multiget(keys[i], values[i], statuses[i],
911
+ std::nullopt /* ryw_expected_value */);
912
+ }
913
+ if (!check_result) {
914
+ break;
915
+ }
918
916
  }
919
917
  }
920
918
 
@@ -923,6 +921,13 @@ class NonBatchedOpsStressTest : public StressTest {
923
921
  }
924
922
  if (use_txn) {
925
923
  txn->Rollback().PermitUncheckedError();
924
+ // Enable back error injection disbled for transactions
925
+ if (fault_fs_guard) {
926
+ fault_fs_guard->EnableThreadLocalErrorInjection(
927
+ FaultInjectionIOType::kRead);
928
+ fault_fs_guard->EnableThreadLocalErrorInjection(
929
+ FaultInjectionIOType::kMetadataRead);
930
+ }
926
931
  }
927
932
  return statuses;
928
933
  }
@@ -930,29 +935,25 @@ class NonBatchedOpsStressTest : public StressTest {
930
935
  void TestGetEntity(ThreadState* thread, const ReadOptions& read_opts,
931
936
  const std::vector<int>& rand_column_families,
932
937
  const std::vector<int64_t>& rand_keys) override {
933
- if (fault_fs_guard) {
934
- fault_fs_guard->EnableErrorInjection();
935
- SharedState::ignore_read_error = false;
936
- }
937
-
938
938
  assert(thread);
939
939
 
940
940
  SharedState* const shared = thread->shared;
941
941
  assert(shared);
942
942
 
943
943
  assert(!rand_column_families.empty());
944
- assert(!rand_keys.empty());
945
944
 
946
- std::unique_ptr<MutexLock> lock(new MutexLock(
947
- shared->GetMutexForKey(rand_column_families[0], rand_keys[0])));
945
+ const int column_family = rand_column_families[0];
948
946
 
949
- assert(rand_column_families[0] >= 0);
950
- assert(rand_column_families[0] < static_cast<int>(column_families_.size()));
947
+ assert(column_family >= 0);
948
+ assert(column_family < static_cast<int>(column_families_.size()));
951
949
 
952
- ColumnFamilyHandle* const cfh = column_families_[rand_column_families[0]];
950
+ ColumnFamilyHandle* const cfh = column_families_[column_family];
953
951
  assert(cfh);
954
952
 
955
- const std::string key = Key(rand_keys[0]);
953
+ assert(!rand_keys.empty());
954
+
955
+ const int64_t key = rand_keys[0];
956
+ const std::string key_str = Key(key);
956
957
 
957
958
  PinnableWideColumns columns_from_db;
958
959
  PinnableAttributeGroups attribute_groups_from_db;
@@ -965,39 +966,57 @@ class NonBatchedOpsStressTest : public StressTest {
965
966
  read_ts_slice = read_ts_str;
966
967
  read_opts_copy.timestamp = &read_ts_slice;
967
968
  }
968
- bool read_older_ts = MaybeUseOlderTimestampForPointLookup(
969
+ const bool read_older_ts = MaybeUseOlderTimestampForPointLookup(
969
970
  thread, read_ts_str, read_ts_slice, read_opts_copy);
970
971
 
972
+ const ExpectedValue pre_read_expected_value =
973
+ thread->shared->Get(column_family, key);
974
+
975
+ if (fault_fs_guard) {
976
+ fault_fs_guard->GetAndResetInjectedThreadLocalErrorCount(
977
+ FaultInjectionIOType::kRead);
978
+ fault_fs_guard->GetAndResetInjectedThreadLocalErrorCount(
979
+ FaultInjectionIOType::kMetadataRead);
980
+ SharedState::ignore_read_error = false;
981
+ }
982
+
971
983
  Status s;
972
984
  if (FLAGS_use_attribute_group) {
973
985
  attribute_groups_from_db.emplace_back(cfh);
974
- s = db_->GetEntity(read_opts_copy, key, &attribute_groups_from_db);
986
+ s = db_->GetEntity(read_opts_copy, key_str, &attribute_groups_from_db);
975
987
  if (s.ok()) {
976
988
  s = attribute_groups_from_db.back().status();
977
989
  }
978
990
  } else {
979
- s = db_->GetEntity(read_opts_copy, cfh, key, &columns_from_db);
991
+ s = db_->GetEntity(read_opts_copy, cfh, key_str, &columns_from_db);
980
992
  }
981
993
 
982
- int error_count = 0;
994
+ const ExpectedValue post_read_expected_value =
995
+ thread->shared->Get(column_family, key);
983
996
 
997
+ int injected_error_count = 0;
984
998
  if (fault_fs_guard) {
985
- error_count = fault_fs_guard->GetAndResetErrorCount();
999
+ injected_error_count = GetMinInjectedErrorCount(
1000
+ fault_fs_guard->GetAndResetInjectedThreadLocalErrorCount(
1001
+ FaultInjectionIOType::kRead),
1002
+ fault_fs_guard->GetAndResetInjectedThreadLocalErrorCount(
1003
+ FaultInjectionIOType::kMetadataRead));
1004
+ if (!SharedState::ignore_read_error && injected_error_count > 0 &&
1005
+ (s.ok() || s.IsNotFound())) {
1006
+ // Grab mutex so multiple thread don't try to print the
1007
+ // stack trace at the same time
1008
+ MutexLock l(thread->shared->GetMutex());
1009
+ fprintf(stderr, "Didn't get expected error from GetEntity\n");
1010
+ fprintf(stderr, "Callstack that injected the fault\n");
1011
+ fault_fs_guard->PrintInjectedThreadLocalErrorBacktrace(
1012
+ FaultInjectionIOType::kRead);
1013
+ fault_fs_guard->PrintInjectedThreadLocalErrorBacktrace(
1014
+ FaultInjectionIOType::kMetadataRead);
1015
+ std::terminate();
1016
+ }
986
1017
  }
987
1018
 
988
1019
  if (s.ok()) {
989
- if (fault_fs_guard) {
990
- if (error_count && !SharedState::ignore_read_error) {
991
- // Grab mutex so multiple threads don't try to print the
992
- // stack trace at the same time
993
- MutexLock l(shared->GetMutex());
994
- fprintf(stderr, "Didn't get expected error from GetEntity\n");
995
- fprintf(stderr, "Call stack that injected the fault\n");
996
- fault_fs_guard->PrintFaultBacktrace();
997
- std::terminate();
998
- }
999
- }
1000
-
1001
1020
  thread->stats.AddGets(1, 1);
1002
1021
 
1003
1022
  if (!FLAGS_skip_verifydb && !read_older_ts) {
@@ -1008,48 +1027,55 @@ class NonBatchedOpsStressTest : public StressTest {
1008
1027
  FLAGS_use_attribute_group
1009
1028
  ? attribute_groups_from_db.back().columns()
1010
1029
  : columns_from_db.columns();
1011
- ExpectedValue expected =
1012
- shared->Get(rand_column_families[0], rand_keys[0]);
1013
1030
  if (!VerifyWideColumns(columns)) {
1014
1031
  shared->SetVerificationFailure();
1015
1032
  fprintf(stderr,
1016
1033
  "error : inconsistent columns returned by GetEntity for key "
1017
1034
  "%s: %s\n",
1018
- StringToHex(key).c_str(), WideColumnsToHex(columns).c_str());
1019
- } else if (ExpectedValueHelper::MustHaveNotExisted(expected,
1020
- expected)) {
1035
+ StringToHex(key_str).c_str(),
1036
+ WideColumnsToHex(columns).c_str());
1037
+ } else if (ExpectedValueHelper::MustHaveNotExisted(
1038
+ pre_read_expected_value, post_read_expected_value)) {
1021
1039
  shared->SetVerificationFailure();
1022
1040
  fprintf(
1023
1041
  stderr,
1024
1042
  "error : inconsistent values for key %s: GetEntity returns %s, "
1025
1043
  "expected state does not have the key.\n",
1026
- StringToHex(key).c_str(), WideColumnsToHex(columns).c_str());
1044
+ StringToHex(key_str).c_str(), WideColumnsToHex(columns).c_str());
1045
+ } else {
1046
+ const uint32_t value_base_from_db =
1047
+ GetValueBase(WideColumnsHelper::GetDefaultColumn(columns));
1048
+ if (!ExpectedValueHelper::InExpectedValueBaseRange(
1049
+ value_base_from_db, pre_read_expected_value,
1050
+ post_read_expected_value)) {
1051
+ shared->SetVerificationFailure();
1052
+ fprintf(
1053
+ stderr,
1054
+ "error : inconsistent values for key %s: GetEntity returns %s "
1055
+ "with value base %d that falls out of expected state's value "
1056
+ "base range.\n",
1057
+ StringToHex(key_str).c_str(), WideColumnsToHex(columns).c_str(),
1058
+ value_base_from_db);
1059
+ }
1027
1060
  }
1028
1061
  }
1029
1062
  } else if (s.IsNotFound()) {
1030
1063
  thread->stats.AddGets(1, 0);
1031
1064
 
1032
1065
  if (!FLAGS_skip_verifydb && !read_older_ts) {
1033
- ExpectedValue expected =
1034
- shared->Get(rand_column_families[0], rand_keys[0]);
1035
- if (ExpectedValueHelper::MustHaveExisted(expected, expected)) {
1066
+ if (ExpectedValueHelper::MustHaveExisted(pre_read_expected_value,
1067
+ post_read_expected_value)) {
1036
1068
  shared->SetVerificationFailure();
1037
1069
  fprintf(stderr,
1038
1070
  "error : inconsistent values for key %s: expected state has "
1039
1071
  "the key, GetEntity returns NotFound.\n",
1040
- StringToHex(key).c_str());
1072
+ StringToHex(key_str).c_str());
1041
1073
  }
1042
1074
  }
1043
- } else {
1044
- if (error_count == 0) {
1045
- thread->stats.AddErrors(1);
1046
- } else {
1047
- thread->stats.AddVerifiedErrors(1);
1048
- }
1049
- }
1050
-
1051
- if (fault_fs_guard) {
1052
- fault_fs_guard->DisableErrorInjection();
1075
+ } else if (injected_error_count == 0 || !IsErrorInjectedAndRetryable(s)) {
1076
+ fprintf(stderr, "error : GetEntity() returns %s for key: %s.\n",
1077
+ s.ToString().c_str(), StringToHex(key_str).c_str());
1078
+ thread->shared->SetVerificationFailure();
1053
1079
  }
1054
1080
  }
1055
1081
 
@@ -1064,272 +1090,347 @@ class NonBatchedOpsStressTest : public StressTest {
1064
1090
  read_opts_copy.snapshot = snapshot_guard.snapshot();
1065
1091
 
1066
1092
  assert(!rand_column_families.empty());
1067
- assert(rand_column_families[0] >= 0);
1068
- assert(rand_column_families[0] < static_cast<int>(column_families_.size()));
1069
1093
 
1070
- ColumnFamilyHandle* const cfh = column_families_[rand_column_families[0]];
1094
+ const int column_family = rand_column_families[0];
1095
+
1096
+ assert(column_family >= 0);
1097
+ assert(column_family < static_cast<int>(column_families_.size()));
1098
+
1099
+ ColumnFamilyHandle* const cfh = column_families_[column_family];
1071
1100
  assert(cfh);
1072
1101
 
1073
1102
  assert(!rand_keys.empty());
1074
1103
 
1075
1104
  const size_t num_keys = rand_keys.size();
1076
1105
 
1077
- std::vector<std::string> keys(num_keys);
1078
- std::vector<Slice> key_slices(num_keys);
1106
+ std::unique_ptr<Transaction> txn;
1079
1107
 
1080
- if (fault_fs_guard) {
1081
- fault_fs_guard->EnableErrorInjection();
1082
- SharedState::ignore_read_error = false;
1083
- }
1108
+ if (FLAGS_use_txn) {
1109
+ // TODO(hx235): test fault injection with MultiGetEntity() with
1110
+ // transactions
1111
+ if (fault_fs_guard) {
1112
+ fault_fs_guard->DisableThreadLocalErrorInjection(
1113
+ FaultInjectionIOType::kRead);
1114
+ fault_fs_guard->DisableThreadLocalErrorInjection(
1115
+ FaultInjectionIOType::kMetadataRead);
1116
+ }
1117
+ WriteOptions write_options;
1118
+ if (FLAGS_rate_limit_auto_wal_flush) {
1119
+ write_options.rate_limiter_priority = Env::IO_USER;
1120
+ }
1084
1121
 
1085
- for (size_t i = 0; i < num_keys; ++i) {
1086
- keys[i] = Key(rand_keys[i]);
1087
- key_slices[i] = keys[i];
1122
+ const Status s = NewTxn(write_options, &txn);
1123
+ if (!s.ok()) {
1124
+ fprintf(stderr, "NewTxn error: %s\n", s.ToString().c_str());
1125
+ thread->shared->SafeTerminate();
1126
+ }
1088
1127
  }
1089
1128
 
1090
- int error_count = 0;
1129
+ std::vector<std::string> keys(num_keys);
1130
+ std::vector<Slice> key_slices(num_keys);
1131
+ std::unordered_map<std::string, ExpectedValue> ryw_expected_values;
1091
1132
 
1092
- auto handle_result = [](ThreadState* _thread, const Status& s,
1093
- bool is_consistent, int err_count) {
1094
- if (!is_consistent) {
1095
- fprintf(stderr,
1096
- "TestMultiGetEntity%s error: results are not consistent\n",
1097
- FLAGS_use_attribute_group ? "(AttributeGroup)" : "");
1098
- _thread->stats.AddErrors(1);
1099
- // Fail fast to preserve the DB state
1100
- _thread->shared->SetVerificationFailure();
1101
- } else if (s.ok()) {
1102
- _thread->stats.AddGets(1, 1);
1103
- } else if (s.IsNotFound()) {
1104
- _thread->stats.AddGets(1, 0);
1105
- } else {
1106
- if (err_count == 0) {
1107
- fprintf(stderr, "MultiGetEntity%s error: %s\n",
1108
- FLAGS_use_attribute_group ? "(AttributeGroup)" : "",
1109
- s.ToString().c_str());
1110
- _thread->stats.AddErrors(1);
1111
- } else {
1112
- _thread->stats.AddVerifiedErrors(1);
1113
- }
1114
- }
1115
- };
1133
+ for (size_t i = 0; i < num_keys; ++i) {
1134
+ const int64_t key = rand_keys[i];
1116
1135
 
1117
- if (FLAGS_use_attribute_group) {
1118
- // AttributeGroup MultiGetEntity verification
1136
+ keys[i] = Key(key);
1137
+ key_slices[i] = keys[i];
1119
1138
 
1120
- std::vector<PinnableAttributeGroups> results;
1121
- results.reserve(num_keys);
1122
- for (size_t i = 0; i < num_keys; ++i) {
1123
- PinnableAttributeGroups attribute_groups;
1124
- attribute_groups.emplace_back(cfh);
1125
- results.emplace_back(std::move(attribute_groups));
1139
+ if (FLAGS_use_txn) {
1140
+ MaybeAddKeyToTxnForRYW(thread, column_family, key, txn.get(),
1141
+ ryw_expected_values);
1126
1142
  }
1127
- db_->MultiGetEntity(read_opts_copy, num_keys, key_slices.data(),
1128
- results.data());
1143
+ }
1129
1144
 
1130
- if (fault_fs_guard) {
1131
- error_count = fault_fs_guard->GetAndResetErrorCount();
1145
+ int injected_error_count = 0;
1132
1146
 
1133
- if (error_count && !SharedState::ignore_read_error) {
1134
- int stat_nok = 0;
1135
- for (size_t i = 0; i < num_keys; ++i) {
1136
- const Status& s = results[i][0].status();
1137
- if (!s.ok() && !s.IsNotFound()) {
1138
- stat_nok++;
1139
- }
1147
+ auto verify_expected_errors = [&](auto get_status) {
1148
+ assert(fault_fs_guard);
1149
+ injected_error_count = GetMinInjectedErrorCount(
1150
+ fault_fs_guard->GetAndResetInjectedThreadLocalErrorCount(
1151
+ FaultInjectionIOType::kRead),
1152
+ fault_fs_guard->GetAndResetInjectedThreadLocalErrorCount(
1153
+ FaultInjectionIOType::kMetadataRead));
1154
+ if (injected_error_count) {
1155
+ int stat_nok_nfound = 0;
1156
+ for (size_t i = 0; i < num_keys; ++i) {
1157
+ const Status& s = get_status(i);
1158
+ if (!s.ok() && !s.IsNotFound()) {
1159
+ ++stat_nok_nfound;
1140
1160
  }
1161
+ }
1141
1162
 
1142
- if (stat_nok < error_count) {
1143
- // Grab mutex so multiple threads don't try to print the
1144
- // stack trace at the same time
1145
- assert(thread->shared);
1146
- MutexLock l(thread->shared->GetMutex());
1163
+ if (!SharedState::ignore_read_error &&
1164
+ stat_nok_nfound < injected_error_count) {
1165
+ // Grab mutex so multiple threads don't try to print the
1166
+ // stack trace at the same time
1167
+ assert(thread->shared);
1168
+ MutexLock l(thread->shared->GetMutex());
1147
1169
 
1148
- fprintf(stderr,
1149
- "Didn't get expected error from MultiGetEntity "
1150
- "(AttributeGroup)\n");
1151
- fprintf(stderr, "num_keys %zu Expected %d errors, seen %d\n",
1152
- num_keys, error_count, stat_nok);
1153
- fprintf(stderr, "Call stack that injected the fault\n");
1154
- fault_fs_guard->PrintFaultBacktrace();
1155
- std::terminate();
1156
- }
1170
+ fprintf(stderr, "Didn't get expected error from MultiGetEntity\n");
1171
+ fprintf(stderr, "num_keys %zu Expected %d errors, seen %d\n",
1172
+ num_keys, injected_error_count, stat_nok_nfound);
1173
+ fprintf(stderr, "Call stack that injected the fault\n");
1174
+ fault_fs_guard->PrintInjectedThreadLocalErrorBacktrace(
1175
+ FaultInjectionIOType::kRead);
1176
+ fault_fs_guard->PrintInjectedThreadLocalErrorBacktrace(
1177
+ FaultInjectionIOType::kMetadataRead);
1178
+ std::terminate();
1157
1179
  }
1158
- fault_fs_guard->DisableErrorInjection();
1159
1180
  }
1181
+ };
1160
1182
 
1161
- // Compare against non-attribute-group GetEntity result
1183
+ auto check_results = [&](auto get_columns, auto get_status,
1184
+ auto do_extra_check, auto call_get_entity) {
1185
+ // Temporarily disable error injection for checking results
1186
+ if (fault_fs_guard) {
1187
+ fault_fs_guard->DisableThreadLocalErrorInjection(
1188
+ FaultInjectionIOType::kRead);
1189
+ fault_fs_guard->DisableThreadLocalErrorInjection(
1190
+ FaultInjectionIOType::kMetadataRead);
1191
+ }
1162
1192
  const bool check_get_entity =
1163
- !error_count && FLAGS_check_multiget_entity_consistency;
1193
+ !injected_error_count && FLAGS_check_multiget_entity_consistency;
1164
1194
 
1165
1195
  for (size_t i = 0; i < num_keys; ++i) {
1166
- assert(results[i].size() == 1);
1167
- const Status& s = results[i][0].status();
1196
+ const WideColumns& columns = get_columns(i);
1197
+ const Status& s = get_status(i);
1168
1198
 
1169
1199
  bool is_consistent = true;
1170
1200
 
1171
- if (s.ok() && !VerifyWideColumns(results[i][0].columns())) {
1172
- fprintf(stderr,
1173
- "error : inconsistent columns returned by MultiGetEntity "
1174
- "(AttributeGroup) for key "
1175
- "%s: %s\n",
1176
- StringToHex(keys[i]).c_str(),
1177
- WideColumnsToHex(results[i][0].columns()).c_str());
1201
+ if (s.ok() && !VerifyWideColumns(columns)) {
1202
+ fprintf(
1203
+ stderr,
1204
+ "error : inconsistent columns returned by MultiGetEntity for key "
1205
+ "%s: %s\n",
1206
+ StringToHex(keys[i]).c_str(), WideColumnsToHex(columns).c_str());
1178
1207
  is_consistent = false;
1179
- } else if (check_get_entity && (s.ok() || s.IsNotFound())) {
1180
- PinnableWideColumns cmp_result;
1181
- ThreadStatusUtil::SetThreadOperation(
1182
- ThreadStatus::OperationType::OP_GETENTITY);
1183
- const Status cmp_s =
1184
- db_->GetEntity(read_opts_copy, cfh, key_slices[i], &cmp_result);
1185
-
1186
- if (!cmp_s.ok() && !cmp_s.IsNotFound()) {
1187
- fprintf(stderr, "GetEntity error: %s\n", cmp_s.ToString().c_str());
1208
+ } else if (s.ok() || s.IsNotFound()) {
1209
+ if (!do_extra_check(keys[i], columns, s)) {
1188
1210
  is_consistent = false;
1189
- } else if (cmp_s.IsNotFound()) {
1190
- if (s.ok()) {
1191
- fprintf(stderr,
1192
- "Inconsistent results for key %s: MultiGetEntity "
1193
- "(AttributeGroup) returned "
1194
- "ok, GetEntity returned not found\n",
1195
- StringToHex(keys[i]).c_str());
1196
- is_consistent = false;
1197
- }
1198
- } else {
1199
- assert(cmp_s.ok());
1200
-
1201
- if (s.IsNotFound()) {
1202
- fprintf(stderr,
1203
- "Inconsistent results for key %s: MultiGetEntity "
1204
- "(AttributeGroup) returned "
1205
- "not found, GetEntity returned ok\n",
1206
- StringToHex(keys[i]).c_str());
1211
+ } else if (check_get_entity) {
1212
+ PinnableWideColumns cmp_result;
1213
+ ThreadStatusUtil::SetThreadOperation(
1214
+ ThreadStatus::OperationType::OP_GETENTITY);
1215
+ const Status cmp_s = call_get_entity(key_slices[i], &cmp_result);
1216
+
1217
+ if (!cmp_s.ok() && !cmp_s.IsNotFound()) {
1218
+ fprintf(stderr, "GetEntity error: %s\n",
1219
+ cmp_s.ToString().c_str());
1207
1220
  is_consistent = false;
1221
+ } else if (cmp_s.IsNotFound()) {
1222
+ if (s.ok()) {
1223
+ fprintf(
1224
+ stderr,
1225
+ "Inconsistent results for key %s: MultiGetEntity returned "
1226
+ "ok, GetEntity returned not found\n",
1227
+ StringToHex(keys[i]).c_str());
1228
+ is_consistent = false;
1229
+ }
1208
1230
  } else {
1209
- assert(s.ok());
1210
-
1211
- if (results[i][0].columns() != cmp_result.columns()) {
1212
- fprintf(stderr,
1213
- "Inconsistent results for key %s: MultiGetEntity "
1214
- "(AttributeGroup) returned "
1215
- "%s, GetEntity returned %s\n",
1216
- StringToHex(keys[i]).c_str(),
1217
- WideColumnsToHex(results[i][0].columns()).c_str(),
1218
- WideColumnsToHex(cmp_result.columns()).c_str());
1231
+ assert(cmp_s.ok());
1232
+
1233
+ if (s.IsNotFound()) {
1234
+ fprintf(
1235
+ stderr,
1236
+ "Inconsistent results for key %s: MultiGetEntity returned "
1237
+ "not found, GetEntity returned ok\n",
1238
+ StringToHex(keys[i]).c_str());
1219
1239
  is_consistent = false;
1240
+ } else {
1241
+ assert(s.ok());
1242
+
1243
+ const WideColumns& cmp_columns = cmp_result.columns();
1244
+
1245
+ if (columns != cmp_columns) {
1246
+ fprintf(stderr,
1247
+ "Inconsistent results for key %s: MultiGetEntity "
1248
+ "returned "
1249
+ "%s, GetEntity returned %s\n",
1250
+ StringToHex(keys[i]).c_str(),
1251
+ WideColumnsToHex(columns).c_str(),
1252
+ WideColumnsToHex(cmp_columns).c_str());
1253
+ is_consistent = false;
1254
+ }
1220
1255
  }
1221
1256
  }
1222
1257
  }
1223
1258
  }
1224
- handle_result(thread, s, is_consistent, error_count);
1259
+
1225
1260
  if (!is_consistent) {
1261
+ fprintf(stderr,
1262
+ "TestMultiGetEntity error: results are not consistent\n");
1263
+ thread->stats.AddErrors(1);
1264
+ // Fail fast to preserve the DB state
1265
+ thread->shared->SetVerificationFailure();
1226
1266
  break;
1267
+ } else if (s.ok()) {
1268
+ thread->stats.AddGets(1, 1);
1269
+ } else if (s.IsNotFound()) {
1270
+ thread->stats.AddGets(1, 0);
1271
+ } else if (injected_error_count == 0 ||
1272
+ !IsErrorInjectedAndRetryable(s)) {
1273
+ fprintf(stderr, "MultiGetEntity error: %s\n", s.ToString().c_str());
1274
+ thread->stats.AddErrors(1);
1275
+ thread->shared->SetVerificationFailure();
1227
1276
  }
1228
1277
  }
1229
- } else {
1230
- // Non-AttributeGroup MultiGetEntity verification
1278
+ // Enable back error injection disbled for checking results
1279
+ if (fault_fs_guard) {
1280
+ fault_fs_guard->EnableThreadLocalErrorInjection(
1281
+ FaultInjectionIOType::kRead);
1282
+ fault_fs_guard->EnableThreadLocalErrorInjection(
1283
+ FaultInjectionIOType::kMetadataRead);
1284
+ }
1285
+ };
1231
1286
 
1287
+ if (FLAGS_use_txn) {
1288
+ // Transactional/read-your-own-writes MultiGetEntity verification
1232
1289
  std::vector<PinnableWideColumns> results(num_keys);
1233
1290
  std::vector<Status> statuses(num_keys);
1234
1291
 
1235
- db_->MultiGetEntity(read_opts_copy, cfh, num_keys, key_slices.data(),
1292
+ assert(txn);
1293
+ txn->MultiGetEntity(read_opts_copy, cfh, num_keys, key_slices.data(),
1236
1294
  results.data(), statuses.data());
1237
1295
 
1238
- if (fault_fs_guard) {
1239
- error_count = fault_fs_guard->GetAndResetErrorCount();
1296
+ auto ryw_check = [&](const std::string& key, const WideColumns& columns,
1297
+ const Status& s) -> bool {
1298
+ const auto it = ryw_expected_values.find(key);
1299
+ if (it == ryw_expected_values.end()) {
1300
+ return true;
1301
+ }
1240
1302
 
1241
- if (error_count && !SharedState::ignore_read_error) {
1242
- int stat_nok = 0;
1243
- for (const auto& s : statuses) {
1244
- if (!s.ok() && !s.IsNotFound()) {
1245
- stat_nok++;
1303
+ const auto& ryw_expected_value = it->second;
1304
+
1305
+ if (s.ok()) {
1306
+ if (ryw_expected_value.IsDeleted()) {
1307
+ fprintf(
1308
+ stderr,
1309
+ "MultiGetEntity failed the read-your-own-write check for key "
1310
+ "%s\n",
1311
+ Slice(key).ToString(true).c_str());
1312
+ fprintf(stderr,
1313
+ "MultiGetEntity returned ok, transaction has non-committed "
1314
+ "delete\n");
1315
+ return false;
1316
+ } else {
1317
+ const uint32_t value_base = ryw_expected_value.GetValueBase();
1318
+ char expected_value[100];
1319
+ const size_t sz = GenerateValue(value_base, expected_value,
1320
+ sizeof(expected_value));
1321
+ const Slice expected_slice(expected_value, sz);
1322
+ const WideColumns expected_columns =
1323
+ GenerateExpectedWideColumns(value_base, expected_slice);
1324
+
1325
+ if (columns != expected_columns) {
1326
+ fprintf(
1327
+ stderr,
1328
+ "MultiGetEntity failed the read-your-own-write check for key "
1329
+ "%s\n",
1330
+ Slice(key).ToString(true).c_str());
1331
+ fprintf(stderr, "MultiGetEntity returned %s\n",
1332
+ WideColumnsToHex(columns).c_str());
1333
+ fprintf(stderr, "Transaction has non-committed write %s\n",
1334
+ WideColumnsToHex(expected_columns).c_str());
1335
+ return false;
1246
1336
  }
1247
- }
1248
1337
 
1249
- if (stat_nok < error_count) {
1250
- // Grab mutex so multiple threads don't try to print the
1251
- // stack trace at the same time
1252
- assert(thread->shared);
1253
- MutexLock l(thread->shared->GetMutex());
1254
-
1255
- fprintf(stderr, "Didn't get expected error from MultiGetEntity\n");
1256
- fprintf(stderr, "num_keys %zu Expected %d errors, seen %d\n",
1257
- num_keys, error_count, stat_nok);
1258
- fprintf(stderr, "Call stack that injected the fault\n");
1259
- fault_fs_guard->PrintFaultBacktrace();
1260
- std::terminate();
1338
+ return true;
1261
1339
  }
1262
1340
  }
1263
1341
 
1264
- fault_fs_guard->DisableErrorInjection();
1342
+ assert(s.IsNotFound());
1343
+ if (!ryw_expected_value.IsDeleted()) {
1344
+ fprintf(stderr,
1345
+ "MultiGetEntity failed the read-your-own-write check for key "
1346
+ "%s\n",
1347
+ Slice(key).ToString(true).c_str());
1348
+ fprintf(stderr,
1349
+ "MultiGetEntity returned not found, transaction has "
1350
+ "non-committed write\n");
1351
+ return false;
1352
+ }
1353
+
1354
+ return true;
1355
+ };
1356
+
1357
+ check_results([&](size_t i) { return results[i].columns(); },
1358
+ [&](size_t i) { return statuses[i]; }, ryw_check,
1359
+ [&](const Slice& key, PinnableWideColumns* result) {
1360
+ return txn->GetEntity(read_opts_copy, cfh, key, result);
1361
+ });
1362
+
1363
+ txn->Rollback().PermitUncheckedError();
1364
+ // Enable back error injection disbled for transactions
1365
+ if (fault_fs_guard) {
1366
+ fault_fs_guard->EnableThreadLocalErrorInjection(
1367
+ FaultInjectionIOType::kRead);
1368
+ fault_fs_guard->EnableThreadLocalErrorInjection(
1369
+ FaultInjectionIOType::kMetadataRead);
1265
1370
  }
1371
+ } else if (FLAGS_use_attribute_group) {
1372
+ // AttributeGroup MultiGetEntity verification
1266
1373
 
1267
- const bool check_get_entity =
1268
- !error_count && FLAGS_check_multiget_entity_consistency;
1374
+ if (fault_fs_guard) {
1375
+ fault_fs_guard->GetAndResetInjectedThreadLocalErrorCount(
1376
+ FaultInjectionIOType::kRead);
1377
+ fault_fs_guard->GetAndResetInjectedThreadLocalErrorCount(
1378
+ FaultInjectionIOType::kMetadataRead);
1379
+ SharedState::ignore_read_error = false;
1380
+ }
1269
1381
 
1382
+ std::vector<PinnableAttributeGroups> results;
1383
+ results.reserve(num_keys);
1270
1384
  for (size_t i = 0; i < num_keys; ++i) {
1271
- const Status& s = statuses[i];
1385
+ PinnableAttributeGroups attribute_groups;
1386
+ attribute_groups.emplace_back(cfh);
1387
+ results.emplace_back(std::move(attribute_groups));
1388
+ }
1272
1389
 
1273
- bool is_consistent = true;
1390
+ db_->MultiGetEntity(read_opts_copy, num_keys, key_slices.data(),
1391
+ results.data());
1274
1392
 
1275
- if (s.ok() && !VerifyWideColumns(results[i].columns())) {
1276
- fprintf(
1277
- stderr,
1278
- "error : inconsistent columns returned by MultiGetEntity for key "
1279
- "%s: %s\n",
1280
- StringToHex(keys[i]).c_str(),
1281
- WideColumnsToHex(results[i].columns()).c_str());
1282
- is_consistent = false;
1283
- } else if (check_get_entity && (s.ok() || s.IsNotFound())) {
1284
- PinnableWideColumns cmp_result;
1285
- ThreadStatusUtil::SetThreadOperation(
1286
- ThreadStatus::OperationType::OP_GETENTITY);
1287
- const Status cmp_s =
1288
- db_->GetEntity(read_opts_copy, cfh, key_slices[i], &cmp_result);
1289
-
1290
- if (!cmp_s.ok() && !cmp_s.IsNotFound()) {
1291
- fprintf(stderr, "GetEntity error: %s\n", cmp_s.ToString().c_str());
1292
- is_consistent = false;
1293
- } else if (cmp_s.IsNotFound()) {
1294
- if (s.ok()) {
1295
- fprintf(
1296
- stderr,
1297
- "Inconsistent results for key %s: MultiGetEntity returned "
1298
- "ok, GetEntity returned not found\n",
1299
- StringToHex(keys[i]).c_str());
1300
- is_consistent = false;
1301
- }
1302
- } else {
1303
- assert(cmp_s.ok());
1393
+ if (fault_fs_guard) {
1394
+ verify_expected_errors(
1395
+ [&](size_t i) { return results[i][0].status(); });
1396
+ }
1304
1397
 
1305
- if (s.IsNotFound()) {
1306
- fprintf(
1307
- stderr,
1308
- "Inconsistent results for key %s: MultiGetEntity returned "
1309
- "not found, GetEntity returned ok\n",
1310
- StringToHex(keys[i]).c_str());
1311
- is_consistent = false;
1312
- } else {
1313
- assert(s.ok());
1398
+ // Compare against non-attribute-group GetEntity result
1399
+ check_results([&](size_t i) { return results[i][0].columns(); },
1400
+ [&](size_t i) { return results[i][0].status(); },
1401
+ [](const Slice& /* key */, const WideColumns& /* columns */,
1402
+ const Status& /* s */) { return true; },
1403
+ [&](const Slice& key, PinnableWideColumns* result) {
1404
+ return db_->GetEntity(read_opts_copy, cfh, key, result);
1405
+ });
1406
+ } else {
1407
+ // Non-AttributeGroup MultiGetEntity verification
1314
1408
 
1315
- if (results[i] != cmp_result) {
1316
- fprintf(
1317
- stderr,
1318
- "Inconsistent results for key %s: MultiGetEntity returned "
1319
- "%s, GetEntity returned %s\n",
1320
- StringToHex(keys[i]).c_str(),
1321
- WideColumnsToHex(results[i].columns()).c_str(),
1322
- WideColumnsToHex(cmp_result.columns()).c_str());
1323
- is_consistent = false;
1324
- }
1325
- }
1326
- }
1327
- }
1328
- handle_result(thread, s, is_consistent, error_count);
1329
- if (!is_consistent) {
1330
- break;
1331
- }
1409
+ if (fault_fs_guard) {
1410
+ fault_fs_guard->GetAndResetInjectedThreadLocalErrorCount(
1411
+ FaultInjectionIOType::kRead);
1412
+ fault_fs_guard->GetAndResetInjectedThreadLocalErrorCount(
1413
+ FaultInjectionIOType::kMetadataRead);
1414
+ SharedState::ignore_read_error = false;
1332
1415
  }
1416
+
1417
+ std::vector<PinnableWideColumns> results(num_keys);
1418
+ std::vector<Status> statuses(num_keys);
1419
+
1420
+ db_->MultiGetEntity(read_opts_copy, cfh, num_keys, key_slices.data(),
1421
+ results.data(), statuses.data());
1422
+
1423
+ if (fault_fs_guard) {
1424
+ verify_expected_errors([&](size_t i) { return statuses[i]; });
1425
+ }
1426
+
1427
+ check_results([&](size_t i) { return results[i].columns(); },
1428
+ [&](size_t i) { return statuses[i]; },
1429
+ [](const Slice& /* key */, const WideColumns& /* columns */,
1430
+ const Status& /* s */) { return true; },
1431
+ [&](const Slice& key, PinnableWideColumns* result) {
1432
+ return db_->GetEntity(read_opts_copy, cfh, key, result);
1433
+ });
1333
1434
  }
1334
1435
  }
1335
1436
 
@@ -1355,6 +1456,10 @@ class NonBatchedOpsStressTest : public StressTest {
1355
1456
  // For half of the time, set the upper bound to the next prefix
1356
1457
  ub_slice = Slice(upper_bound);
1357
1458
  ro_copy.iterate_upper_bound = &ub_slice;
1459
+ if (FLAGS_use_sqfc_for_range_queries) {
1460
+ ro_copy.table_filter =
1461
+ sqfc_factory_->GetTableFilterForRangeQuery(prefix, ub_slice);
1462
+ }
1358
1463
  }
1359
1464
 
1360
1465
  std::string read_ts_str;
@@ -1362,16 +1467,19 @@ class NonBatchedOpsStressTest : public StressTest {
1362
1467
  MaybeUseOlderTimestampForRangeScan(thread, read_ts_str, read_ts_slice,
1363
1468
  ro_copy);
1364
1469
 
1470
+ if (fault_fs_guard) {
1471
+ fault_fs_guard->GetAndResetInjectedThreadLocalErrorCount(
1472
+ FaultInjectionIOType::kRead);
1473
+ fault_fs_guard->GetAndResetInjectedThreadLocalErrorCount(
1474
+ FaultInjectionIOType::kMetadataRead);
1475
+ SharedState::ignore_read_error = false;
1476
+ }
1477
+
1365
1478
  std::unique_ptr<Iterator> iter(db_->NewIterator(ro_copy, cfh));
1366
1479
 
1367
1480
  uint64_t count = 0;
1368
1481
  Status s;
1369
1482
 
1370
- if (fault_fs_guard) {
1371
- fault_fs_guard->EnableErrorInjection();
1372
- SharedState::ignore_read_error = false;
1373
- }
1374
-
1375
1483
  for (iter->Seek(prefix); iter->Valid() && iter->key().starts_with(prefix);
1376
1484
  iter->Next()) {
1377
1485
  ++count;
@@ -1402,23 +1510,36 @@ class NonBatchedOpsStressTest : public StressTest {
1402
1510
  s = iter->status();
1403
1511
  }
1404
1512
 
1405
- uint64_t error_count = 0;
1513
+ int injected_error_count = 0;
1406
1514
  if (fault_fs_guard) {
1407
- error_count = fault_fs_guard->GetAndResetErrorCount();
1408
- }
1409
- if (!s.ok() && (!fault_fs_guard || (fault_fs_guard && !error_count))) {
1410
- fprintf(stderr, "TestPrefixScan error: %s\n", s.ToString().c_str());
1411
- thread->stats.AddErrors(1);
1412
-
1413
- return s;
1515
+ injected_error_count = GetMinInjectedErrorCount(
1516
+ fault_fs_guard->GetAndResetInjectedThreadLocalErrorCount(
1517
+ FaultInjectionIOType::kRead),
1518
+ fault_fs_guard->GetAndResetInjectedThreadLocalErrorCount(
1519
+ FaultInjectionIOType::kMetadataRead));
1520
+ if (!SharedState::ignore_read_error && injected_error_count > 0 &&
1521
+ s.ok()) {
1522
+ // Grab mutex so multiple thread don't try to print the
1523
+ // stack trace at the same time
1524
+ MutexLock l(thread->shared->GetMutex());
1525
+ fprintf(stderr, "Didn't get expected error from PrefixScan\n");
1526
+ fprintf(stderr, "Callstack that injected the fault\n");
1527
+ fault_fs_guard->PrintInjectedThreadLocalErrorBacktrace(
1528
+ FaultInjectionIOType::kRead);
1529
+ fault_fs_guard->PrintInjectedThreadLocalErrorBacktrace(
1530
+ FaultInjectionIOType::kMetadataRead);
1531
+ std::terminate();
1532
+ }
1414
1533
  }
1415
1534
 
1416
- if (fault_fs_guard) {
1417
- fault_fs_guard->DisableErrorInjection();
1535
+ if (s.ok()) {
1536
+ thread->stats.AddPrefixes(1, count);
1537
+ } else if (injected_error_count == 0 || !IsErrorInjectedAndRetryable(s)) {
1538
+ fprintf(stderr, "TestPrefixScan error: %s\n", s.ToString().c_str());
1539
+ thread->shared->SetVerificationFailure();
1418
1540
  }
1419
- thread->stats.AddPrefixes(1, count);
1420
1541
 
1421
- return Status::OK();
1542
+ return s;
1422
1543
  }
1423
1544
 
1424
1545
  Status TestPut(ThreadState* thread, WriteOptions& write_opts,
@@ -1464,11 +1585,28 @@ class NonBatchedOpsStressTest : public StressTest {
1464
1585
  assert(cfh);
1465
1586
 
1466
1587
  if (FLAGS_verify_before_write) {
1588
+ // Temporarily disable error injection for preparation
1589
+ if (fault_fs_guard) {
1590
+ fault_fs_guard->DisableThreadLocalErrorInjection(
1591
+ FaultInjectionIOType::kRead);
1592
+ fault_fs_guard->DisableThreadLocalErrorInjection(
1593
+ FaultInjectionIOType::kMetadataRead);
1594
+ }
1595
+
1467
1596
  std::string from_db;
1468
1597
  Status s = db_->Get(read_opts, cfh, k, &from_db);
1469
- if (!VerifyOrSyncValue(rand_column_family, rand_key, read_opts, shared,
1470
- /* msg_prefix */ "Pre-Put Get verification",
1471
- from_db, s)) {
1598
+ bool res = VerifyOrSyncValue(
1599
+ rand_column_family, rand_key, read_opts, shared,
1600
+ /* msg_prefix */ "Pre-Put Get verification", from_db, s);
1601
+
1602
+ // Enable back error injection disabled for preparation
1603
+ if (fault_fs_guard) {
1604
+ fault_fs_guard->EnableThreadLocalErrorInjection(
1605
+ FaultInjectionIOType::kRead);
1606
+ fault_fs_guard->EnableThreadLocalErrorInjection(
1607
+ FaultInjectionIOType::kMetadataRead);
1608
+ }
1609
+ if (!res) {
1472
1610
  return s;
1473
1611
  }
1474
1612
  }
@@ -1483,12 +1621,18 @@ class NonBatchedOpsStressTest : public StressTest {
1483
1621
 
1484
1622
  if (FLAGS_use_put_entity_one_in > 0 &&
1485
1623
  (value_base % FLAGS_use_put_entity_one_in) == 0) {
1486
- if (FLAGS_use_attribute_group) {
1487
- s = db_->PutEntity(write_opts, k,
1488
- GenerateAttributeGroups({cfh}, value_base, v));
1624
+ if (!FLAGS_use_txn) {
1625
+ if (FLAGS_use_attribute_group) {
1626
+ s = db_->PutEntity(write_opts, k,
1627
+ GenerateAttributeGroups({cfh}, value_base, v));
1628
+ } else {
1629
+ s = db_->PutEntity(write_opts, cfh, k,
1630
+ GenerateWideColumns(value_base, v));
1631
+ }
1489
1632
  } else {
1490
- s = db_->PutEntity(write_opts, cfh, k,
1491
- GenerateWideColumns(value_base, v));
1633
+ s = ExecuteTransaction(write_opts, thread, [&](Transaction& txn) {
1634
+ return txn.PutEntity(cfh, k, GenerateWideColumns(value_base, v));
1635
+ });
1492
1636
  }
1493
1637
  } else if (FLAGS_use_timed_put_one_in > 0 &&
1494
1638
  ((value_base + kLargePrimeForCommonFactorSkew) %
@@ -1527,7 +1671,9 @@ class NonBatchedOpsStressTest : public StressTest {
1527
1671
 
1528
1672
  if (!s.ok()) {
1529
1673
  pending_expected_value.Rollback();
1530
- if (FLAGS_inject_error_severity >= 2) {
1674
+ if (IsErrorInjectedAndRetryable(s)) {
1675
+ return s;
1676
+ } else if (FLAGS_inject_error_severity == 2) {
1531
1677
  if (!is_db_stopped_ && s.severity() >= Status::Severity::kFatalError) {
1532
1678
  is_db_stopped_ = true;
1533
1679
  } else if (!is_db_stopped_ ||
@@ -1585,7 +1731,9 @@ class NonBatchedOpsStressTest : public StressTest {
1585
1731
 
1586
1732
  if (!s.ok()) {
1587
1733
  pending_expected_value.Rollback();
1588
- if (FLAGS_inject_error_severity >= 2) {
1734
+ if (IsErrorInjectedAndRetryable(s)) {
1735
+ return s;
1736
+ } else if (FLAGS_inject_error_severity == 2) {
1589
1737
  if (!is_db_stopped_ &&
1590
1738
  s.severity() >= Status::Severity::kFatalError) {
1591
1739
  is_db_stopped_ = true;
@@ -1618,7 +1766,9 @@ class NonBatchedOpsStressTest : public StressTest {
1618
1766
 
1619
1767
  if (!s.ok()) {
1620
1768
  pending_expected_value.Rollback();
1621
- if (FLAGS_inject_error_severity >= 2) {
1769
+ if (IsErrorInjectedAndRetryable(s)) {
1770
+ return s;
1771
+ } else if (FLAGS_inject_error_severity == 2) {
1622
1772
  if (!is_db_stopped_ &&
1623
1773
  s.severity() >= Status::Severity::kFatalError) {
1624
1774
  is_db_stopped_ = true;
@@ -1686,7 +1836,9 @@ class NonBatchedOpsStressTest : public StressTest {
1686
1836
  pending_expected_values) {
1687
1837
  pending_expected_value.Rollback();
1688
1838
  }
1689
- if (FLAGS_inject_error_severity >= 2) {
1839
+ if (IsErrorInjectedAndRetryable(s)) {
1840
+ return s;
1841
+ } else if (FLAGS_inject_error_severity == 2) {
1690
1842
  if (!is_db_stopped_ && s.severity() >= Status::Severity::kFatalError) {
1691
1843
  is_db_stopped_ = true;
1692
1844
  } else if (!is_db_stopped_ ||
@@ -1715,11 +1867,26 @@ class NonBatchedOpsStressTest : public StressTest {
1715
1867
  FLAGS_db + "/." + std::to_string(thread->tid) + ".sst";
1716
1868
  Status s;
1717
1869
  std::ostringstream ingest_options_oss;
1870
+
1871
+ // Temporarily disable error injection for preparation
1872
+ if (fault_fs_guard) {
1873
+ fault_fs_guard->DisableThreadLocalErrorInjection(
1874
+ FaultInjectionIOType::kMetadataRead);
1875
+ fault_fs_guard->DisableThreadLocalErrorInjection(
1876
+ FaultInjectionIOType::kMetadataWrite);
1877
+ }
1878
+
1718
1879
  if (db_stress_env->FileExists(sst_filename).ok()) {
1719
1880
  // Maybe we terminated abnormally before, so cleanup to give this file
1720
1881
  // ingestion a clean slate
1721
1882
  s = db_stress_env->DeleteFile(sst_filename);
1722
1883
  }
1884
+ if (fault_fs_guard) {
1885
+ fault_fs_guard->EnableThreadLocalErrorInjection(
1886
+ FaultInjectionIOType::kMetadataRead);
1887
+ fault_fs_guard->EnableThreadLocalErrorInjection(
1888
+ FaultInjectionIOType::kMetadataWrite);
1889
+ }
1723
1890
 
1724
1891
  SstFileWriter sst_file_writer(EnvOptions(options_), options_);
1725
1892
  if (s.ok()) {
@@ -1801,15 +1968,14 @@ class NonBatchedOpsStressTest : public StressTest {
1801
1968
  pending_expected_values) {
1802
1969
  pending_expected_value.Rollback();
1803
1970
  }
1804
- if (!s.IsIOError() || !std::strstr(s.getState(), "injected")) {
1971
+
1972
+ if (!IsErrorInjectedAndRetryable(s)) {
1805
1973
  fprintf(stderr,
1806
1974
  "file ingestion error: %s under specified "
1807
1975
  "IngestExternalFileOptions: %s (Empty string or "
1808
1976
  "missing field indicates default option or value is used)\n",
1809
1977
  s.ToString().c_str(), ingest_options_oss.str().c_str());
1810
1978
  thread->shared->SafeTerminate();
1811
- } else {
1812
- fprintf(stdout, "file ingestion error: %s\n", s.ToString().c_str());
1813
1979
  }
1814
1980
  } else {
1815
1981
  for (PendingExpectedValue& pending_expected_value :
@@ -1876,6 +2042,13 @@ class NonBatchedOpsStressTest : public StressTest {
1876
2042
  // GetIntVal().
1877
2043
  ro.iterate_upper_bound = &max_key_slice;
1878
2044
  }
2045
+ std::string ub_str, lb_str;
2046
+ if (FLAGS_use_sqfc_for_range_queries) {
2047
+ ub_str = Key(ub);
2048
+ lb_str = Key(lb);
2049
+ ro.table_filter =
2050
+ sqfc_factory_->GetTableFilterForRangeQuery(lb_str, ub_str);
2051
+ }
1879
2052
 
1880
2053
  ColumnFamilyHandle* const cfh = column_families_[rand_column_family];
1881
2054
  assert(cfh);
@@ -1888,7 +2061,19 @@ class NonBatchedOpsStressTest : public StressTest {
1888
2061
  pre_read_expected_values.push_back(
1889
2062
  shared->Get(rand_column_family, i + lb));
1890
2063
  }
1891
- std::unique_ptr<Iterator> iter(db_->NewIterator(ro, cfh));
2064
+ std::unique_ptr<Iterator> iter;
2065
+ if (FLAGS_use_multi_cf_iterator) {
2066
+ std::vector<ColumnFamilyHandle*> cfhs;
2067
+ cfhs.reserve(rand_column_families.size());
2068
+ for (auto cf_index : rand_column_families) {
2069
+ cfhs.emplace_back(column_families_[cf_index]);
2070
+ }
2071
+ assert(!cfhs.empty());
2072
+ iter = db_->NewCoalescingIterator(ro, cfhs);
2073
+ } else {
2074
+ iter = std::unique_ptr<Iterator>(db_->NewIterator(ro, cfh));
2075
+ }
2076
+
1892
2077
  for (int64_t i = 0; i < static_cast<int64_t>(expected_values_size); ++i) {
1893
2078
  post_read_expected_values.push_back(
1894
2079
  shared->Get(rand_column_family, i + lb));
@@ -1973,13 +2158,17 @@ class NonBatchedOpsStressTest : public StressTest {
1973
2158
  assert(last_key < ub);
1974
2159
  if (!iter->Valid()) {
1975
2160
  if (!iter->status().ok()) {
1976
- thread->shared->SetVerificationFailure();
1977
- fprintf(stderr, "TestIterate against expected state error: %s\n",
1978
- iter->status().ToString().c_str());
1979
- fprintf(stderr, "Column family: %s, op_logs: %s\n",
1980
- cfh->GetName().c_str(), op_logs.c_str());
1981
- thread->stats.AddErrors(1);
1982
- return iter->status();
2161
+ if (IsErrorInjectedAndRetryable(iter->status())) {
2162
+ return iter->status();
2163
+ } else {
2164
+ thread->shared->SetVerificationFailure();
2165
+ fprintf(stderr, "TestIterate against expected state error: %s\n",
2166
+ iter->status().ToString().c_str());
2167
+ fprintf(stderr, "Column family: %s, op_logs: %s\n",
2168
+ cfh->GetName().c_str(), op_logs.c_str());
2169
+ thread->stats.AddErrors(1);
2170
+ return iter->status();
2171
+ }
1983
2172
  }
1984
2173
  if (!check_no_key_in_range(last_key + 1, ub)) {
1985
2174
  return Status::OK();
@@ -2031,13 +2220,17 @@ class NonBatchedOpsStressTest : public StressTest {
2031
2220
  assert(lb < last_key);
2032
2221
  if (!iter->Valid()) {
2033
2222
  if (!iter->status().ok()) {
2034
- thread->shared->SetVerificationFailure();
2035
- fprintf(stderr, "TestIterate against expected state error: %s\n",
2036
- iter->status().ToString().c_str());
2037
- fprintf(stderr, "Column family: %s, op_logs: %s\n",
2038
- cfh->GetName().c_str(), op_logs.c_str());
2039
- thread->stats.AddErrors(1);
2040
- return iter->status();
2223
+ if (IsErrorInjectedAndRetryable(iter->status())) {
2224
+ return iter->status();
2225
+ } else {
2226
+ thread->shared->SetVerificationFailure();
2227
+ fprintf(stderr, "TestIterate against expected state error: %s\n",
2228
+ iter->status().ToString().c_str());
2229
+ fprintf(stderr, "Column family: %s, op_logs: %s\n",
2230
+ cfh->GetName().c_str(), op_logs.c_str());
2231
+ thread->stats.AddErrors(1);
2232
+ return iter->status();
2233
+ }
2041
2234
  }
2042
2235
  if (!check_no_key_in_range(lb, last_key)) {
2043
2236
  return Status::OK();
@@ -2078,9 +2271,10 @@ class NonBatchedOpsStressTest : public StressTest {
2078
2271
  op_logs += "P";
2079
2272
  }
2080
2273
 
2081
- // Write-prepared and Write-unprepared do not support Refresh() yet.
2274
+ // Write-prepared/write-unprepared transactions and multi-CF iterator do not
2275
+ // support Refresh() yet.
2082
2276
  if (!(FLAGS_use_txn && FLAGS_txn_write_policy != 0) &&
2083
- thread->rand.OneIn(2)) {
2277
+ !FLAGS_use_multi_cf_iterator && thread->rand.OneIn(2)) {
2084
2278
  pre_read_expected_values.clear();
2085
2279
  post_read_expected_values.clear();
2086
2280
  // Refresh after forward/backward scan to allow higher chance of SV
@@ -2090,6 +2284,9 @@ class NonBatchedOpsStressTest : public StressTest {
2090
2284
  shared->Get(rand_column_family, i + lb));
2091
2285
  }
2092
2286
  Status rs = iter->Refresh();
2287
+ if (!rs.ok() && IsErrorInjectedAndRetryable(rs)) {
2288
+ return rs;
2289
+ }
2093
2290
  assert(rs.ok());
2094
2291
  op_logs += "Refresh ";
2095
2292
  for (int64_t i = 0; i < static_cast<int64_t>(expected_values_size); ++i) {
@@ -2251,13 +2448,17 @@ class NonBatchedOpsStressTest : public StressTest {
2251
2448
  }
2252
2449
 
2253
2450
  if (!iter->status().ok()) {
2254
- thread->shared->SetVerificationFailure();
2255
- fprintf(stderr, "TestIterate against expected state error: %s\n",
2256
- iter->status().ToString().c_str());
2257
- fprintf(stderr, "Column family: %s, op_logs: %s\n",
2258
- cfh->GetName().c_str(), op_logs.c_str());
2259
- thread->stats.AddErrors(1);
2260
- return iter->status();
2451
+ if (IsErrorInjectedAndRetryable(iter->status())) {
2452
+ return iter->status();
2453
+ } else {
2454
+ thread->shared->SetVerificationFailure();
2455
+ fprintf(stderr, "TestIterate against expected state error: %s\n",
2456
+ iter->status().ToString().c_str());
2457
+ fprintf(stderr, "Column family: %s, op_logs: %s\n",
2458
+ cfh->GetName().c_str(), op_logs.c_str());
2459
+ thread->stats.AddErrors(1);
2460
+ return iter->status();
2461
+ }
2261
2462
  }
2262
2463
 
2263
2464
  thread->stats.AddIterations(1);
@@ -2372,6 +2573,93 @@ class NonBatchedOpsStressTest : public StressTest {
2372
2573
  return !shared->AllowsOverwrite(key_num);
2373
2574
  };
2374
2575
  }
2576
+
2577
+ void MaybeAddKeyToTxnForRYW(
2578
+ ThreadState* thread, int column_family, int64_t key, Transaction* txn,
2579
+ std::unordered_map<std::string, ExpectedValue>& ryw_expected_values) {
2580
+ assert(thread);
2581
+ assert(txn);
2582
+
2583
+ SharedState* const shared = thread->shared;
2584
+ assert(shared);
2585
+
2586
+ if (!shared->AllowsOverwrite(key) && shared->Exists(column_family, key)) {
2587
+ // Just do read your write checks for keys that allow overwrites.
2588
+ return;
2589
+ }
2590
+
2591
+ // With a 1 in 10 probability, insert the just added key in the batch
2592
+ // into the transaction. This will create an overlap with the MultiGet
2593
+ // keys and exercise some corner cases in the code
2594
+ if (thread->rand.OneIn(10)) {
2595
+ assert(column_family >= 0);
2596
+ assert(column_family < static_cast<int>(column_families_.size()));
2597
+
2598
+ ColumnFamilyHandle* const cfh = column_families_[column_family];
2599
+ assert(cfh);
2600
+
2601
+ const std::string k = Key(key);
2602
+
2603
+ enum class Op {
2604
+ PutOrPutEntity,
2605
+ Merge,
2606
+ Delete,
2607
+ // add new operations above this line
2608
+ NumberOfOps
2609
+ };
2610
+
2611
+ const Op op = static_cast<Op>(
2612
+ thread->rand.Uniform(static_cast<int>(Op::NumberOfOps)));
2613
+
2614
+ Status s;
2615
+
2616
+ switch (op) {
2617
+ case Op::PutOrPutEntity:
2618
+ case Op::Merge: {
2619
+ ExpectedValue put_value;
2620
+ put_value.SyncPut(static_cast<uint32_t>(thread->rand.Uniform(
2621
+ static_cast<int>(ExpectedValue::GetValueBaseMask()))));
2622
+ ryw_expected_values[k] = put_value;
2623
+
2624
+ const uint32_t value_base = put_value.GetValueBase();
2625
+
2626
+ char value[100];
2627
+ const size_t sz = GenerateValue(value_base, value, sizeof(value));
2628
+ const Slice v(value, sz);
2629
+
2630
+ if (op == Op::PutOrPutEntity) {
2631
+ if (FLAGS_use_put_entity_one_in > 0 &&
2632
+ (value_base % FLAGS_use_put_entity_one_in) == 0) {
2633
+ s = txn->PutEntity(cfh, k, GenerateWideColumns(value_base, v));
2634
+ } else {
2635
+ s = txn->Put(cfh, k, v);
2636
+ }
2637
+ } else {
2638
+ s = txn->Merge(cfh, k, v);
2639
+ }
2640
+
2641
+ break;
2642
+ }
2643
+ case Op::Delete: {
2644
+ ExpectedValue delete_value;
2645
+ delete_value.SyncDelete();
2646
+ ryw_expected_values[k] = delete_value;
2647
+
2648
+ s = txn->Delete(cfh, k);
2649
+ break;
2650
+ }
2651
+ default:
2652
+ assert(false);
2653
+ }
2654
+
2655
+ if (!s.ok()) {
2656
+ fprintf(stderr,
2657
+ "Transaction write error in read-your-own-write test: %s\n",
2658
+ s.ToString().c_str());
2659
+ shared->SafeTerminate();
2660
+ }
2661
+ }
2662
+ }
2375
2663
  };
2376
2664
 
2377
2665
  StressTest* CreateNonBatchedOpsStressTest() {