rubydb 0.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 (436) hide show
  1. checksums.yaml +7 -0
  2. data/.gitattributes +20 -0
  3. data/.github/ISSUE_TEMPLATE/bug.yml +0 -0
  4. data/.github/ISSUE_TEMPLATE/feature.yml +0 -0
  5. data/.github/ISSUE_TEMPLATE/performance.yml +0 -0
  6. data/.github/ISSUE_TEMPLATE/security.yml +0 -0
  7. data/.github/PULL_REQUEST_TEMPLATE.md +15 -0
  8. data/.github/dependabot.yml +0 -0
  9. data/.github/workflows/benchmark.yml +26 -0
  10. data/.github/workflows/compatibility.yml +63 -0
  11. data/.github/workflows/fuzz.yml +33 -0
  12. data/.github/workflows/lint.yml +21 -0
  13. data/.github/workflows/operations.yml +24 -0
  14. data/.github/workflows/production-validation.yml +111 -0
  15. data/.github/workflows/release.yml +77 -0
  16. data/.github/workflows/security.yml +37 -0
  17. data/.github/workflows/test.yml +26 -0
  18. data/.github/workflows/workload.yml +58 -0
  19. data/.gitignore +43 -0
  20. data/.rspec +4 -0
  21. data/.rubocop.yml +44 -0
  22. data/.ruby-version +1 -0
  23. data/.standard.yml +14 -0
  24. data/ARCHITECTURE.md +21 -0
  25. data/CHANGELOG.md +31 -0
  26. data/CODE_OF_CONDUCT.md +13 -0
  27. data/CONTRIBUTING.md +29 -0
  28. data/GOVERNANCE.md +16 -0
  29. data/Gemfile +17 -0
  30. data/Gemfile.lock +71 -0
  31. data/LICENSE +60 -0
  32. data/README.md +162 -0
  33. data/ROADMAP.md +27 -0
  34. data/Rakefile +71 -0
  35. data/SECURITY.md +54 -0
  36. data/SUPPORT.md +14 -0
  37. data/adapters/activerecord/Gemfile +11 -0
  38. data/adapters/activerecord/README.md +9 -0
  39. data/adapters/activerecord/lib/active_record/connection_adapters/rubydb_adapter.rb +887 -0
  40. data/adapters/activerecord/rubydb-activerecord.gemspec +27 -0
  41. data/adapters/activerecord/spec/rubydb_adapter_integration_spec.rb +151 -0
  42. data/adapters/ruby/README.md +18 -0
  43. data/adapters/sequel/README.md +11 -0
  44. data/bin/rubydb +19 -0
  45. data/bin/rubydb-server +126 -0
  46. data/config/development.yml +0 -0
  47. data/config/monitoring/prometheus-alerts.yml +39 -0
  48. data/config/production.yml +36 -0
  49. data/config/test.yml +0 -0
  50. data/docs/README.md +71 -0
  51. data/docs/architecture/concurrency.md +14 -0
  52. data/docs/architecture/current-state.md +125 -0
  53. data/docs/architecture/execution-engine.md +25 -0
  54. data/docs/architecture/indexes.md +19 -0
  55. data/docs/architecture/mvcc.md +19 -0
  56. data/docs/architecture/overview.md +13 -0
  57. data/docs/architecture/pages.md +11 -0
  58. data/docs/architecture/production-roadmap.md +82 -0
  59. data/docs/architecture/query-planner.md +20 -0
  60. data/docs/architecture/recovery.md +18 -0
  61. data/docs/architecture/sql-engine.md +12 -0
  62. data/docs/architecture/storage-engine.md +14 -0
  63. data/docs/architecture/transactions.md +10 -0
  64. data/docs/architecture/wal.md +28 -0
  65. data/docs/cli-cheatsheet.md +98 -0
  66. data/docs/cli.md +275 -0
  67. data/docs/contributing/architecture.md +9 -0
  68. data/docs/contributing/benchmarking.md +14 -0
  69. data/docs/contributing/development.md +16 -0
  70. data/docs/contributing/release-process.md +49 -0
  71. data/docs/contributing/testing.md +16 -0
  72. data/docs/debugging.md +229 -0
  73. data/docs/developer/branching.md +10 -0
  74. data/docs/developer/database-diff.md +10 -0
  75. data/docs/developer/local-development.md +17 -0
  76. data/docs/developer/snapshots.md +9 -0
  77. data/docs/developer/temporal-data.md +10 -0
  78. data/docs/developer-guide.md +297 -0
  79. data/docs/getting-started/first-database.md +16 -0
  80. data/docs/getting-started/first-query.md +13 -0
  81. data/docs/getting-started/installation.md +19 -0
  82. data/docs/getting-started/local-to-production.md +300 -0
  83. data/docs/getting-started/quickstart.md +17 -0
  84. data/docs/getting-started/rails.md +16 -0
  85. data/docs/hardening_backlog.md +93 -0
  86. data/docs/lessons-learned.md +112 -0
  87. data/docs/operations/backups.md +33 -0
  88. data/docs/operations/disaster-recovery.md +31 -0
  89. data/docs/operations/failover.md +30 -0
  90. data/docs/operations/monitoring.md +25 -0
  91. data/docs/operations/production-guide.md +295 -0
  92. data/docs/operations/production-runbook.md +45 -0
  93. data/docs/operations/replication.md +33 -0
  94. data/docs/operations/restore.md +6 -0
  95. data/docs/operations/runbook.md +34 -0
  96. data/docs/operations/upgrades.md +14 -0
  97. data/docs/operations/workload-testing.md +17 -0
  98. data/docs/production-readiness.md +118 -0
  99. data/docs/production_validation.md +150 -0
  100. data/docs/rails/active-record.md +11 -0
  101. data/docs/rails/compatibility-guide.md +90 -0
  102. data/docs/rails/database-yml.md +92 -0
  103. data/docs/rails/installation.md +17 -0
  104. data/docs/rails/migrations.md +17 -0
  105. data/docs/rails/production.md +82 -0
  106. data/docs/rails/troubleshooting.md +18 -0
  107. data/docs/release.md +59 -0
  108. data/docs/server/architecture.md +10 -0
  109. data/docs/server/authentication.md +10 -0
  110. data/docs/server/configuration.md +16 -0
  111. data/docs/server/connection-pooling.md +10 -0
  112. data/docs/server/deployment.md +10 -0
  113. data/docs/server/protocol.md +12 -0
  114. data/docs/sql/compatibility-guide.md +82 -0
  115. data/docs/sql/compatibility.md +39 -0
  116. data/docs/sql/data-types.md +10 -0
  117. data/docs/sql/functions.md +9 -0
  118. data/docs/sql/joins.md +9 -0
  119. data/docs/sql/operators.md +9 -0
  120. data/docs/sql/sqlite-compatibility.md +21 -0
  121. data/docs/sql/syntax.md +10 -0
  122. data/docs/sql/transactions.md +10 -0
  123. data/docs/troubleshooting.md +244 -0
  124. data/exe/rubydb +23 -0
  125. data/lib/rubydb/backup/archive.rb +334 -0
  126. data/lib/rubydb/backup/backup.rb +401 -0
  127. data/lib/rubydb/backup/incremental.rb +353 -0
  128. data/lib/rubydb/backup/restore.rb +290 -0
  129. data/lib/rubydb/backup/snapshot.rb +267 -0
  130. data/lib/rubydb/backup/verification.rb +279 -0
  131. data/lib/rubydb/branching/branch.rb +181 -0
  132. data/lib/rubydb/branching/branch_manager.rb +311 -0
  133. data/lib/rubydb/branching/branch_metadata.rb +140 -0
  134. data/lib/rubydb/branching/checkout.rb +166 -0
  135. data/lib/rubydb/branching/copy_on_write.rb +272 -0
  136. data/lib/rubydb/branching/diff.rb +138 -0
  137. data/lib/rubydb/branching/merge.rb +285 -0
  138. data/lib/rubydb/build_info.rb +15 -0
  139. data/lib/rubydb/catalog/catalog.rb +391 -0
  140. data/lib/rubydb/catalog/column.rb +112 -0
  141. data/lib/rubydb/catalog/constraint.rb +180 -0
  142. data/lib/rubydb/catalog/database.rb +184 -0
  143. data/lib/rubydb/catalog/index.rb +97 -0
  144. data/lib/rubydb/catalog/schema.rb +103 -0
  145. data/lib/rubydb/catalog/sequence.rb +90 -0
  146. data/lib/rubydb/catalog/system_catalog.rb +698 -0
  147. data/lib/rubydb/catalog/table.rb +178 -0
  148. data/lib/rubydb/catalog/trigger.rb +102 -0
  149. data/lib/rubydb/catalog/view.rb +66 -0
  150. data/lib/rubydb/cli/application.rb +163 -0
  151. data/lib/rubydb/cli/commands/backup.rb +81 -0
  152. data/lib/rubydb/cli/commands/branch.rb +72 -0
  153. data/lib/rubydb/cli/commands/checkout.rb +54 -0
  154. data/lib/rubydb/cli/commands/create.rb +58 -0
  155. data/lib/rubydb/cli/commands/diff.rb +77 -0
  156. data/lib/rubydb/cli/commands/doctor.rb +74 -0
  157. data/lib/rubydb/cli/commands/drop.rb +57 -0
  158. data/lib/rubydb/cli/commands/init.rb +102 -0
  159. data/lib/rubydb/cli/commands/inspect.rb +95 -0
  160. data/lib/rubydb/cli/commands/merge.rb +63 -0
  161. data/lib/rubydb/cli/commands/migrate.rb +62 -0
  162. data/lib/rubydb/cli/commands/restart.rb +39 -0
  163. data/lib/rubydb/cli/commands/restore.rb +121 -0
  164. data/lib/rubydb/cli/commands/shell.rb +365 -0
  165. data/lib/rubydb/cli/commands/snapshot.rb +79 -0
  166. data/lib/rubydb/cli/commands/start.rb +82 -0
  167. data/lib/rubydb/cli/commands/status.rb +92 -0
  168. data/lib/rubydb/cli/commands/stop.rb +47 -0
  169. data/lib/rubydb/cli/commands/vacuum.rb +58 -0
  170. data/lib/rubydb/cli/formatter.rb +221 -0
  171. data/lib/rubydb/cli/output.rb +168 -0
  172. data/lib/rubydb/client/client.rb +304 -0
  173. data/lib/rubydb/client/connection.rb +415 -0
  174. data/lib/rubydb/client/connection_pool.rb +168 -0
  175. data/lib/rubydb/client/connection_url.rb +96 -0
  176. data/lib/rubydb/client/prepared_statement.rb +60 -0
  177. data/lib/rubydb/client/result.rb +123 -0
  178. data/lib/rubydb/client/statement.rb +52 -0
  179. data/lib/rubydb/client/transaction.rb +130 -0
  180. data/lib/rubydb/concurrency/concurrency.rb +19 -0
  181. data/lib/rubydb/concurrency/deadlock_detector.rb +150 -0
  182. data/lib/rubydb/concurrency/latch.rb +101 -0
  183. data/lib/rubydb/concurrency/lock_graph.rb +165 -0
  184. data/lib/rubydb/concurrency/mutex.rb +183 -0
  185. data/lib/rubydb/concurrency/rw_lock.rb +180 -0
  186. data/lib/rubydb/concurrency/scheduler.rb +250 -0
  187. data/lib/rubydb/concurrency/worker_pool.rb +143 -0
  188. data/lib/rubydb/configuration/config.rb +170 -0
  189. data/lib/rubydb/configuration/defaults.rb +179 -0
  190. data/lib/rubydb/configuration/environment.rb +152 -0
  191. data/lib/rubydb/configuration/parser.rb +185 -0
  192. data/lib/rubydb/configuration/validation.rb +221 -0
  193. data/lib/rubydb/constants.rb +74 -0
  194. data/lib/rubydb/constraints/check.rb +181 -0
  195. data/lib/rubydb/constraints/constraint.rb +101 -0
  196. data/lib/rubydb/constraints/foreign_key.rb +130 -0
  197. data/lib/rubydb/constraints/not_null.rb +64 -0
  198. data/lib/rubydb/constraints/primary_key.rb +99 -0
  199. data/lib/rubydb/constraints/unique.rb +108 -0
  200. data/lib/rubydb/constraints/validator.rb +350 -0
  201. data/lib/rubydb/errors/authentication_error.rb +10 -0
  202. data/lib/rubydb/errors/authorization_error.rb +23 -0
  203. data/lib/rubydb/errors/client_error.rb +10 -0
  204. data/lib/rubydb/errors/configuration_error.rb +10 -0
  205. data/lib/rubydb/errors/connection_error.rb +10 -0
  206. data/lib/rubydb/errors/constraint_error.rb +23 -0
  207. data/lib/rubydb/errors/corruption_error.rb +10 -0
  208. data/lib/rubydb/errors/database_error.rb +10 -0
  209. data/lib/rubydb/errors/error.rb +20 -0
  210. data/lib/rubydb/errors/execution_error.rb +10 -0
  211. data/lib/rubydb/errors/parser_error.rb +10 -0
  212. data/lib/rubydb/errors/recovery_error.rb +10 -0
  213. data/lib/rubydb/errors/replication_error.rb +10 -0
  214. data/lib/rubydb/errors/server_error.rb +6 -0
  215. data/lib/rubydb/errors/storage_error.rb +10 -0
  216. data/lib/rubydb/errors/transaction_error.rb +10 -0
  217. data/lib/rubydb/execution/aggregate_executor.rb +138 -0
  218. data/lib/rubydb/execution/delete_executor.rb +112 -0
  219. data/lib/rubydb/execution/distinct_executor.rb +135 -0
  220. data/lib/rubydb/execution/executor.rb +1192 -0
  221. data/lib/rubydb/execution/expression.rb +193 -0
  222. data/lib/rubydb/execution/index_scan.rb +142 -0
  223. data/lib/rubydb/execution/insert_executor.rb +217 -0
  224. data/lib/rubydb/execution/join_executor.rb +249 -0
  225. data/lib/rubydb/execution/limit_executor.rb +85 -0
  226. data/lib/rubydb/execution/optimizer.rb +215 -0
  227. data/lib/rubydb/execution/plan.rb +361 -0
  228. data/lib/rubydb/execution/planner.rb +546 -0
  229. data/lib/rubydb/execution/predicate.rb +235 -0
  230. data/lib/rubydb/execution/scan.rb +49 -0
  231. data/lib/rubydb/execution/sequential_scan.rb +63 -0
  232. data/lib/rubydb/execution/sort_executor.rb +185 -0
  233. data/lib/rubydb/execution/update_executor.rb +162 -0
  234. data/lib/rubydb/functions/aggregate.rb +70 -0
  235. data/lib/rubydb/functions/date_functions.rb +278 -0
  236. data/lib/rubydb/functions/function.rb +85 -0
  237. data/lib/rubydb/functions/json_functions.rb +215 -0
  238. data/lib/rubydb/functions/numeric_functions.rb +346 -0
  239. data/lib/rubydb/functions/scalar.rb +52 -0
  240. data/lib/rubydb/functions/string_functions.rb +383 -0
  241. data/lib/rubydb/functions/system_functions.rb +246 -0
  242. data/lib/rubydb/history/as_of.rb +238 -0
  243. data/lib/rubydb/history/change.rb +105 -0
  244. data/lib/rubydb/history/history.rb +131 -0
  245. data/lib/rubydb/history/history_manager.rb +229 -0
  246. data/lib/rubydb/history/temporal_query.rb +202 -0
  247. data/lib/rubydb/history/timeline.rb +144 -0
  248. data/lib/rubydb/indexes/btree.rb +186 -0
  249. data/lib/rubydb/indexes/btree_cursor.rb +258 -0
  250. data/lib/rubydb/indexes/btree_node.rb +385 -0
  251. data/lib/rubydb/indexes/hash_index.rb +150 -0
  252. data/lib/rubydb/indexes/index.rb +71 -0
  253. data/lib/rubydb/indexes/index_manager.rb +406 -0
  254. data/lib/rubydb/indexes/index_scan.rb +470 -0
  255. data/lib/rubydb/migrations/migration.rb +254 -0
  256. data/lib/rubydb/migrations/migration_lock.rb +146 -0
  257. data/lib/rubydb/migrations/migration_manager.rb +176 -0
  258. data/lib/rubydb/migrations/migration_version.rb +71 -0
  259. data/lib/rubydb/migrations/schema_diff.rb +211 -0
  260. data/lib/rubydb/migrations/schema_version.rb +64 -0
  261. data/lib/rubydb/monitoring/events.rb +160 -0
  262. data/lib/rubydb/monitoring/health.rb +222 -0
  263. data/lib/rubydb/monitoring/logger.rb +193 -0
  264. data/lib/rubydb/monitoring/metrics.rb +359 -0
  265. data/lib/rubydb/monitoring/performance.rb +176 -0
  266. data/lib/rubydb/monitoring/statistics.rb +170 -0
  267. data/lib/rubydb/mvcc/garbage_collector.rb +199 -0
  268. data/lib/rubydb/mvcc/mvcc.rb +16 -0
  269. data/lib/rubydb/mvcc/snapshot.rb +147 -0
  270. data/lib/rubydb/mvcc/vacuum.rb +180 -0
  271. data/lib/rubydb/mvcc/version.rb +106 -0
  272. data/lib/rubydb/mvcc/version_store.rb +398 -0
  273. data/lib/rubydb/mvcc/visibility.rb +109 -0
  274. data/lib/rubydb/protocol/capabilities.rb +125 -0
  275. data/lib/rubydb/protocol/decoder.rb +145 -0
  276. data/lib/rubydb/protocol/encoder.rb +136 -0
  277. data/lib/rubydb/protocol/handshake.rb +305 -0
  278. data/lib/rubydb/protocol/message.rb +121 -0
  279. data/lib/rubydb/protocol/protocol.rb +277 -0
  280. data/lib/rubydb/protocol/version.rb +54 -0
  281. data/lib/rubydb/rails/adapter.rb +239 -0
  282. data/lib/rubydb/rails/connection.rb +314 -0
  283. data/lib/rubydb/rails/database_statements.rb +122 -0
  284. data/lib/rubydb/rails/migration.rb +131 -0
  285. data/lib/rubydb/rails/quoting.rb +109 -0
  286. data/lib/rubydb/rails/result.rb +120 -0
  287. data/lib/rubydb/rails/schema_statements.rb +339 -0
  288. data/lib/rubydb/rails/transaction.rb +105 -0
  289. data/lib/rubydb/rails/type.rb +126 -0
  290. data/lib/rubydb/recovery/checkpoint.rb +257 -0
  291. data/lib/rubydb/recovery/consistency.rb +467 -0
  292. data/lib/rubydb/recovery/corruption_detector.rb +5 -0
  293. data/lib/rubydb/recovery/crash_recovery.rb +387 -0
  294. data/lib/rubydb/recovery/recovery_manager.rb +206 -0
  295. data/lib/rubydb/recovery/redo.rb +237 -0
  296. data/lib/rubydb/recovery/undo.rb +206 -0
  297. data/lib/rubydb/replication/failover.rb +5 -0
  298. data/lib/rubydb/replication/fencing.rb +63 -0
  299. data/lib/rubydb/replication/primary.rb +450 -0
  300. data/lib/rubydb/replication/replica.rb +384 -0
  301. data/lib/rubydb/replication/replication_log.rb +200 -0
  302. data/lib/rubydb/replication/replication_manager.rb +308 -0
  303. data/lib/rubydb/replication/replication_slot.rb +295 -0
  304. data/lib/rubydb/replication/replication_stream.rb +201 -0
  305. data/lib/rubydb/rubydb.rb +560 -0
  306. data/lib/rubydb/security/access_control.rb +254 -0
  307. data/lib/rubydb/security/audit_log.rb +213 -0
  308. data/lib/rubydb/security/authentication.rb +302 -0
  309. data/lib/rubydb/security/authorization.rb +282 -0
  310. data/lib/rubydb/security/credentials.rb +196 -0
  311. data/lib/rubydb/security/password.rb +215 -0
  312. data/lib/rubydb/security/permissions.rb +74 -0
  313. data/lib/rubydb/security/role.rb +101 -0
  314. data/lib/rubydb/security/user.rb +86 -0
  315. data/lib/rubydb/server/connection.rb +366 -0
  316. data/lib/rubydb/server/connection_pool.rb +193 -0
  317. data/lib/rubydb/server/lifecycle.rb +228 -0
  318. data/lib/rubydb/server/listener.rb +136 -0
  319. data/lib/rubydb/server/request_handler.rb +276 -0
  320. data/lib/rubydb/server/server.rb +364 -0
  321. data/lib/rubydb/server/session.rb +369 -0
  322. data/lib/rubydb/server/worker.rb +210 -0
  323. data/lib/rubydb/server/worker_pool.rb +168 -0
  324. data/lib/rubydb/sql/ast/alter_table.rb +169 -0
  325. data/lib/rubydb/sql/ast/begin_transaction.rb +47 -0
  326. data/lib/rubydb/sql/ast/commit.rb +37 -0
  327. data/lib/rubydb/sql/ast/constraint.rb +83 -0
  328. data/lib/rubydb/sql/ast/create_database.rb +41 -0
  329. data/lib/rubydb/sql/ast/create_index.rb +61 -0
  330. data/lib/rubydb/sql/ast/create_schema.rb +52 -0
  331. data/lib/rubydb/sql/ast/create_table.rb +187 -0
  332. data/lib/rubydb/sql/ast/delete.rb +54 -0
  333. data/lib/rubydb/sql/ast/drop_database.rb +41 -0
  334. data/lib/rubydb/sql/ast/drop_index.rb +41 -0
  335. data/lib/rubydb/sql/ast/drop_schema.rb +49 -0
  336. data/lib/rubydb/sql/ast/drop_table.rb +49 -0
  337. data/lib/rubydb/sql/ast/explain.rb +64 -0
  338. data/lib/rubydb/sql/ast/expression.rb +604 -0
  339. data/lib/rubydb/sql/ast/insert.rb +82 -0
  340. data/lib/rubydb/sql/ast/node.rb +42 -0
  341. data/lib/rubydb/sql/ast/rollback.rb +63 -0
  342. data/lib/rubydb/sql/ast/savepoint.rb +59 -0
  343. data/lib/rubydb/sql/ast/select.rb +88 -0
  344. data/lib/rubydb/sql/ast/set_operation.rb +20 -0
  345. data/lib/rubydb/sql/ast/trigger.rb +29 -0
  346. data/lib/rubydb/sql/ast/update.rb +88 -0
  347. data/lib/rubydb/sql/ast/vacuum.rb +19 -0
  348. data/lib/rubydb/sql/ast/view.rb +32 -0
  349. data/lib/rubydb/sql/ast/with.rb +32 -0
  350. data/lib/rubydb/sql/grammar.rb +86 -0
  351. data/lib/rubydb/sql/keywords.rb +156 -0
  352. data/lib/rubydb/sql/lexer.rb +214 -0
  353. data/lib/rubydb/sql/operators.rb +100 -0
  354. data/lib/rubydb/sql/parser.rb +1185 -0
  355. data/lib/rubydb/sql/planner/analyzer.rb +302 -0
  356. data/lib/rubydb/sql/planner/binder.rb +550 -0
  357. data/lib/rubydb/sql/planner/type_checker.rb +431 -0
  358. data/lib/rubydb/sql/token.rb +210 -0
  359. data/lib/rubydb/storage/buffer_frame.rb +44 -0
  360. data/lib/rubydb/storage/buffer_pool.rb +155 -0
  361. data/lib/rubydb/storage/database_lock.rb +74 -0
  362. data/lib/rubydb/storage/deserializer.rb +342 -0
  363. data/lib/rubydb/storage/engine.rb +2338 -0
  364. data/lib/rubydb/storage/file_manager.rb +187 -0
  365. data/lib/rubydb/storage/free_space_map.rb +81 -0
  366. data/lib/rubydb/storage/page.rb +94 -0
  367. data/lib/rubydb/storage/page_allocator.rb +855 -0
  368. data/lib/rubydb/storage/page_header.rb +67 -0
  369. data/lib/rubydb/storage/page_manager.rb +131 -0
  370. data/lib/rubydb/storage/record.rb +58 -0
  371. data/lib/rubydb/storage/row.rb +78 -0
  372. data/lib/rubydb/storage/serializer.rb +51 -0
  373. data/lib/rubydb/storage/storage_layout.rb +151 -0
  374. data/lib/rubydb/storage/storage_manager.rb +114 -0
  375. data/lib/rubydb/storage/tuple.rb +461 -0
  376. data/lib/rubydb/storage/visibility_map.rb +984 -0
  377. data/lib/rubydb/transactions/commit_manager.rb +220 -0
  378. data/lib/rubydb/transactions/isolation.rb +98 -0
  379. data/lib/rubydb/transactions/lock.rb +76 -0
  380. data/lib/rubydb/transactions/lock_manager.rb +362 -0
  381. data/lib/rubydb/transactions/savepoint.rb +143 -0
  382. data/lib/rubydb/transactions/transaction.rb +215 -0
  383. data/lib/rubydb/transactions/transaction_id.rb +84 -0
  384. data/lib/rubydb/transactions/transaction_log.rb +257 -0
  385. data/lib/rubydb/transactions/transaction_manager.rb +435 -0
  386. data/lib/rubydb/types/bigint.rb +36 -0
  387. data/lib/rubydb/types/blob.rb +37 -0
  388. data/lib/rubydb/types/boolean.rb +34 -0
  389. data/lib/rubydb/types/date.rb +39 -0
  390. data/lib/rubydb/types/decimal.rb +48 -0
  391. data/lib/rubydb/types/float.rb +34 -0
  392. data/lib/rubydb/types/integer.rb +36 -0
  393. data/lib/rubydb/types/json.rb +41 -0
  394. data/lib/rubydb/types/null.rb +34 -0
  395. data/lib/rubydb/types/smallint.rb +36 -0
  396. data/lib/rubydb/types/text.rb +37 -0
  397. data/lib/rubydb/types/time.rb +46 -0
  398. data/lib/rubydb/types/timestamp.rb +39 -0
  399. data/lib/rubydb/types/type.rb +119 -0
  400. data/lib/rubydb/types/uuid.rb +47 -0
  401. data/lib/rubydb/types/varchar.rb +37 -0
  402. data/lib/rubydb/version.rb +33 -0
  403. data/lib/rubydb/wal/archive.rb +193 -0
  404. data/lib/rubydb/wal/checkpoint.rb +183 -0
  405. data/lib/rubydb/wal/lsn.rb +94 -0
  406. data/lib/rubydb/wal/reader.rb +260 -0
  407. data/lib/rubydb/wal/record.rb +105 -0
  408. data/lib/rubydb/wal/segment.rb +193 -0
  409. data/lib/rubydb/wal/wal.rb +452 -0
  410. data/lib/rubydb/wal/writer.rb +236 -0
  411. data/lib/rubydb.rb +7 -0
  412. data/packaging/docker/Dockerfile +36 -0
  413. data/packaging/docker/docker-compose.failover.yml +43 -0
  414. data/packaging/docker/entrypoint.sh +15 -0
  415. data/packaging/homebrew/rubydb.rb +19 -0
  416. data/packaging/systemd/rubydb.service +22 -0
  417. data/rubydb.gemspec +57 -0
  418. data/scripts/benchmark +7 -0
  419. data/scripts/durability_drill +37 -0
  420. data/scripts/format +0 -0
  421. data/scripts/fuzz +63 -0
  422. data/scripts/lint +0 -0
  423. data/scripts/release +50 -0
  424. data/scripts/release_check +43 -0
  425. data/scripts/replication_failover_drill +250 -0
  426. data/scripts/replication_network_failover_drill +255 -0
  427. data/scripts/restore_drill +45 -0
  428. data/scripts/security +0 -0
  429. data/scripts/setup +0 -0
  430. data/scripts/test +0 -0
  431. data/scripts/test-chaos +0 -0
  432. data/scripts/test-crash +0 -0
  433. data/scripts/test-integration +0 -0
  434. data/scripts/test-unit +0 -0
  435. data/visibility_map.json +1 -0
  436. metadata +538 -0
