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,843 +0,0 @@
1
- //! Memory tables for an LSM (log‑structured merge) stage.
2
- //!
3
- //! Each `tree.zig` maintains two in‑memory tables:
4
- //! - Mutable table: accepts all updates (e.g., `Tree.put`).
5
- //! - Immutable table: sorted read‑only staging area for the next flush to disk.
6
- //!
7
- //! New puts are appended to the mutable table. When the mutable table fills up
8
- //! — or rather when we reach a bar boundary - the mutable table is compacted into
9
- //! the immutable table. Compaction sorts and deduplicates entries and prepares them for the LSM
10
- //! `compaction.zig` to be flushed to disk.
11
- //!
12
- //! Optimizations
13
- //! 1) Sorted runs on every beat:
14
- //! - At the end of each beat, the mutable table’s suffix is sorted and
15
- //! deduplicated, and the suffix offset advances.
16
- //! - By the end of a bar, the mutable table is a sequence of sorted arrays,
17
- //! which are then merged and deduplicated.
18
- //!
19
- //! 2) Deferred disk flush:
20
- //! - If the immutable table is not sufficiently full, `compaction.zig` may
21
- //! choose not to flush to disk. Instead, we retain the current immutable
22
- //! table and absorb the mutable table into it.
23
-
24
- const std = @import("std");
25
- const mem = std.mem;
26
- const assert = std.debug.assert;
27
-
28
- const constants = @import("../constants.zig");
29
- const binary_search = @import("binary_search.zig");
30
- const stdx = @import("stdx");
31
- const maybe = stdx.maybe;
32
-
33
- const KWayMergeIteratorType = @import("k_way_merge.zig").KWayMergeIteratorType;
34
- const ScratchMemory = @import("scratch_memory.zig").ScratchMemory;
35
- const Pending = error{Pending};
36
-
37
- pub fn TableMemoryType(comptime Table: type) type {
38
- const Key = Table.Key;
39
- const Value = Table.Value;
40
- const key_from_value = Table.key_from_value;
41
-
42
- return struct {
43
- const TableMemory = @This();
44
-
45
- values: []Value,
46
- value_context: ValueContext,
47
- mutability: Mutability,
48
- name: []const u8,
49
-
50
- // Maintains per-table mutable state that must be snapshotted for “scopes”.
51
- // When a scope is opened (e.g., in `tree.zig`), we copy `ValueContext` so we can
52
- // roll back both the count and the sorted-run tracker if the scope is discarded.
53
- pub const ValueContext = struct {
54
- count: u32 = 0,
55
- run_tracker: SortedRunTracker,
56
- };
57
-
58
- const Mutability = union(enum) {
59
- mutable: struct {
60
- // This buffer is shared between all `Tables` for the radix sort.
61
- // It is passed down from the forest.
62
- radix_buffer: *ScratchMemory,
63
- },
64
- immutable: struct {
65
- // An empty table has nothing to flush.
66
- flushed: bool = true,
67
- // This field is only used for assertions, to verify that we don't absorb the
68
- // mutable table immediately prior to checkpoint.
69
- absorbed: bool = false,
70
- snapshot_min: u64 = 0,
71
- },
72
- };
73
-
74
- // Where the sorted run originated; affects merge precedence on equal keys.
75
- // We prefer the immutable ones to keep ordering for deduplication (last key wins).
76
- const RunOrigin = enum { mutable, immutable };
77
-
78
- // A contiguous sorted range in `values[min..max)`.
79
- const SortedRun = struct {
80
- min: u32,
81
- max: u32, // exclusive.
82
- origin: RunOrigin, // Where the run originated; affects merge precedence on equal keys.
83
- };
84
-
85
- // At most: LSM compactions + one sort() call + one immutable run for `absorb`.
86
- const sorted_runs_max = constants.lsm_compaction_ops + 2;
87
-
88
- // Merge context for the k-way iterator across all runs in the tracker.
89
- const MergeContext = struct {
90
- streams: [sorted_runs_max][]const Value,
91
- streams_count: u32,
92
-
93
- fn stream_peek(
94
- context: *const MergeContext,
95
- stream_index: u32,
96
- ) Pending!?Key {
97
- // TODO: Enable the asserts once `constants.verify` is disabled on release.
98
- //assert(stream_index < context.streams_count);
99
- const stream = context.streams[stream_index];
100
- if (stream.len == 0) return null;
101
- return key_from_value(&stream[0]);
102
- }
103
-
104
- fn stream_pop(context: *MergeContext, stream_index: u32) Value {
105
- // TODO: Enable the asserts once `constants.verify` is disabled on release.
106
- //assert(stream_index < context.streams_count);
107
- const stream = context.streams[stream_index];
108
- context.streams[stream_index] = stream[1..];
109
- return stream[0];
110
- }
111
- };
112
-
113
- const KWayMergeIterator = KWayMergeIteratorType(
114
- MergeContext,
115
- Key,
116
- Value,
117
- .{
118
- .streams_max = sorted_runs_max,
119
- .deduplicate = false,
120
- },
121
- key_from_value,
122
- MergeContext.stream_peek,
123
- MergeContext.stream_pop,
124
- );
125
-
126
- const SortedRunTracker = struct {
127
- /// Invariants:
128
- /// - Runs are in ascending order.
129
- /// - Runs have no gaps between them.
130
- /// - There is at most one run with run.origin=.immutable
131
- runs: [sorted_runs_max]SortedRun,
132
- runs_count: u8,
133
-
134
- fn init() SortedRunTracker {
135
- return .{
136
- .runs = undefined,
137
- .runs_count = 0,
138
- };
139
- }
140
-
141
- fn add(tracker: *SortedRunTracker, run: SortedRun) void {
142
- if (run.min == run.max) return; // Ignore empty runs.
143
-
144
- tracker.runs[tracker.runs_count] = run;
145
- tracker.runs_count += 1;
146
- }
147
-
148
- // Adds a new run at the front and shifts the other runs by the offset to maintain
149
- // the invariant that no run overlaps and they have no gaps.
150
- fn add_front_and_propagate_offset(tracker: *SortedRunTracker, run: SortedRun) void {
151
- if (run.min == run.max) return; // Ignore empty runs.
152
- assert(tracker.runs_count + 1 <= tracker.runs.len);
153
- stdx.copy_right(
154
- .exact,
155
- SortedRun,
156
- tracker.runs[1 .. tracker.runs_count + 1],
157
- tracker.runs[0..tracker.runs_count],
158
- );
159
-
160
- tracker.runs[0] = run;
161
- tracker.runs_count += 1;
162
-
163
- //Propagate the new offset to the remaining runs.
164
- for (tracker.runs[1..tracker.count()]) |*run_old| {
165
- run_old.min += run.max;
166
- run_old.max += run.max;
167
- }
168
- }
169
-
170
- fn reset(tracker: *SortedRunTracker) void {
171
- tracker.* = .{
172
- .runs = undefined,
173
- .runs_count = 0,
174
- };
175
- }
176
-
177
- fn count(tracker: *const SortedRunTracker) u32 {
178
- return tracker.runs_count;
179
- }
180
-
181
- fn merge_context(tracker: *const SortedRunTracker, values: []const Value) MergeContext {
182
- var context = MergeContext{
183
- .streams = undefined,
184
- .streams_count = undefined,
185
- };
186
-
187
- var stream_idx: u32 = 0;
188
-
189
- // Place the immutable run first so smaller stream_id wins on ties.
190
- for (tracker.runs[0..tracker.count()]) |run| {
191
- if (run.origin != .immutable) continue;
192
- context.streams[stream_idx] = values[run.min..run.max];
193
- stream_idx += 1;
194
- break;
195
- }
196
- // Now place all the mutable runs.
197
- for (tracker.runs[0..tracker.count()]) |run| {
198
- if (run.origin == .immutable) continue;
199
- context.streams[stream_idx] = values[run.min..run.max];
200
- stream_idx += 1;
201
- }
202
- context.streams_count = stream_idx;
203
- return context;
204
- }
205
-
206
- fn last(tracker: *const SortedRunTracker) ?*const SortedRun {
207
- if (tracker.count() == 0) return null;
208
- return &tracker.runs[tracker.count() - 1];
209
- }
210
-
211
- fn assert_invariants(tracker: *const SortedRunTracker, table_count: u32) void {
212
- const runs_count = tracker.count();
213
-
214
- if (runs_count == 0) return;
215
-
216
- assert(tracker.runs[0].min == 0);
217
- assert(tracker.runs[runs_count - 1].max == table_count);
218
-
219
- for (tracker.runs[0 .. runs_count - 1], tracker.runs[1..runs_count]) |a, b| {
220
- assert(a.min < b.min); // Ordered and we ignore empty runs.
221
- assert(a.max == b.min); // No gaps.
222
- }
223
-
224
- var immutable_runs: u1 = 0;
225
- for (tracker.runs[0..runs_count]) |run| {
226
- immutable_runs += @intFromBool(run.origin == .immutable);
227
- }
228
- assert(immutable_runs == 0 or immutable_runs == 1);
229
- }
230
- };
231
-
232
- // Merge values with identical keys (last one wins) and collapse tombstones for
233
- // secondary indexes in a streaming fashion.
234
- const DedupSink = struct {
235
- out: []Value,
236
- target_index: u32 = 0,
237
-
238
- // Holds the current candidate that may merge with the next item.
239
- pending: ?Value = null,
240
-
241
- pub fn init(out: []Value) DedupSink {
242
- return .{ .out = out };
243
- }
244
-
245
- // Streamed equivalent of `deduplicate`.
246
- pub fn push(self: *DedupSink, value: Value) void {
247
- const pending = self.pending orelse {
248
- // Starting a new run with a pending `value`.
249
- self.pending = value;
250
- return;
251
- };
252
-
253
- // If we're at the end of the source, there is no next value, so the next value
254
- // can't be equal.
255
- if (key_from_value(&pending) == key_from_value(&value)) {
256
- if (Table.usage == .secondary_index) {
257
- // Secondary index optimization --- cancel out put and remove.
258
- // NB: while this prevents redundant tombstones from getting to disk, we
259
- // still spend some extra CPU work to sort the entries in memory. Ideally,
260
- // we annihilate tombstones immediately, before sorting, but that's tricky
261
- // to do with scopes.
262
- assert(Table.tombstone(&pending) != Table.tombstone(&value));
263
- // Effect: consume both and produce nothing for this key.
264
- self.pending = null; // drop both
265
- } else {
266
- // The last value in a run of duplicates needs to be the one that ends up in
267
- // target.
268
- // Effect: keep the slot, overwrite winner with the newer value.
269
- self.pending = value; // last wins
270
- }
271
- } else {
272
- // New key encountered: flush previous winner, start a new run.
273
- self.out[self.target_index] = pending;
274
- self.target_index += 1;
275
- self.pending = value;
276
- }
277
- }
278
-
279
- pub fn finish(self: *DedupSink) u32 {
280
- // Flush the final pending value, if any.
281
- if (self.pending) |p| {
282
- self.out[self.target_index] = p;
283
- self.target_index += 1;
284
- self.pending = null;
285
- }
286
-
287
- // At this point, target_index is the number of deduplicated items written.
288
- if (constants.verify) {
289
- if (0 < self.target_index) {
290
- for (
291
- self.out[0 .. self.target_index - 1],
292
- self.out[1..self.target_index],
293
- ) |*value, *value_next| {
294
- assert(key_from_value(value) < key_from_value(value_next));
295
- }
296
- }
297
- }
298
-
299
- return self.target_index;
300
- }
301
- };
302
-
303
- pub fn init(
304
- table: *TableMemory,
305
- allocator: mem.Allocator,
306
- radix_buffer: *ScratchMemory,
307
- mutability: std.meta.Tag(Mutability),
308
- name: []const u8,
309
- options: struct {
310
- value_count_limit: u32,
311
- },
312
- ) !void {
313
- assert(options.value_count_limit <= Table.value_count_max);
314
- assert(radix_buffer.state == .free);
315
-
316
- table.* = .{
317
- .value_context = .{
318
- .run_tracker = SortedRunTracker.init(),
319
- },
320
- .mutability = switch (mutability) {
321
- .mutable => .{ .mutable = .{
322
- .radix_buffer = radix_buffer,
323
- } },
324
- .immutable => .{ .immutable = .{} },
325
- },
326
- .name = name,
327
- .values = undefined,
328
- };
329
-
330
- // TODO This would ideally be value_count_limit, but needs to be value_count_max to
331
- // ensure that memory table coalescing is deterministic even if the batch limit changes.
332
- table.values = try allocator.alloc(Value, Table.value_count_max);
333
- errdefer allocator.free(table.values);
334
- }
335
-
336
- pub fn deinit(table: *TableMemory, allocator: mem.Allocator) void {
337
- allocator.free(table.values);
338
- }
339
-
340
- pub fn reset(table: *TableMemory) void {
341
- const mutability: Mutability = switch (table.mutability) {
342
- .immutable => .{ .immutable = .{} },
343
- .mutable => .{ .mutable = .{
344
- .radix_buffer = table.mutability.mutable.radix_buffer,
345
- } },
346
- };
347
-
348
- table.value_context.run_tracker.reset();
349
-
350
- table.* = .{
351
- .values = table.values,
352
- .value_context = .{
353
- .run_tracker = table.value_context.run_tracker,
354
- },
355
- .mutability = mutability,
356
- .name = table.name,
357
- };
358
- }
359
-
360
- pub fn count(table: *const TableMemory) u32 {
361
- return table.value_context.count;
362
- }
363
-
364
- pub fn values_used(table: *const TableMemory) []Value {
365
- return table.values[0..table.count()];
366
- }
367
-
368
- // Appends a `value`. If it is strictly greater than the previous key,
369
- // expand the last run by 1; otherwise the suffix will be sorted later.
370
- pub fn put(table: *TableMemory, value: *const Value) void {
371
- assert(table.mutability == .mutable);
372
- assert(table.count() < table.values.len);
373
-
374
- const run_count = table.value_context.run_tracker.count();
375
- if (run_count > 0 and
376
- table.value_context.run_tracker.runs[run_count - 1].max == table.count())
377
- {
378
- const expand: bool = table.count() == 0 or
379
- key_from_value(&table.values[table.count() - 1]) <
380
- key_from_value(value);
381
- table.value_context.run_tracker.runs[run_count - 1].max += @intFromBool(expand);
382
- }
383
-
384
- table.values[table.count()] = value.*;
385
- table.value_context.count += 1;
386
- }
387
-
388
- /// This must be called on sorted tables (single run from 0..count).
389
- pub fn get(table: *TableMemory, key: Key) ?*const Value {
390
- assert(table.count() <= table.values.len);
391
- assert(table.sorted());
392
-
393
- if (!table.key_range_contains(key)) {
394
- return null;
395
- }
396
-
397
- return binary_search.binary_search_values(
398
- Key,
399
- Value,
400
- key_from_value,
401
- table.values_used(),
402
- key,
403
- .{ .mode = .upper_bound },
404
- );
405
- }
406
-
407
- fn finalize(table_immutable: *TableMemory, snapshot_min: u64) void {
408
- assert(table_immutable.mutability == .immutable);
409
-
410
- table_immutable.mutability = .{ .immutable = .{
411
- .flushed = table_immutable.count() == 0,
412
- .snapshot_min = snapshot_min,
413
- } };
414
- table_immutable.value_context.run_tracker.reset();
415
- table_immutable.value_context.run_tracker.add(.{
416
- .min = 0,
417
- .max = table_immutable.count(),
418
- .origin = .immutable,
419
- });
420
- }
421
-
422
- // Merge `table_mutable` runs into `table_immutable`.
423
- pub fn compact(
424
- table_immutable: *TableMemory,
425
- table_mutable: *TableMemory,
426
- snapshot_min: u64,
427
- ) void {
428
- assert(table_immutable.mutability == .immutable);
429
- maybe(table_immutable.mutability.immutable.absorbed);
430
- assert(table_mutable.mutability == .mutable);
431
- maybe(table_mutable.sorted());
432
- defer assert(table_immutable.sorted());
433
- defer assert(table_mutable.count() == 0);
434
-
435
- table_mutable.value_context.run_tracker.assert_invariants(table_mutable.count());
436
-
437
- if (table_mutable.sorted()) {
438
- // Fast-path: single contiguous sorted run: swap buffers.
439
- assert(table_mutable.values.len == table_immutable.values.len);
440
- std.mem.swap([]Value, &table_mutable.values, &table_immutable.values);
441
-
442
- table_immutable.value_context.count = table_mutable.count();
443
- } else {
444
- var merge_context = table_mutable.value_context
445
- .run_tracker.merge_context(table_mutable.values_used());
446
- var merge_iterator = KWayMergeIterator.init(
447
- &merge_context,
448
- @intCast(merge_context.streams_count),
449
- .ascending,
450
- );
451
-
452
- // Deduplicate values in streaming fashion.
453
- var dedup_sink = DedupSink.init(table_immutable.values);
454
- while (merge_iterator.pop() catch unreachable) |value| {
455
- dedup_sink.push(value);
456
- }
457
- table_immutable.value_context.count = dedup_sink.finish();
458
- }
459
-
460
- table_mutable.reset();
461
- table_immutable.finalize(snapshot_min);
462
- assert(table_immutable.sorted());
463
- }
464
-
465
- // Absorb the current immutable table into the mutable one,
466
- // then re-materialize a compact immutable table.
467
- pub fn absorb(
468
- table_immutable: *TableMemory,
469
- table_mutable: *TableMemory,
470
- snapshot_min: u64,
471
- ) void {
472
- assert(table_immutable.mutability == .immutable);
473
- maybe(table_immutable.mutability.immutable.absorbed);
474
- assert(table_immutable.sorted());
475
- assert(table_mutable.mutability == .mutable);
476
- maybe(table_mutable.sorted());
477
- defer assert(table_immutable.sorted());
478
-
479
- const values_count_limit = table_immutable.values.len;
480
- assert(table_immutable.count() <= values_count_limit);
481
- assert(table_mutable.count() <= values_count_limit);
482
- assert(table_immutable.count() + table_mutable.count() <= values_count_limit);
483
-
484
- if (table_mutable.count() == 0) return;
485
-
486
- // Copy immutable after the current mutable tail and mark as an immutable run,
487
- // so the merge prefers its entries on key ties.
488
- const tables_combined_count = table_immutable.count() + table_mutable.count();
489
-
490
- // Because `table_mutable` is likely to be smaller then `tabel_immutable` we:
491
- // 1. Copy the values from `table_mutable` into `table_immutable`.
492
- // 2. We swap the backing arrays so that `table_mutable` has all the values.
493
- // 3. We add the new run from `table_immutable` at the beginning.
494
- stdx.copy_disjoint(
495
- .inexact,
496
- Value,
497
- table_immutable.values[table_immutable.count()..],
498
- table_mutable.values[0..table_mutable.count()],
499
- );
500
- std.mem.swap([]Value, &table_mutable.values, &table_immutable.values);
501
-
502
- table_mutable.value_context.run_tracker.add_front_and_propagate_offset(.{
503
- .min = 0,
504
- .max = table_immutable.count(),
505
- .origin = .immutable,
506
- });
507
-
508
- table_mutable.value_context.count = tables_combined_count;
509
- table_mutable.value_context.run_tracker.assert_invariants(table_mutable.count());
510
-
511
- table_immutable.mutability.immutable.absorbed = true;
512
- table_immutable.compact(table_mutable, snapshot_min);
513
-
514
- // One fully sorted run or all keys are annihilated.
515
- assert(table_immutable.value_context.run_tracker.count() <= 1);
516
- assert(table_mutable.value_context.run_tracker.count() == 0);
517
- }
518
-
519
- // Fully sort the table if needed. Produces a single run [0..count).
520
- pub fn sort(table: *TableMemory) void {
521
- assert(table.mutability == .mutable);
522
- defer table.value_context.run_tracker.assert_invariants(table.count());
523
-
524
- if (!table.sorted()) {
525
- _ = table.mutable_sort_suffix_from_offset(0);
526
- table.value_context.run_tracker.reset();
527
- table.value_context.run_tracker.add(.{
528
- .min = 0,
529
- .max = table.count(),
530
- .origin = .mutable,
531
- });
532
- }
533
- }
534
-
535
- // When true, `values` is strictly ascending-ordered (no duplicates).
536
- fn sorted(table: *const TableMemory) bool {
537
- // Empty table is considered sorted.
538
- if (table.count() == 0) return true;
539
-
540
- // Only one sorted run can exist if it is sorted.
541
- if (table.value_context.run_tracker.count() != 1) return false;
542
-
543
- const last_run = table.value_context.run_tracker.last().?;
544
- assert(last_run.min == 0);
545
- assert(last_run.max <= table.count());
546
-
547
- return table.count() == last_run.max;
548
- }
549
-
550
- pub fn sort_suffix(table: *TableMemory) void {
551
- assert(table.mutability == .mutable);
552
- defer table.value_context.run_tracker.assert_invariants(table.count());
553
-
554
- if (table.sorted()) return;
555
-
556
- const sort_suffix_offset = if (table.value_context.run_tracker.last()) |last_run|
557
- last_run.max
558
- else
559
- 0;
560
-
561
- assert(sort_suffix_offset <= table.count());
562
-
563
- if (sort_suffix_offset == table.count()) return;
564
-
565
- const run = table.mutable_sort_suffix_from_offset(sort_suffix_offset);
566
- assert(run.min <= run.max);
567
- assert(run.max == table.count());
568
- assert(sort_suffix_offset <= run.max);
569
- table.value_context.run_tracker.add(run);
570
- }
571
-
572
- fn mutable_sort_suffix_from_offset(table: *TableMemory, offset: u32) SortedRun {
573
- assert(table.mutability == .mutable);
574
- assert(offset == 0 or offset == table.value_context.run_tracker.last().?.max);
575
- assert(offset <= table.count());
576
-
577
- const radix_buffer_values = table.mutability.mutable.radix_buffer.acquire(
578
- Value,
579
- table.count(),
580
- );
581
- defer table.mutability.mutable.radix_buffer.release(Value, radix_buffer_values);
582
-
583
- const target_count = sort_suffix_from_offset(
584
- table.values_used(),
585
- radix_buffer_values,
586
- offset,
587
- );
588
- table.value_context.count = target_count;
589
- return .{ .min = offset, .max = target_count, .origin = .mutable };
590
- }
591
-
592
- // Returns the new length of `values`. Values are deduplicated after sorting, so the
593
- // returned count may be less than or equal to the original `values.len`.
594
- fn sort_suffix_from_offset(values: []Value, values_scratch: []Value, offset: u32) u32 {
595
- assert(values.len == values_scratch.len);
596
- assert(offset <= values.len);
597
-
598
- stdx.radix_sort(Key, Value, key_from_value, values[offset..], values_scratch[offset..]);
599
-
600
- // Deduplicate values in streaming fashion.
601
- var dedup_sink = DedupSink.init(values[offset..]);
602
- for (values[offset..]) |value| {
603
- dedup_sink.push(value);
604
- }
605
- const target_count = offset + dedup_sink.finish();
606
-
607
- return target_count;
608
- }
609
-
610
- pub fn key_range_contains(table: *const TableMemory, key: Key) bool {
611
- assert(table.sorted());
612
-
613
- if (table.count() == 0) return false;
614
- return table.key_min() <= key and key <= table.key_max();
615
- }
616
-
617
- pub fn key_min(table: *const TableMemory) Key {
618
- const values = table.values_used();
619
-
620
- assert(values.len > 0);
621
- assert(table.sorted());
622
-
623
- return key_from_value(&values[0]);
624
- }
625
-
626
- pub fn key_max(table: *const TableMemory) Key {
627
- const values = table.values_used();
628
-
629
- assert(values.len > 0);
630
- assert(table.sorted());
631
-
632
- return key_from_value(&values[values.len - 1]);
633
- }
634
- };
635
- }
636
-
637
- const TestHelper = struct {
638
- pub const TableUsage = enum {
639
- general,
640
- secondary_index,
641
- };
642
-
643
- fn TestTableType(comptime mode: TableUsage) type {
644
- return struct {
645
- const Key = u32;
646
- const Value = struct { key: Key, version: u32, tombstone: bool };
647
- const value_count_max = 16;
648
- const usage = mode;
649
-
650
- pub inline fn key_from_value(v: *const Value) Key {
651
- return v.key;
652
- }
653
- pub fn tombstone(v: *const Value) bool {
654
- return v.tombstone;
655
- }
656
- };
657
- }
658
-
659
- fn create_table_immutable(
660
- comptime TableType: type,
661
- gpa: std.mem.Allocator,
662
- value_count_limit: u32,
663
- radix_buffer: *ScratchMemory,
664
- ) !TableType {
665
- var table_immutable: TableType = undefined;
666
- try table_immutable.init(
667
- gpa,
668
- radix_buffer,
669
- .immutable,
670
- "immutable",
671
- .{ .value_count_limit = value_count_limit },
672
- );
673
- return table_immutable;
674
- }
675
-
676
- fn create_table_mutable(
677
- comptime TableType: type,
678
- gpa: std.mem.Allocator,
679
- value_count_limit: u32,
680
- radix_buffer: *ScratchMemory,
681
- ) !TableType {
682
- var table_mutable: TableType = undefined;
683
- try table_mutable.init(
684
- gpa,
685
- radix_buffer,
686
- .mutable,
687
- "mutable",
688
- .{ .value_count_limit = value_count_limit },
689
- );
690
- return table_mutable;
691
- }
692
- };
693
-
694
- test "table_memory: merge and absorb (last wins across streams)" {
695
- const testing = std.testing;
696
- const Snap = stdx.Snap;
697
- const snap = Snap.snap_fn("src");
698
-
699
- const Table = TestHelper.TestTableType(.general);
700
- const Value = Table.Value;
701
- const TableMemory = TableMemoryType(Table);
702
-
703
- const alloc = testing.allocator;
704
-
705
- var radix_buffer: ScratchMemory = try .init(alloc, Table.value_count_max * @sizeOf(Value));
706
- defer radix_buffer.deinit(alloc);
707
-
708
- var table_immutable: TableMemory = try TestHelper.create_table_immutable(
709
- TableMemory,
710
- alloc,
711
- Table.value_count_max,
712
- &radix_buffer,
713
- );
714
- defer table_immutable.deinit(alloc);
715
-
716
- var table_mutable: TableMemory = try TestHelper.create_table_mutable(
717
- TableMemory,
718
- alloc,
719
- Table.value_count_max,
720
- &radix_buffer,
721
- );
722
- defer table_mutable.deinit(alloc);
723
-
724
- table_mutable.put(&Value{ .key = 2, .version = 0, .tombstone = false });
725
- table_mutable.put(&Value{ .key = 4, .version = 0, .tombstone = false });
726
- table_mutable.sort();
727
-
728
- table_immutable.compact(&table_mutable, 0);
729
- assert(table_immutable.sorted());
730
- assert(table_mutable.count() == 0);
731
-
732
- table_mutable.put(&Value{ .key = 2, .version = 1, .tombstone = false });
733
- table_mutable.put(&Value{ .key = 5, .version = 0, .tombstone = false });
734
- table_mutable.sort();
735
-
736
- table_immutable.absorb(&table_mutable, 0);
737
-
738
- assert(table_immutable.sorted());
739
- assert(table_mutable.count() == 0);
740
- assert(table_immutable.count() == 3);
741
-
742
- var keys: [3]struct { Table.Key, u32 } = undefined;
743
-
744
- for (table_immutable.values_used(), 0..) |value, i| {
745
- keys[i] = .{ value.key, value.version };
746
- }
747
-
748
- try snap(@src(),
749
- \\{ { 2, 1 }, { 4, 0 }, { 5, 0 } }
750
- ).diff_fmt("{any}", .{keys});
751
- }
752
-
753
- test "table_memory: compact and deduplicate across runs" {
754
- const testing = std.testing;
755
- const Snap = stdx.Snap;
756
- const snap = Snap.snap_fn("src");
757
-
758
- const Table = TestHelper.TestTableType(.general);
759
- const Value = Table.Value;
760
- const TableMemory = TableMemoryType(Table);
761
-
762
- const alloc = testing.allocator;
763
-
764
- var radix_buffer: ScratchMemory = try .init(alloc, Table.value_count_max * @sizeOf(Value));
765
- defer radix_buffer.deinit(alloc);
766
-
767
- var table_immutable: TableMemory = try TestHelper.create_table_immutable(
768
- TableMemory,
769
- alloc,
770
- Table.value_count_max,
771
- &radix_buffer,
772
- );
773
- defer table_immutable.deinit(alloc);
774
-
775
- var table_mutable: TableMemory = try TestHelper.create_table_mutable(
776
- TableMemory,
777
- alloc,
778
- Table.value_count_max,
779
- &radix_buffer,
780
- );
781
- defer table_mutable.deinit(alloc);
782
-
783
- table_mutable.put(&Value{ .key = 2, .version = 0, .tombstone = false });
784
- table_mutable.put(&Value{ .key = 2, .version = 1, .tombstone = false });
785
- table_mutable.sort_suffix();
786
-
787
- table_mutable.put(&Value{ .key = 2, .version = 2, .tombstone = false });
788
- table_mutable.put(&Value{ .key = 2, .version = 3, .tombstone = false });
789
- table_mutable.sort_suffix();
790
-
791
- table_immutable.compact(&table_mutable, 0);
792
- assert(table_immutable.sorted());
793
- assert(table_mutable.count() == 0);
794
- assert(table_immutable.count() == 1);
795
-
796
- var keys: [1]struct { Table.Key, u32 } = undefined;
797
-
798
- for (table_immutable.values_used(), 0..) |value, i| {
799
- keys[i] = .{ value.key, value.version };
800
- }
801
-
802
- try snap(@src(),
803
- \\{ { 2, 3 } }
804
- ).diff_fmt("{any}", .{keys});
805
- }
806
-
807
- test "table_memory (secondary): annhiliation yields zero after deduplicate" {
808
- const testing = std.testing;
809
-
810
- const Table = TestHelper.TestTableType(.secondary_index);
811
- const Value = Table.Value;
812
- const TableMemory = TableMemoryType(Table);
813
-
814
- const alloc = testing.allocator;
815
-
816
- var radix_buffer: ScratchMemory = try .init(alloc, Table.value_count_max * @sizeOf(Value));
817
- defer radix_buffer.deinit(alloc);
818
-
819
- var table_immutable: TableMemory = try TestHelper.create_table_immutable(
820
- TableMemory,
821
- alloc,
822
- Table.value_count_max,
823
- &radix_buffer,
824
- );
825
- defer table_immutable.deinit(alloc);
826
-
827
- var table_mutable: TableMemory = try TestHelper.create_table_mutable(
828
- TableMemory,
829
- alloc,
830
- Table.value_count_max,
831
- &radix_buffer,
832
- );
833
- defer table_mutable.deinit(alloc);
834
-
835
- table_mutable.put(&Value{ .key = 2, .version = 0, .tombstone = false });
836
- table_mutable.put(&Value{ .key = 2, .version = 0, .tombstone = true });
837
- table_mutable.sort_suffix();
838
-
839
- table_immutable.compact(&table_mutable, 0);
840
- assert(table_immutable.sorted());
841
- assert(table_mutable.count() == 0);
842
- assert(table_immutable.count() == 0);
843
- }