rubydb 0.1.4 → 0.1.6

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 (469) hide show
  1. checksums.yaml +4 -4
  2. data/.github/PULL_REQUEST_TEMPLATE.md +15 -15
  3. data/.github/workflows/benchmark.yml +26 -26
  4. data/.github/workflows/compatibility.yml +63 -63
  5. data/.github/workflows/fuzz.yml +33 -33
  6. data/.github/workflows/lint.yml +21 -21
  7. data/.github/workflows/operations.yml +24 -24
  8. data/.github/workflows/production-validation.yml +111 -111
  9. data/.github/workflows/release.yml +77 -77
  10. data/.github/workflows/security.yml +39 -37
  11. data/.github/workflows/test.yml +26 -26
  12. data/.github/workflows/workload.yml +58 -58
  13. data/.gitignore +16 -5
  14. data/.rubocop.yml +50 -44
  15. data/.standard.yml +9 -14
  16. data/ARCHITECTURE.md +21 -21
  17. data/CHANGELOG.md +57 -27
  18. data/CODE_OF_CONDUCT.md +13 -13
  19. data/CONTRIBUTING.md +29 -29
  20. data/GOVERNANCE.md +16 -16
  21. data/Gemfile +18 -17
  22. data/Gemfile.lock +125 -71
  23. data/README.md +168 -12
  24. data/ROADMAP.md +27 -27
  25. data/Rakefile +76 -71
  26. data/SECURITY.md +54 -54
  27. data/SUPPORT.md +14 -14
  28. data/accelerator/bin/SHA256SUMS +6 -0
  29. data/accelerator/bin/rubydb-accelerator-darwin-amd64 +0 -0
  30. data/accelerator/bin/rubydb-accelerator-darwin-arm64 +0 -0
  31. data/accelerator/bin/rubydb-accelerator-linux-amd64 +0 -0
  32. data/accelerator/bin/rubydb-accelerator-linux-arm64 +0 -0
  33. data/accelerator/bin/rubydb-accelerator-windows-amd64.exe +0 -0
  34. data/accelerator/bin/rubydb-accelerator-windows-arm64.exe +0 -0
  35. data/accelerator/cmd/rubydb-accelerator/main.go +11 -0
  36. data/accelerator/go.mod +3 -0
  37. data/accelerator/internal/execution/aggregate.go +94 -0
  38. data/accelerator/internal/execution/distinct.go +22 -0
  39. data/accelerator/internal/execution/filter.go +73 -0
  40. data/accelerator/internal/execution/join.go +79 -0
  41. data/accelerator/internal/execution/operators.go +167 -0
  42. data/accelerator/internal/execution/scan.go +20 -0
  43. data/accelerator/internal/execution/sort.go +62 -0
  44. data/accelerator/internal/execution/types.go +136 -0
  45. data/accelerator/internal/execution/value.go +67 -0
  46. data/accelerator/internal/memory/arena.go +47 -0
  47. data/accelerator/internal/memory/reuse.go +22 -0
  48. data/accelerator/internal/metrics/registry.go +67 -0
  49. data/accelerator/internal/parallel/bounded_queue.go +56 -0
  50. data/accelerator/internal/parallel/scheduler.go +47 -0
  51. data/accelerator/internal/parallel/worker_pool.go +53 -0
  52. data/accelerator/internal/protocol/cancellation.go +48 -0
  53. data/accelerator/internal/protocol/columnar.go +263 -0
  54. data/accelerator/internal/protocol/frame.go +187 -0
  55. data/accelerator/internal/runtime/worker.go +521 -0
  56. data/accelerator/internal/storage/page_reader.go +81 -0
  57. data/accelerator/internal/storage/snapshot_scan.go +539 -0
  58. data/accelerator/internal/wal/checksum.go +13 -0
  59. data/accelerator/internal/wal/compression.go +41 -0
  60. data/accelerator/internal/wal/group_commit.go +24 -0
  61. data/accelerator/internal/wal/record_encoder.go +40 -0
  62. data/adapters/activerecord/Gemfile +11 -11
  63. data/adapters/activerecord/README.md +8 -3
  64. data/adapters/activerecord/lib/active_record/connection_adapters/rubydb_adapter.rb +881 -879
  65. data/adapters/activerecord/rubydb-activerecord.gemspec +21 -21
  66. data/adapters/activerecord/spec/rubydb_adapter_integration_spec.rb +143 -143
  67. data/adapters/ruby/README.md +18 -18
  68. data/adapters/sequel/README.md +11 -11
  69. data/config/monitoring/prometheus-alerts.yml +39 -39
  70. data/config/production.yml +36 -36
  71. data/docs/README.md +77 -71
  72. data/docs/architecture/concurrency.md +14 -14
  73. data/docs/architecture/current-state.md +125 -125
  74. data/docs/architecture/execution-engine.md +25 -25
  75. data/docs/architecture/go-accelerator.md +179 -0
  76. data/docs/architecture/indexes.md +19 -19
  77. data/docs/architecture/mvcc.md +19 -19
  78. data/docs/architecture/overview.md +13 -13
  79. data/docs/architecture/pages.md +11 -11
  80. data/docs/architecture/production-roadmap.md +82 -82
  81. data/docs/architecture/query-planner.md +20 -20
  82. data/docs/architecture/recovery.md +18 -18
  83. data/docs/architecture/sql-engine.md +12 -12
  84. data/docs/architecture/storage-engine.md +14 -14
  85. data/docs/architecture/transactions.md +10 -10
  86. data/docs/architecture/wal.md +28 -28
  87. data/docs/cli-cheatsheet.md +98 -98
  88. data/docs/cli.md +299 -275
  89. data/docs/contributing/architecture.md +9 -9
  90. data/docs/contributing/benchmarking.md +30 -14
  91. data/docs/contributing/development.md +16 -16
  92. data/docs/contributing/release-process.md +49 -49
  93. data/docs/contributing/testing.md +16 -16
  94. data/docs/debugging.md +229 -229
  95. data/docs/developer/branching.md +10 -10
  96. data/docs/developer/database-diff.md +10 -10
  97. data/docs/developer/local-development.md +49 -17
  98. data/docs/developer/snapshots.md +9 -9
  99. data/docs/developer/temporal-data.md +10 -10
  100. data/docs/developer-guide.md +297 -297
  101. data/docs/getting-started/first-database.md +16 -16
  102. data/docs/getting-started/first-query.md +13 -13
  103. data/docs/getting-started/installation.md +19 -19
  104. data/docs/getting-started/local-to-production.md +300 -300
  105. data/docs/getting-started/quickstart.md +17 -17
  106. data/docs/getting-started/rails.md +16 -16
  107. data/docs/hardening_backlog.md +93 -93
  108. data/docs/lessons-learned.md +112 -112
  109. data/docs/operations/backups.md +33 -33
  110. data/docs/operations/disaster-recovery.md +31 -31
  111. data/docs/operations/failover.md +30 -30
  112. data/docs/operations/monitoring.md +25 -25
  113. data/docs/operations/production-guide.md +295 -295
  114. data/docs/operations/production-runbook.md +45 -45
  115. data/docs/operations/replication.md +33 -33
  116. data/docs/operations/restore.md +6 -6
  117. data/docs/operations/runbook.md +34 -34
  118. data/docs/operations/upgrades.md +14 -14
  119. data/docs/operations/workload-testing.md +17 -17
  120. data/docs/production-readiness.md +118 -118
  121. data/docs/production_validation.md +150 -150
  122. data/docs/rails/active-record.md +11 -11
  123. data/docs/rails/compatibility-guide.md +90 -90
  124. data/docs/rails/database-yml.md +92 -92
  125. data/docs/rails/installation.md +17 -17
  126. data/docs/rails/migrations.md +17 -17
  127. data/docs/rails/production.md +82 -82
  128. data/docs/rails/troubleshooting.md +18 -18
  129. data/docs/release.md +25 -25
  130. data/docs/server/architecture.md +10 -10
  131. data/docs/server/authentication.md +10 -10
  132. data/docs/server/configuration.md +16 -16
  133. data/docs/server/connection-pooling.md +10 -10
  134. data/docs/server/deployment.md +10 -10
  135. data/docs/server/protocol.md +12 -12
  136. data/docs/sql/compatibility-guide.md +82 -82
  137. data/docs/sql/compatibility.md +39 -39
  138. data/docs/sql/data-types.md +10 -10
  139. data/docs/sql/functions.md +9 -9
  140. data/docs/sql/joins.md +9 -9
  141. data/docs/sql/operators.md +9 -9
  142. data/docs/sql/sqlite-compatibility.md +21 -21
  143. data/docs/sql/syntax.md +10 -10
  144. data/docs/sql/transactions.md +10 -10
  145. data/docs/troubleshooting.md +244 -244
  146. data/lessons/01-foundations.md +73 -0
  147. data/lessons/02-local-development.md +121 -0
  148. data/lessons/03-embedded-rubydb.md +99 -0
  149. data/lessons/04-rails-complex-apps.md +138 -0
  150. data/lessons/05-rubydb-production-server.md +237 -0
  151. data/lessons/06-postgresql-massive-apps.md +96 -0
  152. data/lessons/07-hybrid-microservices.md +179 -0
  153. data/lessons/08-migrations-backups-recovery.md +86 -0
  154. data/lessons/09-observability-security-scale.md +87 -0
  155. data/lessons/10-release-readiness.md +192 -0
  156. data/lessons/11-community-adapter.md +323 -0
  157. data/lessons/12-rails-ecommerce-pressure.md +263 -0
  158. data/lib/rubydb/accelerator/client.rb +451 -0
  159. data/lib/rubydb/accelerator/error.rb +22 -0
  160. data/lib/rubydb/accelerator/manager.rb +606 -0
  161. data/lib/rubydb/accelerator.rb +13 -0
  162. data/lib/rubydb/backup/archive.rb +332 -334
  163. data/lib/rubydb/backup/backup.rb +400 -401
  164. data/lib/rubydb/backup/incremental.rb +349 -353
  165. data/lib/rubydb/backup/restore.rb +289 -290
  166. data/lib/rubydb/backup/snapshot.rb +265 -267
  167. data/lib/rubydb/backup/verification.rb +276 -279
  168. data/lib/rubydb/branching/branch.rb +181 -181
  169. data/lib/rubydb/branching/branch_manager.rb +307 -311
  170. data/lib/rubydb/branching/branch_metadata.rb +140 -140
  171. data/lib/rubydb/branching/checkout.rb +165 -166
  172. data/lib/rubydb/branching/copy_on_write.rb +272 -272
  173. data/lib/rubydb/branching/diff.rb +137 -138
  174. data/lib/rubydb/branching/merge.rb +282 -285
  175. data/lib/rubydb/build_info.rb +15 -15
  176. data/lib/rubydb/catalog/catalog.rb +391 -391
  177. data/lib/rubydb/catalog/column.rb +112 -112
  178. data/lib/rubydb/catalog/constraint.rb +180 -180
  179. data/lib/rubydb/catalog/database.rb +184 -184
  180. data/lib/rubydb/catalog/index.rb +97 -97
  181. data/lib/rubydb/catalog/schema.rb +103 -103
  182. data/lib/rubydb/catalog/sequence.rb +90 -90
  183. data/lib/rubydb/catalog/system_catalog.rb +698 -698
  184. data/lib/rubydb/catalog/table.rb +178 -178
  185. data/lib/rubydb/catalog/trigger.rb +102 -102
  186. data/lib/rubydb/catalog/view.rb +66 -66
  187. data/lib/rubydb/cli/application.rb +168 -163
  188. data/lib/rubydb/cli/commands/accelerator.rb +72 -0
  189. data/lib/rubydb/cli/commands/backup.rb +80 -81
  190. data/lib/rubydb/cli/commands/branch.rb +72 -72
  191. data/lib/rubydb/cli/commands/checkout.rb +54 -54
  192. data/lib/rubydb/cli/commands/create.rb +58 -58
  193. data/lib/rubydb/cli/commands/diff.rb +76 -77
  194. data/lib/rubydb/cli/commands/doctor.rb +77 -74
  195. data/lib/rubydb/cli/commands/drop.rb +57 -57
  196. data/lib/rubydb/cli/commands/init.rb +101 -102
  197. data/lib/rubydb/cli/commands/inspect.rb +95 -95
  198. data/lib/rubydb/cli/commands/merge.rb +63 -63
  199. data/lib/rubydb/cli/commands/migrate.rb +62 -62
  200. data/lib/rubydb/cli/commands/restart.rb +42 -39
  201. data/lib/rubydb/cli/commands/restore.rb +121 -121
  202. data/lib/rubydb/cli/commands/shell.rb +365 -365
  203. data/lib/rubydb/cli/commands/snapshot.rb +79 -79
  204. data/lib/rubydb/cli/commands/start.rb +88 -82
  205. data/lib/rubydb/cli/commands/status.rb +96 -92
  206. data/lib/rubydb/cli/commands/stop.rb +47 -47
  207. data/lib/rubydb/cli/commands/vacuum.rb +58 -58
  208. data/lib/rubydb/cli/formatter.rb +221 -221
  209. data/lib/rubydb/cli/output.rb +168 -168
  210. data/lib/rubydb/client/client.rb +309 -304
  211. data/lib/rubydb/client/connection.rb +429 -415
  212. data/lib/rubydb/client/connection_pool.rb +168 -168
  213. data/lib/rubydb/client/connection_url.rb +96 -96
  214. data/lib/rubydb/client/prepared_statement.rb +60 -60
  215. data/lib/rubydb/client/result.rb +127 -123
  216. data/lib/rubydb/client/statement.rb +52 -52
  217. data/lib/rubydb/client/transaction.rb +130 -130
  218. data/lib/rubydb/concurrency/concurrency.rb +19 -19
  219. data/lib/rubydb/concurrency/deadlock_detector.rb +148 -150
  220. data/lib/rubydb/concurrency/latch.rb +101 -101
  221. data/lib/rubydb/concurrency/lock_graph.rb +163 -165
  222. data/lib/rubydb/concurrency/mutex.rb +181 -183
  223. data/lib/rubydb/concurrency/rw_lock.rb +180 -180
  224. data/lib/rubydb/concurrency/scheduler.rb +248 -250
  225. data/lib/rubydb/concurrency/worker_pool.rb +145 -143
  226. data/lib/rubydb/configuration/config.rb +170 -170
  227. data/lib/rubydb/configuration/defaults.rb +191 -179
  228. data/lib/rubydb/configuration/environment.rb +152 -152
  229. data/lib/rubydb/configuration/parser.rb +185 -185
  230. data/lib/rubydb/configuration/validation.rb +228 -221
  231. data/lib/rubydb/constants.rb +74 -74
  232. data/lib/rubydb/constraints/check.rb +181 -181
  233. data/lib/rubydb/constraints/constraint.rb +101 -101
  234. data/lib/rubydb/constraints/foreign_key.rb +130 -130
  235. data/lib/rubydb/constraints/not_null.rb +64 -64
  236. data/lib/rubydb/constraints/primary_key.rb +99 -99
  237. data/lib/rubydb/constraints/unique.rb +106 -108
  238. data/lib/rubydb/constraints/validator.rb +349 -350
  239. data/lib/rubydb/errors/authentication_error.rb +10 -10
  240. data/lib/rubydb/errors/authorization_error.rb +23 -23
  241. data/lib/rubydb/errors/client_error.rb +10 -10
  242. data/lib/rubydb/errors/configuration_error.rb +10 -10
  243. data/lib/rubydb/errors/connection_error.rb +10 -10
  244. data/lib/rubydb/errors/constraint_error.rb +23 -23
  245. data/lib/rubydb/errors/corruption_error.rb +10 -10
  246. data/lib/rubydb/errors/database_error.rb +10 -10
  247. data/lib/rubydb/errors/error.rb +20 -20
  248. data/lib/rubydb/errors/execution_error.rb +10 -10
  249. data/lib/rubydb/errors/parser_error.rb +10 -10
  250. data/lib/rubydb/errors/recovery_error.rb +10 -10
  251. data/lib/rubydb/errors/replication_error.rb +10 -10
  252. data/lib/rubydb/errors/server_error.rb +6 -6
  253. data/lib/rubydb/errors/storage_error.rb +10 -10
  254. data/lib/rubydb/errors/transaction_error.rb +10 -10
  255. data/lib/rubydb/execution/accelerator_dispatch.rb +30 -0
  256. data/lib/rubydb/execution/aggregate_executor.rb +134 -138
  257. data/lib/rubydb/execution/cost_model.rb +72 -0
  258. data/lib/rubydb/execution/delete_executor.rb +110 -112
  259. data/lib/rubydb/execution/distinct_executor.rb +131 -135
  260. data/lib/rubydb/execution/executor.rb +1544 -1188
  261. data/lib/rubydb/execution/expression.rb +191 -193
  262. data/lib/rubydb/execution/index_scan.rb +142 -142
  263. data/lib/rubydb/execution/insert_executor.rb +215 -217
  264. data/lib/rubydb/execution/join_executor.rb +243 -249
  265. data/lib/rubydb/execution/limit_executor.rb +83 -85
  266. data/lib/rubydb/execution/operator_selection.rb +57 -0
  267. data/lib/rubydb/execution/optimizer.rb +227 -215
  268. data/lib/rubydb/execution/physical_plan.rb +47 -0
  269. data/lib/rubydb/execution/plan.rb +355 -353
  270. data/lib/rubydb/execution/planner.rb +508 -536
  271. data/lib/rubydb/execution/predicate.rb +235 -235
  272. data/lib/rubydb/execution/scan.rb +49 -49
  273. data/lib/rubydb/execution/sequential_scan.rb +63 -63
  274. data/lib/rubydb/execution/sort_executor.rb +194 -185
  275. data/lib/rubydb/execution/update_executor.rb +160 -162
  276. data/lib/rubydb/functions/aggregate.rb +70 -70
  277. data/lib/rubydb/functions/date_functions.rb +274 -278
  278. data/lib/rubydb/functions/function.rb +85 -85
  279. data/lib/rubydb/functions/json_functions.rb +231 -215
  280. data/lib/rubydb/functions/numeric_functions.rb +346 -346
  281. data/lib/rubydb/functions/scalar.rb +52 -52
  282. data/lib/rubydb/functions/string_functions.rb +383 -383
  283. data/lib/rubydb/functions/system_functions.rb +258 -246
  284. data/lib/rubydb/history/as_of.rb +238 -238
  285. data/lib/rubydb/history/change.rb +105 -105
  286. data/lib/rubydb/history/history.rb +131 -131
  287. data/lib/rubydb/history/history_manager.rb +228 -229
  288. data/lib/rubydb/history/temporal_query.rb +202 -202
  289. data/lib/rubydb/history/timeline.rb +144 -144
  290. data/lib/rubydb/indexes/btree.rb +215 -186
  291. data/lib/rubydb/indexes/btree_cursor.rb +258 -258
  292. data/lib/rubydb/indexes/btree_node.rb +384 -385
  293. data/lib/rubydb/indexes/hash_index.rb +150 -150
  294. data/lib/rubydb/indexes/index.rb +71 -71
  295. data/lib/rubydb/indexes/index_manager.rb +408 -406
  296. data/lib/rubydb/indexes/index_scan.rb +466 -470
  297. data/lib/rubydb/migrations/migration.rb +253 -254
  298. data/lib/rubydb/migrations/migration_lock.rb +146 -146
  299. data/lib/rubydb/migrations/migration_manager.rb +187 -176
  300. data/lib/rubydb/migrations/migration_version.rb +71 -71
  301. data/lib/rubydb/migrations/schema_diff.rb +211 -211
  302. data/lib/rubydb/migrations/schema_version.rb +64 -64
  303. data/lib/rubydb/monitoring/events.rb +155 -160
  304. data/lib/rubydb/monitoring/health.rb +216 -222
  305. data/lib/rubydb/monitoring/logger.rb +188 -193
  306. data/lib/rubydb/monitoring/metrics.rb +363 -359
  307. data/lib/rubydb/monitoring/performance.rb +176 -176
  308. data/lib/rubydb/monitoring/statistics.rb +168 -170
  309. data/lib/rubydb/mvcc/garbage_collector.rb +199 -199
  310. data/lib/rubydb/mvcc/mvcc.rb +16 -16
  311. data/lib/rubydb/mvcc/snapshot.rb +146 -147
  312. data/lib/rubydb/mvcc/vacuum.rb +180 -180
  313. data/lib/rubydb/mvcc/version.rb +106 -106
  314. data/lib/rubydb/mvcc/version_store.rb +396 -398
  315. data/lib/rubydb/mvcc/visibility.rb +107 -109
  316. data/lib/rubydb/protocol/capabilities.rb +125 -125
  317. data/lib/rubydb/protocol/decoder.rb +142 -145
  318. data/lib/rubydb/protocol/encoder.rb +131 -136
  319. data/lib/rubydb/protocol/handshake.rb +306 -305
  320. data/lib/rubydb/protocol/message.rb +121 -121
  321. data/lib/rubydb/protocol/parameter_binder.rb +101 -0
  322. data/lib/rubydb/protocol/protocol.rb +276 -277
  323. data/lib/rubydb/protocol/version.rb +54 -54
  324. data/lib/rubydb/rails/adapter.rb +245 -239
  325. data/lib/rubydb/rails/connection.rb +312 -314
  326. data/lib/rubydb/rails/database_statements.rb +122 -122
  327. data/lib/rubydb/rails/migration.rb +131 -131
  328. data/lib/rubydb/rails/quoting.rb +109 -109
  329. data/lib/rubydb/rails/result.rb +117 -117
  330. data/lib/rubydb/rails/schema_statements.rb +339 -339
  331. data/lib/rubydb/rails/transaction.rb +105 -105
  332. data/lib/rubydb/rails/type.rb +126 -126
  333. data/lib/rubydb/recovery/checkpoint.rb +261 -257
  334. data/lib/rubydb/recovery/consistency.rb +457 -467
  335. data/lib/rubydb/recovery/corruption_detector.rb +5 -5
  336. data/lib/rubydb/recovery/crash_recovery.rb +381 -387
  337. data/lib/rubydb/recovery/recovery_manager.rb +204 -206
  338. data/lib/rubydb/recovery/redo.rb +235 -237
  339. data/lib/rubydb/recovery/undo.rb +204 -206
  340. data/lib/rubydb/replication/failover.rb +5 -5
  341. data/lib/rubydb/replication/fencing.rb +63 -63
  342. data/lib/rubydb/replication/primary.rb +461 -450
  343. data/lib/rubydb/replication/replica.rb +382 -384
  344. data/lib/rubydb/replication/replication_log.rb +194 -200
  345. data/lib/rubydb/replication/replication_manager.rb +307 -308
  346. data/lib/rubydb/replication/replication_slot.rb +293 -295
  347. data/lib/rubydb/replication/replication_stream.rb +198 -201
  348. data/lib/rubydb/rubydb.rb +570 -560
  349. data/lib/rubydb/security/access_control.rb +252 -254
  350. data/lib/rubydb/security/audit_log.rb +209 -213
  351. data/lib/rubydb/security/authentication.rb +302 -302
  352. data/lib/rubydb/security/authorization.rb +282 -282
  353. data/lib/rubydb/security/credentials.rb +192 -196
  354. data/lib/rubydb/security/password.rb +205 -215
  355. data/lib/rubydb/security/permissions.rb +74 -74
  356. data/lib/rubydb/security/role.rb +99 -101
  357. data/lib/rubydb/security/user.rb +86 -86
  358. data/lib/rubydb/server/connection.rb +383 -366
  359. data/lib/rubydb/server/connection_pool.rb +193 -193
  360. data/lib/rubydb/server/lifecycle.rb +227 -228
  361. data/lib/rubydb/server/listener.rb +139 -136
  362. data/lib/rubydb/server/request_handler.rb +277 -276
  363. data/lib/rubydb/server/server.rb +363 -364
  364. data/lib/rubydb/server/session.rb +416 -369
  365. data/lib/rubydb/server/worker.rb +206 -210
  366. data/lib/rubydb/server/worker_pool.rb +168 -168
  367. data/lib/rubydb/sql/ast/alter_table.rb +169 -169
  368. data/lib/rubydb/sql/ast/begin_transaction.rb +47 -47
  369. data/lib/rubydb/sql/ast/commit.rb +37 -37
  370. data/lib/rubydb/sql/ast/constraint.rb +92 -83
  371. data/lib/rubydb/sql/ast/create_database.rb +41 -41
  372. data/lib/rubydb/sql/ast/create_index.rb +61 -61
  373. data/lib/rubydb/sql/ast/create_schema.rb +52 -52
  374. data/lib/rubydb/sql/ast/create_table.rb +187 -187
  375. data/lib/rubydb/sql/ast/delete.rb +54 -54
  376. data/lib/rubydb/sql/ast/drop_database.rb +41 -41
  377. data/lib/rubydb/sql/ast/drop_index.rb +41 -41
  378. data/lib/rubydb/sql/ast/drop_schema.rb +49 -49
  379. data/lib/rubydb/sql/ast/drop_table.rb +49 -49
  380. data/lib/rubydb/sql/ast/explain.rb +64 -64
  381. data/lib/rubydb/sql/ast/expression.rb +617 -604
  382. data/lib/rubydb/sql/ast/insert.rb +66 -66
  383. data/lib/rubydb/sql/ast/node.rb +42 -42
  384. data/lib/rubydb/sql/ast/rollback.rb +63 -63
  385. data/lib/rubydb/sql/ast/savepoint.rb +59 -59
  386. data/lib/rubydb/sql/ast/select.rb +88 -88
  387. data/lib/rubydb/sql/ast/set_operation.rb +22 -20
  388. data/lib/rubydb/sql/ast/trigger.rb +35 -29
  389. data/lib/rubydb/sql/ast/update.rb +88 -88
  390. data/lib/rubydb/sql/ast/vacuum.rb +19 -19
  391. data/lib/rubydb/sql/ast/view.rb +38 -32
  392. data/lib/rubydb/sql/ast/with.rb +32 -32
  393. data/lib/rubydb/sql/grammar.rb +86 -86
  394. data/lib/rubydb/sql/keywords.rb +156 -156
  395. data/lib/rubydb/sql/lexer.rb +209 -214
  396. data/lib/rubydb/sql/operators.rb +100 -100
  397. data/lib/rubydb/sql/parser.rb +1167 -1170
  398. data/lib/rubydb/sql/planner/analyzer.rb +283 -302
  399. data/lib/rubydb/sql/planner/binder.rb +537 -550
  400. data/lib/rubydb/sql/planner/type_checker.rb +427 -431
  401. data/lib/rubydb/sql/token.rb +210 -210
  402. data/lib/rubydb/storage/buffer_frame.rb +44 -44
  403. data/lib/rubydb/storage/buffer_pool.rb +155 -155
  404. data/lib/rubydb/storage/database_lock.rb +74 -74
  405. data/lib/rubydb/storage/deserializer.rb +332 -342
  406. data/lib/rubydb/storage/engine.rb +2409 -2330
  407. data/lib/rubydb/storage/file_manager.rb +191 -187
  408. data/lib/rubydb/storage/free_space_map.rb +79 -81
  409. data/lib/rubydb/storage/page.rb +92 -94
  410. data/lib/rubydb/storage/page_allocator.rb +852 -855
  411. data/lib/rubydb/storage/page_header.rb +63 -67
  412. data/lib/rubydb/storage/page_manager.rb +127 -131
  413. data/lib/rubydb/storage/record.rb +58 -58
  414. data/lib/rubydb/storage/row.rb +78 -78
  415. data/lib/rubydb/storage/serializer.rb +51 -51
  416. data/lib/rubydb/storage/snapshot_reader.rb +167 -0
  417. data/lib/rubydb/storage/storage_layout.rb +151 -151
  418. data/lib/rubydb/storage/storage_manager.rb +114 -114
  419. data/lib/rubydb/storage/tuple.rb +458 -461
  420. data/lib/rubydb/storage/visibility_map.rb +964 -973
  421. data/lib/rubydb/transactions/commit_manager.rb +219 -220
  422. data/lib/rubydb/transactions/isolation.rb +98 -98
  423. data/lib/rubydb/transactions/lock.rb +76 -76
  424. data/lib/rubydb/transactions/lock_manager.rb +359 -362
  425. data/lib/rubydb/transactions/savepoint.rb +142 -143
  426. data/lib/rubydb/transactions/transaction.rb +214 -215
  427. data/lib/rubydb/transactions/transaction_id.rb +84 -84
  428. data/lib/rubydb/transactions/transaction_log.rb +256 -257
  429. data/lib/rubydb/transactions/transaction_manager.rb +434 -435
  430. data/lib/rubydb/types/bigint.rb +36 -36
  431. data/lib/rubydb/types/blob.rb +37 -37
  432. data/lib/rubydb/types/boolean.rb +34 -34
  433. data/lib/rubydb/types/date.rb +39 -39
  434. data/lib/rubydb/types/decimal.rb +48 -48
  435. data/lib/rubydb/types/float.rb +34 -34
  436. data/lib/rubydb/types/integer.rb +36 -36
  437. data/lib/rubydb/types/json.rb +41 -41
  438. data/lib/rubydb/types/null.rb +34 -34
  439. data/lib/rubydb/types/smallint.rb +36 -36
  440. data/lib/rubydb/types/text.rb +37 -37
  441. data/lib/rubydb/types/time.rb +46 -46
  442. data/lib/rubydb/types/timestamp.rb +39 -39
  443. data/lib/rubydb/types/type.rb +119 -119
  444. data/lib/rubydb/types/uuid.rb +47 -47
  445. data/lib/rubydb/types/varchar.rb +37 -37
  446. data/lib/rubydb/version.rb +32 -32
  447. data/lib/rubydb/wal/archive.rb +207 -193
  448. data/lib/rubydb/wal/checkpoint.rb +181 -183
  449. data/lib/rubydb/wal/lsn.rb +94 -94
  450. data/lib/rubydb/wal/reader.rb +259 -260
  451. data/lib/rubydb/wal/record.rb +105 -105
  452. data/lib/rubydb/wal/segment.rb +193 -193
  453. data/lib/rubydb/wal/wal.rb +481 -452
  454. data/lib/rubydb/wal/writer.rb +236 -236
  455. data/lib/rubydb.rb +7 -7
  456. data/packaging/docker/docker-compose.failover.yml +43 -43
  457. data/packaging/homebrew/rubydb.rb +19 -19
  458. data/rubydb.gemspec +70 -57
  459. data/scripts/benchmark +7 -7
  460. data/scripts/build_accelerator +49 -0
  461. data/scripts/durability_drill +37 -37
  462. data/scripts/fuzz +63 -63
  463. data/scripts/release +77 -42
  464. data/scripts/release_check +43 -43
  465. data/scripts/replication_failover_drill +268 -250
  466. data/scripts/replication_network_failover_drill +287 -255
  467. data/scripts/restore_drill +45 -45
  468. data/scripts/security +45 -0
  469. metadata +102 -1
