pigeonhole-db 1.1.0

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 (1256) hide show
  1. checksums.yaml +7 -0
  2. data/Cargo.lock +899 -0
  3. data/Cargo.toml +45 -0
  4. data/LICENSE +21 -0
  5. data/README.md +22 -0
  6. data/extconf.rb +12 -0
  7. data/lib/pigeonhole/api.rb +615 -0
  8. data/lib/pigeonhole/index.rb +208 -0
  9. data/lib/pigeonhole/memory.rb +507 -0
  10. data/lib/pigeonhole/version.rb +6 -0
  11. data/lib/pigeonhole-db.rb +6 -0
  12. data/lib/pigeonhole.rb +47 -0
  13. data/sig/pigeonhole.rbs +1484 -0
  14. data/src/budget.rs +205 -0
  15. data/src/classes.rs +279 -0
  16. data/src/convert.rs +192 -0
  17. data/src/db.rs +685 -0
  18. data/src/error.rs +151 -0
  19. data/src/feed.rs +316 -0
  20. data/src/fork.rs +64 -0
  21. data/src/gvl.rs +112 -0
  22. data/src/index.rs +1157 -0
  23. data/src/lib.rs +534 -0
  24. data/src/memory.rs +2178 -0
  25. data/src/read.rs +312 -0
  26. data/src/table.rs +1161 -0
  27. data/src/vector.rs +262 -0
  28. data/src/walk.rs +406 -0
  29. data/vendor/bundle/ruby/3.4.0/bin/minitest +29 -0
  30. data/vendor/bundle/ruby/3.4.0/bin/rake +29 -0
  31. data/vendor/bundle/ruby/3.4.0/bin/rake-compiler +29 -0
  32. data/vendor/bundle/ruby/3.4.0/bin/rake-compiler-dock +29 -0
  33. data/vendor/bundle/ruby/3.4.0/bin/rb-sys-dock +29 -0
  34. data/vendor/bundle/ruby/3.4.0/bin/rbs +29 -0
  35. data/vendor/bundle/ruby/3.4.0/cache/drb-2.2.3.gem +0 -0
  36. data/vendor/bundle/ruby/3.4.0/cache/logger-1.7.0.gem +0 -0
  37. data/vendor/bundle/ruby/3.4.0/cache/minitest-6.0.6.gem +0 -0
  38. data/vendor/bundle/ruby/3.4.0/cache/prism-1.9.0.gem +0 -0
  39. data/vendor/bundle/ruby/3.4.0/cache/rake-13.4.2.gem +0 -0
  40. data/vendor/bundle/ruby/3.4.0/cache/rake-compiler-1.3.2.gem +0 -0
  41. data/vendor/bundle/ruby/3.4.0/cache/rake-compiler-dock-1.12.0.gem +0 -0
  42. data/vendor/bundle/ruby/3.4.0/cache/rb_sys-0.9.130.gem +0 -0
  43. data/vendor/bundle/ruby/3.4.0/cache/rbs-4.2.0.gem +0 -0
  44. data/vendor/bundle/ruby/3.4.0/cache/toml-rb-6.0.0.gem +0 -0
  45. data/vendor/bundle/ruby/3.4.0/cache/tsort-0.2.0.gem +0 -0
  46. data/vendor/bundle/ruby/3.4.0/extensions/x86_64-linux/3.4.0/prism-1.9.0/gem.build_complete +0 -0
  47. data/vendor/bundle/ruby/3.4.0/extensions/x86_64-linux/3.4.0/prism-1.9.0/gem_make.out +44 -0
  48. data/vendor/bundle/ruby/3.4.0/extensions/x86_64-linux/3.4.0/prism-1.9.0/mkmf.log +74 -0
  49. data/vendor/bundle/ruby/3.4.0/extensions/x86_64-linux/3.4.0/prism-1.9.0/prism/prism.so +0 -0
  50. data/vendor/bundle/ruby/3.4.0/extensions/x86_64-linux/3.4.0/rbs-4.2.0/gem.build_complete +0 -0
  51. data/vendor/bundle/ruby/3.4.0/extensions/x86_64-linux/3.4.0/rbs-4.2.0/gem_make.out +41 -0
  52. data/vendor/bundle/ruby/3.4.0/extensions/x86_64-linux/3.4.0/rbs-4.2.0/mkmf.log +102 -0
  53. data/vendor/bundle/ruby/3.4.0/extensions/x86_64-linux/3.4.0/rbs-4.2.0/rbs_extension.so +0 -0
  54. data/vendor/bundle/ruby/3.4.0/gems/drb-2.2.3/LICENSE.txt +22 -0
  55. data/vendor/bundle/ruby/3.4.0/gems/drb-2.2.3/drb.gemspec +42 -0
  56. data/vendor/bundle/ruby/3.4.0/gems/drb-2.2.3/lib/drb/acl.rb +239 -0
  57. data/vendor/bundle/ruby/3.4.0/gems/drb-2.2.3/lib/drb/drb.rb +1993 -0
  58. data/vendor/bundle/ruby/3.4.0/gems/drb-2.2.3/lib/drb/eq.rb +15 -0
  59. data/vendor/bundle/ruby/3.4.0/gems/drb-2.2.3/lib/drb/extserv.rb +44 -0
  60. data/vendor/bundle/ruby/3.4.0/gems/drb-2.2.3/lib/drb/extservm.rb +94 -0
  61. data/vendor/bundle/ruby/3.4.0/gems/drb-2.2.3/lib/drb/gw.rb +161 -0
  62. data/vendor/bundle/ruby/3.4.0/gems/drb-2.2.3/lib/drb/observer.rb +26 -0
  63. data/vendor/bundle/ruby/3.4.0/gems/drb-2.2.3/lib/drb/ssl.rb +354 -0
  64. data/vendor/bundle/ruby/3.4.0/gems/drb-2.2.3/lib/drb/timeridconv.rb +97 -0
  65. data/vendor/bundle/ruby/3.4.0/gems/drb-2.2.3/lib/drb/unix.rb +118 -0
  66. data/vendor/bundle/ruby/3.4.0/gems/drb-2.2.3/lib/drb/version.rb +3 -0
  67. data/vendor/bundle/ruby/3.4.0/gems/drb-2.2.3/lib/drb/weakidconv.rb +31 -0
  68. data/vendor/bundle/ruby/3.4.0/gems/drb-2.2.3/lib/drb.rb +3 -0
  69. data/vendor/bundle/ruby/3.4.0/gems/logger-1.7.0/BSDL +22 -0
  70. data/vendor/bundle/ruby/3.4.0/gems/logger-1.7.0/COPYING +56 -0
  71. data/vendor/bundle/ruby/3.4.0/gems/logger-1.7.0/README.md +104 -0
  72. data/vendor/bundle/ruby/3.4.0/gems/logger-1.7.0/lib/logger/errors.rb +9 -0
  73. data/vendor/bundle/ruby/3.4.0/gems/logger-1.7.0/lib/logger/formatter.rb +36 -0
  74. data/vendor/bundle/ruby/3.4.0/gems/logger-1.7.0/lib/logger/log_device.rb +265 -0
  75. data/vendor/bundle/ruby/3.4.0/gems/logger-1.7.0/lib/logger/period.rb +47 -0
  76. data/vendor/bundle/ruby/3.4.0/gems/logger-1.7.0/lib/logger/severity.rb +38 -0
  77. data/vendor/bundle/ruby/3.4.0/gems/logger-1.7.0/lib/logger/version.rb +5 -0
  78. data/vendor/bundle/ruby/3.4.0/gems/logger-1.7.0/lib/logger.rb +789 -0
  79. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/History.rdoc +1860 -0
  80. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/Manifest.txt +41 -0
  81. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/README.rdoc +763 -0
  82. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/Rakefile +89 -0
  83. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/bin/minitest +5 -0
  84. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/design_rationale.rb +54 -0
  85. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/lib/hoe/minitest.rb +30 -0
  86. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/lib/minitest/assertions.rb +821 -0
  87. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/lib/minitest/autorun.rb +5 -0
  88. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/lib/minitest/benchmark.rb +452 -0
  89. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/lib/minitest/bisect.rb +304 -0
  90. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/lib/minitest/complete.rb +56 -0
  91. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/lib/minitest/compress.rb +94 -0
  92. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/lib/minitest/error_on_warning.rb +11 -0
  93. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/lib/minitest/expectations.rb +321 -0
  94. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/lib/minitest/find_minimal_combination.rb +127 -0
  95. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/lib/minitest/hell.rb +11 -0
  96. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/lib/minitest/manual_plugins.rb +4 -0
  97. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/lib/minitest/parallel.rb +72 -0
  98. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/lib/minitest/path_expander.rb +432 -0
  99. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/lib/minitest/pride.rb +4 -0
  100. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/lib/minitest/pride_plugin.rb +135 -0
  101. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/lib/minitest/server.rb +49 -0
  102. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/lib/minitest/server_plugin.rb +88 -0
  103. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/lib/minitest/spec.rb +324 -0
  104. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/lib/minitest/sprint.rb +105 -0
  105. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/lib/minitest/sprint_plugin.rb +39 -0
  106. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/lib/minitest/test.rb +232 -0
  107. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/lib/minitest/test_task.rb +331 -0
  108. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/lib/minitest.rb +1232 -0
  109. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/test/minitest/metametameta.rb +150 -0
  110. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/test/minitest/test_bisect.rb +249 -0
  111. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/test/minitest/test_find_minimal_combination.rb +138 -0
  112. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/test/minitest/test_minitest_assertions.rb +1729 -0
  113. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/test/minitest/test_minitest_benchmark.rb +151 -0
  114. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/test/minitest/test_minitest_reporter.rb +437 -0
  115. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/test/minitest/test_minitest_spec.rb +1095 -0
  116. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/test/minitest/test_minitest_test.rb +1295 -0
  117. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/test/minitest/test_minitest_test_task.rb +57 -0
  118. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/test/minitest/test_path_expander.rb +229 -0
  119. data/vendor/bundle/ruby/3.4.0/gems/minitest-6.0.6/test/minitest/test_server.rb +146 -0
  120. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/BSDmakefile +58 -0
  121. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/CHANGELOG.md +786 -0
  122. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/CODE_OF_CONDUCT.md +76 -0
  123. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/CONTRIBUTING.md +58 -0
  124. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/LICENSE.md +7 -0
  125. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/Makefile +116 -0
  126. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/README.md +143 -0
  127. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/config.yml +4739 -0
  128. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/docs/build_system.md +119 -0
  129. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/docs/configuration.md +68 -0
  130. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/docs/cruby_compilation.md +27 -0
  131. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/docs/design.md +53 -0
  132. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/docs/encoding.md +121 -0
  133. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/docs/fuzzing.md +88 -0
  134. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/docs/heredocs.md +36 -0
  135. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/docs/javascript.md +118 -0
  136. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/docs/local_variable_depth.md +229 -0
  137. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/docs/mapping.md +117 -0
  138. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/docs/parser_translation.md +24 -0
  139. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/docs/parsing_rules.md +22 -0
  140. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/docs/releasing.md +75 -0
  141. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/docs/relocation.md +34 -0
  142. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/docs/ripper_translation.md +63 -0
  143. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/docs/ruby_api.md +45 -0
  144. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/docs/ruby_parser_translation.md +19 -0
  145. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/docs/serialization.md +233 -0
  146. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/docs/testing.md +55 -0
  147. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/ext/prism/Makefile +273 -0
  148. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/ext/prism/api_node.c +6945 -0
  149. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/ext/prism/api_pack.c +276 -0
  150. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/ext/prism/extconf.rb +127 -0
  151. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/ext/prism/extension.c +1427 -0
  152. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/ext/prism/extension.h +19 -0
  153. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/include/prism/ast.h +8254 -0
  154. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/include/prism/defines.h +260 -0
  155. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/include/prism/diagnostic.h +458 -0
  156. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/include/prism/encoding.h +283 -0
  157. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/include/prism/node.h +129 -0
  158. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/include/prism/options.h +488 -0
  159. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/include/prism/pack.h +163 -0
  160. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/include/prism/parser.h +936 -0
  161. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/include/prism/prettyprint.h +34 -0
  162. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/include/prism/regexp.h +43 -0
  163. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/include/prism/static_literals.h +121 -0
  164. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/include/prism/util/pm_buffer.h +236 -0
  165. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/include/prism/util/pm_char.h +204 -0
  166. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/include/prism/util/pm_constant_pool.h +218 -0
  167. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/include/prism/util/pm_integer.h +130 -0
  168. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/include/prism/util/pm_list.h +103 -0
  169. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/include/prism/util/pm_memchr.h +29 -0
  170. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/include/prism/util/pm_newline_list.h +113 -0
  171. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/include/prism/util/pm_string.h +200 -0
  172. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/include/prism/util/pm_strncasecmp.h +32 -0
  173. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/include/prism/util/pm_strpbrk.h +46 -0
  174. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/include/prism/version.h +29 -0
  175. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/include/prism.h +408 -0
  176. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/compiler.rb +801 -0
  177. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/desugar_compiler.rb +392 -0
  178. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/dispatcher.rb +2210 -0
  179. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/dot_visitor.rb +4767 -0
  180. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/dsl.rb +1003 -0
  181. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/ffi.rb +578 -0
  182. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/inspect_visitor.rb +2393 -0
  183. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/lex_compat.rb +911 -0
  184. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/mutation_compiler.rb +772 -0
  185. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/node.rb +19966 -0
  186. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/node_ext.rb +511 -0
  187. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/pack.rb +230 -0
  188. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/parse_result/comments.rb +188 -0
  189. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/parse_result/errors.rb +66 -0
  190. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/parse_result/newlines.rb +155 -0
  191. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/parse_result.rb +907 -0
  192. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/pattern.rb +269 -0
  193. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/polyfill/append_as_bytes.rb +15 -0
  194. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/polyfill/byteindex.rb +13 -0
  195. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/polyfill/scan_byte.rb +14 -0
  196. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/polyfill/unpack1.rb +14 -0
  197. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/polyfill/warn.rb +36 -0
  198. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/prism.so +0 -0
  199. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/reflection.rb +416 -0
  200. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/relocation.rb +505 -0
  201. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/serialize.rb +2400 -0
  202. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/string_query.rb +31 -0
  203. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/translation/parser/builder.rb +62 -0
  204. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/translation/parser/compiler.rb +2234 -0
  205. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/translation/parser/lexer.rb +820 -0
  206. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/translation/parser.rb +376 -0
  207. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/translation/parser_current.rb +26 -0
  208. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/translation/parser_versions.rb +36 -0
  209. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/translation/ripper/filter.rb +53 -0
  210. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/translation/ripper/lexer.rb +135 -0
  211. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/translation/ripper/sexp.rb +126 -0
  212. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/translation/ripper/shim.rb +5 -0
  213. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/translation/ripper.rb +3520 -0
  214. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/translation/ruby_parser.rb +1964 -0
  215. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/translation.rb +18 -0
  216. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism/visitor.rb +813 -0
  217. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/lib/prism.rb +98 -0
  218. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/prism.gemspec +172 -0
  219. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/rbi/prism/compiler.rbi +12 -0
  220. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/rbi/prism/dsl.rbi +524 -0
  221. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/rbi/prism/inspect_visitor.rbi +12 -0
  222. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/rbi/prism/node.rbi +8750 -0
  223. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/rbi/prism/node_ext.rbi +107 -0
  224. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/rbi/prism/parse_result.rbi +404 -0
  225. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/rbi/prism/reflection.rbi +58 -0
  226. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/rbi/prism/string_query.rbi +12 -0
  227. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/rbi/prism/translation/parser.rbi +11 -0
  228. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/rbi/prism/translation/parser_versions.rbi +23 -0
  229. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/rbi/prism/translation/ripper.rbi +15 -0
  230. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/rbi/prism/visitor.rbi +473 -0
  231. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/rbi/prism.rbi +63 -0
  232. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/sig/prism/compiler.rbs +9 -0
  233. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/sig/prism/dispatcher.rbs +19 -0
  234. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/sig/prism/dot_visitor.rbs +6 -0
  235. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/sig/prism/dsl.rbs +351 -0
  236. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/sig/prism/inspect_visitor.rbs +22 -0
  237. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/sig/prism/lex_compat.rbs +10 -0
  238. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/sig/prism/mutation_compiler.rbs +159 -0
  239. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/sig/prism/node.rbs +4042 -0
  240. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/sig/prism/node_ext.rbs +149 -0
  241. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/sig/prism/pack.rbs +43 -0
  242. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/sig/prism/parse_result/comments.rbs +38 -0
  243. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/sig/prism/parse_result.rbs +197 -0
  244. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/sig/prism/pattern.rbs +13 -0
  245. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/sig/prism/reflection.rbs +50 -0
  246. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/sig/prism/relocation.rbs +185 -0
  247. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/sig/prism/serialize.rbs +8 -0
  248. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/sig/prism/string_query.rbs +11 -0
  249. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/sig/prism/visitor.rbs +169 -0
  250. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/sig/prism.rbs +272 -0
  251. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/src/diagnostic.c +854 -0
  252. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/src/encoding.c +5340 -0
  253. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/src/node.c +8685 -0
  254. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/src/options.c +338 -0
  255. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/src/pack.c +509 -0
  256. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/src/prettyprint.c +8957 -0
  257. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/src/prism.c +22679 -0
  258. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/src/regexp.c +790 -0
  259. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/src/serialize.c +2274 -0
  260. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/src/static_literals.c +617 -0
  261. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/src/token_type.c +703 -0
  262. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/src/util/pm_buffer.c +357 -0
  263. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/src/util/pm_char.c +318 -0
  264. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/src/util/pm_constant_pool.c +342 -0
  265. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/src/util/pm_integer.c +670 -0
  266. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/src/util/pm_list.c +49 -0
  267. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/src/util/pm_memchr.c +35 -0
  268. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/src/util/pm_newline_list.c +125 -0
  269. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/src/util/pm_string.c +381 -0
  270. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/src/util/pm_strncasecmp.c +36 -0
  271. data/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/src/util/pm_strpbrk.c +206 -0
  272. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/History.rdoc +2454 -0
  273. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/MIT-LICENSE +21 -0
  274. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/README.rdoc +155 -0
  275. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/doc/command_line_usage.rdoc +171 -0
  276. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/doc/example/Rakefile1 +38 -0
  277. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/doc/example/Rakefile2 +35 -0
  278. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/doc/example/a.c +6 -0
  279. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/doc/example/b.c +6 -0
  280. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/doc/example/main.c +11 -0
  281. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/doc/glossary.rdoc +42 -0
  282. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/doc/jamis.rb +592 -0
  283. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/doc/proto_rake.rdoc +127 -0
  284. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/doc/rake.1 +156 -0
  285. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/doc/rakefile.rdoc +635 -0
  286. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/doc/rational.rdoc +151 -0
  287. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/exe/rake +27 -0
  288. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/application.rb +847 -0
  289. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/backtrace.rb +25 -0
  290. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/clean.rb +78 -0
  291. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/cloneable.rb +17 -0
  292. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/cpu_counter.rb +122 -0
  293. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/default_loader.rb +15 -0
  294. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/dsl_definition.rb +196 -0
  295. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/early_time.rb +22 -0
  296. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/ext/core.rb +26 -0
  297. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/ext/string.rb +176 -0
  298. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/file_creation_task.rb +25 -0
  299. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/file_list.rb +435 -0
  300. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/file_task.rb +58 -0
  301. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/file_utils.rb +137 -0
  302. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/file_utils_ext.rb +135 -0
  303. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/invocation_chain.rb +57 -0
  304. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/invocation_exception_mixin.rb +17 -0
  305. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/late_time.rb +18 -0
  306. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/linked_list.rb +112 -0
  307. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/loaders/makefile.rb +54 -0
  308. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/multi_task.rb +14 -0
  309. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/name_space.rb +38 -0
  310. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/options.rb +31 -0
  311. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/packagetask.rb +222 -0
  312. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/phony.rb +16 -0
  313. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/private_reader.rb +21 -0
  314. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/promise.rb +100 -0
  315. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/pseudo_status.rb +30 -0
  316. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/rake_module.rb +67 -0
  317. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/rake_test_loader.rb +27 -0
  318. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/rule_recursion_overflow_error.rb +20 -0
  319. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/scope.rb +43 -0
  320. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/task.rb +434 -0
  321. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/task_argument_error.rb +8 -0
  322. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/task_arguments.rb +113 -0
  323. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/task_manager.rb +333 -0
  324. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/tasklib.rb +12 -0
  325. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/testtask.rb +192 -0
  326. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/thread_history_display.rb +49 -0
  327. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/thread_pool.rb +157 -0
  328. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/trace_output.rb +23 -0
  329. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/version.rb +10 -0
  330. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake/win32.rb +17 -0
  331. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/lib/rake.rb +69 -0
  332. data/vendor/bundle/ruby/3.4.0/gems/rake-13.4.2/rake.gemspec +102 -0
  333. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/Gemfile +8 -0
  334. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/History.md +708 -0
  335. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/LICENSE.txt +20 -0
  336. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/README.md +505 -0
  337. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/Rakefile +15 -0
  338. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/appveyor.yml +22 -0
  339. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/bin/rake-compiler +24 -0
  340. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/cucumber.yml +4 -0
  341. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/features/compile.feature +79 -0
  342. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/features/cross-compile.feature +23 -0
  343. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/features/cross-package-multi.feature +15 -0
  344. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/features/cross-package.feature +14 -0
  345. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/features/java-compile.feature +22 -0
  346. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/features/java-no-native-compile.feature +33 -0
  347. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/features/java-package.feature +24 -0
  348. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/features/package.feature +40 -0
  349. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/features/step_definitions/compilation.rb +70 -0
  350. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/features/step_definitions/cross_compilation.rb +27 -0
  351. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/features/step_definitions/execution.rb +52 -0
  352. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/features/step_definitions/folders.rb +32 -0
  353. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/features/step_definitions/gem.rb +46 -0
  354. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/features/step_definitions/java_compilation.rb +7 -0
  355. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/features/support/env.rb +10 -0
  356. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/features/support/file_template_helpers.rb +137 -0
  357. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/features/support/generator_helpers.rb +123 -0
  358. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/features/support/platform_extension_helpers.rb +27 -0
  359. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/lib/rake/baseextensiontask.rb +90 -0
  360. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/lib/rake/compiler_config.rb +38 -0
  361. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/lib/rake/extensioncompiler.rb +51 -0
  362. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/lib/rake/extensiontask.rb +621 -0
  363. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/lib/rake/javaextensiontask.rb +321 -0
  364. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/tasks/bin/cross-ruby.rake +189 -0
  365. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/tasks/bootstrap.rake +11 -0
  366. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/tasks/common.rake +10 -0
  367. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/tasks/cucumber.rake +23 -0
  368. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/tasks/gem.rake +15 -0
  369. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-1.3.2/tasks/rspec.rake +9 -0
  370. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/CHANGELOG.md +446 -0
  371. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/CONTRIBUTING.md +109 -0
  372. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/Dockerfile.jruby +79 -0
  373. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/Dockerfile.mri.erb +282 -0
  374. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/Gemfile +8 -0
  375. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/LICENSE.txt +22 -0
  376. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/README.md +447 -0
  377. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/Rakefile +246 -0
  378. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/bin/rake-compiler-dock +18 -0
  379. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/build/buildkitd.toml +2 -0
  380. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/build/gem_helper.rb +54 -0
  381. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/build/mk_i686.rb +18 -0
  382. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/build/mk_musl_cross.sh +37 -0
  383. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/build/mk_osxcross.sh +45 -0
  384. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/build/mk_pkg_config.sh +24 -0
  385. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/build/parallel_docker_build.rb +169 -0
  386. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/build/patches/rake-compiler-1.3.1/0004-Enable-build-of-static-libruby.patch +38 -0
  387. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/build/patches/rake-compiler-1.3.1/0005-build-miniruby-first.patch +16 -0
  388. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/build/patches/rake-compiler-1.3.1/0006-ruby-4-rubyspec-capiext.patch +16 -0
  389. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/build/rcd-env.sh +6 -0
  390. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/build/runas +7 -0
  391. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/build/sigfw.c +45 -0
  392. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/build/strip_wrapper_codesign +17 -0
  393. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/build/strip_wrapper_vbox +30 -0
  394. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/build/sudoers +1 -0
  395. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/lib/rake_compiler_dock/colors.rb +43 -0
  396. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/lib/rake_compiler_dock/docker_check.rb +356 -0
  397. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/lib/rake_compiler_dock/predefined_user_group.rb +5 -0
  398. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/lib/rake_compiler_dock/starter.rb +206 -0
  399. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/lib/rake_compiler_dock/version.rb +4 -0
  400. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/lib/rake_compiler_dock.rb +151 -0
  401. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/mingw64-ucrt/Dockerfile +66 -0
  402. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/mingw64-ucrt/README.md +14 -0
  403. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/mingw64-ucrt/binutils-mingw-w64-ignore-check-errors.patch +13 -0
  404. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/mingw64-ucrt/gcc-mingw-w64-only-c-c++.patch +13 -0
  405. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/mingw64-ucrt/mingw-w64-enable-ucrt.patch +22 -0
  406. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/rake-compiler-dock.gemspec +34 -0
  407. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/test/env/Dockerfile.alpine +17 -0
  408. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/test/env/Dockerfile.debian +24 -0
  409. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/test/fixtures/mig_test_rpc.defs +8 -0
  410. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/test/rcd_test/Gemfile +11 -0
  411. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/test/rcd_test/Rakefile +97 -0
  412. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/test/rcd_test/ext/java/RcdTestExtService.java +19 -0
  413. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/test/rcd_test/ext/java/RubyRcdTest.java +16 -0
  414. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/test/rcd_test/ext/mri/extconf.rb +111 -0
  415. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/test/rcd_test/ext/mri/rcd_test_ext.c +65 -0
  416. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/test/rcd_test/ext/mri/rcd_test_ext.h +11 -0
  417. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/test/rcd_test/lib/rcd_test.rb +6 -0
  418. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/test/rcd_test/rcd_test.gemspec +28 -0
  419. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/test/rcd_test/test/test_basic.rb +49 -0
  420. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/test/test_environment_variables.rb +108 -0
  421. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/test/test_mig.rb +18 -0
  422. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/test/test_parallel_docker_build.rb +95 -0
  423. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/test/test_rubygems_plugins.rb +12 -0
  424. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/test/test_starter.rb +158 -0
  425. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.12.0/test/test_versions.rb +82 -0
  426. data/vendor/bundle/ruby/3.4.0/gems/rb_sys-0.9.130/LICENSE-APACHE +190 -0
  427. data/vendor/bundle/ruby/3.4.0/gems/rb_sys-0.9.130/LICENSE-MIT +21 -0
  428. data/vendor/bundle/ruby/3.4.0/gems/rb_sys-0.9.130/README.md +42 -0
  429. data/vendor/bundle/ruby/3.4.0/gems/rb_sys-0.9.130/certs/ianks.pem +21 -0
  430. data/vendor/bundle/ruby/3.4.0/gems/rb_sys-0.9.130/exe/rb-sys-dock +495 -0
  431. data/vendor/bundle/ruby/3.4.0/gems/rb_sys-0.9.130/lib/rb_sys/cargo/config.rb +72 -0
  432. data/vendor/bundle/ruby/3.4.0/gems/rb_sys-0.9.130/lib/rb_sys/cargo/metadata.rb +158 -0
  433. data/vendor/bundle/ruby/3.4.0/gems/rb_sys-0.9.130/lib/rb_sys/cargo.rb +9 -0
  434. data/vendor/bundle/ruby/3.4.0/gems/rb_sys-0.9.130/lib/rb_sys/cargo_builder/link_flag_converter.rb +37 -0
  435. data/vendor/bundle/ruby/3.4.0/gems/rb_sys-0.9.130/lib/rb_sys/cargo_builder.rb +370 -0
  436. data/vendor/bundle/ruby/3.4.0/gems/rb_sys-0.9.130/lib/rb_sys/error.rb +43 -0
  437. data/vendor/bundle/ruby/3.4.0/gems/rb_sys-0.9.130/lib/rb_sys/extensiontask.rb +188 -0
  438. data/vendor/bundle/ruby/3.4.0/gems/rb_sys-0.9.130/lib/rb_sys/mkmf/config.rb +75 -0
  439. data/vendor/bundle/ruby/3.4.0/gems/rb_sys-0.9.130/lib/rb_sys/mkmf.rb +413 -0
  440. data/vendor/bundle/ruby/3.4.0/gems/rb_sys-0.9.130/lib/rb_sys/toolchain_info/data.rb +10 -0
  441. data/vendor/bundle/ruby/3.4.0/gems/rb_sys-0.9.130/lib/rb_sys/toolchain_info.rb +82 -0
  442. data/vendor/bundle/ruby/3.4.0/gems/rb_sys-0.9.130/lib/rb_sys/util/logger.rb +73 -0
  443. data/vendor/bundle/ruby/3.4.0/gems/rb_sys-0.9.130/lib/rb_sys/version.rb +5 -0
  444. data/vendor/bundle/ruby/3.4.0/gems/rb_sys-0.9.130/lib/rb_sys.rb +8 -0
  445. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/BSDL +22 -0
  446. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/CHANGELOG.md +2463 -0
  447. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/COPYING +56 -0
  448. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/Dockerfile.jruby +53 -0
  449. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/README.md +240 -0
  450. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/Rakefile +1213 -0
  451. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/Steepfile +55 -0
  452. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/config.yml +920 -0
  453. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/array.rbs +4205 -0
  454. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/basic_object.rbs +376 -0
  455. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/binding.rbs +148 -0
  456. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/builtin.rbs +278 -0
  457. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/class.rbs +223 -0
  458. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/comparable.rbs +192 -0
  459. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/complex.rbs +812 -0
  460. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/constants.rbs +96 -0
  461. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/data.rbs +415 -0
  462. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/dir.rbs +993 -0
  463. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/encoding.rbs +1368 -0
  464. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/enumerable.rbs +2506 -0
  465. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/enumerator/arithmetic_sequence.rbs +70 -0
  466. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/enumerator/product.rbs +92 -0
  467. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/enumerator.rbs +705 -0
  468. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/env.rbs +6 -0
  469. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/errno.rbs +682 -0
  470. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/errors.rbs +789 -0
  471. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/exception.rbs +485 -0
  472. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/false_class.rbs +82 -0
  473. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/fiber.rbs +570 -0
  474. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/fiber_error.rbs +11 -0
  475. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/file.rbs +2045 -0
  476. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/file_constants.rbs +463 -0
  477. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/file_stat.rbs +534 -0
  478. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/file_test.rbs +331 -0
  479. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/float.rbs +1292 -0
  480. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/gc.rbs +788 -0
  481. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/global_variables.rbs +184 -0
  482. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/hash.rbs +2183 -0
  483. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/integer.rbs +1374 -0
  484. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/io/buffer.rbs +995 -0
  485. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/io/wait.rbs +48 -0
  486. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/io.rbs +3473 -0
  487. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/kernel.rbs +3172 -0
  488. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/marshal.rbs +207 -0
  489. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/match_data.rbs +637 -0
  490. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/math.rbs +770 -0
  491. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/method.rbs +422 -0
  492. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/module.rbs +1856 -0
  493. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/nil_class.rbs +210 -0
  494. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/numeric.rbs +832 -0
  495. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/object.rbs +108 -0
  496. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/object_space/weak_key_map.rbs +166 -0
  497. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/object_space.rbs +197 -0
  498. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/pathname.rbs +1312 -0
  499. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/proc.rbs +905 -0
  500. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/process.rbs +2316 -0
  501. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/ractor.rbs +914 -0
  502. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/random.rbs +255 -0
  503. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/range.rbs +1209 -0
  504. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/rational.rbs +502 -0
  505. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/rb_config.rbs +88 -0
  506. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/rbs/ops.rbs +154 -0
  507. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/rbs/unnamed/argf.rbs +1236 -0
  508. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/rbs/unnamed/env_class.rbs +1214 -0
  509. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/rbs/unnamed/main_class.rbs +123 -0
  510. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/rbs/unnamed/random.rbs +186 -0
  511. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/refinement.rbs +59 -0
  512. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/regexp.rbs +1974 -0
  513. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/ruby.rbs +53 -0
  514. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/ruby_vm.rbs +809 -0
  515. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/rubygems/basic_specification.rbs +6 -0
  516. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/rubygems/config_file.rbs +38 -0
  517. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/rubygems/dependency_installer.rbs +6 -0
  518. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/rubygems/errors.rbs +112 -0
  519. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/rubygems/installer.rbs +15 -0
  520. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/rubygems/path_support.rbs +6 -0
  521. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/rubygems/platform.rbs +7 -0
  522. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/rubygems/request_set.rbs +49 -0
  523. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/rubygems/requirement.rbs +138 -0
  524. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/rubygems/rubygems.rbs +1108 -0
  525. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/rubygems/source_list.rbs +15 -0
  526. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/rubygems/specification.rbs +31 -0
  527. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/rubygems/stream_ui.rbs +5 -0
  528. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/rubygems/uninstaller.rbs +10 -0
  529. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/rubygems/version.rbs +133 -0
  530. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/set.rbs +751 -0
  531. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/signal.rbs +110 -0
  532. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/string.rbs +5532 -0
  533. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/struct.rbs +668 -0
  534. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/symbol.rbs +482 -0
  535. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/thread.rbs +1821 -0
  536. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/thread_group.rbs +79 -0
  537. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/time.rbs +1793 -0
  538. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/trace_point.rbs +483 -0
  539. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/true_class.rbs +98 -0
  540. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/unbound_method.rbs +337 -0
  541. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/core/warning.rbs +87 -0
  542. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/docs/CONTRIBUTING.md +107 -0
  543. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/docs/aliases.md +79 -0
  544. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/docs/architecture.md +110 -0
  545. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/docs/collection.md +192 -0
  546. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/docs/config.md +171 -0
  547. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/docs/data_and_struct.md +86 -0
  548. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/docs/encoding.md +56 -0
  549. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/docs/gem.md +56 -0
  550. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/docs/inline.md +634 -0
  551. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/docs/rbs_by_example.md +309 -0
  552. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/docs/release.md +303 -0
  553. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/docs/repo.md +125 -0
  554. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/docs/rust.md +96 -0
  555. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/docs/sigs.md +167 -0
  556. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/docs/stdlib.md +155 -0
  557. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/docs/syntax.md +952 -0
  558. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/docs/tools.md +17 -0
  559. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/docs/type_fingerprint.md +21 -0
  560. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/docs/wasm_serialization.md +80 -0
  561. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/exe/rbs +7 -0
  562. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/ext/rbs_extension/Makefile +273 -0
  563. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/ext/rbs_extension/ast_translation.c +1870 -0
  564. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/ext/rbs_extension/ast_translation.h +41 -0
  565. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/ext/rbs_extension/class_constants.c +189 -0
  566. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/ext/rbs_extension/class_constants.h +105 -0
  567. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/ext/rbs_extension/compat.h +10 -0
  568. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/ext/rbs_extension/extconf.rb +40 -0
  569. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/ext/rbs_extension/legacy_location.c +299 -0
  570. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/ext/rbs_extension/legacy_location.h +82 -0
  571. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/ext/rbs_extension/main.c +649 -0
  572. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/ext/rbs_extension/rbs_extension.h +16 -0
  573. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/ext/rbs_extension/rbs_string_bridging.c +9 -0
  574. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/ext/rbs_extension/rbs_string_bridging.h +24 -0
  575. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/goodcheck.yml +91 -0
  576. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/include/rbs/ast.h +1055 -0
  577. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/include/rbs/defines.h +104 -0
  578. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/include/rbs/lexer.h +208 -0
  579. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/include/rbs/location.h +40 -0
  580. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/include/rbs/parser.h +187 -0
  581. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/include/rbs/serialize.h +39 -0
  582. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/include/rbs/string.h +47 -0
  583. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/include/rbs/util/rbs_allocator.h +59 -0
  584. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/include/rbs/util/rbs_assert.h +20 -0
  585. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/include/rbs/util/rbs_buffer.h +83 -0
  586. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/include/rbs/util/rbs_constant_pool.h +155 -0
  587. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/include/rbs/util/rbs_encoding.h +282 -0
  588. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/include/rbs/util/rbs_unescape.h +24 -0
  589. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/include/rbs.h +14 -0
  590. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/ancestor_graph.rb +92 -0
  591. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/annotate/annotations.rb +199 -0
  592. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/annotate/formatter.rb +82 -0
  593. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/annotate/rdoc_annotator.rb +398 -0
  594. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/annotate/rdoc_source.rb +131 -0
  595. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/annotate.rb +8 -0
  596. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/ast/annotation.rb +29 -0
  597. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/ast/comment.rb +29 -0
  598. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/ast/declarations.rb +472 -0
  599. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/ast/directives.rb +49 -0
  600. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/ast/members.rb +451 -0
  601. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/ast/ruby/annotations.rb +451 -0
  602. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/ast/ruby/comment_block.rb +247 -0
  603. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/ast/ruby/declarations.rb +291 -0
  604. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/ast/ruby/helpers/constant_helper.rb +28 -0
  605. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/ast/ruby/helpers/location_helper.rb +15 -0
  606. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/ast/ruby/members.rb +762 -0
  607. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/ast/type_param.rb +235 -0
  608. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/ast/visitor.rb +137 -0
  609. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/buffer.rb +189 -0
  610. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/builtin_names.rb +58 -0
  611. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/cli/colored_io.rb +48 -0
  612. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/cli/diff.rb +84 -0
  613. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/cli/validate.rb +294 -0
  614. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/cli.rb +1253 -0
  615. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/collection/cleaner.rb +38 -0
  616. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/collection/config/lockfile.rb +92 -0
  617. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/collection/config/lockfile_generator.rb +269 -0
  618. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/collection/config.rb +81 -0
  619. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/collection/installer.rb +32 -0
  620. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/collection/sources/base.rb +14 -0
  621. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/collection/sources/git.rb +265 -0
  622. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/collection/sources/local.rb +81 -0
  623. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/collection/sources/rubygems.rb +48 -0
  624. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/collection/sources/stdlib.rb +50 -0
  625. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/collection/sources.rb +38 -0
  626. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/collection.rb +16 -0
  627. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/constant.rb +28 -0
  628. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/definition.rb +415 -0
  629. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/definition_builder/ancestor_builder.rb +681 -0
  630. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/definition_builder/method_builder.rb +295 -0
  631. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/definition_builder.rb +1057 -0
  632. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/diff.rb +131 -0
  633. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/environment/class_entry.rb +81 -0
  634. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/environment/module_entry.rb +91 -0
  635. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/environment/use_map.rb +77 -0
  636. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/environment.rb +1028 -0
  637. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/environment_loader.rb +167 -0
  638. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/environment_walker.rb +155 -0
  639. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/errors.rb +634 -0
  640. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/factory.rb +18 -0
  641. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/file_finder.rb +28 -0
  642. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/inline_parser/comment_association.rb +117 -0
  643. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/inline_parser.rb +568 -0
  644. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/location_aux.rb +170 -0
  645. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/locator.rb +247 -0
  646. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/method_type.rb +145 -0
  647. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/namespace.rb +154 -0
  648. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/parser/lex_result.rb +15 -0
  649. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/parser/token.rb +23 -0
  650. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/parser_aux.rb +144 -0
  651. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/prototype/helpers.rb +164 -0
  652. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/prototype/node_usage.rb +99 -0
  653. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/prototype/rb.rb +816 -0
  654. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/prototype/rbi.rb +793 -0
  655. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/prototype/runtime/helpers.rb +59 -0
  656. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/prototype/runtime/reflection.rb +19 -0
  657. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/prototype/runtime/value_object_generator.rb +278 -0
  658. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/prototype/runtime.rb +680 -0
  659. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/repository.rb +127 -0
  660. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/resolver/constant_resolver.rb +219 -0
  661. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/resolver/type_name_resolver.rb +167 -0
  662. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/rewriter.rb +70 -0
  663. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/sorter.rb +198 -0
  664. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/source.rb +99 -0
  665. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/substitution.rb +83 -0
  666. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/subtractor.rb +204 -0
  667. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/test/errors.rb +80 -0
  668. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/test/guaranteed.rb +30 -0
  669. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/test/hook.rb +212 -0
  670. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/test/observer.rb +19 -0
  671. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/test/setup.rb +84 -0
  672. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/test/setup_helper.rb +50 -0
  673. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/test/tester.rb +167 -0
  674. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/test/type_check.rb +457 -0
  675. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/test.rb +112 -0
  676. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/type_alias_dependency.rb +100 -0
  677. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/type_alias_regularity.rb +126 -0
  678. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/type_name.rb +122 -0
  679. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/types.rb +1646 -0
  680. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/unit_test/convertibles.rb +177 -0
  681. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/unit_test/spy.rb +138 -0
  682. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/unit_test/type_assertions.rb +383 -0
  683. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/unit_test/with_aliases.rb +145 -0
  684. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/unit_test.rb +6 -0
  685. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/validator.rb +186 -0
  686. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/variance_calculator.rb +189 -0
  687. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/vendorer.rb +71 -0
  688. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/version.rb +5 -0
  689. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/wasm/deserializer.rb +213 -0
  690. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/wasm/location.rb +61 -0
  691. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/wasm/parser.rb +174 -0
  692. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/wasm/runtime.rb +211 -0
  693. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/wasm/serialization_schema.rb +111 -0
  694. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs/writer.rb +424 -0
  695. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs.rb +117 -0
  696. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs_extension.so +0 -0
  697. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rbs_jars.rb +39 -0
  698. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rdoc/discover.rb +20 -0
  699. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/lib/rdoc_plugin/parser.rb +168 -0
  700. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/rbs.gemspec +77 -0
  701. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/schema/annotation.json +14 -0
  702. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/schema/comment.json +26 -0
  703. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/schema/decls.json +326 -0
  704. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/schema/function.json +98 -0
  705. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/schema/location.json +56 -0
  706. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/schema/members.json +266 -0
  707. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/schema/methodType.json +50 -0
  708. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/schema/typeParam.json +52 -0
  709. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/schema/types.json +317 -0
  710. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/ancestor_builder.rbs +163 -0
  711. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/ancestor_graph.rbs +60 -0
  712. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/annotate/annotations.rbs +102 -0
  713. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/annotate/formatter.rbs +24 -0
  714. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/annotate/rdoc_annotater.rbs +85 -0
  715. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/annotate/rdoc_source.rbs +32 -0
  716. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/annotation.rbs +27 -0
  717. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/ast/ruby/annotations.rbs +470 -0
  718. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/ast/ruby/comment_block.rbs +127 -0
  719. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/ast/ruby/declarations.rbs +158 -0
  720. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/ast/ruby/helpers/constant_helper.rbs +11 -0
  721. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/ast/ruby/helpers/location_helper.rbs +15 -0
  722. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/ast/ruby/members.rbs +198 -0
  723. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/buffer.rbs +108 -0
  724. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/builtin_names.rbs +44 -0
  725. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/cli/colored_io.rbs +15 -0
  726. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/cli/diff.rbs +15 -0
  727. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/cli/validate.rbs +47 -0
  728. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/cli.rbs +89 -0
  729. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/collection/cleaner.rbs +13 -0
  730. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/collection/config/lockfile.rbs +74 -0
  731. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/collection/config/lockfile_generator.rbs +68 -0
  732. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/collection/config.rbs +46 -0
  733. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/collection/installer.rbs +17 -0
  734. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/collection/sources.rbs +214 -0
  735. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/collection.rbs +4 -0
  736. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/comment.rbs +26 -0
  737. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/constant.rbs +21 -0
  738. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/declarations.rbs +274 -0
  739. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/definition.rbs +232 -0
  740. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/definition_builder.rbs +181 -0
  741. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/diff.rbs +28 -0
  742. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/directives.rbs +77 -0
  743. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/environment/class_entry.rbs +56 -0
  744. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/environment/module_entry.rbs +65 -0
  745. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/environment.rbs +286 -0
  746. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/environment_loader.rbs +111 -0
  747. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/environment_walker.rbs +65 -0
  748. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/errors.rbs +408 -0
  749. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/factory.rbs +5 -0
  750. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/file_finder.rbs +28 -0
  751. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/inline_parser/comment_association.rbs +71 -0
  752. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/inline_parser.rbs +126 -0
  753. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/location.rbs +135 -0
  754. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/locator.rbs +56 -0
  755. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/manifest.yaml +5 -0
  756. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/members.rbs +258 -0
  757. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/method_builder.rbs +89 -0
  758. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/method_types.rbs +58 -0
  759. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/namespace.rbs +161 -0
  760. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/parser.rbs +164 -0
  761. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/prototype/helpers.rbs +29 -0
  762. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/prototype/node_usage.rbs +20 -0
  763. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/prototype/rb.rbs +96 -0
  764. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/prototype/rbi.rbs +104 -0
  765. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/prototype/runtime.rbs +182 -0
  766. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/rbs.rbs +21 -0
  767. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/rdoc/rbs.rbs +67 -0
  768. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/repository.rbs +85 -0
  769. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/resolver/constant_resolver.rbs +92 -0
  770. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/resolver/context.rbs +34 -0
  771. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/resolver/type_name_resolver.rbs +61 -0
  772. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/rewriter.rbs +45 -0
  773. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/shims/bundler.rbs +38 -0
  774. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/shims/enumerable.rbs +5 -0
  775. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/shims/rubygems.rbs +19 -0
  776. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/sorter.rbs +41 -0
  777. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/source.rbs +48 -0
  778. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/substitution.rbs +48 -0
  779. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/subtractor.rbs +37 -0
  780. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/test/errors.rbs +52 -0
  781. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/test/guranteed.rbs +9 -0
  782. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/test/type_check.rbs +19 -0
  783. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/test.rbs +82 -0
  784. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/type_alias_dependency.rbs +53 -0
  785. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/type_alias_regularity.rbs +98 -0
  786. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/type_param.rbs +115 -0
  787. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/typename.rbs +89 -0
  788. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/types.rbs +588 -0
  789. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/unit_test/convertibles.rbs +154 -0
  790. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/unit_test/spy.rbs +22 -0
  791. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/unit_test/type_assertions.rbs +211 -0
  792. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/unit_test/with_aliases.rbs +136 -0
  793. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/use_map.rbs +35 -0
  794. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/util.rbs +9 -0
  795. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/validator.rbs +63 -0
  796. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/variance_calculator.rbs +87 -0
  797. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/vendorer.rbs +51 -0
  798. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/version.rbs +3 -0
  799. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/visitor.rbs +47 -0
  800. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/wasm/deserializer.rbs +66 -0
  801. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/wasm/serialization_schema.rbs +13 -0
  802. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/sig/writer.rbs +127 -0
  803. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/src/ast.c +1644 -0
  804. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/src/lexer.c +3223 -0
  805. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/src/lexer.re +187 -0
  806. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/src/lexstate.c +222 -0
  807. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/src/location.c +31 -0
  808. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/src/parser.c +4318 -0
  809. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/src/serialize.c +965 -0
  810. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/src/string.c +41 -0
  811. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/src/util/rbs_allocator.c +171 -0
  812. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/src/util/rbs_assert.c +19 -0
  813. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/src/util/rbs_buffer.c +54 -0
  814. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/src/util/rbs_constant_pool.c +268 -0
  815. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/src/util/rbs_encoding.c +21454 -0
  816. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/src/util/rbs_unescape.c +167 -0
  817. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/abbrev/0/abbrev.rbs +66 -0
  818. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/abbrev/0/array.rbs +26 -0
  819. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/base64/0/base64.rbs +355 -0
  820. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/benchmark/0/benchmark.rbs +452 -0
  821. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/bigdecimal/0/big_decimal.rbs +1647 -0
  822. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/bigdecimal-math/0/big_math.rbs +280 -0
  823. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/bigdecimal-math/0/manifest.yaml +2 -0
  824. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/cgi/0/core.rbs +911 -0
  825. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/cgi/0/manifest.yaml +4 -0
  826. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/cgi-escape/0/escape.rbs +171 -0
  827. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/coverage/0/coverage.rbs +266 -0
  828. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/csv/0/csv.rbs +3776 -0
  829. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/csv/0/manifest.yaml +3 -0
  830. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/date/0/date.rbs +1598 -0
  831. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/date/0/date_time.rbs +617 -0
  832. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/date/0/time.rbs +26 -0
  833. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/dbm/0/dbm.rbs +421 -0
  834. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/delegate/0/delegator.rbs +188 -0
  835. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/delegate/0/kernel.rbs +47 -0
  836. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/delegate/0/simple_delegator.rbs +96 -0
  837. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/did_you_mean/0/did_you_mean.rbs +344 -0
  838. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/digest/0/digest.rbs +693 -0
  839. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/erb/0/erb.rbs +933 -0
  840. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/etc/0/etc.rbs +884 -0
  841. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/fileutils/0/fileutils.rbs +1753 -0
  842. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/find/0/find.rbs +49 -0
  843. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/forwardable/0/forwardable.rbs +271 -0
  844. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/io-console/0/io-console.rbs +414 -0
  845. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/ipaddr/0/ipaddr.rbs +431 -0
  846. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/json/0/json.rbs +1963 -0
  847. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/kconv/0/kconv.rbs +166 -0
  848. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/logger/0/formatter.rbs +45 -0
  849. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/logger/0/log_device.rbs +100 -0
  850. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/logger/0/logger.rbs +796 -0
  851. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/logger/0/manifest.yaml +2 -0
  852. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/logger/0/period.rbs +17 -0
  853. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/logger/0/severity.rbs +34 -0
  854. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/kernel.rbs +42 -0
  855. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/abstract_reporter.rbs +52 -0
  856. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/assertion.rbs +17 -0
  857. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/assertions.rbs +590 -0
  858. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/backtrace_filter.rbs +23 -0
  859. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/bench_spec.rbs +102 -0
  860. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/benchmark.rbs +259 -0
  861. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/composite_reporter.rbs +25 -0
  862. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/compress.rbs +13 -0
  863. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/error_on_warning.rbs +3 -0
  864. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/expectation.rbs +2 -0
  865. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/expectations.rbs +21 -0
  866. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/guard.rbs +64 -0
  867. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/mock.rbs +64 -0
  868. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/parallel/executor.rbs +46 -0
  869. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/parallel/test/class_methods.rbs +5 -0
  870. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/parallel/test.rbs +3 -0
  871. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/parallel.rbs +2 -0
  872. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/pride_io.rbs +62 -0
  873. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/pride_lol.rbs +19 -0
  874. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/progress_reporter.rbs +11 -0
  875. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/reportable.rbs +53 -0
  876. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/reporter.rbs +5 -0
  877. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/result.rbs +28 -0
  878. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/runnable.rbs +163 -0
  879. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/skip.rbs +6 -0
  880. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/spec/dsl/instance_methods.rbs +48 -0
  881. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/spec/dsl.rbs +129 -0
  882. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/spec.rbs +11 -0
  883. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/statistics_reporter.rbs +81 -0
  884. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/summary_reporter.rbs +18 -0
  885. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/test/lifecycle_hooks.rbs +92 -0
  886. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/test.rbs +69 -0
  887. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/unexpected_error.rbs +12 -0
  888. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/unexpected_warning.rbs +6 -0
  889. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/unit/test_case.rbs +3 -0
  890. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest/unit.rbs +4 -0
  891. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/minitest/0/minitest.rbs +115 -0
  892. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/monitor/0/monitor.rbs +363 -0
  893. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/mutex_m/0/mutex_m.rbs +104 -0
  894. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/net-http/0/manifest.yaml +3 -0
  895. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/net-http/0/net-http.rbs +5580 -0
  896. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/net-protocol/0/manifest.yaml +2 -0
  897. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/net-protocol/0/net-protocol.rbs +56 -0
  898. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/net-smtp/0/manifest.yaml +2 -0
  899. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/net-smtp/0/net-smtp.rbs +55 -0
  900. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/nkf/0/nkf.rbs +402 -0
  901. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/objspace/0/objspace.rbs +470 -0
  902. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/observable/0/observable.rbs +217 -0
  903. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/open-uri/0/manifest.yaml +4 -0
  904. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/open-uri/0/open-uri.rbs +433 -0
  905. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/open3/0/open3.rbs +606 -0
  906. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/openssl/0/manifest.yaml +3 -0
  907. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/openssl/0/openssl.rbs +12237 -0
  908. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/optparse/0/optparse.rbs +1734 -0
  909. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/pathname/0/pathname.rbs +36 -0
  910. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/pp/0/manifest.yaml +2 -0
  911. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/pp/0/pp.rbs +301 -0
  912. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/prettyprint/0/prettyprint.rbs +383 -0
  913. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/pstore/0/pstore.rbs +608 -0
  914. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/psych/0/core_ext.rbs +12 -0
  915. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/psych/0/dbm.rbs +237 -0
  916. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/psych/0/manifest.yaml +3 -0
  917. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/psych/0/psych.rbs +455 -0
  918. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/psych/0/store.rbs +57 -0
  919. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/pty/0/pty.rbs +240 -0
  920. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/random-formatter/0/random-formatter.rbs +277 -0
  921. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/rdoc/0/code_object.rbs +52 -0
  922. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/rdoc/0/comment.rbs +61 -0
  923. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/rdoc/0/context.rbs +153 -0
  924. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/rdoc/0/markup.rbs +117 -0
  925. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/rdoc/0/options.rbs +76 -0
  926. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/rdoc/0/parser.rbs +56 -0
  927. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/rdoc/0/rdoc.rbs +393 -0
  928. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/rdoc/0/ri.rbs +17 -0
  929. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/rdoc/0/store.rbs +48 -0
  930. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/rdoc/0/top_level.rbs +97 -0
  931. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/resolv/0/manifest.yaml +3 -0
  932. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/resolv/0/resolv.rbs +1787 -0
  933. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/ripper/0/ripper.rbs +1654 -0
  934. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/securerandom/0/manifest.yaml +2 -0
  935. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/securerandom/0/securerandom.rbs +49 -0
  936. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/shellwords/0/shellwords.rbs +229 -0
  937. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/singleton/0/singleton.rbs +137 -0
  938. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/socket/0/addrinfo.rbs +666 -0
  939. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/socket/0/basic_socket.rbs +590 -0
  940. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/socket/0/constants.rbs +2295 -0
  941. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/socket/0/ip_socket.rbs +94 -0
  942. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/socket/0/socket.rbs +4170 -0
  943. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/socket/0/socket_error.rbs +5 -0
  944. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/socket/0/tcp_server.rbs +192 -0
  945. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/socket/0/tcp_socket.rbs +87 -0
  946. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/socket/0/udp_socket.rbs +133 -0
  947. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/socket/0/unix_server.rbs +169 -0
  948. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/socket/0/unix_socket.rbs +172 -0
  949. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/stringio/0/stringio.rbs +1682 -0
  950. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/strscan/0/string_scanner.rbs +1648 -0
  951. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/tempfile/0/manifest.yaml +3 -0
  952. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/tempfile/0/tempfile.rbs +483 -0
  953. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/time/0/time.rbs +434 -0
  954. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/timeout/0/timeout.rbs +132 -0
  955. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/tmpdir/0/tmpdir.rbs +69 -0
  956. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/tsort/0/cyclic.rbs +8 -0
  957. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/tsort/0/interfaces.rbs +20 -0
  958. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/tsort/0/tsort.rbs +410 -0
  959. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/uri/0/common.rbs +621 -0
  960. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/uri/0/file.rbs +118 -0
  961. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/uri/0/ftp.rbs +13 -0
  962. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/uri/0/generic.rbs +1111 -0
  963. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/uri/0/http.rbs +104 -0
  964. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/uri/0/https.rbs +14 -0
  965. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/uri/0/ldap.rbs +230 -0
  966. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/uri/0/ldaps.rbs +14 -0
  967. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/uri/0/mailto.rbs +92 -0
  968. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/uri/0/rfc2396_parser.rbs +189 -0
  969. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/uri/0/rfc3986_parser.rbs +2 -0
  970. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/uri/0/ws.rbs +13 -0
  971. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/uri/0/wss.rbs +9 -0
  972. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/yaml/0/manifest.yaml +2 -0
  973. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/yaml/0/yaml.rbs +1 -0
  974. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/zlib/0/buf_error.rbs +10 -0
  975. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/zlib/0/data_error.rbs +10 -0
  976. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/zlib/0/deflate.rbs +211 -0
  977. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/zlib/0/error.rbs +20 -0
  978. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/zlib/0/gzip_file/crc_error.rbs +12 -0
  979. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/zlib/0/gzip_file/error.rbs +23 -0
  980. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/zlib/0/gzip_file/length_error.rbs +12 -0
  981. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/zlib/0/gzip_file/no_footer.rbs +11 -0
  982. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/zlib/0/gzip_file.rbs +156 -0
  983. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/zlib/0/gzip_reader.rbs +293 -0
  984. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/zlib/0/gzip_writer.rbs +169 -0
  985. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/zlib/0/inflate.rbs +180 -0
  986. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/zlib/0/mem_error.rbs +10 -0
  987. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/zlib/0/need_dict.rbs +13 -0
  988. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/zlib/0/stream_end.rbs +11 -0
  989. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/zlib/0/stream_error.rbs +11 -0
  990. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/zlib/0/version_error.rbs +11 -0
  991. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/zlib/0/zlib.rbs +449 -0
  992. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/stdlib/zlib/0/zstream.rbs +200 -0
  993. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/wasm/README.md +109 -0
  994. data/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/wasm/rbs_wasm.c +479 -0
  995. data/vendor/bundle/ruby/3.4.0/gems/toml-rb-6.0.0/LICENSE +19 -0
  996. data/vendor/bundle/ruby/3.4.0/gems/toml-rb-6.0.0/README.md +135 -0
  997. data/vendor/bundle/ruby/3.4.0/gems/toml-rb-6.0.0/lib/toml-rb/datetime.rb +54 -0
  998. data/vendor/bundle/ruby/3.4.0/gems/toml-rb-6.0.0/lib/toml-rb/dumper.rb +182 -0
  999. data/vendor/bundle/ruby/3.4.0/gems/toml-rb-6.0.0/lib/toml-rb/errors.rb +17 -0
  1000. data/vendor/bundle/ruby/3.4.0/gems/toml-rb-6.0.0/lib/toml-rb/inline_table.rb +18 -0
  1001. data/vendor/bundle/ruby/3.4.0/gems/toml-rb-6.0.0/lib/toml-rb/keyvalue.rb +45 -0
  1002. data/vendor/bundle/ruby/3.4.0/gems/toml-rb-6.0.0/lib/toml-rb/parser.rb +296 -0
  1003. data/vendor/bundle/ruby/3.4.0/gems/toml-rb-6.0.0/lib/toml-rb/string.rb +41 -0
  1004. data/vendor/bundle/ruby/3.4.0/gems/toml-rb-6.0.0/lib/toml-rb/table.rb +34 -0
  1005. data/vendor/bundle/ruby/3.4.0/gems/toml-rb-6.0.0/lib/toml-rb/table_array.rb +43 -0
  1006. data/vendor/bundle/ruby/3.4.0/gems/toml-rb-6.0.0/lib/toml-rb/version.rb +5 -0
  1007. data/vendor/bundle/ruby/3.4.0/gems/toml-rb-6.0.0/lib/toml-rb.rb +90 -0
  1008. data/vendor/bundle/ruby/3.4.0/gems/tsort-0.2.0/Gemfile +4 -0
  1009. data/vendor/bundle/ruby/3.4.0/gems/tsort-0.2.0/LICENSE.txt +22 -0
  1010. data/vendor/bundle/ruby/3.4.0/gems/tsort-0.2.0/README.md +72 -0
  1011. data/vendor/bundle/ruby/3.4.0/gems/tsort-0.2.0/Rakefile +10 -0
  1012. data/vendor/bundle/ruby/3.4.0/gems/tsort-0.2.0/bin/console +14 -0
  1013. data/vendor/bundle/ruby/3.4.0/gems/tsort-0.2.0/bin/setup +8 -0
  1014. data/vendor/bundle/ruby/3.4.0/gems/tsort-0.2.0/lib/tsort.rb +455 -0
  1015. data/vendor/bundle/ruby/3.4.0/gems/tsort-0.2.0/tsort.gemspec +29 -0
  1016. data/vendor/bundle/ruby/3.4.0/specifications/drb-2.2.3.gemspec +22 -0
  1017. data/vendor/bundle/ruby/3.4.0/specifications/logger-1.7.0.gemspec +22 -0
  1018. data/vendor/bundle/ruby/3.4.0/specifications/minitest-6.0.6.gemspec +35 -0
  1019. data/vendor/bundle/ruby/3.4.0/specifications/prism-1.9.0.gemspec +24 -0
  1020. data/vendor/bundle/ruby/3.4.0/specifications/rake-13.4.2.gemspec +26 -0
  1021. data/vendor/bundle/ruby/3.4.0/specifications/rake-compiler-1.3.2.gemspec +33 -0
  1022. data/vendor/bundle/ruby/3.4.0/specifications/rake-compiler-dock-1.12.0.gemspec +28 -0
  1023. data/vendor/bundle/ruby/3.4.0/specifications/rb_sys-0.9.130.gemspec +29 -0
  1024. data/vendor/bundle/ruby/3.4.0/specifications/rbs-4.2.0.gemspec +33 -0
  1025. data/vendor/bundle/ruby/3.4.0/specifications/toml-rb-6.0.0.gemspec +27 -0
  1026. data/vendor/bundle/ruby/3.4.0/specifications/tsort-0.2.0.gemspec +23 -0
  1027. data/vendor/cache/Cargo.toml +21 -0
  1028. data/vendor/cache/LICENSE +21 -0
  1029. data/vendor/cache/README.md +5 -0
  1030. data/vendor/cache/src/hash.rs +85 -0
  1031. data/vendor/cache/src/lib.rs +751 -0
  1032. data/vendor/cache/src/loom_tests.rs +340 -0
  1033. data/vendor/cache/src/s3fifo.rs +648 -0
  1034. data/vendor/cache/src/sync.rs +25 -0
  1035. data/vendor/cache/src/tests.rs +260 -0
  1036. data/vendor/compaction/Cargo.toml +32 -0
  1037. data/vendor/compaction/LICENSE +21 -0
  1038. data/vendor/compaction/README.md +5 -0
  1039. data/vendor/compaction/src/blob.rs +478 -0
  1040. data/vendor/compaction/src/cursor.rs +700 -0
  1041. data/vendor/compaction/src/gc.rs +802 -0
  1042. data/vendor/compaction/src/job.rs +861 -0
  1043. data/vendor/compaction/src/lib.rs +102 -0
  1044. data/vendor/compaction/src/merge.rs +995 -0
  1045. data/vendor/compaction/src/picker.rs +681 -0
  1046. data/vendor/compaction/src/resolver.rs +1346 -0
  1047. data/vendor/engine/Cargo.toml +56 -0
  1048. data/vendor/engine/LICENSE +21 -0
  1049. data/vendor/engine/README.md +5 -0
  1050. data/vendor/engine/src/admission.rs +421 -0
  1051. data/vendor/engine/src/catalog.rs +1233 -0
  1052. data/vendor/engine/src/check.rs +1386 -0
  1053. data/vendor/engine/src/clock.rs +244 -0
  1054. data/vendor/engine/src/clock_loom.rs +482 -0
  1055. data/vendor/engine/src/close_gate.rs +325 -0
  1056. data/vendor/engine/src/compact.rs +1509 -0
  1057. data/vendor/engine/src/engine/hooks.rs +1654 -0
  1058. data/vendor/engine/src/engine/info.rs +229 -0
  1059. data/vendor/engine/src/engine.rs +6114 -0
  1060. data/vendor/engine/src/error.rs +490 -0
  1061. data/vendor/engine/src/feed.rs +960 -0
  1062. data/vendor/engine/src/feed_reader.rs +1600 -0
  1063. data/vendor/engine/src/flush.rs +839 -0
  1064. data/vendor/engine/src/flushed_roots.rs +158 -0
  1065. data/vendor/engine/src/flushed_through_loom.rs +77 -0
  1066. data/vendor/engine/src/health.rs +201 -0
  1067. data/vendor/engine/src/large.rs +372 -0
  1068. data/vendor/engine/src/large_settle.rs +201 -0
  1069. data/vendor/engine/src/lib.rs +112 -0
  1070. data/vendor/engine/src/load_slot.rs +324 -0
  1071. data/vendor/engine/src/maintenance.rs +935 -0
  1072. data/vendor/engine/src/manifest/flight.rs +563 -0
  1073. data/vendor/engine/src/manifest.rs +1516 -0
  1074. data/vendor/engine/src/nonblocking.rs +603 -0
  1075. data/vendor/engine/src/options.rs +334 -0
  1076. data/vendor/engine/src/position.rs +125 -0
  1077. data/vendor/engine/src/purge_guard.rs +220 -0
  1078. data/vendor/engine/src/read/keys.rs +1049 -0
  1079. data/vendor/engine/src/read/knn.rs +423 -0
  1080. data/vendor/engine/src/read/reduce.rs +2057 -0
  1081. data/vendor/engine/src/read/traverse.rs +1013 -0
  1082. data/vendor/engine/src/read.rs +2429 -0
  1083. data/vendor/engine/src/row_cache.rs +1101 -0
  1084. data/vendor/engine/src/shard/tablets.rs +3582 -0
  1085. data/vendor/engine/src/shard.rs +12215 -0
  1086. data/vendor/engine/src/snapshot.rs +1429 -0
  1087. data/vendor/engine/src/source.rs +1379 -0
  1088. data/vendor/engine/src/timer_state.rs +226 -0
  1089. data/vendor/engine/src/waker.rs +124 -0
  1090. data/vendor/engine/src/watermark_waiters.rs +674 -0
  1091. data/vendor/engine/src/write.rs +1321 -0
  1092. data/vendor/format/Cargo.toml +40 -0
  1093. data/vendor/format/LICENSE +21 -0
  1094. data/vendor/format/README.md +5 -0
  1095. data/vendor/format/src/blob.rs +101 -0
  1096. data/vendor/format/src/block.rs +1120 -0
  1097. data/vendor/format/src/bloom.rs +456 -0
  1098. data/vendor/format/src/buckets.rs +552 -0
  1099. data/vendor/format/src/bytes.rs +101 -0
  1100. data/vendor/format/src/checksum.rs +132 -0
  1101. data/vendor/format/src/compress.rs +196 -0
  1102. data/vendor/format/src/cursor.rs +110 -0
  1103. data/vendor/format/src/distance.rs +598 -0
  1104. data/vendor/format/src/error.rs +93 -0
  1105. data/vendor/format/src/exact.rs +602 -0
  1106. data/vendor/format/src/feed.rs +285 -0
  1107. data/vendor/format/src/filter.rs +157 -0
  1108. data/vendor/format/src/half.rs +182 -0
  1109. data/vendor/format/src/hash.rs +127 -0
  1110. data/vendor/format/src/hll.rs +500 -0
  1111. data/vendor/format/src/ids.rs +95 -0
  1112. data/vendor/format/src/key.rs +620 -0
  1113. data/vendor/format/src/kind_params.rs +101 -0
  1114. data/vendor/format/src/lib.rs +54 -0
  1115. data/vendor/format/src/manifest.rs +1287 -0
  1116. data/vendor/format/src/roaring.rs +865 -0
  1117. data/vendor/format/src/scan.rs +297 -0
  1118. data/vendor/format/src/shm.rs +805 -0
  1119. data/vendor/format/src/sst.rs +233 -0
  1120. data/vendor/format/src/superblock.rs +345 -0
  1121. data/vendor/format/src/value.rs +163 -0
  1122. data/vendor/format/src/varint.rs +87 -0
  1123. data/vendor/format/src/vector.rs +936 -0
  1124. data/vendor/format/src/version.rs +92 -0
  1125. data/vendor/format/src/wal.rs +999 -0
  1126. data/vendor/io/Cargo.toml +29 -0
  1127. data/vendor/io/LICENSE +21 -0
  1128. data/vendor/io/README.md +5 -0
  1129. data/vendor/io/src/async_poll.rs +44 -0
  1130. data/vendor/io/src/buf.rs +694 -0
  1131. data/vendor/io/src/completion.rs +444 -0
  1132. data/vendor/io/src/error.rs +110 -0
  1133. data/vendor/io/src/file.rs +206 -0
  1134. data/vendor/io/src/lib.rs +53 -0
  1135. data/vendor/io/src/nowait.rs +256 -0
  1136. data/vendor/io/src/os/mod.rs +149 -0
  1137. data/vendor/io/src/os/unix.rs +897 -0
  1138. data/vendor/io/src/os/windows.rs +552 -0
  1139. data/vendor/io/src/own.rs +257 -0
  1140. data/vendor/io/src/pread.rs +854 -0
  1141. data/vendor/io/src/ring_wake.rs +113 -0
  1142. data/vendor/io/src/shared.rs +410 -0
  1143. data/vendor/io/src/sim.rs +1545 -0
  1144. data/vendor/io/src/sys.rs +214 -0
  1145. data/vendor/io/src/uring.rs +1839 -0
  1146. data/vendor/io/src/vfs.rs +154 -0
  1147. data/vendor/memory/Cargo.toml +34 -0
  1148. data/vendor/memory/LICENSE +21 -0
  1149. data/vendor/memory/README.md +11 -0
  1150. data/vendor/memory/src/consolidate.rs +640 -0
  1151. data/vendor/memory/src/dedup.rs +231 -0
  1152. data/vendor/memory/src/error.rs +131 -0
  1153. data/vendor/memory/src/feed_loop.rs +572 -0
  1154. data/vendor/memory/src/forget.rs +724 -0
  1155. data/vendor/memory/src/hooks.rs +109 -0
  1156. data/vendor/memory/src/ivf.rs +204 -0
  1157. data/vendor/memory/src/layout.rs +340 -0
  1158. data/vendor/memory/src/lib.rs +61 -0
  1159. data/vendor/memory/src/recall.rs +1182 -0
  1160. data/vendor/memory/src/store.rs +1785 -0
  1161. data/vendor/memory/src/watch.rs +339 -0
  1162. data/vendor/memtable/Cargo.toml +24 -0
  1163. data/vendor/memtable/LICENSE +21 -0
  1164. data/vendor/memtable/README.md +5 -0
  1165. data/vendor/memtable/src/lib.rs +1658 -0
  1166. data/vendor/memtable/src/loom_tests.rs +274 -0
  1167. data/vendor/memtable/src/mem.rs +344 -0
  1168. data/vendor/memtable/src/tests.rs +1061 -0
  1169. data/vendor/pager/Cargo.toml +23 -0
  1170. data/vendor/pager/LICENSE +21 -0
  1171. data/vendor/pager/README.md +5 -0
  1172. data/vendor/pager/src/alloc.rs +1008 -0
  1173. data/vendor/pager/src/lib.rs +1710 -0
  1174. data/vendor/pigeonhole/Cargo.toml +42 -0
  1175. data/vendor/pigeonhole/LICENSE +21 -0
  1176. data/vendor/pigeonhole/README.md +99 -0
  1177. data/vendor/pigeonhole/src/cell.rs +829 -0
  1178. data/vendor/pigeonhole/src/check.rs +368 -0
  1179. data/vendor/pigeonhole/src/db.rs +2324 -0
  1180. data/vendor/pigeonhole/src/doc_support.rs +89 -0
  1181. data/vendor/pigeonhole/src/error.rs +257 -0
  1182. data/vendor/pigeonhole/src/feed.rs +696 -0
  1183. data/vendor/pigeonhole/src/info.rs +425 -0
  1184. data/vendor/pigeonhole/src/lib.rs +202 -0
  1185. data/vendor/pigeonhole/src/merge.rs +135 -0
  1186. data/vendor/pigeonhole/src/metrics.rs +476 -0
  1187. data/vendor/pigeonhole/src/nonblocking.rs +666 -0
  1188. data/vendor/pigeonhole/src/options.rs +2075 -0
  1189. data/vendor/pigeonhole/src/read/budget.rs +584 -0
  1190. data/vendor/pigeonhole/src/read.rs +2463 -0
  1191. data/vendor/pigeonhole/src/recovery.rs +876 -0
  1192. data/vendor/pigeonhole/src/retry.rs +358 -0
  1193. data/vendor/pigeonhole/src/set.rs +103 -0
  1194. data/vendor/pigeonhole/src/table.rs +861 -0
  1195. data/vendor/pigeonhole/src/vector.rs +351 -0
  1196. data/vendor/pigeonhole/src/write.rs +2815 -0
  1197. data/vendor/runtime/Cargo.toml +21 -0
  1198. data/vendor/runtime/LICENSE +21 -0
  1199. data/vendor/runtime/README.md +5 -0
  1200. data/vendor/runtime/src/completion.rs +629 -0
  1201. data/vendor/runtime/src/drivers.rs +1175 -0
  1202. data/vendor/runtime/src/lib.rs +1546 -0
  1203. data/vendor/runtime/src/pool.rs +992 -0
  1204. data/vendor/runtime/src/sched.rs +809 -0
  1205. data/vendor/runtime/src/signal.rs +532 -0
  1206. data/vendor/runtime/src/submit_gate.rs +144 -0
  1207. data/vendor/shm/Cargo.toml +24 -0
  1208. data/vendor/shm/LICENSE +21 -0
  1209. data/vendor/shm/README.md +5 -0
  1210. data/vendor/shm/src/lib.rs +427 -0
  1211. data/vendor/shm/src/lock.rs +153 -0
  1212. data/vendor/shm/src/region.rs +1609 -0
  1213. data/vendor/sst/Cargo.toml +26 -0
  1214. data/vendor/sst/LICENSE +21 -0
  1215. data/vendor/sst/README.md +5 -0
  1216. data/vendor/sst/src/blob.rs +380 -0
  1217. data/vendor/sst/src/iter.rs +803 -0
  1218. data/vendor/sst/src/lib.rs +695 -0
  1219. data/vendor/sst/src/reader.rs +814 -0
  1220. data/vendor/sst/src/writer.rs +596 -0
  1221. data/vendor/text/Cargo.toml +26 -0
  1222. data/vendor/text/LICENSE +21 -0
  1223. data/vendor/text/README.md +9 -0
  1224. data/vendor/text/src/error.rs +108 -0
  1225. data/vendor/text/src/fuzzy.rs +265 -0
  1226. data/vendor/text/src/highlight.rs +236 -0
  1227. data/vendor/text/src/index.rs +1152 -0
  1228. data/vendor/text/src/layout.rs +424 -0
  1229. data/vendor/text/src/lib.rs +75 -0
  1230. data/vendor/text/src/maxscore.rs +658 -0
  1231. data/vendor/text/src/query.rs +450 -0
  1232. data/vendor/text/src/search.rs +569 -0
  1233. data/vendor/text/src/sloppy.rs +460 -0
  1234. data/vendor/text/src/tokenizer.rs +163 -0
  1235. data/vendor/vector/Cargo.toml +28 -0
  1236. data/vendor/vector/LICENSE +21 -0
  1237. data/vendor/vector/README.md +9 -0
  1238. data/vendor/vector/src/error.rs +63 -0
  1239. data/vendor/vector/src/half.rs +167 -0
  1240. data/vendor/vector/src/hooks.rs +135 -0
  1241. data/vendor/vector/src/index.rs +2690 -0
  1242. data/vendor/vector/src/layout.rs +102 -0
  1243. data/vendor/vector/src/lib.rs +52 -0
  1244. data/vendor/vector/src/point.rs +500 -0
  1245. data/vendor/vector/src/rebalancer.rs +200 -0
  1246. data/vendor/vector/src/registry.rs +81 -0
  1247. data/vendor/wal/Cargo.toml +25 -0
  1248. data/vendor/wal/LICENSE +21 -0
  1249. data/vendor/wal/README.md +5 -0
  1250. data/vendor/wal/src/feed.rs +610 -0
  1251. data/vendor/wal/src/foreground.rs +122 -0
  1252. data/vendor/wal/src/lib.rs +458 -0
  1253. data/vendor/wal/src/mem.rs +166 -0
  1254. data/vendor/wal/src/recovery.rs +426 -0
  1255. data/vendor/wal/src/stream.rs +2382 -0
  1256. metadata +1310 -0
