tigerbeetle 0.0.36 → 0.0.37

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 (247) hide show
  1. checksums.yaml +4 -4
  2. data/ext/tb_client/extconf.rb +13 -13
  3. data/ext/tb_client/tigerbeetle/LICENSE +177 -0
  4. data/ext/tb_client/tigerbeetle/build.zig +2327 -0
  5. data/ext/tb_client/tigerbeetle/src/aof.zig +1000 -0
  6. data/ext/tb_client/tigerbeetle/src/build_multiversion.zig +808 -0
  7. data/ext/tb_client/tigerbeetle/src/cdc/amqp/protocol.zig +1283 -0
  8. data/ext/tb_client/tigerbeetle/src/cdc/amqp/spec.zig +1704 -0
  9. data/ext/tb_client/tigerbeetle/src/cdc/amqp/types.zig +341 -0
  10. data/ext/tb_client/tigerbeetle/src/cdc/amqp.zig +1450 -0
  11. data/ext/tb_client/tigerbeetle/src/cdc/runner.zig +1659 -0
  12. data/ext/tb_client/tigerbeetle/src/clients/c/samples/main.c +406 -0
  13. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/context.zig +1084 -0
  14. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/echo_client.zig +286 -0
  15. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/packet.zig +158 -0
  16. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/signal.zig +229 -0
  17. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/signal_fuzz.zig +110 -0
  18. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client.h +386 -0
  19. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client.zig +34 -0
  20. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_exports.zig +281 -0
  21. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_header.zig +312 -0
  22. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_header_test.zig +138 -0
  23. data/ext/tb_client/tigerbeetle/src/clients/c/test.zig +466 -0
  24. data/ext/tb_client/tigerbeetle/src/clients/docs_samples.zig +157 -0
  25. data/ext/tb_client/tigerbeetle/src/clients/docs_types.zig +90 -0
  26. data/ext/tb_client/tigerbeetle/src/clients/dotnet/ci.zig +203 -0
  27. data/ext/tb_client/tigerbeetle/src/clients/dotnet/docs.zig +79 -0
  28. data/ext/tb_client/tigerbeetle/src/clients/dotnet/dotnet_bindings.zig +542 -0
  29. data/ext/tb_client/tigerbeetle/src/clients/go/ci.zig +109 -0
  30. data/ext/tb_client/tigerbeetle/src/clients/go/docs.zig +86 -0
  31. data/ext/tb_client/tigerbeetle/src/clients/go/go_bindings.zig +370 -0
  32. data/ext/tb_client/tigerbeetle/src/clients/go/pkg/native/tb_client.h +386 -0
  33. data/ext/tb_client/tigerbeetle/src/clients/java/ci.zig +167 -0
  34. data/ext/tb_client/tigerbeetle/src/clients/java/docs.zig +126 -0
  35. data/ext/tb_client/tigerbeetle/src/clients/java/java_bindings.zig +996 -0
  36. data/ext/tb_client/tigerbeetle/src/clients/java/src/client.zig +748 -0
  37. data/ext/tb_client/tigerbeetle/src/clients/java/src/jni.zig +3238 -0
  38. data/ext/tb_client/tigerbeetle/src/clients/java/src/jni_tests.zig +1718 -0
  39. data/ext/tb_client/tigerbeetle/src/clients/java/src/jni_thread_cleaner.zig +190 -0
  40. data/ext/tb_client/tigerbeetle/src/clients/node/ci.zig +104 -0
  41. data/ext/tb_client/tigerbeetle/src/clients/node/docs.zig +75 -0
  42. data/ext/tb_client/tigerbeetle/src/clients/node/node.zig +522 -0
  43. data/ext/tb_client/tigerbeetle/src/clients/node/node_bindings.zig +267 -0
  44. data/ext/tb_client/tigerbeetle/src/clients/node/src/c.zig +3 -0
  45. data/ext/tb_client/tigerbeetle/src/clients/node/src/translate.zig +379 -0
  46. data/ext/tb_client/tigerbeetle/src/clients/python/ci.zig +131 -0
  47. data/ext/tb_client/tigerbeetle/src/clients/python/docs.zig +63 -0
  48. data/ext/tb_client/tigerbeetle/src/clients/python/python_bindings.zig +588 -0
  49. data/ext/tb_client/tigerbeetle/src/clients/rust/assets/tb_client.h +386 -0
  50. data/ext/tb_client/tigerbeetle/src/clients/rust/ci.zig +73 -0
  51. data/ext/tb_client/tigerbeetle/src/clients/rust/docs.zig +106 -0
  52. data/ext/tb_client/tigerbeetle/src/clients/rust/rust_bindings.zig +305 -0
  53. data/ext/tb_client/tigerbeetle/src/config.zig +296 -0
  54. data/ext/tb_client/tigerbeetle/src/constants.zig +790 -0
  55. data/ext/tb_client/tigerbeetle/src/copyhound.zig +202 -0
  56. data/ext/tb_client/tigerbeetle/src/counting_allocator.zig +72 -0
  57. data/ext/tb_client/tigerbeetle/src/direction.zig +11 -0
  58. data/ext/tb_client/tigerbeetle/src/docs_website/build.zig +158 -0
  59. data/ext/tb_client/tigerbeetle/src/docs_website/src/content.zig +156 -0
  60. data/ext/tb_client/tigerbeetle/src/docs_website/src/docs.zig +252 -0
  61. data/ext/tb_client/tigerbeetle/src/docs_website/src/file_checker.zig +313 -0
  62. data/ext/tb_client/tigerbeetle/src/docs_website/src/html.zig +87 -0
  63. data/ext/tb_client/tigerbeetle/src/docs_website/src/page_writer.zig +63 -0
  64. data/ext/tb_client/tigerbeetle/src/docs_website/src/redirects.zig +47 -0
  65. data/ext/tb_client/tigerbeetle/src/docs_website/src/search_index_writer.zig +28 -0
  66. data/ext/tb_client/tigerbeetle/src/docs_website/src/service_worker_writer.zig +61 -0
  67. data/ext/tb_client/tigerbeetle/src/docs_website/src/single_page_writer.zig +169 -0
  68. data/ext/tb_client/tigerbeetle/src/docs_website/src/website.zig +46 -0
  69. data/ext/tb_client/tigerbeetle/src/ewah.zig +445 -0
  70. data/ext/tb_client/tigerbeetle/src/ewah_benchmark.zig +128 -0
  71. data/ext/tb_client/tigerbeetle/src/ewah_fuzz.zig +171 -0
  72. data/ext/tb_client/tigerbeetle/src/fuzz_tests.zig +179 -0
  73. data/ext/tb_client/tigerbeetle/src/integration_tests.zig +662 -0
  74. data/ext/tb_client/tigerbeetle/src/io/common.zig +155 -0
  75. data/ext/tb_client/tigerbeetle/src/io/darwin.zig +1093 -0
  76. data/ext/tb_client/tigerbeetle/src/io/linux.zig +1880 -0
  77. data/ext/tb_client/tigerbeetle/src/io/test.zig +1005 -0
  78. data/ext/tb_client/tigerbeetle/src/io/windows.zig +1598 -0
  79. data/ext/tb_client/tigerbeetle/src/io.zig +34 -0
  80. data/ext/tb_client/tigerbeetle/src/iops.zig +134 -0
  81. data/ext/tb_client/tigerbeetle/src/list.zig +236 -0
  82. data/ext/tb_client/tigerbeetle/src/lsm/binary_search.zig +848 -0
  83. data/ext/tb_client/tigerbeetle/src/lsm/binary_search_benchmark.zig +179 -0
  84. data/ext/tb_client/tigerbeetle/src/lsm/cache_map.zig +424 -0
  85. data/ext/tb_client/tigerbeetle/src/lsm/cache_map_fuzz.zig +420 -0
  86. data/ext/tb_client/tigerbeetle/src/lsm/compaction.zig +2117 -0
  87. data/ext/tb_client/tigerbeetle/src/lsm/composite_key.zig +182 -0
  88. data/ext/tb_client/tigerbeetle/src/lsm/forest.zig +1119 -0
  89. data/ext/tb_client/tigerbeetle/src/lsm/forest_fuzz.zig +1102 -0
  90. data/ext/tb_client/tigerbeetle/src/lsm/forest_table_iterator.zig +200 -0
  91. data/ext/tb_client/tigerbeetle/src/lsm/groove.zig +1495 -0
  92. data/ext/tb_client/tigerbeetle/src/lsm/k_way_merge.zig +739 -0
  93. data/ext/tb_client/tigerbeetle/src/lsm/k_way_merge_benchmark.zig +166 -0
  94. data/ext/tb_client/tigerbeetle/src/lsm/manifest.zig +754 -0
  95. data/ext/tb_client/tigerbeetle/src/lsm/manifest_level.zig +1294 -0
  96. data/ext/tb_client/tigerbeetle/src/lsm/manifest_level_fuzz.zig +510 -0
  97. data/ext/tb_client/tigerbeetle/src/lsm/manifest_log.zig +1263 -0
  98. data/ext/tb_client/tigerbeetle/src/lsm/manifest_log_fuzz.zig +628 -0
  99. data/ext/tb_client/tigerbeetle/src/lsm/node_pool.zig +247 -0
  100. data/ext/tb_client/tigerbeetle/src/lsm/scan_buffer.zig +116 -0
  101. data/ext/tb_client/tigerbeetle/src/lsm/scan_builder.zig +543 -0
  102. data/ext/tb_client/tigerbeetle/src/lsm/scan_fuzz.zig +938 -0
  103. data/ext/tb_client/tigerbeetle/src/lsm/scan_lookup.zig +293 -0
  104. data/ext/tb_client/tigerbeetle/src/lsm/scan_merge.zig +362 -0
  105. data/ext/tb_client/tigerbeetle/src/lsm/scan_range.zig +99 -0
  106. data/ext/tb_client/tigerbeetle/src/lsm/scan_state.zig +17 -0
  107. data/ext/tb_client/tigerbeetle/src/lsm/scan_tree.zig +1036 -0
  108. data/ext/tb_client/tigerbeetle/src/lsm/schema.zig +617 -0
  109. data/ext/tb_client/tigerbeetle/src/lsm/scratch_memory.zig +84 -0
  110. data/ext/tb_client/tigerbeetle/src/lsm/segmented_array.zig +1500 -0
  111. data/ext/tb_client/tigerbeetle/src/lsm/segmented_array_benchmark.zig +149 -0
  112. data/ext/tb_client/tigerbeetle/src/lsm/segmented_array_fuzz.zig +7 -0
  113. data/ext/tb_client/tigerbeetle/src/lsm/set_associative_cache.zig +865 -0
  114. data/ext/tb_client/tigerbeetle/src/lsm/table.zig +607 -0
  115. data/ext/tb_client/tigerbeetle/src/lsm/table_memory.zig +843 -0
  116. data/ext/tb_client/tigerbeetle/src/lsm/table_value_iterator.zig +105 -0
  117. data/ext/tb_client/tigerbeetle/src/lsm/timestamp_range.zig +40 -0
  118. data/ext/tb_client/tigerbeetle/src/lsm/tree.zig +630 -0
  119. data/ext/tb_client/tigerbeetle/src/lsm/tree_fuzz.zig +933 -0
  120. data/ext/tb_client/tigerbeetle/src/lsm/zig_zag_merge.zig +557 -0
  121. data/ext/tb_client/tigerbeetle/src/message_buffer.zig +469 -0
  122. data/ext/tb_client/tigerbeetle/src/message_bus.zig +1214 -0
  123. data/ext/tb_client/tigerbeetle/src/message_bus_fuzz.zig +936 -0
  124. data/ext/tb_client/tigerbeetle/src/message_pool.zig +343 -0
  125. data/ext/tb_client/tigerbeetle/src/multiversion.zig +2195 -0
  126. data/ext/tb_client/tigerbeetle/src/queue.zig +390 -0
  127. data/ext/tb_client/tigerbeetle/src/repl/completion.zig +201 -0
  128. data/ext/tb_client/tigerbeetle/src/repl/parser.zig +1356 -0
  129. data/ext/tb_client/tigerbeetle/src/repl/terminal.zig +496 -0
  130. data/ext/tb_client/tigerbeetle/src/repl.zig +1034 -0
  131. data/ext/tb_client/tigerbeetle/src/scripts/amqp.zig +973 -0
  132. data/ext/tb_client/tigerbeetle/src/scripts/cfo.zig +1866 -0
  133. data/ext/tb_client/tigerbeetle/src/scripts/changelog.zig +304 -0
  134. data/ext/tb_client/tigerbeetle/src/scripts/ci.zig +227 -0
  135. data/ext/tb_client/tigerbeetle/src/scripts/client_readmes.zig +658 -0
  136. data/ext/tb_client/tigerbeetle/src/scripts/devhub.zig +466 -0
  137. data/ext/tb_client/tigerbeetle/src/scripts/release.zig +1058 -0
  138. data/ext/tb_client/tigerbeetle/src/scripts.zig +105 -0
  139. data/ext/tb_client/tigerbeetle/src/shell.zig +1195 -0
  140. data/ext/tb_client/tigerbeetle/src/stack.zig +260 -0
  141. data/ext/tb_client/tigerbeetle/src/state_machine/auditor.zig +911 -0
  142. data/ext/tb_client/tigerbeetle/src/state_machine/workload.zig +2079 -0
  143. data/ext/tb_client/tigerbeetle/src/state_machine.zig +4872 -0
  144. data/ext/tb_client/tigerbeetle/src/state_machine_fuzz.zig +288 -0
  145. data/ext/tb_client/tigerbeetle/src/state_machine_tests.zig +3128 -0
  146. data/ext/tb_client/tigerbeetle/src/static_allocator.zig +82 -0
  147. data/ext/tb_client/tigerbeetle/src/stdx/bit_set.zig +157 -0
  148. data/ext/tb_client/tigerbeetle/src/stdx/bounded_array.zig +292 -0
  149. data/ext/tb_client/tigerbeetle/src/stdx/debug.zig +65 -0
  150. data/ext/tb_client/tigerbeetle/src/stdx/flags.zig +1414 -0
  151. data/ext/tb_client/tigerbeetle/src/stdx/mlock.zig +92 -0
  152. data/ext/tb_client/tigerbeetle/src/stdx/prng.zig +677 -0
  153. data/ext/tb_client/tigerbeetle/src/stdx/radix.zig +336 -0
  154. data/ext/tb_client/tigerbeetle/src/stdx/ring_buffer.zig +511 -0
  155. data/ext/tb_client/tigerbeetle/src/stdx/sort_test.zig +112 -0
  156. data/ext/tb_client/tigerbeetle/src/stdx/stdx.zig +1160 -0
  157. data/ext/tb_client/tigerbeetle/src/stdx/testing/low_level_hash_vectors.zig +142 -0
  158. data/ext/tb_client/tigerbeetle/src/stdx/testing/snaptest.zig +361 -0
  159. data/ext/tb_client/tigerbeetle/src/stdx/time_units.zig +275 -0
  160. data/ext/tb_client/tigerbeetle/src/stdx/unshare.zig +295 -0
  161. data/ext/tb_client/tigerbeetle/src/stdx/vendored/aegis.zig +436 -0
  162. data/ext/tb_client/tigerbeetle/src/stdx/windows.zig +48 -0
  163. data/ext/tb_client/tigerbeetle/src/stdx/zipfian.zig +402 -0
  164. data/ext/tb_client/tigerbeetle/src/storage.zig +489 -0
  165. data/ext/tb_client/tigerbeetle/src/storage_fuzz.zig +180 -0
  166. data/ext/tb_client/tigerbeetle/src/testing/bench.zig +146 -0
  167. data/ext/tb_client/tigerbeetle/src/testing/cluster/grid_checker.zig +53 -0
  168. data/ext/tb_client/tigerbeetle/src/testing/cluster/journal_checker.zig +61 -0
  169. data/ext/tb_client/tigerbeetle/src/testing/cluster/manifest_checker.zig +76 -0
  170. data/ext/tb_client/tigerbeetle/src/testing/cluster/message_bus.zig +110 -0
  171. data/ext/tb_client/tigerbeetle/src/testing/cluster/network.zig +412 -0
  172. data/ext/tb_client/tigerbeetle/src/testing/cluster/state_checker.zig +331 -0
  173. data/ext/tb_client/tigerbeetle/src/testing/cluster/storage_checker.zig +458 -0
  174. data/ext/tb_client/tigerbeetle/src/testing/cluster.zig +1198 -0
  175. data/ext/tb_client/tigerbeetle/src/testing/exhaustigen.zig +128 -0
  176. data/ext/tb_client/tigerbeetle/src/testing/fixtures.zig +181 -0
  177. data/ext/tb_client/tigerbeetle/src/testing/fuzz.zig +144 -0
  178. data/ext/tb_client/tigerbeetle/src/testing/id.zig +97 -0
  179. data/ext/tb_client/tigerbeetle/src/testing/io.zig +317 -0
  180. data/ext/tb_client/tigerbeetle/src/testing/marks.zig +126 -0
  181. data/ext/tb_client/tigerbeetle/src/testing/packet_simulator.zig +533 -0
  182. data/ext/tb_client/tigerbeetle/src/testing/reply_sequence.zig +154 -0
  183. data/ext/tb_client/tigerbeetle/src/testing/state_machine.zig +389 -0
  184. data/ext/tb_client/tigerbeetle/src/testing/storage.zig +1247 -0
  185. data/ext/tb_client/tigerbeetle/src/testing/table.zig +249 -0
  186. data/ext/tb_client/tigerbeetle/src/testing/time.zig +98 -0
  187. data/ext/tb_client/tigerbeetle/src/testing/tmp_tigerbeetle.zig +212 -0
  188. data/ext/tb_client/tigerbeetle/src/testing/vortex/constants.zig +26 -0
  189. data/ext/tb_client/tigerbeetle/src/testing/vortex/faulty_network.zig +580 -0
  190. data/ext/tb_client/tigerbeetle/src/testing/vortex/java_driver/ci.zig +39 -0
  191. data/ext/tb_client/tigerbeetle/src/testing/vortex/logged_process.zig +214 -0
  192. data/ext/tb_client/tigerbeetle/src/testing/vortex/rust_driver/ci.zig +34 -0
  193. data/ext/tb_client/tigerbeetle/src/testing/vortex/supervisor.zig +766 -0
  194. data/ext/tb_client/tigerbeetle/src/testing/vortex/workload.zig +543 -0
  195. data/ext/tb_client/tigerbeetle/src/testing/vortex/zig_driver.zig +181 -0
  196. data/ext/tb_client/tigerbeetle/src/tidy.zig +1448 -0
  197. data/ext/tb_client/tigerbeetle/src/tigerbeetle/benchmark_driver.zig +227 -0
  198. data/ext/tb_client/tigerbeetle/src/tigerbeetle/benchmark_load.zig +1069 -0
  199. data/ext/tb_client/tigerbeetle/src/tigerbeetle/cli.zig +1422 -0
  200. data/ext/tb_client/tigerbeetle/src/tigerbeetle/inspect.zig +1658 -0
  201. data/ext/tb_client/tigerbeetle/src/tigerbeetle/inspect_integrity.zig +518 -0
  202. data/ext/tb_client/tigerbeetle/src/tigerbeetle/libtb_client.zig +36 -0
  203. data/ext/tb_client/tigerbeetle/src/tigerbeetle/main.zig +646 -0
  204. data/ext/tb_client/tigerbeetle/src/tigerbeetle.zig +958 -0
  205. data/ext/tb_client/tigerbeetle/src/time.zig +236 -0
  206. data/ext/tb_client/tigerbeetle/src/trace/event.zig +745 -0
  207. data/ext/tb_client/tigerbeetle/src/trace/statsd.zig +462 -0
  208. data/ext/tb_client/tigerbeetle/src/trace.zig +556 -0
  209. data/ext/tb_client/tigerbeetle/src/unit_tests.zig +321 -0
  210. data/ext/tb_client/tigerbeetle/src/vopr.zig +1785 -0
  211. data/ext/tb_client/tigerbeetle/src/vortex.zig +101 -0
  212. data/ext/tb_client/tigerbeetle/src/vsr/checkpoint_trailer.zig +473 -0
  213. data/ext/tb_client/tigerbeetle/src/vsr/checksum.zig +208 -0
  214. data/ext/tb_client/tigerbeetle/src/vsr/checksum_benchmark.zig +43 -0
  215. data/ext/tb_client/tigerbeetle/src/vsr/client.zig +768 -0
  216. data/ext/tb_client/tigerbeetle/src/vsr/client_replies.zig +532 -0
  217. data/ext/tb_client/tigerbeetle/src/vsr/client_sessions.zig +338 -0
  218. data/ext/tb_client/tigerbeetle/src/vsr/clock.zig +1019 -0
  219. data/ext/tb_client/tigerbeetle/src/vsr/fault_detector.zig +279 -0
  220. data/ext/tb_client/tigerbeetle/src/vsr/free_set.zig +1381 -0
  221. data/ext/tb_client/tigerbeetle/src/vsr/free_set_fuzz.zig +315 -0
  222. data/ext/tb_client/tigerbeetle/src/vsr/grid.zig +1460 -0
  223. data/ext/tb_client/tigerbeetle/src/vsr/grid_blocks_missing.zig +757 -0
  224. data/ext/tb_client/tigerbeetle/src/vsr/grid_scrubber.zig +797 -0
  225. data/ext/tb_client/tigerbeetle/src/vsr/journal.zig +2586 -0
  226. data/ext/tb_client/tigerbeetle/src/vsr/marzullo.zig +308 -0
  227. data/ext/tb_client/tigerbeetle/src/vsr/message_header.zig +1777 -0
  228. data/ext/tb_client/tigerbeetle/src/vsr/multi_batch.zig +715 -0
  229. data/ext/tb_client/tigerbeetle/src/vsr/multi_batch_fuzz.zig +185 -0
  230. data/ext/tb_client/tigerbeetle/src/vsr/repair_budget.zig +333 -0
  231. data/ext/tb_client/tigerbeetle/src/vsr/replica.zig +12355 -0
  232. data/ext/tb_client/tigerbeetle/src/vsr/replica_format.zig +416 -0
  233. data/ext/tb_client/tigerbeetle/src/vsr/replica_reformat.zig +165 -0
  234. data/ext/tb_client/tigerbeetle/src/vsr/replica_test.zig +2910 -0
  235. data/ext/tb_client/tigerbeetle/src/vsr/routing.zig +1075 -0
  236. data/ext/tb_client/tigerbeetle/src/vsr/superblock.zig +1603 -0
  237. data/ext/tb_client/tigerbeetle/src/vsr/superblock_fuzz.zig +484 -0
  238. data/ext/tb_client/tigerbeetle/src/vsr/superblock_quorums.zig +405 -0
  239. data/ext/tb_client/tigerbeetle/src/vsr/superblock_quorums_fuzz.zig +355 -0
  240. data/ext/tb_client/tigerbeetle/src/vsr/sync.zig +29 -0
  241. data/ext/tb_client/tigerbeetle/src/vsr.zig +1727 -0
  242. data/lib/tb_client/shared_lib.rb +12 -5
  243. data/lib/tigerbeetle/platforms.rb +9 -0
  244. data/lib/tigerbeetle/version.rb +1 -1
  245. data/tigerbeetle.gemspec +22 -5
  246. metadata +242 -3
  247. data/ext/tb_client/pkg.tar.gz +0 -0
