tigerbeetle 0.0.36 → 0.0.38

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 (248) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/ext/tb_client/extconf.rb +13 -13
  4. data/ext/tb_client/tigerbeetle/LICENSE +177 -0
  5. data/ext/tb_client/tigerbeetle/build.zig +2327 -0
  6. data/ext/tb_client/tigerbeetle/src/aof.zig +1000 -0
  7. data/ext/tb_client/tigerbeetle/src/build_multiversion.zig +808 -0
  8. data/ext/tb_client/tigerbeetle/src/cdc/amqp/protocol.zig +1283 -0
  9. data/ext/tb_client/tigerbeetle/src/cdc/amqp/spec.zig +1704 -0
  10. data/ext/tb_client/tigerbeetle/src/cdc/amqp/types.zig +341 -0
  11. data/ext/tb_client/tigerbeetle/src/cdc/amqp.zig +1450 -0
  12. data/ext/tb_client/tigerbeetle/src/cdc/runner.zig +1659 -0
  13. data/ext/tb_client/tigerbeetle/src/clients/c/samples/main.c +406 -0
  14. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/context.zig +1092 -0
  15. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/echo_client.zig +286 -0
  16. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/packet.zig +158 -0
  17. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/signal.zig +229 -0
  18. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/signal_fuzz.zig +110 -0
  19. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client.h +386 -0
  20. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client.zig +34 -0
  21. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_exports.zig +281 -0
  22. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_header.zig +312 -0
  23. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_header_test.zig +138 -0
  24. data/ext/tb_client/tigerbeetle/src/clients/c/test.zig +466 -0
  25. data/ext/tb_client/tigerbeetle/src/clients/docs_samples.zig +157 -0
  26. data/ext/tb_client/tigerbeetle/src/clients/docs_types.zig +90 -0
  27. data/ext/tb_client/tigerbeetle/src/clients/dotnet/ci.zig +203 -0
  28. data/ext/tb_client/tigerbeetle/src/clients/dotnet/docs.zig +79 -0
  29. data/ext/tb_client/tigerbeetle/src/clients/dotnet/dotnet_bindings.zig +542 -0
  30. data/ext/tb_client/tigerbeetle/src/clients/go/ci.zig +109 -0
  31. data/ext/tb_client/tigerbeetle/src/clients/go/docs.zig +86 -0
  32. data/ext/tb_client/tigerbeetle/src/clients/go/go_bindings.zig +370 -0
  33. data/ext/tb_client/tigerbeetle/src/clients/go/pkg/native/tb_client.h +386 -0
  34. data/ext/tb_client/tigerbeetle/src/clients/java/ci.zig +167 -0
  35. data/ext/tb_client/tigerbeetle/src/clients/java/docs.zig +126 -0
  36. data/ext/tb_client/tigerbeetle/src/clients/java/java_bindings.zig +996 -0
  37. data/ext/tb_client/tigerbeetle/src/clients/java/src/client.zig +748 -0
  38. data/ext/tb_client/tigerbeetle/src/clients/java/src/jni.zig +3238 -0
  39. data/ext/tb_client/tigerbeetle/src/clients/java/src/jni_tests.zig +1718 -0
  40. data/ext/tb_client/tigerbeetle/src/clients/java/src/jni_thread_cleaner.zig +190 -0
  41. data/ext/tb_client/tigerbeetle/src/clients/node/ci.zig +104 -0
  42. data/ext/tb_client/tigerbeetle/src/clients/node/docs.zig +75 -0
  43. data/ext/tb_client/tigerbeetle/src/clients/node/node.zig +522 -0
  44. data/ext/tb_client/tigerbeetle/src/clients/node/node_bindings.zig +267 -0
  45. data/ext/tb_client/tigerbeetle/src/clients/node/src/c.zig +3 -0
  46. data/ext/tb_client/tigerbeetle/src/clients/node/src/translate.zig +379 -0
  47. data/ext/tb_client/tigerbeetle/src/clients/python/ci.zig +131 -0
  48. data/ext/tb_client/tigerbeetle/src/clients/python/docs.zig +63 -0
  49. data/ext/tb_client/tigerbeetle/src/clients/python/python_bindings.zig +588 -0
  50. data/ext/tb_client/tigerbeetle/src/clients/rust/assets/tb_client.h +386 -0
  51. data/ext/tb_client/tigerbeetle/src/clients/rust/ci.zig +73 -0
  52. data/ext/tb_client/tigerbeetle/src/clients/rust/docs.zig +106 -0
  53. data/ext/tb_client/tigerbeetle/src/clients/rust/rust_bindings.zig +305 -0
  54. data/ext/tb_client/tigerbeetle/src/config.zig +296 -0
  55. data/ext/tb_client/tigerbeetle/src/constants.zig +790 -0
  56. data/ext/tb_client/tigerbeetle/src/copyhound.zig +202 -0
  57. data/ext/tb_client/tigerbeetle/src/counting_allocator.zig +72 -0
  58. data/ext/tb_client/tigerbeetle/src/direction.zig +120 -0
  59. data/ext/tb_client/tigerbeetle/src/docs_website/build.zig +158 -0
  60. data/ext/tb_client/tigerbeetle/src/docs_website/src/content.zig +156 -0
  61. data/ext/tb_client/tigerbeetle/src/docs_website/src/docs.zig +252 -0
  62. data/ext/tb_client/tigerbeetle/src/docs_website/src/file_checker.zig +313 -0
  63. data/ext/tb_client/tigerbeetle/src/docs_website/src/html.zig +87 -0
  64. data/ext/tb_client/tigerbeetle/src/docs_website/src/page_writer.zig +63 -0
  65. data/ext/tb_client/tigerbeetle/src/docs_website/src/redirects.zig +47 -0
  66. data/ext/tb_client/tigerbeetle/src/docs_website/src/search_index_writer.zig +28 -0
  67. data/ext/tb_client/tigerbeetle/src/docs_website/src/service_worker_writer.zig +61 -0
  68. data/ext/tb_client/tigerbeetle/src/docs_website/src/single_page_writer.zig +169 -0
  69. data/ext/tb_client/tigerbeetle/src/docs_website/src/website.zig +46 -0
  70. data/ext/tb_client/tigerbeetle/src/ewah.zig +445 -0
  71. data/ext/tb_client/tigerbeetle/src/ewah_benchmark.zig +128 -0
  72. data/ext/tb_client/tigerbeetle/src/ewah_fuzz.zig +171 -0
  73. data/ext/tb_client/tigerbeetle/src/fuzz_tests.zig +179 -0
  74. data/ext/tb_client/tigerbeetle/src/integration_tests.zig +662 -0
  75. data/ext/tb_client/tigerbeetle/src/io/common.zig +155 -0
  76. data/ext/tb_client/tigerbeetle/src/io/darwin.zig +1093 -0
  77. data/ext/tb_client/tigerbeetle/src/io/linux.zig +1880 -0
  78. data/ext/tb_client/tigerbeetle/src/io/test.zig +1005 -0
  79. data/ext/tb_client/tigerbeetle/src/io/windows.zig +1598 -0
  80. data/ext/tb_client/tigerbeetle/src/io.zig +34 -0
  81. data/ext/tb_client/tigerbeetle/src/iops.zig +134 -0
  82. data/ext/tb_client/tigerbeetle/src/list.zig +236 -0
  83. data/ext/tb_client/tigerbeetle/src/lsm/binary_search.zig +848 -0
  84. data/ext/tb_client/tigerbeetle/src/lsm/binary_search_benchmark.zig +179 -0
  85. data/ext/tb_client/tigerbeetle/src/lsm/cache_map.zig +424 -0
  86. data/ext/tb_client/tigerbeetle/src/lsm/cache_map_fuzz.zig +420 -0
  87. data/ext/tb_client/tigerbeetle/src/lsm/compaction.zig +2117 -0
  88. data/ext/tb_client/tigerbeetle/src/lsm/composite_key.zig +182 -0
  89. data/ext/tb_client/tigerbeetle/src/lsm/forest.zig +1119 -0
  90. data/ext/tb_client/tigerbeetle/src/lsm/forest_fuzz.zig +1102 -0
  91. data/ext/tb_client/tigerbeetle/src/lsm/forest_table_iterator.zig +200 -0
  92. data/ext/tb_client/tigerbeetle/src/lsm/groove.zig +1495 -0
  93. data/ext/tb_client/tigerbeetle/src/lsm/k_way_merge.zig +739 -0
  94. data/ext/tb_client/tigerbeetle/src/lsm/k_way_merge_benchmark.zig +166 -0
  95. data/ext/tb_client/tigerbeetle/src/lsm/manifest.zig +754 -0
  96. data/ext/tb_client/tigerbeetle/src/lsm/manifest_level.zig +1294 -0
  97. data/ext/tb_client/tigerbeetle/src/lsm/manifest_level_fuzz.zig +510 -0
  98. data/ext/tb_client/tigerbeetle/src/lsm/manifest_log.zig +1263 -0
  99. data/ext/tb_client/tigerbeetle/src/lsm/manifest_log_fuzz.zig +628 -0
  100. data/ext/tb_client/tigerbeetle/src/lsm/node_pool.zig +247 -0
  101. data/ext/tb_client/tigerbeetle/src/lsm/scan_buffer.zig +116 -0
  102. data/ext/tb_client/tigerbeetle/src/lsm/scan_builder.zig +543 -0
  103. data/ext/tb_client/tigerbeetle/src/lsm/scan_fuzz.zig +938 -0
  104. data/ext/tb_client/tigerbeetle/src/lsm/scan_lookup.zig +293 -0
  105. data/ext/tb_client/tigerbeetle/src/lsm/scan_merge.zig +359 -0
  106. data/ext/tb_client/tigerbeetle/src/lsm/scan_range.zig +99 -0
  107. data/ext/tb_client/tigerbeetle/src/lsm/scan_state.zig +17 -0
  108. data/ext/tb_client/tigerbeetle/src/lsm/scan_tree.zig +962 -0
  109. data/ext/tb_client/tigerbeetle/src/lsm/schema.zig +617 -0
  110. data/ext/tb_client/tigerbeetle/src/lsm/scratch_memory.zig +84 -0
  111. data/ext/tb_client/tigerbeetle/src/lsm/segmented_array.zig +1500 -0
  112. data/ext/tb_client/tigerbeetle/src/lsm/segmented_array_benchmark.zig +149 -0
  113. data/ext/tb_client/tigerbeetle/src/lsm/segmented_array_fuzz.zig +7 -0
  114. data/ext/tb_client/tigerbeetle/src/lsm/set_associative_cache.zig +865 -0
  115. data/ext/tb_client/tigerbeetle/src/lsm/table.zig +607 -0
  116. data/ext/tb_client/tigerbeetle/src/lsm/table_memory.zig +843 -0
  117. data/ext/tb_client/tigerbeetle/src/lsm/table_value_iterator.zig +90 -0
  118. data/ext/tb_client/tigerbeetle/src/lsm/timestamp_range.zig +40 -0
  119. data/ext/tb_client/tigerbeetle/src/lsm/tree.zig +630 -0
  120. data/ext/tb_client/tigerbeetle/src/lsm/tree_fuzz.zig +933 -0
  121. data/ext/tb_client/tigerbeetle/src/lsm/zig_zag_merge.zig +534 -0
  122. data/ext/tb_client/tigerbeetle/src/message_buffer.zig +469 -0
  123. data/ext/tb_client/tigerbeetle/src/message_bus.zig +1214 -0
  124. data/ext/tb_client/tigerbeetle/src/message_bus_fuzz.zig +936 -0
  125. data/ext/tb_client/tigerbeetle/src/message_pool.zig +343 -0
  126. data/ext/tb_client/tigerbeetle/src/multiversion.zig +2195 -0
  127. data/ext/tb_client/tigerbeetle/src/queue.zig +390 -0
  128. data/ext/tb_client/tigerbeetle/src/repl/completion.zig +201 -0
  129. data/ext/tb_client/tigerbeetle/src/repl/parser.zig +1356 -0
  130. data/ext/tb_client/tigerbeetle/src/repl/terminal.zig +496 -0
  131. data/ext/tb_client/tigerbeetle/src/repl.zig +1034 -0
  132. data/ext/tb_client/tigerbeetle/src/scripts/amqp.zig +973 -0
  133. data/ext/tb_client/tigerbeetle/src/scripts/cfo.zig +1866 -0
  134. data/ext/tb_client/tigerbeetle/src/scripts/changelog.zig +304 -0
  135. data/ext/tb_client/tigerbeetle/src/scripts/ci.zig +227 -0
  136. data/ext/tb_client/tigerbeetle/src/scripts/client_readmes.zig +658 -0
  137. data/ext/tb_client/tigerbeetle/src/scripts/devhub.zig +466 -0
  138. data/ext/tb_client/tigerbeetle/src/scripts/release.zig +1058 -0
  139. data/ext/tb_client/tigerbeetle/src/scripts.zig +105 -0
  140. data/ext/tb_client/tigerbeetle/src/shell.zig +1195 -0
  141. data/ext/tb_client/tigerbeetle/src/stack.zig +260 -0
  142. data/ext/tb_client/tigerbeetle/src/state_machine/auditor.zig +911 -0
  143. data/ext/tb_client/tigerbeetle/src/state_machine/workload.zig +2079 -0
  144. data/ext/tb_client/tigerbeetle/src/state_machine.zig +4872 -0
  145. data/ext/tb_client/tigerbeetle/src/state_machine_fuzz.zig +288 -0
  146. data/ext/tb_client/tigerbeetle/src/state_machine_tests.zig +3128 -0
  147. data/ext/tb_client/tigerbeetle/src/static_allocator.zig +82 -0
  148. data/ext/tb_client/tigerbeetle/src/stdx/bit_set.zig +157 -0
  149. data/ext/tb_client/tigerbeetle/src/stdx/bounded_array.zig +292 -0
  150. data/ext/tb_client/tigerbeetle/src/stdx/debug.zig +65 -0
  151. data/ext/tb_client/tigerbeetle/src/stdx/flags.zig +1414 -0
  152. data/ext/tb_client/tigerbeetle/src/stdx/mlock.zig +92 -0
  153. data/ext/tb_client/tigerbeetle/src/stdx/prng.zig +677 -0
  154. data/ext/tb_client/tigerbeetle/src/stdx/radix.zig +336 -0
  155. data/ext/tb_client/tigerbeetle/src/stdx/ring_buffer.zig +511 -0
  156. data/ext/tb_client/tigerbeetle/src/stdx/sort_test.zig +112 -0
  157. data/ext/tb_client/tigerbeetle/src/stdx/stdx.zig +1160 -0
  158. data/ext/tb_client/tigerbeetle/src/stdx/testing/low_level_hash_vectors.zig +142 -0
  159. data/ext/tb_client/tigerbeetle/src/stdx/testing/snaptest.zig +361 -0
  160. data/ext/tb_client/tigerbeetle/src/stdx/time_units.zig +275 -0
  161. data/ext/tb_client/tigerbeetle/src/stdx/unshare.zig +295 -0
  162. data/ext/tb_client/tigerbeetle/src/stdx/vendored/aegis.zig +436 -0
  163. data/ext/tb_client/tigerbeetle/src/stdx/windows.zig +48 -0
  164. data/ext/tb_client/tigerbeetle/src/stdx/zipfian.zig +402 -0
  165. data/ext/tb_client/tigerbeetle/src/storage.zig +489 -0
  166. data/ext/tb_client/tigerbeetle/src/storage_fuzz.zig +180 -0
  167. data/ext/tb_client/tigerbeetle/src/testing/bench.zig +146 -0
  168. data/ext/tb_client/tigerbeetle/src/testing/cluster/grid_checker.zig +53 -0
  169. data/ext/tb_client/tigerbeetle/src/testing/cluster/journal_checker.zig +61 -0
  170. data/ext/tb_client/tigerbeetle/src/testing/cluster/manifest_checker.zig +76 -0
  171. data/ext/tb_client/tigerbeetle/src/testing/cluster/message_bus.zig +110 -0
  172. data/ext/tb_client/tigerbeetle/src/testing/cluster/network.zig +412 -0
  173. data/ext/tb_client/tigerbeetle/src/testing/cluster/state_checker.zig +331 -0
  174. data/ext/tb_client/tigerbeetle/src/testing/cluster/storage_checker.zig +458 -0
  175. data/ext/tb_client/tigerbeetle/src/testing/cluster.zig +1198 -0
  176. data/ext/tb_client/tigerbeetle/src/testing/exhaustigen.zig +128 -0
  177. data/ext/tb_client/tigerbeetle/src/testing/fixtures.zig +181 -0
  178. data/ext/tb_client/tigerbeetle/src/testing/fuzz.zig +144 -0
  179. data/ext/tb_client/tigerbeetle/src/testing/id.zig +97 -0
  180. data/ext/tb_client/tigerbeetle/src/testing/io.zig +317 -0
  181. data/ext/tb_client/tigerbeetle/src/testing/marks.zig +126 -0
  182. data/ext/tb_client/tigerbeetle/src/testing/packet_simulator.zig +533 -0
  183. data/ext/tb_client/tigerbeetle/src/testing/reply_sequence.zig +154 -0
  184. data/ext/tb_client/tigerbeetle/src/testing/state_machine.zig +389 -0
  185. data/ext/tb_client/tigerbeetle/src/testing/storage.zig +1247 -0
  186. data/ext/tb_client/tigerbeetle/src/testing/table.zig +249 -0
  187. data/ext/tb_client/tigerbeetle/src/testing/time.zig +98 -0
  188. data/ext/tb_client/tigerbeetle/src/testing/tmp_tigerbeetle.zig +212 -0
  189. data/ext/tb_client/tigerbeetle/src/testing/vortex/constants.zig +26 -0
  190. data/ext/tb_client/tigerbeetle/src/testing/vortex/faulty_network.zig +580 -0
  191. data/ext/tb_client/tigerbeetle/src/testing/vortex/java_driver/ci.zig +39 -0
  192. data/ext/tb_client/tigerbeetle/src/testing/vortex/logged_process.zig +214 -0
  193. data/ext/tb_client/tigerbeetle/src/testing/vortex/rust_driver/ci.zig +34 -0
  194. data/ext/tb_client/tigerbeetle/src/testing/vortex/supervisor.zig +766 -0
  195. data/ext/tb_client/tigerbeetle/src/testing/vortex/workload.zig +543 -0
  196. data/ext/tb_client/tigerbeetle/src/testing/vortex/zig_driver.zig +181 -0
  197. data/ext/tb_client/tigerbeetle/src/tidy.zig +1448 -0
  198. data/ext/tb_client/tigerbeetle/src/tigerbeetle/benchmark_driver.zig +227 -0
  199. data/ext/tb_client/tigerbeetle/src/tigerbeetle/benchmark_load.zig +1069 -0
  200. data/ext/tb_client/tigerbeetle/src/tigerbeetle/cli.zig +1422 -0
  201. data/ext/tb_client/tigerbeetle/src/tigerbeetle/inspect.zig +1658 -0
  202. data/ext/tb_client/tigerbeetle/src/tigerbeetle/inspect_integrity.zig +518 -0
  203. data/ext/tb_client/tigerbeetle/src/tigerbeetle/libtb_client.zig +36 -0
  204. data/ext/tb_client/tigerbeetle/src/tigerbeetle/main.zig +646 -0
  205. data/ext/tb_client/tigerbeetle/src/tigerbeetle.zig +958 -0
  206. data/ext/tb_client/tigerbeetle/src/time.zig +236 -0
  207. data/ext/tb_client/tigerbeetle/src/trace/event.zig +745 -0
  208. data/ext/tb_client/tigerbeetle/src/trace/statsd.zig +462 -0
  209. data/ext/tb_client/tigerbeetle/src/trace.zig +556 -0
  210. data/ext/tb_client/tigerbeetle/src/unit_tests.zig +321 -0
  211. data/ext/tb_client/tigerbeetle/src/vopr.zig +1785 -0
  212. data/ext/tb_client/tigerbeetle/src/vortex.zig +101 -0
  213. data/ext/tb_client/tigerbeetle/src/vsr/checkpoint_trailer.zig +473 -0
  214. data/ext/tb_client/tigerbeetle/src/vsr/checksum.zig +208 -0
  215. data/ext/tb_client/tigerbeetle/src/vsr/checksum_benchmark.zig +43 -0
  216. data/ext/tb_client/tigerbeetle/src/vsr/client.zig +768 -0
  217. data/ext/tb_client/tigerbeetle/src/vsr/client_replies.zig +532 -0
  218. data/ext/tb_client/tigerbeetle/src/vsr/client_sessions.zig +338 -0
  219. data/ext/tb_client/tigerbeetle/src/vsr/clock.zig +1019 -0
  220. data/ext/tb_client/tigerbeetle/src/vsr/fault_detector.zig +279 -0
  221. data/ext/tb_client/tigerbeetle/src/vsr/free_set.zig +1381 -0
  222. data/ext/tb_client/tigerbeetle/src/vsr/free_set_fuzz.zig +315 -0
  223. data/ext/tb_client/tigerbeetle/src/vsr/grid.zig +1460 -0
  224. data/ext/tb_client/tigerbeetle/src/vsr/grid_blocks_missing.zig +757 -0
  225. data/ext/tb_client/tigerbeetle/src/vsr/grid_scrubber.zig +797 -0
  226. data/ext/tb_client/tigerbeetle/src/vsr/journal.zig +2586 -0
  227. data/ext/tb_client/tigerbeetle/src/vsr/marzullo.zig +308 -0
  228. data/ext/tb_client/tigerbeetle/src/vsr/message_header.zig +1777 -0
  229. data/ext/tb_client/tigerbeetle/src/vsr/multi_batch.zig +715 -0
  230. data/ext/tb_client/tigerbeetle/src/vsr/multi_batch_fuzz.zig +185 -0
  231. data/ext/tb_client/tigerbeetle/src/vsr/repair_budget.zig +333 -0
  232. data/ext/tb_client/tigerbeetle/src/vsr/replica.zig +12355 -0
  233. data/ext/tb_client/tigerbeetle/src/vsr/replica_format.zig +416 -0
  234. data/ext/tb_client/tigerbeetle/src/vsr/replica_reformat.zig +165 -0
  235. data/ext/tb_client/tigerbeetle/src/vsr/replica_test.zig +2928 -0
  236. data/ext/tb_client/tigerbeetle/src/vsr/routing.zig +1075 -0
  237. data/ext/tb_client/tigerbeetle/src/vsr/superblock.zig +1603 -0
  238. data/ext/tb_client/tigerbeetle/src/vsr/superblock_fuzz.zig +484 -0
  239. data/ext/tb_client/tigerbeetle/src/vsr/superblock_quorums.zig +405 -0
  240. data/ext/tb_client/tigerbeetle/src/vsr/superblock_quorums_fuzz.zig +355 -0
  241. data/ext/tb_client/tigerbeetle/src/vsr/sync.zig +29 -0
  242. data/ext/tb_client/tigerbeetle/src/vsr.zig +1727 -0
  243. data/lib/tb_client/shared_lib.rb +12 -5
  244. data/lib/tigerbeetle/platforms.rb +9 -0
  245. data/lib/tigerbeetle/version.rb +2 -2
  246. data/tigerbeetle.gemspec +22 -5
  247. metadata +242 -3
  248. data/ext/tb_client/pkg.tar.gz +0 -0
