tigerbeetle 0.0.34 → 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 (249) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -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 +1084 -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 +11 -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 +362 -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 +1036 -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 +105 -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 +557 -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 +2910 -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/client.rb +1 -1
  245. data/lib/tigerbeetle/platforms.rb +9 -0
  246. data/lib/tigerbeetle/version.rb +2 -2
  247. data/tigerbeetle.gemspec +22 -5
  248. metadata +242 -3
  249. data/ext/tb_client/pkg.tar.gz +0 -0
@@ -0,0 +1,338 @@
1
+ const std = @import("std");
2
+ const assert = std.debug.assert;
3
+ const mem = std.mem;
4
+
5
+ const constants = @import("../constants.zig");
6
+ const vsr = @import("../vsr.zig");
7
+ const stdx = @import("stdx");
8
+
9
+ /// There is a slot corresponding to every active client (i.e. a total of clients_max slots).
10
+ pub const ReplySlot = struct { index: usize };
11
+
12
+ /// Track the headers of the latest reply for each active client.
13
+ /// Serialized/deserialized to/from the trailer on-disk.
14
+ /// For the reply bodies, see ClientReplies.
15
+ pub const ClientSessions = struct {
16
+ /// We found two bugs in the VRR paper relating to the client table:
17
+ ///
18
+ /// 1. a correctness bug, where successive client crashes may cause request numbers to collide
19
+ /// for different request payloads, resulting in requests receiving the wrong reply, and
20
+ ///
21
+ /// 2. a liveness bug, where if the client table is updated for request and prepare messages
22
+ /// with the client's latest request number, then the client may be locked out from the cluster
23
+ /// if the request is ever reordered through a view change.
24
+ ///
25
+ /// We therefore take a different approach with the implementation of our client table, to:
26
+ ///
27
+ /// 1. register client sessions explicitly through the state machine to ensure that
28
+ /// session numbers always increase, and
29
+ ///
30
+ /// 2. make a more careful distinction between uncommitted and committed request numbers,
31
+ /// considering that uncommitted requests may not survive a view change.
32
+ pub const Entry = struct {
33
+ /// The client's session number as committed to the cluster by a register request.
34
+ session: u64,
35
+
36
+ /// The header of the reply corresponding to the client's latest committed request.
37
+ header: vsr.Header.Reply,
38
+ };
39
+
40
+ /// Values are indexes into `entries`.
41
+ const EntriesByClient = std.AutoHashMapUnmanaged(u128, usize);
42
+
43
+ const EntriesPresent = stdx.BitSetType(constants.clients_max);
44
+
45
+ /// Free entries are zeroed, both in `entries` and on-disk.
46
+ entries: []Entry,
47
+ entries_by_client: EntriesByClient,
48
+ entries_present: EntriesPresent = .{},
49
+
50
+ pub fn init(allocator: mem.Allocator) !ClientSessions {
51
+ var entries_by_client: EntriesByClient = .{};
52
+ errdefer entries_by_client.deinit(allocator);
53
+
54
+ try entries_by_client.ensureTotalCapacity(allocator, @intCast(constants.clients_max));
55
+ assert(entries_by_client.capacity() >= constants.clients_max);
56
+
57
+ const entries = try allocator.alloc(Entry, constants.clients_max);
58
+ errdefer allocator.free(entries);
59
+ @memset(entries, std.mem.zeroes(Entry));
60
+
61
+ return ClientSessions{
62
+ .entries_by_client = entries_by_client,
63
+ .entries = entries,
64
+ };
65
+ }
66
+
67
+ pub fn deinit(client_sessions: *ClientSessions, allocator: mem.Allocator) void {
68
+ client_sessions.entries_by_client.deinit(allocator);
69
+ allocator.free(client_sessions.entries);
70
+ }
71
+
72
+ pub fn reset(client_sessions: *ClientSessions) void {
73
+ @memset(client_sessions.entries, std.mem.zeroes(Entry));
74
+ client_sessions.entries_by_client.clearRetainingCapacity();
75
+ client_sessions.entries_present = .{};
76
+ }
77
+
78
+ /// Size of the buffer needed to encode the client sessions on disk.
79
+ /// (Not rounded up to a sector boundary).
80
+ pub const encode_size = blk: {
81
+ var size_max: usize = 0;
82
+
83
+ // First goes the vsr headers for the entries.
84
+ // This takes advantage of the buffer alignment to avoid adding padding for the headers.
85
+ assert(@alignOf(vsr.Header) == 16);
86
+ size_max = std.mem.alignForward(usize, size_max, 16);
87
+ size_max += @sizeOf(vsr.Header) * constants.clients_max;
88
+
89
+ // Then follows the session values for the entries.
90
+ assert(@alignOf(u64) == 8);
91
+ size_max = std.mem.alignForward(usize, size_max, 8);
92
+ size_max += @sizeOf(u64) * constants.clients_max;
93
+
94
+ // For encoding/decoding simplicity, the ClientSessions always fits in a single block.
95
+ assert(size_max <= constants.block_size - @sizeOf(vsr.Header));
96
+
97
+ break :blk size_max;
98
+ };
99
+
100
+ pub fn encode(
101
+ client_sessions: *const ClientSessions,
102
+ target: []align(@alignOf(vsr.Header)) u8,
103
+ ) u64 {
104
+ assert(target.len >= encode_size);
105
+
106
+ var size: u64 = 0;
107
+
108
+ // Write all headers:
109
+ assert(@alignOf(vsr.Header) == 16);
110
+ var new_size = std.mem.alignForward(usize, size, 16);
111
+ @memset(target[size..new_size], 0);
112
+ size = new_size;
113
+
114
+ for (client_sessions.entries) |*entry| {
115
+ stdx.copy_disjoint(.inexact, u8, target[size..], mem.asBytes(&entry.header));
116
+ size += @sizeOf(vsr.Header);
117
+ }
118
+
119
+ // Write all sessions:
120
+ assert(@alignOf(u64) == 8);
121
+ new_size = std.mem.alignForward(usize, size, 8);
122
+ @memset(target[size..new_size], 0);
123
+ size = new_size;
124
+
125
+ for (client_sessions.entries) |*entry| {
126
+ stdx.copy_disjoint(.inexact, u8, target[size..], mem.asBytes(&entry.session));
127
+ size += @sizeOf(u64);
128
+ }
129
+
130
+ assert(size == encode_size);
131
+ return size;
132
+ }
133
+
134
+ pub fn decode(
135
+ client_sessions: *ClientSessions,
136
+ source: []align(@alignOf(vsr.Header)) const u8,
137
+ ) void {
138
+ assert(client_sessions.count() == 0);
139
+ assert(client_sessions.entries_present.empty());
140
+ for (client_sessions.entries) |*entry| {
141
+ assert(entry.session == 0);
142
+ assert(stdx.zeroed(std.mem.asBytes(&entry.header)));
143
+ }
144
+
145
+ var size: u64 = 0;
146
+ assert(source.len > 0);
147
+ assert(source.len <= encode_size);
148
+
149
+ assert(@alignOf(vsr.Header) == 16);
150
+ size = std.mem.alignForward(usize, size, 16);
151
+ const headers: []const vsr.Header.Reply = @alignCast(mem.bytesAsSlice(
152
+ vsr.Header.Reply,
153
+ source[size..][0 .. constants.clients_max * @sizeOf(vsr.Header)],
154
+ ));
155
+ size += mem.sliceAsBytes(headers).len;
156
+
157
+ assert(@alignOf(u64) == 8);
158
+ size = std.mem.alignForward(usize, size, 8);
159
+ const sessions = mem.bytesAsSlice(
160
+ u64,
161
+ source[size..][0 .. constants.clients_max * @sizeOf(u64)],
162
+ );
163
+ size += mem.sliceAsBytes(sessions).len;
164
+
165
+ assert(size == encode_size);
166
+
167
+ for (headers, 0..) |*header, i| {
168
+ const session = sessions[i];
169
+ if (session == 0) {
170
+ assert(stdx.zeroed(std.mem.asBytes(header)));
171
+ } else {
172
+ assert(header.valid_checksum());
173
+ assert(header.command == .reply);
174
+ assert(header.commit >= session);
175
+
176
+ client_sessions.entries_by_client.putAssumeCapacityNoClobber(header.client, i);
177
+ client_sessions.entries_present.set(i);
178
+ client_sessions.entries[i] = .{
179
+ .session = session,
180
+ .header = header.*,
181
+ };
182
+ }
183
+ }
184
+
185
+ assert(
186
+ client_sessions.entries_present.count() == client_sessions.entries_by_client.count(),
187
+ );
188
+ }
189
+
190
+ pub fn count(client_sessions: *const ClientSessions) usize {
191
+ return client_sessions.entries_by_client.count();
192
+ }
193
+
194
+ pub fn capacity(client_sessions: *const ClientSessions) usize {
195
+ _ = client_sessions;
196
+ return constants.clients_max;
197
+ }
198
+
199
+ pub fn get(client_sessions: *ClientSessions, client: u128) ?*Entry {
200
+ const entry_index = client_sessions.entries_by_client.get(client) orelse return null;
201
+ const entry = &client_sessions.entries[entry_index];
202
+ assert(entry.session != 0);
203
+ assert(entry.header.command == .reply);
204
+ assert(entry.header.client == client);
205
+ return entry;
206
+ }
207
+
208
+ pub fn get_slot_for_client(client_sessions: *const ClientSessions, client: u128) ?ReplySlot {
209
+ const index = client_sessions.entries_by_client.get(client) orelse return null;
210
+ return ReplySlot{ .index = index };
211
+ }
212
+
213
+ pub fn get_slot_for_header(
214
+ client_sessions: *const ClientSessions,
215
+ header: *const vsr.Header.Reply,
216
+ ) ?ReplySlot {
217
+ if (client_sessions.entries_by_client.get(header.client)) |entry_index| {
218
+ const entry = &client_sessions.entries[entry_index];
219
+ if (entry.header.checksum == header.checksum) {
220
+ return ReplySlot{ .index = entry_index };
221
+ }
222
+ }
223
+ return null;
224
+ }
225
+
226
+ /// If the entry is from a newly-registered client, the caller is responsible for ensuring
227
+ /// the ClientSessions has available capacity.
228
+ pub fn put(
229
+ client_sessions: *ClientSessions,
230
+ session: u64,
231
+ header: *const vsr.Header.Reply,
232
+ ) ReplySlot {
233
+ assert(session != 0);
234
+ assert(header.command == .reply);
235
+ const client = header.client;
236
+
237
+ defer assert(client_sessions.entries_by_client.contains(client));
238
+
239
+ const entry_gop = client_sessions.entries_by_client.getOrPutAssumeCapacity(client);
240
+ if (entry_gop.found_existing) {
241
+ const entry_index = entry_gop.value_ptr.*;
242
+ assert(client_sessions.entries_present.is_set(entry_index));
243
+
244
+ const existing = &client_sessions.entries[entry_index];
245
+ assert(existing.session == session);
246
+ assert(existing.header.cluster == header.cluster);
247
+ assert(existing.header.client == header.client);
248
+ assert(existing.header.commit < header.commit);
249
+
250
+ existing.header = header.*;
251
+ return ReplySlot{ .index = entry_index };
252
+ } else {
253
+ const entry_index = client_sessions.entries_present.first_unset().?;
254
+ client_sessions.entries_present.set(entry_index);
255
+
256
+ const e = &client_sessions.entries[entry_index];
257
+ assert(e.session == 0);
258
+
259
+ entry_gop.value_ptr.* = entry_index;
260
+ e.session = session;
261
+ e.header = header.*;
262
+ return ReplySlot{ .index = entry_index };
263
+ }
264
+ }
265
+
266
+ /// For correctness, it's critical that all replicas evict deterministically:
267
+ /// We cannot depend on `HashMap.capacity()` since `HashMap.ensureTotalCapacity()` may
268
+ /// change across versions of the Zig std lib. We therefore rely on
269
+ /// `constants.clients_max`, which must be the same across all replicas, and must not
270
+ /// change after initializing a cluster.
271
+ /// We also do not depend on `HashMap.valueIterator()` being deterministic here. However,
272
+ /// we do require that all entries have different commit numbers and are iterated.
273
+ /// This ensures that we will always pick the entry with the oldest commit number.
274
+ /// We also check that a client has only one entry in the hash map (or it's buggy).
275
+ pub fn evictee(client_sessions: *const ClientSessions) u128 {
276
+ assert(client_sessions.entries_present.full());
277
+ assert(client_sessions.count() == constants.clients_max);
278
+
279
+ var evictee_: ?*const vsr.Header.Reply = null;
280
+ var iterated: usize = 0;
281
+ var entries = client_sessions.iterator();
282
+ while (entries.next()) |entry| : (iterated += 1) {
283
+ assert(entry.header.command == .reply);
284
+ assert(entry.header.op == entry.header.commit);
285
+ assert(entry.header.commit >= entry.session);
286
+
287
+ if (evictee_) |evictee_reply| {
288
+ assert(entry.header.client != evictee_reply.client);
289
+ assert(entry.header.commit != evictee_reply.commit);
290
+
291
+ if (entry.header.commit < evictee_reply.commit) {
292
+ evictee_ = &entry.header;
293
+ }
294
+ } else {
295
+ evictee_ = &entry.header;
296
+ }
297
+ }
298
+ assert(iterated == constants.clients_max);
299
+
300
+ return evictee_.?.client;
301
+ }
302
+
303
+ pub fn remove(client_sessions: *ClientSessions, client: u128) void {
304
+ const entry_index = client_sessions.entries_by_client.fetchRemove(client).?.value;
305
+
306
+ assert(client_sessions.entries_present.is_set(entry_index));
307
+ client_sessions.entries_present.unset(entry_index);
308
+
309
+ assert(client_sessions.entries[entry_index].header.client == client);
310
+ client_sessions.entries[entry_index] = std.mem.zeroes(Entry);
311
+
312
+ assert(!client_sessions.entries_by_client.contains(client));
313
+ }
314
+
315
+ pub const Iterator = struct {
316
+ client_sessions: *const ClientSessions,
317
+ index: usize = 0,
318
+
319
+ pub fn next(it: *Iterator) ?*const Entry {
320
+ while (it.index < it.client_sessions.entries.len) {
321
+ defer it.index += 1;
322
+
323
+ const entry = &it.client_sessions.entries[it.index];
324
+ if (entry.session == 0) {
325
+ assert(!it.client_sessions.entries_present.is_set(it.index));
326
+ } else {
327
+ assert(it.client_sessions.entries_present.is_set(it.index));
328
+ return entry;
329
+ }
330
+ }
331
+ return null;
332
+ }
333
+ };
334
+
335
+ pub fn iterator(client_sessions: *const ClientSessions) Iterator {
336
+ return .{ .client_sessions = client_sessions };
337
+ }
338
+ };