tigerbeetle 0.0.40 → 0.17.8

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 (293) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +0 -25
  3. data/README.md +670 -80
  4. data/docs/migration.md +201 -0
  5. data/sig/tigerbeetle.rbs +271 -0
  6. data/src/ext/tigerbeetle/extconf.rb +47 -0
  7. data/src/ext/tigerbeetle/lib/aarch64-linux-gnu.2.27/libtb_client.so +0 -0
  8. data/src/ext/tigerbeetle/lib/aarch64-linux-musl/libtb_client.so +0 -0
  9. data/src/ext/tigerbeetle/lib/aarch64-macos/libtb_client.dylib +0 -0
  10. data/src/ext/tigerbeetle/lib/x86_64-linux-gnu.2.27/libtb_client.so +0 -0
  11. data/src/ext/tigerbeetle/lib/x86_64-linux-musl/libtb_client.so +0 -0
  12. data/src/ext/tigerbeetle/lib/x86_64-macos/libtb_client.dylib +0 -0
  13. data/src/ext/tigerbeetle/lib/x86_64-windows/tb_client.dll +0 -0
  14. data/src/ext/tigerbeetle/rb_tb_gen.h +458 -0
  15. data/{ext/tb_client/tigerbeetle/src/clients/rust/assets → src/ext/tigerbeetle}/tb_client.h +18 -16
  16. data/src/ext/tigerbeetle/tigerbeetle.c +310 -0
  17. data/src/tigerbeetle/bindings.rb +347 -0
  18. data/src/tigerbeetle/client.rb +129 -0
  19. data/src/tigerbeetle/completion_dispatcher.rb +108 -0
  20. data/src/tigerbeetle/id.rb +40 -0
  21. data/src/tigerbeetle/tb.rb +3 -0
  22. data/src/tigerbeetle/version.rb +3 -0
  23. data/src/tigerbeetle.rb +39 -0
  24. metadata +33 -350
  25. data/CHANGELOG.md +0 -162
  26. data/ext/tb_client/extconf.rb +0 -41
  27. data/ext/tb_client/tigerbeetle/LICENSE +0 -177
  28. data/ext/tb_client/tigerbeetle/build.zig +0 -2296
  29. data/ext/tb_client/tigerbeetle/src/aof.zig +0 -1000
  30. data/ext/tb_client/tigerbeetle/src/build/fetch.zig +0 -112
  31. data/ext/tb_client/tigerbeetle/src/build_multiversion.zig +0 -808
  32. data/ext/tb_client/tigerbeetle/src/cdc/amqp/protocol.zig +0 -1283
  33. data/ext/tb_client/tigerbeetle/src/cdc/amqp/spec.zig +0 -1704
  34. data/ext/tb_client/tigerbeetle/src/cdc/amqp/types.zig +0 -341
  35. data/ext/tb_client/tigerbeetle/src/cdc/amqp.zig +0 -1450
  36. data/ext/tb_client/tigerbeetle/src/cdc/runner.zig +0 -1659
  37. data/ext/tb_client/tigerbeetle/src/clients/c/samples/main.c +0 -406
  38. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/context.zig +0 -1092
  39. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/echo_client.zig +0 -286
  40. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/packet.zig +0 -158
  41. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/signal.zig +0 -229
  42. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/signal_fuzz.zig +0 -110
  43. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client.h +0 -386
  44. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client.zig +0 -34
  45. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_exports.zig +0 -281
  46. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_header.zig +0 -312
  47. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_header_test.zig +0 -138
  48. data/ext/tb_client/tigerbeetle/src/clients/c/test.zig +0 -466
  49. data/ext/tb_client/tigerbeetle/src/clients/docs_samples.zig +0 -157
  50. data/ext/tb_client/tigerbeetle/src/clients/docs_types.zig +0 -90
  51. data/ext/tb_client/tigerbeetle/src/clients/dotnet/ci.zig +0 -203
  52. data/ext/tb_client/tigerbeetle/src/clients/dotnet/docs.zig +0 -79
  53. data/ext/tb_client/tigerbeetle/src/clients/dotnet/dotnet_bindings.zig +0 -542
  54. data/ext/tb_client/tigerbeetle/src/clients/go/ci.zig +0 -109
  55. data/ext/tb_client/tigerbeetle/src/clients/go/docs.zig +0 -86
  56. data/ext/tb_client/tigerbeetle/src/clients/go/go_bindings.zig +0 -370
  57. data/ext/tb_client/tigerbeetle/src/clients/go/pkg/native/tb_client.h +0 -386
  58. data/ext/tb_client/tigerbeetle/src/clients/java/ci.zig +0 -167
  59. data/ext/tb_client/tigerbeetle/src/clients/java/docs.zig +0 -126
  60. data/ext/tb_client/tigerbeetle/src/clients/java/java_bindings.zig +0 -996
  61. data/ext/tb_client/tigerbeetle/src/clients/java/src/client.zig +0 -748
  62. data/ext/tb_client/tigerbeetle/src/clients/java/src/jni.zig +0 -3238
  63. data/ext/tb_client/tigerbeetle/src/clients/java/src/jni_tests.zig +0 -1718
  64. data/ext/tb_client/tigerbeetle/src/clients/java/src/jni_thread_cleaner.zig +0 -190
  65. data/ext/tb_client/tigerbeetle/src/clients/node/ci.zig +0 -104
  66. data/ext/tb_client/tigerbeetle/src/clients/node/docs.zig +0 -75
  67. data/ext/tb_client/tigerbeetle/src/clients/node/node.zig +0 -522
  68. data/ext/tb_client/tigerbeetle/src/clients/node/node_bindings.zig +0 -267
  69. data/ext/tb_client/tigerbeetle/src/clients/node/src/c.zig +0 -3
  70. data/ext/tb_client/tigerbeetle/src/clients/node/src/translate.zig +0 -379
  71. data/ext/tb_client/tigerbeetle/src/clients/python/ci.zig +0 -131
  72. data/ext/tb_client/tigerbeetle/src/clients/python/docs.zig +0 -63
  73. data/ext/tb_client/tigerbeetle/src/clients/python/python_bindings.zig +0 -588
  74. data/ext/tb_client/tigerbeetle/src/clients/rust/ci.zig +0 -73
  75. data/ext/tb_client/tigerbeetle/src/clients/rust/docs.zig +0 -106
  76. data/ext/tb_client/tigerbeetle/src/clients/rust/rust_bindings.zig +0 -305
  77. data/ext/tb_client/tigerbeetle/src/config.zig +0 -296
  78. data/ext/tb_client/tigerbeetle/src/constants.zig +0 -790
  79. data/ext/tb_client/tigerbeetle/src/copyhound.zig +0 -202
  80. data/ext/tb_client/tigerbeetle/src/counting_allocator.zig +0 -72
  81. data/ext/tb_client/tigerbeetle/src/direction.zig +0 -120
  82. data/ext/tb_client/tigerbeetle/src/docs_website/build.zig +0 -158
  83. data/ext/tb_client/tigerbeetle/src/docs_website/src/content.zig +0 -156
  84. data/ext/tb_client/tigerbeetle/src/docs_website/src/docs.zig +0 -252
  85. data/ext/tb_client/tigerbeetle/src/docs_website/src/file_checker.zig +0 -313
  86. data/ext/tb_client/tigerbeetle/src/docs_website/src/html.zig +0 -87
  87. data/ext/tb_client/tigerbeetle/src/docs_website/src/page_writer.zig +0 -63
  88. data/ext/tb_client/tigerbeetle/src/docs_website/src/redirects.zig +0 -47
  89. data/ext/tb_client/tigerbeetle/src/docs_website/src/search_index_writer.zig +0 -28
  90. data/ext/tb_client/tigerbeetle/src/docs_website/src/service_worker_writer.zig +0 -61
  91. data/ext/tb_client/tigerbeetle/src/docs_website/src/single_page_writer.zig +0 -169
  92. data/ext/tb_client/tigerbeetle/src/docs_website/src/website.zig +0 -46
  93. data/ext/tb_client/tigerbeetle/src/ewah.zig +0 -445
  94. data/ext/tb_client/tigerbeetle/src/ewah_benchmark.zig +0 -128
  95. data/ext/tb_client/tigerbeetle/src/ewah_fuzz.zig +0 -171
  96. data/ext/tb_client/tigerbeetle/src/fuzz_tests.zig +0 -179
  97. data/ext/tb_client/tigerbeetle/src/integration_tests.zig +0 -662
  98. data/ext/tb_client/tigerbeetle/src/io/common.zig +0 -155
  99. data/ext/tb_client/tigerbeetle/src/io/darwin.zig +0 -1093
  100. data/ext/tb_client/tigerbeetle/src/io/linux.zig +0 -1880
  101. data/ext/tb_client/tigerbeetle/src/io/test.zig +0 -1005
  102. data/ext/tb_client/tigerbeetle/src/io/windows.zig +0 -1598
  103. data/ext/tb_client/tigerbeetle/src/io.zig +0 -34
  104. data/ext/tb_client/tigerbeetle/src/iops.zig +0 -134
  105. data/ext/tb_client/tigerbeetle/src/list.zig +0 -236
  106. data/ext/tb_client/tigerbeetle/src/lsm/binary_search.zig +0 -848
  107. data/ext/tb_client/tigerbeetle/src/lsm/binary_search_benchmark.zig +0 -179
  108. data/ext/tb_client/tigerbeetle/src/lsm/cache_map.zig +0 -424
  109. data/ext/tb_client/tigerbeetle/src/lsm/cache_map_fuzz.zig +0 -420
  110. data/ext/tb_client/tigerbeetle/src/lsm/compaction.zig +0 -2114
  111. data/ext/tb_client/tigerbeetle/src/lsm/composite_key.zig +0 -185
  112. data/ext/tb_client/tigerbeetle/src/lsm/forest.zig +0 -1146
  113. data/ext/tb_client/tigerbeetle/src/lsm/forest_fuzz.zig +0 -1102
  114. data/ext/tb_client/tigerbeetle/src/lsm/forest_table_iterator.zig +0 -200
  115. data/ext/tb_client/tigerbeetle/src/lsm/groove.zig +0 -1495
  116. data/ext/tb_client/tigerbeetle/src/lsm/k_way_merge.zig +0 -739
  117. data/ext/tb_client/tigerbeetle/src/lsm/k_way_merge_benchmark.zig +0 -166
  118. data/ext/tb_client/tigerbeetle/src/lsm/manifest.zig +0 -754
  119. data/ext/tb_client/tigerbeetle/src/lsm/manifest_level.zig +0 -1294
  120. data/ext/tb_client/tigerbeetle/src/lsm/manifest_level_fuzz.zig +0 -510
  121. data/ext/tb_client/tigerbeetle/src/lsm/manifest_log.zig +0 -1241
  122. data/ext/tb_client/tigerbeetle/src/lsm/manifest_log_fuzz.zig +0 -628
  123. data/ext/tb_client/tigerbeetle/src/lsm/node_pool.zig +0 -247
  124. data/ext/tb_client/tigerbeetle/src/lsm/scan_buffer.zig +0 -116
  125. data/ext/tb_client/tigerbeetle/src/lsm/scan_builder.zig +0 -543
  126. data/ext/tb_client/tigerbeetle/src/lsm/scan_fuzz.zig +0 -938
  127. data/ext/tb_client/tigerbeetle/src/lsm/scan_lookup.zig +0 -293
  128. data/ext/tb_client/tigerbeetle/src/lsm/scan_merge.zig +0 -359
  129. data/ext/tb_client/tigerbeetle/src/lsm/scan_range.zig +0 -99
  130. data/ext/tb_client/tigerbeetle/src/lsm/scan_state.zig +0 -17
  131. data/ext/tb_client/tigerbeetle/src/lsm/scan_tree.zig +0 -962
  132. data/ext/tb_client/tigerbeetle/src/lsm/schema.zig +0 -617
  133. data/ext/tb_client/tigerbeetle/src/lsm/scratch_memory.zig +0 -84
  134. data/ext/tb_client/tigerbeetle/src/lsm/segmented_array.zig +0 -1500
  135. data/ext/tb_client/tigerbeetle/src/lsm/segmented_array_benchmark.zig +0 -149
  136. data/ext/tb_client/tigerbeetle/src/lsm/segmented_array_fuzz.zig +0 -7
  137. data/ext/tb_client/tigerbeetle/src/lsm/set_associative_cache.zig +0 -865
  138. data/ext/tb_client/tigerbeetle/src/lsm/table.zig +0 -607
  139. data/ext/tb_client/tigerbeetle/src/lsm/table_memory.zig +0 -843
  140. data/ext/tb_client/tigerbeetle/src/lsm/table_value_iterator.zig +0 -90
  141. data/ext/tb_client/tigerbeetle/src/lsm/timestamp_range.zig +0 -40
  142. data/ext/tb_client/tigerbeetle/src/lsm/tree.zig +0 -629
  143. data/ext/tb_client/tigerbeetle/src/lsm/tree_fuzz.zig +0 -933
  144. data/ext/tb_client/tigerbeetle/src/lsm/zig_zag_merge.zig +0 -534
  145. data/ext/tb_client/tigerbeetle/src/message_buffer.zig +0 -469
  146. data/ext/tb_client/tigerbeetle/src/message_bus.zig +0 -1219
  147. data/ext/tb_client/tigerbeetle/src/message_bus_fuzz.zig +0 -936
  148. data/ext/tb_client/tigerbeetle/src/message_pool.zig +0 -343
  149. data/ext/tb_client/tigerbeetle/src/multiversion.zig +0 -2195
  150. data/ext/tb_client/tigerbeetle/src/queue.zig +0 -390
  151. data/ext/tb_client/tigerbeetle/src/repl/completion.zig +0 -201
  152. data/ext/tb_client/tigerbeetle/src/repl/parser.zig +0 -1356
  153. data/ext/tb_client/tigerbeetle/src/repl/terminal.zig +0 -496
  154. data/ext/tb_client/tigerbeetle/src/repl.zig +0 -1034
  155. data/ext/tb_client/tigerbeetle/src/scripts/amqp.zig +0 -973
  156. data/ext/tb_client/tigerbeetle/src/scripts/cfo.zig +0 -1866
  157. data/ext/tb_client/tigerbeetle/src/scripts/changelog.zig +0 -304
  158. data/ext/tb_client/tigerbeetle/src/scripts/ci.zig +0 -227
  159. data/ext/tb_client/tigerbeetle/src/scripts/client_readmes.zig +0 -658
  160. data/ext/tb_client/tigerbeetle/src/scripts/devhub.zig +0 -466
  161. data/ext/tb_client/tigerbeetle/src/scripts/release.zig +0 -1058
  162. data/ext/tb_client/tigerbeetle/src/scripts.zig +0 -105
  163. data/ext/tb_client/tigerbeetle/src/shell.zig +0 -1195
  164. data/ext/tb_client/tigerbeetle/src/stack.zig +0 -260
  165. data/ext/tb_client/tigerbeetle/src/state_machine/auditor.zig +0 -911
  166. data/ext/tb_client/tigerbeetle/src/state_machine/workload.zig +0 -2079
  167. data/ext/tb_client/tigerbeetle/src/state_machine.zig +0 -4872
  168. data/ext/tb_client/tigerbeetle/src/state_machine_fuzz.zig +0 -288
  169. data/ext/tb_client/tigerbeetle/src/state_machine_tests.zig +0 -3128
  170. data/ext/tb_client/tigerbeetle/src/static_allocator.zig +0 -82
  171. data/ext/tb_client/tigerbeetle/src/stdx/bit_set.zig +0 -157
  172. data/ext/tb_client/tigerbeetle/src/stdx/bounded_array.zig +0 -292
  173. data/ext/tb_client/tigerbeetle/src/stdx/debug.zig +0 -65
  174. data/ext/tb_client/tigerbeetle/src/stdx/flags.zig +0 -1414
  175. data/ext/tb_client/tigerbeetle/src/stdx/huge_page_allocator.zig +0 -115
  176. data/ext/tb_client/tigerbeetle/src/stdx/mlock.zig +0 -92
  177. data/ext/tb_client/tigerbeetle/src/stdx/prng.zig +0 -677
  178. data/ext/tb_client/tigerbeetle/src/stdx/radix.zig +0 -336
  179. data/ext/tb_client/tigerbeetle/src/stdx/ring_buffer.zig +0 -511
  180. data/ext/tb_client/tigerbeetle/src/stdx/sort_test.zig +0 -112
  181. data/ext/tb_client/tigerbeetle/src/stdx/stdx.zig +0 -1163
  182. data/ext/tb_client/tigerbeetle/src/stdx/testing/low_level_hash_vectors.zig +0 -142
  183. data/ext/tb_client/tigerbeetle/src/stdx/testing/snaptest.zig +0 -361
  184. data/ext/tb_client/tigerbeetle/src/stdx/time_units.zig +0 -275
  185. data/ext/tb_client/tigerbeetle/src/stdx/unshare.zig +0 -295
  186. data/ext/tb_client/tigerbeetle/src/stdx/vendored/aegis.zig +0 -436
  187. data/ext/tb_client/tigerbeetle/src/stdx/windows.zig +0 -48
  188. data/ext/tb_client/tigerbeetle/src/stdx/zipfian.zig +0 -402
  189. data/ext/tb_client/tigerbeetle/src/storage.zig +0 -489
  190. data/ext/tb_client/tigerbeetle/src/storage_fuzz.zig +0 -180
  191. data/ext/tb_client/tigerbeetle/src/testing/bench.zig +0 -146
  192. data/ext/tb_client/tigerbeetle/src/testing/cluster/grid_checker.zig +0 -53
  193. data/ext/tb_client/tigerbeetle/src/testing/cluster/journal_checker.zig +0 -61
  194. data/ext/tb_client/tigerbeetle/src/testing/cluster/manifest_checker.zig +0 -76
  195. data/ext/tb_client/tigerbeetle/src/testing/cluster/message_bus.zig +0 -110
  196. data/ext/tb_client/tigerbeetle/src/testing/cluster/network.zig +0 -412
  197. data/ext/tb_client/tigerbeetle/src/testing/cluster/state_checker.zig +0 -331
  198. data/ext/tb_client/tigerbeetle/src/testing/cluster/storage_checker.zig +0 -458
  199. data/ext/tb_client/tigerbeetle/src/testing/cluster.zig +0 -1198
  200. data/ext/tb_client/tigerbeetle/src/testing/exhaustigen.zig +0 -128
  201. data/ext/tb_client/tigerbeetle/src/testing/fixtures.zig +0 -181
  202. data/ext/tb_client/tigerbeetle/src/testing/fuzz.zig +0 -144
  203. data/ext/tb_client/tigerbeetle/src/testing/id.zig +0 -97
  204. data/ext/tb_client/tigerbeetle/src/testing/io.zig +0 -317
  205. data/ext/tb_client/tigerbeetle/src/testing/marks.zig +0 -126
  206. data/ext/tb_client/tigerbeetle/src/testing/packet_simulator.zig +0 -533
  207. data/ext/tb_client/tigerbeetle/src/testing/reply_sequence.zig +0 -154
  208. data/ext/tb_client/tigerbeetle/src/testing/state_machine.zig +0 -389
  209. data/ext/tb_client/tigerbeetle/src/testing/storage.zig +0 -1247
  210. data/ext/tb_client/tigerbeetle/src/testing/table.zig +0 -249
  211. data/ext/tb_client/tigerbeetle/src/testing/time.zig +0 -98
  212. data/ext/tb_client/tigerbeetle/src/testing/tmp_tigerbeetle.zig +0 -212
  213. data/ext/tb_client/tigerbeetle/src/testing/vortex/constants.zig +0 -26
  214. data/ext/tb_client/tigerbeetle/src/testing/vortex/faulty_network.zig +0 -579
  215. data/ext/tb_client/tigerbeetle/src/testing/vortex/java_driver/ci.zig +0 -39
  216. data/ext/tb_client/tigerbeetle/src/testing/vortex/logged_process.zig +0 -214
  217. data/ext/tb_client/tigerbeetle/src/testing/vortex/rust_driver/ci.zig +0 -34
  218. data/ext/tb_client/tigerbeetle/src/testing/vortex/supervisor.zig +0 -785
  219. data/ext/tb_client/tigerbeetle/src/testing/vortex/workload.zig +0 -543
  220. data/ext/tb_client/tigerbeetle/src/testing/vortex/zig_driver.zig +0 -181
  221. data/ext/tb_client/tigerbeetle/src/tidy.zig +0 -1449
  222. data/ext/tb_client/tigerbeetle/src/tigerbeetle/benchmark_driver.zig +0 -227
  223. data/ext/tb_client/tigerbeetle/src/tigerbeetle/benchmark_load.zig +0 -1069
  224. data/ext/tb_client/tigerbeetle/src/tigerbeetle/cli.zig +0 -1422
  225. data/ext/tb_client/tigerbeetle/src/tigerbeetle/inspect.zig +0 -1658
  226. data/ext/tb_client/tigerbeetle/src/tigerbeetle/inspect_integrity.zig +0 -518
  227. data/ext/tb_client/tigerbeetle/src/tigerbeetle/libtb_client.zig +0 -36
  228. data/ext/tb_client/tigerbeetle/src/tigerbeetle/main.zig +0 -646
  229. data/ext/tb_client/tigerbeetle/src/tigerbeetle.zig +0 -958
  230. data/ext/tb_client/tigerbeetle/src/time.zig +0 -236
  231. data/ext/tb_client/tigerbeetle/src/trace/event.zig +0 -745
  232. data/ext/tb_client/tigerbeetle/src/trace/statsd.zig +0 -462
  233. data/ext/tb_client/tigerbeetle/src/trace.zig +0 -556
  234. data/ext/tb_client/tigerbeetle/src/unit_tests.zig +0 -321
  235. data/ext/tb_client/tigerbeetle/src/vopr.zig +0 -1785
  236. data/ext/tb_client/tigerbeetle/src/vortex.zig +0 -101
  237. data/ext/tb_client/tigerbeetle/src/vsr/checkpoint_trailer.zig +0 -473
  238. data/ext/tb_client/tigerbeetle/src/vsr/checksum.zig +0 -208
  239. data/ext/tb_client/tigerbeetle/src/vsr/checksum_benchmark.zig +0 -43
  240. data/ext/tb_client/tigerbeetle/src/vsr/client.zig +0 -768
  241. data/ext/tb_client/tigerbeetle/src/vsr/client_replies.zig +0 -532
  242. data/ext/tb_client/tigerbeetle/src/vsr/client_sessions.zig +0 -338
  243. data/ext/tb_client/tigerbeetle/src/vsr/clock.zig +0 -1019
  244. data/ext/tb_client/tigerbeetle/src/vsr/fault_detector.zig +0 -279
  245. data/ext/tb_client/tigerbeetle/src/vsr/free_set.zig +0 -1381
  246. data/ext/tb_client/tigerbeetle/src/vsr/free_set_fuzz.zig +0 -315
  247. data/ext/tb_client/tigerbeetle/src/vsr/grid.zig +0 -1460
  248. data/ext/tb_client/tigerbeetle/src/vsr/grid_blocks_missing.zig +0 -757
  249. data/ext/tb_client/tigerbeetle/src/vsr/grid_scrubber.zig +0 -797
  250. data/ext/tb_client/tigerbeetle/src/vsr/journal.zig +0 -2586
  251. data/ext/tb_client/tigerbeetle/src/vsr/marzullo.zig +0 -308
  252. data/ext/tb_client/tigerbeetle/src/vsr/message_header.zig +0 -1777
  253. data/ext/tb_client/tigerbeetle/src/vsr/multi_batch.zig +0 -715
  254. data/ext/tb_client/tigerbeetle/src/vsr/multi_batch_fuzz.zig +0 -185
  255. data/ext/tb_client/tigerbeetle/src/vsr/repair_budget.zig +0 -333
  256. data/ext/tb_client/tigerbeetle/src/vsr/replica.zig +0 -12356
  257. data/ext/tb_client/tigerbeetle/src/vsr/replica_format.zig +0 -416
  258. data/ext/tb_client/tigerbeetle/src/vsr/replica_reformat.zig +0 -165
  259. data/ext/tb_client/tigerbeetle/src/vsr/replica_test.zig +0 -2928
  260. data/ext/tb_client/tigerbeetle/src/vsr/routing.zig +0 -1075
  261. data/ext/tb_client/tigerbeetle/src/vsr/superblock.zig +0 -1603
  262. data/ext/tb_client/tigerbeetle/src/vsr/superblock_fuzz.zig +0 -484
  263. data/ext/tb_client/tigerbeetle/src/vsr/superblock_quorums.zig +0 -405
  264. data/ext/tb_client/tigerbeetle/src/vsr/superblock_quorums_fuzz.zig +0 -355
  265. data/ext/tb_client/tigerbeetle/src/vsr/sync.zig +0 -29
  266. data/ext/tb_client/tigerbeetle/src/vsr.zig +0 -1727
  267. data/lib/tb_client/shared_lib.rb +0 -66
  268. data/lib/tb_client.rb +0 -282
  269. data/lib/tigerbeetle/account.rb +0 -38
  270. data/lib/tigerbeetle/account_balance.rb +0 -23
  271. data/lib/tigerbeetle/account_filter.rb +0 -31
  272. data/lib/tigerbeetle/atomic_counter.rb +0 -14
  273. data/lib/tigerbeetle/client.rb +0 -214
  274. data/lib/tigerbeetle/converters/account.rb +0 -63
  275. data/lib/tigerbeetle/converters/account_balance.rb +0 -31
  276. data/lib/tigerbeetle/converters/account_filter.rb +0 -32
  277. data/lib/tigerbeetle/converters/base.rb +0 -35
  278. data/lib/tigerbeetle/converters/create_accounts_result.rb +0 -21
  279. data/lib/tigerbeetle/converters/create_transfers_result.rb +0 -21
  280. data/lib/tigerbeetle/converters/query_filter.rb +0 -33
  281. data/lib/tigerbeetle/converters/time.rb +0 -23
  282. data/lib/tigerbeetle/converters/transfer.rb +0 -64
  283. data/lib/tigerbeetle/converters/uint_128.rb +0 -24
  284. data/lib/tigerbeetle/converters.rb +0 -12
  285. data/lib/tigerbeetle/error.rb +0 -4
  286. data/lib/tigerbeetle/id.rb +0 -30
  287. data/lib/tigerbeetle/platforms.rb +0 -9
  288. data/lib/tigerbeetle/query_filter.rb +0 -31
  289. data/lib/tigerbeetle/request.rb +0 -7
  290. data/lib/tigerbeetle/transfer.rb +0 -40
  291. data/lib/tigerbeetle/version.rb +0 -4
  292. data/lib/tigerbeetle.rb +0 -13
  293. data/tigerbeetle.gemspec +0 -60