@@ -0,0 +1,317 @@
1
+ const std = @import("std");
2
+ const posix = std.posix;
3
+ const mem = std.mem;
4
+ const assert = std.debug.assert;
5
+
6
+ const stdx = @import("stdx");
7
+ const constants = @import("../constants.zig");
8
+ const QueueType = @import("../queue.zig").QueueType;
9
+ const buffer_limit = @import("../io.zig").buffer_limit;
10
+ const Ratio = stdx.PRNG.Ratio;
11
+
12
+ /// A very simple mock IO implementation that only implements what is needed to test Storage.
13
+ pub const IO = struct {
14
+ pub const fd_t = u32;
15
+
16
+ pub const File = struct {
17
+ buffer: []u8,
18
+
19
+ /// Each bit of the fault map represents a sector that will fault consistently.
20
+ fault_map: ?[]const u8 = null,
21
+
22
+ closed: bool = false,
23
+
24
+ // Maintained for appending to the end of the file via `write_blocking`.
25
+ offset: u32 = 0,
26
+ };
27
+
28
+ /// Options for fault injection during fuzz testing.
29
+ pub const Options = struct {
30
+ /// Seed for the storage PRNG.
31
+ seed: u64 = 0,
32
+
33
+ /// Chance out of 100 that a read larger than a logical sector
34
+ /// will return an error.InputOutput.
35
+ larger_than_logical_sector_read_fault_probability: Ratio = Ratio.zero(),
36
+ };
37
+
38
+ const Queue = QueueType(Completion);
39
+
40
+ files: []File,
41
+
42
+ options: Options,
43
+ prng: stdx.PRNG,
44
+
45
+ completed: Queue = Queue.init(.{ .name = "io_completed" }),
46
+
47
+ pub fn init(files: []File, options: Options) !IO {
48
+ return .{
49
+ .options = options,
50
+ .prng = stdx.PRNG.from_seed(options.seed),
51
+ .files = files,
52
+ };
53
+ }
54
+
55
+ pub fn deinit(io: *IO) void {
56
+ for (io.files) |file| assert(file.closed);
57
+ }
58
+
59
+ /// Pass all queued submissions to the kernel and peek for completions.
60
+ pub fn run(io: *IO) !void {
61
+ while (io.completed.pop()) |completion| {
62
+ completion.callback(io, completion);
63
+ }
64
+ }
65
+
66
+ /// This struct holds the data needed for a single IO operation.
67
+ pub const Completion = struct {
68
+ link: Queue.Link,
69
+ context: ?*anyopaque,
70
+ callback: *const fn (*IO, *Completion) void,
71
+ operation: Operation,
72
+ };
73
+
74
+ const Operation = union(enum) {
75
+ read: struct {
76
+ fd: fd_t,
77
+ buf: [*]u8,
78
+ len: u32,
79
+ offset: u64,
80
+ },
81
+ write: struct {
82
+ fd: fd_t,
83
+ buf: [*]const u8,
84
+ len: u32,
85
+ offset: u64,
86
+ },
87
+ fsync: struct {
88
+ fd: fd_t,
89
+ },
90
+ };
91
+
92
+ fn submit(
93
+ self: *IO,
94
+ context: anytype,
95
+ comptime callback: anytype,
96
+ completion: *Completion,
97
+ comptime operation_tag: std.meta.Tag(Operation),
98
+ operation_data: std.meta.TagPayload(Operation, operation_tag),
99
+ comptime OperationImpl: type,
100
+ ) void {
101
+ const on_complete_fn = struct {
102
+ fn on_complete(io: *IO, _completion: *Completion) void {
103
+ // Perform the actual operation.
104
+ const op_data = &@field(_completion.operation, @tagName(operation_tag));
105
+ const result = OperationImpl.do_operation(io, op_data);
106
+
107
+ // Complete the Completion.
108
+ return callback(
109
+ @ptrCast(@alignCast(_completion.context)),
110
+ _completion,
111
+ result,
112
+ );
113
+ }
114
+ }.on_complete;
115
+
116
+ completion.* = .{
117
+ .link = .{},
118
+ .context = context,
119
+ .callback = on_complete_fn,
120
+ .operation = @unionInit(Operation, @tagName(operation_tag), operation_data),
121
+ };
122
+
123
+ self.completed.push(completion);
124
+ }
125
+
126
+ pub const OpenDataFilePurpose = enum { format, open, inspect };
127
+
128
+ pub const ReadError = error{
129
+ WouldBlock,
130
+ NotOpenForReading,
131
+ ConnectionResetByPeer,
132
+ Alignment,
133
+ InputOutput,
134
+ IsDir,
135
+ SystemResources,
136
+ Unseekable,
137
+ ConnectionTimedOut,
138
+ } || posix.UnexpectedError;
139
+
140
+ pub fn read(
141
+ self: *IO,
142
+ comptime Context: type,
143
+ context: Context,
144
+ comptime callback: fn (
145
+ context: Context,
146
+ completion: *Completion,
147
+ result: ReadError!usize,
148
+ ) void,
149
+ completion: *Completion,
150
+ fd: fd_t,
151
+ buffer: []u8,
152
+ offset: u64,
153
+ ) void {
154
+ assert(fd < self.files.len);
155
+
156
+ self.submit(
157
+ context,
158
+ callback,
159
+ completion,
160
+ .read,
161
+ .{
162
+ .fd = fd,
163
+ .buf = buffer.ptr,
164
+ .len = @as(u32, @intCast(buffer_limit(buffer.len))),
165
+ .offset = offset,
166
+ },
167
+ struct {
168
+ fn do_operation(io: *IO, op: anytype) ReadError!usize {
169
+ const sector_marked_in_fault_map = if (io.files[op.fd].fault_map) |fault_map|
170
+ std.mem.readPackedIntNative(
171
+ u1,
172
+ fault_map,
173
+ @divExact(op.offset, constants.sector_size),
174
+ ) != 0
175
+ else
176
+ false;
177
+
178
+ const sector_has_larger_than_logical_sector_read_fault =
179
+ (op.len > constants.sector_size and io.prng.chance(
180
+ io.options.larger_than_logical_sector_read_fault_probability,
181
+ ));
182
+
183
+ if (sector_marked_in_fault_map or
184
+ sector_has_larger_than_logical_sector_read_fault)
185
+ {
186
+ return error.InputOutput;
187
+ }
188
+
189
+ const data = io.files[op.fd].buffer;
190
+ stdx.copy_disjoint(.exact, u8, op.buf[0..op.len], data[op.offset..][0..op.len]);
191
+ return op.len;
192
+ }
193
+ },
194
+ );
195
+ }
196
+
197
+ pub const WriteError = posix.PWriteError;
198
+
199
+ pub fn write(
200
+ self: *IO,
201
+ comptime Context: type,
202
+ context: Context,
203
+ comptime callback: fn (
204
+ context: Context,
205
+ completion: *Completion,
206
+ result: WriteError!usize,
207
+ ) void,
208
+ completion: *Completion,
209
+ fd: fd_t,
210
+ buffer: []const u8,
211
+ offset: u64,
212
+ ) void {
213
+ assert(fd < self.files.len);
214
+
215
+ self.submit(
216
+ context,
217
+ callback,
218
+ completion,
219
+ .write,
220
+ .{
221
+ .fd = fd,
222
+ .buf = buffer.ptr,
223
+ .len = @as(u32, @intCast(buffer_limit(buffer.len))),
224
+ .offset = offset,
225
+ },
226
+ struct {
227
+ fn do_operation(io: *IO, op: anytype) WriteError!usize {
228
+ const data = io.files[op.fd].buffer;
229
+ if (op.offset + op.len >= data.len) {
230
+ @panic("write beyond simulated file size");
231
+ }
232
+ stdx.copy_disjoint(.exact, u8, data[op.offset..][0..op.len], op.buf[0..op.len]);
233
+ return op.len;
234
+ }
235
+ },
236
+ );
237
+ }
238
+
239
+ pub const FsyncError = posix.SyncError;
240
+
241
+ pub fn fsync(
242
+ self: *IO,
243
+ comptime Context: type,
244
+ context: Context,
245
+ comptime callback: fn (
246
+ context: Context,
247
+ completion: *Completion,
248
+ result: FsyncError!void,
249
+ ) void,
250
+ completion: *Completion,
251
+ fd: fd_t,
252
+ ) void {
253
+ assert(fd < self.files.len);
254
+
255
+ self.submit(
256
+ context,
257
+ callback,
258
+ completion,
259
+ .fsync,
260
+ .{ .fd = fd },
261
+ struct {
262
+ fn do_operation(_: *IO, _: anytype) FsyncError!void {}
263
+ },
264
+ );
265
+ }
266
+
267
+ pub fn aof_blocking_write_all(self: *IO, fd: fd_t, source: []const u8) posix.WriteError!void {
268
+ assert(fd < self.files.len);
269
+
270
+ const file_index = @as(u32, @intCast(fd));
271
+ const file = &self.files[file_index];
272
+ const target = file.buffer;
273
+ const offset = file.offset;
274
+
275
+ assert(offset + source.len <= target.len);
276
+
277
+ stdx.copy_disjoint(.exact, u8, target[offset..][0..source.len], source);
278
+
279
+ file.offset += @as(u32, @intCast(source.len));
280
+ }
281
+
282
+ pub const PReadError = posix.PReadError;
283
+
284
+ pub fn aof_blocking_close(self: *IO, fd: fd_t) void {
285
+ assert(fd < self.files.len);
286
+ self.files[fd].closed = true;
287
+ }
288
+
289
+ pub fn aof_blocking_pread_all(self: *IO, fd: fd_t, target: []u8, offset: u64) PReadError!usize {
290
+ assert(fd < self.files.len);
291
+
292
+ const file_index = @as(u32, @intCast(fd));
293
+ const source = self.files[file_index].buffer;
294
+
295
+ assert(offset + target.len <= source.len);
296
+
297
+ stdx.copy_disjoint(.exact, u8, target, source[offset..][0..target.len]);
298
+
299
+ return target.len;
300
+ }
301
+
302
+ pub fn aof_blocking_stat(_: *IO, _: []const u8) std.fs.Dir.StatFileError!std.fs.File.Stat {
303
+ return error.Unexpected;
304
+ }
305
+
306
+ pub fn aof_blocking_fstat(_: *IO, _: fd_t) std.fs.Dir.StatError!std.fs.File.Stat {
307
+ return error.Unexpected;
308
+ }
309
+
310
+ pub fn aof_blocking_open(_: *IO, _: []const u8) !fd_t {
311
+ return error.Unexpected;
312
+ }
313
+
314
+ pub fn reset(self: *IO) void {
315
+ self.completed.reset();
316
+ }
317
+ };
@@ -0,0 +1,126 @@
1
+ //! This file piggy-backs on the logging infrastructure to implement explicit coverage marks:
2
+ //! <https://ferrous-systems.com/blog/coverage-marks/>
3
+ //!
4
+ //! In production code, you can mark certain log lines as "this should be covered by a test".
5
+ //! In test code, you can then assert that a _specific_ test covers a specific log line. The two
6
+ //! benefits are:
7
+ //! - tests are more resilient to refactors
8
+ //! - production code is more readable (you can immediately jump to a specific test)
9
+ //!
10
+ //! At the surface level, this resembles usual code coverage, but the idea is closer to traceability
11
+ //! from safety-critical systems:
12
+ //! <https://en.wikipedia.org/wiki/Requirements_traceability>
13
+ //!
14
+ //! That is, the important part is not that a log line is covered at all, but that we can trace
15
+ //! production code to a single minimal hand-written test which explains why the code needs to
16
+ //! exist.
17
+ test "tutorial" {
18
+ // Import by a qualified name.
19
+ const marks = @import("./marks.zig");
20
+
21
+ const production_code = struct {
22
+ // In production code, wrap the logger.
23
+ const log = marks.wrap_log(std.log.scoped(.my_module));
24
+
25
+ fn function_under_test(x: u32) void {
26
+ if (x % 2 == 0) {
27
+ // Both `log.info` and log.covered.info` are available.
28
+ // Only second version records coverage.
29
+ log.mark.info("x is even (x={})", .{x});
30
+ }
31
+ }
32
+ };
33
+
34
+ // Create a mark with the `mark` function...
35
+ const mark = marks.check("x is even");
36
+ production_code.function_under_test(92);
37
+ try mark.expect_hit(); // ... and don't forget to assert at the end!
38
+ }
39
+
40
+ const std = @import("std");
41
+ const assert = std.debug.assert;
42
+ const builtin = @import("builtin");
43
+
44
+ const GlobalStateType = if (builtin.is_test) struct {
45
+ mark_name: ?[]const u8 = null,
46
+ mark_hit_count: u32 = 0,
47
+ } else void;
48
+
49
+ /// Stores the currently active mark and its hit count. State is not synchronized and assumes
50
+ /// single threaded execution.
51
+ var global_state: GlobalStateType = .{};
52
+
53
+ pub const Mark = struct {
54
+ name: []const u8,
55
+
56
+ pub fn expect_hit(mark: Mark) !void {
57
+ comptime assert(builtin.is_test);
58
+ assert(global_state.mark_name.?.ptr == mark.name.ptr);
59
+ defer global_state = .{};
60
+
61
+ if (global_state.mark_hit_count == 0) {
62
+ std.debug.print("mark '{s}' not hit", .{mark.name});
63
+ return error.MarkNotHit;
64
+ }
65
+ }
66
+
67
+ pub fn expect_not_hit(mark: Mark) !void {
68
+ comptime assert(builtin.is_test);
69
+ assert(global_state.mark_name.?.ptr == mark.name.ptr);
70
+ defer global_state = .{};
71
+
72
+ if (global_state.mark_hit_count != 0) {
73
+ std.debug.print("mark '{s}' hit", .{mark.name});
74
+ return error.MarkHit;
75
+ }
76
+ }
77
+ };
78
+
79
+ pub fn check(name: []const u8) Mark {
80
+ comptime assert(builtin.is_test);
81
+ assert(global_state.mark_name == null);
82
+ assert(global_state.mark_hit_count == 0);
83
+
84
+ global_state.mark_name = name;
85
+ return Mark{ .name = name };
86
+ }
87
+
88
+ pub fn wrap_log(comptime base: type) type {
89
+ return struct {
90
+ pub const mark = if (builtin.is_test) struct {
91
+ pub fn err(comptime fmt: []const u8, args: anytype) void {
92
+ record(fmt);
93
+ base.err(fmt, args);
94
+ }
95
+
96
+ pub fn warn(comptime fmt: []const u8, args: anytype) void {
97
+ record(fmt);
98
+ base.warn(fmt, args);
99
+ }
100
+
101
+ pub fn info(comptime fmt: []const u8, args: anytype) void {
102
+ record(fmt);
103
+ base.info(fmt, args);
104
+ }
105
+
106
+ pub fn debug(comptime fmt: []const u8, args: anytype) void {
107
+ record(fmt);
108
+ base.debug(fmt, args);
109
+ }
110
+ } else base;
111
+
112
+ pub const err = base.err;
113
+ pub const warn = base.warn;
114
+ pub const info = base.info;
115
+ pub const debug = base.debug;
116
+ };
117
+ }
118
+
119
+ fn record(fmt: []const u8) void {
120
+ comptime assert(builtin.is_test);
121
+ if (global_state.mark_name) |mark_active| {
122
+ if (std.mem.indexOf(u8, fmt, mark_active) != null) {
123
+ global_state.mark_hit_count += 1;
124
+ }
125
+ }
126
+ }