@@ -0,0 +1,3582 @@
1
+ //! Tablet splits, merges and moves, and the balancer that decides them (spec: Tablets and
2
+ //! Rebalancing; issue #38).
3
+ //!
4
+ //! Every change runs on the shard that owns the tablets, one at a time, on the same path:
5
+ //!
6
+ //! 1. **Start.** The tablets join `moving`. From now on the shard parks single-shard commits
7
+ //! that touch them (unlogged, so they hold no seqno and never block the watermark) and
8
+ //! refuses PREPAREs that touch them with [`PrepareError::Moved`]; the coordinator retries
9
+ //! such a commit once the tablet map has changed. Their memtables are frozen and flushed.
10
+ //! 2. **Drain.** The change waits until every memtable of the tablets is in SSTs, no prepared
11
+ //! share and no compaction touches them. Shares decided after the freeze land in a fresh
12
+ //! memtable, which is frozen and flushed again.
13
+ //! 3. **Commit.** One manifest request (`ReqKind::Tablets`) retires the old tablets and adds
14
+ //! the new ones (`PutTablet`/`DropTablet`; children reference their parent's SSTs until
15
+ //! compaction rewrites them, D13) and hands out owners. Its view publishes the new tablet
16
+ //! map, memtables and SST set together, so reads are never blocked and never see a
17
+ //! partial change. A shard receiving tablets has its default-timestamp floor raised first
18
+ //! (D11: the floor travels with the tablet).
19
+ //! 4. **Forward.** Parked commits are routed again through the new map: to this shard's
20
+ //! queue, to the new owner, or through two-phase commit when their rows now span shards.
21
+
22
+ use super::*;
23
+ #[cfg(feature = "test-hooks")]
24
+ use crate::engine::hooks::LoadTerm;
25
+
26
+ use pigeonhole_format::key::{Escaped, row_prefix_len};
27
+ use pigeonhole_format::manifest::SstMeta;
28
+
29
+ use crate::catalog::Catalog;
30
+ use crate::manifest::{ReqKind, TabletChange, TabletEdits};
31
+ use crate::snapshot::TabletEntry;
32
+
33
+ /// Row samples kept per tablet and balancer interval (split points for write skew).
34
+ const SAMPLES: usize = 64;
35
+
36
+ /// Weight of the newest interval in the moving averages of write load (#103, D214): one
37
+ /// interval's noise never decides a move on its own.
38
+ const LOAD_ALPHA: f64 = 0.2;
39
+
40
+ /// Consecutive balancer passes a shard's load must stay skewed (above `balance_skew` times
41
+ /// the mean, and at least `balance_min_writes`) before it starts acting on write skew
42
+ /// (D214): short-term noise never moves a tablet.
43
+ const SKEW_PERSIST: u64 = 10;
44
+
45
+ /// Where a shard that is acting on write skew stops (D214): it keeps shedding load after
46
+ /// each dwell until its load falls below `1 + SKEW_STOP * (balance_skew - 1)` times the mean
47
+ /// (1.1 at the default skew of 1.25), then needs `SKEW_PERSIST` skewed passes to start
48
+ /// again.
49
+ const SKEW_STOP: f64 = 0.4;
50
+
51
+ /// Weight of the newest pass in the slow moving average of the mean write load (D224).
52
+ const MEAN_SLOW_ALPHA: f64 = 0.05;
53
+
54
+ /// The mean write load is falling while it is below this fraction of its slow average
55
+ /// (D224, #582). Skew that appears because other shards' load fell, not because this shard's
56
+ /// rose, is the tail of a closed-loop load: the lighter shards finished their work, and the
57
+ /// busy ones look skewed only beside them. Such a pass neither counts toward
58
+ /// `SKEW_PERSIST` nor resets it, and moves no tablet. If the others' load stays down, the
59
+ /// slow average catches up in a few seconds and the skew counts again.
60
+ const MEAN_FALL: f64 = 0.9;
61
+
62
+ /// How long a tablet must go unwritten, and have been on its shard, before it counts as cold
63
+ /// for merges and consolidation (D224): `COLD_PASSES` balancer passes or as many base
64
+ /// intervals of clock (10 s at the default), whichever comes first, so an idle shard backing
65
+ /// off its passes still merges. Longer than a closed-loop load's phases, so a tablet idle only
66
+ /// through a phase's tail (its shard finished its work first) is not merged or moved away.
67
+ pub(crate) const COLD_PASSES: u64 = 100;
68
+
69
+ /// Weight of the newest interval in the slow moving averages of write load (D224): a time
70
+ /// constant of about 10 s at the default interval, longer than a closed-loop load's phases, so
71
+ /// a shard's slow load follows its share of the work rather than its rate while busy.
72
+ const SLOW_ALPHA: f64 = 0.01;
73
+
74
+ /// Balancer passes the slow skew path waits after a change before deciding again (D224):
75
+ /// about the slow averages' time constant, so they show the change first.
76
+ const SLOW_DWELL: u64 = 100;
77
+
78
+ /// Balancer passes a shard waits after starting a move or a skew split, and a tablet stays
79
+ /// put after it arrived on a shard, before write skew moves or splits again (#103): the
80
+ /// moving averages catch up with a change before the next one is decided.
81
+ const DWELL_PASSES: u64 = 10;
82
+
83
+ /// The longest balancer interval of an idle shard: passes that find nothing to do, with no
84
+ /// writes and no tablet change since the last one, double the interval up to this (10 s).
85
+ const BALANCE_IDLE_CAP_NANOS: u64 = 10_000_000_000;
86
+
87
+ /// Packing (D217): the busy fraction each active shard aims for. With `B` the summed busy
88
+ /// fraction of all shards, `ceil(B / PACK_TARGET)` shards stay active, so each has headroom
89
+ /// before commits queue.
90
+ const PACK_TARGET: f64 = 0.5;
91
+
92
+ /// Packing grows the active shards once `B / k` stays above this for `PACK_GROW_PASSES`.
93
+ const PACK_SPREAD: f64 = 0.75;
94
+
95
+ /// Packing (D257): the commits in flight each active shard is sized for. With `C` the mean
96
+ /// number of client commit rounds in flight over the store (every shard's rise of
97
+ /// `commit_inflight_nanos` over the interval, Little's law; a cross-shard commit counts at
98
+ /// its coordinator and at each participant, D262), `round(C / PACK_CONCURRENCY)` shards
99
+ /// stay active, at least one: one writer with one commit in flight gains nothing
100
+ /// from a second shard and pays a wake per write on a thin one (ycsb-a at one client fell
101
+ /// 180K → 130K ops/s spread over 13 shards on the AX102, #734's follow-up), while sixteen
102
+ /// clients with about twelve commits in flight (a get is a quarter of their loop) keep
103
+ /// sixteen. Rounded, so a lone pure writer (`C` → 1) stays on one shard where a ceiling
104
+ /// would give it two. The concurrency is the demand side: it grows `k` and gates a
105
+ /// shrink; the stall and saturation floors (D255, D256) are the capacity side and grow
106
+ /// `k` past it.
107
+ const PACK_CONCURRENCY: f64 = 0.75;
108
+
109
+ /// Consecutive passes over `PACK_SPREAD` before more shards become active (1 s): a burst
110
+ /// spreads quickly.
111
+ const PACK_GROW_PASSES: u64 = 10;
112
+
113
+ /// Consecutive passes with `B / (k - 1)` below `PACK_TARGET` before fewer shards stay active
114
+ /// (5 s): packing is slow, so a pause between bursts does not reshuffle.
115
+ const PACK_SHRINK_PASSES: u64 = 50;
116
+
117
+ /// Balancer passes on which the store must have written before its first shrink from the
118
+ /// unpacked start (30 s at the base interval, a slow-average window, D255, #734): a load's
119
+ /// phases (a load, a settle, a warm-up) dip between them for a few seconds, and a pack on
120
+ /// a dip moves every tablet twice, the second time while the load is measured. On the
121
+ /// AX102 the dip packed 16 shards to 2 at about 21 s and D251's regrowth then moved
122
+ /// tablets back out until about 90 s, a put p99.9 of 290-362 µs against 73 with the moves
123
+ /// out of the measured phase. A light store still packs, 30 s in.
124
+ const PACK_FIRST_SHRINK_PASSES: u64 = 300;
125
+
126
+ /// Packing (D251): an active shard whose thread is busier than this (turn busy, without
127
+ /// D248's sync term) also calls for more active shards, whatever the average (`PACK_SPREAD`
128
+ /// looks only at `B / k`, which a saturated shard beside an idle one never passes), and while
129
+ /// one is, the active shards never shrink.
130
+ const PACK_HOT: f64 = 0.9;
131
+
132
+ /// How much a hot shard's turn busy fraction must fall (millionths) after a hot-triggered
133
+ /// growth before another one (D251): shedding helped.
134
+ const PACK_HOT_COOLED: u64 = 20_000;
135
+
136
+ /// The fast write average over the slow one above which the load is still ramping (D255):
137
+ /// the shrink counter pauses then (it does not reset: a periodic batch writer reads as
138
+ /// ramping after every batch, and a reset would never let it pack). The first pass of a
139
+ /// load read its ramp as a light store and cut the active shards from 16 to 2 or 3 on the
140
+ /// AX102, and the full load then sat there (#734).
141
+ const PACK_RAMP: f64 = 1.25;
142
+
143
+ /// Consecutive ramping passes after which the shrink counter runs anyway (60 s at the base
144
+ /// interval): a load that only ever grows still packs.
145
+ const PACK_RAMP_MAX: u64 = 600;
146
+
147
+ /// Balancer passes after a shrink within which a stall-driven growth undoes it (60 s at
148
+ /// the base interval, D255): the growth goes straight back to the count before the shrink.
149
+ /// Regrowing one shard per ten passes took most of a 16 GiB load on the AX102 after one
150
+ /// mistaken shrink from 16 to 2.
151
+ const PACK_SHRINK_UNDO: u64 = 600;
152
+
153
+ /// A shard reads stalled when its writers stalled on at least `PACK_STALL_PASSES` of the
154
+ /// last `PACK_STALL_WINDOW` balancer passes (3 of 10: about 3 stalls a second at the base
155
+ /// interval, or one wait spanning 0.3 s, D255). A buffered load's stalls are short and a few
156
+ /// per second per shard: a pass-by-pass reading smoothed by the moving average read them at
157
+ /// about half and never hot (the buffered riders row on the AX102: thousands of write stalls,
158
+ /// the top shards' stall terms at 0), while any single stall must not count as capacity (a
159
+ /// light store with one burst would spread). The term is 0 or 1 and the hot test reads it
160
+ /// as published, so the decision is this count, not a moving average's tail.
161
+ const PACK_STALL_WINDOW: u32 = 10;
162
+ const PACK_STALL_PASSES: u32 = 3;
163
+
164
+ /// Balancer passes with no active shard stalling after which a stall-driven floor expires
165
+ /// (30 s at the base interval), and the cap of its doubling after each expiry (D255).
166
+ const PACK_FLOOR_QUIET: u64 = 300;
167
+ const PACK_FLOOR_QUIET_MAX: u64 = 300 * 16;
168
+
169
+ /// Slots reserved on shards receiving tablets (`LoadSlot::reserved`).
170
+ type Reserved = Vec<(ShardId, usize)>;
171
+
172
+ /// A change to tablets this shard owns.
173
+ #[derive(Debug, Clone, PartialEq, Eq)]
174
+ pub(crate) enum TabletOpKind {
175
+ /// Split `tablet` at `keys` (sorted, strictly inside its range); child `i` covers
176
+ /// `[keys[i - 1], keys[i])` and goes to `owners[i]`.
177
+ Split {
178
+ tablet: TabletId,
179
+ keys: Vec<Vec<u8>>,
180
+ owners: Vec<ShardId>,
181
+ },
182
+ /// Merge `left` with `right`, its right neighbour of the same table; both on this shard.
183
+ Merge { left: TabletId, right: TabletId },
184
+ /// Hand `tablet` to shard `to`.
185
+ Move { tablet: TabletId, to: ShardId },
186
+ }
187
+
188
+ impl TabletOpKind {
189
+ /// The tablets the change retires (or hands away).
190
+ fn tablets(&self) -> Vec<TabletId> {
191
+ match self {
192
+ TabletOpKind::Split { tablet, .. } | TabletOpKind::Move { tablet, .. } => {
193
+ vec![*tablet]
194
+ }
195
+ TabletOpKind::Merge { left, right } => vec![*left, *right],
196
+ }
197
+ }
198
+
199
+ /// The other shards receiving a tablet.
200
+ fn targets(&self, me: ShardId) -> Vec<ShardId> {
201
+ let mut out = match self {
202
+ TabletOpKind::Split { owners, .. } => owners.clone(),
203
+ TabletOpKind::Move { to, .. } => vec![*to],
204
+ TabletOpKind::Merge { .. } => Vec::new(),
205
+ };
206
+ out.retain(|s| *s != me);
207
+ out.sort_unstable();
208
+ out.dedup();
209
+ out
210
+ }
211
+ }
212
+
213
+ /// The change in progress on a shard.
214
+ #[derive(Debug)]
215
+ pub(crate) struct ActiveOp {
216
+ kind: TabletOpKind,
217
+ reply: Option<Notifier<Result<()>>>,
218
+ /// The tablets as they were when the change started; the commit checks they are still
219
+ /// so (a table drop may have raced it).
220
+ entries: Vec<TabletEntry>,
221
+ /// The manifest request is in flight.
222
+ committing: bool,
223
+ /// Slots reserved on each receiving shard (`LoadSlot::reserved`), released when the
224
+ /// change ends.
225
+ reserved: Reserved,
226
+ }
227
+
228
+ /// Writes to one tablet during the current balancer interval.
229
+ #[derive(Debug, Default)]
230
+ pub(crate) struct TabletLoad {
231
+ /// Rows written this interval and the one before.
232
+ writes: u64,
233
+ prev_writes: u64,
234
+ /// Rows seen by the reservoir this interval.
235
+ seen: u64,
236
+ /// A uniform sample of the rows written this interval: the first `sampled`. Buffers past
237
+ /// it are earlier intervals' rows, kept for reuse so a new interval's samples do not
238
+ /// allocate (#320).
239
+ samples: Vec<Vec<u8>>,
240
+ sampled: usize,
241
+ /// Moving average of `writes` over intervals (`LOAD_ALPHA`).
242
+ ewma: f64,
243
+ /// Slow moving average of `writes` (`SLOW_ALPHA`, D224).
244
+ slow: f64,
245
+ /// The balancer pass and clock of the last interval with writes (D224).
246
+ last_write: (u64, u64),
247
+ }
248
+
249
+ impl TabletLoad {
250
+ /// This interval's row samples.
251
+ fn live_samples(&self) -> &[Vec<u8>] {
252
+ &self.samples[..self.sampled]
253
+ }
254
+ }
255
+
256
+ /// The balancer settings, copied from `EngineOptions` at open.
257
+ #[derive(Debug, Clone, Copy, Default)]
258
+ pub(crate) struct BalanceConfig {
259
+ /// `EngineOptions::tablet_changes`: off, nothing splits, merges or moves.
260
+ pub enabled: bool,
261
+ pub interval_nanos: u64,
262
+ pub min_writes: u64,
263
+ pub skew: f64,
264
+ pub split_bytes: u64,
265
+ /// `EngineOptions::balance_pack`, engine-owned shards only (D217).
266
+ pub pack: bool,
267
+ /// Unwritten passes before a tablet is cold (`EngineOptions::balance_cold_passes`, D224).
268
+ pub cold_passes: u64,
269
+ }
270
+
271
+ pub(crate) use crate::load_slot::LoadSlot;
272
+
273
+ /// Where a member's rows live.
274
+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
275
+ enum Routing {
276
+ Owned,
277
+ /// A row is in a tablet this shard is splitting, merging or moving.
278
+ Moving,
279
+ /// A row belongs to another shard (the router used an older tablet map).
280
+ Elsewhere,
281
+ }
282
+
283
+ impl ShardState {
284
+ // ---- routing at admission ----
285
+
286
+ /// Admission routing for one member: returns it if this shard should run it now; parks,
287
+ /// forwards or refuses it otherwise.
288
+ pub(super) fn route_member(
289
+ &mut self,
290
+ m: Member,
291
+ ctx: &mut ShardContext<'_, ShardMsg>,
292
+ ) -> Option<Member> {
293
+ match m.kind {
294
+ MemberKind::CommitRecord { .. } => Some(m),
295
+ MemberKind::Prepare { .. } => self.route_prepare(m, ctx),
296
+ MemberKind::Single => self.route_by_map(m, ctx),
297
+ }
298
+ }
299
+
300
+ /// A PREPARE's admission routing: routed as any member (D263); a test hook can refuse it
301
+ /// as overlapping an undecided share.
302
+ #[inline(never)]
303
+ fn route_prepare(&mut self, m: Member, ctx: &mut ShardContext<'_, ShardMsg>) -> Option<Member> {
304
+ #[cfg(feature = "test-hooks")]
305
+ {
306
+ let forced = &self.shared.metrics[usize::from(self.id.0)]
307
+ .hooks
308
+ .refuse_prepares;
309
+ if forced.load(Ordering::Acquire) > 0 {
310
+ forced.fetch_sub(1, Ordering::AcqRel);
311
+ // Nothing here overlaps it, so the abort's decision wakes its coordinator.
312
+ self.refuse_for_overlap(m, ctx);
313
+ return None;
314
+ }
315
+ }
316
+ // A PREPARE carries no timestamp: its coordinator picks one at the decision, above
317
+ // every participant's floor then (D263). Per-row order comes from admission's
318
+ // overlap rule (`overlaps_undecided`).
319
+ self.route_by_map(m, ctx)
320
+ }
321
+
322
+ /// Routing through the tablet map for a single or a PREPARE: returns it if this shard
323
+ /// should run it now; parks, forwards or refuses it otherwise. Inlined into both callers:
324
+ /// a single's commit path pays no call for it.
325
+ #[inline(always)]
326
+ fn route_by_map(&mut self, m: Member, ctx: &mut ShardContext<'_, ShardMsg>) -> Option<Member> {
327
+ let single = matches!(m.kind, MemberKind::Single);
328
+ if self.moving.is_empty() && m.map_version >= self.lost_version {
329
+ return Some(m);
330
+ }
331
+ let mut routing = self.routing_of(&m);
332
+ if routing == Routing::Elsewhere {
333
+ // Our map may be the stale one.
334
+ self.refresh_tablets();
335
+ routing = self.routing_of(&m);
336
+ }
337
+ if single && routing == Routing::Owned && !self.parked.is_empty() {
338
+ // Per-row submission order: behind a parked commit on any of the same rows.
339
+ let rows = member_rows(&m);
340
+ if rows.iter().any(|h| self.parked_rows.contains(h)) {
341
+ routing = Routing::Moving;
342
+ }
343
+ }
344
+ match (routing, single) {
345
+ (Routing::Owned, _) => Some(m),
346
+ (Routing::Moving, true) => {
347
+ self.parked_rows.extend(member_rows(&m));
348
+ self.parked.push(m);
349
+ self.arm_tablet_timer(ctx);
350
+ None
351
+ }
352
+ (Routing::Elsewhere, true) => self.forward(m, ctx),
353
+ (_, false) => {
354
+ self.shared.metrics[usize::from(self.id.0)].count_refusal(CrossRefusal::Moved);
355
+ self.refuse_prepare(m, PrepareError::Moved, ctx);
356
+ None
357
+ }
358
+ }
359
+ }
360
+
361
+ fn routing_of(&self, m: &Member) -> Routing {
362
+ let prepare = matches!(m.kind, MemberKind::Prepare { .. });
363
+ let mut out = Routing::Owned;
364
+ // A share routed with an older tablet map may name rows this shard no longer owns,
365
+ // and its reads may now belong to a shard outside the commit (nobody would validate
366
+ // them): it runs again through the new map only then (#102). A read another
367
+ // participant owns now is validated there, under that shard's current map.
368
+ let participants: Option<&[ShardId]> = (prepare && m.map_version < self.tablets.version())
369
+ .then(|| {
370
+ self.prepared
371
+ .get(&m.seqno)
372
+ .map_or(&[][..], |s| s.participants.as_slice())
373
+ });
374
+ let mut look = |table: TableId, row: &[u8], read_by_others: bool| {
375
+ if let Some((tablet, owner)) = self.tablets.route(table, row) {
376
+ if self.moving.contains(&tablet) {
377
+ out = Routing::Moving;
378
+ } else if owner != self.id
379
+ && out == Routing::Owned
380
+ && (!read_by_others || participants.is_some_and(|p| !p.contains(&owner)))
381
+ {
382
+ out = Routing::Elsewhere;
383
+ }
384
+ }
385
+ };
386
+ if let Ok(batch) = m.bytes.batch() {
387
+ for mu in batch.iter().flatten() {
388
+ look(mu.table, mu.row, false);
389
+ }
390
+ }
391
+ // A PREPARE carries the whole commit's reads; each participant validates its own.
392
+ if let Some(reads) = m.validate.as_ref().map(|v| &v.reads) {
393
+ for r in reads {
394
+ look(r.table, &r.row, prepare);
395
+ }
396
+ }
397
+ if let Some((table, row, _)) = m.predicate.as_deref() {
398
+ look(*table, row, false);
399
+ }
400
+ out
401
+ }
402
+
403
+ /// A PREPARE that would wait for arena room, refused instead (D245, ICR 0042); its
404
+ /// coordinator hears a room `Wake` once this shard's room wait ends.
405
+ #[inline(never)]
406
+ pub(super) fn refuse_for_room(
407
+ &mut self,
408
+ m: Member,
409
+ coordinator: ShardId,
410
+ ctx: &mut ShardContext<'_, ShardMsg>,
411
+ ) {
412
+ #[cfg(feature = "test-hooks")]
413
+ self.shared
414
+ .hooks
415
+ .room_refusals
416
+ .fetch_add(1, Ordering::Relaxed);
417
+ self.shared.metrics[usize::from(self.id.0)].count_refusal(CrossRefusal::Room);
418
+ if !self.room_refused.contains(&coordinator) {
419
+ self.room_refused.push(coordinator);
420
+ }
421
+ self.room_refused_free = self.arena.free_bytes().saturating_sub(self.reserved);
422
+ self.refuse_prepare(m, PrepareError::Room(self.room_generation), ctx);
423
+ }
424
+
425
+ /// Whether room may fit a share this shard refused for room (D245): its room wait ended,
426
+ /// or nothing waits or flushes and more is free than at the latest refusal (after
427
+ /// reclaiming the memtables readers left).
428
+ #[inline(never)]
429
+ pub(super) fn room_freed_since_refusal(&mut self) -> bool {
430
+ if self.room_wait.is_none() {
431
+ return true;
432
+ }
433
+ if !self.pending.is_empty() || self.flush_running || !self.flush_queue.is_empty() {
434
+ return false;
435
+ }
436
+ self.reclaim_retired();
437
+ self.refresh_free();
438
+ self.arena.free_bytes().saturating_sub(self.reserved) > self.room_refused_free
439
+ }
440
+
441
+ /// Tells the coordinators this shard refused for room that its room will not free: it
442
+ /// waits on a frozen clock with nothing in flight (#70). Their retries give up with
443
+ /// `Busy`, as a waiting single is refused (D301).
444
+ #[inline(never)]
445
+ pub(super) fn notify_room_gone(&mut self, ctx: &mut ShardContext<'_, ShardMsg>) {
446
+ self.room_generation += 1;
447
+ let generation = self.room_generation;
448
+ for c in std::mem::take(&mut self.room_refused) {
449
+ trace!(
450
+ "shard {} room gone ({generation}): tells {}",
451
+ self.id.0, c.0
452
+ );
453
+ self.send(
454
+ c,
455
+ ShardMsg::Wake {
456
+ from: self.id,
457
+ reason: WakeReason::RoomGone { generation },
458
+ },
459
+ ctx,
460
+ );
461
+ }
462
+ }
463
+
464
+ /// Tells the coordinators this shard refused for room that it has room again (D245).
465
+ #[inline(never)]
466
+ pub(super) fn notify_room_freed(&mut self, ctx: &mut ShardContext<'_, ShardMsg>) {
467
+ self.room_generation += 1;
468
+ let generation = self.room_generation;
469
+ for c in std::mem::take(&mut self.room_refused) {
470
+ trace!(
471
+ "shard {} room freed ({generation}): tells {}",
472
+ self.id.0, c.0
473
+ );
474
+ self.send(
475
+ c,
476
+ ShardMsg::Wake {
477
+ from: self.id,
478
+ reason: WakeReason::Room { generation },
479
+ },
480
+ ctx,
481
+ );
482
+ }
483
+ }
484
+
485
+ /// The rows a conditional member writes, reads, or tests (`hash_row`), deduplicated: what
486
+ /// `conflicts_with_group` checks against undecided shares.
487
+ fn member_row_hashes(m: &Member) -> Vec<u64> {
488
+ let mut rows = Vec::new();
489
+ if let Ok(batch) = m.bytes.batch() {
490
+ for mu in batch.iter().flatten() {
491
+ rows.push(hash_row(mu.table, mu.row));
492
+ }
493
+ }
494
+ if let Some(v) = &m.validate {
495
+ for r in &v.reads {
496
+ rows.push(hash_row(r.table, &r.row));
497
+ }
498
+ }
499
+ if let Some((table, row, _)) = m.predicate.as_deref() {
500
+ rows.push(hash_row(*table, row));
501
+ }
502
+ rows.sort_unstable();
503
+ rows.dedup();
504
+ rows
505
+ }
506
+
507
+ /// A PREPARE overlapping an undecided share, refused rather than held (D249, ICR 0045).
508
+ /// Its coordinator is woken once no undecided share here overlaps it; if one of the
509
+ /// shares it overlaps belongs to an older commit, only once that commit has run its next
510
+ /// attempt here (or its last, or retried elsewhere), so the older one goes first.
511
+ #[cold]
512
+ #[inline(never)]
513
+ pub(super) fn refuse_for_overlap(&mut self, m: Member, ctx: &mut ShardContext<'_, ShardMsg>) {
514
+ self.refuse_waiting(m, OverlapWait::Shares, ctx);
515
+ }
516
+
517
+ /// [`refuse_for_overlap`](Self::refuse_for_overlap), waiting for `wait` (D267): a
518
+ /// refusal by a reader's fence waits behind that reader, and one by a waiting single
519
+ /// until the single is logged, rather than for shares that may already be gone, which
520
+ /// would wake it at once to be refused again.
521
+ #[cold]
522
+ #[inline(never)]
523
+ pub(super) fn refuse_waiting(
524
+ &mut self,
525
+ m: Member,
526
+ wait: OverlapWait,
527
+ ctx: &mut ShardContext<'_, ShardMsg>,
528
+ ) {
529
+ let MemberKind::Prepare { coordinator } = m.kind else {
530
+ return;
531
+ };
532
+ let rows = Self::member_row_hashes(&m);
533
+ let priority = self
534
+ .prepared
535
+ .get(&m.seqno)
536
+ .map_or((0, m.seqno), |s| s.priority);
537
+ // The oldest commit among the undecided shares it overlaps.
538
+ let mut oldest: Option<(CommitPriority, Seqno)> = None;
539
+ for (seqno, share) in &self.prepared {
540
+ if *seqno == m.seqno || !share.tracked {
541
+ continue;
542
+ }
543
+ let overlaps = share
544
+ .bytes
545
+ .batch()
546
+ .iter()
547
+ .flatten()
548
+ .any(|mu| rows.binary_search(&hash_row(mu.table, mu.row)).is_ok());
549
+ if overlaps && oldest.is_none_or(|(p, _)| share.priority < p) {
550
+ oldest = Some((share.priority, *seqno));
551
+ }
552
+ }
553
+ let (behind, single) = match wait {
554
+ OverlapWait::Shares => (oldest.filter(|(p, _)| *p < priority), 0),
555
+ OverlapWait::Fence(reader) => (Some((reader, 0)), 0),
556
+ OverlapWait::Single(id) => (None, id),
557
+ };
558
+ // D267: a commit that reads cannot chain; older than every undecided share on its
559
+ // rows, it fences them, so younger blind PREPAREs stop chaining there and the row
560
+ // drains for its retry.
561
+ if behind.is_none()
562
+ && oldest.is_none_or(|(p, _)| p > priority)
563
+ && (m.validate.as_ref().is_some_and(|v| !v.reads.is_empty()) || m.predicate.is_some())
564
+ {
565
+ self.reader_fences.retain(|(p, _)| *p != priority);
566
+ self.reader_fences.push((priority, rows.clone()));
567
+ }
568
+ trace!(
569
+ "shard {} refuses {} {priority:?} over an undecided overlap (behind {behind:?})",
570
+ self.id.0, m.seqno
571
+ );
572
+ self.shared.metrics[usize::from(self.id.0)].count_refusal(CrossRefusal::PendingOverlap);
573
+ let validate = m.validate.clone().filter(|v| !v.reads.is_empty());
574
+ self.overlap_refused.push(OverlapRefusal {
575
+ coordinator,
576
+ priority,
577
+ rows,
578
+ behind,
579
+ single,
580
+ validate,
581
+ });
582
+ self.refuse_prepare(m, PrepareError::PendingOverlap, ctx);
583
+ }
584
+
585
+ /// The rows `m` writes (`hash_row`), sorted and deduplicated.
586
+ fn written_rows(m: &Member) -> Vec<u64> {
587
+ let mut rows: Vec<u64> = m
588
+ .bytes
589
+ .batch()
590
+ .map(|b| {
591
+ b.iter()
592
+ .flatten()
593
+ .map(|mu| hash_row(mu.table, mu.row))
594
+ .collect()
595
+ })
596
+ .unwrap_or_default();
597
+ rows.sort_unstable();
598
+ rows.dedup();
599
+ rows
600
+ }
601
+
602
+ /// The rows `m` reads (validated reads, predicate row), sorted and deduplicated.
603
+ fn read_rows(m: &Member) -> Vec<u64> {
604
+ let mut rows: Vec<u64> = m
605
+ .validate
606
+ .as_ref()
607
+ .map(|v| v.reads.iter().map(|r| hash_row(r.table, &r.row)).collect())
608
+ .unwrap_or_default();
609
+ if let Some((table, row, _)) = m.predicate.as_deref() {
610
+ rows.push(hash_row(*table, row));
611
+ }
612
+ // D314: a returning member reads its row at apply (simp724's Q2 on #1440).
613
+ if let Reply::Returning(_) = &m.reply
614
+ && let Ok(batch) = m.bytes.batch()
615
+ {
616
+ rows.extend(batch.iter().flatten().map(|mu| hash_row(mu.table, mu.row)));
617
+ }
618
+ rows.sort_unstable();
619
+ rows.dedup();
620
+ rows
621
+ }
622
+
623
+ /// The tracked undecided shares here that write or read one of `rows` (sorted), with
624
+ /// their priorities, in seqno order (`prepared` is a hash map; a seed replays).
625
+ fn shares_on(&self, rows: &[u64], skip: Seqno) -> Vec<(Seqno, CommitPriority)> {
626
+ let mut on: Vec<(Seqno, CommitPriority)> = self
627
+ .prepared
628
+ .iter()
629
+ .filter(|(seqno, share)| {
630
+ **seqno != skip
631
+ && share.tracked
632
+ && (share.reads.iter().any(|h| rows.binary_search(h).is_ok())
633
+ || share
634
+ .bytes
635
+ .batch()
636
+ .iter()
637
+ .flatten()
638
+ .any(|mu| rows.binary_search(&hash_row(mu.table, mu.row)).is_ok()))
639
+ })
640
+ .map(|(seqno, share)| (*seqno, share.priority))
641
+ .collect();
642
+ on.sort_unstable();
643
+ on
644
+ }
645
+
646
+ /// Whether blind PREPARE `m` writes a row a refused reading commit older than it fences
647
+ /// (D267): it is refused, chained or not, so the row drains for that commit's retry.
648
+ /// The oldest such commit, which the refusal waits behind. A PREPARE that reads cannot
649
+ /// chain, so it cannot keep the row from draining: it is not fenced, and D249 orders
650
+ /// it as before (fenced, every reading commit on a hot row waited out an older one's
651
+ /// whole retry).
652
+ #[inline]
653
+ pub(super) fn fenced(&self, m: &Member) -> Option<CommitPriority> {
654
+ if self.reader_fences.is_empty()
655
+ || m.validate.as_ref().is_some_and(|v| !v.reads.is_empty())
656
+ || m.predicate.is_some()
657
+ {
658
+ return None;
659
+ }
660
+ self.fenced_slow(m)
661
+ }
662
+
663
+ #[cold]
664
+ #[inline(never)]
665
+ fn fenced_slow(&self, m: &Member) -> Option<CommitPriority> {
666
+ let priority = self.prepared.get(&m.seqno)?.priority;
667
+ let rows = Self::written_rows(m);
668
+ self.reader_fences
669
+ .iter()
670
+ .filter(|(p, fenced)| {
671
+ *p < priority && fenced.iter().any(|h| rows.binary_search(h).is_ok())
672
+ })
673
+ .map(|(p, _)| *p)
674
+ .min()
675
+ }
676
+
677
+ /// Single `m` starts waiting for the undecided shares on its rows (D267): it waits for
678
+ /// those only; shares chained on its rows later wait for it.
679
+ #[cold]
680
+ #[inline(never)]
681
+ pub(super) fn start_share_wait(&mut self, m: &mut Member) {
682
+ let writes = Self::written_rows(m);
683
+ let reads = Self::read_rows(m);
684
+ let mut ahead: Vec<Seqno> = self
685
+ .shares_on(&writes, 0)
686
+ .into_iter()
687
+ .map(|(seqno, _)| seqno)
688
+ .collect();
689
+ // A row it reads waits only for the shares writing it.
690
+ for (seqno, share) in &self.prepared {
691
+ if share.tracked
692
+ && share
693
+ .bytes
694
+ .batch()
695
+ .iter()
696
+ .flatten()
697
+ .any(|mu| reads.binary_search(&hash_row(mu.table, mu.row)).is_ok())
698
+ {
699
+ ahead.push(*seqno);
700
+ }
701
+ }
702
+ ahead.sort_unstable();
703
+ ahead.dedup();
704
+ let mut rows = writes.clone();
705
+ rows.extend(&reads);
706
+ rows.sort_unstable();
707
+ rows.dedup();
708
+ self.next_share_wait = self.next_share_wait.wrapping_add(1).max(1);
709
+ let id = self.next_share_wait;
710
+ for h in &rows {
711
+ self.single_rows.entry(*h).or_default().push(id);
712
+ }
713
+ self.waiting_singles.insert(
714
+ id,
715
+ WaitingSingle {
716
+ ahead,
717
+ writes,
718
+ reads,
719
+ rows,
720
+ },
721
+ );
722
+ m.share_wait = id;
723
+ }
724
+
725
+ /// Whether waiting single `m` still has a share it waits for undecided here.
726
+ #[cold]
727
+ #[inline(never)]
728
+ pub(super) fn single_ahead_undecided(&self, m: &Member) -> bool {
729
+ self.waiting_singles.get(&m.share_wait).is_some_and(|w| {
730
+ w.ahead
731
+ .iter()
732
+ .any(|s| self.prepared.get(s).is_some_and(|share| share.tracked))
733
+ })
734
+ }
735
+
736
+ /// A waiting single that writes a row PREPARE `m` reads (D267), or reads a row `m`
737
+ /// writes (D271, perf287's M1), if any.
738
+ #[inline]
739
+ pub(super) fn overlaps_waiting_single(&self, m: &Member) -> Option<u32> {
740
+ if self.waiting_singles.is_empty() {
741
+ return None;
742
+ }
743
+ self.overlaps_waiting_single_slow(m)
744
+ }
745
+
746
+ #[cold]
747
+ #[inline(never)]
748
+ fn overlaps_waiting_single_slow(&self, m: &Member) -> Option<u32> {
749
+ let on = |rows: Vec<u64>, of: fn(&WaitingSingle) -> &[u64]| {
750
+ rows.into_iter().find_map(|h| {
751
+ self.single_rows.get(&h).and_then(|ids| {
752
+ ids.iter()
753
+ .copied()
754
+ .find(|id| of(&self.waiting_singles[id]).binary_search(&h).is_ok())
755
+ })
756
+ })
757
+ };
758
+ on(Self::read_rows(m), |w| &w.writes).or_else(|| on(Self::written_rows(m), |w| &w.reads))
759
+ }
760
+
761
+ /// Waiting single `id` was logged, or failed (D267): the shares chained behind it count
762
+ /// one less.
763
+ #[cold]
764
+ #[inline(never)]
765
+ pub(super) fn end_single_wait(&mut self, id: u32, ctx: &mut ShardContext<'_, ShardMsg>) {
766
+ let Some(w) = self.waiting_singles.remove(&id) else {
767
+ return;
768
+ };
769
+ for h in &w.rows {
770
+ if let Some(ids) = self.single_rows.get_mut(h) {
771
+ ids.retain(|i| *i != id);
772
+ if ids.is_empty() {
773
+ self.single_rows.remove(h);
774
+ }
775
+ }
776
+ }
777
+ // The PREPAREs it refused may retry (R4: not before, or they spin).
778
+ let mut i = 0;
779
+ while i < self.overlap_refused.len() {
780
+ if self.overlap_refused[i].single == id {
781
+ let r = self.overlap_refused.swap_remove(i);
782
+ self.wake_overlap(r, ctx);
783
+ } else {
784
+ i += 1;
785
+ }
786
+ }
787
+ }
788
+
789
+ /// After a decision here (D249): wakes the coordinators refused over an overlap that has
790
+ /// cleared. One waiting behind an older commit is woken once that commit's next attempt
791
+ /// here (a later seqno than the share it met) commits, or by its last; any other once
792
+ /// no undecided share here holds its rows. Not by an aborted attempt (D263): the older
793
+ /// commit's attempt may have been refused elsewhere over the younger one's share, at the
794
+ /// younger one's own coordinator, and woken together they would cross again on every
795
+ /// round. The younger one holds no share while it waits, so the older one's retry
796
+ /// meets none of its shares.
797
+ #[inline(never)]
798
+ pub(super) fn release_overlaps(
799
+ &mut self,
800
+ seqno: Seqno,
801
+ priority: CommitPriority,
802
+ commit: bool,
803
+ last: bool,
804
+ ctx: &mut ShardContext<'_, ShardMsg>,
805
+ ) {
806
+ if last && !self.reader_fences.is_empty() {
807
+ // Its last attempt: a fence it set here is done (D267).
808
+ self.reader_fences.retain(|(p, _)| *p != priority);
809
+ }
810
+ let mut i = 0;
811
+ while i < self.overlap_refused.len() {
812
+ let r = &self.overlap_refused[i];
813
+ let go = r.single == 0
814
+ && match r.behind {
815
+ Some((older, met)) => older == priority && (last || (commit && seqno > met)),
816
+ None => !r.rows.iter().any(|h| {
817
+ self.pending_rows.contains_key(h) || self.pending_reads.contains_key(h)
818
+ }),
819
+ };
820
+ if go {
821
+ let r = self.overlap_refused.swap_remove(i);
822
+ self.wake_overlap(r, ctx);
823
+ } else {
824
+ i += 1;
825
+ }
826
+ }
827
+ }
828
+
829
+ /// A share of the commit of `priority`, writing `written` (`hash_row`, sorted), committed
830
+ /// here (D276): a refused commit that reads one of those rows and now fails validation
831
+ /// on it would fail its retry the same way (its snapshot stays, and a version above it
832
+ /// stays above it), so its coordinator is told to fail it now, without another round.
833
+ #[cold]
834
+ #[inline(never)]
835
+ pub(super) fn doom_overlaps(
836
+ &mut self,
837
+ priority: CommitPriority,
838
+ written: &[u64],
839
+ ctx: &mut ShardContext<'_, ShardMsg>,
840
+ ) {
841
+ let mut refused = std::mem::take(&mut self.overlap_refused);
842
+ let mut i = 0;
843
+ while i < refused.len() {
844
+ let r = &refused[i];
845
+ let doomed = r.priority != priority
846
+ && r.validate.as_deref().is_some_and(|v| {
847
+ v.reads.iter().any(|read| {
848
+ written
849
+ .binary_search(&hash_row(read.table, &read.row))
850
+ .is_ok()
851
+ && self.conflicts(v.seqno, read).unwrap_or(false)
852
+ })
853
+ });
854
+ if doomed {
855
+ let r = refused.swap_remove(i);
856
+ trace!(
857
+ "shard {} dooms {:?}: tells {}",
858
+ self.id.0, r.priority, r.coordinator.0
859
+ );
860
+ // Through the queue, as `wake_overlap`.
861
+ let _ = ctx.submitter(r.coordinator).submit(ShardMsg::Wake {
862
+ from: self.id,
863
+ reason: WakeReason::Doomed {
864
+ priority: r.priority,
865
+ },
866
+ });
867
+ } else {
868
+ i += 1;
869
+ }
870
+ }
871
+ refused.append(&mut self.overlap_refused);
872
+ self.overlap_refused = refused;
873
+ }
874
+
875
+ /// The commit of `priority` retries without this shard (D249): the commits waiting here
876
+ /// behind it are woken.
877
+ pub(super) fn release_overlaps_behind(
878
+ &mut self,
879
+ priority: CommitPriority,
880
+ ctx: &mut ShardContext<'_, ShardMsg>,
881
+ ) {
882
+ // It retries without this shard: a fence it set here is done (D267).
883
+ self.reader_fences.retain(|(p, _)| *p != priority);
884
+ let mut i = 0;
885
+ while i < self.overlap_refused.len() {
886
+ if self.overlap_refused[i]
887
+ .behind
888
+ .is_some_and(|(older, _)| older == priority)
889
+ {
890
+ let r = self.overlap_refused.swap_remove(i);
891
+ self.wake_overlap(r, ctx);
892
+ } else {
893
+ i += 1;
894
+ }
895
+ }
896
+ }
897
+
898
+ fn wake_overlap(&mut self, r: OverlapRefusal, ctx: &mut ShardContext<'_, ShardMsg>) {
899
+ trace!(
900
+ "shard {} overlap cleared for {:?}: tells {}",
901
+ self.id.0, r.priority, r.coordinator.0
902
+ );
903
+ // Through the queue even to this shard: it must follow what this shard queued for the
904
+ // same commit before it, or the coordinator, not yet waiting, drops it (D249).
905
+ let _ = ctx.submitter(r.coordinator).submit(ShardMsg::Wake {
906
+ from: self.id,
907
+ reason: WakeReason::Overlap {
908
+ priority: r.priority,
909
+ },
910
+ });
911
+ }
912
+
913
+ /// A coordinator's side of a participant's wake (D245, D249): the retries it wakes run
914
+ /// now (`RetryWait::woken_by`). Room is remembered per shard by generation, for a retry
915
+ /// still in its abort round; an overlap wake that came before the refused round was
916
+ /// decided is kept for that commit's retry.
917
+ pub(super) fn on_wake(
918
+ &mut self,
919
+ from: ShardId,
920
+ reason: WakeReason,
921
+ ctx: &mut ShardContext<'_, ShardMsg>,
922
+ ) {
923
+ if let WakeReason::Room { generation } = reason {
924
+ let seen = &mut self.room_freed[usize::from(from.0)];
925
+ *seen = (*seen).max(generation);
926
+ }
927
+ if let WakeReason::RoomGone { generation } = reason {
928
+ let seen = &mut self.room_gone[usize::from(from.0)];
929
+ *seen = (*seen).max(generation);
930
+ }
931
+ if let WakeReason::Doomed { priority } = reason {
932
+ self.on_doomed(priority, ctx);
933
+ return;
934
+ }
935
+ let (ready, wait): (Vec<CoordinateReq>, Vec<CoordinateReq>) =
936
+ std::mem::take(&mut self.retries)
937
+ .into_iter()
938
+ .partition(|r| {
939
+ r.wait
940
+ .is_some_and(|w| w.woken_by(from, reason, (r.submitted_at, r.first_seqno)))
941
+ });
942
+ self.retries = wait;
943
+ trace!(
944
+ "shard {} wake from {} ({reason:?}): {} retries ready",
945
+ self.id.0,
946
+ from.0,
947
+ ready.len()
948
+ );
949
+ if let WakeReason::Overlap { priority } = reason
950
+ && ready.is_empty()
951
+ && self
952
+ .coord
953
+ .values()
954
+ .any(|c| c.priority == priority && c.refused == Some(RetryWait::Overlap { from }))
955
+ {
956
+ self.overlap_released.push((from, priority));
957
+ }
958
+ for mut r in ready {
959
+ r.wait = None;
960
+ if self.closing {
961
+ r.reply.notify(Err(Error::Closed));
962
+ } else if matches!(reason, WakeReason::RoomGone { .. }) {
963
+ // Its room will not free (D301).
964
+ trace!(
965
+ "shard {} gives up on a room retry: room gone on {}",
966
+ self.id.0, from.0
967
+ );
968
+ r.reply.notify(Err(Error::Busy));
969
+ } else {
970
+ self.retry(r, ctx);
971
+ }
972
+ }
973
+ self.try_finish_close(ctx);
974
+ self.arm_tablet_timer(ctx);
975
+ }
976
+
977
+ /// A participant found the commit of `priority` doomed (D276): a retry waiting for its
978
+ /// wake fails now; one whose round is still undecided or aborting fails at the round's
979
+ /// end (`on_applied`). Otherwise it has ended, or it runs a later round: that round's
980
+ /// PREPARE there either came after the doom and fails validation, or was refused again
981
+ /// and doomed in the same pass.
982
+ fn on_doomed(&mut self, priority: CommitPriority, ctx: &mut ShardContext<'_, ShardMsg>) {
983
+ if let Some(i) = self
984
+ .retries
985
+ .iter()
986
+ .position(|r| (r.submitted_at, r.first_seqno) == priority)
987
+ {
988
+ let r = self.retries.swap_remove(i);
989
+ self.overlap_released.retain(|(_, p)| *p != priority);
990
+ self.fail_doomed(r.submitted_at, r.first_seqno, &r.prev_shards, r.reply, ctx);
991
+ } else if self
992
+ .coord
993
+ .values()
994
+ .any(|c| c.priority == priority && !c.committing)
995
+ && !self.doomed.contains(&priority)
996
+ {
997
+ self.doomed.push(priority);
998
+ }
999
+ }
1000
+
1001
+ /// Ends a doomed commit (D276) with `Conflict`: its last participants hear `Released`,
1002
+ /// so fences it set and commits waiting behind it there go on, as for any commit that
1003
+ /// runs no further attempt.
1004
+ pub(super) fn fail_doomed(
1005
+ &mut self,
1006
+ submitted_at: u64,
1007
+ first_seqno: Seqno,
1008
+ shards: &[ShardId],
1009
+ reply: Notifier<Result<Settled>>,
1010
+ ctx: &mut ShardContext<'_, ShardMsg>,
1011
+ ) {
1012
+ trace!(
1013
+ "shard {} fails doomed {:?}",
1014
+ self.id.0,
1015
+ (submitted_at, first_seqno)
1016
+ );
1017
+ self.shared.metrics[usize::from(self.id.0)]
1018
+ .cross
1019
+ .failed_fast
1020
+ .fetch_add(1, Ordering::Relaxed);
1021
+ self.release_shards(submitted_at, first_seqno, shards, ctx);
1022
+ reply.notify(Err(Error::Conflict));
1023
+ self.try_finish_close(ctx);
1024
+ }
1025
+
1026
+ /// A PREPARE refused without a record: for rows this shard is moving or no longer owns
1027
+ /// (`Moved`: the coordinator retries through the new tablet map), for arena room or an
1028
+ /// undecided share's rows (the coordinator retries on this shard's wake).
1029
+ fn refuse_prepare(
1030
+ &mut self,
1031
+ m: Member,
1032
+ error: PrepareError,
1033
+ ctx: &mut ShardContext<'_, ShardMsg>,
1034
+ ) {
1035
+ let MemberKind::Prepare { coordinator } = m.kind else {
1036
+ return;
1037
+ };
1038
+ if let Some(share) = self.prepared.remove(&m.seqno) {
1039
+ if share.tracked {
1040
+ self.track_share_rows(share.bytes.batch(), false);
1041
+ self.track_share_reads(&share.reads, false);
1042
+ }
1043
+ self.release_room(share.reserved);
1044
+ }
1045
+ self.release_room(m.reserved);
1046
+ self.send(
1047
+ coordinator,
1048
+ ShardMsg::Prepared {
1049
+ seqno: m.seqno,
1050
+ from: self.id,
1051
+ error: Some(error),
1052
+ },
1053
+ ctx,
1054
+ );
1055
+ }
1056
+
1057
+ /// Routes a single-shard member again through the current tablet map. Returns it when it
1058
+ /// is this shard's; otherwise submits it to its owner (or to two-phase commit when its
1059
+ /// rows now span shards) and returns `None`.
1060
+ pub(super) fn forward(
1061
+ &mut self,
1062
+ mut m: Member,
1063
+ ctx: &mut ShardContext<'_, ShardMsg>,
1064
+ ) -> Option<Member> {
1065
+ if m.share_wait != 0 {
1066
+ // It leaves: what it waited for here no longer orders it, and the shares chained
1067
+ // behind it here go on (D267).
1068
+ self.end_single_wait(m.share_wait, ctx);
1069
+ m.share_wait = 0;
1070
+ }
1071
+ let view = self.shared.view.load_full();
1072
+ let shards = commit_shards(
1073
+ &view,
1074
+ m.bytes.as_slice(),
1075
+ m.validate.as_ref().map(|v| v.reads.as_slice()),
1076
+ m.predicate.as_deref().map(|(t, r, _)| (*t, r.as_slice())),
1077
+ );
1078
+ let shards = match shards {
1079
+ Ok(s) => s,
1080
+ Err(e) => {
1081
+ self.release_prev_shards(&m, ctx);
1082
+ m.reply.resolve(Err(e));
1083
+ return None;
1084
+ }
1085
+ };
1086
+ if shards.len() <= 1 {
1087
+ // A retried cross-shard commit now on one shard runs no further two-phase attempt
1088
+ // at its earlier participants: commits refused there behind it (D249's
1089
+ // older-first) are released now, or they would wait for the write-stall timeout
1090
+ // (#772).
1091
+ self.release_prev_shards(&m, ctx);
1092
+ }
1093
+ match shards.as_slice() {
1094
+ [] => Some(m),
1095
+ [s] if *s == self.id => {
1096
+ self.refresh_tablets();
1097
+ Some(m)
1098
+ }
1099
+ [s] => {
1100
+ let s = *s;
1101
+ let mut req = member_req(m);
1102
+ req.map_version = view.tablets.version();
1103
+ if let Err(pigeonhole_runtime::Error::Closed) =
1104
+ ctx.submitter(s).submit(ShardMsg::Commit(req))
1105
+ {
1106
+ // The message (and its reply) is dropped with the closed queue: the
1107
+ // waiter sees `Closed`.
1108
+ }
1109
+ None
1110
+ }
1111
+ _ => {
1112
+ let req = member_req(m);
1113
+ let Reply::Commit(reply) = req.reply else {
1114
+ req.reply.resolve(Err(Error::InvalidArgument(
1115
+ "check_and_mutate touches one row".to_owned(),
1116
+ )));
1117
+ return None;
1118
+ };
1119
+ let parts = match split_by_shard(&view, &req.bytes, &shards) {
1120
+ Ok(p) => p,
1121
+ Err(e) => {
1122
+ reply.notify(Err(e));
1123
+ return None;
1124
+ }
1125
+ };
1126
+ let retried = req.retry.map(|r| *r).unwrap_or_default();
1127
+ let creq = CoordinateReq {
1128
+ parts,
1129
+ durability: req.durability,
1130
+ reply,
1131
+ submitted_at: req.submitted_at,
1132
+ validate: req.validate,
1133
+ map_version: view.tablets.version(),
1134
+ epoch: 0,
1135
+ first_seqno: retried.first_seqno,
1136
+ prev_shards: retried.prev_shards,
1137
+ attempts: retried.attempts,
1138
+ wait: None,
1139
+ };
1140
+ if shards[0] == self.id {
1141
+ self.start_coordination(creq, ctx);
1142
+ } else {
1143
+ let _ = ctx
1144
+ .submitter(shards[0])
1145
+ .submit(ShardMsg::Coordinate(Box::new(creq)));
1146
+ }
1147
+ None
1148
+ }
1149
+ }
1150
+ }
1151
+
1152
+ /// Sends `Released` to the earlier participants of a retried cross-shard commit that runs
1153
+ /// no further two-phase attempt (D249, #772).
1154
+ fn release_prev_shards(&mut self, m: &Member, ctx: &mut ShardContext<'_, ShardMsg>) {
1155
+ if let Some(r) = m.retry.as_deref() {
1156
+ self.release_shards(m.submitted_at, r.first_seqno, &r.prev_shards.clone(), ctx);
1157
+ }
1158
+ }
1159
+
1160
+ /// `Released` for the commit of priority `(submitted_at, first_seqno)` to `shards`.
1161
+ fn release_shards(
1162
+ &mut self,
1163
+ submitted_at: u64,
1164
+ first_seqno: Seqno,
1165
+ shards: &[ShardId],
1166
+ ctx: &mut ShardContext<'_, ShardMsg>,
1167
+ ) {
1168
+ let priority = (submitted_at, first_seqno);
1169
+ for p in shards {
1170
+ self.send(*p, ShardMsg::Released { priority }, ctx);
1171
+ }
1172
+ }
1173
+
1174
+ /// Cross-shard commits refused by a participant moving a tablet: retried once the tablet
1175
+ /// map is newer than the one they were routed with.
1176
+ pub(super) fn run_retries(&mut self, ctx: &mut ShardContext<'_, ShardMsg>) {
1177
+ if self.retries.is_empty() {
1178
+ return;
1179
+ }
1180
+ if self.closing {
1181
+ for r in self.retries.drain(..) {
1182
+ r.reply.notify(Err(Error::Closed));
1183
+ }
1184
+ return;
1185
+ }
1186
+ // After a shard's death no commit is accepted (D227): one waiting for a participant's
1187
+ // room, or for an overlap there to clear, may wait on the dead one, so it ends now
1188
+ // rather than at the timeout (D245, D249).
1189
+ let waits = |r: &CoordinateReq| {
1190
+ matches!(
1191
+ r.wait,
1192
+ Some(RetryWait::Room { .. } | RetryWait::Overlap { .. })
1193
+ )
1194
+ };
1195
+ if self.shared.shard_died.load(Ordering::Acquire) && self.retries.iter().any(waits) {
1196
+ let (dead, keep): (Vec<CoordinateReq>, Vec<CoordinateReq>) =
1197
+ std::mem::take(&mut self.retries)
1198
+ .into_iter()
1199
+ .partition(waits);
1200
+ self.retries = keep;
1201
+ for r in dead {
1202
+ r.reply.notify(Err(Error::Closed));
1203
+ }
1204
+ }
1205
+ let version = self.shared.view.load().tablets.version();
1206
+ let epoch = self.shared.tablet_epoch.load(Ordering::Acquire);
1207
+ let (ready, wait): (Vec<CoordinateReq>, Vec<CoordinateReq>) =
1208
+ std::mem::take(&mut self.retries)
1209
+ .into_iter()
1210
+ .partition(|r| !waits(r) && (r.map_version < version || r.epoch < epoch));
1211
+ self.retries = wait;
1212
+ if !self.retries.is_empty() {
1213
+ trace!(
1214
+ "shard {} retries waiting: {:?} (map v{version}, epoch {epoch})",
1215
+ self.id.0,
1216
+ self.retries
1217
+ .iter()
1218
+ .map(|r| {
1219
+ (
1220
+ r.wait,
1221
+ (r.submitted_at, r.first_seqno),
1222
+ r.map_version,
1223
+ r.epoch,
1224
+ )
1225
+ })
1226
+ .collect::<Vec<_>>()
1227
+ );
1228
+ }
1229
+ for r in ready {
1230
+ self.retry(r, ctx);
1231
+ }
1232
+ }
1233
+
1234
+ /// Runs a refused cross-shard commit again through the current tablet map.
1235
+ pub(super) fn retry(&mut self, r: CoordinateReq, ctx: &mut ShardContext<'_, ShardMsg>) {
1236
+ let mut builder = BatchBuilder::new();
1237
+ let mut failed = None;
1238
+ for (_, part) in &r.parts {
1239
+ for mu in part.batch().iter() {
1240
+ let pushed = mu.map_err(Error::from).and_then(|mu| {
1241
+ builder
1242
+ .push(
1243
+ mu.table,
1244
+ mu.family,
1245
+ mu.kind,
1246
+ mu.row,
1247
+ mu.qualifier,
1248
+ mu.ts,
1249
+ mu.value,
1250
+ )
1251
+ .map_err(Error::from)
1252
+ });
1253
+ if let Err(e) = pushed {
1254
+ failed = Some(e);
1255
+ }
1256
+ }
1257
+ }
1258
+ if let Some(e) = failed {
1259
+ self.release_shards(r.submitted_at, r.first_seqno, &r.prev_shards, ctx);
1260
+ r.reply.notify(Err(e));
1261
+ return;
1262
+ }
1263
+ let m = Member::single(CommitReq {
1264
+ bytes: builder,
1265
+ durability: r.durability,
1266
+ reply: Reply::Commit(r.reply),
1267
+ submitted_at: r.submitted_at,
1268
+ validate: r.validate,
1269
+ predicate: None,
1270
+ retry: Some(Box::new(Retried {
1271
+ first_seqno: r.first_seqno,
1272
+ prev_shards: r.prev_shards,
1273
+ attempts: r.attempts,
1274
+ })),
1275
+ map_version: r.map_version,
1276
+ });
1277
+ if let Some(m) = self.forward(m, ctx) {
1278
+ self.pending.push(m);
1279
+ let _ = ctx.submitter(self.id).submit(ShardMsg::Kick);
1280
+ }
1281
+ }
1282
+
1283
+ /// Fails with `Busy` every parked commit and every waiting retry that was submitted
1284
+ /// `write_stall_timeout_nanos` ago (#102): a change can wait on a long compaction or a
1285
+ /// slow flush, and a commit that keeps meeting changes must not wait for ever.
1286
+ pub(super) fn expire_tablet_waits(&mut self, ctx: &mut ShardContext<'_, ShardMsg>) {
1287
+ if self.parked.is_empty() && self.retries.is_empty() {
1288
+ if let Some((_, t)) = self.tablet_timer.take() {
1289
+ t.cancel();
1290
+ }
1291
+ return;
1292
+ }
1293
+ let now = ctx.now_nanos();
1294
+ let timeout = self.shared.write_stall_timeout_nanos;
1295
+ let late = |submitted_at: u64| now.saturating_sub(submitted_at) >= timeout;
1296
+ if self.parked.iter().any(|m| late(m.submitted_at)) {
1297
+ let (expired, kept): (Vec<Member>, Vec<Member>) = std::mem::take(&mut self.parked)
1298
+ .into_iter()
1299
+ .partition(|m| late(m.submitted_at));
1300
+ self.parked = kept;
1301
+ self.parked_rows = self.parked.iter().flat_map(member_rows).collect();
1302
+ for m in expired {
1303
+ trace!("shard {} parked commit times out", self.id.0);
1304
+ m.reply.resolve(Err(Error::Busy));
1305
+ }
1306
+ }
1307
+ if self.retries.iter().any(|r| late(r.submitted_at)) {
1308
+ let (expired, kept): (Vec<CoordinateReq>, Vec<CoordinateReq>) =
1309
+ std::mem::take(&mut self.retries)
1310
+ .into_iter()
1311
+ .partition(|r| late(r.submitted_at));
1312
+ self.retries = kept;
1313
+ for r in expired {
1314
+ trace!("shard {} retried commit times out", self.id.0);
1315
+ // It runs no further attempt: commits waiting behind it go (#772).
1316
+ self.release_shards(r.submitted_at, r.first_seqno, &r.prev_shards, ctx);
1317
+ r.reply.notify(Err(Error::Busy));
1318
+ }
1319
+ }
1320
+ self.arm_tablet_timer(ctx);
1321
+ self.try_finish_close(ctx);
1322
+ }
1323
+
1324
+ /// Arms (or re-arms) the timer that ends the oldest parked commit or retry.
1325
+ pub(super) fn arm_tablet_timer(&mut self, ctx: &mut ShardContext<'_, ShardMsg>) {
1326
+ let oldest = self
1327
+ .parked
1328
+ .iter()
1329
+ .map(|m| m.submitted_at)
1330
+ .chain(self.retries.iter().map(|r| r.submitted_at))
1331
+ .min();
1332
+ let Some(oldest) = oldest else {
1333
+ if let Some((_, t)) = self.tablet_timer.take() {
1334
+ t.cancel();
1335
+ }
1336
+ return;
1337
+ };
1338
+ let deadline = oldest.saturating_add(self.shared.write_stall_timeout_nanos);
1339
+ // A timer that gave up on a clock still frozen is not armed again: the change's
1340
+ // progress releases the commits instead.
1341
+ if let Some((at, t)) = &self.tablet_timer
1342
+ && ((*at <= deadline && !t.finished()) || t.frozen(ctx.now_nanos()))
1343
+ {
1344
+ return;
1345
+ }
1346
+ if let Some((_, t)) = self.tablet_timer.take() {
1347
+ t.cancel();
1348
+ }
1349
+ trace!("shard {} tablet timer armed for {deadline}", self.id.0);
1350
+ let state = TimerState::new();
1351
+ ctx.spawn(Box::new(ClockTimer::new(
1352
+ &self.shared.vfs,
1353
+ deadline,
1354
+ Arc::clone(&state),
1355
+ ctx.submitter(self.id).clone(),
1356
+ ShardMsg::Kick,
1357
+ )));
1358
+ self.tablet_timer = Some((deadline, state));
1359
+ }
1360
+
1361
+ // ---- the change ----
1362
+
1363
+ /// Queues a tablet change and starts it if none is running.
1364
+ pub(super) fn request_tablet_op(
1365
+ &mut self,
1366
+ kind: TabletOpKind,
1367
+ reply: Option<Notifier<Result<()>>>,
1368
+ ctx: &mut ShardContext<'_, ShardMsg>,
1369
+ ) {
1370
+ if !self.tablets_on() {
1371
+ if let Some(r) = reply {
1372
+ r.notify(Err(Error::Unsupported("tablet changes are off")));
1373
+ }
1374
+ return;
1375
+ }
1376
+ if self.closing {
1377
+ if let Some(r) = reply {
1378
+ r.notify(Err(Error::Closed));
1379
+ }
1380
+ return;
1381
+ }
1382
+ self.op_queue.push_back((kind, reply));
1383
+ self.start_next_op(ctx);
1384
+ }
1385
+
1386
+ fn start_next_op(&mut self, ctx: &mut ShardContext<'_, ShardMsg>) {
1387
+ while self.op.is_none() {
1388
+ let Some((kind, reply)) = self.op_queue.pop_front() else {
1389
+ return;
1390
+ };
1391
+ self.refresh_tablets();
1392
+ match self.validate_op(&kind) {
1393
+ Err(e) => {
1394
+ balance!("shard {} tablet change {kind:?} refused: {e}", self.id.0);
1395
+ if let Some(r) = reply {
1396
+ r.notify(Err(e));
1397
+ }
1398
+ }
1399
+ Ok((entries, reserved)) => {
1400
+ balance!("shard {} tablet change {kind:?} starts", self.id.0);
1401
+ self.moving = kind.tablets().into_iter().collect();
1402
+ self.op = Some(ActiveOp {
1403
+ kind,
1404
+ reply,
1405
+ entries,
1406
+ committing: false,
1407
+ reserved,
1408
+ });
1409
+ if self.freeze_moving().is_err() {
1410
+ self.poison(crate::health::FailureCause::Internal);
1411
+ }
1412
+ self.spawn_flush(ctx);
1413
+ self.progress_op(ctx);
1414
+ }
1415
+ }
1416
+ }
1417
+ }
1418
+
1419
+ /// Checks a change against the current tablet map; returns the tablets it touches and the
1420
+ /// slots it reserved on the shards receiving tablets.
1421
+ fn validate_op(&self, kind: &TabletOpKind) -> Result<(Vec<TabletEntry>, Reserved)> {
1422
+ if self.poisoned || self.shared.pager_poisoned.load(Ordering::Acquire) {
1423
+ return Err(poisoned_error());
1424
+ }
1425
+ let view = self.shared.view.load();
1426
+ let shards = self.shared.shards;
1427
+ let entry = |id: TabletId| -> Result<TabletEntry> {
1428
+ view.tablets
1429
+ .entry(id)
1430
+ .filter(|t| t.shard == self.id)
1431
+ .cloned()
1432
+ .ok_or_else(|| {
1433
+ Error::InvalidArgument(format!("tablet {} is not on shard {}", id.0, self.id.0))
1434
+ })
1435
+ };
1436
+ match kind {
1437
+ TabletOpKind::Split {
1438
+ tablet,
1439
+ keys,
1440
+ owners,
1441
+ } => {
1442
+ let t = entry(*tablet)?;
1443
+ if keys.is_empty()
1444
+ || owners.len() != keys.len() + 1
1445
+ || owners.iter().any(|s| usize::from(s.0) >= shards)
1446
+ {
1447
+ return Err(Error::InvalidArgument("malformed split".to_owned()));
1448
+ }
1449
+ // Above the tablet's start, then above the previous key.
1450
+ let mut prev: &[u8] = &t.start;
1451
+ for k in keys {
1452
+ if k.as_slice() <= prev {
1453
+ return Err(Error::InvalidArgument(
1454
+ "split keys must increase strictly inside the tablet".to_owned(),
1455
+ ));
1456
+ }
1457
+ prev = k;
1458
+ }
1459
+ if t.end.as_ref().is_some_and(|e| prev >= e.as_slice()) {
1460
+ return Err(Error::InvalidArgument(
1461
+ "split keys must increase strictly inside the tablet".to_owned(),
1462
+ ));
1463
+ }
1464
+ // D28: refuse a split whose view would not fit the shared-memory buffer.
1465
+ let families = view.catalog.family_ids_of(t.table).len();
1466
+ let key_bytes: usize = keys.iter().map(Vec::len).sum();
1467
+ let grow = keys.len() * (32 + 24 * families)
1468
+ + 2 * key_bytes
1469
+ + t.start.len()
1470
+ + t.end.as_ref().map_or(0, Vec::len)
1471
+ + 16;
1472
+ if view.to_record().encoded_len() + grow > self.shared.view_capacity {
1473
+ self.shared.metrics[usize::from(self.id.0)]
1474
+ .refused_view
1475
+ .fetch_add(1, Ordering::Relaxed);
1476
+ return Err(Error::Unsupported(
1477
+ "the tablet map would not fit the shared-memory view buffer (D28)",
1478
+ ));
1479
+ }
1480
+ // Each shard keeps its slots within its arena's chunks.
1481
+ let mut extra: Vec<(ShardId, usize)> = Vec::new();
1482
+ for o in owners {
1483
+ if extra.iter().any(|(s, _)| s == o) {
1484
+ continue;
1485
+ }
1486
+ let children = owners.iter().filter(|x| *x == o).count();
1487
+ // The parent's slots leave this shard as its children arrive.
1488
+ let freed = if *o == self.id { families } else { 0 };
1489
+ extra.push((*o, (families * children).saturating_sub(freed)));
1490
+ }
1491
+ let reserved = self.reserve_slots(&view, &extra)?;
1492
+ Ok((vec![t], reserved))
1493
+ }
1494
+ TabletOpKind::Merge { left, right } => {
1495
+ let l = entry(*left)?;
1496
+ let r = entry(*right)?;
1497
+ if l.table != r.table || l.end.as_deref() != Some(r.start.as_slice()) {
1498
+ return Err(Error::InvalidArgument(
1499
+ "only adjacent tablets of one table merge".to_owned(),
1500
+ ));
1501
+ }
1502
+ Ok((vec![l, r], Vec::new()))
1503
+ }
1504
+ TabletOpKind::Move { tablet, to } => {
1505
+ let t = entry(*tablet)?;
1506
+ if *to == self.id || usize::from(to.0) >= shards {
1507
+ return Err(Error::InvalidArgument(format!(
1508
+ "cannot move tablet {} to shard {}",
1509
+ tablet.0, to.0
1510
+ )));
1511
+ }
1512
+ let families = view.catalog.family_ids_of(t.table).len();
1513
+ let reserved = self.reserve_slots(&view, &[(*to, families)])?;
1514
+ Ok((vec![t], reserved))
1515
+ }
1516
+ }
1517
+ }
1518
+
1519
+ /// The most `(tablet, family)` slots a shard should hold: a quarter of its arena's
1520
+ /// chunks. Every slot written to takes a memtable chunk (and usually two before it
1521
+ /// freezes), and frozen memtables keep theirs until flushed and released.
1522
+ fn max_slots(&self) -> usize {
1523
+ crate::engine::max_slots(self.arena.region().len(), self.chunk_size)
1524
+ }
1525
+
1526
+ /// Slots `shard` holds in `view`.
1527
+ fn slots_in(view: &View, shard: ShardId) -> usize {
1528
+ view.tablets
1529
+ .iter()
1530
+ .filter(|t| t.shard == shard)
1531
+ .map(|t| view.catalog.family_ids_of(t.table).len())
1532
+ .sum()
1533
+ }
1534
+
1535
+ /// Whether `shard` can take `extra` more slots under [`ShardState::max_slots`], counting
1536
+ /// the slots other changes reserved there.
1537
+ fn slots_fit(&self, view: &View, shard: ShardId, extra: usize) -> bool {
1538
+ let reserved = self.shared.loads[usize::from(shard.0)].reserved();
1539
+ Self::slots_in(view, shard) + reserved + extra <= self.max_slots()
1540
+ }
1541
+
1542
+ /// Reserves `extra` slots on each shard (all or none), so a change running on another
1543
+ /// shard sees them before this one commits (#103).
1544
+ fn reserve_slots(&self, view: &View, extra: &[(ShardId, usize)]) -> Result<Reserved> {
1545
+ let mut out: Reserved = Vec::new();
1546
+ for &(shard, n) in extra {
1547
+ if n == 0 {
1548
+ continue;
1549
+ }
1550
+ let before = self.shared.loads[usize::from(shard.0)].reserve(n);
1551
+ out.push((shard, n));
1552
+ if Self::slots_in(view, shard) + before + n > self.max_slots() {
1553
+ self.release_slots(&out);
1554
+ self.shared.metrics[usize::from(self.id.0)]
1555
+ .refused_slots
1556
+ .fetch_add(1, Ordering::Relaxed);
1557
+ return Err(Error::Unsupported(
1558
+ "a shard would hold more tablets than its memtable arena serves",
1559
+ ));
1560
+ }
1561
+ }
1562
+ Ok(out)
1563
+ }
1564
+
1565
+ fn release_slots(&self, reserved: &[(ShardId, usize)]) {
1566
+ for &(shard, n) in reserved {
1567
+ self.shared.loads[usize::from(shard.0)].release(n);
1568
+ }
1569
+ }
1570
+
1571
+ /// Moves the running change on: commits it once its tablets are drained.
1572
+ pub(super) fn progress_op(&mut self, ctx: &mut ShardContext<'_, ShardMsg>) {
1573
+ let Some(op) = &self.op else {
1574
+ return;
1575
+ };
1576
+ if op.committing {
1577
+ return;
1578
+ }
1579
+ if self.poisoned || self.shared.pager_poisoned.load(Ordering::Acquire) {
1580
+ self.abort_op(poisoned_error(), ctx);
1581
+ return;
1582
+ }
1583
+ let mut busy = false;
1584
+ let mut refreeze = false;
1585
+ for (key, slot) in &self.memtables {
1586
+ if !self.moving.contains(&key.0) {
1587
+ continue;
1588
+ }
1589
+ if !slot.active.table.is_empty() {
1590
+ busy = true;
1591
+ refreeze = true;
1592
+ }
1593
+ if !slot.frozen.is_empty() {
1594
+ busy = true;
1595
+ }
1596
+ }
1597
+ if self
1598
+ .compaction
1599
+ .is_some_and(|(t, _)| self.moving.contains(&t))
1600
+ {
1601
+ busy = true;
1602
+ }
1603
+ if !busy && self.shares_touch_moving() {
1604
+ busy = true;
1605
+ }
1606
+ trace!(
1607
+ "shard {} tablet change waits: busy={busy} refreeze={refreeze} deferred={} flush_running={}",
1608
+ self.id.0, self.freeze_deferred, self.flush_running
1609
+ );
1610
+ if refreeze {
1611
+ if self.freeze_moving().is_err() {
1612
+ self.poison(crate::health::FailureCause::Internal);
1613
+ }
1614
+ self.spawn_flush(ctx);
1615
+ }
1616
+ if busy {
1617
+ return;
1618
+ }
1619
+ self.commit_op(ctx);
1620
+ }
1621
+
1622
+ /// Freezes the memtables of the tablets being changed (`freeze` freezes them whatever
1623
+ /// they hold).
1624
+ fn freeze_moving(&mut self) -> Result<()> {
1625
+ #[cfg(feature = "test-hooks")]
1626
+ if self
1627
+ .shared
1628
+ .hooks
1629
+ .faults
1630
+ .take(crate::engine::hooks::Fault::NextTabletFreeze)
1631
+ {
1632
+ return Err(Error::Busy);
1633
+ }
1634
+ self.freeze(false)
1635
+ }
1636
+
1637
+ /// Whether a prepared, undecided share writes or reads a tablet being changed.
1638
+ fn shares_touch_moving(&self) -> bool {
1639
+ self.prepared.values().any(|share| {
1640
+ share.bytes.batch().iter().flatten().any(|mu| {
1641
+ self.tablets
1642
+ .route(mu.table, mu.row)
1643
+ .is_some_and(|(t, _)| self.moving.contains(&t))
1644
+ })
1645
+ })
1646
+ }
1647
+
1648
+ fn commit_op(&mut self, ctx: &mut ShardContext<'_, ShardMsg>) {
1649
+ let Some(op) = self.op.as_mut() else {
1650
+ return;
1651
+ };
1652
+ op.committing = true;
1653
+ let kind = op.kind.clone();
1654
+ let entries = op.entries.clone();
1655
+ // A tablet changes shard only once its memtables are flushed (`progress_op`): the
1656
+ // flushed-through seqno (`Shared::flushed_through`) relies on it, since no write at or
1657
+ // below it may leave this shard's memtables for another's (#724).
1658
+ debug_assert!(
1659
+ self.memtables
1660
+ .iter()
1661
+ .filter(|(k, _)| self.moving.contains(&k.0))
1662
+ .all(|(_, s)| s.active.table.is_empty() && s.frozen.is_empty()),
1663
+ "shard {}: a tablet change commits with unflushed memtables on its tablets",
1664
+ self.id.0
1665
+ );
1666
+ // D11, D271: default timestamps never go backwards on a tablet. The new owner's next
1667
+ // stamp is above every one the allocator handed out, so above the tablet's own.
1668
+ self.shared.clock.raise();
1669
+ balance!("shard {} tablet change {kind:?} commits", self.id.0);
1670
+ let me = self.id;
1671
+ let change: TabletChange =
1672
+ Box::new(move |catalog| tablet_change(catalog, &kind, &entries, me));
1673
+ let submitter = ctx.submitter(self.id).clone();
1674
+ let req = ManifestReq {
1675
+ kind: ReqKind::Tablets(change),
1676
+ readers: Vec::new(),
1677
+ flushed_roots: Vec::new(),
1678
+ compactions: Vec::new(),
1679
+ rewrite_snapshot: manifest::Rewrite::AsNeeded,
1680
+ dropped_ok: Vec::new(),
1681
+ on_refusal: Vec::new(),
1682
+ reply: Box::new(move |result| {
1683
+ let _ = submitter.submit(ShardMsg::TabletOpDone { result });
1684
+ }),
1685
+ };
1686
+ manifest::submit(&self.shared, self.id, req);
1687
+ }
1688
+
1689
+ /// The change's manifest commit finished.
1690
+ pub(super) fn on_tablet_op_done(
1691
+ &mut self,
1692
+ result: Result<ManifestVersion>,
1693
+ ctx: &mut ShardContext<'_, ShardMsg>,
1694
+ ) {
1695
+ let Some(op) = self.op.take() else {
1696
+ return;
1697
+ };
1698
+ self.finished_op();
1699
+ let moving: Vec<TabletId> = std::mem::take(&mut self.moving).into_iter().collect();
1700
+ // The view now holds the slots (or the change failed): the reservation goes.
1701
+ self.refresh_tablets();
1702
+ self.release_slots(&op.reserved);
1703
+ match result {
1704
+ Ok(_) => {
1705
+ balance!("shard {} tablet change {:?} done", self.id.0, op.kind);
1706
+ self.refresh_tablets();
1707
+ if self.drop_tablets(&moving).is_err() {
1708
+ self.poison(crate::health::FailureCause::Internal);
1709
+ }
1710
+ for t in &moving {
1711
+ self.loads.remove(t);
1712
+ }
1713
+ if !op.kind.targets(self.id).is_empty() {
1714
+ self.lost_version = self.tablets.version();
1715
+ }
1716
+ let metrics = &self.shared.metrics[usize::from(self.id.0)];
1717
+ match op.kind {
1718
+ TabletOpKind::Split { .. } => &metrics.splits,
1719
+ TabletOpKind::Merge { .. } => &metrics.merges,
1720
+ TabletOpKind::Move { .. } => &metrics.moves,
1721
+ }
1722
+ .fetch_add(1, Ordering::Relaxed);
1723
+ self.release_parked(ctx);
1724
+ if let Some(r) = op.reply {
1725
+ r.notify(Ok(()));
1726
+ }
1727
+ }
1728
+ Err(e) => {
1729
+ balance!(
1730
+ "shard {} tablet change {:?} failed: {e}",
1731
+ self.id.0,
1732
+ op.kind
1733
+ );
1734
+ self.release_parked(ctx);
1735
+ if let Some(r) = op.reply {
1736
+ r.notify(Err(e));
1737
+ }
1738
+ }
1739
+ }
1740
+ self.start_next_op(ctx);
1741
+ self.try_finish_close(ctx);
1742
+ }
1743
+
1744
+ /// Gives up the running change before its commit (a failed flush, a poisoned pager).
1745
+ pub(super) fn abort_op(&mut self, e: Error, ctx: &mut ShardContext<'_, ShardMsg>) {
1746
+ if self.op.as_ref().is_none_or(|op| op.committing) {
1747
+ return;
1748
+ }
1749
+ let op = self.op.take().expect("checked");
1750
+ self.finished_op();
1751
+ self.release_slots(&op.reserved);
1752
+ self.moving.clear();
1753
+ self.release_parked(ctx);
1754
+ if let Some(r) = op.reply {
1755
+ r.notify(Err(e));
1756
+ }
1757
+ self.start_next_op(ctx);
1758
+ }
1759
+
1760
+ /// A change finished or was given up: commits refused meanwhile may run again.
1761
+ fn finished_op(&self) {
1762
+ self.shared.tablet_epoch.fetch_add(1, Ordering::AcqRel);
1763
+ self.shared.broadcast(|| ShardMsg::Maintain);
1764
+ }
1765
+
1766
+ /// Routes every parked commit again, ahead of whatever is pending.
1767
+ fn release_parked(&mut self, ctx: &mut ShardContext<'_, ShardMsg>) {
1768
+ self.parked_rows.clear();
1769
+ let parked = std::mem::take(&mut self.parked);
1770
+ let mut mine = Vec::with_capacity(parked.len());
1771
+ for m in parked {
1772
+ if let Some(m) = self.forward(m, ctx) {
1773
+ mine.push(m);
1774
+ }
1775
+ }
1776
+ mine.append(&mut self.pending);
1777
+ self.pending = mine;
1778
+ if !self.pending.is_empty() {
1779
+ let _ = ctx.submitter(self.id).submit(ShardMsg::Kick);
1780
+ }
1781
+ }
1782
+
1783
+ // ---- load tracking and the balancer ----
1784
+
1785
+ /// Counts a row written to `tablet` and samples it (reservoir sampling).
1786
+ pub(super) fn note_write(&mut self, tablet: TabletId, row: &[u8]) {
1787
+ self.window_writes += 1;
1788
+ self.rng ^= self.rng << 13;
1789
+ self.rng ^= self.rng >> 7;
1790
+ self.rng ^= self.rng << 17;
1791
+ let r = self.rng;
1792
+ let l = self.loads.entry(tablet).or_default();
1793
+ l.writes += 1;
1794
+ l.seen += 1;
1795
+ if l.sampled < SAMPLES {
1796
+ match l.samples.get_mut(l.sampled) {
1797
+ Some(s) => {
1798
+ s.clear();
1799
+ s.extend_from_slice(row);
1800
+ }
1801
+ None => l.samples.push(row.to_vec()),
1802
+ }
1803
+ l.sampled += 1;
1804
+ } else {
1805
+ let j = (r % l.seen) as usize;
1806
+ if j < SAMPLES {
1807
+ let s = &mut l.samples[j];
1808
+ s.clear();
1809
+ s.extend_from_slice(row);
1810
+ }
1811
+ }
1812
+ }
1813
+
1814
+ /// Memtable bytes of this shard, and per tablet (empty active memtables count 0).
1815
+ fn mem_bytes(&self) -> (u64, HashMap<TabletId, u64>) {
1816
+ let mut total = 0;
1817
+ let mut per = HashMap::new();
1818
+ for (key, slot) in &self.memtables {
1819
+ // An empty active memtable holds no writes, whatever it has allocated: its tablet
1820
+ // can still be cold (a slot now keeps its memtable after a flush).
1821
+ let active = if slot.active.table.is_empty() {
1822
+ 0
1823
+ } else {
1824
+ slot.active.table.allocated_bytes() as u64
1825
+ };
1826
+ let b = active
1827
+ + slot
1828
+ .frozen
1829
+ .iter()
1830
+ .map(|m| m.table.allocated_bytes() as u64)
1831
+ .sum::<u64>();
1832
+ total += b;
1833
+ *per.entry(key.0).or_insert(0) += b;
1834
+ }
1835
+ (total, per)
1836
+ }
1837
+
1838
+ /// Ends a balancer interval when it is due (or at once when `force`): publishes this
1839
+ /// shard's load and starts a split, move or merge when one is warranted.
1840
+ pub(super) fn maybe_balance(
1841
+ &mut self,
1842
+ force: bool,
1843
+ reply: Option<Notifier<Result<()>>>,
1844
+ ctx: &mut ShardContext<'_, ShardMsg>,
1845
+ ) {
1846
+ let cfg = self.shared.balance;
1847
+ // A read-only open (ICR 0059) changes no tablet.
1848
+ if !cfg.enabled || self.shared.no_writes {
1849
+ if let Some(r) = reply {
1850
+ r.notify(Err(Error::Unsupported("tablet changes are off")));
1851
+ }
1852
+ return;
1853
+ }
1854
+ if !force && cfg.interval_nanos == 0 {
1855
+ return;
1856
+ }
1857
+ let now = ctx.now_nanos();
1858
+ let base = cfg.interval_nanos.max(1);
1859
+ let epoch = self.shared.tablet_epoch.load(Ordering::Acquire);
1860
+ // A write or a tablet change (here or on any shard) ends an idle backoff: the next
1861
+ // pass is due one base interval from now.
1862
+ let active = self.window_writes > 0
1863
+ || self.op.is_some()
1864
+ || !self.op_queue.is_empty()
1865
+ || epoch != self.balance_epoch;
1866
+ if active && self.balance_interval > base {
1867
+ self.balance_interval = base;
1868
+ let due = now.saturating_add(base);
1869
+ if due < self.next_balance {
1870
+ self.next_balance = due;
1871
+ self.cancel_balance_timer();
1872
+ self.arm_balance_timer(ctx);
1873
+ }
1874
+ }
1875
+ if !force && now < self.next_balance {
1876
+ return;
1877
+ }
1878
+ self.next_balance = now.saturating_add(base);
1879
+ let wrote = self.window_writes > 0;
1880
+ self.balance_pass += 1;
1881
+ // Moving averages of the write load: a shard's (published for the other shards) and
1882
+ // each tablet's (#103). One interval's swing, or a flush, never decides a move.
1883
+ self.load_ewma =
1884
+ LOAD_ALPHA * self.window_writes as f64 + (1.0 - LOAD_ALPHA) * self.load_ewma;
1885
+ self.load_slow =
1886
+ SLOW_ALPHA * self.window_writes as f64 + (1.0 - SLOW_ALPHA) * self.load_slow;
1887
+ let (pass, clock) = (self.balance_pass, now);
1888
+ for l in self.loads.values_mut() {
1889
+ if l.writes > 0 {
1890
+ l.last_write = (pass, clock);
1891
+ }
1892
+ l.ewma = LOAD_ALPHA * l.writes as f64 + (1.0 - LOAD_ALPHA) * l.ewma;
1893
+ l.slow = SLOW_ALPHA * l.writes as f64 + (1.0 - SLOW_ALPHA) * l.slow;
1894
+ }
1895
+ self.note_arrivals(now);
1896
+ let (_, mem_per) = self.mem_bytes();
1897
+ self.measure_busy(now);
1898
+ self.shared.loads[usize::from(self.id.0)]
1899
+ .set_turn_busy((self.turn_ewma * 1e6).round() as u64);
1900
+ self.shared.loads[usize::from(self.id.0)]
1901
+ .set_stall_busy((self.stall_term * 1e6).round() as u64);
1902
+ self.shared.loads[usize::from(self.id.0)]
1903
+ .set_inflight((self.inflight_ewma * 1e6).round() as u64);
1904
+ self.shared.loads[usize::from(self.id.0)].publish(
1905
+ self.load_ewma.round() as u64,
1906
+ self.load_slow.round() as u64,
1907
+ (self.busy_ewma * 1e6).round() as u64,
1908
+ now.max(1),
1909
+ self.balance_pass,
1910
+ );
1911
+ let store_writes = self.track_pack(now);
1912
+ #[cfg(feature = "test-hooks")]
1913
+ self.shared.metrics[usize::from(self.id.0)]
1914
+ .hooks
1915
+ .pack_k
1916
+ .store(self.active_shards() as u64 + 1, Ordering::Relaxed);
1917
+ self.track_skew(now);
1918
+ let idle = self.may_change();
1919
+ // A change waits for a running compaction on its tablets (#102: a running change
1920
+ // parks their writes, and a compaction can run for minutes). It is decided again as
1921
+ // soon as this one ends, before the next one is picked, so back-to-back compactions
1922
+ // never starve it.
1923
+ self.change_waits = false;
1924
+ let (decision, cleanups) = if idle {
1925
+ let (kind, cleanups) = self.decide(now, &mem_per);
1926
+ let kind = kind.filter(|kind| {
1927
+ let waits = self.waits_on_compaction(kind);
1928
+ self.change_waits |= waits;
1929
+ !waits
1930
+ });
1931
+ (kind, cleanups)
1932
+ } else {
1933
+ (None, Vec::new())
1934
+ };
1935
+ self.window_writes = 0;
1936
+ for l in self.loads.values_mut() {
1937
+ l.prev_writes = l.writes;
1938
+ l.writes = 0;
1939
+ l.seen = 0;
1940
+ l.sampled = 0;
1941
+ }
1942
+ let decision_none = decision.is_none();
1943
+ match decision {
1944
+ Some(kind) => {
1945
+ balance!("shard {} balancer: {kind:?}", self.id.0);
1946
+ self.start_change(kind, reply, ctx);
1947
+ }
1948
+ None => {
1949
+ if let Some(r) = reply {
1950
+ r.notify(Ok(()));
1951
+ }
1952
+ }
1953
+ }
1954
+ // Idle backoff: a pass that found nothing to do, after no writes and no tablet change,
1955
+ // doubles the interval (up to `BALANCE_IDLE_CAP_NANOS`, never below the base), so an
1956
+ // idle shard wakes rarely; anything else returns to the base interval.
1957
+ // Shard 0 decides the active shard count for every shard: it keeps the base interval
1958
+ // while the store writes, even when it writes nothing itself (D217).
1959
+ let quiet = idle
1960
+ && !wrote
1961
+ && !store_writes
1962
+ && decision_none
1963
+ && cleanups.is_empty()
1964
+ && epoch == self.balance_epoch
1965
+ && self.op.is_none();
1966
+ let current = self.balance_interval.max(base);
1967
+ self.balance_interval = if quiet {
1968
+ current
1969
+ .saturating_mul(2)
1970
+ .min(BALANCE_IDLE_CAP_NANOS.max(base))
1971
+ } else {
1972
+ base
1973
+ };
1974
+ self.balance_epoch = self.shared.tablet_epoch.load(Ordering::Acquire);
1975
+ self.next_balance = now.saturating_add(self.balance_interval);
1976
+ if !cleanups.is_empty() {
1977
+ for c in cleanups {
1978
+ if !self.cleanups.contains(&c) {
1979
+ self.cleanups.push(c);
1980
+ }
1981
+ }
1982
+ self.maintain(ctx);
1983
+ }
1984
+ self.arm_balance_timer(ctx);
1985
+ }
1986
+
1987
+ /// Whether the balancer may start a tablet change now.
1988
+ fn may_change(&self) -> bool {
1989
+ self.op.is_none()
1990
+ && self.op_queue.is_empty()
1991
+ && !self.closing
1992
+ && !self.replaying
1993
+ && !self.poisoned
1994
+ && !self.shared.closing.load(Ordering::Acquire)
1995
+ && !self.shared.pager_poisoned.load(Ordering::Acquire)
1996
+ && self.shared.full_compactions.load(Ordering::Acquire) == 0
1997
+ }
1998
+
1999
+ /// The compaction a change waited on ended: decides again (on this interval's loads)
2000
+ /// and starts the change, before the next compaction is picked.
2001
+ pub(super) fn start_waiting_change(&mut self, ctx: &mut ShardContext<'_, ShardMsg>) {
2002
+ // With a compaction running, `claim_targets` would pass a change on its tablets
2003
+ // without claiming, and the change would start during the compaction (#102, D270).
2004
+ debug_assert!(
2005
+ self.compaction.is_none(),
2006
+ "a waiting change decided again while a compaction runs"
2007
+ );
2008
+ self.change_waits = false;
2009
+ if !self.may_change() {
2010
+ return;
2011
+ }
2012
+ let (_, mem_per) = self.mem_bytes();
2013
+ let (kind, _) = self.decide(ctx.now_nanos(), &mem_per);
2014
+ if let Some(kind) = kind {
2015
+ balance!("shard {} balancer, after a compaction: {kind:?}", self.id.0);
2016
+ self.start_change(kind, None, ctx);
2017
+ }
2018
+ }
2019
+
2020
+ /// Starts a change the balancer chose.
2021
+ fn start_change(
2022
+ &mut self,
2023
+ kind: TabletOpKind,
2024
+ reply: Option<Notifier<Result<()>>>,
2025
+ ctx: &mut ShardContext<'_, ShardMsg>,
2026
+ ) {
2027
+ // Anything but a size split (a move, or a split over shards) starts the shard's
2028
+ // dwell: the loads settle before write skew acts again.
2029
+ let size_split = matches!(&kind, TabletOpKind::Split { owners, .. }
2030
+ if owners.iter().all(|o| *o == self.id));
2031
+ if !size_split {
2032
+ self.skew_pass = Some(self.balance_pass);
2033
+ }
2034
+ if self.chose_slow.get() {
2035
+ self.slow_pass = Some(self.balance_pass);
2036
+ }
2037
+ self.request_tablet_op(kind, reply, ctx);
2038
+ }
2039
+
2040
+ /// Records the balancer pass at which each tablet this shard owns first appeared here
2041
+ /// (the tablets it held at its first pass count as settled).
2042
+ fn note_arrivals(&mut self, now: u64) {
2043
+ let view = self.shared.view.load();
2044
+ let first = self.balance_pass <= 1;
2045
+ let pass = if first { 0 } else { self.balance_pass };
2046
+ let owned: HashSet<TabletId> = view
2047
+ .tablets
2048
+ .iter()
2049
+ .filter(|t| t.shard == self.id)
2050
+ .map(|t| t.id)
2051
+ .collect();
2052
+ self.arrived.retain(|t, _| owned.contains(t));
2053
+ self.arrived_at.retain(|t, _| owned.contains(t));
2054
+ for t in owned {
2055
+ self.arrived_at
2056
+ .entry(t)
2057
+ .or_insert(if first { 0 } else { now });
2058
+ self.arrived.entry(t).or_insert(pass);
2059
+ }
2060
+ }
2061
+
2062
+ /// Updates this shard's moving average of how busy it was since the last pass (D217,
2063
+ /// D248, D255): the largest of its thread's busy time, its group syncs' utilization and
2064
+ /// whether its writers are stalling, each over the time that passed. Utilization is the
2065
+ /// syncs' in-flight time (summed over the syncs in flight) over that time, capped at 1,
2066
+ /// so a shard whose durable commits keep a sync in flight reads busy although its thread
2067
+ /// mostly waits. Not divided by `group_sync_depth`: a shard's concurrent syncs fold into
2068
+ /// one journal commit (D221), so they are one server, not two (D248's A/B). The stall
2069
+ /// term is 1 when the writers stalled (a wait for room or L0 pacing began or was open) on
2070
+ /// at least `PACK_STALL_PASSES` of the last `PACK_STALL_WINDOW` passes, else 0 (D255):
2071
+ /// with flush and compaction on dedicated threads (D252) a shard carrying a full write
2072
+ /// load runs cheap turns and reads idle, so packing kept whole tables on one shard; a
2073
+ /// shard whose writers wait is hot in the sense that counts, more shards would take the
2074
+ /// load. The pool's slices for this shard's flushes and compactions add to the turn
2075
+ /// term (D256; before D252 they ran inside the turns and counted there), and the sum
2076
+ /// may pass 1 (two pool threads serving one shard). `max` over that sum, the syncs and
2077
+ /// the stalls, since a turn often runs while a sync is in flight or writers wait. All
2078
+ /// of them count only while the runtime counts turn time (engine-owned shards): an
2079
+ /// application-owned store stays unpacked, as before. The thread's spin before parking
2080
+ /// (D198) is measured and traced but is no term since D257: a thin shard spins after
2081
+ /// every message, so the term grew with the spread it justified (one client over 13
2082
+ /// shards read 6.5 shards' worth). Its replacement is measured here too, apart from the
2083
+ /// busy fraction: the mean number of client commit rounds in flight at this shard, the
2084
+ /// rise of `commit_inflight_nanos` over the interval (Little's law; a closed-loop
2085
+ /// client's worth is at most 1 per shard its commit occupies, whatever the shard
2086
+ /// count), which shard 0 sums over the shards into the store's concurrency (D257,
2087
+ /// D262, `decide_pack`).
2088
+ fn measure_busy(&mut self, now: u64) {
2089
+ let me = usize::from(self.id.0);
2090
+ let (busy, spin, pool) = self
2091
+ .shared
2092
+ .submitters
2093
+ .get()
2094
+ .and_then(|s| s.get(me))
2095
+ .map_or((0, 0, 0), |s| {
2096
+ (s.busy_nanos(), s.spin_nanos(), s.pool_busy_nanos())
2097
+ });
2098
+ let sync = self.sync_busy_nanos(now);
2099
+ let inflight = self.shared.metrics[me]
2100
+ .commit_inflight_nanos
2101
+ .load(Ordering::Relaxed);
2102
+ let mark = self.busy_mark.filter(|m| now > m.at);
2103
+ let elapsed = mark.map(|m| (now - m.at) as f64);
2104
+ // The thread's busy time (none counted for an application-owned shard).
2105
+ let turns = mark.map(|m| busy.saturating_sub(m.turns) as f64 / elapsed.unwrap_or(1.0));
2106
+ let counted = busy > 0;
2107
+ // A chosen turn busy, as an engine-owned shard measures it.
2108
+ #[cfg(feature = "test-hooks")]
2109
+ let (turns, counted) = match self.shared.metrics[me].hooks.load_override(LoadTerm::Busy) {
2110
+ None => (turns, counted),
2111
+ Some(v) => (Some(v), true),
2112
+ };
2113
+ // A counted term over the interval, from its counter's rise (0 for an
2114
+ // application-owned shard, which counts no turns).
2115
+ let term = |now_v: u64, was: fn(&BusyMark) -> u64| match (mark, elapsed) {
2116
+ (Some(m), Some(e)) if counted => now_v.saturating_sub(was(&m)) as f64 / e,
2117
+ _ => 0.0,
2118
+ };
2119
+ let syncs = term(sync, |m| m.sync);
2120
+ // The thread's spin before parking (D198) over the interval: traced, no term (D257).
2121
+ let spins = term(spin, |m| m.spin);
2122
+ // The client commits in flight at this shard over the interval (D257). Counted on
2123
+ // the shard's own clock reads, so it needs no engine-owned thread: it is the
2124
+ // concurrency of the writers, which any clock that moves between a submit and its
2125
+ // reply measures.
2126
+ let inflights = match (mark, elapsed) {
2127
+ (Some(m), Some(e)) => Some(inflight.saturating_sub(m.inflight) as f64 / e),
2128
+ _ => None,
2129
+ };
2130
+ // A chosen concurrency (D257's packing tests), measured whether or not the clock
2131
+ // moved, as the chosen busy fraction is.
2132
+ #[cfg(feature = "test-hooks")]
2133
+ let inflights = self.shared.metrics[me]
2134
+ .hooks
2135
+ .load_override(LoadTerm::Inflight)
2136
+ .or(inflights);
2137
+ // The pool's slices for this shard over the interval (D256).
2138
+ let pools = term(pool, |m| m.pool);
2139
+ // A chosen pool term (D256's packing tests).
2140
+ #[cfg(feature = "test-hooks")]
2141
+ let pools = self.shared.metrics[me]
2142
+ .hooks
2143
+ .load_override(LoadTerm::Pool)
2144
+ .unwrap_or(pools);
2145
+ // This pass's stall bit, then the count over the window.
2146
+ let m = &self.shared.metrics[me];
2147
+ let events =
2148
+ m.room_stalls.load(Ordering::Relaxed) + m.pacing_stalls.load(Ordering::Relaxed);
2149
+ let stalled_now = events > self.stall_events_mark || self.stall_open();
2150
+ self.stall_events_mark = events;
2151
+ self.stall_history = (self.stall_history << 1) | u32::from(stalled_now);
2152
+ let window = self.stall_history & ((1u32 << PACK_STALL_WINDOW) - 1);
2153
+ let stalls = if counted && window.count_ones() >= PACK_STALL_PASSES {
2154
+ 1.0
2155
+ } else {
2156
+ 0.0
2157
+ };
2158
+ // A chosen stall term (D255's packing tests).
2159
+ #[cfg(feature = "test-hooks")]
2160
+ let stalls = self.shared.metrics[me]
2161
+ .hooks
2162
+ .load_override(LoadTerm::Stalled)
2163
+ .unwrap_or(stalls);
2164
+ let measured = turns.map(|t| (t + pools).max(syncs.min(1.0)).max(stalls));
2165
+ if let Some(frac) = measured {
2166
+ self.busy_ewma = LOAD_ALPHA * frac + (1.0 - LOAD_ALPHA) * self.busy_ewma;
2167
+ }
2168
+ if let Some(c) = inflights {
2169
+ self.inflight_ewma = LOAD_ALPHA * c + (1.0 - LOAD_ALPHA) * self.inflight_ewma;
2170
+ }
2171
+ if let Some(t) = turns {
2172
+ self.turn_ewma = LOAD_ALPHA * t.min(1.0) + (1.0 - LOAD_ALPHA) * self.turn_ewma;
2173
+ }
2174
+ self.stall_term = stalls;
2175
+ self.busy_mark = Some(BusyMark {
2176
+ turns: busy,
2177
+ spin,
2178
+ pool,
2179
+ sync,
2180
+ inflight,
2181
+ at: now,
2182
+ });
2183
+ trace!(
2184
+ "shard {} balancer: busy turn {:.2} pool {:.2} sync {:.2} stall {:.2} (events {}, window {:010b}) spin {:.2} in flight {:.2} -> ewma {:.2}, turn {:.2}, in flight {:.2}",
2185
+ self.id.0,
2186
+ turns.unwrap_or(0.0),
2187
+ pools,
2188
+ syncs,
2189
+ stalls,
2190
+ events,
2191
+ window,
2192
+ spins,
2193
+ inflights.unwrap_or(0.0),
2194
+ self.busy_ewma,
2195
+ self.turn_ewma,
2196
+ self.inflight_ewma
2197
+ );
2198
+ }
2199
+
2200
+ /// The shards that stay active under packing (D217): `0..k`. Every shard, without
2201
+ /// packing or before it has decided.
2202
+ pub(super) fn active_shards(&self) -> usize {
2203
+ let n = self.shared.shards;
2204
+ let k = self.shared.pack_k.load(Ordering::Acquire);
2205
+ if self.shared.balance.pack && k > 0 {
2206
+ k.min(n)
2207
+ } else {
2208
+ n
2209
+ }
2210
+ }
2211
+
2212
+ /// Shard 0 decides how many shards stay active and publishes it; the others read it
2213
+ /// (`active_shards`), so every shard uses the same `k` (D217). Each shard keeping its own
2214
+ /// hysteresis over loads read at different passes disagreed for good. Returns whether the
2215
+ /// store writes enough for packing to act (shard 0 then keeps its base interval).
2216
+ fn track_pack(&mut self, now: u64) -> bool {
2217
+ if self.id.0 != 0 {
2218
+ return false;
2219
+ }
2220
+ let writing = self.decide_pack(now);
2221
+ self.shared.pack_k.store(self.pack_k, Ordering::Release);
2222
+ self.shared
2223
+ .pack_target
2224
+ .store(self.pack_target, Ordering::Release);
2225
+ writing
2226
+ }
2227
+
2228
+ /// Updates how many shards stay active (D217): shard 0 decides `k` for every shard and
2229
+ /// publishes it (`Shared::pack_k`), from the published busy fractions,
2230
+ /// `ceil(B / PACK_TARGET)`, or the published commits in flight,
2231
+ /// `round(C / PACK_CONCURRENCY)` (D257), whichever is more. It grows (at least by one)
2232
+ /// after `PACK_GROW_PASSES` passes with the active shards above `PACK_SPREAD` busy on
2233
+ /// average, or fewer than the concurrency calls for, or with one of them above
2234
+ /// `PACK_HOT` (D251), and shrinks after `PACK_SHRINK_PASSES` passes with one fewer shard
2235
+ /// enough to stay under `PACK_TARGET`, more than the concurrency calls for, and none
2236
+ /// above `PACK_HOT`. The first shrink from the unpacked start waits for
2237
+ /// `PACK_FIRST_SHRINK_PASSES` of writing (D255) unless the slow concurrency has agreed
2238
+ /// with the fast one for a shrink count (D257): that first pack then decides on
2239
+ /// `PACK_GROW_PASSES` and counts through a write ramp, since one client's gate row
2240
+ /// measures ten seconds after a load and a few seconds of warm-up, inside which the
2241
+ /// 30 s wait, the 50 passes and the ramp guard each put the pack. Never fewer than the
2242
+ /// shards the tablets' memtable slots need (`max_slots` each), and at once up to that.
2243
+ /// Only while the store writes (`balance_min_writes` over all shards) and some shard
2244
+ /// reports busy time: an idle store, or a clock that does not move while shards work (the
2245
+ /// simulated VFS), keeps its placement.
2246
+ fn decide_pack(&mut self, now: u64) -> bool {
2247
+ let n = self.shared.shards;
2248
+ if !self.shared.balance.pack || n < 2 {
2249
+ return false;
2250
+ }
2251
+ if self.pack_k == 0 {
2252
+ self.pack_k = n;
2253
+ }
2254
+ self.pack_target = self.pack_k;
2255
+ let stale = self.shared.balance.interval_nanos.saturating_mul(3).max(1);
2256
+ // Over every shard's fresh report (a stale one reads 0): the sum, and the sum of the
2257
+ // fractions (millionths each).
2258
+ let loads = &self.shared.loads;
2259
+ let sum = |read: fn(&LoadSlot, u64, u64) -> Option<u64>| -> u64 {
2260
+ loads.iter().map(|l| read(l, now, stale).unwrap_or(0)).sum()
2261
+ };
2262
+ let sum_fractions = |read: fn(&LoadSlot, u64, u64) -> Option<u64>| -> f64 {
2263
+ loads
2264
+ .iter()
2265
+ .map(|l| read(l, now, stale).unwrap_or(0) as f64 / 1e6)
2266
+ .sum()
2267
+ };
2268
+ let busy = sum_fractions(LoadSlot::read_busy_fresh);
2269
+ let writes = sum(LoadSlot::read_fresh);
2270
+ let writes_slow = sum(LoadSlot::read_slow_fresh);
2271
+ // D257: the store's concurrency, the mean client commits in flight over every shard,
2272
+ // and the active shards it calls for. For `t` closed-loop clients it is at most `t`
2273
+ // whatever `k` is, so unlike the spin term it replaced it never justifies the spread
2274
+ // it caused.
2275
+ let inflight = sum_fractions(LoadSlot::read_inflight_fresh);
2276
+ let k_for = |inflight: f64| ((inflight / PACK_CONCURRENCY).round() as usize).clamp(1, n);
2277
+ let k_c = k_for(inflight);
2278
+ // The slow concurrency (D257): when it calls for the same active shards as the
2279
+ // fast one, the concurrency has held for the slow window and the first shrink from
2280
+ // the unpacked start need not wait for `PACK_FIRST_SHRINK_PASSES`. A dip after a
2281
+ // heavy phase still waits: the slow average remembers the phase for about the
2282
+ // window. A concurrency that reads 0 (the simulated clock, an application-owned
2283
+ // store) settles nothing, so the window applies as before.
2284
+ self.inflight_slow = SLOW_ALPHA * inflight + (1.0 - SLOW_ALPHA) * self.inflight_slow;
2285
+ let k_c_slow = k_for(self.inflight_slow);
2286
+ // Agreement must hold for a shrink count: the fast average crosses the slow one on
2287
+ // its way back up after a dip, and a count the dip accrued must not fire then.
2288
+ self.settled_passes = if inflight > 0.0 && k_c_slow == k_c {
2289
+ self.settled_passes.saturating_add(1)
2290
+ } else {
2291
+ 0
2292
+ };
2293
+ let settled = self.settled_passes >= PACK_SHRINK_PASSES;
2294
+ let writing = writes >= self.shared.balance.min_writes.max(1);
2295
+ if writing {
2296
+ self.writing_passes = self.writing_passes.saturating_add(1);
2297
+ }
2298
+ if busy <= 0.0 || !writing {
2299
+ self.pack_up = 0;
2300
+ self.pack_down = 0;
2301
+ return false;
2302
+ }
2303
+ // The active shards must hold every tablet's memtable slots: without the floor, the
2304
+ // first full shard strands the rest of the written tablets across the inactive ones.
2305
+ let floor = {
2306
+ let view = self.shared.view.load();
2307
+ let slots: usize = view
2308
+ .tablets
2309
+ .iter()
2310
+ .map(|t| view.catalog.family_ids_of(t.table).len())
2311
+ .sum();
2312
+ slots.div_ceil(self.max_slots().max(1))
2313
+ };
2314
+ let k = self.pack_k;
2315
+ let want = ((busy / PACK_TARGET).ceil() as usize)
2316
+ .max(k_c)
2317
+ .max(floor)
2318
+ .clamp(1, n);
2319
+ if k < floor {
2320
+ self.pack_k = want;
2321
+ self.pack_target = want;
2322
+ balance!(
2323
+ "shard {} balancer: active shards {k} -> {want} (slots need {floor})",
2324
+ self.id.0
2325
+ );
2326
+ self.pack_up = 0;
2327
+ self.pack_down = 0;
2328
+ return true;
2329
+ }
2330
+ // D251: an active shard whose thread is saturated (turn busy, not D248's sync term:
2331
+ // a shard whose syncs run back to back may not cool however many shards share the
2332
+ // load) grows `k` too, and holds off a shrink; so does one whose writers stall
2333
+ // (D255: their waits for room and L0 depth do ease once it sheds tablets). A
2334
+ // hot-triggered growth repeats only once the hot shard has cooled since the last
2335
+ // one (what it shed helped), or another shard is hot: a hot spot more shards cannot
2336
+ // cool (one unsplittable tablet) grows `k` once.
2337
+ let hottest = self.shared.loads[..k.min(n)]
2338
+ .iter()
2339
+ .enumerate()
2340
+ .map(|(i, l)| {
2341
+ let turn = l.read_turn_busy_fresh(now, stale).unwrap_or(0);
2342
+ let stall = l.read_stall_busy_fresh(now, stale).unwrap_or(0);
2343
+ (turn.max(stall), stall > turn, i)
2344
+ })
2345
+ .max()
2346
+ .filter(|(b, _, _)| *b as f64 / 1e6 > PACK_HOT);
2347
+ let hot = hottest.is_some();
2348
+ // A stall-driven hot shard grows `k` again while it still has tablets to shed
2349
+ // (D255): its stall fraction stays at 1 however much it sheds, so D251's cooled
2350
+ // check would hold it to one growth, and on the AX102 a load cut to 3 shards regrew
2351
+ // one shard per 20 s. The cooled check keeps holding thread-saturated hot spots.
2352
+ let view = self.shared.view.load();
2353
+ let hot_grows = hottest.is_some_and(|(b, stalled, h)| {
2354
+ let sheds = stalled
2355
+ && view
2356
+ .tablets
2357
+ .iter()
2358
+ .filter(|t| usize::from(t.shard.0) == h)
2359
+ .count()
2360
+ > 1;
2361
+ sheds
2362
+ || self
2363
+ .hot_grew
2364
+ .is_none_or(|(shard, was)| shard != h || b + PACK_HOT_COOLED < was)
2365
+ });
2366
+ if !hot {
2367
+ self.hot_grew = None;
2368
+ }
2369
+ // D255: the active shards a stall-driven growth reached stay active while the store
2370
+ // writes at least half of what it did then. The shards it spread to run cheap turns
2371
+ // once their writers stop stalling, so the busy sum alone would call for a shrink,
2372
+ // the stalls would come back, and `k` would swing between the two. The floor also
2373
+ // expires after a quiet window with no active shard stalling (the cause went away
2374
+ // with the load unchanged), each expiry doubling the next window.
2375
+ // A pass with a stalling or a saturated shard is not quiet (D255, D256): the floor
2376
+ // expires only once neither cause has shown for a window. A stalling shard reads
2377
+ // hot: its stall term is 0 or 1 (D255), and 1 is past `PACK_HOT`.
2378
+ if hot {
2379
+ self.floor_quiet = 0;
2380
+ } else {
2381
+ self.floor_quiet = self.floor_quiet.saturating_add(1);
2382
+ }
2383
+ let quiet_needed = self.floor_quiet_needed.max(PACK_FLOOR_QUIET);
2384
+ let stall_floor = match self.stall_floor {
2385
+ Some((floor_k, writes_then))
2386
+ if writes.saturating_mul(2) >= writes_then && self.floor_quiet < quiet_needed =>
2387
+ {
2388
+ floor_k
2389
+ }
2390
+ Some(_) => {
2391
+ self.stall_floor = None;
2392
+ if self.floor_quiet >= quiet_needed {
2393
+ // Expired on a quiet window: a floor set again within one window is
2394
+ // the same cause coming back and doubles the next window (below).
2395
+ self.floor_expired_pass = self.balance_pass.max(1);
2396
+ } else {
2397
+ // Released by a write drop: the next floor starts from the base window.
2398
+ self.floor_expired_pass = 0;
2399
+ self.floor_quiet_needed = PACK_FLOOR_QUIET;
2400
+ }
2401
+ 0
2402
+ }
2403
+ None => 0,
2404
+ };
2405
+ let floor = floor.max(stall_floor.min(n));
2406
+ let spread = busy / k as f64 > PACK_SPREAD;
2407
+ // D257: fewer active shards than the commits in flight call for grow them; more
2408
+ // than they call for is one of the conditions of a shrink.
2409
+ let concurrent = k < k_c;
2410
+ // No shrink while the load is still ramping (D255, #734): the fast write average
2411
+ // above the slow one. The first pass of a load read its ramp as a light store.
2412
+ let ramping = writes_slow > 0 && writes as f64 > PACK_RAMP * writes_slow as f64;
2413
+ self.ramp_passes = if ramping {
2414
+ self.ramp_passes.saturating_add(1)
2415
+ } else {
2416
+ 0
2417
+ };
2418
+ let ramping = ramping && self.ramp_passes <= PACK_RAMP_MAX;
2419
+ // Shard 0 decides the packing (D217): its pass state, when an input to the decision
2420
+ // changes or once a second (#1188).
2421
+ if self.id.0 == 0 && balance_logging() {
2422
+ let key = format!(
2423
+ "k {k} k_c {k_c}/{k_c_slow} settled {} ramping {ramping} hottest {} floor {floor} up {} down {}",
2424
+ self.settled_passes >= PACK_SHRINK_PASSES,
2425
+ hottest.is_some(),
2426
+ self.pack_up > 0,
2427
+ self.pack_down > 0
2428
+ );
2429
+ let due = self.balance_logged.as_ref().is_none_or(|(last, at)| {
2430
+ *last != key || at.elapsed() >= std::time::Duration::from_secs(1)
2431
+ });
2432
+ if due {
2433
+ balance!(
2434
+ "shard 0 pass {}: k {k} busy {busy:.2} in flight {inflight:.2} (k_c {k_c}, slow {:.2} k_c {k_c_slow}, settled {} of {}) writes {writes} (slow {writes_slow}, ramping {ramping}) floor {floor} hottest {:?} up {} down {} stall floor {:?}",
2435
+ self.balance_pass,
2436
+ self.inflight_slow,
2437
+ self.settled_passes,
2438
+ PACK_SHRINK_PASSES,
2439
+ hottest,
2440
+ self.pack_up,
2441
+ self.pack_down,
2442
+ self.stall_floor
2443
+ );
2444
+ self.balance_logged = Some((key, std::time::Instant::now()));
2445
+ }
2446
+ }
2447
+ trace!(
2448
+ "shard {} balancer pass: k {k} busy {busy:.2} in flight {inflight:.2} (k_c {k_c}, slow {:.2} k_c {k_c_slow}, settled {} of {}) writes {writes} (slow {writes_slow}, ramping {ramping}) floor {floor} (quiet {} of {}) hottest {:?} up {} down {}",
2449
+ self.id.0,
2450
+ self.inflight_slow,
2451
+ self.settled_passes,
2452
+ PACK_SHRINK_PASSES,
2453
+ self.floor_quiet,
2454
+ self.floor_quiet_needed.max(PACK_FLOOR_QUIET),
2455
+ hottest,
2456
+ self.pack_up,
2457
+ self.pack_down
2458
+ );
2459
+ if k < n && (spread || concurrent || hot_grows) {
2460
+ self.pack_up += 1;
2461
+ // Where the growth is heading, for the bench's warm-up (D242's amendment): it
2462
+ // does not measure across a growth whose passes are still accruing.
2463
+ self.pack_target = want.max(k + 1).min(n);
2464
+ } else {
2465
+ self.pack_up = 0;
2466
+ }
2467
+ // No shrink on a pass with a hot shard, stalling ones included (D255): a pass on which
2468
+ // an active shard's writers stall is no light pass, whatever the busy sum reads. On
2469
+ // the AX102 a write lull in the middle of a 16 GiB load (the loader's writers waiting
2470
+ // on room: writes 2,479 against 10–48K around it, busy 0.27) completed the count the
2471
+ // ramp had let accrue, and D217 shrank 16 → 2 mid-load.
2472
+ if !hot && k > floor.max(1) && k > k_c && busy / ((k - 1) as f64) < PACK_TARGET {
2473
+ // A ramping pass pauses the shrink count: a light pass advances it only while
2474
+ // the load is not ramping, and a hot, busy or stalling pass resets it ramping
2475
+ // or not (ctr274's review: a count carried across a bursty heavy load's bursts
2476
+ // would shrink and grow in a slow cycle; a lull whose writers wait on room is
2477
+ // no light pass).
2478
+ // A settled concurrency counts through a write ramp (D257): a ramp fools the
2479
+ // busy sum, which reads a load's start as light, not the commits in flight,
2480
+ // which read one client as one client at any rate; and a cold start's slow
2481
+ // write average reads every steady load as ramping for its first 16 s.
2482
+ if !ramping || settled {
2483
+ self.pack_down += 1;
2484
+ }
2485
+ // Where the first pack from the unpacked start is heading, for the bench's
2486
+ // warm-up (#983): it moves every tablet, and from all `n` shards the store reads
2487
+ // as settled while it accrues its count. Later shrinks are not published: their
2488
+ // last steps are slow and the warm-up's quiet window covers their moves.
2489
+ if k == n {
2490
+ self.pack_target = want.min(k - 1).max(floor.max(1));
2491
+ }
2492
+ } else {
2493
+ self.pack_down = 0;
2494
+ }
2495
+ // The first pack from the unpacked start on a settled concurrency decides on the
2496
+ // growth count, not the shrink count (D257): the concurrency agreed for a shrink
2497
+ // count already, and a client's placement must settle inside the few seconds a
2498
+ // warm-up gives it before its measured phase (D242's 2 s quiet). Later shrinks
2499
+ // keep D217's 50 passes, so a short dip in a running load does not flap.
2500
+ let shrink_passes = if settled && k == n {
2501
+ PACK_GROW_PASSES
2502
+ } else {
2503
+ PACK_SHRINK_PASSES
2504
+ };
2505
+ let why = if k < floor {
2506
+ self.pack_k = want.max(floor).min(n);
2507
+ "the stall floor"
2508
+ } else if self.pack_up >= PACK_GROW_PASSES {
2509
+ self.pack_k = want.max(k + 1).min(n);
2510
+ // Whatever called for it, a growth with a hot shard counts as its growth.
2511
+ match hottest {
2512
+ Some((b, stalled, h)) => {
2513
+ self.hot_grew = Some((h, b));
2514
+ if stalled {
2515
+ // A shrink that stalls writers within a minute, with the store
2516
+ // writing twice what it did then, was wrong (the load came back):
2517
+ // back to the count before it in one step (D255).
2518
+ if let Some((from, at, writes_then)) = self.shrunk_from.take()
2519
+ && self.balance_pass.saturating_sub(at) <= PACK_SHRINK_UNDO
2520
+ && writes >= writes_then.saturating_mul(2)
2521
+ {
2522
+ self.pack_k = self.pack_k.max(from.min(n));
2523
+ }
2524
+ }
2525
+ // The count a hot shard grew the store to is the floor while the
2526
+ // store keeps writing at least half its rate then (D255 for a
2527
+ // stalling shard, D256 for a saturated one): the shards it spread to
2528
+ // run cheap turns, so the busy sum alone would shrink it back and the
2529
+ // stall or the saturation would return.
2530
+ if self.stall_floor.is_none() {
2531
+ // A floor set within one quiet window of the last expiry is the
2532
+ // same cause coming back: the window doubles, up to the cap. One
2533
+ // set later starts from the base again.
2534
+ let since = self.balance_pass.saturating_sub(self.floor_expired_pass);
2535
+ self.floor_quiet_needed =
2536
+ if self.floor_expired_pass != 0 && since <= quiet_needed {
2537
+ (quiet_needed * 2).min(PACK_FLOOR_QUIET_MAX)
2538
+ } else {
2539
+ PACK_FLOOR_QUIET
2540
+ };
2541
+ }
2542
+ self.stall_floor = Some((self.pack_k, writes));
2543
+ if stalled {
2544
+ "a shard whose writers stall (D255)"
2545
+ } else {
2546
+ "a shard whose thread is saturated (D251)"
2547
+ }
2548
+ }
2549
+ None if spread => "the busy sum over the active shards (D217)",
2550
+ None => {
2551
+ debug_assert!(concurrent);
2552
+ "the commits in flight (D257)"
2553
+ }
2554
+ }
2555
+ } else if self.pack_down >= shrink_passes
2556
+ && (k < n || settled || self.writing_passes >= PACK_FIRST_SHRINK_PASSES)
2557
+ {
2558
+ self.pack_k = want.min(k - 1).max(floor.max(1));
2559
+ self.shrunk_from = Some((k, self.balance_pass, writes));
2560
+ "a busy sum and commits in flight low enough for one fewer (D217, D257)"
2561
+ } else {
2562
+ return true;
2563
+ };
2564
+ // A shrink lands where it decided; a growth's undo may land above its target.
2565
+ self.pack_target = if self.pack_k < k {
2566
+ self.pack_k
2567
+ } else {
2568
+ self.pack_target.max(self.pack_k)
2569
+ };
2570
+ balance!(
2571
+ "shard {} balancer: active shards {k} -> {} (busy {busy:.2}, in flight {inflight:.2}, floor {floor}, writes {writes}): {why}",
2572
+ self.id.0,
2573
+ self.pack_k
2574
+ );
2575
+ self.pack_up = 0;
2576
+ self.pack_down = 0;
2577
+ true
2578
+ }
2579
+
2580
+ /// Updates whether this shard acts on write skew (D214, with hysteresis): it starts after
2581
+ /// `SKEW_PERSIST` consecutive passes above `balance_skew` times the mean (and at least
2582
+ /// `balance_min_writes`), and stops once its load falls below the stop ratio or
2583
+ /// `balance_min_writes`. Counted on every pass, dwell or not.
2584
+ fn track_skew(&mut self, now: u64) {
2585
+ let cfg = self.shared.balance;
2586
+ // The slow path (D224): skew on the slow averages, whatever the mean does.
2587
+ self.slow_run = match self.published_slow_loads(now) {
2588
+ Some(slow) => {
2589
+ let my = slow[usize::from(self.id.0)] as f64;
2590
+ let mean = slow.iter().sum::<u64>() as f64 / slow.len() as f64;
2591
+ if my >= cfg.min_writes.max(1) as f64 && my > cfg.skew * mean {
2592
+ self.slow_run + 1
2593
+ } else {
2594
+ 0
2595
+ }
2596
+ }
2597
+ None => 0,
2598
+ };
2599
+ let Some((my, mean)) = self.shard_loads(now) else {
2600
+ self.skew_run = 0;
2601
+ self.skew_active = false;
2602
+ self.mean_falling = false;
2603
+ return;
2604
+ };
2605
+ self.mean_slow = MEAN_SLOW_ALPHA * mean + (1.0 - MEAN_SLOW_ALPHA) * self.mean_slow;
2606
+ self.mean_falling = mean < MEAN_FALL * self.mean_slow;
2607
+ let min = cfg.min_writes.max(1) as f64;
2608
+ if self.skew_active {
2609
+ if my < min || my < Self::skew_stop(cfg.skew) * mean {
2610
+ balance!(
2611
+ "shard {} write skew ends: writes {my:.0} against a mean of {mean:.0}",
2612
+ self.id.0
2613
+ );
2614
+ self.skew_active = false;
2615
+ self.skew_run = 0;
2616
+ }
2617
+ return;
2618
+ }
2619
+ // A pass while the mean is falling neither counts nor resets the persistence (D224):
2620
+ // under a closed-loop load it is a phase's tail, which must not trigger, and a bursty
2621
+ // load whose mean dips between bursts must still reach `SKEW_PERSIST`.
2622
+ let run_before = self.skew_run;
2623
+ if !self.mean_falling {
2624
+ if my >= min && my > cfg.skew * mean {
2625
+ self.skew_run += 1;
2626
+ } else {
2627
+ self.skew_run = 0;
2628
+ }
2629
+ }
2630
+ if self.skew_run >= SKEW_PERSIST {
2631
+ balance!(
2632
+ "shard {} write skew: writes {my:.0} against a mean of {mean:.0} for {} passes",
2633
+ self.id.0,
2634
+ self.skew_run
2635
+ );
2636
+ self.skew_active = true;
2637
+ } else if run_before == 0 && self.skew_run == 1 {
2638
+ balance!(
2639
+ "shard {} write skew starts: writes {my:.0} against a mean of {mean:.0}",
2640
+ self.id.0
2641
+ );
2642
+ } else if run_before > 0 && self.skew_run == 0 {
2643
+ balance!(
2644
+ "shard {} write skew run resets after {run_before} passes: writes {my:.0} \
2645
+ against a mean of {mean:.0}",
2646
+ self.id.0
2647
+ );
2648
+ }
2649
+ }
2650
+
2651
+ /// The load ratio below which a shard acting on write skew stops (D214).
2652
+ fn skew_stop(skew: f64) -> f64 {
2653
+ 1.0 + SKEW_STOP * (skew - 1.0)
2654
+ }
2655
+
2656
+ /// The published write loads of the active shards (every shard without packing, D217;
2657
+ /// stale ones count as 0), or `None` with a single active shard or when this shard is not
2658
+ /// active (it only hands its tablets to the active ones).
2659
+ fn published_loads(&self, now: u64) -> Option<Vec<u64>> {
2660
+ let n = self.active_shards();
2661
+ if n < 2 || usize::from(self.id.0) >= n {
2662
+ return None;
2663
+ }
2664
+ let stale = self.shared.balance.interval_nanos.saturating_mul(3).max(1);
2665
+ Some(
2666
+ self.shared.loads[..n]
2667
+ .iter()
2668
+ .map(|slot| slot.read_fresh(now, stale).unwrap_or(0))
2669
+ .collect(),
2670
+ )
2671
+ }
2672
+
2673
+ /// The published slow write loads of the active shards (D224), as
2674
+ /// [`published_loads`](Self::published_loads). A shard backing off while idle publishes
2675
+ /// rarely, so a slow load stays current for twice the longest backoff.
2676
+ fn published_slow_loads(&self, now: u64) -> Option<Vec<u64>> {
2677
+ let n = self.active_shards();
2678
+ if n < 2 || usize::from(self.id.0) >= n {
2679
+ return None;
2680
+ }
2681
+ let stale = BALANCE_IDLE_CAP_NANOS
2682
+ .max(self.shared.balance.interval_nanos)
2683
+ .saturating_mul(2);
2684
+ Some(
2685
+ self.shared.loads[..n]
2686
+ .iter()
2687
+ .map(|slot| slot.read_slow_fresh(now, stale).unwrap_or(0))
2688
+ .collect(),
2689
+ )
2690
+ }
2691
+
2692
+ /// This shard's published load and the mean over the active shards.
2693
+ fn shard_loads(&self, now: u64) -> Option<(f64, f64)> {
2694
+ let loads = self.published_loads(now)?;
2695
+ let mean = loads.iter().sum::<u64>() as f64 / loads.len() as f64;
2696
+ Some((loads[usize::from(self.id.0)] as f64, mean))
2697
+ }
2698
+
2699
+ /// Whether write skew may move or split `t` this pass (it has dwelt here long enough).
2700
+ fn settled(&self, t: TabletId) -> bool {
2701
+ self.arrived
2702
+ .get(&t)
2703
+ .is_none_or(|p| *p == 0 || *p + DWELL_PASSES <= self.balance_pass)
2704
+ }
2705
+
2706
+ /// Wakes the shard for its next balancer pass even when no message arrives (#103), so
2707
+ /// an idle shard still merges cold tablets. Like the other clock timers (D126), one that
2708
+ /// gave up on a frozen clock is not armed again while the clock stays frozen.
2709
+ fn arm_balance_timer(&mut self, ctx: &mut ShardContext<'_, ShardMsg>) {
2710
+ let interval = self.shared.balance.interval_nanos;
2711
+ if interval == 0 || interval == u64::MAX || self.closing || self.next_balance == u64::MAX {
2712
+ return;
2713
+ }
2714
+ let now = ctx.now_nanos();
2715
+ if self.balance_timer.as_ref().is_some_and(|t| t.holds(now)) {
2716
+ return;
2717
+ }
2718
+ let state = TimerState::new();
2719
+ ctx.spawn(Box::new(ClockTimer::new(
2720
+ &self.shared.vfs,
2721
+ self.next_balance,
2722
+ Arc::clone(&state),
2723
+ ctx.submitter(self.id).clone(),
2724
+ ShardMsg::Kick,
2725
+ )));
2726
+ self.balance_timer = Some(state);
2727
+ }
2728
+
2729
+ /// Cancels the balancer's wakeup (close).
2730
+ pub(super) fn cancel_balance_timer(&mut self) {
2731
+ if let Some(t) = self.balance_timer.take() {
2732
+ t.cancel();
2733
+ }
2734
+ }
2735
+
2736
+ /// Starts a rewrite of the first queued cleanup slot that still holds an SST sticking out
2737
+ /// of its tablet (#95): the rewrite drops the sibling's rows, so a later balancer pass can
2738
+ /// merge. Slots that no longer need one, or whose tablet left this shard or is being
2739
+ /// changed, are dropped (the balancer queues them again while the merge is refused).
2740
+ pub(super) fn start_cleanup(
2741
+ &mut self,
2742
+ view: &Arc<View>,
2743
+ busy: &[SstId],
2744
+ ctx: &mut ShardContext<'_, ShardMsg>,
2745
+ ) {
2746
+ let last = self.shared.picker.max_levels.max(2) - 1;
2747
+ let now = ctx.now_nanos();
2748
+ // Slots waiting out a failed compaction's backoff stay queued (issue #141).
2749
+ let mut later = Vec::new();
2750
+ while !self.cleanups.is_empty() {
2751
+ let key = self.cleanups.remove(0);
2752
+ if let Some(&(_, until)) = self.slot_backoff.get(&key)
2753
+ && until > now
2754
+ {
2755
+ later.push(key);
2756
+ continue;
2757
+ }
2758
+ let Some(tablet) = view.tablets.entry(key.0).filter(|t| t.shard == self.id) else {
2759
+ continue;
2760
+ };
2761
+ if self.moving.contains(&key.0)
2762
+ || view
2763
+ .catalog
2764
+ .family(key.1)
2765
+ .is_none_or(|m| m.merge == MergeKind::Unknown)
2766
+ {
2767
+ continue;
2768
+ }
2769
+ let Some(fam) = view.ssts.family(key.0, key.1) else {
2770
+ continue;
2771
+ };
2772
+ let levels = fam.levels_meta();
2773
+ if !sticks_out_of(tablet, &levels) {
2774
+ continue;
2775
+ }
2776
+ let Some(task) = compact::plan_full(
2777
+ tablet,
2778
+ key.1,
2779
+ &levels,
2780
+ last,
2781
+ busy,
2782
+ true,
2783
+ // A cleanup is no full compaction: `None` below means busy inputs only.
2784
+ false,
2785
+ self.shared.picker.target_sst_bytes,
2786
+ // Rewritten anyway: it holds rows outside the tablet.
2787
+ |_| false,
2788
+ ) else {
2789
+ // Its inputs are busy: try again after the running work.
2790
+ self.cleanups.insert(0, key);
2791
+ break;
2792
+ };
2793
+ trace!("shard {} cleanup rewrite of {key:?}", self.id.0);
2794
+ if let Err(e) = self.start_compaction(view, key, task, ctx) {
2795
+ trace!("shard {} compaction start failed: {e}", self.id.0);
2796
+ self.back_off_compaction(key, ctx);
2797
+ }
2798
+ break;
2799
+ }
2800
+ // A cleanup passed over for its slot's backoff runs when the backoff ends, even on
2801
+ // a shard that is idle by then.
2802
+ if let Some(until) = later
2803
+ .iter()
2804
+ .filter_map(|k| self.slot_backoff.get(k).map(|&(_, until)| until))
2805
+ .min()
2806
+ {
2807
+ self.arm_compaction_retry(until, ctx);
2808
+ }
2809
+ self.cleanups.extend(later);
2810
+ }
2811
+
2812
+ /// The balancer's choice for this interval, if any: a size split, a write-skew (or
2813
+ /// memtable-skew) move or split, or a merge of two small, cold neighbours. With no
2814
+ /// choice, also the slots to rewrite so that a refused merge can go through later.
2815
+ fn decide(
2816
+ &self,
2817
+ now: u64,
2818
+ mem_per: &HashMap<TabletId, u64>,
2819
+ ) -> (Option<TabletOpKind>, Vec<(TabletId, FamilyId)>) {
2820
+ let mut cleanups = Vec::new();
2821
+ (self.choose(now, mem_per, &mut cleanups), cleanups)
2822
+ }
2823
+
2824
+ fn choose(
2825
+ &self,
2826
+ now: u64,
2827
+ mem_per: &HashMap<TabletId, u64>,
2828
+ cleanups: &mut Vec<(TabletId, FamilyId)>,
2829
+ ) -> Option<TabletOpKind> {
2830
+ let cfg = self.shared.balance;
2831
+ let view = self.shared.view.load_full();
2832
+ let owned: Vec<TabletEntry> = view
2833
+ .tablets
2834
+ .iter()
2835
+ .filter(|t| t.shard == self.id)
2836
+ .cloned()
2837
+ .collect();
2838
+ if owned.is_empty() {
2839
+ return None;
2840
+ }
2841
+ let refs = view.catalog.sst_refs();
2842
+ // Every `(tablet, family)` slot written to takes memtable chunks: a shard keeps its
2843
+ // slots within `max_slots`, so splits never starve writers of memtables.
2844
+ let room_for = |t: &TabletEntry| {
2845
+ self.slots_fit(&view, self.id, view.catalog.family_ids_of(t.table).len())
2846
+ };
2847
+ // 1. Size: a tablet holding `tablet_split_bytes` of SSTs splits in two (not while it
2848
+ // still shares SSTs with a sibling: their bytes would count twice).
2849
+ for t in &owned {
2850
+ let (bytes, shared) = live_bytes(&view, t, &refs);
2851
+ if bytes < cfg.split_bytes || shared {
2852
+ continue;
2853
+ }
2854
+ if !room_for(t) {
2855
+ self.shared.metrics[usize::from(self.id.0)]
2856
+ .refused_slots
2857
+ .fetch_add(1, Ordering::Relaxed);
2858
+ balance!(
2859
+ "shard {} balancer: tablet {} is due a size split but the shard holds \
2860
+ {} of its {} slots",
2861
+ self.id.0,
2862
+ t.id.0,
2863
+ Self::slots_in(&view, self.id),
2864
+ self.max_slots()
2865
+ );
2866
+ continue;
2867
+ }
2868
+ if let Some(key) = self.size_split_key(&view, t) {
2869
+ return Some(TabletOpKind::Split {
2870
+ tablet: t.id,
2871
+ keys: vec![key],
2872
+ owners: vec![self.id, self.id],
2873
+ });
2874
+ }
2875
+ }
2876
+ let dwelling = self
2877
+ .skew_pass
2878
+ .is_some_and(|p| p + DWELL_PASSES > self.balance_pass);
2879
+ // Packing (D217): a shard outside the active ones (`0..k`) hands its written tablets,
2880
+ // one per dwell, to the least busy active shard with room. Cold tablets stay: they
2881
+ // cost no wakeups. A shard a skew change claimed is no target until its load shows
2882
+ // (D270), as for skew changes (D224). A packing move claims nothing itself: packing
2883
+ // means handing load to the active shards, and claims would hold its moves to one
2884
+ // per target per dwell.
2885
+ let active = self.active_shards();
2886
+ if usize::from(self.id.0) >= active && !dwelling {
2887
+ let stale = cfg.interval_nanos.saturating_mul(3).max(1);
2888
+ let mut targets: Vec<(u64, usize)> = self.shared.loads[..active]
2889
+ .iter()
2890
+ .enumerate()
2891
+ .map(|(i, l)| (l.read_busy_fresh(now, stale).unwrap_or(0), i))
2892
+ .collect();
2893
+ targets.sort_unstable();
2894
+ let written = owned
2895
+ .iter()
2896
+ .filter(|t| self.settled(t.id))
2897
+ .filter(|t| self.loads.get(&t.id).is_some_and(|l| l.ewma >= 1.0))
2898
+ .max_by(|a, b| {
2899
+ let w = |t: &TabletEntry| self.loads.get(&t.id).map_or(0.0, |l| l.ewma);
2900
+ w(a).total_cmp(&w(b)).then(b.id.cmp(&a.id))
2901
+ });
2902
+ if let Some(t) = written {
2903
+ let families = view.catalog.family_ids_of(t.table).len();
2904
+ if let Some((_, to)) = targets.iter().find(|(_, i)| {
2905
+ self.shared.loads[*i].claimable(now)
2906
+ && self.slots_fit(&view, ShardId(*i as u16), families)
2907
+ }) {
2908
+ return Some(TabletOpKind::Move {
2909
+ tablet: t.id,
2910
+ to: ShardId(*to as u16),
2911
+ });
2912
+ }
2913
+ }
2914
+ }
2915
+ // 2. Skew across shards, on the moving averages of write load (#103; memtable bytes
2916
+ // swing with every flush and no longer count). Only once the skew persisted
2917
+ // (`track_skew`, D214), not during the shard's dwell after its last move, and only
2918
+ // for tablets that dwelt here long enough. Under packing, only among the active
2919
+ // shards (D217).
2920
+ // The slow path (D224) acts on the slow averages instead, once per `SLOW_DWELL`:
2921
+ // under a closed-loop load the fast averages show skew only in each phase's tail
2922
+ // (where it doesn't count), the slow ones the shards' shares of the work.
2923
+ self.chose_slow.set(false);
2924
+ let slow_dwelling = self
2925
+ .slow_pass
2926
+ .is_some_and(|p| p + SLOW_DWELL > self.balance_pass);
2927
+ for slow in [false, true] {
2928
+ let (ready, loads) = if slow {
2929
+ // Only while the fast averages agree this shard is above the stop ratio: once
2930
+ // the fast path balanced it, the slow averages still show the old skew for a
2931
+ // while, and acting on them would overshoot.
2932
+ let agrees = self
2933
+ .shard_loads(now)
2934
+ .is_some_and(|(my, mean)| my > Self::skew_stop(cfg.skew) * mean);
2935
+ (
2936
+ self.slow_run >= SKEW_PERSIST && !slow_dwelling && agrees,
2937
+ self.published_slow_loads(now),
2938
+ )
2939
+ } else {
2940
+ (
2941
+ self.skew_active && !self.mean_falling,
2942
+ self.published_loads(now),
2943
+ )
2944
+ };
2945
+ let Some(writes) = loads.filter(|_| ready && !dwelling) else {
2946
+ continue;
2947
+ };
2948
+ let settled: Vec<TabletEntry> = owned
2949
+ .iter()
2950
+ .filter(|t| self.settled(t.id))
2951
+ .cloned()
2952
+ .collect();
2953
+ let tablet_writes: HashMap<TabletId, u64> = settled
2954
+ .iter()
2955
+ .map(|t| {
2956
+ let w = self
2957
+ .loads
2958
+ .get(&t.id)
2959
+ .map_or(0.0, |l| if slow { l.slow } else { l.ewma });
2960
+ (t.id, w.round() as u64)
2961
+ })
2962
+ .collect();
2963
+ let splits_ok = |op: &TabletOpKind| match op {
2964
+ TabletOpKind::Split { tablet, .. } => {
2965
+ owned.iter().find(|t| t.id == *tablet).is_some_and(room_for)
2966
+ }
2967
+ _ => true,
2968
+ };
2969
+ // The slow path makes one change per dwell, only past the trigger itself.
2970
+ let ratio = if slow {
2971
+ cfg.skew
2972
+ } else {
2973
+ Self::skew_stop(cfg.skew)
2974
+ };
2975
+ if let Some(op) = self.skew_op(&view, &settled, &writes, &tablet_writes, ratio, now)
2976
+ && splits_ok(&op)
2977
+ && self.claim_targets(&op, if slow { SLOW_DWELL } else { DWELL_PASSES }, now)
2978
+ {
2979
+ self.chose_slow.set(slow);
2980
+ return Some(op);
2981
+ }
2982
+ }
2983
+ // 3. Merge two adjacent cold tablets of one table that are small together.
2984
+ let small_together = |a: &TabletEntry, b: &TabletEntry| {
2985
+ live_bytes(&view, a, &refs).0 + live_bytes(&view, b, &refs).0 < cfg.split_bytes / 4
2986
+ };
2987
+ let cold_nanos = cfg.interval_nanos.saturating_mul(cfg.cold_passes);
2988
+ let long_ago = |(pass, clock): (u64, u64)| {
2989
+ pass + cfg.cold_passes <= self.balance_pass || clock.saturating_add(cold_nanos) <= now
2990
+ };
2991
+ let cold = |id: TabletId| {
2992
+ self.loads.get(&id).is_none_or(|l| {
2993
+ l.writes == 0
2994
+ && l.prev_writes == 0
2995
+ && (l.last_write == (0, 0) || long_ago(l.last_write))
2996
+ }) && long_ago((
2997
+ self.arrived.get(&id).copied().unwrap_or(0),
2998
+ self.arrived_at.get(&id).copied().unwrap_or(0),
2999
+ )) && mem_per.get(&id).copied().unwrap_or(0) == 0
3000
+ };
3001
+ for pair in owned.windows(2) {
3002
+ let (l, r) = (&pair[0], &pair[1]);
3003
+ if l.table != r.table
3004
+ || l.end.as_deref() != Some(r.start.as_slice())
3005
+ || !cold(l.id)
3006
+ || !cold(r.id)
3007
+ {
3008
+ continue;
3009
+ }
3010
+ if !small_together(l, r) {
3011
+ continue;
3012
+ }
3013
+ if merged_ssts(&view.catalog, l, r).is_ok() {
3014
+ return Some(TabletOpKind::Merge {
3015
+ left: l.id,
3016
+ right: r.id,
3017
+ });
3018
+ }
3019
+ // Refused while a side still holds an SST inherited from the split, with its
3020
+ // sibling's rows: nothing else rewrites a cold tablet's SSTs, so ask for it.
3021
+ for t in [l, r] {
3022
+ for f in view.catalog.family_ids_of(t.table) {
3023
+ if view
3024
+ .ssts
3025
+ .family(t.id, f)
3026
+ .is_some_and(|fam| sticks_out_of(t, &fam.levels_meta()))
3027
+ {
3028
+ cleanups.push((t.id, f));
3029
+ }
3030
+ }
3031
+ }
3032
+ }
3033
+ // 4. Consolidate (#103): a cold tablet whose left neighbour lives on another shard
3034
+ // moves there when the two are small together, so that shard can merge them.
3035
+ // Only right to left, so two shards never swap tablets, and only tablets that
3036
+ // dwelt here (a split's child is cold until its first writes arrive).
3037
+ for t in &owned {
3038
+ if !cold(t.id) || t.start.is_empty() || !self.settled(t.id) {
3039
+ continue;
3040
+ }
3041
+ let Some(left) = view
3042
+ .tablets
3043
+ .tablets_of(t.table)
3044
+ .iter()
3045
+ .find(|l| l.end.as_deref() == Some(t.start.as_slice()))
3046
+ else {
3047
+ continue;
3048
+ };
3049
+ // Never onto a shard packing is emptying (D217).
3050
+ if left.shard == self.id || usize::from(left.shard.0) >= active {
3051
+ continue;
3052
+ }
3053
+ let families = view.catalog.family_ids_of(t.table).len();
3054
+ if small_together(left, t) && self.slots_fit(&view, left.shard, families) {
3055
+ return Some(TabletOpKind::Move {
3056
+ tablet: t.id,
3057
+ to: left.shard,
3058
+ });
3059
+ }
3060
+ }
3061
+ None
3062
+ }
3063
+
3064
+ /// Whether `op` touches the tablet a running compaction is on: it waits for the
3065
+ /// compaction's end and is decided again then (#102).
3066
+ fn waits_on_compaction(&self, op: &TabletOpKind) -> bool {
3067
+ matches!(self.compaction, Some((t, _)) if op.tablets().contains(&t))
3068
+ }
3069
+
3070
+ /// Claims every shard a skew change hands load to (D224), for `dwell` of their passes or
3071
+ /// as many base intervals of clock, whichever comes first (the slow path's dwell for its
3072
+ /// changes). False if another change claimed one first: the change waits for a later
3073
+ /// pass. A claim whose change is refused simply runs out.
3074
+ ///
3075
+ /// A change that waits on a compaction claims nothing and reads as claimed (D270): it
3076
+ /// claims when it is decided again at the compaction's end. So a caller that starts the
3077
+ /// change it gets must not have a compaction running on its tablets: `maybe_balance`
3078
+ /// filters waiting changes out, and `start_waiting_change` runs with no compaction.
3079
+ fn claim_targets(&self, op: &TabletOpKind, dwell: u64, now: u64) -> bool {
3080
+ if self.waits_on_compaction(op) {
3081
+ return true;
3082
+ }
3083
+ let dwell_nanos = self.shared.balance.interval_nanos.saturating_mul(dwell);
3084
+ let to: Vec<ShardId> = match op {
3085
+ TabletOpKind::Move { to, .. } => vec![*to],
3086
+ TabletOpKind::Split { owners, .. } => {
3087
+ owners.iter().copied().filter(|o| *o != self.id).collect()
3088
+ }
3089
+ _ => Vec::new(),
3090
+ };
3091
+ to.iter()
3092
+ .all(|s| self.shared.loads[usize::from(s.0)].claim(dwell, dwell_nanos, now))
3093
+ }
3094
+
3095
+ /// A move or split that evens out `loads` (per shard), given this shard's tablets'
3096
+ /// shares of it (`per_tablet`), when this shard is skewed past the threshold.
3097
+ fn skew_op(
3098
+ &self,
3099
+ view: &View,
3100
+ owned: &[TabletEntry],
3101
+ loads: &[u64],
3102
+ per_tablet: &HashMap<TabletId, u64>,
3103
+ ratio: f64,
3104
+ now: u64,
3105
+ ) -> Option<TabletOpKind> {
3106
+ let min = self.shared.balance.min_writes;
3107
+ let me = usize::from(self.id.0);
3108
+ let my = loads[me];
3109
+ let total: u64 = loads.iter().sum();
3110
+ let mean = total as f64 / loads.len() as f64;
3111
+ if my < min.max(1) || (my as f64) <= ratio * mean {
3112
+ return None;
3113
+ }
3114
+ // A shard another skew change just handed load is not a target until its published
3115
+ // load shows it (D224): shards balancing at once would otherwise all shed into the
3116
+ // same cold shard.
3117
+ let open = |i: usize| self.shared.loads[i].claimable(now);
3118
+ let (cold, low) = loads
3119
+ .iter()
3120
+ .enumerate()
3121
+ .filter(|(i, _)| *i != me && open(*i))
3122
+ .min_by_key(|(i, l)| (**l, *i))
3123
+ .map(|(i, l)| (i, *l))?;
3124
+ // With the claimed shards left out, the coldest one left may not be cold at all.
3125
+ if low as f64 >= mean {
3126
+ return None;
3127
+ }
3128
+ let gap = my - low;
3129
+ let mut tablets: Vec<(TabletId, u64)> = owned
3130
+ .iter()
3131
+ .map(|t| (t.id, per_tablet.get(&t.id).copied().unwrap_or(0)))
3132
+ .filter(|(_, w)| *w > 0)
3133
+ .collect();
3134
+ tablets.sort_by_key(|(id, w)| (std::cmp::Reverse(*w), *id));
3135
+ // A tablet carrying less than the gap moves: the one closest to half of it.
3136
+ let to = ShardId(cold as u16);
3137
+ let fits = |id: TabletId| {
3138
+ owned.iter().find(|t| t.id == id).is_some_and(|t| {
3139
+ self.slots_fit(view, to, view.catalog.family_ids_of(t.table).len())
3140
+ })
3141
+ };
3142
+ if let Some((t, _)) = tablets
3143
+ .iter()
3144
+ .filter(|(id, w)| *w < gap && *w >= gap / 8 && fits(*id))
3145
+ .min_by_key(|(id, w)| ((gap / 2).abs_diff(*w), *id))
3146
+ {
3147
+ return Some(TabletOpKind::Move { tablet: *t, to });
3148
+ }
3149
+ // No tablet carries an eighth of the gap, and none dominates (the hottest is below the
3150
+ // gap): many small tablets, as a full shard of equal ones (D251). Splitting one would
3151
+ // not help, and needs a slot this shard may not have: the largest that fits moves.
3152
+ if tablets.first().is_some_and(|(_, w)| *w < gap)
3153
+ && let Some((t, _)) = tablets.iter().find(|(id, w)| *w < gap && fits(*id))
3154
+ {
3155
+ return Some(TabletOpKind::Move { tablet: *t, to });
3156
+ }
3157
+ // One tablet dominates: split it over this shard and the coldest shards below the
3158
+ // mean, about `my / mean` children (D214): a shard at 1.3x the mean sheds into one
3159
+ // other shard, one carrying all the load into every shard.
3160
+ let (hot, _) = *tablets.first()?;
3161
+ let entry = owned.iter().find(|t| t.id == hot)?;
3162
+ let mut targets: Vec<(u64, usize)> = loads
3163
+ .iter()
3164
+ .enumerate()
3165
+ .filter(|(i, l)| *i != me && open(*i) && (**l as f64) < mean)
3166
+ .map(|(i, l)| (*l, i))
3167
+ .collect();
3168
+ if targets.is_empty() {
3169
+ // Every shard below the mean is claimed by another skew change (D224).
3170
+ return None;
3171
+ }
3172
+ targets.sort_unstable();
3173
+ let parts = ((my as f64 / mean.max(1.0)).round() as usize).clamp(2, targets.len() + 1);
3174
+ let mut owners = vec![self.id];
3175
+ owners.extend(
3176
+ targets
3177
+ .iter()
3178
+ .take(parts - 1)
3179
+ .map(|(_, i)| ShardId(*i as u16)),
3180
+ );
3181
+ let keys = self.skew_split_keys(entry, owners.len());
3182
+ if keys.is_empty() {
3183
+ return None;
3184
+ }
3185
+ owners.truncate(keys.len() + 1);
3186
+ Some(TabletOpKind::Split {
3187
+ tablet: hot,
3188
+ keys,
3189
+ owners,
3190
+ })
3191
+ }
3192
+
3193
+ /// Up to `parts - 1` split keys from the rows written to `t` this interval (quantiles of
3194
+ /// the sample), strictly inside its range.
3195
+ fn skew_split_keys(&self, t: &TabletEntry, parts: usize) -> Vec<Vec<u8>> {
3196
+ let Some(load) = self.loads.get(&t.id) else {
3197
+ return Vec::new();
3198
+ };
3199
+ let mut rows: Vec<&[u8]> = load
3200
+ .live_samples()
3201
+ .iter()
3202
+ .map(Vec::as_slice)
3203
+ .filter(|r| inside(t, r))
3204
+ .collect();
3205
+ rows.sort_unstable();
3206
+ rows.dedup();
3207
+ quantiles(&rows, parts)
3208
+ }
3209
+
3210
+ /// A split key near the middle of `t`'s SSTs (their boundary rows) and recent writes.
3211
+ fn size_split_key(&self, view: &View, t: &TabletEntry) -> Option<Vec<u8>> {
3212
+ let mut rows: Vec<Vec<u8>> = Vec::new();
3213
+ for f in view.catalog.family_ids_of(t.table) {
3214
+ if let Some(fam) = view.ssts.family(t.id, f) {
3215
+ for sst in fam.iter() {
3216
+ for key in [&sst.meta.smallest_key, &sst.meta.largest_key] {
3217
+ if let Some(r) = row_of_key(key) {
3218
+ rows.push(r);
3219
+ }
3220
+ }
3221
+ }
3222
+ }
3223
+ }
3224
+ if let Some(l) = self.loads.get(&t.id) {
3225
+ rows.extend(l.live_samples().iter().cloned());
3226
+ }
3227
+ let mut rows: Vec<&[u8]> = rows
3228
+ .iter()
3229
+ .map(Vec::as_slice)
3230
+ .filter(|r| inside(t, r))
3231
+ .collect();
3232
+ rows.sort_unstable();
3233
+ rows.dedup();
3234
+ quantiles(&rows, 2).pop()
3235
+ }
3236
+ }
3237
+
3238
+ /// `parts - 1` evenly spaced rows of `rows` (sorted, distinct).
3239
+ fn quantiles(rows: &[&[u8]], parts: usize) -> Vec<Vec<u8>> {
3240
+ let parts = parts.min(rows.len());
3241
+ let mut out: Vec<Vec<u8>> = Vec::new();
3242
+ for i in 1..parts {
3243
+ let r = rows[i * rows.len() / parts];
3244
+ if out.last().is_none_or(|l| l.as_slice() < r) {
3245
+ out.push(r.to_vec());
3246
+ }
3247
+ }
3248
+ out
3249
+ }
3250
+
3251
+ /// Whether `row` lies strictly inside `t` (a split there leaves both sides non-empty).
3252
+ fn inside(t: &TabletEntry, row: &[u8]) -> bool {
3253
+ row > t.start.as_slice() && t.end.as_ref().is_none_or(|e| row < e.as_slice())
3254
+ }
3255
+
3256
+ /// Whether any SST of a slot of `t` holds rows outside `t`.
3257
+ fn sticks_out_of(t: &TabletEntry, levels: &pigeonhole_compaction::Levels) -> bool {
3258
+ compact::tablet_range(t).is_ok_and(|range| {
3259
+ levels
3260
+ .levels
3261
+ .iter()
3262
+ .flatten()
3263
+ .any(|m| compact::sticks_out(m, &range))
3264
+ })
3265
+ }
3266
+
3267
+ /// The unescaped row of an internal key.
3268
+ fn row_of_key(key: &[u8]) -> Option<Vec<u8>> {
3269
+ let n = row_prefix_len(key).ok()?;
3270
+ let mut out = Vec::new();
3271
+ Escaped::new(key.get(..n.checked_sub(2)?)?).unescape_into(&mut out);
3272
+ Some(out)
3273
+ }
3274
+
3275
+ /// Bytes of SSTs `t` references, and whether any of them is shared with another tablet.
3276
+ fn live_bytes(view: &View, t: &TabletEntry, refs: &HashMap<SstId, usize>) -> (u64, bool) {
3277
+ let mut bytes = 0;
3278
+ let mut shared = false;
3279
+ for f in view.catalog.family_ids_of(t.table) {
3280
+ if let Some(fam) = view.ssts.family(t.id, f) {
3281
+ for sst in fam.iter() {
3282
+ bytes += sst.meta.len;
3283
+ shared |= refs.get(&sst.meta.id).copied().unwrap_or(0) > 1;
3284
+ }
3285
+ }
3286
+ }
3287
+ (bytes, shared)
3288
+ }
3289
+
3290
+ /// The rows (hashed with their table) a member writes or reads.
3291
+ fn member_rows(m: &Member) -> Vec<u64> {
3292
+ let mut out = Vec::new();
3293
+ if let Ok(batch) = m.bytes.batch() {
3294
+ for mu in batch.iter().flatten() {
3295
+ out.push(hash_row(mu.table, mu.row));
3296
+ }
3297
+ }
3298
+ if let Some(reads) = m.validate.as_ref().map(|v| &v.reads) {
3299
+ for r in reads {
3300
+ out.push(hash_row(r.table, &r.row));
3301
+ }
3302
+ }
3303
+ if let Some((table, row, _)) = m.predicate.as_deref() {
3304
+ out.push(hash_row(*table, row));
3305
+ }
3306
+ out
3307
+ }
3308
+
3309
+ /// A single-shard member back as the request it came from.
3310
+ fn member_req(m: Member) -> CommitReq {
3311
+ let bytes = match m.bytes {
3312
+ Bytes::Own(b) => b,
3313
+ Bytes::Shared(b) => (*b).clone(),
3314
+ Bytes::Streams(_) => BatchBuilder::new(),
3315
+ };
3316
+ CommitReq {
3317
+ bytes,
3318
+ durability: m.durability,
3319
+ reply: m.reply,
3320
+ submitted_at: m.submitted_at,
3321
+ validate: m.validate,
3322
+ predicate: m.predicate,
3323
+ retry: m.retry,
3324
+ map_version: m.map_version,
3325
+ }
3326
+ }
3327
+
3328
+ /// The shards a commit's rows (written and read, and its predicate row) route to through
3329
+ /// `view`, in first-appearance order.
3330
+ pub(crate) fn commit_shards(
3331
+ view: &View,
3332
+ bytes: &[u8],
3333
+ reads: Option<&[crate::write::ReadKey]>,
3334
+ predicate: Option<(TableId, &[u8])>,
3335
+ ) -> Result<Vec<ShardId>> {
3336
+ let mut out: Vec<ShardId> = Vec::new();
3337
+ let mut add = |s: ShardId| {
3338
+ if !out.contains(&s) {
3339
+ out.push(s);
3340
+ }
3341
+ };
3342
+ let mut wrote = false;
3343
+ for mu in BatchRef::new(bytes)?.iter() {
3344
+ let mu = mu?;
3345
+ if let Some((_, s)) = view.tablets.route(mu.table, mu.row) {
3346
+ wrote = true;
3347
+ add(s);
3348
+ }
3349
+ }
3350
+ if !wrote
3351
+ && let Some((table, row)) = predicate
3352
+ && let Some((_, s)) = view.tablets.route(table, row)
3353
+ {
3354
+ add(s);
3355
+ }
3356
+ for r in reads.unwrap_or_default() {
3357
+ if let Some((_, s)) = view.tablets.route(r.table, &r.row) {
3358
+ add(s);
3359
+ }
3360
+ }
3361
+ Ok(out)
3362
+ }
3363
+
3364
+ /// Splits a batch into one builder per shard, in `shards` order.
3365
+ pub(crate) fn split_by_shard(
3366
+ view: &View,
3367
+ builder: &BatchBuilder,
3368
+ shards: &[ShardId],
3369
+ ) -> Result<Vec<(ShardId, Arc<BatchBuilder>)>> {
3370
+ let mut parts: Vec<(ShardId, BatchBuilder)> =
3371
+ shards.iter().map(|s| (*s, BatchBuilder::new())).collect();
3372
+ for m in builder.batch().iter() {
3373
+ let m = m?;
3374
+ let Some((_, shard)) = view.tablets.route(m.table, m.row) else {
3375
+ return Err(Error::TableNotFound(format!("table {}", m.table.0)));
3376
+ };
3377
+ let Some(part) = parts.iter_mut().find(|(s, _)| *s == shard) else {
3378
+ return Err(Error::Corruption(
3379
+ "a row routed to an unlisted shard".to_owned(),
3380
+ ));
3381
+ };
3382
+ part.1
3383
+ .push(m.table, m.family, m.kind, m.row, m.qualifier, m.ts, m.value)?;
3384
+ }
3385
+ Ok(parts.into_iter().map(|(s, b)| (s, Arc::new(b))).collect())
3386
+ }
3387
+
3388
+ /// The row-prefix bounds of `[start, end)`.
3389
+ fn prefix_bounds(start: &[u8], end: Option<&[u8]>) -> Result<(Vec<u8>, Option<Vec<u8>>)> {
3390
+ let mut s = Vec::new();
3391
+ if !start.is_empty() {
3392
+ encode_row_prefix(&mut s, start)?;
3393
+ }
3394
+ let e = match end {
3395
+ Some(e) => {
3396
+ let mut k = Vec::new();
3397
+ encode_row_prefix(&mut k, e)?;
3398
+ Some(k)
3399
+ }
3400
+ None => None,
3401
+ };
3402
+ Ok((s, e))
3403
+ }
3404
+
3405
+ /// Whether an SST holds rows within the row-prefix range `[start, end)`.
3406
+ fn overlaps(meta: &SstMeta, start: &[u8], end: Option<&[u8]>) -> bool {
3407
+ let first = crate::snapshot::row_of(&meta.smallest_key);
3408
+ let last = crate::snapshot::row_of(&meta.largest_key);
3409
+ last >= start && end.is_none_or(|e| first < e)
3410
+ }
3411
+
3412
+ /// The SSTs of a merge of `l` and `r`, per family as `(level, meta)`, each once.
3413
+ ///
3414
+ /// Refused while a sibling still has to compact its copy of an SST they shared after a split
3415
+ /// (D13): an SST only one side references must hold none of the other side's rows (the other
3416
+ /// side rewrote them; the merged tablet would see them twice), and no level of the result may
3417
+ /// hold overlapping SSTs.
3418
+ fn merged_ssts(
3419
+ catalog: &Catalog,
3420
+ l: &TabletEntry,
3421
+ r: &TabletEntry,
3422
+ ) -> Result<Vec<(FamilyId, u8, Arc<SstMeta>)>> {
3423
+ let (ls, le) = prefix_bounds(&l.start, l.end.as_deref())?;
3424
+ let (rs, re) = prefix_bounds(&r.start, r.end.as_deref())?;
3425
+ let pending = || {
3426
+ Error::InvalidArgument(
3427
+ "a sibling has not compacted a shared SST yet; merge after compaction".to_owned(),
3428
+ )
3429
+ };
3430
+ let mut out = Vec::new();
3431
+ for f in catalog.family_ids_of(l.table) {
3432
+ let ids = |t: &TabletEntry| -> HashSet<SstId> {
3433
+ catalog
3434
+ .ssts
3435
+ .get(&(t.id, f))
3436
+ .map(|list| list.iter().map(|(_, m)| m.id).collect())
3437
+ .unwrap_or_default()
3438
+ };
3439
+ let (lids, rids) = (ids(l), ids(r));
3440
+ let mut seen: HashSet<SstId> = HashSet::new();
3441
+ let mut levels: BTreeMap<u8, Vec<Arc<SstMeta>>> = BTreeMap::new();
3442
+ for t in [l, r] {
3443
+ if let Some(list) = catalog.ssts.get(&(t.id, f)) {
3444
+ for (level, meta) in list.iter() {
3445
+ let only_left = lids.contains(&meta.id) && !rids.contains(&meta.id);
3446
+ let only_right = rids.contains(&meta.id) && !lids.contains(&meta.id);
3447
+ if (only_left && overlaps(meta, &rs, re.as_deref()))
3448
+ || (only_right && overlaps(meta, &ls, le.as_deref()))
3449
+ {
3450
+ return Err(pending());
3451
+ }
3452
+ if seen.insert(meta.id) {
3453
+ levels.entry(*level).or_default().push(Arc::clone(meta));
3454
+ out.push((f, *level, Arc::clone(meta)));
3455
+ }
3456
+ }
3457
+ }
3458
+ }
3459
+ for (level, list) in &mut levels {
3460
+ if *level == 0 {
3461
+ continue;
3462
+ }
3463
+ list.sort_by(|a, b| a.smallest_key.cmp(&b.smallest_key));
3464
+ if list
3465
+ .windows(2)
3466
+ .any(|w| w[0].largest_key >= w[1].smallest_key)
3467
+ {
3468
+ return Err(Error::InvalidArgument(
3469
+ "the tablets' SSTs overlap within a level; merge after compaction".to_owned(),
3470
+ ));
3471
+ }
3472
+ }
3473
+ }
3474
+ Ok(out)
3475
+ }
3476
+
3477
+ /// The manifest edits and owners of a tablet change, against the catalog at commit time.
3478
+ fn tablet_change(
3479
+ catalog: &mut Catalog,
3480
+ kind: &TabletOpKind,
3481
+ entries: &[TabletEntry],
3482
+ me: ShardId,
3483
+ ) -> Result<TabletEdits> {
3484
+ for e in entries {
3485
+ match catalog.tablet(e.id) {
3486
+ Some(t) if t.table == e.table && t.start == e.start && t.end == e.end => {}
3487
+ _ => {
3488
+ return Err(Error::TableNotFound(format!(
3489
+ "tablet {} changed during the split, merge or move",
3490
+ e.id.0
3491
+ )));
3492
+ }
3493
+ }
3494
+ }
3495
+ let table = entries[0].table;
3496
+ let families = catalog.family_ids_of(table);
3497
+ match kind {
3498
+ TabletOpKind::Move { tablet, to } => Ok((Vec::new(), vec![(*tablet, *to)])),
3499
+ TabletOpKind::Split {
3500
+ tablet,
3501
+ keys,
3502
+ owners,
3503
+ } => {
3504
+ let parent = &entries[0];
3505
+ let mut starts: Vec<Vec<u8>> = vec![parent.start.clone()];
3506
+ starts.extend(keys.iter().cloned());
3507
+ let mut ends: Vec<Option<Vec<u8>>> = keys.iter().cloned().map(Some).collect();
3508
+ ends.push(parent.end.clone());
3509
+ let mut edits = Vec::new();
3510
+ let mut out = Vec::new();
3511
+ for (i, (start, end)) in starts.into_iter().zip(ends).enumerate() {
3512
+ let id = catalog.alloc_tablet();
3513
+ let (s, e) = prefix_bounds(&start, end.as_deref())?;
3514
+ edits.push(Edit::PutTablet {
3515
+ tablet: id,
3516
+ table,
3517
+ start,
3518
+ end,
3519
+ });
3520
+ out.push((id, owners[i]));
3521
+ for &f in &families {
3522
+ if let Some(list) = catalog.ssts.get(&(parent.id, f)) {
3523
+ for (level, meta) in list.iter() {
3524
+ if overlaps(meta, &s, e.as_deref()) {
3525
+ edits.push(Edit::AddSst {
3526
+ tablet: id,
3527
+ family: f,
3528
+ level: *level,
3529
+ meta: (**meta).clone(),
3530
+ });
3531
+ }
3532
+ }
3533
+ }
3534
+ if let Some(seqno) = catalog.flushed.get(&(parent.id, f)) {
3535
+ edits.push(Edit::SetFlushed {
3536
+ tablet: id,
3537
+ family: f,
3538
+ seqno: *seqno,
3539
+ });
3540
+ }
3541
+ }
3542
+ }
3543
+ edits.push(Edit::DropTablet { tablet: *tablet });
3544
+ Ok((edits, out))
3545
+ }
3546
+ TabletOpKind::Merge { left, right } => {
3547
+ let (l, r) = (&entries[0], &entries[1]);
3548
+ let ssts = merged_ssts(catalog, l, r)?;
3549
+ let id = catalog.alloc_tablet();
3550
+ let mut edits = vec![Edit::PutTablet {
3551
+ tablet: id,
3552
+ table,
3553
+ start: l.start.clone(),
3554
+ end: r.end.clone(),
3555
+ }];
3556
+ for (f, level, meta) in ssts {
3557
+ edits.push(Edit::AddSst {
3558
+ tablet: id,
3559
+ family: f,
3560
+ level,
3561
+ meta: (*meta).clone(),
3562
+ });
3563
+ }
3564
+ for &f in &families {
3565
+ let seqno = [left, right]
3566
+ .iter()
3567
+ .filter_map(|t| catalog.flushed.get(&(**t, f)).copied())
3568
+ .max();
3569
+ if let Some(seqno) = seqno {
3570
+ edits.push(Edit::SetFlushed {
3571
+ tablet: id,
3572
+ family: f,
3573
+ seqno,
3574
+ });
3575
+ }
3576
+ }
3577
+ edits.push(Edit::DropTablet { tablet: *left });
3578
+ edits.push(Edit::DropTablet { tablet: *right });
3579
+ Ok((edits, vec![(id, me)]))
3580
+ }
3581
+ }
3582
+ }