@@ -1,785 +0,0 @@
1
- //! The Vortex _supervisor_ is a program that runs:
2
- //!
3
- //! * a set of TigerBeetle replicas, forming a cluster
4
- //! * a workload that runs commands and queries against the cluster, verifying its correctness
5
- //! (whatever that means is up to the workload)
6
- //!
7
- //! The replicas and workload run as child processes, while the supervisor restarts terminated
8
- //! replicas and injects crashes and network faults. After some configurable amount of time, the
9
- //! supervisor terminates the workload and replicas, unless the workload exits on its own or if
10
- //! any of the replicas exit unexpectedly.
11
- //!
12
- //! If the workload exits successfully, or is actively terminated, the whole vortex exits
13
- //! successfully.
14
- //!
15
- //! To launch a one-second smoke test, run this command from the repository root:
16
- //!
17
- //! $ zig build test:integration -- "vortex smoke"
18
- //!
19
- //! If you need more control, you can run this program directly.
20
- //!
21
- //! $ zig build vortex -- supervisor
22
- //!
23
- //! Other options:
24
- //!
25
- //! * Set the test duration by adding the `--test-duration=XmYs` option (it's 1 minute by default).
26
- //! * Enable replica debug logging with `--log-debug`.
27
- //!
28
- //! If you have permissions troubles with unshare and Ubuntu, see:
29
- //! https://github.com/YoYoGames/GameMaker-Bugs/issues/6015#issuecomment-2135552784
30
- //!
31
- //! Further possible work:
32
- //!
33
- //! * full partitioning
34
- //! * filesystem faults
35
- //! * clock faults
36
- //! * upgrades (replicas and clients)
37
- //! * multiple drivers? could use a special multiplexer driver that delegates to others
38
-
39
- const std = @import("std");
40
- const stdx = @import("stdx");
41
- const builtin = @import("builtin");
42
- const IO = @import("../../io.zig").IO;
43
- const RingBufferType = stdx.RingBufferType;
44
- const LoggedProcess = @import("./logged_process.zig");
45
- const faulty_network = @import("./faulty_network.zig");
46
- const constants = @import("constants.zig");
47
- const Progress = @import("./workload.zig").Progress;
48
- const ratio = stdx.PRNG.ratio;
49
- const Shell = @import("../../shell.zig");
50
-
51
- const log = std.log.scoped(.supervisor);
52
- const tigerbeetle_exe_default: []const u8 = @import("vortex_options").tigerbeetle_exe;
53
- const vortex_driver_exe_default: []const u8 = @import("vortex_options").driver_exe;
54
-
55
- const assert = std.debug.assert;
56
- const maybe = stdx.maybe;
57
-
58
- pub const CLIArgs = struct {
59
- tigerbeetle_executable: ?[]const u8 = null,
60
- test_duration: stdx.Duration = .minutes(1),
61
- driver_command: ?[]const u8 = null,
62
- replica_count: u8 = 1,
63
- disable_faults: bool = false,
64
- output_directory: ?[]const u8 = null,
65
- log_debug: bool = false,
66
- /// Log file path.
67
- log: ?[]const u8 = null,
68
-
69
- @"--": void,
70
- /// Vortex is non-deterministic, but providing a seed can still help constrain the scenario.
71
- seed: ?u64 = null,
72
- };
73
-
74
- pub fn main(allocator: std.mem.Allocator, args: CLIArgs) !void {
75
- if (builtin.os.tag == .windows) {
76
- log.err("vortex is not supported on Windows", .{});
77
- return error.NotSupported;
78
- }
79
-
80
- if (args.log) |log_path| {
81
- const log_file = try std.fs.cwd().createFile(log_path, .{});
82
- defer log_file.close();
83
-
84
- // Redirect stderr to the file.
85
- try std.posix.dup2(log_file.handle, std.posix.STDERR_FILENO);
86
- }
87
-
88
- if (builtin.os.tag == .linux) {
89
- // Relaunch in fresh pid / network namespaces.
90
- try stdx.unshare.maybe_unshare_and_relaunch(allocator, .{
91
- .pid = true,
92
- .network = true,
93
- });
94
- } else {
95
- log.warn("vortex may spawn runaway processes when run on a non-Linux OS", .{});
96
- log.warn("vortex may encounter port collisions non-Linux OS", .{});
97
- }
98
-
99
- const shell = try Shell.create(allocator);
100
- defer shell.destroy();
101
-
102
- // By default, the shell uses project root as cwd, but we want to use the actual process cwd.
103
- try shell.pushd_dir(std.fs.cwd());
104
- defer shell.popd();
105
-
106
- var io = try IO.init(128, 0);
107
-
108
- const tigerbeetle_executable = args.tigerbeetle_executable orelse tigerbeetle_exe_default;
109
- const output_directory = args.output_directory orelse try shell.create_tmp_dir();
110
- defer {
111
- if (args.output_directory == null) {
112
- shell.cwd.deleteTree(output_directory) catch |err| {
113
- log.err("error deleting tree: {}", .{err});
114
- };
115
- }
116
- }
117
-
118
- log.info("output directory: {s}", .{output_directory});
119
- log.info("starting test with target runtime of {}", .{args.test_duration});
120
-
121
- const seed = args.seed orelse std.crypto.random.int(u64);
122
- var prng = stdx.PRNG.from_seed(seed);
123
-
124
- var network = try faulty_network.Network.listen(
125
- allocator,
126
- &prng,
127
- &io,
128
- constants.vortex.replica_ports_actual[0..args.replica_count],
129
- );
130
- defer network.destroy(allocator);
131
-
132
- var replicas: [constants.vsr.replicas_max]*Replica = undefined;
133
- var replicas_initialized: usize = 0;
134
- defer {
135
- for (replicas[0..replicas_initialized]) |replica| {
136
- // We might have terminated the replica and never restarted it,
137
- // so we need to check its state.
138
- if (replica.state() != .terminated) {
139
- _ = replica.terminate() catch {};
140
- }
141
- replica.destroy();
142
- }
143
- }
144
-
145
- var datafile_buffers: [constants.vsr.replicas_max][std.fs.max_path_bytes]u8 = undefined;
146
- for (0..args.replica_count) |replica_index| {
147
- const datafile = try std.fmt.bufPrint(
148
- datafile_buffers[replica_index][0..],
149
- "{s}/{d}_{d}.tigerbeetle",
150
- .{ output_directory, constants.vortex.cluster_id, replica_index },
151
- );
152
-
153
- shell.exec(
154
- \\{tigerbeetle_executable} format
155
- \\ --cluster={cluster}
156
- \\ --replica={replica_index}
157
- \\ --replica-count={replica_count}
158
- \\ {datafile}
159
- , .{
160
- .tigerbeetle_executable = tigerbeetle_executable,
161
- .cluster = constants.vortex.cluster_id,
162
- .replica_index = replica_index,
163
- .replica_count = args.replica_count,
164
- .datafile = datafile,
165
- }) catch |err| {
166
- log.err("failed formatting datafile: {}", .{err});
167
- return error.SetupFailed;
168
- };
169
-
170
- var replica_ports: [constants.vsr.replicas_max]u16 = undefined;
171
- for (replica_ports[0..args.replica_count], 0..) |*replica_port, i| {
172
- if (replica_index == i) {
173
- replica_port.* = network.proxies[i].remote_address.getPort();
174
- } else {
175
- replica_port.* = network.proxies[i].origin_address.getPort();
176
- }
177
- }
178
-
179
- var replica = try Replica.create(
180
- allocator,
181
- tigerbeetle_executable,
182
- args.replica_count,
183
- @intCast(replica_index),
184
- replica_ports,
185
- datafile,
186
- args.log_debug,
187
- );
188
-
189
- replicas[replica_index] = replica;
190
- replicas_initialized += 1;
191
-
192
- try replica.start();
193
- }
194
-
195
- var proxy_ports: [constants.vsr.replicas_max]u16 = undefined;
196
- for (proxy_ports[0..args.replica_count], 0..) |*port, i| {
197
- port.* = network.proxies[i].origin_address.getPort();
198
- }
199
-
200
- const workload = try Workload.spawn(allocator, &io, proxy_ports[0..args.replica_count], args);
201
- defer {
202
- if (workload.process.state == .running) {
203
- _ = workload.process.terminate() catch {};
204
- }
205
- workload.destroy(allocator);
206
- }
207
-
208
- const supervisor = try Supervisor.create(allocator, .{
209
- .io = &io,
210
- .network = network,
211
- .replicas = replicas[0..args.replica_count],
212
- .workload = workload,
213
- .prng = &prng,
214
- .test_duration = args.test_duration,
215
- .faulty = !args.disable_faults,
216
- });
217
- defer supervisor.destroy(allocator);
218
-
219
- try supervisor.run();
220
- }
221
-
222
- const Supervisor = struct {
223
- io: *IO,
224
- network: *faulty_network.Network,
225
- replicas: []*Replica,
226
- workload: *Workload,
227
- prng: *stdx.PRNG,
228
- test_deadline: i128,
229
- faulty: bool,
230
-
231
- fn create(allocator: std.mem.Allocator, options: struct {
232
- io: *IO,
233
- network: *faulty_network.Network,
234
- replicas: []*Replica,
235
- workload: *Workload,
236
- prng: *stdx.PRNG,
237
- test_duration: stdx.Duration,
238
- faulty: bool,
239
- }) !*Supervisor {
240
- const supervisor = try allocator.create(Supervisor);
241
- errdefer allocator.destroy(supervisor);
242
-
243
- supervisor.* = .{
244
- .io = options.io,
245
- .network = options.network,
246
- .replicas = options.replicas,
247
- .workload = options.workload,
248
- .prng = options.prng,
249
- .test_deadline = std.time.nanoTimestamp() + options.test_duration.ns,
250
- .faulty = options.faulty,
251
- };
252
- return supervisor;
253
- }
254
-
255
- fn destroy(supervisor: *Supervisor, allocator: std.mem.Allocator) void {
256
- allocator.destroy(supervisor);
257
- }
258
-
259
- fn run(supervisor: *Supervisor) !void {
260
- var running_replicas_buffer: [constants.vsr.replicas_max]ReplicaWithIndex = undefined;
261
- var terminated_replicas_buffer: [constants.vsr.replicas_max]ReplicaWithIndex = undefined;
262
- var paused_replicas_buffer: [constants.vsr.replicas_max]ReplicaWithIndex = undefined;
263
-
264
- var sleep_deadline: u64 = 0;
265
- // This represents the start timestamp of a period where we have an acceptable number of
266
- // process faults, such that we require liveness (that requests are finished within a
267
- // certain time period). If null, it means we're in a period of too many faults, thus
268
- // enforcing no such requirement.
269
- var acceptable_faults_start_ns: ?u64 = null;
270
- // How many replicas can be faulty while still expecting the cluster to
271
- // make progress (based on 2f+1).
272
- const liveness_faulty_replicas_max = @divFloor(supervisor.replicas.len - 1, 2);
273
- const workload_result = while (std.time.nanoTimestamp() < supervisor.test_deadline) {
274
- supervisor.network.tick();
275
- try supervisor.io.run_for_ns(constants.vsr.tick_ms * std.time.ns_per_ms);
276
- const now: u64 = @intCast(std.time.nanoTimestamp());
277
-
278
- const running_replicas =
279
- replicas_in_state(supervisor.replicas, &running_replicas_buffer, .running);
280
- const terminated_replicas =
281
- replicas_in_state(supervisor.replicas, &terminated_replicas_buffer, .terminated);
282
- const paused_replicas =
283
- replicas_in_state(supervisor.replicas, &paused_replicas_buffer, .paused);
284
-
285
- const faulty_replica_count = terminated_replicas.len + paused_replicas.len;
286
-
287
- if (acceptable_faults_start_ns) |start_ns| {
288
- const deadline = start_ns + constants.vortex.liveness_requirement_seconds *
289
- std.time.ns_per_s;
290
- // If we've been in a state with an acceptable number of faults for the required
291
- // amount of time, we should have seen finished requests.
292
- const no_finished_requests =
293
- now > deadline and supervisor.workload.requests_finished.empty();
294
- // Also, those that do finish should not have too long durations, counting from the
295
- // start of the acceptably-faulty period.
296
- const too_slow_request = supervisor.workload.find_slow_request_since(start_ns);
297
-
298
- if (no_finished_requests) {
299
- fatal(.liveness, "liveness check: no finished requests after {d} seconds", .{
300
- constants.vortex.liveness_requirement_seconds,
301
- });
302
- }
303
-
304
- if (too_slow_request) |_| {
305
- fatal(.request_slow, "liveness check: too slow request", .{});
306
- }
307
- }
308
-
309
- // Check if `acceptable_faults_start_ns` should change state. If so, we reset the max
310
- // request duration too.
311
- // NOTE: Network faults are currently global, so we relax the requirement in such cases.
312
- if (faulty_replica_count <= liveness_faulty_replicas_max and
313
- supervisor.network.faults.is_healed())
314
- {
315
- // We have an acceptable number of faults, so we require liveness (after some time).
316
- if (acceptable_faults_start_ns == null) {
317
- acceptable_faults_start_ns = @intCast(std.time.nanoTimestamp());
318
- supervisor.workload.requests_finished.clear();
319
- }
320
- } else {
321
- // We have too many faults to require liveness.
322
- if (acceptable_faults_start_ns) |_| {
323
- acceptable_faults_start_ns = null;
324
- supervisor.workload.requests_finished.clear();
325
- }
326
- }
327
-
328
- if (sleep_deadline < now and supervisor.faulty) {
329
- const Action = enum {
330
- sleep,
331
- replica_terminate,
332
- replica_restart,
333
- replica_pause,
334
- replica_resume,
335
- network_delay,
336
- network_corrupt,
337
- network_heal,
338
- quiesce,
339
- };
340
-
341
- switch (supervisor.prng.enum_weighted(Action, .{
342
- .sleep = 10,
343
- .replica_terminate = if (running_replicas.len > 0) 4 else 0,
344
- .replica_restart = if (terminated_replicas.len > 0) 3 else 0,
345
- .replica_pause = if (running_replicas.len > 0) 3 else 0,
346
- .replica_resume = if (paused_replicas.len > 0) 10 else 0,
347
- .network_delay = if (supervisor.network.faults.delay == null) 3 else 0,
348
- .network_corrupt = if (supervisor.network.faults.corrupt == null) 3 else 0,
349
- .network_heal = if (!supervisor.network.faults.is_healed()) 10 else 0,
350
- .quiesce = if (faulty_replica_count > 0 or
351
- !supervisor.network.faults.is_healed()) 1 else 0,
352
- })) {
353
- .sleep => {
354
- const duration =
355
- supervisor.prng.int_inclusive(u64, 10 * std.time.ns_per_s);
356
- log.info("sleeping for {}", .{std.fmt.fmtDuration(duration)});
357
- sleep_deadline = now + duration;
358
- },
359
- .replica_terminate => {
360
- const pick =
361
- running_replicas[supervisor.prng.index(running_replicas)];
362
- _ = try pick.replica.terminate();
363
- },
364
- .replica_restart => {
365
- const pick =
366
- terminated_replicas[supervisor.prng.index(terminated_replicas)];
367
- try pick.replica.start();
368
- },
369
- .replica_pause => {
370
- const pick =
371
- running_replicas[supervisor.prng.index(running_replicas)];
372
- try pick.replica.pause();
373
- },
374
- .replica_resume => {
375
- const pick =
376
- paused_replicas[supervisor.prng.index(paused_replicas)];
377
- try pick.replica.unpause();
378
- },
379
- .network_delay => {
380
- const time_ms = supervisor.prng.range_inclusive(u32, 10, 500);
381
- supervisor.network.faults.delay = .{
382
- .time_ms = time_ms,
383
- .jitter_ms = @min(time_ms, 50),
384
- };
385
- log.info("injecting network delays: {any}", .{supervisor.network.faults});
386
- },
387
- .network_corrupt => {
388
- supervisor.network.faults.corrupt =
389
- ratio(supervisor.prng.range_inclusive(u8, 1, 10), 100);
390
- log.info("injecting network corruption: {any}", .{
391
- supervisor.network.faults,
392
- });
393
- },
394
- .network_heal => {
395
- log.info("healing network", .{});
396
- supervisor.network.faults.heal();
397
- },
398
- .quiesce => {
399
- const duration = supervisor.prng.range_inclusive(
400
- u64,
401
- constants.vortex.liveness_requirement_seconds,
402
- constants.vortex.liveness_requirement_seconds * 2,
403
- ) * std.time.ns_per_s;
404
- sleep_deadline = now + duration;
405
-
406
- supervisor.network.faults.heal();
407
- for (paused_replicas) |paused| try paused.replica.unpause();
408
- for (terminated_replicas) |terminated| try terminated.replica.start();
409
-
410
- log.info("going into {} quiescence (no faults)", .{
411
- std.fmt.fmtDuration(duration),
412
- });
413
- },
414
- }
415
- }
416
-
417
- // Check for replicas that have exited.
418
- for (supervisor.replicas, 0..) |replica, replica_index| {
419
- if (replica.state() != .terminated) {
420
- if (replica.process.?.wait_nonblocking()) |term| {
421
- // Replicas shouldn't exit on their own, even with code=0.
422
- maybe(std.meta.eql(term, .{ .Exited = 0 }));
423
-
424
- log.err(
425
- "{}: replica terminated unexpectedly with {}",
426
- .{ replica_index, term },
427
- );
428
- if (std.meta.eql(term, .{ .Signal = std.posix.SIG.KILL })) {
429
- // If one of the replica dies to SIGKILL, it is likely an OOM.
430
- // Bubble that up to CFO so that this Vortex run is counted as neither a
431
- // success or failure.
432
- std.posix.exit(@intCast(128 + term.Signal));
433
- } else {
434
- fatal(.replica_exit_result, "replica exited with: {}", .{term});
435
- }
436
- }
437
- }
438
- }
439
-
440
- if (supervisor.workload.process.wait_nonblocking()) |code| {
441
- fatal(
442
- .workload_exit_early,
443
- "workload terminated by itself: code={}",
444
- .{code},
445
- );
446
- }
447
- } else blk: {
448
- log.info("terminating workload due to max duration", .{});
449
- break :blk try supervisor.workload.process.terminate();
450
- };
451
-
452
- switch (workload_result) {
453
- .Signal => |signal| {
454
- switch (signal) {
455
- std.posix.SIG.KILL => log.info("workload terminated as requested", .{}),
456
- else => {
457
- fatal(
458
- .workload_exit_result,
459
- "workload exited unexpectedly with signal {d}",
460
- .{signal},
461
- );
462
- },
463
- }
464
- },
465
- else => {
466
- fatal(
467
- .workload_exit_result,
468
- "unexpected workload result: {any}",
469
- .{workload_result},
470
- );
471
- },
472
- }
473
- }
474
- };
475
-
476
- const ReplicaWithIndex = struct { replica: *Replica, index: u8 };
477
-
478
- fn replicas_in_state(
479
- replicas: []*Replica,
480
- buffer: []ReplicaWithIndex,
481
- state: Replica.State,
482
- ) []ReplicaWithIndex {
483
- var count: u8 = 0;
484
-
485
- for (replicas, 0..) |replica, index| {
486
- if (replica.state() == state) {
487
- buffer[count] = .{ .replica = replica, .index = @intCast(index) };
488
- count += 1;
489
- }
490
- }
491
- return buffer[0..count];
492
- }
493
-
494
- fn comma_separate_ports(allocator: std.mem.Allocator, ports: []const u16) ![]const u8 {
495
- assert(ports.len > 0);
496
-
497
- var out = std.ArrayList(u8).init(allocator);
498
- errdefer out.deinit();
499
-
500
- const writer = out.writer();
501
- try writer.print("{d}", .{ports[0]});
502
- for (ports[1..]) |port| try writer.print(",{d}", .{port});
503
-
504
- return out.toOwnedSlice();
505
- }
506
-
507
- test comma_separate_ports {
508
- const formatted = try comma_separate_ports(std.testing.allocator, &.{ 3000, 3001, 3002 });
509
- defer std.testing.allocator.free(formatted);
510
-
511
- try std.testing.expectEqualStrings("3000,3001,3002", formatted);
512
- }
513
-
514
- const Replica = struct {
515
- pub const State = enum(u8) { initial, running, paused, terminated };
516
-
517
- allocator: std.mem.Allocator,
518
- executable_path: []const u8,
519
- replica_count: u8,
520
- replica_index: u8,
521
- replica_ports: [constants.vsr.replicas_max]u16,
522
- datafile: []const u8,
523
- log_debug: bool,
524
- process: ?*LoggedProcess,
525
-
526
- pub fn create(
527
- allocator: std.mem.Allocator,
528
- executable_path: []const u8,
529
- replica_count: u8,
530
- replica_index: u8,
531
- replica_ports: [constants.vsr.replicas_max]u16,
532
- datafile: []const u8,
533
- log_debug: bool,
534
- ) !*Replica {
535
- assert(replica_index < replica_count);
536
-
537
- const self = try allocator.create(Replica);
538
- errdefer allocator.destroy(self);
539
-
540
- self.* = .{
541
- .allocator = allocator,
542
- .executable_path = executable_path,
543
- .replica_count = replica_count,
544
- .replica_index = replica_index,
545
- .replica_ports = replica_ports,
546
- .datafile = datafile,
547
- .log_debug = log_debug,
548
- .process = null,
549
- };
550
- return self;
551
- }
552
-
553
- pub fn destroy(self: *Replica) void {
554
- assert(self.state() == .initial or self.state() == .terminated);
555
- const allocator = self.allocator;
556
- if (self.process) |process| {
557
- process.destroy(allocator);
558
- }
559
- allocator.destroy(self);
560
- }
561
-
562
- pub fn state(self: *Replica) State {
563
- if (self.process) |process| {
564
- switch (process.state) {
565
- .running => return .running,
566
- .paused => return .paused,
567
- .terminated => return .terminated,
568
- }
569
- } else return .initial;
570
- }
571
-
572
- pub fn start(self: *Replica) !void {
573
- assert(self.state() != .running);
574
- defer assert(self.state() == .running);
575
-
576
- if (self.process) |process| {
577
- process.destroy(self.allocator);
578
- }
579
-
580
- const replica_addresses =
581
- try comma_separate_ports(self.allocator, self.replica_ports[0..self.replica_count]);
582
- defer self.allocator.free(replica_addresses);
583
-
584
- var addresses_buffer: [128]u8 = undefined;
585
- const addresses_arg = try std.fmt.bufPrint(
586
- addresses_buffer[0..],
587
- "--addresses={s}",
588
- .{replica_addresses},
589
- );
590
-
591
- var argv: stdx.BoundedArrayType([]const u8, 16) = .{};
592
- argv.push_slice(&.{ self.executable_path, "start" });
593
- if (self.log_debug) {
594
- argv.push_slice(&.{ "--log-debug", "--experimental" });
595
- }
596
- argv.push_slice(&.{ addresses_arg, self.datafile });
597
-
598
- log.info("{}: starting replica", .{self.replica_index});
599
- self.process = try LoggedProcess.spawn(self.allocator, argv.const_slice(), .{});
600
- }
601
-
602
- pub fn terminate(self: *Replica) !std.process.Child.Term {
603
- assert(self.state() == .running or self.state() == .paused);
604
- defer assert(self.state() == .terminated);
605
-
606
- log.info("{}: terminating replica", .{self.replica_index});
607
- return try self.process.?.terminate();
608
- }
609
-
610
- pub fn pause(self: *Replica) !void {
611
- assert(self.state() == .running);
612
- defer assert(self.state() == .paused);
613
-
614
- log.info("{}: pausing replica", .{self.replica_index});
615
- try self.process.?.pause();
616
- }
617
-
618
- pub fn unpause(self: *Replica) !void {
619
- assert(self.state() == .paused);
620
- defer assert(self.state() == .running);
621
-
622
- log.info("{}: unpausing replica", .{self.replica_index});
623
- try self.process.?.unpause();
624
- }
625
- };
626
-
627
- const Workload = struct {
628
- pub const State = enum(u8) { running, terminated };
629
-
630
- const RequestInfo = struct {
631
- timestamp_start_micros: u64,
632
- timestamp_end_micros: u64,
633
- };
634
-
635
- const Requests = RingBufferType(RequestInfo, .{ .array = 1024 * 16 });
636
-
637
- io: *IO,
638
- process: *LoggedProcess,
639
-
640
- read_buffer: [@sizeOf(Progress)]u8 = undefined,
641
- read_completion: IO.Completion = undefined,
642
- read_progress: usize = 0,
643
-
644
- requests_finished: Requests = Requests.init(),
645
-
646
- pub fn spawn(
647
- allocator: std.mem.Allocator,
648
- io: *IO,
649
- proxy_ports: []u16,
650
- args: CLIArgs,
651
- ) !*Workload {
652
- var vortex_path_buffer: [std.fs.max_path_bytes]u8 = undefined;
653
- const vortex_path = try std.fs.selfExePath(&vortex_path_buffer);
654
-
655
- const driver_command_selected = args.driver_command orelse vortex_driver_exe_default;
656
- log.info("launching workload with driver: {s}", .{driver_command_selected});
657
-
658
- var driver_command_arg_buffer: [std.fs.max_path_bytes]u8 = undefined;
659
- const driver_command_arg = try std.fmt.bufPrint(
660
- &driver_command_arg_buffer,
661
- "--driver-command={s}",
662
- .{driver_command_selected},
663
- );
664
-
665
- const proxy_addresses = try comma_separate_ports(allocator, proxy_ports);
666
- defer allocator.free(proxy_addresses);
667
-
668
- const arg_addresses =
669
- try std.fmt.allocPrint(allocator, "--addresses={s}", .{proxy_addresses});
670
- defer allocator.free(arg_addresses);
671
-
672
- const argv = &.{
673
- vortex_path,
674
- "workload",
675
- std.fmt.comptimePrint("--cluster-id={d}", .{constants.vortex.cluster_id}),
676
- arg_addresses,
677
- driver_command_arg,
678
- };
679
-
680
- const workload = try allocator.create(Workload);
681
- errdefer allocator.destroy(workload);
682
-
683
- const process = try LoggedProcess.spawn(allocator, argv, .{
684
- .stdout_behavior = .Pipe,
685
- });
686
- errdefer process.destroy(allocator);
687
-
688
- workload.* = .{
689
- .io = io,
690
- .process = process,
691
- };
692
-
693
- // Kick off read loop.
694
- workload.read();
695
-
696
- return workload;
697
- }
698
-
699
- pub fn destroy(workload: *Workload, allocator: std.mem.Allocator) void {
700
- assert(workload.process.state == .terminated);
701
- workload.process.destroy(allocator);
702
- allocator.destroy(workload);
703
- }
704
-
705
- fn read(workload: *Workload) void {
706
- assert(workload.process.state == .running);
707
-
708
- workload.io.read(
709
- *Workload,
710
- workload,
711
- on_read,
712
- &workload.read_completion,
713
- workload.process.child.stdout.?.handle,
714
- workload.read_buffer[workload.read_progress..workload.read_buffer.len],
715
- 0,
716
- );
717
- }
718
-
719
- fn on_read(
720
- workload: *Workload,
721
- _: *IO.Completion,
722
- result: IO.ReadError!usize,
723
- ) void {
724
- if (workload.process.state != .running) return;
725
-
726
- const count = result catch |err| {
727
- fatal(.workload_read_error, "couldn't read from workload stdout: {}", .{err});
728
- };
729
-
730
- workload.read_progress += count;
731
-
732
- if (workload.read_progress >= workload.read_buffer.len) {
733
- const progress = std.mem.bytesAsValue(Progress, workload.read_buffer[0..]);
734
- const request_info: RequestInfo = .{
735
- .timestamp_start_micros = progress.timestamp_start_micros,
736
- .timestamp_end_micros = progress.timestamp_end_micros,
737
- };
738
- workload.read_progress = 0;
739
- workload.requests_finished.push(request_info) catch
740
- log.warn("requests_finished is full", .{});
741
-
742
- log.debug("workload: request done duration={}us events={}", .{
743
- progress.timestamp_end_micros - progress.timestamp_start_micros,
744
- progress.event_count,
745
- });
746
- }
747
-
748
- workload.read();
749
- }
750
-
751
- fn find_slow_request_since(workload: *const Workload, start_ns: u64) ?RequestInfo {
752
- var it = workload.requests_finished.iterator();
753
- while (it.next()) |request| {
754
- assert(request.timestamp_start_micros < request.timestamp_end_micros);
755
- // If a request started before the acceptably-faulty period,
756
- // we ignore that part of its duration.
757
- const duration_adjusted_micros = request.timestamp_end_micros -|
758
- @max(request.timestamp_start_micros, @divFloor(start_ns, 1000));
759
- if (duration_adjusted_micros > constants.vortex.liveness_requirement_micros) {
760
- return request;
761
- }
762
- }
763
- return null;
764
- }
765
- };
766
-
767
- const FatalReason = enum(u8) {
768
- workload_exit_early = 10,
769
- workload_exit_result = 11,
770
- workload_read_error = 12,
771
- replica_exit_result = 13,
772
- liveness = 14,
773
- request_slow = 15,
774
-
775
- pub fn exit_status(reason: FatalReason) u8 {
776
- return @intFromEnum(reason);
777
- }
778
- };
779
-
780
- fn fatal(reason: FatalReason, comptime fmt: []const u8, args: anytype) noreturn {
781
- log.err(fmt, args);
782
- const status = reason.exit_status();
783
- assert(status != 0);
784
- std.process.exit(status);
785
- }