tigerbeetle 0.0.34 → 0.0.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (249) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/ext/tb_client/extconf.rb +13 -13
  4. data/ext/tb_client/tigerbeetle/LICENSE +177 -0
  5. data/ext/tb_client/tigerbeetle/build.zig +2327 -0
  6. data/ext/tb_client/tigerbeetle/src/aof.zig +1000 -0
  7. data/ext/tb_client/tigerbeetle/src/build_multiversion.zig +808 -0
  8. data/ext/tb_client/tigerbeetle/src/cdc/amqp/protocol.zig +1283 -0
  9. data/ext/tb_client/tigerbeetle/src/cdc/amqp/spec.zig +1704 -0
  10. data/ext/tb_client/tigerbeetle/src/cdc/amqp/types.zig +341 -0
  11. data/ext/tb_client/tigerbeetle/src/cdc/amqp.zig +1450 -0
  12. data/ext/tb_client/tigerbeetle/src/cdc/runner.zig +1659 -0
  13. data/ext/tb_client/tigerbeetle/src/clients/c/samples/main.c +406 -0
  14. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/context.zig +1084 -0
  15. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/echo_client.zig +286 -0
  16. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/packet.zig +158 -0
  17. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/signal.zig +229 -0
  18. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/signal_fuzz.zig +110 -0
  19. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client.h +386 -0
  20. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client.zig +34 -0
  21. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_exports.zig +281 -0
  22. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_header.zig +312 -0
  23. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_header_test.zig +138 -0
  24. data/ext/tb_client/tigerbeetle/src/clients/c/test.zig +466 -0
  25. data/ext/tb_client/tigerbeetle/src/clients/docs_samples.zig +157 -0
  26. data/ext/tb_client/tigerbeetle/src/clients/docs_types.zig +90 -0
  27. data/ext/tb_client/tigerbeetle/src/clients/dotnet/ci.zig +203 -0
  28. data/ext/tb_client/tigerbeetle/src/clients/dotnet/docs.zig +79 -0
  29. data/ext/tb_client/tigerbeetle/src/clients/dotnet/dotnet_bindings.zig +542 -0
  30. data/ext/tb_client/tigerbeetle/src/clients/go/ci.zig +109 -0
  31. data/ext/tb_client/tigerbeetle/src/clients/go/docs.zig +86 -0
  32. data/ext/tb_client/tigerbeetle/src/clients/go/go_bindings.zig +370 -0
  33. data/ext/tb_client/tigerbeetle/src/clients/go/pkg/native/tb_client.h +386 -0
  34. data/ext/tb_client/tigerbeetle/src/clients/java/ci.zig +167 -0
  35. data/ext/tb_client/tigerbeetle/src/clients/java/docs.zig +126 -0
  36. data/ext/tb_client/tigerbeetle/src/clients/java/java_bindings.zig +996 -0
  37. data/ext/tb_client/tigerbeetle/src/clients/java/src/client.zig +748 -0
  38. data/ext/tb_client/tigerbeetle/src/clients/java/src/jni.zig +3238 -0
  39. data/ext/tb_client/tigerbeetle/src/clients/java/src/jni_tests.zig +1718 -0
  40. data/ext/tb_client/tigerbeetle/src/clients/java/src/jni_thread_cleaner.zig +190 -0
  41. data/ext/tb_client/tigerbeetle/src/clients/node/ci.zig +104 -0
  42. data/ext/tb_client/tigerbeetle/src/clients/node/docs.zig +75 -0
  43. data/ext/tb_client/tigerbeetle/src/clients/node/node.zig +522 -0
  44. data/ext/tb_client/tigerbeetle/src/clients/node/node_bindings.zig +267 -0
  45. data/ext/tb_client/tigerbeetle/src/clients/node/src/c.zig +3 -0
  46. data/ext/tb_client/tigerbeetle/src/clients/node/src/translate.zig +379 -0
  47. data/ext/tb_client/tigerbeetle/src/clients/python/ci.zig +131 -0
  48. data/ext/tb_client/tigerbeetle/src/clients/python/docs.zig +63 -0
  49. data/ext/tb_client/tigerbeetle/src/clients/python/python_bindings.zig +588 -0
  50. data/ext/tb_client/tigerbeetle/src/clients/rust/assets/tb_client.h +386 -0
  51. data/ext/tb_client/tigerbeetle/src/clients/rust/ci.zig +73 -0
  52. data/ext/tb_client/tigerbeetle/src/clients/rust/docs.zig +106 -0
  53. data/ext/tb_client/tigerbeetle/src/clients/rust/rust_bindings.zig +305 -0
  54. data/ext/tb_client/tigerbeetle/src/config.zig +296 -0
  55. data/ext/tb_client/tigerbeetle/src/constants.zig +790 -0
  56. data/ext/tb_client/tigerbeetle/src/copyhound.zig +202 -0
  57. data/ext/tb_client/tigerbeetle/src/counting_allocator.zig +72 -0
  58. data/ext/tb_client/tigerbeetle/src/direction.zig +11 -0
  59. data/ext/tb_client/tigerbeetle/src/docs_website/build.zig +158 -0
  60. data/ext/tb_client/tigerbeetle/src/docs_website/src/content.zig +156 -0
  61. data/ext/tb_client/tigerbeetle/src/docs_website/src/docs.zig +252 -0
  62. data/ext/tb_client/tigerbeetle/src/docs_website/src/file_checker.zig +313 -0
  63. data/ext/tb_client/tigerbeetle/src/docs_website/src/html.zig +87 -0
  64. data/ext/tb_client/tigerbeetle/src/docs_website/src/page_writer.zig +63 -0
  65. data/ext/tb_client/tigerbeetle/src/docs_website/src/redirects.zig +47 -0
  66. data/ext/tb_client/tigerbeetle/src/docs_website/src/search_index_writer.zig +28 -0
  67. data/ext/tb_client/tigerbeetle/src/docs_website/src/service_worker_writer.zig +61 -0
  68. data/ext/tb_client/tigerbeetle/src/docs_website/src/single_page_writer.zig +169 -0
  69. data/ext/tb_client/tigerbeetle/src/docs_website/src/website.zig +46 -0
  70. data/ext/tb_client/tigerbeetle/src/ewah.zig +445 -0
  71. data/ext/tb_client/tigerbeetle/src/ewah_benchmark.zig +128 -0
  72. data/ext/tb_client/tigerbeetle/src/ewah_fuzz.zig +171 -0
  73. data/ext/tb_client/tigerbeetle/src/fuzz_tests.zig +179 -0
  74. data/ext/tb_client/tigerbeetle/src/integration_tests.zig +662 -0
  75. data/ext/tb_client/tigerbeetle/src/io/common.zig +155 -0
  76. data/ext/tb_client/tigerbeetle/src/io/darwin.zig +1093 -0
  77. data/ext/tb_client/tigerbeetle/src/io/linux.zig +1880 -0
  78. data/ext/tb_client/tigerbeetle/src/io/test.zig +1005 -0
  79. data/ext/tb_client/tigerbeetle/src/io/windows.zig +1598 -0
  80. data/ext/tb_client/tigerbeetle/src/io.zig +34 -0
  81. data/ext/tb_client/tigerbeetle/src/iops.zig +134 -0
  82. data/ext/tb_client/tigerbeetle/src/list.zig +236 -0
  83. data/ext/tb_client/tigerbeetle/src/lsm/binary_search.zig +848 -0
  84. data/ext/tb_client/tigerbeetle/src/lsm/binary_search_benchmark.zig +179 -0
  85. data/ext/tb_client/tigerbeetle/src/lsm/cache_map.zig +424 -0
  86. data/ext/tb_client/tigerbeetle/src/lsm/cache_map_fuzz.zig +420 -0
  87. data/ext/tb_client/tigerbeetle/src/lsm/compaction.zig +2117 -0
  88. data/ext/tb_client/tigerbeetle/src/lsm/composite_key.zig +182 -0
  89. data/ext/tb_client/tigerbeetle/src/lsm/forest.zig +1119 -0
  90. data/ext/tb_client/tigerbeetle/src/lsm/forest_fuzz.zig +1102 -0
  91. data/ext/tb_client/tigerbeetle/src/lsm/forest_table_iterator.zig +200 -0
  92. data/ext/tb_client/tigerbeetle/src/lsm/groove.zig +1495 -0
  93. data/ext/tb_client/tigerbeetle/src/lsm/k_way_merge.zig +739 -0
  94. data/ext/tb_client/tigerbeetle/src/lsm/k_way_merge_benchmark.zig +166 -0
  95. data/ext/tb_client/tigerbeetle/src/lsm/manifest.zig +754 -0
  96. data/ext/tb_client/tigerbeetle/src/lsm/manifest_level.zig +1294 -0
  97. data/ext/tb_client/tigerbeetle/src/lsm/manifest_level_fuzz.zig +510 -0
  98. data/ext/tb_client/tigerbeetle/src/lsm/manifest_log.zig +1263 -0
  99. data/ext/tb_client/tigerbeetle/src/lsm/manifest_log_fuzz.zig +628 -0
  100. data/ext/tb_client/tigerbeetle/src/lsm/node_pool.zig +247 -0
  101. data/ext/tb_client/tigerbeetle/src/lsm/scan_buffer.zig +116 -0
  102. data/ext/tb_client/tigerbeetle/src/lsm/scan_builder.zig +543 -0
  103. data/ext/tb_client/tigerbeetle/src/lsm/scan_fuzz.zig +938 -0
  104. data/ext/tb_client/tigerbeetle/src/lsm/scan_lookup.zig +293 -0
  105. data/ext/tb_client/tigerbeetle/src/lsm/scan_merge.zig +362 -0
  106. data/ext/tb_client/tigerbeetle/src/lsm/scan_range.zig +99 -0
  107. data/ext/tb_client/tigerbeetle/src/lsm/scan_state.zig +17 -0
  108. data/ext/tb_client/tigerbeetle/src/lsm/scan_tree.zig +1036 -0
  109. data/ext/tb_client/tigerbeetle/src/lsm/schema.zig +617 -0
  110. data/ext/tb_client/tigerbeetle/src/lsm/scratch_memory.zig +84 -0
  111. data/ext/tb_client/tigerbeetle/src/lsm/segmented_array.zig +1500 -0
  112. data/ext/tb_client/tigerbeetle/src/lsm/segmented_array_benchmark.zig +149 -0
  113. data/ext/tb_client/tigerbeetle/src/lsm/segmented_array_fuzz.zig +7 -0
  114. data/ext/tb_client/tigerbeetle/src/lsm/set_associative_cache.zig +865 -0
  115. data/ext/tb_client/tigerbeetle/src/lsm/table.zig +607 -0
  116. data/ext/tb_client/tigerbeetle/src/lsm/table_memory.zig +843 -0
  117. data/ext/tb_client/tigerbeetle/src/lsm/table_value_iterator.zig +105 -0
  118. data/ext/tb_client/tigerbeetle/src/lsm/timestamp_range.zig +40 -0
  119. data/ext/tb_client/tigerbeetle/src/lsm/tree.zig +630 -0
  120. data/ext/tb_client/tigerbeetle/src/lsm/tree_fuzz.zig +933 -0
  121. data/ext/tb_client/tigerbeetle/src/lsm/zig_zag_merge.zig +557 -0
  122. data/ext/tb_client/tigerbeetle/src/message_buffer.zig +469 -0
  123. data/ext/tb_client/tigerbeetle/src/message_bus.zig +1214 -0
  124. data/ext/tb_client/tigerbeetle/src/message_bus_fuzz.zig +936 -0
  125. data/ext/tb_client/tigerbeetle/src/message_pool.zig +343 -0
  126. data/ext/tb_client/tigerbeetle/src/multiversion.zig +2195 -0
  127. data/ext/tb_client/tigerbeetle/src/queue.zig +390 -0
  128. data/ext/tb_client/tigerbeetle/src/repl/completion.zig +201 -0
  129. data/ext/tb_client/tigerbeetle/src/repl/parser.zig +1356 -0
  130. data/ext/tb_client/tigerbeetle/src/repl/terminal.zig +496 -0
  131. data/ext/tb_client/tigerbeetle/src/repl.zig +1034 -0
  132. data/ext/tb_client/tigerbeetle/src/scripts/amqp.zig +973 -0
  133. data/ext/tb_client/tigerbeetle/src/scripts/cfo.zig +1866 -0
  134. data/ext/tb_client/tigerbeetle/src/scripts/changelog.zig +304 -0
  135. data/ext/tb_client/tigerbeetle/src/scripts/ci.zig +227 -0
  136. data/ext/tb_client/tigerbeetle/src/scripts/client_readmes.zig +658 -0
  137. data/ext/tb_client/tigerbeetle/src/scripts/devhub.zig +466 -0
  138. data/ext/tb_client/tigerbeetle/src/scripts/release.zig +1058 -0
  139. data/ext/tb_client/tigerbeetle/src/scripts.zig +105 -0
  140. data/ext/tb_client/tigerbeetle/src/shell.zig +1195 -0
  141. data/ext/tb_client/tigerbeetle/src/stack.zig +260 -0
  142. data/ext/tb_client/tigerbeetle/src/state_machine/auditor.zig +911 -0
  143. data/ext/tb_client/tigerbeetle/src/state_machine/workload.zig +2079 -0
  144. data/ext/tb_client/tigerbeetle/src/state_machine.zig +4872 -0
  145. data/ext/tb_client/tigerbeetle/src/state_machine_fuzz.zig +288 -0
  146. data/ext/tb_client/tigerbeetle/src/state_machine_tests.zig +3128 -0
  147. data/ext/tb_client/tigerbeetle/src/static_allocator.zig +82 -0
  148. data/ext/tb_client/tigerbeetle/src/stdx/bit_set.zig +157 -0
  149. data/ext/tb_client/tigerbeetle/src/stdx/bounded_array.zig +292 -0
  150. data/ext/tb_client/tigerbeetle/src/stdx/debug.zig +65 -0
  151. data/ext/tb_client/tigerbeetle/src/stdx/flags.zig +1414 -0
  152. data/ext/tb_client/tigerbeetle/src/stdx/mlock.zig +92 -0
  153. data/ext/tb_client/tigerbeetle/src/stdx/prng.zig +677 -0
  154. data/ext/tb_client/tigerbeetle/src/stdx/radix.zig +336 -0
  155. data/ext/tb_client/tigerbeetle/src/stdx/ring_buffer.zig +511 -0
  156. data/ext/tb_client/tigerbeetle/src/stdx/sort_test.zig +112 -0
  157. data/ext/tb_client/tigerbeetle/src/stdx/stdx.zig +1160 -0
  158. data/ext/tb_client/tigerbeetle/src/stdx/testing/low_level_hash_vectors.zig +142 -0
  159. data/ext/tb_client/tigerbeetle/src/stdx/testing/snaptest.zig +361 -0
  160. data/ext/tb_client/tigerbeetle/src/stdx/time_units.zig +275 -0
  161. data/ext/tb_client/tigerbeetle/src/stdx/unshare.zig +295 -0
  162. data/ext/tb_client/tigerbeetle/src/stdx/vendored/aegis.zig +436 -0
  163. data/ext/tb_client/tigerbeetle/src/stdx/windows.zig +48 -0
  164. data/ext/tb_client/tigerbeetle/src/stdx/zipfian.zig +402 -0
  165. data/ext/tb_client/tigerbeetle/src/storage.zig +489 -0
  166. data/ext/tb_client/tigerbeetle/src/storage_fuzz.zig +180 -0
  167. data/ext/tb_client/tigerbeetle/src/testing/bench.zig +146 -0
  168. data/ext/tb_client/tigerbeetle/src/testing/cluster/grid_checker.zig +53 -0
  169. data/ext/tb_client/tigerbeetle/src/testing/cluster/journal_checker.zig +61 -0
  170. data/ext/tb_client/tigerbeetle/src/testing/cluster/manifest_checker.zig +76 -0
  171. data/ext/tb_client/tigerbeetle/src/testing/cluster/message_bus.zig +110 -0
  172. data/ext/tb_client/tigerbeetle/src/testing/cluster/network.zig +412 -0
  173. data/ext/tb_client/tigerbeetle/src/testing/cluster/state_checker.zig +331 -0
  174. data/ext/tb_client/tigerbeetle/src/testing/cluster/storage_checker.zig +458 -0
  175. data/ext/tb_client/tigerbeetle/src/testing/cluster.zig +1198 -0
  176. data/ext/tb_client/tigerbeetle/src/testing/exhaustigen.zig +128 -0
  177. data/ext/tb_client/tigerbeetle/src/testing/fixtures.zig +181 -0
  178. data/ext/tb_client/tigerbeetle/src/testing/fuzz.zig +144 -0
  179. data/ext/tb_client/tigerbeetle/src/testing/id.zig +97 -0
  180. data/ext/tb_client/tigerbeetle/src/testing/io.zig +317 -0
  181. data/ext/tb_client/tigerbeetle/src/testing/marks.zig +126 -0
  182. data/ext/tb_client/tigerbeetle/src/testing/packet_simulator.zig +533 -0
  183. data/ext/tb_client/tigerbeetle/src/testing/reply_sequence.zig +154 -0
  184. data/ext/tb_client/tigerbeetle/src/testing/state_machine.zig +389 -0
  185. data/ext/tb_client/tigerbeetle/src/testing/storage.zig +1247 -0
  186. data/ext/tb_client/tigerbeetle/src/testing/table.zig +249 -0
  187. data/ext/tb_client/tigerbeetle/src/testing/time.zig +98 -0
  188. data/ext/tb_client/tigerbeetle/src/testing/tmp_tigerbeetle.zig +212 -0
  189. data/ext/tb_client/tigerbeetle/src/testing/vortex/constants.zig +26 -0
  190. data/ext/tb_client/tigerbeetle/src/testing/vortex/faulty_network.zig +580 -0
  191. data/ext/tb_client/tigerbeetle/src/testing/vortex/java_driver/ci.zig +39 -0
  192. data/ext/tb_client/tigerbeetle/src/testing/vortex/logged_process.zig +214 -0
  193. data/ext/tb_client/tigerbeetle/src/testing/vortex/rust_driver/ci.zig +34 -0
  194. data/ext/tb_client/tigerbeetle/src/testing/vortex/supervisor.zig +766 -0
  195. data/ext/tb_client/tigerbeetle/src/testing/vortex/workload.zig +543 -0
  196. data/ext/tb_client/tigerbeetle/src/testing/vortex/zig_driver.zig +181 -0
  197. data/ext/tb_client/tigerbeetle/src/tidy.zig +1448 -0
  198. data/ext/tb_client/tigerbeetle/src/tigerbeetle/benchmark_driver.zig +227 -0
  199. data/ext/tb_client/tigerbeetle/src/tigerbeetle/benchmark_load.zig +1069 -0
  200. data/ext/tb_client/tigerbeetle/src/tigerbeetle/cli.zig +1422 -0
  201. data/ext/tb_client/tigerbeetle/src/tigerbeetle/inspect.zig +1658 -0
  202. data/ext/tb_client/tigerbeetle/src/tigerbeetle/inspect_integrity.zig +518 -0
  203. data/ext/tb_client/tigerbeetle/src/tigerbeetle/libtb_client.zig +36 -0
  204. data/ext/tb_client/tigerbeetle/src/tigerbeetle/main.zig +646 -0
  205. data/ext/tb_client/tigerbeetle/src/tigerbeetle.zig +958 -0
  206. data/ext/tb_client/tigerbeetle/src/time.zig +236 -0
  207. data/ext/tb_client/tigerbeetle/src/trace/event.zig +745 -0
  208. data/ext/tb_client/tigerbeetle/src/trace/statsd.zig +462 -0
  209. data/ext/tb_client/tigerbeetle/src/trace.zig +556 -0
  210. data/ext/tb_client/tigerbeetle/src/unit_tests.zig +321 -0
  211. data/ext/tb_client/tigerbeetle/src/vopr.zig +1785 -0
  212. data/ext/tb_client/tigerbeetle/src/vortex.zig +101 -0
  213. data/ext/tb_client/tigerbeetle/src/vsr/checkpoint_trailer.zig +473 -0
  214. data/ext/tb_client/tigerbeetle/src/vsr/checksum.zig +208 -0
  215. data/ext/tb_client/tigerbeetle/src/vsr/checksum_benchmark.zig +43 -0
  216. data/ext/tb_client/tigerbeetle/src/vsr/client.zig +768 -0
  217. data/ext/tb_client/tigerbeetle/src/vsr/client_replies.zig +532 -0
  218. data/ext/tb_client/tigerbeetle/src/vsr/client_sessions.zig +338 -0
  219. data/ext/tb_client/tigerbeetle/src/vsr/clock.zig +1019 -0
  220. data/ext/tb_client/tigerbeetle/src/vsr/fault_detector.zig +279 -0
  221. data/ext/tb_client/tigerbeetle/src/vsr/free_set.zig +1381 -0
  222. data/ext/tb_client/tigerbeetle/src/vsr/free_set_fuzz.zig +315 -0
  223. data/ext/tb_client/tigerbeetle/src/vsr/grid.zig +1460 -0
  224. data/ext/tb_client/tigerbeetle/src/vsr/grid_blocks_missing.zig +757 -0
  225. data/ext/tb_client/tigerbeetle/src/vsr/grid_scrubber.zig +797 -0
  226. data/ext/tb_client/tigerbeetle/src/vsr/journal.zig +2586 -0
  227. data/ext/tb_client/tigerbeetle/src/vsr/marzullo.zig +308 -0
  228. data/ext/tb_client/tigerbeetle/src/vsr/message_header.zig +1777 -0
  229. data/ext/tb_client/tigerbeetle/src/vsr/multi_batch.zig +715 -0
  230. data/ext/tb_client/tigerbeetle/src/vsr/multi_batch_fuzz.zig +185 -0
  231. data/ext/tb_client/tigerbeetle/src/vsr/repair_budget.zig +333 -0
  232. data/ext/tb_client/tigerbeetle/src/vsr/replica.zig +12355 -0
  233. data/ext/tb_client/tigerbeetle/src/vsr/replica_format.zig +416 -0
  234. data/ext/tb_client/tigerbeetle/src/vsr/replica_reformat.zig +165 -0
  235. data/ext/tb_client/tigerbeetle/src/vsr/replica_test.zig +2910 -0
  236. data/ext/tb_client/tigerbeetle/src/vsr/routing.zig +1075 -0
  237. data/ext/tb_client/tigerbeetle/src/vsr/superblock.zig +1603 -0
  238. data/ext/tb_client/tigerbeetle/src/vsr/superblock_fuzz.zig +484 -0
  239. data/ext/tb_client/tigerbeetle/src/vsr/superblock_quorums.zig +405 -0
  240. data/ext/tb_client/tigerbeetle/src/vsr/superblock_quorums_fuzz.zig +355 -0
  241. data/ext/tb_client/tigerbeetle/src/vsr/sync.zig +29 -0
  242. data/ext/tb_client/tigerbeetle/src/vsr.zig +1727 -0
  243. data/lib/tb_client/shared_lib.rb +12 -5
  244. data/lib/tigerbeetle/client.rb +1 -1
  245. data/lib/tigerbeetle/platforms.rb +9 -0
  246. data/lib/tigerbeetle/version.rb +2 -2
  247. data/tigerbeetle.gemspec +22 -5
  248. metadata +242 -3
  249. data/ext/tb_client/pkg.tar.gz +0 -0