@@ -0,0 +1,580 @@
1
+ //! The `Network` is a set of proxies used to inject network faults in a Vortex test cluster. We
2
+ //! create one `Proxy` per replica in the test cluster. Each proxy has a set of available
3
+ //! `Connection`s, which model the communication through the proxy (replica-to-replica or
4
+ //! client-to-replica). Each `Connection` has two pipes, connecting the peers' inputs and outputs
5
+ //! (recv and send).
6
+ //!
7
+ //! The _mappings_ are pairs of addresses:
8
+ //!
9
+ //! * _origin_: the address on which the proxy listens for connections from _origin_ peers
10
+ //! * _remote_: the address the proxy connects to, to communicate with the _remote_ peers
11
+ //!
12
+ //! A pipe runs, alternating recv and send, until it sees that the connection is no longer proxying
13
+ //! or if there's an error or EOF, in which case it also closes the parent connection.
14
+ //!
15
+ //! When the `Faults` struct is populated with non-null configurations, the pipes inject
16
+ //! corresponding faults according to the probabilities.
17
+ //!
18
+ //! NOTE: The pipe is not yet message-aware (and perhaps shouldn't be?), which means that we deal
19
+ //! with whatever chunks of bytes we receive immediately, instead of collecting a buffer with a
20
+ //! full message before piping it through.
21
+ const std = @import("std");
22
+ const stdx = @import("stdx");
23
+ const IO = @import("../../io.zig").IO;
24
+ const constants = @import("constants.zig");
25
+
26
+ const assert = std.debug.assert;
27
+ const log = std.log.scoped(.faulty_network);
28
+ const Ratio = stdx.PRNG.Ratio;
29
+
30
+ const Faults = struct {
31
+ const Delay = struct {
32
+ time_ms: u32,
33
+ jitter_ms: u32,
34
+ };
35
+
36
+ delay: ?Delay = null,
37
+ lose: ?Ratio = null,
38
+ corrupt: ?Ratio = null,
39
+
40
+ // Others not implemented: duplication, reordering, rate
41
+
42
+ pub fn heal(faults: *Faults) void {
43
+ faults.delay = null;
44
+ faults.lose = null;
45
+ faults.corrupt = null;
46
+ }
47
+
48
+ pub fn is_healed(faults: *const Faults) bool {
49
+ return faults.delay == null and faults.lose == null and faults.corrupt == null;
50
+ }
51
+ };
52
+
53
+ const Pipe = struct {
54
+ io: *IO,
55
+ connection: *Connection,
56
+ input: ?std.posix.socket_t = null,
57
+ output: ?std.posix.socket_t = null,
58
+ buffer: [constants.vsr.message_size_max]u8 = undefined,
59
+ status: enum { idle, recv, send, send_timeout } = .idle,
60
+ recv_size: u32 = 0,
61
+ send_size: u32 = 0,
62
+
63
+ recv_completion: IO.Completion = undefined,
64
+ send_completion: IO.Completion = undefined,
65
+
66
+ fn open(
67
+ pipe: *Pipe,
68
+ input: std.posix.socket_t,
69
+ output: std.posix.socket_t,
70
+ ) void {
71
+ assert(pipe.connection.state == .proxying);
72
+ assert(pipe.status == .idle);
73
+
74
+ pipe.input = input;
75
+ pipe.output = output;
76
+ pipe.recv_size = 0;
77
+ pipe.send_size = 0;
78
+
79
+ // Kick off the recv/send loop.
80
+ pipe.recv();
81
+ }
82
+
83
+ fn recv(pipe: *Pipe) void {
84
+ assert(pipe.send_size <= pipe.recv_size);
85
+ assert(pipe.connection.state == .proxying);
86
+
87
+ assert(pipe.status == .idle);
88
+ pipe.status = .recv;
89
+
90
+ pipe.recv_size = 0;
91
+ pipe.send_size = 0;
92
+
93
+ // We don't need to recv a certain count of bytes, because whatever we recv, we send along.
94
+ pipe.connection.io.recv(
95
+ *Pipe,
96
+ pipe,
97
+ on_recv,
98
+ &pipe.recv_completion,
99
+ pipe.input.?,
100
+ pipe.buffer[0..],
101
+ );
102
+ }
103
+
104
+ fn on_recv(pipe: *Pipe, _: *IO.Completion, result: IO.RecvError!usize) void {
105
+ assert(pipe.recv_size == 0);
106
+ assert(pipe.send_size == 0);
107
+
108
+ assert(pipe.status == .recv);
109
+ pipe.status = .idle;
110
+
111
+ if (pipe.connection.state != .proxying) return;
112
+
113
+ const recv_size = result catch |err| {
114
+ log.warn("recv error ({d},{d}): {any}", .{
115
+ pipe.connection.replica_index,
116
+ pipe.connection.connection_index,
117
+ err,
118
+ });
119
+ return pipe.connection.try_close();
120
+ };
121
+
122
+ pipe.recv_size = @intCast(recv_size);
123
+ if (pipe.recv_size == 0) {
124
+ // Zero bytes means EOF.
125
+ return pipe.connection.try_close();
126
+ }
127
+
128
+ if (pipe.connection.network.faults.lose) |lose| {
129
+ if (pipe.connection.network.prng.chance(lose)) {
130
+ log.debug("losing {d} bytes ({d},{d})", .{
131
+ pipe.recv_size,
132
+ pipe.connection.replica_index,
133
+ pipe.connection.connection_index,
134
+ });
135
+ pipe.recv();
136
+ return;
137
+ }
138
+ }
139
+
140
+ if (pipe.connection.network.faults.corrupt) |corrupt| {
141
+ if (pipe.connection.network.prng.chance(corrupt)) {
142
+ switch (pipe.connection.network.prng.enum_uniform(enum { shuffle, zero })) {
143
+ .shuffle => {
144
+ log.debug("shuffling {d} bytes ({d},{d})", .{
145
+ pipe.recv_size,
146
+ pipe.connection.replica_index,
147
+ pipe.connection.connection_index,
148
+ });
149
+ pipe.connection.network.prng.shuffle(u8, pipe.buffer[0..pipe.recv_size]);
150
+ },
151
+ .zero => {
152
+ log.debug("zeroing {d} bytes ({d},{d})", .{
153
+ pipe.recv_size,
154
+ pipe.connection.replica_index,
155
+ pipe.connection.connection_index,
156
+ });
157
+ @memset(pipe.buffer[0..pipe.recv_size], 0);
158
+ },
159
+ }
160
+ }
161
+ }
162
+
163
+ if (pipe.connection.network.faults.delay) |delay| {
164
+ assert(delay.jitter_ms <= delay.time_ms);
165
+ const jitter_size = pipe.connection.network.prng.int_inclusive(
166
+ u32,
167
+ delay.jitter_ms,
168
+ );
169
+ const jitter_diff_ms: i32 = @as(i32, @intCast(jitter_size)) *
170
+ (if (pipe.connection.network.prng.boolean()) @as(i32, 1) else -1);
171
+ const timeout_duration_ns = @as(
172
+ u63,
173
+ @intCast(@as(i32, @intCast(delay.time_ms)) + jitter_diff_ms),
174
+ ) * std.time.ns_per_ms;
175
+ log.debug("delaying {} ({d},{d})", .{
176
+ std.fmt.fmtDuration(timeout_duration_ns),
177
+ pipe.connection.replica_index,
178
+ pipe.connection.connection_index,
179
+ });
180
+
181
+ assert(pipe.status == .idle);
182
+ pipe.status = .send_timeout;
183
+ pipe.io.timeout(*Pipe, pipe, on_timeout, &pipe.send_completion, timeout_duration_ns);
184
+ } else {
185
+ pipe.send();
186
+ }
187
+ }
188
+
189
+ fn on_timeout(pipe: *Pipe, _: *IO.Completion, result: IO.TimeoutError!void) void {
190
+ assert(pipe.status == .send_timeout);
191
+ pipe.status = .idle;
192
+
193
+ if (pipe.connection.state != .proxying) return;
194
+
195
+ result catch @panic("timeout error");
196
+ pipe.send();
197
+ }
198
+
199
+ fn send(pipe: *Pipe) void {
200
+ assert(pipe.connection.state == .proxying);
201
+ assert(pipe.send_size < pipe.recv_size);
202
+
203
+ assert(pipe.status == .idle);
204
+ pipe.status = .send;
205
+
206
+ pipe.io.send(
207
+ *Pipe,
208
+ pipe,
209
+ on_send,
210
+ &pipe.send_completion,
211
+ pipe.output.?,
212
+ pipe.buffer[pipe.send_size..pipe.recv_size],
213
+ );
214
+ }
215
+
216
+ fn on_send(pipe: *Pipe, _: *IO.Completion, result: IO.SendError!usize) void {
217
+ assert(pipe.send_size < pipe.recv_size);
218
+
219
+ assert(pipe.status == .send);
220
+ pipe.status = .idle;
221
+
222
+ if (pipe.connection.state != .proxying) return;
223
+
224
+ const send_size = result catch |err| {
225
+ log.warn("send error ({d},{d}): {any}", .{
226
+ pipe.connection.replica_index,
227
+ pipe.connection.connection_index,
228
+ err,
229
+ });
230
+ return pipe.connection.try_close();
231
+ };
232
+ pipe.send_size += @intCast(send_size);
233
+
234
+ if (pipe.send_size < pipe.recv_size) {
235
+ pipe.send();
236
+ } else {
237
+ assert(pipe.send_size == pipe.recv_size);
238
+ pipe.recv();
239
+ }
240
+ }
241
+ };
242
+
243
+ const Connection = struct {
244
+ io: *IO,
245
+ network: *Network,
246
+ state: enum {
247
+ free,
248
+ accepting,
249
+ connecting,
250
+ proxying,
251
+ closing,
252
+ closing_origin,
253
+ closing_remote,
254
+ } = .free,
255
+
256
+ replica_index: usize,
257
+ connection_index: usize,
258
+
259
+ origin_fd: ?std.posix.socket_t = null,
260
+ remote_fd: ?std.posix.socket_t = null,
261
+
262
+ origin_to_remote_pipe: Pipe,
263
+ remote_to_origin_pipe: Pipe,
264
+
265
+ remote_address: ?std.net.Address = null,
266
+
267
+ accept_completion: IO.Completion = undefined,
268
+ connect_completion: IO.Completion = undefined,
269
+ close_completion: IO.Completion = undefined,
270
+
271
+ fn on_accept(
272
+ connection: *Connection,
273
+ _: *IO.Completion,
274
+ result: IO.AcceptError!std.posix.socket_t,
275
+ ) void {
276
+ assert(connection.state == .accepting);
277
+ defer assert(connection.state == .connecting);
278
+
279
+ assert(connection.origin_fd == null);
280
+ defer assert(connection.origin_fd != null);
281
+
282
+ assert(connection.remote_fd == null);
283
+ defer assert(connection.remote_fd != null);
284
+
285
+ assert(connection.remote_address != null);
286
+
287
+ const fd = result catch |err| {
288
+ log.warn("accept failed ({d},{d}): {}", .{
289
+ connection.replica_index,
290
+ connection.connection_index,
291
+ err,
292
+ });
293
+ return connection.try_close();
294
+ };
295
+ connection.origin_fd = fd;
296
+
297
+ const remote_fd = connection.io.open_socket_tcp(
298
+ connection.remote_address.?.any.family,
299
+ tcp_options,
300
+ ) catch |err| {
301
+ log.warn("couldn't open socket for remote ({d},{d}): {}", .{
302
+ connection.replica_index,
303
+ connection.connection_index,
304
+ err,
305
+ });
306
+ return connection.try_close();
307
+ };
308
+ connection.remote_fd = remote_fd;
309
+
310
+ connection.state = .connecting;
311
+
312
+ connection.io.connect(
313
+ *Connection,
314
+ connection,
315
+ Connection.on_connect,
316
+ &connection.connect_completion,
317
+ connection.remote_fd.?,
318
+ connection.remote_address.?,
319
+ );
320
+ }
321
+
322
+ fn on_connect(
323
+ connection: *Connection,
324
+ _: *IO.Completion,
325
+ result: IO.ConnectError!void,
326
+ ) void {
327
+ assert(connection.state == .connecting);
328
+ assert(connection.origin_fd != null);
329
+ assert(connection.remote_fd != null);
330
+
331
+ result catch |err| {
332
+ log.warn("connect failed ({d},{d}): {}", .{
333
+ connection.replica_index,
334
+ connection.connection_index,
335
+ err,
336
+ });
337
+ return connection.try_close();
338
+ };
339
+ connection.state = .proxying;
340
+ connection.origin_to_remote_pipe.open(connection.origin_fd.?, connection.remote_fd.?);
341
+ connection.remote_to_origin_pipe.open(connection.remote_fd.?, connection.origin_fd.?);
342
+ }
343
+
344
+ fn try_close(connection: *Connection) void {
345
+ assert(connection.state != .free);
346
+
347
+ if (connection.state == .closing_origin or
348
+ connection.state == .closing_remote) return;
349
+
350
+ const has_inflight_operations =
351
+ connection.origin_to_remote_pipe.status != .idle or
352
+ connection.remote_to_origin_pipe.status != .idle;
353
+
354
+ if (connection.state != .closing and has_inflight_operations) {
355
+ log.debug("try_close ({d},{d}): marking connection as closing", .{
356
+ connection.replica_index,
357
+ connection.connection_index,
358
+ });
359
+ connection.state = .closing;
360
+ std.posix.shutdown(connection.origin_fd.?, .both) catch |err| {
361
+ switch (err) {
362
+ error.SocketNotConnected => {},
363
+ else => log.warn("shutdown origin_fd ({d},{d}) failed: {}", .{
364
+ connection.replica_index, connection.connection_index, err,
365
+ }),
366
+ }
367
+ };
368
+ std.posix.shutdown(connection.remote_fd.?, .both) catch |err| {
369
+ switch (err) {
370
+ error.SocketNotConnected => {},
371
+ else => log.warn("shutdown remote_fd ({d},{d}) failed: {}", .{
372
+ connection.replica_index, connection.connection_index, err,
373
+ }),
374
+ }
375
+ };
376
+ }
377
+
378
+ if (!has_inflight_operations) {
379
+ // Kick off the close sequence.
380
+ connection.state = .closing_origin;
381
+ connection.io.close(
382
+ *Connection,
383
+ connection,
384
+ on_close_origin,
385
+ &connection.close_completion,
386
+ connection.origin_fd.?,
387
+ );
388
+ return;
389
+ }
390
+
391
+ assert(connection.state == .closing);
392
+ }
393
+
394
+ fn on_close_origin(
395
+ connection: *Connection,
396
+ _: *IO.Completion,
397
+ result: IO.CloseError!void,
398
+ ) void {
399
+ assert(connection.state == .closing_origin);
400
+ defer assert(connection.state == .closing_remote);
401
+
402
+ assert(connection.origin_fd != null);
403
+ defer assert(connection.origin_fd == null);
404
+
405
+ result catch |err| {
406
+ log.warn("on_close_origin ({d},{d}) error: {any}", .{
407
+ connection.replica_index,
408
+ connection.connection_index,
409
+ err,
410
+ });
411
+ };
412
+
413
+ connection.state = .closing_remote;
414
+ connection.origin_fd = null;
415
+ connection.io.close(
416
+ *Connection,
417
+ connection,
418
+ on_close_remote,
419
+ &connection.close_completion,
420
+ connection.remote_fd.?,
421
+ );
422
+ }
423
+
424
+ fn on_close_remote(
425
+ connection: *Connection,
426
+ _: *IO.Completion,
427
+ result: IO.CloseError!void,
428
+ ) void {
429
+ assert(connection.state == .closing_remote);
430
+ defer assert(connection.state == .free);
431
+
432
+ assert(connection.remote_fd != null);
433
+ defer assert(connection.remote_fd == null);
434
+
435
+ result catch |err| {
436
+ log.warn("on_close_remote ({d},{d}) error: {any}", .{
437
+ connection.replica_index,
438
+ connection.connection_index,
439
+ err,
440
+ });
441
+ };
442
+
443
+ log.debug("on_close_remote ({d},{d}): marking connection as free", .{
444
+ connection.replica_index,
445
+ connection.connection_index,
446
+ });
447
+ connection.state = .free;
448
+ connection.remote_fd = null;
449
+ }
450
+ };
451
+
452
+ const Proxy = struct {
453
+ io: *IO,
454
+ accept_fd: std.posix.socket_t,
455
+ origin_address: std.net.Address, // The proxy's address.
456
+ remote_address: std.net.Address, // The replica's address.
457
+ connections: [constants.vortex.connections_count_max]Connection,
458
+
459
+ fn deinit(proxy: *Proxy) void {
460
+ proxy.io.close_socket(proxy.accept_fd);
461
+ proxy.* = undefined;
462
+ }
463
+ };
464
+
465
+ const tcp_options: IO.TCPOptions = .{
466
+ .rcvbuf = 0,
467
+ .sndbuf = 0,
468
+ .keepalive = null,
469
+ .user_timeout_ms = 0,
470
+ .nodelay = false,
471
+ };
472
+
473
+ pub const Network = struct {
474
+ io: *IO,
475
+ prng: *stdx.PRNG,
476
+ proxies: []Proxy,
477
+ faults: Faults,
478
+
479
+ pub fn listen(
480
+ allocator: std.mem.Allocator,
481
+ prng: *stdx.PRNG,
482
+ io: *IO,
483
+ replica_ports: []const u16,
484
+ ) !*Network {
485
+ const network = try allocator.create(Network);
486
+ errdefer allocator.destroy(network);
487
+
488
+ const proxies = try allocator.alloc(Proxy, replica_ports.len);
489
+ errdefer allocator.free(proxies);
490
+
491
+ network.* = .{
492
+ .io = io,
493
+ .prng = prng,
494
+ .proxies = proxies,
495
+ .faults = std.mem.zeroes(Faults),
496
+ };
497
+
498
+ var proxies_initialized: usize = 0;
499
+ errdefer for (proxies[0..proxies_initialized]) |*proxy| proxy.deinit();
500
+
501
+ // Proxies get an unused port from the ephemeral port range (usually 32768-60999; see
502
+ // /proc/sys/net/ipv4/ip_local_port_range) by listening on port=0.
503
+ // We assume that replicas' ports are from outside of that range and cannot conflict.
504
+ for (proxies, replica_ports, 0..) |*proxy, replica_port, replica_index| {
505
+ const Address = std.net.Address;
506
+ const replica_address = Address.parseIp("127.0.0.1", replica_port) catch unreachable;
507
+ const listen_address = Address.parseIp("127.0.0.1", 0) catch unreachable;
508
+ const listen_fd = try io.open_socket_tcp(std.posix.AF.INET, tcp_options);
509
+ errdefer io.close_socket(listen_fd);
510
+
511
+ const origin_address = try io.listen(listen_fd, listen_address, .{ .backlog = 64 });
512
+ proxy.* = .{
513
+ .io = io,
514
+ .accept_fd = listen_fd,
515
+ .origin_address = origin_address,
516
+ .remote_address = replica_address,
517
+ .connections = undefined,
518
+ };
519
+
520
+ for (&proxy.connections, 0..) |*connection, connection_index| {
521
+ connection.* = .{
522
+ .io = io,
523
+ .network = network,
524
+ .state = .free,
525
+ .replica_index = replica_index,
526
+ .connection_index = connection_index,
527
+ .origin_to_remote_pipe = .{ .io = io, .connection = connection },
528
+ .remote_to_origin_pipe = .{ .io = io, .connection = connection },
529
+ };
530
+ }
531
+ proxies_initialized += 1;
532
+
533
+ log.debug("proxying {any} -> {any}", .{ origin_address, replica_address });
534
+ }
535
+
536
+ return network;
537
+ }
538
+
539
+ pub fn destroy(network: *Network, allocator: std.mem.Allocator) void {
540
+ for (network.proxies) |*proxy| proxy.deinit();
541
+ allocator.free(network.proxies);
542
+ allocator.destroy(network);
543
+ }
544
+
545
+ pub fn tick(network: *Network) void {
546
+ for (network.proxies) |*proxy| {
547
+ for (&proxy.connections) |*connection| {
548
+ if (connection.state == .closing) {
549
+ connection.try_close();
550
+ continue;
551
+ }
552
+ // This proxy tries to accept with connections that are free. The pipes must also
553
+ // have no outstanding IO submissions racing with reusing the pipes for new
554
+ // connections.
555
+ if (connection.state == .free) {
556
+ assert(connection.origin_to_remote_pipe.status == .idle);
557
+ assert(connection.remote_to_origin_pipe.status == .idle);
558
+
559
+ log.debug("accepting ({d},{d})", .{
560
+ connection.replica_index,
561
+ connection.connection_index,
562
+ });
563
+
564
+ connection.state = .accepting;
565
+ connection.remote_address = proxy.remote_address;
566
+ connection.origin_fd = null;
567
+ connection.remote_fd = null;
568
+
569
+ network.io.accept(
570
+ *Connection,
571
+ connection,
572
+ Connection.on_accept,
573
+ &connection.accept_completion,
574
+ proxy.accept_fd,
575
+ );
576
+ }
577
+ }
578
+ }
579
+ }
580
+ };
@@ -0,0 +1,39 @@
1
+ const builtin = @import("builtin");
2
+ const std = @import("std");
3
+ const log = std.log;
4
+ const assert = std.debug.assert;
5
+
6
+ const Shell = @import("../../../shell.zig");
7
+
8
+ pub fn tests(shell: *Shell, gpa: std.mem.Allocator) !void {
9
+ _ = gpa;
10
+
11
+ assert(shell.file_exists("pom.xml"));
12
+
13
+ // NB: This expects the TB java driver to have been installed with `mvn install`.
14
+ try shell.exec("mvn --batch-mode --file pom.xml --quiet package", .{});
15
+
16
+ // NB: This expects the vortex bin to be available.
17
+ if (builtin.target.os.tag == .linux) {
18
+ const base_path = "../../../../";
19
+ const vortex_bin = base_path ++ "zig-out/bin/vortex";
20
+ const class_path_driver = base_path ++
21
+ "src/clients/java/target/tigerbeetle-java-0.0.1-SNAPSHOT.jar";
22
+ const class_path = class_path_driver ++ ":" ++ base_path ++
23
+ "src/testing/vortex/java_driver/target/vortex-driver-java-0.0.1-SNAPSHOT.jar";
24
+ const driver_command = "java -cp " ++ class_path ++ " Main";
25
+ try shell.exec(
26
+ "{vortex_bin} " ++
27
+ "supervisor --driver-command={driver_command} " ++
28
+ "--replica-count=1 " ++
29
+ "--disable-faults " ++
30
+ "--test-duration=1s",
31
+ .{
32
+ .vortex_bin = vortex_bin,
33
+ .driver_command = driver_command,
34
+ },
35
+ );
36
+ } else {
37
+ log.warn("Not testing vortex java on OS {}", .{builtin.target.os.tag});
38
+ }
39
+ }