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,1658 +0,0 @@
1
- //! Decode a TigerBeetle data file without running a replica or modifying the data file.
2
- //!
3
- //! This tool is intended for TigerBeetle developers, for debugging and understanding data files.
4
- //!
5
- //! Principles:
6
- //! - Never modify the data file.
7
- //! - Adhere to the "be liberal in what you accept" side of Postel's Law.
8
- //! When the data file is corrupt, decode as much as possible. (This is somewhat aspirational).
9
- //! - Outside of the "summary" commands, don't discard potentially useful information.
10
-
11
- const std = @import("std");
12
- const assert = std.debug.assert;
13
- const log = std.log.scoped(.inspect);
14
-
15
- const cli = @import("cli.zig");
16
- const vsr = @import("vsr");
17
- const stdx = vsr.stdx;
18
- const schema = vsr.lsm.schema;
19
- const constants = vsr.constants;
20
- const IO = vsr.io.IO;
21
- const Tracer = vsr.trace.Tracer;
22
- const Storage = @import("main.zig").Storage;
23
- const SuperBlockHeader = vsr.superblock.SuperBlockHeader;
24
- const SuperBlockVersion = vsr.superblock.SuperBlockVersion;
25
- const SuperBlockQuorums = vsr.superblock.Quorums;
26
- const StateMachine = @import("main.zig").StateMachine;
27
- const BlockPtr = vsr.grid.BlockPtr;
28
- const BlockPtrConst = vsr.grid.BlockPtrConst;
29
- const allocate_block = vsr.grid.allocate_block;
30
- const is_composite_key = vsr.lsm.composite_key.is_composite_key;
31
-
32
- const EventMetric = vsr.trace.EventMetric;
33
- const EventMetricAggregate = vsr.trace.EventMetricAggregate;
34
- const EventTiming = vsr.trace.EventTiming;
35
- const EventTimingAggregate = vsr.trace.EventTimingAggregate;
36
- const command_inspect_integrity = @import("inspect_integrity.zig").command_inspect_integrity;
37
-
38
- pub fn command_inspect(
39
- allocator: std.mem.Allocator,
40
- io: *IO,
41
- tracer: *Tracer,
42
- cli_args: *const cli.Command.Inspect,
43
- ) !void {
44
- var stdout_buffer = std.io.bufferedWriter(std.io.getStdOut().writer());
45
- var stdout_writer = stdout_buffer.writer();
46
-
47
- const inspect_result = run_inspect(allocator, io, tracer, cli_args, stdout_writer.any());
48
- const flush_result = stdout_buffer.flush();
49
-
50
- inline for (.{ inspect_result, flush_result }) |result| {
51
- result catch |err| switch (err) {
52
- // Ignore BrokenPipe so that e.g. "tigerbeetle inspect ... | head -n12" succeeds.
53
- error.BrokenPipe => {},
54
- else => return err,
55
- };
56
- }
57
- }
58
-
59
- fn run_inspect(
60
- allocator: std.mem.Allocator,
61
- io: *IO,
62
- tracer: *Tracer,
63
- cli_args: *const cli.Command.Inspect,
64
- stdout: std.io.AnyWriter,
65
- ) !void {
66
- const data_file = switch (cli_args.*) {
67
- .constants => return try inspect_constants(stdout),
68
- .metrics => return try inspect_metrics(stdout),
69
- .op => |op| return try inspect_op(stdout, op),
70
- .integrity => |*args| return try command_inspect_integrity(allocator, io, tracer, args),
71
- .data_file => |data_file| data_file,
72
- };
73
-
74
- const inspector = try Inspector.create(allocator, io, tracer, data_file.path);
75
- defer inspector.destroy();
76
-
77
- switch (data_file.query) {
78
- .superblock => try inspector.inspect_superblock(stdout),
79
- .wal => |args| {
80
- if (args.slot) |slot| {
81
- if (slot >= constants.journal_slot_count) {
82
- return vsr.fatal(
83
- .cli,
84
- "--slot: slot exceeds {}",
85
- .{constants.journal_slot_count - 1},
86
- );
87
- }
88
- try inspector.inspect_wal_slot(stdout, slot);
89
- } else {
90
- try inspector.inspect_wal(stdout);
91
- }
92
- },
93
- .replies => |args| {
94
- if (args.slot) |slot| {
95
- if (slot >= constants.clients_max) {
96
- return vsr.fatal(.cli, "--slot: slot exceeds {}", .{constants.clients_max - 1});
97
- }
98
- try inspector.inspect_replies_slot(stdout, args.superblock_copy, slot);
99
- } else {
100
- try inspector.inspect_replies(stdout, args.superblock_copy);
101
- }
102
- },
103
- .grid => |args| {
104
- if (args.superblock_copy != null and
105
- args.superblock_copy.? >= constants.superblock_copies)
106
- {
107
- return vsr.fatal(
108
- .cli,
109
- "--superblock-copy: copy exceeds {}",
110
- .{constants.superblock_copies - 1},
111
- );
112
- }
113
-
114
- if (args.block) |address| {
115
- try inspector.inspect_grid_block(stdout, address);
116
- } else {
117
- try inspector.inspect_grid(stdout, args.superblock_copy);
118
- }
119
- },
120
- .manifest => |args| {
121
- if (args.superblock_copy != null and
122
- args.superblock_copy.? >= constants.superblock_copies)
123
- {
124
- return vsr.fatal(
125
- .cli,
126
- "--superblock-copy: copy exceeds {}",
127
- .{constants.superblock_copies - 1},
128
- );
129
- }
130
-
131
- try inspector.inspect_manifest(stdout, args.superblock_copy);
132
- },
133
- .tables => |args| {
134
- if (args.superblock_copy != null and
135
- args.superblock_copy.? >= constants.superblock_copies)
136
- {
137
- return vsr.fatal(
138
- .cli,
139
- "--superblock-copy: copy exceeds {}",
140
- .{constants.superblock_copies - 1},
141
- );
142
- }
143
-
144
- const tree_id = parse_tree_id(args.tree) orelse {
145
- return vsr.fatal(.cli, "--tree: invalid tree name/id: {s}", .{args.tree});
146
- };
147
- try inspector.inspect_tables(stdout, args.superblock_copy, .{
148
- .tree_id = tree_id,
149
- .level = args.level,
150
- });
151
- },
152
- }
153
- }
154
-
155
- fn inspect_constants(output: std.io.AnyWriter) !void {
156
- try output.print("VSR:\n", .{});
157
- try print_header(output, 0, "prepare_queue");
158
- try output.print("{}\n", .{constants.pipeline_prepare_queue_max});
159
- try print_header(output, 0, "request_queue");
160
- try output.print("{}\n", .{constants.pipeline_request_queue_max});
161
- try print_header(output, 0, "prepare_cache");
162
- try output.print("{}\n", .{
163
- constants.pipeline_prepare_queue_max + constants.pipeline_request_queue_max,
164
- });
165
- try output.print("\n", .{});
166
-
167
- try output.print("LSM:\n", .{});
168
- try print_header(output, 0, "compaction_ops");
169
- try output.print("{}\n", .{constants.lsm_compaction_ops});
170
- try print_header(output, 0, "checkpoint_ops");
171
- try output.print("{}\n", .{constants.vsr_checkpoint_ops});
172
- try print_header(output, 0, "journal_slot_count");
173
- try output.print("{}\n", .{constants.journal_slot_count});
174
- try output.print("\n", .{});
175
-
176
- try output.print("Data File Layout:\n", .{});
177
- inline for (comptime std.enums.values(vsr.Zone)) |zone| {
178
- try print_header(output, 0, @tagName(zone));
179
- switch (zone) {
180
- inline else => |zone_sized| {
181
- try print_size_count(
182
- output,
183
- zone_sized.size().?,
184
- 1,
185
- );
186
- },
187
- .grid => {
188
- try output.print("elastic\n", .{});
189
- },
190
- }
191
- switch (zone) {
192
- .superblock => {
193
- try print_header(output, 1, "copy");
194
- try print_size_count(
195
- output,
196
- vsr.superblock.superblock_copy_size,
197
- constants.superblock_copies,
198
- );
199
- },
200
- .wal_headers => {
201
- try print_header(output, 1, "sector");
202
- try print_size_count(
203
- output,
204
- constants.sector_size,
205
- @divExact(vsr.Zone.wal_headers.size().?, constants.sector_size),
206
- );
207
-
208
- try print_header(output, 2, "header");
209
- try print_size_count(
210
- output,
211
- @sizeOf(vsr.Header),
212
- @divExact(constants.sector_size, @sizeOf(vsr.Header)),
213
- );
214
- },
215
- .wal_prepares => {
216
- try print_header(output, 1, "prepare");
217
- try print_size_count(
218
- output,
219
- constants.message_size_max,
220
- constants.journal_slot_count,
221
- );
222
- },
223
- .client_replies => {
224
- try print_header(output, 1, "reply");
225
- try print_size_count(
226
- output,
227
- constants.message_size_max,
228
- constants.clients_max,
229
- );
230
- },
231
- .grid => {
232
- try print_header(output, 1, "block");
233
- try print_size_count(output, constants.block_size, 1);
234
- },
235
- else => {},
236
- }
237
- try output.print("\n", .{});
238
- }
239
-
240
- // Print the size required to store each object + indexes.
241
- try output.print("StateMachine:\n", .{});
242
- try print_objects(output);
243
-
244
- // Memory usage is intentionally estimated from constants, rather than measured, to sanity
245
- // check that our observed memory usage is reasonable.
246
- try output.print("Memory (approximate):\n", .{});
247
- const datafile_size = constants.storage_size_limit_max;
248
- try print_header(output, 0, "datafile (on disk)");
249
- try output.print("{}\n", .{
250
- stdx.fmt_int_size_bin_exact(datafile_size),
251
- });
252
-
253
- {
254
- const grid_size_limit = datafile_size - vsr.superblock.data_file_size_min;
255
- const blocks_count = vsr.FreeSet.block_count_max(grid_size_limit);
256
- const ewah = vsr.ewah(vsr.FreeSet.Word);
257
-
258
- // 2x since both `blocks_acquired` and `blocks_released` are encoded.
259
- const free_set_encoded_blocks_max = 2 *
260
- vsr.checkpoint_trailer.block_count_for_trailer_size(ewah.encode_size_max(blocks_count));
261
-
262
- const client_sessions_encoded_blocks_max =
263
- vsr.checkpoint_trailer.block_count_for_trailer_size(vsr.ClientSessions.encode_size);
264
-
265
- try print_header(output, 0, "free_set");
266
- const hashmap_entries = stdx.div_ceil(
267
- 100 * (StateMachine.Forest.compaction_blocks_released_per_pipeline_max() +
268
- free_set_encoded_blocks_max + client_sessions_encoded_blocks_max),
269
- std.hash_map.default_max_load_percentage,
270
- );
271
-
272
- try output.print("{:.2}\n", .{std.fmt.fmtIntSizeBin(
273
- // HashMap of block addresses plus two bitsets with bit per block.
274
- hashmap_entries * @sizeOf(u64) + 2 * stdx.div_ceil(blocks_count, 8),
275
- )});
276
- }
277
- }
278
-
279
- fn inspect_metrics(output: std.io.AnyWriter) !void {
280
- const EventMetricTag = std.meta.Tag(EventMetric);
281
- const EventTimingTag = std.meta.Tag(EventTiming);
282
-
283
- const stats_per_gauge = std.meta.fields(EventMetricAggregate).len - 1; // -1 to ignore `event`.
284
- const stats_per_timing = std.meta.fields(std.meta.FieldType(EventTimingAggregate, .values)).len;
285
- var stats_total: usize = 0;
286
-
287
- log.info("Format: [metric type]: [metric name]([metric tags])=[metric cardinality]", .{});
288
-
289
- inline for (std.meta.fields(EventMetric)) |field| {
290
- const metric_tag = std.meta.stringToEnum(EventMetricTag, field.name).?;
291
- try output.print("gauge: {s}(", .{field.name});
292
- if (field.type != void) {
293
- inline for (std.meta.fields(field.type), 0..) |data_field, i| {
294
- if (i != 0) try output.print(", ");
295
- try output.print("{s}", .{data_field.name});
296
- }
297
- }
298
- const metric_stats = EventMetric.slot_limits.get(metric_tag) * stats_per_gauge;
299
- try output.print(")={}\n", .{metric_stats});
300
- stats_total += metric_stats;
301
- }
302
- inline for (std.meta.fields(EventTiming)) |field| {
303
- const timing_tag = std.meta.stringToEnum(EventTimingTag, field.name).?;
304
- try output.print("timing: {s}(", .{field.name});
305
- if (field.type != void) {
306
- inline for (std.meta.fields(field.type), 0..) |data_field, i| {
307
- if (i != 0) try output.print(", ");
308
- try output.print("{s}", .{data_field.name});
309
- }
310
- }
311
- const timing_stats = EventTiming.slot_limits.get(timing_tag) * stats_per_timing;
312
- try output.print(")={}\n", .{timing_stats});
313
- stats_total += timing_stats;
314
- }
315
- log.info("Total stats per replica: {}", .{stats_total});
316
- log.info(
317
- "(All stats are tagged with the replica, so the cluster has 6x as many stats.)",
318
- .{},
319
- );
320
- }
321
-
322
- // Example output:
323
- // checkpoint op trigger prepare_max checkpoint_next
324
- // 624894719 +20 624894739 +12 624894751 +16 624894767 +912 624895679
325
- fn inspect_op(output: std.io.AnyWriter, op: u64) !void {
326
- const checkpoint = if (op < constants.vsr_checkpoint_ops - 1) 0 else checkpoint: {
327
- // op = q * checkpoints_ops - 1 + r
328
- const r = (op + 1) % constants.vsr_checkpoint_ops;
329
- const q = @divExact(op + 1 - r, constants.vsr_checkpoint_ops);
330
- break :checkpoint q * constants.vsr_checkpoint_ops - 1;
331
- };
332
- const checkpoint_next = vsr.Checkpoint.checkpoint_after(checkpoint);
333
-
334
- const points = .{
335
- .checkpoint = checkpoint,
336
- .trigger = vsr.Checkpoint.trigger_for_checkpoint(checkpoint) orelse 0,
337
- .prepare_max = vsr.Checkpoint.prepare_max_for_checkpoint(checkpoint) orelse 0,
338
- .checkpoint_next = checkpoint_next,
339
- .op = op,
340
- };
341
- const Points = @TypeOf(points);
342
-
343
- const Entry = struct {
344
- label: []const u8,
345
- op: u64,
346
- fn less_than(_: void, a: @This(), b: @This()) bool {
347
- return a.op < b.op;
348
- }
349
- };
350
-
351
- var entries: [std.meta.fields(Points).len]Entry = undefined;
352
- inline for (std.meta.fields(Points), 0..) |field, index| {
353
- entries[index] = .{
354
- .label = field.name,
355
- .op = @field(points, field.name),
356
- };
357
- }
358
- std.sort.insertion(Entry, &entries, {}, Entry.less_than);
359
- for (entries) |entry| {
360
- try output.print("{s: <20}", .{entry.label});
361
- }
362
- try output.print("\n", .{});
363
- for (entries[0 .. entries.len - 1], entries[1..]) |entry, entry_next| {
364
- try output.print("{d: <15}", .{entry.op});
365
- try output.print("+{d: <4}", .{entry_next.op - entry.op});
366
- }
367
- try output.print("{d: <20}", .{entries[entries.len - 1].op});
368
- try output.print("\n", .{});
369
- }
370
-
371
- fn print_header(output: std.io.AnyWriter, comptime level: u8, comptime header: []const u8) !void {
372
- const width_total = 32;
373
- const pad_left = " " ** level;
374
- const pad_right = " " ** (width_total -| level * 2 -| header.len);
375
- try output.print(pad_left ++ header ++ pad_right, .{});
376
- }
377
-
378
- fn print_size_count(output: std.io.AnyWriter, comptime size: u64, comptime count: u64) !void {
379
- if (count == 1) {
380
- try output.print("{}\n", .{stdx.fmt_int_size_bin_exact(size)});
381
- } else {
382
- const size_formatted = comptime if (size < 1024)
383
- std.fmt.comptimePrint("{}B", .{size})
384
- else
385
- std.fmt.comptimePrint("{}", .{stdx.fmt_int_size_bin_exact(size)});
386
- try output.print("{s<8} x{}\n", .{ size_formatted, count });
387
- }
388
- }
389
-
390
- fn print_objects(output: std.io.AnyWriter) !void {
391
- const Grooves = StateMachine.Forest.Grooves;
392
- inline for (std.meta.fields(Grooves)) |groove_field| {
393
- const Groove = groove_field.type;
394
- const ObjectTree = Groove.ObjectTree;
395
-
396
- comptime var size_total: usize = 0;
397
-
398
- const object_size = @sizeOf(ObjectTree.Table.Value);
399
- size_total += object_size;
400
-
401
- const id_size = if (Groove.IdTree == void) 0 else @sizeOf(Groove.IdTree.Table.Value);
402
- size_total += id_size;
403
-
404
- comptime {
405
- for (std.meta.fields(Groove.IndexTrees)) |index_field| {
406
- const IndexTree = index_field.type;
407
- const index_size = @sizeOf(IndexTree.Table.Value);
408
- size_total += index_size;
409
- }
410
- }
411
-
412
- try print_header(output, 0, ObjectTree.tree_name());
413
- try print_size_count(output, size_total, 1);
414
-
415
- try print_header(output, 1, "object");
416
- try print_size_count(output, object_size, 1);
417
-
418
- try print_header(output, 1, "id");
419
- try print_size_count(output, id_size, 1);
420
-
421
- inline for (std.meta.fields(Groove.IndexTrees)) |index_field| {
422
- const IndexTree = index_field.type;
423
- const index_size = @sizeOf(IndexTree.Table.Value);
424
-
425
- try print_header(output, 1, index_field.name);
426
- try print_size_count(output, index_size, 1);
427
- }
428
-
429
- try output.print("\n", .{});
430
- }
431
- }
432
-
433
- const Inspector = struct {
434
- allocator: std.mem.Allocator,
435
- io: *IO,
436
- storage: Storage,
437
-
438
- superblock_buffer: []align(constants.sector_size) u8,
439
- superblock_headers: [constants.superblock_copies]*const SuperBlockHeader,
440
-
441
- busy: bool = false,
442
- read: Storage.Read = undefined,
443
-
444
- fn create(
445
- allocator: std.mem.Allocator,
446
- io: *IO,
447
- tracer: *Tracer,
448
- path: []const u8,
449
- ) !*Inspector {
450
- var inspector = try allocator.create(Inspector);
451
- errdefer allocator.destroy(inspector);
452
-
453
- inspector.* = .{
454
- .allocator = allocator,
455
- .io = io,
456
- .storage = undefined,
457
- .superblock_buffer = undefined,
458
- .superblock_headers = undefined,
459
- };
460
-
461
- inspector.storage = try Storage.init(io, tracer, .{
462
- .path = path,
463
- .size_min = vsr.superblock.data_file_size_min,
464
- .purpose = .inspect,
465
- .direct_io = .direct_io_optional,
466
- });
467
- errdefer inspector.storage.deinit();
468
-
469
- inspector.superblock_buffer = try allocator.alignedAlloc(
470
- u8,
471
- constants.sector_size,
472
- vsr.superblock.superblock_zone_size,
473
- );
474
- errdefer allocator.free(inspector.superblock_buffer);
475
-
476
- try inspector.read_buffer(inspector.superblock_buffer, .superblock, 0);
477
-
478
- for (&inspector.superblock_headers, 0..) |*superblock_header, copy| {
479
- const offset = @as(u64, copy) * vsr.superblock.superblock_copy_size;
480
- superblock_header.* = @alignCast(std.mem.bytesAsValue(
481
- SuperBlockHeader,
482
- inspector.superblock_buffer[offset..][0..@sizeOf(SuperBlockHeader)],
483
- ));
484
- }
485
-
486
- const superblock = try inspector.read_superblock(null);
487
- if (superblock.version != SuperBlockVersion) {
488
- return vsr.fatal(
489
- .cli,
490
- "invalid superblock version; inspector supports version={}, version in {s}={}",
491
- .{
492
- SuperBlockVersion,
493
- path,
494
- superblock.version,
495
- },
496
- );
497
- }
498
- return inspector;
499
- }
500
-
501
- fn destroy(inspector: *Inspector) void {
502
- inspector.allocator.free(inspector.superblock_buffer);
503
- inspector.storage.deinit();
504
- inspector.allocator.destroy(inspector);
505
- }
506
-
507
- fn work(inspector: *Inspector) !void {
508
- assert(!inspector.busy);
509
- inspector.busy = true;
510
-
511
- while (inspector.busy) {
512
- try inspector.io.run_for_ns(constants.tick_ms * std.time.ns_per_ms);
513
- }
514
- }
515
-
516
- fn inspector_read_callback(read: *Storage.Read) void {
517
- const inspector: *Inspector = @alignCast(@fieldParentPtr("read", read));
518
- assert(inspector.busy);
519
-
520
- inspector.busy = false;
521
- }
522
-
523
- fn inspect_superblock(inspector: *Inspector, output: std.io.AnyWriter) !void {
524
- log.info("In the left column of the output, \"|\" denotes which copies have a " ++
525
- "particular value.", .{});
526
- log.info("\"||||\" means that all four superblock copies are in agreement.", .{});
527
- log.info("\"|_|_\" means that the value matches in copies 0/2, but differs from copies " ++
528
- "1/3.", .{});
529
-
530
- var header_valid: [constants.superblock_copies]bool = undefined;
531
- for (&inspector.superblock_headers, 0..) |header, i| {
532
- header_valid[i] = header.valid_checksum();
533
- }
534
-
535
- inline for (std.meta.fields(SuperBlockHeader)) |field| {
536
- var group_by = GroupByType(constants.superblock_copies){};
537
- for (inspector.superblock_headers) |header| {
538
- group_by.compare(std.mem.asBytes(&@field(header, field.name)));
539
- }
540
-
541
- var label_buffer: [128]u8 = undefined;
542
- for (group_by.groups()) |group| {
543
- const header_index = group.first_set().?;
544
- const header = &inspector.superblock_headers[header_index];
545
- const header_mark: u8 = if (header_valid[header_index]) '|' else 'X';
546
-
547
- var label_stream = std.io.fixedBufferStream(&label_buffer);
548
- for (0..constants.superblock_copies) |j| {
549
- try label_stream.writer().writeByte(if (group.is_set(j)) header_mark else '_');
550
- }
551
- try label_stream.writer().writeByte(' ');
552
- try label_stream.writer().writeAll(field.name);
553
-
554
- try print_struct(output, label_stream.getWritten(), &@field(header.*, field.name));
555
- }
556
- }
557
- }
558
-
559
- fn inspect_wal(inspector: *Inspector, output: std.io.AnyWriter) !void {
560
- log.info("In the left column of the output, \"|\" denotes which set of headers has " ++
561
- "each value.", .{});
562
- log.info("\"||\" denotes that the prepare and the redundant header match.", .{});
563
- log.info("\"|_\" is the redundant header.", .{});
564
- log.info("\"_|\" is the prepare's header.", .{});
565
-
566
- const headers_buffer = try inspector.allocator.alignedAlloc(
567
- u8,
568
- constants.sector_size,
569
- constants.journal_size_headers,
570
- );
571
- defer inspector.allocator.free(headers_buffer);
572
-
573
- const prepare_buffer = try inspector.allocator.alignedAlloc(
574
- u8,
575
- constants.sector_size,
576
- constants.message_size_max,
577
- );
578
- defer inspector.allocator.free(prepare_buffer);
579
-
580
- try inspector.read_buffer(headers_buffer, .wal_headers, 0);
581
-
582
- for (std.mem.bytesAsSlice(vsr.Header.Prepare, headers_buffer), 0..) |*wal_header, slot| {
583
- const offset = slot * constants.message_size_max;
584
- try inspector.read_buffer(prepare_buffer, .wal_prepares, offset);
585
-
586
- const wal_prepare = std.mem.bytesAsValue(
587
- vsr.Header.Prepare,
588
- prepare_buffer[0..@sizeOf(vsr.Header)],
589
- );
590
-
591
- const wal_prepare_body_valid =
592
- wal_prepare.valid_checksum() and
593
- wal_prepare.valid_checksum_body(
594
- prepare_buffer[@sizeOf(vsr.Header)..wal_prepare.size],
595
- );
596
-
597
- const header_pair = [_]*const vsr.Header.Prepare{ wal_header, wal_prepare };
598
-
599
- var group_by = GroupByType(2){};
600
- group_by.compare(std.mem.asBytes(wal_header));
601
- group_by.compare(std.mem.asBytes(wal_prepare));
602
-
603
- var label_buffer: [64]u8 = undefined;
604
- for (group_by.groups()) |group| {
605
- const header = header_pair[group.first_set().?];
606
- const header_valid = header.valid_checksum() and
607
- (!group.is_set(1) or wal_prepare_body_valid);
608
-
609
- const mark: u8 = if (header_valid) '|' else 'X';
610
- var label_stream = std.io.fixedBufferStream(&label_buffer);
611
- try label_stream.writer().writeByte(if (group.is_set(0)) mark else '_');
612
- try label_stream.writer().writeByte(if (group.is_set(1)) mark else '_');
613
- try label_stream.writer().print("{:_>4}: ", .{slot});
614
-
615
- try print_struct(output, label_stream.getWritten(), &.{
616
- "checksum=", header.checksum,
617
- "release=", header.release,
618
- "view=", header.view,
619
- "op=", header.op,
620
- "size=", header.size,
621
- "operation=", header.operation,
622
- });
623
- }
624
- }
625
- }
626
-
627
- fn inspect_wal_slot(inspector: *Inspector, output: std.io.AnyWriter, slot: usize) !void {
628
- assert(slot <= constants.journal_slot_count);
629
-
630
- const headers_buffer = try inspector.allocator.alignedAlloc(
631
- u8,
632
- constants.sector_size,
633
- constants.journal_size_headers,
634
- );
635
- defer inspector.allocator.free(headers_buffer);
636
-
637
- const prepare_buffer = try inspector.allocator.alignedAlloc(
638
- u8,
639
- constants.sector_size,
640
- constants.message_size_max,
641
- );
642
- defer inspector.allocator.free(prepare_buffer);
643
-
644
- try inspector.read_buffer(headers_buffer, .wal_headers, 0);
645
- try inspector.read_buffer(prepare_buffer, .wal_prepares, slot * constants.message_size_max);
646
-
647
- const headers = std.mem.bytesAsSlice(vsr.Header.Prepare, headers_buffer);
648
- const prepare_header =
649
- std.mem.bytesAsValue(vsr.Header.Prepare, prepare_buffer[0..@sizeOf(vsr.Header)]);
650
-
651
- const prepare_body_valid =
652
- prepare_header.valid_checksum() and
653
- prepare_header.valid_checksum_body(
654
- prepare_buffer[@sizeOf(vsr.Header)..prepare_header.size],
655
- );
656
-
657
- const copies: [2]*const vsr.Header.Prepare = .{ &headers[slot], prepare_header };
658
-
659
- var group_by = GroupByType(2){};
660
- for (copies) |h| group_by.compare(std.mem.asBytes(h));
661
-
662
- var label_buffer: [2]u8 = undefined;
663
- for (group_by.groups()) |group| {
664
- const header = copies[group.first_set().?];
665
- const header_mark: u8 = if (header.valid_checksum()) '|' else 'X';
666
- label_buffer[0] = if (group.is_set(0)) header_mark else '_';
667
- label_buffer[1] = if (group.is_set(1)) header_mark else '_';
668
-
669
- try print_struct(output, &label_buffer, header);
670
- }
671
- try print_prepare_body(output, prepare_buffer);
672
-
673
- if (!prepare_body_valid) {
674
- try output.writeAll("error: invalid prepare body!\n");
675
- }
676
- }
677
-
678
- fn inspect_replies(
679
- inspector: *Inspector,
680
- output: std.io.AnyWriter,
681
- superblock_copy: ?u8,
682
- ) !void {
683
- const entries_block = try allocate_block(inspector.allocator);
684
- defer inspector.allocator.free(entries_block);
685
-
686
- const reply_sector =
687
- try inspector.allocator.alignedAlloc(u8, constants.sector_size, constants.sector_size);
688
- defer inspector.allocator.free(reply_sector);
689
-
690
- const entries =
691
- try inspector.read_client_sessions(entries_block, superblock_copy) orelse return;
692
-
693
- var label_buffer: [64]u8 = undefined;
694
- for (&entries.headers, &entries.sessions, 0..) |*session_header, session, slot| {
695
- try inspector.read_buffer(
696
- reply_sector,
697
- .client_replies,
698
- constants.message_size_max * slot,
699
- );
700
-
701
- const reply_header =
702
- std.mem.bytesAsValue(vsr.Header.Reply, reply_sector[0..@sizeOf(vsr.Header)]);
703
- const copies: [2]*const vsr.Header.Reply = .{ session_header, reply_header };
704
- var group_by = GroupByType(2){};
705
- for (copies) |h| group_by.compare(std.mem.asBytes(h));
706
-
707
- // The session doesn't include the group diff labels since it is only stored in the
708
- // client sessions, not the replies.
709
- try output.print("{:_>2} session={}\n", .{ slot, session });
710
-
711
- for (group_by.groups()) |group| {
712
- const header_index = group.first_set().?;
713
- const header = copies[header_index];
714
- const header_mark: u8 = if (header.valid_checksum()) '|' else 'X';
715
-
716
- var label_stream = std.io.fixedBufferStream(&label_buffer);
717
- try label_stream.writer().print("{:_>2}: ", .{slot});
718
- try label_stream.writer().writeByte(if (group.is_set(0)) header_mark else '_');
719
- try label_stream.writer().writeByte(if (group.is_set(1)) header_mark else '_');
720
- try label_stream.writer().writeAll(" header");
721
- try print_struct(output, label_stream.getWritten(), header);
722
- }
723
- }
724
- }
725
-
726
- fn inspect_replies_slot(
727
- inspector: *Inspector,
728
- output: std.io.AnyWriter,
729
- superblock_copy: ?u8,
730
- slot: usize,
731
- ) !void {
732
- assert(slot < constants.clients_max);
733
-
734
- const block = try allocate_block(inspector.allocator);
735
- defer inspector.allocator.free(block);
736
-
737
- const reply = try inspector.allocator.alignedAlloc(
738
- u8,
739
- constants.sector_size,
740
- constants.message_size_max,
741
- );
742
- defer inspector.allocator.free(reply);
743
-
744
- log.info("\"||\" denotes that the client session header and reply header match.", .{});
745
- log.info("\"|_\" is the client session header.", .{});
746
- log.info("\"_|\" is the client reply's header.", .{});
747
-
748
- const entries = try inspector.read_client_sessions(block, superblock_copy) orelse {
749
- try output.writeAll("error: no client sessions\n");
750
- return;
751
- };
752
-
753
- try inspector.read_buffer(
754
- reply,
755
- .client_replies,
756
- constants.message_size_max * slot,
757
- );
758
-
759
- const reply_header = std.mem.bytesAsValue(vsr.Header.Reply, reply[0..@sizeOf(vsr.Header)]);
760
- const copies: [2]*const vsr.Header.Reply = .{ &entries.headers[slot], reply_header };
761
- var group_by = GroupByType(2){};
762
- for (copies) |h| group_by.compare(std.mem.asBytes(h));
763
-
764
- var label_buffer: [2]u8 = undefined;
765
- for (group_by.groups()) |group| {
766
- const header = copies[group.first_set().?];
767
- const header_mark: u8 = if (header.valid_checksum()) '|' else 'X';
768
- label_buffer[0] = if (group.is_set(0)) header_mark else '_';
769
- label_buffer[1] = if (group.is_set(1)) header_mark else '_';
770
-
771
- try print_struct(output, &label_buffer, header);
772
- }
773
- try print_reply_body(output, reply);
774
- }
775
-
776
- fn inspect_grid(inspector: *Inspector, output: std.io.AnyWriter, superblock_copy: ?u8) !void {
777
- const superblock = try inspector.read_superblock(superblock_copy);
778
-
779
- const free_set_blocks_acquired_size =
780
- superblock.vsr_state.checkpoint.free_set_blocks_acquired_size;
781
- const free_set_blocks_released_size =
782
- superblock.vsr_state.checkpoint.free_set_blocks_released_size;
783
-
784
- const free_set_blocks_acquired_buffer =
785
- try inspector.allocator.alignedAlloc(
786
- u8,
787
- @alignOf(vsr.FreeSet.Word),
788
- free_set_blocks_acquired_size,
789
- );
790
- defer inspector.allocator.free(free_set_blocks_acquired_buffer);
791
-
792
- var free_set_blocks_acquired_addresses =
793
- try std.ArrayList(u64).initCapacity(
794
- inspector.allocator,
795
- stdx.div_ceil(
796
- free_set_blocks_acquired_size,
797
- constants.block_size - @sizeOf(vsr.Header),
798
- ),
799
- );
800
- defer free_set_blocks_acquired_addresses.deinit();
801
-
802
- const free_set_blocks_released_buffer =
803
- try inspector.allocator.alignedAlloc(
804
- u8,
805
- @alignOf(vsr.FreeSet.Word),
806
- free_set_blocks_released_size,
807
- );
808
- defer inspector.allocator.free(free_set_blocks_released_buffer);
809
-
810
- var free_set_blocks_released_addresses =
811
- try std.ArrayList(u64).initCapacity(
812
- inspector.allocator,
813
- stdx.div_ceil(
814
- free_set_blocks_released_size,
815
- constants.block_size - @sizeOf(vsr.Header),
816
- ),
817
- );
818
- defer free_set_blocks_released_addresses.deinit();
819
-
820
- try inspector.read_free_set_bitset(
821
- output,
822
- superblock,
823
- .blocks_acquired,
824
- free_set_blocks_acquired_buffer,
825
- &free_set_blocks_acquired_addresses,
826
- );
827
- try inspector.read_free_set_bitset(
828
- output,
829
- superblock,
830
- .blocks_released,
831
- free_set_blocks_released_buffer,
832
- &free_set_blocks_released_addresses,
833
- );
834
-
835
- // This is not exact, but is an overestimate:
836
- const grid_blocks_max =
837
- @divFloor(constants.storage_size_limit_max, constants.block_size);
838
-
839
- var free_set = try vsr.FreeSet.init(
840
- inspector.allocator,
841
- .{
842
- .grid_size_limit = grid_blocks_max * constants.block_size,
843
- .blocks_released_prior_checkpoint_durability_max = 0,
844
- },
845
- );
846
- defer free_set.deinit(inspector.allocator);
847
-
848
- const SliceOfAlignedWordSlice = []const []align(@alignOf(vsr.FreeSet.Word)) const u8;
849
- const encoded_free_set_blocks_acquired: SliceOfAlignedWordSlice =
850
- if (free_set_blocks_acquired_buffer.len != 0)
851
- &.{free_set_blocks_acquired_buffer}
852
- else
853
- &.{};
854
- const encoded_free_set_blocks_released: SliceOfAlignedWordSlice =
855
- if (free_set_blocks_released_buffer.len != 0)
856
- &.{free_set_blocks_released_buffer}
857
- else
858
- &.{};
859
-
860
- free_set.open(.{
861
- .encoded = .{
862
- .blocks_acquired = encoded_free_set_blocks_acquired,
863
- .blocks_released = encoded_free_set_blocks_released,
864
- },
865
- .free_set_block_addresses = .{
866
- .blocks_acquired = free_set_blocks_acquired_addresses.items,
867
- .blocks_released = free_set_blocks_released_addresses.items,
868
- },
869
- });
870
-
871
- const free_set_acquired_address_max = free_set.highest_address_acquired() orelse 0;
872
- const free_set_blocks_acquired_compression_ratio =
873
- @as(f64, @floatFromInt(stdx.div_ceil(free_set_acquired_address_max, 8))) /
874
- @as(f64, @floatFromInt(superblock.vsr_state.checkpoint.free_set_blocks_acquired_size));
875
-
876
- const free_set_released_address_max = free_set.highest_address_released() orelse 0;
877
- const free_set_blocks_released_compression_ratio =
878
- @as(f64, @floatFromInt(stdx.div_ceil(free_set_released_address_max, 8))) /
879
- @as(f64, @floatFromInt(superblock.vsr_state.checkpoint.free_set_blocks_released_size));
880
-
881
- try output.print(
882
- \\free_set.blocks_free={}
883
- \\free_set.blocks_acquired={}
884
- \\free_set.blocks_released={}
885
- \\free_set.highest_address_acquired={?}
886
- \\free_set.acquired_size={}
887
- \\free_set.acquired_compression_ratio={d:0.4}
888
- \\free_set.highest_address_released={?}
889
- \\free_set.released_size={}
890
- \\free_set.released_compression_ratio={d:0.4}
891
- \\
892
- ,
893
- .{
894
- free_set.count_free(),
895
- free_set.count_acquired(),
896
- free_set.count_released(),
897
- free_set.highest_address_acquired(),
898
- std.fmt.fmtIntSizeBin(superblock.vsr_state.checkpoint
899
- .free_set_blocks_acquired_size),
900
- free_set_blocks_acquired_compression_ratio,
901
- free_set.highest_address_released(),
902
- std.fmt.fmtIntSizeBin(superblock.vsr_state.checkpoint
903
- .free_set_blocks_released_size),
904
- free_set_blocks_released_compression_ratio,
905
- },
906
- );
907
- }
908
-
909
- fn inspect_grid_block(inspector: *Inspector, output: std.io.AnyWriter, address: u64) !void {
910
- const block = try allocate_block(inspector.allocator);
911
- defer inspector.allocator.free(block);
912
-
913
- try inspector.read_block(block, address, null);
914
-
915
- // If this is an unexpected (but valid) block, log an error but keep going.
916
- const header = schema.header_from_block(block);
917
- if (header.address != address) log.err("misdirected block", .{});
918
-
919
- try print_block(output, block);
920
- }
921
-
922
- fn inspect_manifest(
923
- inspector: *Inspector,
924
- output: std.io.AnyWriter,
925
- superblock_copy: ?u8,
926
- ) !void {
927
- const superblock = try inspector.read_superblock(superblock_copy);
928
-
929
- const block = try allocate_block(inspector.allocator);
930
- defer inspector.allocator.free(block);
931
-
932
- var manifest_block_address = superblock.vsr_state.checkpoint.manifest_newest_address;
933
- var manifest_block_checksum = superblock.vsr_state.checkpoint.manifest_newest_checksum;
934
- for (0..superblock.vsr_state.checkpoint.manifest_block_count) |i| {
935
- try output.print(
936
- "manifest_log.blocks[{}]: address={} checksum={x:0>32} ",
937
- .{ i, manifest_block_address, manifest_block_checksum },
938
- );
939
-
940
- inspector.read_block(
941
- block,
942
- manifest_block_address,
943
- manifest_block_checksum,
944
- ) catch {
945
- try output.writeAll("error: manifest block not found\n");
946
- break;
947
- };
948
-
949
- var entry_counts = std.enums.EnumArray(
950
- schema.ManifestNode.Event,
951
- [constants.lsm_levels]usize,
952
- ).initDefault([_]usize{0} ** constants.lsm_levels, .{});
953
-
954
- const manifest_node = schema.ManifestNode.from(block);
955
- for (manifest_node.tables_const(block)) |*table_info| {
956
- entry_counts.getPtr(table_info.label.event)[table_info.label.level] += 1;
957
- }
958
-
959
- try output.print(
960
- "entries={}/{}",
961
- .{ manifest_node.entry_count, schema.ManifestNode.entry_count_max },
962
- );
963
-
964
- for (std.enums.values(schema.ManifestNode.Event)) |event| {
965
- if (event == .reserved) continue;
966
- try output.print(" {s}=", .{@tagName(event)});
967
- for (0..constants.lsm_levels) |level| {
968
- if (level != 0) try output.writeAll(",");
969
- try output.print("{}", .{entry_counts.get(event)[level]});
970
- }
971
- }
972
- try output.writeAll("\n");
973
-
974
- const manifest_metadata = schema.ManifestNode.metadata(block);
975
- manifest_block_address = manifest_metadata.previous_manifest_block_address;
976
- manifest_block_checksum = manifest_metadata.previous_manifest_block_checksum;
977
- }
978
- }
979
-
980
- fn inspect_tables(
981
- inspector: *Inspector,
982
- output: std.io.AnyWriter,
983
- superblock_copy: ?u8,
984
- filter: struct { tree_id: u16, level: ?u6 },
985
- ) !void {
986
- var tables_latest =
987
- std.AutoHashMap(u128, ?schema.ManifestNode.TableInfo).init(inspector.allocator);
988
- defer tables_latest.deinit();
989
-
990
- const block = try allocate_block(inspector.allocator);
991
- defer inspector.allocator.free(block);
992
-
993
- // Construct a set of all active tables.
994
- const superblock = try inspector.read_superblock(superblock_copy);
995
- var manifest_block_address = superblock.vsr_state.checkpoint.manifest_newest_address;
996
- var manifest_block_checksum = superblock.vsr_state.checkpoint.manifest_newest_checksum;
997
- for (0..superblock.vsr_state.checkpoint.manifest_block_count) |_| {
998
- try inspector.read_block(block, manifest_block_address, manifest_block_checksum);
999
-
1000
- const manifest_node = schema.ManifestNode.from(block);
1001
- const tables = manifest_node.tables_const(block);
1002
- for (0..tables.len) |i| {
1003
- const table_info = &tables[tables.len - i - 1];
1004
- const table_latest = try tables_latest.getOrPut(table_info.checksum);
1005
- if (!table_latest.found_existing) {
1006
- if (table_info.label.event == .remove) {
1007
- table_latest.value_ptr.* = null;
1008
- } else {
1009
- table_latest.value_ptr.* = table_info.*;
1010
- }
1011
- }
1012
- }
1013
-
1014
- const manifest_metadata = schema.ManifestNode.metadata(block);
1015
- manifest_block_address = manifest_metadata.previous_manifest_block_address;
1016
- manifest_block_checksum = manifest_metadata.previous_manifest_block_checksum;
1017
- }
1018
-
1019
- var tables_filtered =
1020
- std.ArrayList(schema.ManifestNode.TableInfo).init(inspector.allocator);
1021
- defer tables_filtered.deinit();
1022
-
1023
- // Construct a list of only the tables matching the `filter`.
1024
- var tables_latest_iterator = tables_latest.iterator();
1025
- while (tables_latest_iterator.next()) |table_or_null| {
1026
- const table = table_or_null.value_ptr.* orelse continue;
1027
- if (table.tree_id != filter.tree_id) continue;
1028
- if (filter.level) |level| {
1029
- if (table.label.level != level) continue;
1030
- }
1031
- try tables_filtered.append(table);
1032
- }
1033
-
1034
- // Order the tables in a predictable way, since the manifest log can shuffle them around.
1035
- std.mem.sortUnstable(schema.ManifestNode.TableInfo, tables_filtered.items, {}, struct {
1036
- fn less_than(
1037
- _: void,
1038
- table_a: schema.ManifestNode.TableInfo,
1039
- table_b: schema.ManifestNode.TableInfo,
1040
- ) bool {
1041
- for ([_]std.math.Order{
1042
- std.math.order(table_a.tree_id, table_b.tree_id),
1043
- std.math.order(table_a.label.level, table_b.label.level),
1044
- std.math.order(
1045
- std.mem.bytesAsValue(u256, &table_a.key_min).*,
1046
- std.mem.bytesAsValue(u256, &table_b.key_min).*,
1047
- ),
1048
- std.math.order(
1049
- std.mem.bytesAsValue(u256, &table_a.key_max).*,
1050
- std.mem.bytesAsValue(u256, &table_b.key_max).*,
1051
- ),
1052
- std.math.order(table_a.snapshot_min, table_b.snapshot_min),
1053
- std.math.order(table_a.snapshot_max, table_b.snapshot_max),
1054
- std.math.order(table_a.checksum, table_b.checksum),
1055
- }) |order| {
1056
- if (order != .eq) return order == .lt;
1057
- }
1058
- // This *should* be unreachable, especially given the checksum comparison.
1059
- return false;
1060
- }
1061
- }.less_than);
1062
-
1063
- inline for (StateMachine.Forest.tree_infos) |tree_info| {
1064
- if (tree_info.tree_id == filter.tree_id) {
1065
- for (tables_filtered.items) |*table| {
1066
- try print_table_info(output, tree_info, table);
1067
- }
1068
- break;
1069
- }
1070
- } else {
1071
- try output.print("error: unknown tree_id={}\n", .{filter.tree_id});
1072
- }
1073
- }
1074
-
1075
- fn read_buffer(
1076
- inspector: *Inspector,
1077
- buffer: []align(constants.sector_size) u8,
1078
- zone: vsr.Zone,
1079
- offset_in_zone: u64,
1080
- ) !void {
1081
- inspector.storage.read_sectors(
1082
- inspector_read_callback,
1083
- &inspector.read,
1084
- buffer,
1085
- zone,
1086
- offset_in_zone,
1087
- );
1088
- try inspector.work();
1089
- }
1090
-
1091
- fn read_superblock(inspector: *const Inspector, superblock_copy: ?u8) !*const SuperBlockHeader {
1092
- if (superblock_copy) |copy| {
1093
- return inspector.superblock_headers[copy];
1094
- } else {
1095
- var copies: [constants.superblock_copies]SuperBlockHeader = undefined;
1096
- for (&copies, inspector.superblock_headers) |*copy, header| copy.* = header.*;
1097
-
1098
- var quorums = SuperBlockQuorums{};
1099
- const quorum = try quorums.working(&copies, .open);
1100
- if (!quorum.valid) return error.SuperBlockQuorumInvalid;
1101
- return inspector.superblock_headers[quorum.copies.first_set().?];
1102
- }
1103
- }
1104
-
1105
- fn read_block(
1106
- inspector: *Inspector,
1107
- buffer: BlockPtr,
1108
- address: u64,
1109
- checksum: ?u128,
1110
- ) !void {
1111
- try inspector.read_buffer(buffer, .grid, (address - 1) * constants.block_size);
1112
-
1113
- const header = std.mem.bytesAsValue(vsr.Header.Block, buffer[0..@sizeOf(vsr.Header)]);
1114
- if (!header.valid_checksum()) {
1115
- log.err(
1116
- "read_block: invalid block address={} checksum_expect={?x:0>32} " ++
1117
- "checksum_actual={x:0>32} (bad checksum)",
1118
- .{ address, checksum, header.checksum },
1119
- );
1120
- return error.InvalidChecksum;
1121
- }
1122
-
1123
- if (!header.valid_checksum_body(buffer[@sizeOf(vsr.Header)..header.size])) {
1124
- log.err(
1125
- "read_block: invalid block address={} checksum_expect={?x:0>32} " ++
1126
- "checksum_actual={x:0>32} (bad checksum_body)",
1127
- .{ address, checksum, header.checksum },
1128
- );
1129
- return error.InvalidChecksumBody;
1130
- }
1131
-
1132
- if (checksum) |checksum_| {
1133
- if (header.checksum != checksum_) {
1134
- log.err(
1135
- "read_block: invalid block address={} checksum_expect={?x:0>32} " ++
1136
- "checksum_actual={x:0>32} (wrong block)",
1137
- .{ address, checksum, header.checksum },
1138
- );
1139
- return error.WrongBlock;
1140
- }
1141
- }
1142
- }
1143
-
1144
- fn read_free_set_bitset(
1145
- inspector: *Inspector,
1146
- output: std.io.AnyWriter,
1147
- superblock: *const SuperBlockHeader,
1148
- bitset: vsr.FreeSet.BitsetKind,
1149
- free_set_buffer: []align(@alignOf(vsr.FreeSet.Word)) u8,
1150
- free_set_addresses: *std.ArrayList(u64),
1151
- ) !void {
1152
- const block = try allocate_block(inspector.allocator);
1153
- defer inspector.allocator.free(block);
1154
-
1155
- const free_set_reference = superblock.free_set_reference(bitset);
1156
- const free_set_size = free_set_reference.trailer_size;
1157
- const free_set_checksum = free_set_reference.checksum;
1158
-
1159
- const free_set_block_count = stdx.div_ceil(
1160
- free_set_size,
1161
- constants.block_size - @sizeOf(vsr.Header),
1162
- );
1163
-
1164
- var free_set_block_references = try std.ArrayList(vsr.BlockReference).initCapacity(
1165
- inspector.allocator,
1166
- free_set_block_count,
1167
- );
1168
- defer free_set_block_references.deinit();
1169
-
1170
- if (free_set_size > 0) {
1171
- // Read free set from the grid by manually following the linked list of blocks.
1172
- // Note that free set is written in direct order, and must be read backwards.
1173
- var free_set_block_reference: ?vsr.BlockReference = .{
1174
- .address = free_set_reference.last_block_address,
1175
- .checksum = free_set_reference.last_block_checksum,
1176
- };
1177
-
1178
- var free_set_cursor: usize = free_set_size;
1179
- while (free_set_block_reference) |block_reference| {
1180
- try inspector.read_block(
1181
- block,
1182
- block_reference.address,
1183
- block_reference.checksum,
1184
- );
1185
-
1186
- assert(schema.header_from_block(block).checksum == block_reference.checksum);
1187
-
1188
- const encoded_words = schema.TrailerNode.body(block);
1189
- free_set_cursor -= encoded_words.len;
1190
- stdx.copy_disjoint(
1191
- .inexact,
1192
- u8,
1193
- free_set_buffer[free_set_cursor..],
1194
- encoded_words,
1195
- );
1196
- free_set_block_references.appendAssumeCapacity(block_reference);
1197
- free_set_addresses.appendAssumeCapacity(block_reference.address);
1198
- free_set_block_reference = schema.TrailerNode.previous(block);
1199
- }
1200
- assert(free_set_block_reference == null);
1201
- assert(free_set_cursor == 0);
1202
- } else {
1203
- assert(free_set_reference.last_block_address == 0);
1204
- assert(free_set_reference.last_block_checksum == 0);
1205
- }
1206
-
1207
- assert(free_set_block_references.items.len == free_set_block_count);
1208
- assert(free_set_addresses.items.len == free_set_block_count);
1209
- assert(vsr.checksum(free_set_buffer[0..free_set_size]) == free_set_checksum);
1210
-
1211
- for (free_set_block_references.items, 0..) |reference, i| {
1212
- try output.print(
1213
- "free_set_trailer.blocks[{}]: address={} checksum={x:0>32}\n",
1214
- .{ i, reference.address, reference.checksum },
1215
- );
1216
- }
1217
- }
1218
-
1219
- const ClientSessions = extern struct {
1220
- headers: [constants.clients_max]vsr.Header.Reply,
1221
- sessions: [constants.clients_max]u64,
1222
- };
1223
-
1224
- fn read_client_sessions(
1225
- inspector: *Inspector,
1226
- block: BlockPtr,
1227
- superblock_copy: ?u8,
1228
- ) !?*ClientSessions {
1229
- const superblock = try inspector.read_superblock(superblock_copy);
1230
-
1231
- if (superblock.vsr_state.checkpoint.client_sessions_size == 0) {
1232
- assert(superblock.vsr_state.checkpoint.client_sessions_last_block_address == 0);
1233
- assert(superblock.vsr_state.checkpoint.client_sessions_last_block_checksum == 0);
1234
- return null;
1235
- }
1236
- assert(superblock.vsr_state.checkpoint.client_sessions_size == @sizeOf(ClientSessions));
1237
-
1238
- try inspector.read_block(
1239
- block,
1240
- superblock.vsr_state.checkpoint.client_sessions_last_block_address,
1241
- superblock.vsr_state.checkpoint.client_sessions_last_block_checksum,
1242
- );
1243
-
1244
- const block_header = schema.header_from_block(block);
1245
- assert(block_header.size == @sizeOf(vsr.Header) + @sizeOf(ClientSessions));
1246
- assert(vsr.checksum(block[@sizeOf(vsr.Header)..block_header.size]) ==
1247
- superblock.vsr_state.checkpoint.client_sessions_checksum);
1248
-
1249
- return std.mem.bytesAsValue(
1250
- ClientSessions,
1251
- block[@sizeOf(vsr.Header)..][0..@sizeOf(ClientSessions)],
1252
- );
1253
- }
1254
- };
1255
-
1256
- fn print_struct(
1257
- output: std.io.AnyWriter,
1258
- label: []const u8,
1259
- value: anytype,
1260
- ) !void {
1261
- comptime assert(@typeInfo(@TypeOf(value)) == .pointer);
1262
- comptime assert(@typeInfo(@TypeOf(value)).pointer.size == .one);
1263
-
1264
- const Type = @typeInfo(@TypeOf(value)).pointer.child;
1265
- // Print structs *without* a custom format() function.
1266
- if (comptime @typeInfo(Type) == .@"struct" and !std.meta.hasFn(Type, "format")) {
1267
- if (@typeInfo(Type).@"struct".is_tuple) {
1268
- try output.writeAll(label);
1269
- // Print tuples as a single line.
1270
- inline for (std.meta.fields(Type), 0..) |field, i| {
1271
- if (@typeInfo(field.type) == .pointer and
1272
- @typeInfo(@typeInfo(field.type).pointer.child) == .array)
1273
- {
1274
- // Allow inline labels.
1275
- try output.writeAll(@field(value, field.name));
1276
- } else {
1277
- try print_value(output, @field(value, field.name));
1278
- if (i != std.meta.fields(Type).len) try output.writeAll(" ");
1279
- }
1280
- }
1281
- try output.writeAll("\n");
1282
- return;
1283
- } else {
1284
- var label_buffer: [1024]u8 = undefined;
1285
- inline for (std.meta.fields(Type)) |field| {
1286
- var label_stream = std.io.fixedBufferStream(&label_buffer);
1287
- try label_stream.writer().print("{s}.{s}", .{ label, field.name });
1288
- try print_struct(output, label_stream.getWritten(), &@field(value, field.name));
1289
- }
1290
- return;
1291
- }
1292
- }
1293
-
1294
- if (Element: {
1295
- const type_info = @typeInfo(Type);
1296
- if (type_info == .array) {
1297
- break :Element @as(?type, type_info.array.child);
1298
- }
1299
- break :Element null;
1300
- }) |Element| {
1301
- if (Element == u8) {
1302
- if (stdx.zeroed(value)) {
1303
- return output.print("{s}=[{}]u8{{0}}\n", .{ label, value.len });
1304
- } else {
1305
- return output.print("{s}=[{}]u8{{nonzero}}\n", .{ label, value.len });
1306
- }
1307
- } else {
1308
- var label_buffer: [1024]u8 = undefined;
1309
- for (value[0..], 0..) |*item, index| {
1310
- var label_stream = std.io.fixedBufferStream(&label_buffer);
1311
- try label_stream.writer().print("{s}[{}]", .{ label, index });
1312
- try print_struct(output, label_stream.getWritten(), item);
1313
- }
1314
- return;
1315
- }
1316
- }
1317
-
1318
- try output.print("{s}=", .{label});
1319
- try print_value(output, value.*);
1320
- try output.writeAll("\n");
1321
- }
1322
-
1323
- fn print_value(output: std.io.AnyWriter, value: anytype) !void {
1324
- const Type = @TypeOf(value);
1325
- if (@typeInfo(Type) == .@"struct") assert(std.meta.hasFn(Type, "format"));
1326
- assert(@typeInfo(Type) != .array);
1327
-
1328
- if (Type == u128) return output.print("0x{x:0>32}", .{value});
1329
-
1330
- if (Type == vsr.Operation) {
1331
- if (value.valid(StateMachine.Operation)) {
1332
- return output.writeAll(value.tag_name(StateMachine.Operation));
1333
- } else {
1334
- return output.print("{}!", .{@intFromEnum(value)});
1335
- }
1336
- }
1337
-
1338
- if (@typeInfo(Type) == .@"enum") {
1339
- if (std.enums.tagName(Type, value)) |value_string| {
1340
- return output.print("{s}", .{value_string});
1341
- } else {
1342
- return output.print("{}!", .{@intFromEnum(value)});
1343
- }
1344
- }
1345
- try output.print("{}", .{value});
1346
- }
1347
-
1348
- fn print_block(writer: std.io.AnyWriter, block: BlockPtrConst) !void {
1349
- const header = schema.header_from_block(block);
1350
- try print_struct(writer, "header", header);
1351
-
1352
- inline for (.{
1353
- .{ .block_type = .free_set, .Schema = schema.TrailerNode },
1354
- .{ .block_type = .client_sessions, .Schema = schema.TrailerNode },
1355
- .{ .block_type = .manifest, .Schema = schema.ManifestNode },
1356
- .{ .block_type = .index, .Schema = schema.TableIndex },
1357
- .{ .block_type = .value, .Schema = schema.TableValue },
1358
- }) |pair| {
1359
- if (header.block_type == pair.block_type) {
1360
- try print_struct(writer, "header.metadata", pair.Schema.metadata(block));
1361
- break;
1362
- }
1363
- } else {
1364
- try writer.print("header.metadata: unknown block type\n", .{});
1365
- }
1366
-
1367
- switch (header.block_type) {
1368
- .manifest => {
1369
- const manifest_node = schema.ManifestNode.from(block);
1370
- for (manifest_node.tables_const(block), 0..) |*table_info, entry_index| {
1371
- try writer.print(
1372
- "entry[{:_>4}]: {s} level={} address={} checksum={x:0>32} " ++
1373
- "tree_id={s} key={:0>64}..{:0>64} snapshot={}..{} values={}\n",
1374
- .{
1375
- entry_index,
1376
- @tagName(table_info.label.event),
1377
- table_info.label.level,
1378
- table_info.address,
1379
- table_info.checksum,
1380
- format_tree_id(table_info.tree_id),
1381
- std.fmt.fmtSliceHexLower(&table_info.key_min),
1382
- std.fmt.fmtSliceHexLower(&table_info.key_max),
1383
- table_info.snapshot_min,
1384
- table_info.snapshot_max,
1385
- table_info.value_count,
1386
- },
1387
- );
1388
- }
1389
- },
1390
- .index => {
1391
- const index = schema.TableIndex.from(block);
1392
- for (
1393
- index.value_addresses_used(block),
1394
- index.value_checksums_used(block),
1395
- 0..,
1396
- ) |value_address, value_checksum, i| {
1397
- try writer.print(
1398
- "value_blocks[{:_>3}]: address={} checksum={x:0>32}\n",
1399
- .{ i, value_address, value_checksum.value },
1400
- );
1401
- }
1402
- },
1403
- .value => {
1404
- const value_block = schema.TableValue.from(block);
1405
- const metadata = value_block.block_metadata(block);
1406
- const value_bytes = value_block.block_values_used_bytes(block);
1407
-
1408
- var label_buffer: [256]u8 = undefined;
1409
- inline for (StateMachine.Forest.tree_infos) |tree_info| {
1410
- if (metadata.tree_id == tree_info.tree_id) {
1411
- for (
1412
- std.mem.bytesAsSlice(tree_info.Tree.Table.Value, value_bytes),
1413
- 0..,
1414
- ) |*value, i| {
1415
- var label_stream = std.io.fixedBufferStream(&label_buffer);
1416
- try label_stream.writer().print("{s}[{}]", .{ tree_info.tree_name, i });
1417
- if (comptime is_composite_key(tree_info.Tree.Table.Value)) {
1418
- try label_stream.writer().writeAll(": ");
1419
- try print_struct(
1420
- writer,
1421
- label_stream.getWritten(),
1422
- &.{ value.field, value.timestamp },
1423
- );
1424
- } else {
1425
- try print_struct(writer, label_stream.getWritten(), value);
1426
- }
1427
- }
1428
- break;
1429
- }
1430
- } else {
1431
- try writer.print("body: unknown tree id\n", .{});
1432
- }
1433
- },
1434
- else => {
1435
- try writer.print(
1436
- "body: unimplemented for block_type={s}\n",
1437
- .{@tagName(header.block_type)},
1438
- );
1439
- },
1440
- }
1441
- }
1442
-
1443
- fn format_tree_id(tree_id: u16) []const u8 {
1444
- inline for (StateMachine.Forest.tree_infos) |tree_info| {
1445
- if (tree_info.tree_id == tree_id) {
1446
- return tree_info.tree_name;
1447
- }
1448
- } else {
1449
- return "(unknown)";
1450
- }
1451
- }
1452
-
1453
- fn parse_tree_id(tree_label: []const u8) ?u16 {
1454
- const tree_label_integer = std.fmt.parseInt(u16, tree_label, 10) catch null;
1455
- inline for (StateMachine.Forest.tree_infos) |tree_info| {
1456
- if (std.mem.eql(u8, tree_info.tree_name, tree_label)) {
1457
- return tree_info.tree_id;
1458
- }
1459
-
1460
- if (tree_label_integer) |tree_id| {
1461
- if (tree_info.tree_id == tree_id) {
1462
- return tree_id;
1463
- }
1464
- }
1465
- }
1466
- return null;
1467
- }
1468
-
1469
- const operation_schemas = list: {
1470
- const OperationSchema = struct {
1471
- operation: vsr.Operation,
1472
- Event: type,
1473
- Result: type,
1474
- };
1475
-
1476
- var list: []const OperationSchema = &[_]OperationSchema{};
1477
-
1478
- for (&[_]struct { vsr.Operation, type, type }{
1479
- .{ .reserved, extern struct {}, extern struct {} },
1480
- .{ .root, extern struct {}, extern struct {} },
1481
- // TODO vsr.RegisterRequest once that is merged.
1482
- .{ .register, extern struct {}, vsr.RegisterResult },
1483
- .{ .reconfigure, vsr.ReconfigurationRequest, vsr.ReconfigurationResult },
1484
- .{ .pulse, extern struct {}, extern struct {} },
1485
- .{ .upgrade, vsr.UpgradeRequest, extern struct {} },
1486
- }) |operation_schema| {
1487
- list = list ++ [_]OperationSchema{.{
1488
- .operation = operation_schema[0],
1489
- .Event = operation_schema[1],
1490
- .Result = operation_schema[2],
1491
- }};
1492
- }
1493
-
1494
- for (std.enums.values(StateMachine.Operation)) |operation| {
1495
- if (operation == .pulse) continue;
1496
- list = list ++ [_]OperationSchema{.{
1497
- .operation = operation.to_vsr(),
1498
- .Event = operation.EventType(),
1499
- .Result = operation.ResultType(),
1500
- }};
1501
- }
1502
- break :list list;
1503
- };
1504
-
1505
- fn print_prepare_body(output: std.io.AnyWriter, prepare: []const u8) !void {
1506
- const header = std.mem.bytesAsValue(vsr.Header.Prepare, prepare[0..@sizeOf(vsr.Header)]);
1507
- inline for (operation_schemas) |operation_schema| {
1508
- if (operation_schema.operation == header.operation) {
1509
- const event_size = @sizeOf(operation_schema.Event);
1510
- const body_size = header.size - @sizeOf(vsr.Header);
1511
- if (body_size == 0) {
1512
- try output.print("(no body)\n", .{});
1513
- } else if (event_size != 0 and body_size % event_size == 0) {
1514
- var label_buffer: [128]u8 = undefined;
1515
- for (std.mem.bytesAsSlice(
1516
- operation_schema.Event,
1517
- prepare[@sizeOf(vsr.Header)..header.size],
1518
- ), 0..) |*event, i| {
1519
- var label_stream = std.io.fixedBufferStream(&label_buffer);
1520
- try label_stream.writer().print("events[{}]: ", .{i});
1521
- try print_struct(output, label_stream.getWritten(), event);
1522
- }
1523
- } else {
1524
- try output.print(
1525
- "error: unexpected body size={}, @sizeOf(Event)={}\n",
1526
- .{ header.size, event_size },
1527
- );
1528
- }
1529
- return;
1530
- }
1531
- } else {
1532
- try output.print("error: unimplemented operation={s}\n", .{@tagName(header.operation)});
1533
- }
1534
- }
1535
-
1536
- fn print_reply_body(output: std.io.AnyWriter, reply: []const u8) !void {
1537
- const header = std.mem.bytesAsValue(vsr.Header.Reply, reply[0..@sizeOf(vsr.Header)]);
1538
- inline for (operation_schemas) |operation_schema| {
1539
- if (operation_schema.operation == header.operation) {
1540
- const result_size = @sizeOf(operation_schema.Result);
1541
- const body_size = header.size - @sizeOf(vsr.Header);
1542
- if (body_size == 0) {
1543
- try output.print("(no body)\n", .{});
1544
- } else if (result_size != 0 and body_size % result_size == 0) {
1545
- var label_buffer: [128]u8 = undefined;
1546
- for (std.mem.bytesAsSlice(
1547
- operation_schema.Result,
1548
- reply[@sizeOf(vsr.Header)..header.size],
1549
- ), 0..) |*result, i| {
1550
- var label_stream = std.io.fixedBufferStream(&label_buffer);
1551
- try label_stream.writer().print("results[{}]: ", .{i});
1552
- try print_struct(output, label_stream.getWritten(), result);
1553
- }
1554
- } else {
1555
- try output.print(
1556
- "error: unexpected body size={}, @sizeOf(Result)={}\n",
1557
- .{ header.size, result_size },
1558
- );
1559
- }
1560
- return;
1561
- }
1562
- } else {
1563
- try output.print("error: unimplemented operation={s}\n", .{@tagName(header.operation)});
1564
- }
1565
- }
1566
-
1567
- fn print_table_info(
1568
- output: std.io.AnyWriter,
1569
- comptime tree_info: anytype,
1570
- table: *const schema.ManifestNode.TableInfo,
1571
- ) !void {
1572
- try output.print("{c} T={s} L={}", .{
1573
- @as(u8, switch (table.label.event) {
1574
- .insert => 'I',
1575
- .update => 'U',
1576
- // These shouldn't be hit, but included just for completeness' sake:
1577
- .remove => 'R',
1578
- else => '?',
1579
- }),
1580
- format_tree_id(table.tree_id),
1581
- table.label.level,
1582
- });
1583
-
1584
- const Key = tree_info.Tree.Table.Key;
1585
- const Value = tree_info.Tree.Table.Value;
1586
- const key_min = std.mem.bytesAsValue(Key, table.key_min[0..@sizeOf(Key)]).*;
1587
- const key_max = std.mem.bytesAsValue(Key, table.key_max[0..@sizeOf(Key)]).*;
1588
-
1589
- if (comptime is_composite_key(Value)) {
1590
- const f: Value = undefined;
1591
- const Field = @TypeOf(f.field);
1592
- const key_min_timestamp: u64 = @truncate(key_min & std.math.maxInt(u64));
1593
- const key_max_timestamp: u64 = @truncate(key_max & std.math.maxInt(u64));
1594
- const key_min_field: Field = Value.key_prefix(key_min);
1595
- const key_max_field: Field = Value.key_prefix(key_max);
1596
-
1597
- try output.print(" K={:_>6}:{}..{:_>6}:{}", .{
1598
- key_min_field,
1599
- key_min_timestamp,
1600
- key_max_field,
1601
- key_max_timestamp,
1602
- });
1603
- } else {
1604
- try output.print(" K={}..{}", .{ key_min, key_max });
1605
- }
1606
-
1607
- if (table.snapshot_max == std.math.maxInt(u64)) {
1608
- try output.print(" S={}..max", .{table.snapshot_min});
1609
- } else {
1610
- try output.print(" S={}..{}", .{ table.snapshot_min, table.snapshot_max });
1611
- }
1612
-
1613
- try output.print(" V={:_>6}/{} C={x:0>32} A={} O={}\n", .{
1614
- table.value_count,
1615
- tree_info.Tree.Table.value_count_max,
1616
- table.checksum,
1617
- table.address,
1618
- vsr.Zone.offset(.grid, (table.address - 1) * constants.block_size),
1619
- });
1620
- }
1621
-
1622
- fn GroupByType(comptime count_max: usize) type {
1623
- return struct {
1624
- const GroupBy = @This();
1625
- const BitSet = stdx.BitSetType(count_max);
1626
-
1627
- count: usize = 0,
1628
- checksums: [count_max]?u128 = @splat(null),
1629
- matches: [count_max]BitSet = undefined,
1630
-
1631
- pub fn compare(group_by: *GroupBy, bytes: []const u8) void {
1632
- assert(group_by.count < count_max);
1633
- defer group_by.count += 1;
1634
-
1635
- assert(group_by.checksums[group_by.count] == null);
1636
- group_by.checksums[group_by.count] = vsr.checksum(bytes);
1637
- }
1638
-
1639
- pub fn groups(group_by: *GroupBy) []const BitSet {
1640
- assert(group_by.count == count_max);
1641
-
1642
- var distinct: usize = 0;
1643
- for (&group_by.checksums, 0..) |checksum_a, a| {
1644
- var matches: BitSet = .{};
1645
- for (&group_by.checksums, 0..) |checksum_b, b| {
1646
- matches.set_value(b, checksum_a.? == checksum_b.?);
1647
- }
1648
- if (matches.first_set().? == a) {
1649
- group_by.matches[distinct] = matches;
1650
- distinct += 1;
1651
- }
1652
- }
1653
- assert(distinct > 0);
1654
- assert(distinct <= count_max);
1655
- return group_by.matches[0..distinct];
1656
- }
1657
- };
1658
- }