@@ -1,19 +1,19 @@
1
- # Installation
2
-
3
- RubyDB requires Ruby 3.3 or newer in the current support policy.
4
-
5
- ```sh
6
- gem install rubydb --pre
7
- ```
8
-
9
- From a checkout:
10
-
11
- ```sh
12
- bundle install
13
- bundle exec rspec
14
- ```
15
-
16
- For Rails, install the adapter from `adapters/activerecord` and use the
17
- configuration documented in `docs/rails/database-yml.md`. Pin RubyDB and Ruby
18
- versions in production and test the exact gem on a restored staging backup
19
- before deployment.
1
+ # Installation
2
+
3
+ RubyDB requires Ruby 3.3 or newer in the current support policy.
4
+
5
+ ```sh
6
+ gem install rubydb --pre
7
+ ```
8
+
9
+ From a checkout:
10
+
11
+ ```sh
12
+ bundle install
13
+ bundle exec rspec
14
+ ```
15
+
16
+ For Rails, install the adapter from `adapters/activerecord` and use the
17
+ configuration documented in `docs/rails/database-yml.md`. Pin RubyDB and Ruby
18
+ versions in production and test the exact gem on a restored staging backup
19
+ before deployment.
@@ -1,300 +1,300 @@
1
- # From local development to production
2
-
3
- This guide is for a beginner starting with a Ruby or Rails application. It
4
- shows two valid deployment choices:
5
-
6
- 1. develop with RubyDB locally and deploy with PostgreSQL; or
7
- 2. develop with RubyDB locally and keep RubyDB in production.
8
-
9
- The application code can be similar in both cases, but the database is not
10
- interchangeable by copying files. Choose the production database before
11
- launch, run the application’s migrations and query tests against it, and make
12
- backups before importing important data.
13
-
14
- ## Which path should I choose?
15
-
16
- | Goal | Local database | Production database | Recommended when |
17
- | --- | --- | --- | --- |
18
- | Learn/build quickly | RubyDB embedded | PostgreSQL | You want the broadest hosting and Rails ecosystem |
19
- | Keep one Ruby-native database | RubyDB embedded | RubyDB server | Your SQL/workload fits RubyDB and you can operate the server |
20
- | Prototype only | RubyDB embedded | RubyDB embedded | One process owns the path and data is non-critical |
21
-
22
- For a public or business-critical application, PostgreSQL is the safer default
23
- until RubyDB has been validated against your complete workload, backup/restore
24
- process, concurrency, and failover requirements. RubyDB is not a complete
25
- PostgreSQL or SQLite replacement.
26
-
27
- ## Part 1: local Rails development with RubyDB
28
-
29
- ### 1. Add the gems
30
-
31
- In the Rails application `Gemfile`:
32
-
33
- ```ruby
34
- gem "rubydb"
35
- gem "rubydb-activerecord"
36
- gem "pg" # Keep this if PostgreSQL is a possible production target.
37
- ```
38
-
39
- Run:
40
-
41
- ```sh
42
- bundle install
43
- ```
44
-
45
- ### 2. Configure development and test
46
-
47
- Use an embedded path for local development. Only the Rails process should own
48
- each path:
49
-
50
- ```yaml
51
- default: &default
52
- adapter: rubydb
53
- embedded: true
54
- database: <%= Rails.root.join("tmp/rubydb_development.rdb") %>
55
- pool: <%= ENV.fetch("RAILS_MAX_THREADS", "5") %>
56
-
57
- development:
58
- <<: *default
59
-
60
- test:
61
- <<: *default
62
- database: <%= Rails.root.join("tmp/rubydb_test.rdb") %>
63
- ```
64
-
65
- Use separate development and test paths. Do not put the database under a
66
- source-controlled directory. Do not let a web server, job worker, and console
67
- open the same embedded path at the same time.
68
-
69
- ### 3. Create the schema and run the app
70
-
71
- ```sh
72
- bin/rails db:create
73
- bin/rails db:migrate
74
- bin/rails db:seed # only if your seed data is safe to recreate
75
- bin/rails test
76
- bin/rails server
77
- ```
78
-
79
- Exercise real application flows: sign-up, login, CRUD, joins, eager loading,
80
- background jobs, file metadata, transactions, and error handling. Do not test
81
- only that the server boots.
82
-
83
- ### 4. Use RubyDB in a regular Ruby app
84
-
85
- Local single-process code can use the embedded engine:
86
-
87
- ```ruby
88
- require "rubydb"
89
-
90
- engine = RubyDB::Storage::Engine.new("tmp/app.rdb")
91
- begin
92
- engine.execute("CREATE TABLE IF NOT EXISTS events (id INTEGER PRIMARY KEY, name TEXT)")
93
- engine.execute("INSERT INTO events (name) VALUES (?)", ["boot"])
94
- p engine.execute("SELECT * FROM events")
95
- ensure
96
- engine.close
97
- end
98
- ```
99
-
100
- For multiple processes, use the client/server connection described below.
101
-
102
- ## Part 2A: deploy the same app on PostgreSQL
103
-
104
- This path keeps RubyDB for local development and uses PostgreSQL in production.
105
- It is a database migration, not a file copy.
106
-
107
- ### 1. Configure the production Rails block
108
-
109
- ```yaml
110
- production:
111
- adapter: postgresql
112
- url: <%= ENV.fetch("DATABASE_URL") %>
113
- pool: <%= ENV.fetch("RAILS_MAX_THREADS", "5") %>
114
- ```
115
-
116
- The hosting provider supplies a PostgreSQL URL such as:
117
-
118
- ```text
119
- postgresql://app_user:password@postgres.example.com:5432/my_app
120
- ```
121
-
122
- Keep `DATABASE_URL` in the provider’s secret settings. Never commit it.
123
-
124
- ### 2. Review the schema and SQL
125
-
126
- Before switching, review RubyDB-specific behavior:
127
-
128
- * integer primary-key/autoincrement behavior;
129
- * `BOOLEAN`, `JSON`, `UUID`, dates, timestamps, and decimals;
130
- * indexes, foreign keys, check constraints, and defaults;
131
- * `NULL`, ordering, grouping, joins, upserts, and functions;
132
- * migrations that alter populated tables; and
133
- * raw SQL, extensions, pragmas, and database-specific functions.
134
-
135
- Run `db:schema:dump` and inspect the generated schema. Do not assume every
136
- RubyDB schema statement is valid PostgreSQL syntax. Fix migrations or use
137
- adapter-specific migrations deliberately and document the difference.
138
-
139
- ### 3. Transfer data safely
140
-
141
- RubyDB `.rdb` files cannot be opened by PostgreSQL. A safe small-dataset flow is:
142
-
143
- 1. stop writes to the RubyDB application;
144
- 2. create a verified RubyDB backup;
145
- 3. create the PostgreSQL database and run reviewed migrations;
146
- 4. export each table in a deterministic order, including parent tables first;
147
- 5. transform types and IDs explicitly;
148
- 6. import into PostgreSQL using bound/escaped data or PostgreSQL `COPY`;
149
- 7. compare row counts, checksums, foreign keys, indexes, and business totals;
150
- 8. run the application test and smoke suite against PostgreSQL; and
151
- 9. switch traffic only after the verification report is approved.
152
-
153
- For large or live data, use a purpose-built migration process with checkpoints,
154
- retries, idempotency, and a cutover plan. Do not write a one-off script that
155
- silently skips a row or converts an unknown type to text.
156
-
157
- ### 4. Test production configuration before cutover
158
-
159
- ```sh
160
- RAILS_ENV=production DATABASE_URL='postgresql://...' bin/rails db:migrate
161
- RAILS_ENV=production DATABASE_URL='postgresql://...' bin/rails db:seed
162
- RAILS_ENV=production DATABASE_URL='postgresql://...' bin/rails test
163
- ```
164
-
165
- Run this against a restored staging database, not the only production copy.
166
- Keep the RubyDB backup until PostgreSQL row counts and application behavior
167
- have been accepted.
168
-
169
- ## Part 2B: deploy RubyDB in production
170
-
171
- This path runs one managed RubyDB server and connects Rails/Ruby processes to it
172
- over the RubyDB protocol. The application never opens the server’s data file.
173
-
174
- ### 1. Provision a database host
175
-
176
- Install a pinned RubyDB release, create a dedicated service account, and attach
177
- persistent storage. The data directory must survive process restarts and
178
- deploys. Keep backups on a separate system or failure domain.
179
-
180
- ```sh
181
- gem install rubydb -v 0.1.0
182
- install -d -o rubydb -g rubydb -m 0700 /var/lib/rubydb/data
183
- install -d -o rubydb -g rubydb -m 0750 /var/log/rubydb
184
- ```
185
-
186
- Use the complete setup in the [production operations guide](../operations/production-guide.md)
187
- for service supervision, TLS, authentication, resource limits, backups, and
188
- monitoring.
189
-
190
- ### 2. Start the RubyDB server
191
-
192
- Use a reviewed production configuration with WAL, authentication, TLS, and
193
- bounded resources:
194
-
195
- ```sh
196
- rubydb --config /etc/rubydb/production.yml --env production start
197
- ```
198
-
199
- Keep port `7432` on a private network. Verify the server before connecting the
200
- application:
201
-
202
- ```sh
203
- rubydb --config /etc/rubydb/production.yml --env production status --json
204
- rubydb --config /etc/rubydb/production.yml --env production doctor --json
205
- ```
206
-
207
- ### 3. Put one RubyDB URL in the application environment
208
-
209
- RubyDB supports its own URL format. `rubydbs` enables TLS:
210
-
211
- ```text
212
- RUBYDB_URL=rubydbs://app_user:URL_ENCODED_PASSWORD@db.internal.example:7432/my_app?verify_peer=true&ca_file=%2Fetc%2Frubydb%2Fca.crt
213
- ```
214
-
215
- Special characters in usernames and passwords must be percent-encoded. Store
216
- the complete value in a secret manager. Do not print it during deploys.
217
-
218
- ### 4. Configure Rails
219
-
220
- ```yaml
221
- production:
222
- adapter: rubydb
223
- embedded: false
224
- url: <%= ENV.fetch("RUBYDB_URL") %>
225
- pool: <%= ENV.fetch("RAILS_MAX_THREADS", "5") %>
226
- ```
227
-
228
- Run the migration once from a controlled release job:
229
-
230
- ```sh
231
- RAILS_ENV=production bundle exec rails db:migrate
232
- RAILS_ENV=production bundle exec rails runner 'puts User.count'
233
- ```
234
-
235
- Do not run migrations simultaneously from every web process. Confirm that the
236
- Rails pool fits below the RubyDB server connection limit with room for workers,
237
- monitoring, and administration.
238
-
239
- ### 5. Configure regular Ruby
240
-
241
- ```ruby
242
- require "rubydb"
243
-
244
- client = RubyDB::Client::Client.new(url: ENV.fetch("RUBYDB_URL"))
245
- begin
246
- result = client.query("SELECT 1")
247
- puts result.to_hash
248
- ensure
249
- client.disconnect
250
- end
251
- ```
252
-
253
- Use idempotency keys for retried writes. A timeout or broken connection does
254
- not prove that a write was rolled back; check the operation outcome before
255
- retrying a non-idempotent request.
256
-
257
- ### 6. Perform a production smoke test
258
-
259
- Before routing users:
260
-
261
- ```sh
262
- RAILS_ENV=production bundle exec rails db:migrate:status
263
- RAILS_ENV=production bundle exec rails runner 'puts User.limit(1).to_a.inspect'
264
- rubydb --config /etc/rubydb/production.yml --env production doctor --json
265
- ```
266
-
267
- Then test one authenticated read, one create/update/delete transaction, one
268
- background job, one backup, and one restore into a separate directory. Confirm
269
- logs, metrics, disk alerts, WAL/checkpoint state, and rollback ownership.
270
-
271
- ## Render-style cloud deployment
272
-
273
- On a platform such as Render, use a private service for the RubyDB server and a
274
- web service for Rails. Attach a persistent disk to the RubyDB service and set
275
- `RUBYDB_URL` on the Rails service. Keep both services in the same region and
276
- use the private hostname. A platform’s default filesystem is often ephemeral;
277
- verify the provider’s storage behavior before using it for database files.
278
-
279
- A single persistent disk normally means one RubyDB primary instance. Do not
280
- assume that increasing the web-service instance count creates database
281
- high availability. Maintain external backups and validate failover separately.
282
-
283
- ## Final beginner checklist
284
-
285
- Before calling the app production-ready, confirm:
286
-
287
- * the production database choice is written down;
288
- * all application SQL and migrations pass against that database;
289
- * credentials are environment/secret-manager values, not source files;
290
- * RubyDB uses server mode when more than one process connects;
291
- * TLS, authentication, private networking, and least privilege are enabled;
292
- * a verified backup can be restored on another directory or host;
293
- * monitoring and alerts are visible to an on-call owner;
294
- * connection, lock, request, and shutdown timeouts are bounded; and
295
- * rollback, data migration, and incident procedures have been rehearsed.
296
-
297
- For deeper details, continue with [Rails compatibility](../rails/compatibility-guide.md),
298
- [production operations](../operations/production-guide.md),
299
- [troubleshooting](../troubleshooting.md), and [debugging](../debugging.md).
300
-
1
+ # From local development to production
2
+
3
+ This guide is for a beginner starting with a Ruby or Rails application. It
4
+ shows two valid deployment choices:
5
+
6
+ 1. develop with RubyDB locally and deploy with PostgreSQL; or
7
+ 2. develop with RubyDB locally and keep RubyDB in production.
8
+
9
+ The application code can be similar in both cases, but the database is not
10
+ interchangeable by copying files. Choose the production database before
11
+ launch, run the application’s migrations and query tests against it, and make
12
+ backups before importing important data.
13
+
14
+ ## Which path should I choose?
15
+
16
+ | Goal | Local database | Production database | Recommended when |
17
+ | --- | --- | --- | --- |
18
+ | Learn/build quickly | RubyDB embedded | PostgreSQL | You want the broadest hosting and Rails ecosystem |
19
+ | Keep one Ruby-native database | RubyDB embedded | RubyDB server | Your SQL/workload fits RubyDB and you can operate the server |
20
+ | Prototype only | RubyDB embedded | RubyDB embedded | One process owns the path and data is non-critical |
21
+
22
+ For a public or business-critical application, PostgreSQL is the safer default
23
+ until RubyDB has been validated against your complete workload, backup/restore
24
+ process, concurrency, and failover requirements. RubyDB is not a complete
25
+ PostgreSQL or SQLite replacement.
26
+
27
+ ## Part 1: local Rails development with RubyDB
28
+
29
+ ### 1. Add the gems
30
+
31
+ In the Rails application `Gemfile`:
32
+
33
+ ```ruby
34
+ gem "rubydb"
35
+ gem "rubydb-activerecord"
36
+ gem "pg" # Keep this if PostgreSQL is a possible production target.
37
+ ```
38
+
39
+ Run:
40
+
41
+ ```sh
42
+ bundle install
43
+ ```
44
+
45
+ ### 2. Configure development and test
46
+
47
+ Use an embedded path for local development. Only the Rails process should own
48
+ each path:
49
+
50
+ ```yaml
51
+ default: &default
52
+ adapter: rubydb
53
+ embedded: true
54
+ database: <%= Rails.root.join("tmp/rubydb_development.rdb") %>
55
+ pool: <%= ENV.fetch("RAILS_MAX_THREADS", "5") %>
56
+
57
+ development:
58
+ <<: *default
59
+
60
+ test:
61
+ <<: *default
62
+ database: <%= Rails.root.join("tmp/rubydb_test.rdb") %>
63
+ ```
64
+
65
+ Use separate development and test paths. Do not put the database under a
66
+ source-controlled directory. Do not let a web server, job worker, and console
67
+ open the same embedded path at the same time.
68
+
69
+ ### 3. Create the schema and run the app
70
+
71
+ ```sh
72
+ bin/rails db:create
73
+ bin/rails db:migrate
74
+ bin/rails db:seed # only if your seed data is safe to recreate
75
+ bin/rails test
76
+ bin/rails server
77
+ ```
78
+
79
+ Exercise real application flows: sign-up, login, CRUD, joins, eager loading,
80
+ background jobs, file metadata, transactions, and error handling. Do not test
81
+ only that the server boots.
82
+
83
+ ### 4. Use RubyDB in a regular Ruby app
84
+
85
+ Local single-process code can use the embedded engine:
86
+
87
+ ```ruby
88
+ require "rubydb"
89
+
90
+ engine = RubyDB::Storage::Engine.new("tmp/app.rdb")
91
+ begin
92
+ engine.execute("CREATE TABLE IF NOT EXISTS events (id INTEGER PRIMARY KEY, name TEXT)")
93
+ engine.execute("INSERT INTO events (name) VALUES (?)", ["boot"])
94
+ p engine.execute("SELECT * FROM events")
95
+ ensure
96
+ engine.close
97
+ end
98
+ ```
99
+
100
+ For multiple processes, use the client/server connection described below.
101
+
102
+ ## Part 2A: deploy the same app on PostgreSQL
103
+
104
+ This path keeps RubyDB for local development and uses PostgreSQL in production.
105
+ It is a database migration, not a file copy.
106
+
107
+ ### 1. Configure the production Rails block
108
+
109
+ ```yaml
110
+ production:
111
+ adapter: postgresql
112
+ url: <%= ENV.fetch("DATABASE_URL") %>
113
+ pool: <%= ENV.fetch("RAILS_MAX_THREADS", "5") %>
114
+ ```
115
+
116
+ The hosting provider supplies a PostgreSQL URL such as:
117
+
118
+ ```text
119
+ postgresql://app_user:password@postgres.example.com:5432/my_app
120
+ ```
121
+
122
+ Keep `DATABASE_URL` in the provider’s secret settings. Never commit it.
123
+
124
+ ### 2. Review the schema and SQL
125
+
126
+ Before switching, review RubyDB-specific behavior:
127
+
128
+ * integer primary-key/autoincrement behavior;
129
+ * `BOOLEAN`, `JSON`, `UUID`, dates, timestamps, and decimals;
130
+ * indexes, foreign keys, check constraints, and defaults;
131
+ * `NULL`, ordering, grouping, joins, upserts, and functions;
132
+ * migrations that alter populated tables; and
133
+ * raw SQL, extensions, pragmas, and database-specific functions.
134
+
135
+ Run `db:schema:dump` and inspect the generated schema. Do not assume every
136
+ RubyDB schema statement is valid PostgreSQL syntax. Fix migrations or use
137
+ adapter-specific migrations deliberately and document the difference.
138
+
139
+ ### 3. Transfer data safely
140
+
141
+ RubyDB `.rdb` files cannot be opened by PostgreSQL. A safe small-dataset flow is:
142
+
143
+ 1. stop writes to the RubyDB application;
144
+ 2. create a verified RubyDB backup;
145
+ 3. create the PostgreSQL database and run reviewed migrations;
146
+ 4. export each table in a deterministic order, including parent tables first;
147
+ 5. transform types and IDs explicitly;
148
+ 6. import into PostgreSQL using bound/escaped data or PostgreSQL `COPY`;
149
+ 7. compare row counts, checksums, foreign keys, indexes, and business totals;
150
+ 8. run the application test and smoke suite against PostgreSQL; and
151
+ 9. switch traffic only after the verification report is approved.
152
+
153
+ For large or live data, use a purpose-built migration process with checkpoints,
154
+ retries, idempotency, and a cutover plan. Do not write a one-off script that
155
+ silently skips a row or converts an unknown type to text.
156
+
157
+ ### 4. Test production configuration before cutover
158
+
159
+ ```sh
160
+ RAILS_ENV=production DATABASE_URL='postgresql://...' bin/rails db:migrate
161
+ RAILS_ENV=production DATABASE_URL='postgresql://...' bin/rails db:seed
162
+ RAILS_ENV=production DATABASE_URL='postgresql://...' bin/rails test
163
+ ```
164
+
165
+ Run this against a restored staging database, not the only production copy.
166
+ Keep the RubyDB backup until PostgreSQL row counts and application behavior
167
+ have been accepted.
168
+
169
+ ## Part 2B: deploy RubyDB in production
170
+
171
+ This path runs one managed RubyDB server and connects Rails/Ruby processes to it
172
+ over the RubyDB protocol. The application never opens the server’s data file.
173
+
174
+ ### 1. Provision a database host
175
+
176
+ Install a pinned RubyDB release, create a dedicated service account, and attach
177
+ persistent storage. The data directory must survive process restarts and
178
+ deploys. Keep backups on a separate system or failure domain.
179
+
180
+ ```sh
181
+ gem install rubydb -v 0.1.0
182
+ install -d -o rubydb -g rubydb -m 0700 /var/lib/rubydb/data
183
+ install -d -o rubydb -g rubydb -m 0750 /var/log/rubydb
184
+ ```
185
+
186
+ Use the complete setup in the [production operations guide](../operations/production-guide.md)
187
+ for service supervision, TLS, authentication, resource limits, backups, and
188
+ monitoring.
189
+
190
+ ### 2. Start the RubyDB server
191
+
192
+ Use a reviewed production configuration with WAL, authentication, TLS, and
193
+ bounded resources:
194
+
195
+ ```sh
196
+ rubydb --config /etc/rubydb/production.yml --env production start
197
+ ```
198
+
199
+ Keep port `7432` on a private network. Verify the server before connecting the
200
+ application:
201
+
202
+ ```sh
203
+ rubydb --config /etc/rubydb/production.yml --env production status --json
204
+ rubydb --config /etc/rubydb/production.yml --env production doctor --json
205
+ ```
206
+
207
+ ### 3. Put one RubyDB URL in the application environment
208
+
209
+ RubyDB supports its own URL format. `rubydbs` enables TLS:
210
+
211
+ ```text
212
+ RUBYDB_URL=rubydbs://app_user:URL_ENCODED_PASSWORD@db.internal.example:7432/my_app?verify_peer=true&ca_file=%2Fetc%2Frubydb%2Fca.crt
213
+ ```
214
+
215
+ Special characters in usernames and passwords must be percent-encoded. Store
216
+ the complete value in a secret manager. Do not print it during deploys.
217
+
218
+ ### 4. Configure Rails
219
+
220
+ ```yaml
221
+ production:
222
+ adapter: rubydb
223
+ embedded: false
224
+ url: <%= ENV.fetch("RUBYDB_URL") %>
225
+ pool: <%= ENV.fetch("RAILS_MAX_THREADS", "5") %>
226
+ ```
227
+
228
+ Run the migration once from a controlled release job:
229
+
230
+ ```sh
231
+ RAILS_ENV=production bundle exec rails db:migrate
232
+ RAILS_ENV=production bundle exec rails runner 'puts User.count'
233
+ ```
234
+
235
+ Do not run migrations simultaneously from every web process. Confirm that the
236
+ Rails pool fits below the RubyDB server connection limit with room for workers,
237
+ monitoring, and administration.
238
+
239
+ ### 5. Configure regular Ruby
240
+
241
+ ```ruby
242
+ require "rubydb"
243
+
244
+ client = RubyDB::Client::Client.new(url: ENV.fetch("RUBYDB_URL"))
245
+ begin
246
+ result = client.query("SELECT 1")
247
+ puts result.to_hash
248
+ ensure
249
+ client.disconnect
250
+ end
251
+ ```
252
+
253
+ Use idempotency keys for retried writes. A timeout or broken connection does
254
+ not prove that a write was rolled back; check the operation outcome before
255
+ retrying a non-idempotent request.
256
+
257
+ ### 6. Perform a production smoke test
258
+
259
+ Before routing users:
260
+
261
+ ```sh
262
+ RAILS_ENV=production bundle exec rails db:migrate:status
263
+ RAILS_ENV=production bundle exec rails runner 'puts User.limit(1).to_a.inspect'
264
+ rubydb --config /etc/rubydb/production.yml --env production doctor --json
265
+ ```
266
+
267
+ Then test one authenticated read, one create/update/delete transaction, one
268
+ background job, one backup, and one restore into a separate directory. Confirm
269
+ logs, metrics, disk alerts, WAL/checkpoint state, and rollback ownership.
270
+
271
+ ## Render-style cloud deployment
272
+
273
+ On a platform such as Render, use a private service for the RubyDB server and a
274
+ web service for Rails. Attach a persistent disk to the RubyDB service and set
275
+ `RUBYDB_URL` on the Rails service. Keep both services in the same region and
276
+ use the private hostname. A platform’s default filesystem is often ephemeral;
277
+ verify the provider’s storage behavior before using it for database files.
278
+
279
+ A single persistent disk normally means one RubyDB primary instance. Do not
280
+ assume that increasing the web-service instance count creates database
281
+ high availability. Maintain external backups and validate failover separately.
282
+
283
+ ## Final beginner checklist
284
+
285
+ Before calling the app production-ready, confirm:
286
+
287
+ * the production database choice is written down;
288
+ * all application SQL and migrations pass against that database;
289
+ * credentials are environment/secret-manager values, not source files;
290
+ * RubyDB uses server mode when more than one process connects;
291
+ * TLS, authentication, private networking, and least privilege are enabled;
292
+ * a verified backup can be restored on another directory or host;
293
+ * monitoring and alerts are visible to an on-call owner;
294
+ * connection, lock, request, and shutdown timeouts are bounded; and
295
+ * rollback, data migration, and incident procedures have been rehearsed.
296
+
297
+ For deeper details, continue with [Rails compatibility](../rails/compatibility-guide.md),
298
+ [production operations](../operations/production-guide.md),
299
+ [troubleshooting](../troubleshooting.md), and [debugging](../debugging.md).
300
+