@@ -0,0 +1,510 @@
1
+ //! Fuzz ManifestLevel. All public methods are covered.
2
+ //!
3
+ //! Strategy:
4
+ //!
5
+ //! Applies operations to both the ManifestLevel and a separate table buffer to ensure the tables in
6
+ //! both match up along the way. Sporadic usage similar to Manifest/Tree is applied to make sure it
7
+ //! covers a good amount of positive space.
8
+ //!
9
+ //! Under various interleavings (those not common during normal usage but still allowed), tables are
10
+ //! inserted and eventually either have their snapshot_max updated to the current snapshot or
11
+ //! removed directly (e.g. move_table). If their snapshot_max is updated, they will eventually be
12
+ //! removed once the current snapshot is bumped either due to the level being full of tables or the
13
+ //! fuzzer deciding it wants to clean them up.
14
+ //!
15
+ //! Invariants:
16
+ //!
17
+ //! - Inserted tables are visible to the current snapshot and snapshot_latest.
18
+ //! - Updated tables are visible to the current snapshot but no longer snapshot_latest.
19
+ //! - Updated tables become completely invisible when the current snapshot is bumped.
20
+ //!
21
+ //! - Tables visible to both snapshot_latest and the current snapshot can be removed.
22
+ //! - Tables invisible to snapshot_latest but still the current snapshot cannot be removed.
23
+ //! - The current snapshot must be bumped which puts them in the next category:
24
+ //! - Tables invisible to snapshot_latest and the current snapshot can be removed.
25
+ //!
26
+ const std = @import("std");
27
+ const stdx = @import("stdx");
28
+ const assert = std.debug.assert;
29
+
30
+ const log = std.log.scoped(.lsm_manifest_level_fuzz);
31
+ const fuzz = @import("../testing/fuzz.zig");
32
+ const binary_search = @import("binary_search.zig");
33
+ const lsm = @import("tree.zig");
34
+
35
+ const Key = u64;
36
+ const Value = packed struct(u128) {
37
+ key: Key,
38
+ tombstone: bool,
39
+ padding: u63 = 0,
40
+ };
41
+
42
+ inline fn key_from_value(value: *const Value) Key {
43
+ return value.key;
44
+ }
45
+
46
+ inline fn tombstone_from_key(key: Key) Value {
47
+ return .{ .key = key, .tombstone = true };
48
+ }
49
+
50
+ inline fn tombstone(value: *const Value) bool {
51
+ return value.tombstone;
52
+ }
53
+
54
+ const Table = @import("table.zig").TableType(
55
+ Key,
56
+ Value,
57
+ key_from_value,
58
+ std.math.maxInt(Key),
59
+ tombstone,
60
+ tombstone_from_key,
61
+ 1, // Doesn't matter for this test.
62
+ .general,
63
+ );
64
+
65
+ pub fn main(gpa: std.mem.Allocator, args: fuzz.FuzzArgs) !void {
66
+ var prng = stdx.PRNG.from_seed(args.seed);
67
+
68
+ const fuzz_op_count = @min(
69
+ args.events_max orelse @as(usize, 2e5),
70
+ fuzz.random_int_exponential(&prng, usize, 1e5),
71
+ );
72
+
73
+ const table_count_max_tree = 1024;
74
+ const node_size = 1024;
75
+
76
+ const fuzz_ops = try generate_fuzz_ops(gpa, &prng, table_count_max_tree, fuzz_op_count);
77
+ defer gpa.free(fuzz_ops);
78
+
79
+ const Environment = EnvironmentType(@as(u32, table_count_max_tree), node_size);
80
+ var env = try Environment.init(gpa, &prng);
81
+ try env.run_fuzz_ops(fuzz_ops);
82
+ try env.deinit(gpa);
83
+ }
84
+
85
+ const FuzzOpTag = std.meta.Tag(FuzzOp);
86
+ const FuzzOp = union(enum) {
87
+ insert_tables: usize,
88
+ update_tables: usize,
89
+ take_snapshot,
90
+ remove_invisible: usize,
91
+ remove_visible: usize,
92
+ };
93
+
94
+ // TODO: Pretty arbitrary.
95
+ const max_tables_per_insert = 10;
96
+
97
+ fn generate_fuzz_ops(
98
+ gpa: std.mem.Allocator,
99
+ prng: *stdx.PRNG,
100
+ table_count_max_tree: usize,
101
+ fuzz_op_count: usize,
102
+ ) ![]const FuzzOp {
103
+ log.info("fuzz_op_count = {}", .{fuzz_op_count});
104
+
105
+ const fuzz_ops = try gpa.alloc(FuzzOp, fuzz_op_count);
106
+ errdefer gpa.free(fuzz_ops);
107
+
108
+ // TODO: These seem good enough, but we should find proper distributions.
109
+ const fuzz_op_weights = stdx.PRNG.EnumWeightsType(FuzzOpTag){
110
+ .insert_tables = 8,
111
+ .update_tables = 5,
112
+ .take_snapshot = 3,
113
+ .remove_invisible = 3,
114
+ .remove_visible = 3,
115
+ };
116
+ log.info("fuzz_op_weights = {:.2}", .{fuzz_op_weights});
117
+
118
+ var ctx = GenerateContext{ .max_inserted = table_count_max_tree, .prng = prng };
119
+ for (fuzz_ops) |*fuzz_op| {
120
+ const fuzz_op_tag = prng.enum_weighted(FuzzOpTag, fuzz_op_weights);
121
+ fuzz_op.* = ctx.next(fuzz_op_tag);
122
+ }
123
+
124
+ return fuzz_ops;
125
+ }
126
+
127
+ const GenerateContext = struct {
128
+ inserted: usize = 0,
129
+ updated: usize = 0,
130
+ invisible: usize = 0,
131
+ max_inserted: usize,
132
+ prng: *stdx.PRNG,
133
+
134
+ fn next(ctx: *GenerateContext, fuzz_op_tag: FuzzOpTag) FuzzOp {
135
+ switch (fuzz_op_tag) {
136
+ .insert_tables => {
137
+ // If there's no room for new tables, existing ones should be removed.
138
+ const insertable = @min(ctx.max_inserted - ctx.inserted, max_tables_per_insert);
139
+ if (insertable == 0) {
140
+ // Decide whether to remove visible or invisible tables:
141
+ if (ctx.invisible > 0) return ctx.next(.remove_invisible);
142
+ return ctx.next(.remove_visible);
143
+ }
144
+
145
+ const amount = ctx.prng.range_inclusive(usize, 1, insertable);
146
+ ctx.inserted += amount;
147
+ assert(ctx.invisible <= ctx.inserted);
148
+ assert(ctx.invisible + ctx.updated <= ctx.inserted);
149
+ return FuzzOp{ .insert_tables = amount };
150
+ },
151
+ .update_tables => {
152
+ // If there's no tables visible to snapshot_latest to update, make more tables.
153
+ const visible_latest = (ctx.inserted - ctx.invisible) - ctx.updated;
154
+ if (visible_latest == 0) return ctx.next(.insert_tables);
155
+
156
+ // Decide if all, or tables visible to snapshot_latest should be updated.
157
+ const amount = if (ctx.prng.boolean())
158
+ visible_latest
159
+ else
160
+ ctx.prng.range_inclusive(usize, 1, visible_latest);
161
+
162
+ ctx.updated += amount;
163
+ assert(ctx.invisible <= ctx.inserted);
164
+ assert(ctx.invisible + ctx.updated <= ctx.inserted);
165
+ return FuzzOp{ .update_tables = amount };
166
+ },
167
+ .take_snapshot => {
168
+ ctx.invisible += ctx.updated;
169
+ ctx.updated = 0;
170
+ return FuzzOp.take_snapshot;
171
+ },
172
+ .remove_invisible => {
173
+ // Decide what to do if there's no invisible tables to be removed:
174
+ const invisible = ctx.invisible;
175
+ if (invisible == 0) {
176
+ // Either insert more tables to later be made invisible,
177
+ // update currently inserted tables to be made invisible on the next snapshot,
178
+ // or take a snapshot to make existing updated tables invisible for next remove.
179
+ if (ctx.inserted == 0) return ctx.next(.insert_tables);
180
+ if (ctx.updated == 0) return ctx.next(.update_tables);
181
+ return ctx.next(.take_snapshot);
182
+ }
183
+
184
+ // Decide if all invisible tables should be removed.
185
+ const amount = if (ctx.prng.boolean())
186
+ invisible
187
+ else
188
+ ctx.prng.range_inclusive(usize, 1, invisible);
189
+
190
+ ctx.inserted -= amount;
191
+ ctx.invisible -= amount;
192
+ assert(ctx.invisible <= ctx.inserted);
193
+ assert(ctx.invisible + ctx.updated <= ctx.inserted);
194
+ return FuzzOp{ .remove_invisible = amount };
195
+ },
196
+ .remove_visible => {
197
+ // If there are no tables visible to snapshot_latest for removal,
198
+ // we either create new ones for future removal or remove invisible ones.
199
+ const visible_latest = (ctx.inserted - ctx.invisible) - ctx.updated;
200
+ if (visible_latest == 0) {
201
+ if (ctx.inserted < ctx.max_inserted) return ctx.next(.insert_tables);
202
+ return ctx.next(.remove_invisible);
203
+ }
204
+
205
+ // Decide if all tables visible to snapshot_latest should be removed.
206
+ const amount = if (ctx.prng.boolean())
207
+ visible_latest
208
+ else
209
+ ctx.prng.range_inclusive(usize, 1, visible_latest);
210
+
211
+ ctx.inserted -= amount;
212
+ assert(ctx.invisible <= ctx.inserted);
213
+ assert(ctx.invisible + ctx.updated <= ctx.inserted);
214
+ return FuzzOp{ .remove_visible = amount };
215
+ },
216
+ }
217
+ }
218
+ };
219
+
220
+ pub fn EnvironmentType(comptime table_count_max_tree: u32, comptime node_size: u32) type {
221
+ return struct {
222
+ const Environment = @This();
223
+
224
+ const TableBuffer = std.ArrayList(TableInfo);
225
+ const NodePool = @import("node_pool.zig").NodePoolType(node_size, @alignOf(TableInfo));
226
+ pub const ManifestLevel = @import("manifest_level.zig").ManifestLevelType(
227
+ NodePool,
228
+ Key,
229
+ TableInfo,
230
+ table_count_max_tree,
231
+ );
232
+ pub const TableInfo = @import("manifest.zig").TreeTableInfoType(Table);
233
+ pool: NodePool,
234
+ level: ManifestLevel,
235
+ buffer: TableBuffer,
236
+ tables: TableBuffer,
237
+ prng: *stdx.PRNG,
238
+ snapshot: u64,
239
+
240
+ pub fn init(gpa: std.mem.Allocator, prng: *stdx.PRNG) !Environment {
241
+ var env: Environment = undefined;
242
+
243
+ const node_pool_size = ManifestLevel.Keys.node_count_max +
244
+ ManifestLevel.Tables.node_count_max;
245
+ try env.pool.init(gpa, node_pool_size);
246
+ errdefer env.pool.deinit(gpa);
247
+
248
+ try env.level.init(gpa, &env.pool);
249
+ errdefer env.level.deinit(gpa, &env.pool);
250
+
251
+ env.buffer = TableBuffer.init(gpa);
252
+ errdefer env.buffer.deinit();
253
+
254
+ env.tables = TableBuffer.init(gpa);
255
+ errdefer env.tables.deinit();
256
+
257
+ env.prng = prng;
258
+ env.snapshot = 1; // the first snapshot is reserved.
259
+ return env;
260
+ }
261
+
262
+ pub fn deinit(env: *Environment, gpa: std.mem.Allocator) !void {
263
+ env.tables.deinit();
264
+ env.buffer.deinit();
265
+ env.level.deinit(gpa, &env.pool);
266
+ env.pool.deinit(gpa);
267
+ }
268
+
269
+ pub fn run_fuzz_ops(env: *Environment, fuzz_ops: []const FuzzOp) !void {
270
+ for (fuzz_ops, 0..) |fuzz_op, op_index| {
271
+ log.debug("Running fuzz_ops[{}/{}] == {}", .{ op_index, fuzz_ops.len, fuzz_op });
272
+ switch (fuzz_op) {
273
+ .insert_tables => |amount| try env.insert_tables(amount),
274
+ .update_tables => |amount| try env.update_tables(amount),
275
+ .take_snapshot => try env.take_snapshot(),
276
+ .remove_invisible => |amount| try env.remove_invisible(amount),
277
+ .remove_visible => |amount| try env.remove_visible(amount),
278
+ }
279
+ }
280
+ }
281
+
282
+ pub fn insert_tables(env: *Environment, amount: usize) !void {
283
+ assert(amount > 0);
284
+ assert(env.buffer.items.len == 0);
285
+
286
+ // Generate random, non-overlapping TableInfo's into env.buffer:
287
+ {
288
+ var insert_amount = amount;
289
+ var key = env.prng.int_inclusive(Key, table_count_max_tree * 64);
290
+
291
+ while (insert_amount > 0) : (insert_amount -= 1) {
292
+ const table = env.generate_non_overlapping_table(key);
293
+ try env.buffer.append(table);
294
+ key = table.key_max;
295
+ }
296
+ }
297
+
298
+ const tables = env.buffer.items;
299
+ defer env.buffer.clearRetainingCapacity();
300
+
301
+ // Insert the generated tables into the ManifestLevel:
302
+ for (tables) |*table| {
303
+ assert(table.visible(env.snapshot));
304
+ assert(table.visible(lsm.snapshot_latest));
305
+ env.level.insert_table(&env.pool, table);
306
+ }
307
+
308
+ // Insert the generated tables into the Environment for reference:
309
+ for (tables) |*table| {
310
+ const index = binary_search.binary_search_values_upsert_index(
311
+ Key,
312
+ TableInfo,
313
+ key_min_from_table,
314
+ env.tables.items,
315
+ table.key_max,
316
+ .{},
317
+ );
318
+
319
+ // Can't be equal as the tables may not overlap.
320
+ if (index < env.tables.items.len) {
321
+ assert(env.tables.items[index].key_min > table.key_max);
322
+ }
323
+
324
+ try env.tables.insert(index, table.*);
325
+ }
326
+ }
327
+
328
+ fn generate_non_overlapping_table(env: *Environment, key: Key) TableInfo {
329
+ var new_key_min = key + env.prng.int_inclusive(Key, 30) + 1;
330
+ assert(new_key_min > key);
331
+
332
+ const i = binary_search.binary_search_values_upsert_index(
333
+ Key,
334
+ TableInfo,
335
+ key_min_from_table,
336
+ env.tables.items,
337
+ new_key_min,
338
+ .{},
339
+ );
340
+
341
+ if (i > 0) {
342
+ if (new_key_min <= env.tables.items[i - 1].key_max) {
343
+ new_key_min = env.tables.items[i - 1].key_max + 1;
344
+ }
345
+ }
346
+
347
+ const next_key_min = for (env.tables.items[i..]) |table| {
348
+ switch (std.math.order(new_key_min, table.key_min)) {
349
+ .lt => break table.key_min,
350
+ .eq => new_key_min = table.key_max + 1,
351
+ .gt => unreachable,
352
+ }
353
+ } else std.math.maxInt(Key);
354
+
355
+ const max_delta = @min(32, next_key_min - 1 - new_key_min);
356
+ const new_key_max = new_key_min + env.prng.int_inclusive(Key, max_delta);
357
+
358
+ return .{
359
+ .checksum = env.prng.int(u128),
360
+ // Zero addresses are used to indicate the table being removed.
361
+ .address = env.prng.int(u64) +| 1,
362
+ .snapshot_min = env.snapshot,
363
+ .key_min = new_key_min,
364
+ .key_max = new_key_max,
365
+ .value_count = 64,
366
+ };
367
+ }
368
+
369
+ inline fn key_min_from_table(table: *const TableInfo) Key {
370
+ return table.key_min;
371
+ }
372
+
373
+ fn update_tables(env: *Environment, amount: usize) !void {
374
+ var update_amount = amount;
375
+ assert(amount > 0);
376
+
377
+ // Only update the snapshot_max of those visible to snapshot_latest.
378
+ // Those visible to env.snapshot would include tables with updated snapshot_max.
379
+ const snapshots = @as(*const [1]u64, &lsm.snapshot_latest);
380
+
381
+ var it = env.level.iterator(.visible, snapshots, .descending, null);
382
+ while (it.next()) |level_table| {
383
+ assert(level_table.visible(env.snapshot));
384
+ assert(level_table.visible(lsm.snapshot_latest));
385
+
386
+ const env_table = env.find_exact(level_table);
387
+ assert(level_table.equal(env_table));
388
+
389
+ env.level.set_snapshot_max(env.snapshot, .{
390
+ .table_info = level_table,
391
+ .generation = env.level.generation,
392
+ });
393
+ // This is required to keep the table in the fuzzer's environment consistent with
394
+ // the table in the ManifestLevel.
395
+ env_table.snapshot_max = env.snapshot;
396
+ assert(level_table.snapshot_max == env.snapshot);
397
+ assert(!level_table.visible(lsm.snapshot_latest));
398
+ assert(level_table.visible(env.snapshot));
399
+
400
+ update_amount -= 1;
401
+ if (update_amount == 0) break;
402
+ }
403
+
404
+ assert(update_amount == 0);
405
+ }
406
+
407
+ fn find_exact(env: *Environment, level_table: *const TableInfo) *TableInfo {
408
+ const index = binary_search.binary_search_values_upsert_index(
409
+ Key,
410
+ TableInfo,
411
+ key_min_from_table,
412
+ env.tables.items,
413
+ level_table.key_min,
414
+ .{},
415
+ );
416
+
417
+ assert(index < env.tables.items.len);
418
+ const tables = env.tables.items[index..];
419
+
420
+ assert(tables[0].key_min == level_table.key_min);
421
+ for (tables) |*env_table| {
422
+ if (env_table.key_max == level_table.key_max) {
423
+ return env_table;
424
+ }
425
+ }
426
+
427
+ std.debug.panic("table not found in fuzzer reference model: {any}", .{level_table.*});
428
+ }
429
+
430
+ fn take_snapshot(env: *Environment) !void {
431
+ env.snapshot += 1;
432
+ assert(env.snapshot < lsm.snapshot_latest);
433
+ }
434
+
435
+ fn remove_invisible(env: *Environment, amount: usize) !void {
436
+ var remove_amount = amount;
437
+ assert(amount > 0);
438
+
439
+ // Remove tables not visible to the current snapshot.
440
+ const snapshots = [_]u64{env.snapshot};
441
+
442
+ // Remove invisible tables from ManifestLevel and mark them as removed in env.tables:
443
+ var it = env.level.iterator(.invisible, &snapshots, .descending, null);
444
+ while (it.next()) |level_table| {
445
+ env.mark_removed_table(level_table);
446
+
447
+ assert(level_table.invisible(&snapshots));
448
+ var level_table_copy = level_table.*;
449
+ env.level.remove_table(&env.pool, &level_table_copy);
450
+
451
+ remove_amount -= 1;
452
+ if (remove_amount == 0) break;
453
+ }
454
+
455
+ assert(remove_amount == 0);
456
+ try env.purge_removed_tables();
457
+ }
458
+
459
+ fn remove_visible(env: *Environment, amount: usize) !void {
460
+ var remove_amount = amount;
461
+ assert(amount > 0);
462
+
463
+ // ManifestLevel.remove_table_visible() only removes those visible to snapshot_latest.
464
+ const snapshots = @as(*const [1]u64, &lsm.snapshot_latest);
465
+
466
+ // Remove visible tables from ManifestLevel and mark them as removed in env.tables:
467
+ var it = env.level.iterator(.visible, snapshots, .descending, null);
468
+ while (it.next()) |level_table| {
469
+ env.mark_removed_table(level_table);
470
+
471
+ assert(level_table.visible(lsm.snapshot_latest));
472
+ var level_table_copy = level_table.*;
473
+ env.level.remove_table(&env.pool, &level_table_copy);
474
+
475
+ remove_amount -= 1;
476
+ if (remove_amount == 0) break;
477
+ }
478
+
479
+ assert(remove_amount == 0);
480
+ try env.purge_removed_tables();
481
+ }
482
+
483
+ /// Mark the matching table as removed in env.tables.
484
+ /// It will be removed from env.tables from a later call to env.purge_removed_tables().
485
+ fn mark_removed_table(env: *Environment, level_table: *const TableInfo) void {
486
+ const env_table = env.find_exact(level_table);
487
+ assert(level_table.equal(env_table));
488
+
489
+ // Zero address means the table is removed.
490
+ assert(env_table.address != 0);
491
+ env_table.address = 0;
492
+ }
493
+
494
+ /// Filter out all env.tables removed with env.mark_removed_table() by copying all
495
+ /// non-removed tables into env.buffer and flipping it with env.tables.
496
+ /// TODO: This clears removed tables in O(n).
497
+ fn purge_removed_tables(env: *Environment) !void {
498
+ assert(env.buffer.items.len == 0);
499
+ try env.buffer.ensureTotalCapacity(env.tables.items.len);
500
+
501
+ for (env.tables.items) |*table| {
502
+ if (table.address == 0) continue;
503
+ try env.buffer.append(table.*);
504
+ }
505
+
506
+ std.mem.swap(TableBuffer, &env.buffer, &env.tables);
507
+ env.buffer.clearRetainingCapacity();
508
+ }
509
+ };
510
+ }