@@ -0,0 +1,82 @@
1
+ # SQL compatibility guide
2
+
3
+ This page is a developer reference for evaluating SQL support. The normative
4
+ statement list is [SQL compatibility](compatibility.md); the SQLite-style
5
+ application profile is [here](sqlite-compatibility.md). RubyDB does not claim
6
+ complete PostgreSQL, MySQL, or SQLite dialect compatibility.
7
+
8
+ ## Compatibility has four layers
9
+
10
+ An SQL feature is production-ready only when all four layers agree:
11
+
12
+ 1. syntax is parsed and rejected with useful errors;
13
+ 2. binding and type rules are defined, including `NULL`;
14
+ 3. planner/executor results and transaction semantics are correct; and
15
+ 4. Ruby, client/server, and ActiveRecord paths behave consistently.
16
+
17
+ A parser accepting a statement is not sufficient. Test duplicate rows,
18
+ ordering, aggregates, joins, constraints, rollback, savepoints, indexes,
19
+ timeouts, and recovery for every feature that mutates or reads data.
20
+
21
+ ## Query review checklist
22
+
23
+ For each query shape, record schema, indexes, bind types, expected rows,
24
+ expected ordering, transaction isolation, and error behavior. Test empty,
25
+ single-row, duplicate, `NULL`, and large-result cases. Explicitly order results
26
+ when the application requires order; relational results are not inherently
27
+ ordered.
28
+
29
+ Review:
30
+
31
+ * projections and aliases;
32
+ * boolean precedence and `NULL` truth tables;
33
+ * inner, left, and multi-table joins;
34
+ * grouping, aggregate input, and `HAVING`;
35
+ * limits and offsets at boundaries;
36
+ * conflict/upsert behavior and affected-row counts;
37
+ * casts, defaults, and constraint errors; and
38
+ * snapshot visibility during concurrent writes.
39
+
40
+ ## Application migration from SQLite
41
+
42
+ Start with a schema dump and a representative query/migration inventory. Run
43
+ the application test suite against RubyDB, not only a few hand-written
44
+ queries. Review pragmas, virtual tables, FTS, extensions, custom functions,
45
+ file-format assumptions, recursive queries, date/time behavior, collations,
46
+ and error handling. These areas are not included merely because the common
47
+ profile looks SQLite-like.
48
+
49
+ Never point RubyDB at an existing SQLite file and expect it to open. Migrate
50
+ through an explicit export/import process with checksums, row counts, and
51
+ application-level verification.
52
+
53
+ ## SQL change workflow
54
+
55
+ Add a contract example under `spec/sql`, parser tests, execution tests, failure
56
+ tests, and adapter coverage when relevant. Update the compatibility page and
57
+ release notes. Add a regression for every bug. If semantics are intentionally
58
+ different from another database, document the difference with a migration
59
+ recommendation.
60
+
61
+ ## Safe examples
62
+
63
+ ```sql
64
+ CREATE TABLE IF NOT EXISTS users (
65
+ id INTEGER PRIMARY KEY,
66
+ email TEXT NOT NULL UNIQUE,
67
+ active BOOLEAN DEFAULT TRUE
68
+ );
69
+
70
+ INSERT INTO users (email, active) VALUES (?, ?);
71
+
72
+ SELECT active, COUNT(*) AS total
73
+ FROM users
74
+ WHERE email IS NOT NULL
75
+ GROUP BY active
76
+ HAVING COUNT(*) > 0
77
+ ORDER BY active;
78
+ ```
79
+
80
+ Use bound parameters from Ruby or ActiveRecord. Do not construct SQL by
81
+ concatenating user input.
82
+
@@ -0,0 +1,39 @@
1
+ # RubyDB SQL compatibility
2
+
3
+ RubyDB supports a deliberately documented SQL dialect. It includes a tested
4
+ SQLite-style compatibility profile for common new Ruby/Rails applications (see
5
+ `sqlite-compatibility.md`), but this is not a claim of complete SQLite,
6
+ PostgreSQL, or MySQL compatibility.
7
+
8
+ Supported and tested statements include:
9
+
10
+ - `SELECT` with projections, `WHERE`, ordering, limits, offsets, built-in
11
+ expressions, and `COUNT`, `SUM`, `AVG`, `MIN`, and `MAX` aggregates (including
12
+ `DISTINCT` aggregate arguments) with
13
+ `GROUP BY` and `HAVING`
14
+ - window ranking functions `ROW_NUMBER`, `RANK`, and `DENSE_RANK`, plus
15
+ partition-wide and explicit `ROWS`-framed aggregate windows using
16
+ `OVER (PARTITION BY ... ORDER BY ...)`
17
+ - `UNION`, `UNION ALL`, `INTERSECT`, and `EXCEPT` for compatible SELECT
18
+ projections
19
+ - non-correlated scalar subqueries, `IN (SELECT ...)`, and `EXISTS (SELECT ...)`
20
+ predicates
21
+ - materialized non-recursive and bounded recursive `WITH` common table
22
+ expressions
23
+ - `INSERT`, `UPDATE`, and `DELETE`, including multi-row `VALUES`,
24
+ `ON CONFLICT DO NOTHING`, and targeted `ON CONFLICT (...) DO UPDATE SET ...`
25
+ with `excluded.column`
26
+ - `CREATE TABLE` and `DROP TABLE`, including primary keys, unique constraints,
27
+ checks, foreign keys, and referential actions
28
+ - `CREATE INDEX`/`CREATE UNIQUE INDEX` and `DROP INDEX`
29
+ - `ALTER TABLE` add/drop columns and constraints
30
+ - `CREATE`/`DROP DATABASE`, `CREATE`/`DROP SCHEMA`, and `CREATE`/`DROP VIEW`
31
+ - supported trigger metadata DDL: `CREATE TRIGGER ... EXECUTE FUNCTION ...`
32
+ - `BEGIN`, `COMMIT`, `ROLLBACK`, `SAVEPOINT`, `ROLLBACK TO SAVEPOINT`, and
33
+ `RELEASE SAVEPOINT`
34
+ - `EXPLAIN`, `EXPLAIN ANALYZE`, and `VACUUM`
35
+
36
+ Unsupported syntax must fail with a parser or execution error. RubyDB does not
37
+ promise arbitrary SQL extensions, PostgreSQL wire-level compatibility, or
38
+ feature parity with another database engine. The executable contract is the
39
+ integration coverage under `spec/`.
@@ -0,0 +1,10 @@
1
+ # SQL data types
2
+
3
+ The documented RubyDB types are `INTEGER`, `BIGINT`, `SMALLINT`, `FLOAT`,
4
+ `DECIMAL`, `BOOLEAN`, `TEXT`, `VARCHAR`, `BLOB`, `DATE`, `TIME`, `TIMESTAMP`,
5
+ `JSON`, and `UUID`. Type conversion, nullability, defaults, and constraint
6
+ behavior are validated through the SQL and Rails suites.
7
+
8
+ RubyDB does not claim storage or coercion compatibility with every other SQL
9
+ engine. Preserve types explicitly in migrations and test application boundary
10
+ values, nulls, booleans, timestamps, decimals, JSON, and binary data.
@@ -0,0 +1,9 @@
1
+ # SQL functions
2
+
3
+ The tested function surface includes `COUNT`, `SUM`, `AVG`, `MIN`, `MAX`,
4
+ `LOWER`, `UPPER`, `LENGTH`, `SUBSTR`, `CONCAT`, `COALESCE`, and `NULLIF`, plus
5
+ the documented window ranking and aggregate functions.
6
+
7
+ Function null behavior and return types are part of the compatibility contract.
8
+ Do not assume a PostgreSQL, MySQL, or SQLite extension exists because a function
9
+ has the same name; unsupported functions must be reported explicitly.
data/docs/sql/joins.md ADDED
@@ -0,0 +1,9 @@
1
+ # SQL joins
2
+
3
+ RubyDB supports qualified `INNER`, `LEFT [OUTER]`, `RIGHT`, `FULL [OUTER]`, and
4
+ `CROSS JOIN` forms with `ON` predicates in the documented dialect. Outer joins
5
+ preserve unmatched rows with null-extended columns.
6
+
7
+ Use explicit table qualification when columns are ambiguous. Validate join
8
+ cardinality, null behavior, ordering, grouping, and transaction visibility with
9
+ representative data. Join reordering is limited to safe inner-join plans.
@@ -0,0 +1,9 @@
1
+ # SQL operators and predicates
2
+
3
+ The documented surface includes arithmetic, comparison, boolean `AND`/`OR` and
4
+ `NOT`, `IS NULL`/`IS NOT NULL`, `BETWEEN`, `IN`, `EXISTS`, `LIKE`, `ILIKE`, and
5
+ three-valued null behavior covered by the SQL tests.
6
+
7
+ Use bound parameters for user input. Test false, null, empty string, numeric
8
+ precision, and mixed-type values explicitly; similar syntax across SQL engines
9
+ does not guarantee identical semantics.
@@ -0,0 +1,21 @@
1
+ # SQLite compatibility profile
2
+
3
+ RubyDB now maintains an explicit SQLite-style compatibility profile for new
4
+ Ruby and Rails applications. The profile is tested by
5
+ `spec/sqlite_compatibility_spec.rb` and covers the common application surface:
6
+
7
+ - `CREATE TABLE IF NOT EXISTS`, integer primary keys with `AUTOINCREMENT`,
8
+ defaults, `NOT NULL`, and `UNIQUE`
9
+ - CRUD, parameter binding through the Rails connection, transactions, and
10
+ rollback
11
+ - `WHERE`, `IS NULL`/boolean predicates, ordering, `LIMIT`/`OFFSET`, joins,
12
+ grouped aggregates, and `HAVING`
13
+ - targeted `ON CONFLICT ... DO UPDATE` upserts
14
+ - ActiveRecord schema inspection through the embedded adapter
15
+
16
+ This is useful for applications written against the documented RubyDB surface,
17
+ but it is not a complete replacement for the SQLite library. SQLite pragmas,
18
+ virtual tables, FTS, recursive query edge cases, extension APIs, file-format
19
+ compatibility, and every SQLite function/error behavior remain unsupported or
20
+ unverified. An existing SQLite application must run its own migration and
21
+ query suite before migration.
@@ -0,0 +1,10 @@
1
+ # SQL syntax
2
+
3
+ Statements are parsed by RubyDB's lexer and parser and executed through the
4
+ planner. The supported statements include `SELECT`, `INSERT`, `UPDATE`,
5
+ `DELETE`, table/index/schema/view DDL, transactions/savepoints, `EXPLAIN`, and
6
+ `VACUUM` as listed in [compatibility](compatibility.md).
7
+
8
+ Use semicolons for multiple statements only where the client path supports
9
+ them. Identifiers may be quoted with double quotes or backticks. Unsupported
10
+ syntax fails with a parser or execution error; it is never silently ignored.
@@ -0,0 +1,10 @@
1
+ # SQL transactions
2
+
3
+ RubyDB supports `BEGIN`, `COMMIT`, `ROLLBACK`, `SAVEPOINT`, `ROLLBACK TO
4
+ SAVEPOINT`, and `RELEASE SAVEPOINT`. Commits coordinate MVCC, locks, row
5
+ mutation, WAL, and durable acknowledgement.
6
+
7
+ Keep transactions short enough for the workload. Long-running readers can
8
+ retain old versions and delay vacuum; deadlock victims must retry the
9
+ application unit. Validate transaction behavior after restart and under
10
+ concurrency.
@@ -0,0 +1,244 @@
1
+ # RubyDB troubleshooting guide
2
+
3
+ This guide is for developers and operators diagnosing a live or test
4
+ deployment. Preserve evidence before attempting recovery. If data is
5
+ important, stop writes, copy the database directory and WAL to protected
6
+ storage, record the RubyDB version and commit, and work on a copy.
7
+
8
+ ## First response
9
+
10
+ Collect the smallest useful incident bundle:
11
+
12
+ ```sh
13
+ ruby -v
14
+ bundle exec ruby -Ilib exe/rubydb --version
15
+ bundle exec ruby -Ilib exe/rubydb status --config config/rubydb.yml
16
+ bundle exec ruby -Ilib exe/rubydb doctor --config config/rubydb.yml
17
+ ```
18
+
19
+ Also record the operating system, deployment topology, database path (without
20
+ credentials), configuration checksum, recent migrations, request IDs, error
21
+ logs, disk/free-inode state, process list, and whether the failure affects
22
+ embedded mode, server mode, or both. Redact passwords, tokens, private keys,
23
+ certificate contents, and customer values.
24
+
25
+ Do not delete WAL files, run vacuum, force promotion, or retry an unknown
26
+ commit until the state and evidence are preserved.
27
+
28
+ ## Startup and configuration
29
+
30
+ ### The database will not open
31
+
32
+ Check that the path is the intended directory, is readable and writable by the
33
+ service account, and is not already owned by another embedded process. Inspect
34
+ the status and doctor output. If the path contains an incomplete checkpoint,
35
+ use the documented recovery flow and keep the original directory unchanged.
36
+
37
+ Common causes are a wrong working directory, a missing parent directory,
38
+ permissions, a stale lock, an unsupported format version, and an incomplete
39
+ restore. A stale lock must be investigated against the process owner; never
40
+ remove it merely because startup is inconvenient.
41
+
42
+ ### The server starts and immediately exits
43
+
44
+ Run the same command in the foreground with verbose logging. Validate the
45
+ configuration, TLS files, certificate/key pairing, authentication settings,
46
+ listen address, and port availability. Check the service manager’s stdout and
47
+ stderr rather than only its health endpoint. `RUBYDB_DEBUG=1` can expose a
48
+ development backtrace; do not enable verbose debug output on a public service
49
+ without reviewing sensitive data exposure.
50
+
51
+ ### The server is healthy but clients cannot connect
52
+
53
+ Confirm the client endpoint, port, TLS mode, CA path, SNI/hostname, and
54
+ authentication credentials. Test from the same network namespace as the
55
+ application. A listening socket proves only that a process has bound a port;
56
+ the readiness check must also verify the database owner and request path.
57
+
58
+ ## SQL and query failures
59
+
60
+ ### A statement is rejected
61
+
62
+ Capture the exact SQL shape with values redacted and determine whether the
63
+ failure is parser, binder, planner, executor, or constraint related. Compare
64
+ the statement against [SQL compatibility](sql/compatibility.md) and the
65
+ [SQLite-style profile](sql/sqlite-compatibility.md). Test a minimal statement
66
+ with one table, then add joins, predicates, grouping, and constraints one at a
67
+ time.
68
+
69
+ Do not assume that syntax accepted by SQLite, PostgreSQL, or MySQL has the
70
+ same semantics in RubyDB. Unsupported dialect features should be rewritten or
71
+ tracked as compatibility work, not hidden behind a generic fallback.
72
+
73
+ ### Results are wrong or unstable
74
+
75
+ Reproduce without the optimizer if that diagnostic mode exists, then compare
76
+ the plan and row versions. Add explicit ordering when order is part of the
77
+ application contract. Check `NULL` predicates, implicit casts, duplicate join
78
+ keys, grouping columns, transaction snapshot, and stale statistics. Preserve
79
+ the schema, seed data, SQL, and expected result as a regression spec.
80
+
81
+ ### A query is slow
82
+
83
+ Record query shape, row count, indexes, bind values, plan, duration, lock wait,
84
+ and whether the delay is execution or checkpoint/WAL pressure. Test with and
85
+ without the suspected index and inspect the scan cardinality. Do not add
86
+ indexes blindly: each index adds write, storage, recovery, and vacuum cost.
87
+
88
+ ## Transactions, locks, and concurrency
89
+
90
+ ### Requests hang
91
+
92
+ Separate network wait, lock wait, disk wait, and executor work. Check active
93
+ transactions, lock owners, waiters, deadlines, and cancellation logs. Set a
94
+ bounded request/lock timeout in staging and capture a thread dump. A timeout
95
+ must release resources and report whether commit was known.
96
+
97
+ ### Deadlock detected
98
+
99
+ Keep the deadlock graph, victim transaction ID, SQL fingerprints, and lock
100
+ order. Confirm that the victim rolled back all writes and released every lock.
101
+ Retry only idempotent application work. Fix the application’s lock ordering or
102
+ transaction size; do not disable deadlock detection.
103
+
104
+ ### Data disappears inside a transaction
105
+
106
+ Check snapshot timing, savepoints, rollback paths, and whether the read and
107
+ write use the same connection. In server mode, a transaction is connection
108
+ scoped unless the API says otherwise. A connection-pool checkout must not
109
+ reuse a connection with an open transaction.
110
+
111
+ ### High concurrency causes errors
112
+
113
+ Reduce workers and payload size, then increase one at a time. Monitor memory,
114
+ file descriptors, WAL growth, checkpoint time, lock waits, cancellation rate,
115
+ and p99 latency. Embedded mode has one process owner; use server mode for
116
+ multiple application processes. Use the production soak scripts before
117
+ changing limits.
118
+
119
+ ## WAL, recovery, and corruption
120
+
121
+ ### Recovery takes too long
122
+
123
+ Measure WAL size, last checkpoint LSN, frame count, page count, and storage
124
+ latency. A large WAL may indicate a blocked checkpoint, a long reader, or
125
+ insufficient checkpoint scheduling. Preserve the directory, then run a copy
126
+ through inspection and compaction. Never truncate WAL by hand.
127
+
128
+ ### Checksum or framing validation fails
129
+
130
+ Treat this as a durability incident. Stop writes, preserve all database and WAL
131
+ files, capture filesystem and process termination evidence, and attempt restore
132
+ from the newest verified backup in a separate directory. Compare checksums and
133
+ LSNs. If the backup also fails, escalate with the complete evidence bundle.
134
+
135
+ ### An index is inconsistent
136
+
137
+ Do not make application decisions from a suspect index. Run the supported
138
+ inspection/recovery or rebuild operation on a copy, compare indexed and table
139
+ scans, and verify after reopen. The repair result must be durable before the
140
+ copy is promoted. A failed index persistence operation must remain visible as
141
+ an error.
142
+
143
+ ### Disk is full
144
+
145
+ Stop growth safely: pause writes if necessary, preserve logs, and identify
146
+ database, WAL, backup, and temporary-file usage. Free capacity through the
147
+ host’s approved procedure, then verify the filesystem and resume with a
148
+ controlled write. Do not delete WAL, active checkpoints, or the newest backup
149
+ to make room.
150
+
151
+ ## Backup, restore, and upgrades
152
+
153
+ ### Backup succeeds but restore fails
154
+
155
+ Check the backup manifest, checksum, base identity, LSN range, compression,
156
+ RubyDB version, and free space in the target directory. Restore to a fresh
157
+ directory and run integrity, schema, row-count, and application smoke checks.
158
+ Keep the failed restore for diagnosis.
159
+
160
+ ### Incremental/differential chain is rejected
161
+
162
+ Restore the verified base first and apply deltas in order. Confirm that the
163
+ declared base checksum and LSN match. Missing or reordered pieces must fail
164
+ closed; do not bypass validation.
165
+
166
+ ### An upgrade will not start
167
+
168
+ Read the upgrade guard and format version. Take a verified backup, test the
169
+ upgrade on a copy with a representative workload, and retain a rollback plan.
170
+ Do not mix binary versions against a live embedded directory unless the
171
+ compatibility contract explicitly allows it.
172
+
173
+ ## Replication and failover
174
+
175
+ ### Replica is behind
176
+
177
+ Compare primary and replica acknowledged LSN, WAL retention, connection state,
178
+ authentication, and apply errors. Check that the replica is not accepting
179
+ writes. Reconnect/catch up through the supported protocol and verify row and
180
+ LSN consistency before promotion.
181
+
182
+ ### Promotion is rejected
183
+
184
+ Promotion should require a synchronized candidate and a valid fencing epoch.
185
+ Resolve lag, stale metadata, or fence ownership first. Never force promotion
186
+ because an application health check is red; a stale primary may still be able
187
+ to write.
188
+
189
+ ### Suspected split brain
190
+
191
+ Fence both writers at the deployment layer, stop application writes, preserve
192
+ both logs and WALs, and identify the highest acknowledged commit/fence epoch.
193
+ Do not merge divergent database directories manually. The current RubyDB
194
+ workflow is explicitly fenced/manual unless a deployment has separately
195
+ validated its election and fencing system across hosts.
196
+
197
+ ## Rails and migrations
198
+
199
+ Check the Rails/Ruby versions, adapter configuration, connection pool size,
200
+ database ownership mode, generated SQL, bind values, and migration version.
201
+ Run `db:migrate:status`, inspect schema state, and compare the schema dump with
202
+ the intended model. For a populated-table migration, test on a copy and plan
203
+ backfill, locking, rollback, and deployment sequencing.
204
+
205
+ Frequent causes include unsupported generated SQL, an embedded path shared by
206
+ web and job processes, pool size exceeding server capacity, a migration
207
+ checksum mismatch, or a schema dump that uses a feature outside RubyDB’s
208
+ documented profile. See [Rails compatibility](rails/compatibility-guide.md)
209
+ and [Rails troubleshooting](rails/troubleshooting.md).
210
+
211
+ ## TLS, authentication, and authorization
212
+
213
+ Verify the server certificate chain, hostname, expiration, key permissions,
214
+ CA bundle, and client/server TLS settings. Rotate certificates by staging the
215
+ new chain, testing a client, switching atomically, and retaining the old chain
216
+ only for the documented overlap period. Rotate secrets through the secret
217
+ manager, not source control or command-line history.
218
+
219
+ Authentication success does not imply authorization. Check the authenticated
220
+ identity, role, operation, database, and audit record. Treat repeated failures
221
+ as a security event and preserve timestamps and request IDs.
222
+
223
+ ## Resource exhaustion
224
+
225
+ Track open files, memory, threads, CPU, disk bytes, inodes, WAL size, active
226
+ transactions, pool utilization, and queue depth. Apply limits at the service
227
+ and application layers. Reduce concurrency before raising limits, and confirm
228
+ that cancellation and shutdown drain work without corrupting state.
229
+
230
+ ## Evidence and escalation
231
+
232
+ An actionable report includes:
233
+
234
+ * exact command/API and a minimal reproduction;
235
+ * RubyDB commit/version, Ruby/Rails versions, OS and filesystem;
236
+ * topology, configuration names, and relevant metrics;
237
+ * sanitized logs with request/transaction/LSN identifiers;
238
+ * database/WAL/backup checksums and sizes;
239
+ * expected versus actual result; and
240
+ * what was already attempted and whether it changed state.
241
+
242
+ See [Debugging RubyDB](debugging.md) for collection commands and safe
243
+ instrumentation.
244
+
data/exe/rubydb ADDED
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # RubyDB executable - This is the gem's main executable that gets installed
5
+ # when the gem is installed. It delegates to bin/rubydb.
6
+
7
+ # This file is the entry point that RubyGems uses when the gem is installed.
8
+ # It allows users to run `rubydb` from anywhere after `gem install rubydb`.
9
+
10
+ require_relative "../lib/rubydb"
11
+ require_relative "../lib/rubydb/cli/application"
12
+
13
+ # Load and execute the CLI application
14
+ begin
15
+ RubyDB::CLI::Application.start(ARGV)
16
+ rescue Interrupt
17
+ puts "\nInterrupted. Exiting..."
18
+ exit 0
19
+ rescue StandardError => e
20
+ $stderr.puts "Error: #{e.message}"
21
+ $stderr.puts e.backtrace if ENV["RUBYDB_DEBUG"]
22
+ exit 1
23
+ end