rubydb 0.1.3 → 0.1.5

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 (420) 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 +12 -5
  14. data/.rubocop.yml +50 -44
  15. data/.standard.yml +9 -14
  16. data/ARCHITECTURE.md +21 -21
  17. data/CHANGELOG.md +49 -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 +249 -162
  24. data/ROADMAP.md +27 -27
  25. data/Rakefile +71 -71
  26. data/SECURITY.md +54 -54
  27. data/SUPPORT.md +14 -14
  28. data/adapters/activerecord/Gemfile +11 -11
  29. data/adapters/activerecord/lib/active_record/connection_adapters/rubydb_adapter.rb +877 -880
  30. data/adapters/activerecord/rubydb-activerecord.gemspec +21 -21
  31. data/adapters/activerecord/spec/rubydb_adapter_integration_spec.rb +155 -143
  32. data/adapters/ruby/README.md +18 -18
  33. data/adapters/sequel/README.md +11 -11
  34. data/config/monitoring/prometheus-alerts.yml +39 -39
  35. data/config/production.yml +36 -36
  36. data/docs/README.md +75 -71
  37. data/docs/architecture/concurrency.md +14 -14
  38. data/docs/architecture/current-state.md +125 -125
  39. data/docs/architecture/execution-engine.md +25 -25
  40. data/docs/architecture/indexes.md +19 -19
  41. data/docs/architecture/mvcc.md +19 -19
  42. data/docs/architecture/overview.md +13 -13
  43. data/docs/architecture/pages.md +11 -11
  44. data/docs/architecture/production-roadmap.md +82 -82
  45. data/docs/architecture/query-planner.md +20 -20
  46. data/docs/architecture/recovery.md +18 -18
  47. data/docs/architecture/sql-engine.md +12 -12
  48. data/docs/architecture/storage-engine.md +14 -14
  49. data/docs/architecture/transactions.md +10 -10
  50. data/docs/architecture/wal.md +28 -28
  51. data/docs/cli-cheatsheet.md +98 -98
  52. data/docs/cli.md +275 -275
  53. data/docs/contributing/architecture.md +9 -9
  54. data/docs/contributing/benchmarking.md +14 -14
  55. data/docs/contributing/development.md +16 -16
  56. data/docs/contributing/release-process.md +49 -49
  57. data/docs/contributing/testing.md +16 -16
  58. data/docs/debugging.md +229 -229
  59. data/docs/developer/branching.md +10 -10
  60. data/docs/developer/database-diff.md +10 -10
  61. data/docs/developer/local-development.md +17 -17
  62. data/docs/developer/snapshots.md +9 -9
  63. data/docs/developer/temporal-data.md +10 -10
  64. data/docs/developer-guide.md +297 -297
  65. data/docs/getting-started/first-database.md +16 -16
  66. data/docs/getting-started/first-query.md +13 -13
  67. data/docs/getting-started/installation.md +19 -19
  68. data/docs/getting-started/local-to-production.md +300 -300
  69. data/docs/getting-started/quickstart.md +17 -17
  70. data/docs/getting-started/rails.md +16 -16
  71. data/docs/hardening_backlog.md +93 -93
  72. data/docs/lessons-learned.md +112 -112
  73. data/docs/operations/backups.md +33 -33
  74. data/docs/operations/disaster-recovery.md +31 -31
  75. data/docs/operations/failover.md +30 -30
  76. data/docs/operations/monitoring.md +25 -25
  77. data/docs/operations/production-guide.md +295 -295
  78. data/docs/operations/production-runbook.md +45 -45
  79. data/docs/operations/replication.md +33 -33
  80. data/docs/operations/restore.md +6 -6
  81. data/docs/operations/runbook.md +34 -34
  82. data/docs/operations/upgrades.md +14 -14
  83. data/docs/operations/workload-testing.md +17 -17
  84. data/docs/production-readiness.md +118 -118
  85. data/docs/production_validation.md +150 -150
  86. data/docs/rails/active-record.md +11 -11
  87. data/docs/rails/compatibility-guide.md +90 -90
  88. data/docs/rails/database-yml.md +92 -92
  89. data/docs/rails/installation.md +17 -17
  90. data/docs/rails/migrations.md +17 -17
  91. data/docs/rails/production.md +82 -82
  92. data/docs/rails/troubleshooting.md +18 -18
  93. data/docs/release.md +25 -25
  94. data/docs/server/architecture.md +10 -10
  95. data/docs/server/authentication.md +10 -10
  96. data/docs/server/configuration.md +16 -16
  97. data/docs/server/connection-pooling.md +10 -10
  98. data/docs/server/deployment.md +10 -10
  99. data/docs/server/protocol.md +12 -12
  100. data/docs/sql/compatibility-guide.md +82 -82
  101. data/docs/sql/compatibility.md +39 -39
  102. data/docs/sql/data-types.md +10 -10
  103. data/docs/sql/functions.md +9 -9
  104. data/docs/sql/joins.md +9 -9
  105. data/docs/sql/operators.md +9 -9
  106. data/docs/sql/sqlite-compatibility.md +21 -21
  107. data/docs/sql/syntax.md +10 -10
  108. data/docs/sql/transactions.md +10 -10
  109. data/docs/troubleshooting.md +244 -244
  110. data/lessons/01-foundations.md +73 -0
  111. data/lessons/02-local-development.md +121 -0
  112. data/lessons/03-embedded-rubydb.md +99 -0
  113. data/lessons/04-rails-complex-apps.md +138 -0
  114. data/lessons/05-rubydb-production-server.md +237 -0
  115. data/lessons/06-postgresql-massive-apps.md +96 -0
  116. data/lessons/07-hybrid-microservices.md +94 -0
  117. data/lessons/08-migrations-backups-recovery.md +86 -0
  118. data/lessons/09-observability-security-scale.md +87 -0
  119. data/lessons/10-release-readiness.md +125 -0
  120. data/lib/rubydb/backup/archive.rb +332 -334
  121. data/lib/rubydb/backup/backup.rb +400 -401
  122. data/lib/rubydb/backup/incremental.rb +349 -353
  123. data/lib/rubydb/backup/restore.rb +289 -290
  124. data/lib/rubydb/backup/snapshot.rb +265 -267
  125. data/lib/rubydb/backup/verification.rb +276 -279
  126. data/lib/rubydb/branching/branch.rb +181 -181
  127. data/lib/rubydb/branching/branch_manager.rb +307 -311
  128. data/lib/rubydb/branching/branch_metadata.rb +140 -140
  129. data/lib/rubydb/branching/checkout.rb +165 -166
  130. data/lib/rubydb/branching/copy_on_write.rb +272 -272
  131. data/lib/rubydb/branching/diff.rb +137 -138
  132. data/lib/rubydb/branching/merge.rb +282 -285
  133. data/lib/rubydb/build_info.rb +15 -15
  134. data/lib/rubydb/catalog/catalog.rb +391 -391
  135. data/lib/rubydb/catalog/column.rb +112 -112
  136. data/lib/rubydb/catalog/constraint.rb +180 -180
  137. data/lib/rubydb/catalog/database.rb +184 -184
  138. data/lib/rubydb/catalog/index.rb +97 -97
  139. data/lib/rubydb/catalog/schema.rb +103 -103
  140. data/lib/rubydb/catalog/sequence.rb +90 -90
  141. data/lib/rubydb/catalog/system_catalog.rb +698 -698
  142. data/lib/rubydb/catalog/table.rb +178 -178
  143. data/lib/rubydb/catalog/trigger.rb +102 -102
  144. data/lib/rubydb/catalog/view.rb +66 -66
  145. data/lib/rubydb/cli/application.rb +163 -163
  146. data/lib/rubydb/cli/commands/backup.rb +80 -81
  147. data/lib/rubydb/cli/commands/branch.rb +72 -72
  148. data/lib/rubydb/cli/commands/checkout.rb +54 -54
  149. data/lib/rubydb/cli/commands/create.rb +58 -58
  150. data/lib/rubydb/cli/commands/diff.rb +76 -77
  151. data/lib/rubydb/cli/commands/doctor.rb +74 -74
  152. data/lib/rubydb/cli/commands/drop.rb +57 -57
  153. data/lib/rubydb/cli/commands/init.rb +101 -102
  154. data/lib/rubydb/cli/commands/inspect.rb +95 -95
  155. data/lib/rubydb/cli/commands/merge.rb +63 -63
  156. data/lib/rubydb/cli/commands/migrate.rb +62 -62
  157. data/lib/rubydb/cli/commands/restart.rb +42 -39
  158. data/lib/rubydb/cli/commands/restore.rb +121 -121
  159. data/lib/rubydb/cli/commands/shell.rb +365 -365
  160. data/lib/rubydb/cli/commands/snapshot.rb +79 -79
  161. data/lib/rubydb/cli/commands/start.rb +88 -82
  162. data/lib/rubydb/cli/commands/status.rb +96 -92
  163. data/lib/rubydb/cli/commands/stop.rb +47 -47
  164. data/lib/rubydb/cli/commands/vacuum.rb +58 -58
  165. data/lib/rubydb/cli/formatter.rb +221 -221
  166. data/lib/rubydb/cli/output.rb +168 -168
  167. data/lib/rubydb/client/client.rb +302 -304
  168. data/lib/rubydb/client/connection.rb +414 -415
  169. data/lib/rubydb/client/connection_pool.rb +168 -168
  170. data/lib/rubydb/client/connection_url.rb +96 -96
  171. data/lib/rubydb/client/prepared_statement.rb +60 -60
  172. data/lib/rubydb/client/result.rb +123 -123
  173. data/lib/rubydb/client/statement.rb +52 -52
  174. data/lib/rubydb/client/transaction.rb +130 -130
  175. data/lib/rubydb/concurrency/concurrency.rb +19 -19
  176. data/lib/rubydb/concurrency/deadlock_detector.rb +148 -150
  177. data/lib/rubydb/concurrency/latch.rb +101 -101
  178. data/lib/rubydb/concurrency/lock_graph.rb +163 -165
  179. data/lib/rubydb/concurrency/mutex.rb +181 -183
  180. data/lib/rubydb/concurrency/rw_lock.rb +180 -180
  181. data/lib/rubydb/concurrency/scheduler.rb +248 -250
  182. data/lib/rubydb/concurrency/worker_pool.rb +145 -143
  183. data/lib/rubydb/configuration/config.rb +170 -170
  184. data/lib/rubydb/configuration/defaults.rb +179 -179
  185. data/lib/rubydb/configuration/environment.rb +152 -152
  186. data/lib/rubydb/configuration/parser.rb +185 -185
  187. data/lib/rubydb/configuration/validation.rb +221 -221
  188. data/lib/rubydb/constants.rb +74 -74
  189. data/lib/rubydb/constraints/check.rb +181 -181
  190. data/lib/rubydb/constraints/constraint.rb +101 -101
  191. data/lib/rubydb/constraints/foreign_key.rb +130 -130
  192. data/lib/rubydb/constraints/not_null.rb +64 -64
  193. data/lib/rubydb/constraints/primary_key.rb +99 -99
  194. data/lib/rubydb/constraints/unique.rb +106 -108
  195. data/lib/rubydb/constraints/validator.rb +349 -350
  196. data/lib/rubydb/errors/authentication_error.rb +10 -10
  197. data/lib/rubydb/errors/authorization_error.rb +23 -23
  198. data/lib/rubydb/errors/client_error.rb +10 -10
  199. data/lib/rubydb/errors/configuration_error.rb +10 -10
  200. data/lib/rubydb/errors/connection_error.rb +10 -10
  201. data/lib/rubydb/errors/constraint_error.rb +23 -23
  202. data/lib/rubydb/errors/corruption_error.rb +10 -10
  203. data/lib/rubydb/errors/database_error.rb +10 -10
  204. data/lib/rubydb/errors/error.rb +20 -20
  205. data/lib/rubydb/errors/execution_error.rb +10 -10
  206. data/lib/rubydb/errors/parser_error.rb +10 -10
  207. data/lib/rubydb/errors/recovery_error.rb +10 -10
  208. data/lib/rubydb/errors/replication_error.rb +10 -10
  209. data/lib/rubydb/errors/server_error.rb +6 -6
  210. data/lib/rubydb/errors/storage_error.rb +10 -10
  211. data/lib/rubydb/errors/transaction_error.rb +10 -10
  212. data/lib/rubydb/execution/aggregate_executor.rb +134 -138
  213. data/lib/rubydb/execution/delete_executor.rb +110 -112
  214. data/lib/rubydb/execution/distinct_executor.rb +131 -135
  215. data/lib/rubydb/execution/executor.rb +1195 -1192
  216. data/lib/rubydb/execution/expression.rb +191 -193
  217. data/lib/rubydb/execution/index_scan.rb +142 -142
  218. data/lib/rubydb/execution/insert_executor.rb +215 -217
  219. data/lib/rubydb/execution/join_executor.rb +243 -249
  220. data/lib/rubydb/execution/limit_executor.rb +83 -85
  221. data/lib/rubydb/execution/optimizer.rb +227 -215
  222. data/lib/rubydb/execution/plan.rb +355 -353
  223. data/lib/rubydb/execution/planner.rb +542 -536
  224. data/lib/rubydb/execution/predicate.rb +235 -235
  225. data/lib/rubydb/execution/scan.rb +49 -49
  226. data/lib/rubydb/execution/sequential_scan.rb +63 -63
  227. data/lib/rubydb/execution/sort_executor.rb +180 -185
  228. data/lib/rubydb/execution/update_executor.rb +160 -162
  229. data/lib/rubydb/functions/aggregate.rb +70 -70
  230. data/lib/rubydb/functions/date_functions.rb +274 -278
  231. data/lib/rubydb/functions/function.rb +85 -85
  232. data/lib/rubydb/functions/json_functions.rb +231 -215
  233. data/lib/rubydb/functions/numeric_functions.rb +346 -346
  234. data/lib/rubydb/functions/scalar.rb +52 -52
  235. data/lib/rubydb/functions/string_functions.rb +383 -383
  236. data/lib/rubydb/functions/system_functions.rb +258 -246
  237. data/lib/rubydb/history/as_of.rb +238 -238
  238. data/lib/rubydb/history/change.rb +105 -105
  239. data/lib/rubydb/history/history.rb +131 -131
  240. data/lib/rubydb/history/history_manager.rb +228 -229
  241. data/lib/rubydb/history/temporal_query.rb +202 -202
  242. data/lib/rubydb/history/timeline.rb +144 -144
  243. data/lib/rubydb/indexes/btree.rb +186 -186
  244. data/lib/rubydb/indexes/btree_cursor.rb +258 -258
  245. data/lib/rubydb/indexes/btree_node.rb +384 -385
  246. data/lib/rubydb/indexes/hash_index.rb +150 -150
  247. data/lib/rubydb/indexes/index.rb +71 -71
  248. data/lib/rubydb/indexes/index_manager.rb +408 -406
  249. data/lib/rubydb/indexes/index_scan.rb +466 -470
  250. data/lib/rubydb/migrations/migration.rb +253 -254
  251. data/lib/rubydb/migrations/migration_lock.rb +146 -146
  252. data/lib/rubydb/migrations/migration_manager.rb +187 -176
  253. data/lib/rubydb/migrations/migration_version.rb +71 -71
  254. data/lib/rubydb/migrations/schema_diff.rb +211 -211
  255. data/lib/rubydb/migrations/schema_version.rb +64 -64
  256. data/lib/rubydb/monitoring/events.rb +155 -160
  257. data/lib/rubydb/monitoring/health.rb +216 -222
  258. data/lib/rubydb/monitoring/logger.rb +188 -193
  259. data/lib/rubydb/monitoring/metrics.rb +363 -359
  260. data/lib/rubydb/monitoring/performance.rb +176 -176
  261. data/lib/rubydb/monitoring/statistics.rb +168 -170
  262. data/lib/rubydb/mvcc/garbage_collector.rb +199 -199
  263. data/lib/rubydb/mvcc/mvcc.rb +16 -16
  264. data/lib/rubydb/mvcc/snapshot.rb +146 -147
  265. data/lib/rubydb/mvcc/vacuum.rb +180 -180
  266. data/lib/rubydb/mvcc/version.rb +106 -106
  267. data/lib/rubydb/mvcc/version_store.rb +396 -398
  268. data/lib/rubydb/mvcc/visibility.rb +107 -109
  269. data/lib/rubydb/protocol/capabilities.rb +125 -125
  270. data/lib/rubydb/protocol/decoder.rb +142 -145
  271. data/lib/rubydb/protocol/encoder.rb +131 -136
  272. data/lib/rubydb/protocol/handshake.rb +306 -305
  273. data/lib/rubydb/protocol/message.rb +121 -121
  274. data/lib/rubydb/protocol/parameter_binder.rb +101 -0
  275. data/lib/rubydb/protocol/protocol.rb +276 -277
  276. data/lib/rubydb/protocol/version.rb +54 -54
  277. data/lib/rubydb/rails/adapter.rb +245 -239
  278. data/lib/rubydb/rails/connection.rb +312 -314
  279. data/lib/rubydb/rails/database_statements.rb +122 -122
  280. data/lib/rubydb/rails/migration.rb +131 -131
  281. data/lib/rubydb/rails/quoting.rb +109 -109
  282. data/lib/rubydb/rails/result.rb +123 -120
  283. data/lib/rubydb/rails/schema_statements.rb +339 -339
  284. data/lib/rubydb/rails/transaction.rb +105 -105
  285. data/lib/rubydb/rails/type.rb +126 -126
  286. data/lib/rubydb/recovery/checkpoint.rb +261 -257
  287. data/lib/rubydb/recovery/consistency.rb +457 -467
  288. data/lib/rubydb/recovery/corruption_detector.rb +5 -5
  289. data/lib/rubydb/recovery/crash_recovery.rb +381 -387
  290. data/lib/rubydb/recovery/recovery_manager.rb +204 -206
  291. data/lib/rubydb/recovery/redo.rb +235 -237
  292. data/lib/rubydb/recovery/undo.rb +204 -206
  293. data/lib/rubydb/replication/failover.rb +5 -5
  294. data/lib/rubydb/replication/fencing.rb +63 -63
  295. data/lib/rubydb/replication/primary.rb +461 -450
  296. data/lib/rubydb/replication/replica.rb +382 -384
  297. data/lib/rubydb/replication/replication_log.rb +194 -200
  298. data/lib/rubydb/replication/replication_manager.rb +307 -308
  299. data/lib/rubydb/replication/replication_slot.rb +293 -295
  300. data/lib/rubydb/replication/replication_stream.rb +198 -201
  301. data/lib/rubydb/rubydb.rb +564 -560
  302. data/lib/rubydb/security/access_control.rb +252 -254
  303. data/lib/rubydb/security/audit_log.rb +209 -213
  304. data/lib/rubydb/security/authentication.rb +302 -302
  305. data/lib/rubydb/security/authorization.rb +282 -282
  306. data/lib/rubydb/security/credentials.rb +192 -196
  307. data/lib/rubydb/security/password.rb +205 -215
  308. data/lib/rubydb/security/permissions.rb +74 -74
  309. data/lib/rubydb/security/role.rb +99 -101
  310. data/lib/rubydb/security/user.rb +86 -86
  311. data/lib/rubydb/server/connection.rb +383 -366
  312. data/lib/rubydb/server/connection_pool.rb +193 -193
  313. data/lib/rubydb/server/lifecycle.rb +227 -228
  314. data/lib/rubydb/server/listener.rb +139 -136
  315. data/lib/rubydb/server/request_handler.rb +277 -276
  316. data/lib/rubydb/server/server.rb +363 -364
  317. data/lib/rubydb/server/session.rb +371 -369
  318. data/lib/rubydb/server/worker.rb +206 -210
  319. data/lib/rubydb/server/worker_pool.rb +168 -168
  320. data/lib/rubydb/sql/ast/alter_table.rb +169 -169
  321. data/lib/rubydb/sql/ast/begin_transaction.rb +47 -47
  322. data/lib/rubydb/sql/ast/commit.rb +37 -37
  323. data/lib/rubydb/sql/ast/constraint.rb +92 -83
  324. data/lib/rubydb/sql/ast/create_database.rb +41 -41
  325. data/lib/rubydb/sql/ast/create_index.rb +61 -61
  326. data/lib/rubydb/sql/ast/create_schema.rb +52 -52
  327. data/lib/rubydb/sql/ast/create_table.rb +187 -187
  328. data/lib/rubydb/sql/ast/delete.rb +54 -54
  329. data/lib/rubydb/sql/ast/drop_database.rb +41 -41
  330. data/lib/rubydb/sql/ast/drop_index.rb +41 -41
  331. data/lib/rubydb/sql/ast/drop_schema.rb +49 -49
  332. data/lib/rubydb/sql/ast/drop_table.rb +49 -49
  333. data/lib/rubydb/sql/ast/explain.rb +64 -64
  334. data/lib/rubydb/sql/ast/expression.rb +617 -604
  335. data/lib/rubydb/sql/ast/insert.rb +66 -66
  336. data/lib/rubydb/sql/ast/node.rb +42 -42
  337. data/lib/rubydb/sql/ast/rollback.rb +63 -63
  338. data/lib/rubydb/sql/ast/savepoint.rb +59 -59
  339. data/lib/rubydb/sql/ast/select.rb +88 -88
  340. data/lib/rubydb/sql/ast/set_operation.rb +22 -20
  341. data/lib/rubydb/sql/ast/trigger.rb +35 -29
  342. data/lib/rubydb/sql/ast/update.rb +88 -88
  343. data/lib/rubydb/sql/ast/vacuum.rb +19 -19
  344. data/lib/rubydb/sql/ast/view.rb +38 -32
  345. data/lib/rubydb/sql/ast/with.rb +32 -32
  346. data/lib/rubydb/sql/grammar.rb +86 -86
  347. data/lib/rubydb/sql/keywords.rb +156 -156
  348. data/lib/rubydb/sql/lexer.rb +209 -214
  349. data/lib/rubydb/sql/operators.rb +100 -100
  350. data/lib/rubydb/sql/parser.rb +1167 -1170
  351. data/lib/rubydb/sql/planner/analyzer.rb +283 -302
  352. data/lib/rubydb/sql/planner/binder.rb +537 -550
  353. data/lib/rubydb/sql/planner/type_checker.rb +427 -431
  354. data/lib/rubydb/sql/token.rb +210 -210
  355. data/lib/rubydb/storage/buffer_frame.rb +44 -44
  356. data/lib/rubydb/storage/buffer_pool.rb +155 -155
  357. data/lib/rubydb/storage/database_lock.rb +74 -74
  358. data/lib/rubydb/storage/deserializer.rb +332 -342
  359. data/lib/rubydb/storage/engine.rb +2347 -2330
  360. data/lib/rubydb/storage/file_manager.rb +191 -187
  361. data/lib/rubydb/storage/free_space_map.rb +79 -81
  362. data/lib/rubydb/storage/page.rb +92 -94
  363. data/lib/rubydb/storage/page_allocator.rb +852 -855
  364. data/lib/rubydb/storage/page_header.rb +63 -67
  365. data/lib/rubydb/storage/page_manager.rb +127 -131
  366. data/lib/rubydb/storage/record.rb +58 -58
  367. data/lib/rubydb/storage/row.rb +78 -78
  368. data/lib/rubydb/storage/serializer.rb +51 -51
  369. data/lib/rubydb/storage/storage_layout.rb +151 -151
  370. data/lib/rubydb/storage/storage_manager.rb +114 -114
  371. data/lib/rubydb/storage/tuple.rb +458 -461
  372. data/lib/rubydb/storage/visibility_map.rb +964 -973
  373. data/lib/rubydb/transactions/commit_manager.rb +219 -220
  374. data/lib/rubydb/transactions/isolation.rb +98 -98
  375. data/lib/rubydb/transactions/lock.rb +76 -76
  376. data/lib/rubydb/transactions/lock_manager.rb +359 -362
  377. data/lib/rubydb/transactions/savepoint.rb +142 -143
  378. data/lib/rubydb/transactions/transaction.rb +214 -215
  379. data/lib/rubydb/transactions/transaction_id.rb +84 -84
  380. data/lib/rubydb/transactions/transaction_log.rb +256 -257
  381. data/lib/rubydb/transactions/transaction_manager.rb +434 -435
  382. data/lib/rubydb/types/bigint.rb +36 -36
  383. data/lib/rubydb/types/blob.rb +37 -37
  384. data/lib/rubydb/types/boolean.rb +34 -34
  385. data/lib/rubydb/types/date.rb +39 -39
  386. data/lib/rubydb/types/decimal.rb +48 -48
  387. data/lib/rubydb/types/float.rb +34 -34
  388. data/lib/rubydb/types/integer.rb +36 -36
  389. data/lib/rubydb/types/json.rb +41 -41
  390. data/lib/rubydb/types/null.rb +34 -34
  391. data/lib/rubydb/types/smallint.rb +36 -36
  392. data/lib/rubydb/types/text.rb +37 -37
  393. data/lib/rubydb/types/time.rb +46 -46
  394. data/lib/rubydb/types/timestamp.rb +39 -39
  395. data/lib/rubydb/types/type.rb +119 -119
  396. data/lib/rubydb/types/uuid.rb +47 -47
  397. data/lib/rubydb/types/varchar.rb +37 -37
  398. data/lib/rubydb/version.rb +32 -32
  399. data/lib/rubydb/wal/archive.rb +190 -193
  400. data/lib/rubydb/wal/checkpoint.rb +181 -183
  401. data/lib/rubydb/wal/lsn.rb +94 -94
  402. data/lib/rubydb/wal/reader.rb +259 -260
  403. data/lib/rubydb/wal/record.rb +105 -105
  404. data/lib/rubydb/wal/segment.rb +193 -193
  405. data/lib/rubydb/wal/wal.rb +480 -452
  406. data/lib/rubydb/wal/writer.rb +236 -236
  407. data/lib/rubydb.rb +7 -7
  408. data/packaging/docker/docker-compose.failover.yml +43 -43
  409. data/packaging/homebrew/rubydb.rb +19 -19
  410. data/rubydb.gemspec +60 -57
  411. data/scripts/benchmark +7 -7
  412. data/scripts/durability_drill +37 -37
  413. data/scripts/fuzz +63 -63
  414. data/scripts/release +45 -40
  415. data/scripts/release_check +43 -43
  416. data/scripts/replication_failover_drill +268 -250
  417. data/scripts/replication_network_failover_drill +287 -255
  418. data/scripts/restore_drill +45 -45
  419. data/scripts/security +45 -0
  420. metadata +54 -1
@@ -1,295 +1,295 @@
1
- # RubyDB production operations guide
2
-
3
- This guide describes a controlled production deployment for applications that
4
- fit RubyDB’s documented feature surface. It is an operational companion to
5
- the [production runbook](production-runbook.md), [disaster recovery guide](disaster-recovery.md),
6
- and [monitoring guide](monitoring.md). It does not turn the current project
7
- into a universal PostgreSQL, MySQL, or SQLite replacement.
8
-
9
- ## Deployment decision
10
-
11
- Choose embedded mode only when one process owns the database directory and the
12
- application accepts process-local availability. Use server mode when web,
13
- worker, migration, or administrative processes need concurrent access. Put
14
- the database directory on storage with documented durability and rename/
15
- flush semantics. Do not place it on an untested shared filesystem.
16
-
17
- Before launch, validate the application’s schema, generated SQL, migrations,
18
- backup/restore path, concurrency profile, and failure behavior against the
19
- exact RubyDB version and configuration that will be deployed.
20
-
21
- ## Reference topology
22
-
23
- ```text
24
- clients/web/workers -> TLS -> RubyDB server -> private database volume
25
- |-> WAL/checkpoints
26
- |-> verified backup destination
27
- |-> metrics/log sink
28
- optional replica --------------------^
29
- ```
30
-
31
- A replica is not a backup. A backup is not a fencing system. An application
32
- load balancer health check is not proof that a primary is safe to write. Keep
33
- these responsibilities separate.
34
-
35
- ## Complete first deployment
36
-
37
- The following is a reference deployment for a Rails or regular Ruby
38
- application. Replace paths, hostnames, users, and limits with values approved
39
- by your infrastructure team.
40
-
41
- ### 1. Install and provision the server
42
-
43
- Pin the RubyDB gem version on the database host. Do not use an unpinned
44
- prerelease in a production deployment:
45
-
46
- ```sh
47
- gem install rubydb -v 0.1.0
48
- useradd --system --home-dir /var/lib/rubydb --shell /usr/sbin/nologin rubydb
49
- install -d -o rubydb -g rubydb -m 0700 /var/lib/rubydb/data
50
- install -d -o rubydb -g rubydb -m 0750 /var/log/rubydb
51
- install -d -o root -g rubydb -m 0750 /etc/rubydb
52
- ```
53
-
54
- Use a persistent local volume for `/var/lib/rubydb/data`. Keep backups on a
55
- separate failure domain. The server account should not own application source,
56
- certificate private keys, or unrelated host data.
57
-
58
- ### 2. Configure the server
59
-
60
- Start from the repository’s `config/production.yml` and place a reviewed copy
61
- at `/etc/rubydb/production.yml`. Supply required secrets through the service
62
- manager or secret store. At minimum, configure:
63
-
64
- ```text
65
- RUBYDB_HOST=0.0.0.0
66
- RUBYDB_PORT=7432
67
- RUBYDB_DATA_DIR=/var/lib/rubydb/data
68
- RUBYDB_LOG_DIR=/var/log/rubydb
69
- RUBYDB_USERNAME=app_rw
70
- RUBYDB_PASSWORD=<secret-manager-value>
71
- RUBYDB_SSL_ENABLED=true
72
- RUBYDB_SSL_CERT_FILE=/etc/rubydb/tls/server.crt
73
- RUBYDB_SSL_KEY_FILE=/etc/rubydb/tls/server.key
74
- RUBYDB_SSL_CA_FILE=/etc/rubydb/tls/ca.crt
75
- RUBYDB_SSL_VERIFY_PEER=true
76
- ```
77
-
78
- The server’s TLS private key and application password must be readable only by
79
- the service or secret-management mechanism. Restrict port `7432` to the Rails
80
- and worker network; do not expose it to the public internet.
81
-
82
- ### 3. Start and verify the server
83
-
84
- Run it under systemd, a supervised container, or an equivalent process
85
- manager. The CLI configuration options must appear before the command:
86
-
87
- ```sh
88
- sudo -u rubydb env RUBYDB_USERNAME=app_rw RUBYDB_PASSWORD='from-secret-store' \
89
- rubydb --config /etc/rubydb/production.yml --env production start
90
- ```
91
-
92
- In a systemd unit, use an `EnvironmentFile` protected with mode `0600` or a
93
- native secret integration, then use:
94
-
95
- ```ini
96
- ExecStart=/usr/local/bin/rubydb --config /etc/rubydb/production.yml --env production start
97
- Restart=on-failure
98
- ```
99
-
100
- Verify from the application network, not only from the database host:
101
-
102
- ```sh
103
- rubydb --config /etc/rubydb/production.yml --env production status --json
104
- rubydb --config /etc/rubydb/production.yml --env production doctor --json
105
- ```
106
-
107
- Then run an authenticated TLS smoke query using the Ruby client and the same
108
- URL the application will use:
109
-
110
- ```sh
111
- RUBYDB_URL='rubydbs://app_rw:URL_ENCODED_PASSWORD@db.example.com:7432/app?verify_peer=true&ca_file=%2Fetc%2Frubydb%2Ftls%2Fca.crt' \
112
- ruby -rrubydb -e 'c=RubyDB::Client::Client.new(url: ENV.fetch("RUBYDB_URL")); p c.query("SELECT 1").to_hash; c.disconnect'
113
- ```
114
-
115
- ### 4. Configure a Rails application
116
-
117
- In the Rails application’s `config/database.yml`, select server mode and read
118
- the connection string from the deployment environment:
119
-
120
- ```yaml
121
- production:
122
- adapter: rubydb
123
- embedded: false
124
- url: <%= ENV.fetch("RUBYDB_URL") %>
125
- pool: <%= ENV.fetch("RAILS_MAX_THREADS", "5") %>
126
- ```
127
-
128
- Set `RUBYDB_URL` through the platform secret store:
129
-
130
- ```text
131
- RUBYDB_URL=rubydbs://app_rw:URL_ENCODED_PASSWORD@db.example.com:7432/app?verify_peer=true&ca_file=%2Fetc%2Frubydb%2Ftls%2Fca.crt
132
- ```
133
-
134
- Deploy the Rails application, then run the migration once using a controlled
135
- release job, not concurrently from every web process:
136
-
137
- ```sh
138
- RAILS_ENV=production bundle exec rails db:migrate
139
- RAILS_ENV=production bundle exec rails runner 'puts User.count'
140
- ```
141
-
142
- The web and job processes connect to the server endpoint. They never mount or
143
- open `/var/lib/rubydb/data`.
144
-
145
- ### 5. Configure a regular Ruby application
146
-
147
- The regular client uses the same environment value:
148
-
149
- ```ruby
150
- require "rubydb"
151
-
152
- client = RubyDB::Client::Client.new(url: ENV.fetch("RUBYDB_URL"))
153
- begin
154
- client.query("SELECT 1")
155
- client.query("INSERT INTO audit_events (event_name) VALUES (?)", ["boot"])
156
- ensure
157
- client.disconnect
158
- end
159
- ```
160
-
161
- Use application-level idempotency for retried writes. A network timeout does
162
- not by itself prove that a commit was rolled back.
163
-
164
- ### 6. Accept traffic gradually
165
-
166
- Run a read/write smoke test, migration status check, backup, and representative
167
- workload before routing all traffic. Watch p95/p99 latency, errors, lock waits,
168
- active connections, WAL growth, checkpoint age, disk space, and memory during a
169
- canary period. Keep the previous application version and verified database
170
- backup available until the rollback window closes.
171
-
172
- The Rails URL example and URL option reference are also maintained in [Rails
173
- database configuration](../rails/database-yml.md).
174
-
175
- ## Configuration and service identity
176
-
177
- Run the server as a dedicated least-privilege account. Give it access only to
178
- the database, WAL, temporary, certificate, and backup paths it needs. Store
179
- passwords, peer tokens, private keys, and API credentials in a secret manager.
180
- Do not put secrets in YAML committed to the repository, process arguments, or
181
- logs.
182
-
183
- Pin the RubyDB version and configuration for each deployment. Review changes to
184
- durability mode, WAL retention, checkpoint thresholds, memory, connection
185
- limits, request deadlines, lock timeouts, and TLS/authentication as production
186
- changes. Keep a configuration checksum in the deployment record.
187
-
188
- ## Readiness checklist
189
-
190
- Before accepting traffic:
191
-
192
- * database directory is on approved storage with sufficient space and inodes;
193
- * service account and file permissions are verified;
194
- * TLS certificate, key, CA, hostname, and expiration are checked;
195
- * authentication and authorization deny an unauthenticated test client;
196
- * health and readiness checks exercise a real request path;
197
- * connection, request, lock, and shutdown timeouts are bounded;
198
- * schema/migrations have completed and version/checksum is recorded;
199
- * full backup has been created and restored into a fresh directory;
200
- * monitoring, alert routing, and log retention are active;
201
- * rollback and restore owners are named; and
202
- * a representative smoke query and write have passed.
203
-
204
- ## Capacity and resource limits
205
-
206
- Set explicit limits for connections, request duration, lock waits, result size,
207
- memory, worker count, WAL size, backup space, and file descriptors. Size the
208
- application pool below the server limit, leaving room for migrations,
209
- replication, health checks, and administration. A pool that equals the server
210
- limit can starve the control plane.
211
-
212
- Alert before exhaustion, not after it. Watch CPU, RSS, open files, disk bytes,
213
- free inodes, WAL bytes, checkpoint age/duration, active transactions, lock
214
- waits, pool utilization, errors, cancellations, and p95/p99 latency.
215
-
216
- ## Backup policy
217
-
218
- Define RPO and RTO with the application owner. At minimum, maintain verified
219
- full backups, protect them from the database host, encrypt them at rest and in
220
- transit, retain multiple generations, and record manifests/checksums. If using
221
- incremental or differential backups, retain their verified base and ordered
222
- chain.
223
-
224
- A successful backup command is not proof of recoverability. Regularly restore
225
- to an isolated directory, validate checksums and schema, run representative
226
- queries, compare critical row counts, and record elapsed restore time. Run a
227
- restore drill after format, backup, storage, or release changes.
228
-
229
- ## Upgrade procedure
230
-
231
- 1. Read the release notes, format compatibility, and migration notes.
232
- 2. Create and verify a new full backup.
233
- 3. Test the new version against a restored production-like copy.
234
- 4. Run schema and application smoke tests, including populated-table writes.
235
- 5. Drain or fence writes according to the deployment topology.
236
- 6. Upgrade one controlled instance and verify health, WAL, and metrics.
237
- 7. Re-enable traffic gradually and watch errors and latency.
238
- 8. Keep the rollback binary and backup available until the validation window
239
- closes.
240
-
241
- Never roll back by pointing an older binary at a directory whose format or
242
- metadata it cannot read. Use the documented restore/rollback path.
243
-
244
- ## Failover procedure
245
-
246
- RubyDB’s safe failover model requires a synchronized candidate and a durable
247
- fencing decision. A manual operator sequence is:
248
-
249
- 1. declare the incident and stop or isolate application writes;
250
- 2. verify the primary’s last acknowledged LSN and fence epoch;
251
- 3. confirm the candidate’s applied LSN and integrity;
252
- 4. fence the old primary at the process, host, storage, or network layer;
253
- 5. promote only after fencing is observable and durable;
254
- 6. point clients at the new primary and run smoke writes/reads;
255
- 7. monitor replication and stale-writer rejection; and
256
- 8. recover the old primary as a replica only after its state is understood.
257
-
258
- Automatic election requires an independently validated quorum, fencing,
259
- partition behavior, stale-primary rejection, and recovery procedure. Do not
260
- enable election based solely on a successful same-host test.
261
-
262
- ## Incident response
263
-
264
- Contain first: stop unsafe writes, protect the database directory, and record
265
- the timeline. Preserve logs, metrics, WAL, metadata, configuration, process
266
- state, and backup manifests. Use [troubleshooting](../troubleshooting.md) and
267
- [debugging](../debugging.md) for evidence collection.
268
-
269
- Classify the event as availability, durability, correctness, security, or
270
- capacity. Assign an incident owner and a recovery owner. Communicate whether
271
- commit outcomes are known, unknown, or confirmed rolled back. After recovery,
272
- verify application invariants rather than relying only on process health.
273
-
274
- ## TLS and secret rotation
275
-
276
- Stage new certificates and CA material, validate the chain and hostname with a
277
- test client, then switch through an atomic deployment/configuration change.
278
- Maintain an overlap window only if clients support it. Confirm old material is
279
- no longer accepted before revoking it. Rotate database passwords and peer
280
- tokens through the secret manager; audit access and avoid printing values.
281
-
282
- ## Maintenance
283
-
284
- Schedule vacuum, compaction, checkpoint, index maintenance, and backups with
285
- awareness of active readers and write load. Measure before and after. Use a
286
- copy for repair or compaction experiments. Verify reopen, checksums, row counts,
287
- indexes, and application smoke queries after maintenance.
288
-
289
- ## Production evidence
290
-
291
- The release record should contain the RubyDB commit, Ruby/Rails versions,
292
- configuration checksum, schema/migration version, backup manifest, restore
293
- drill result, benchmark/soak result, monitoring link, security review status,
294
- and known limitations. See [production readiness](../production-readiness.md)
295
- for the project-level boundaries.
1
+ # RubyDB production operations guide
2
+
3
+ This guide describes a controlled production deployment for applications that
4
+ fit RubyDB’s documented feature surface. It is an operational companion to
5
+ the [production runbook](production-runbook.md), [disaster recovery guide](disaster-recovery.md),
6
+ and [monitoring guide](monitoring.md). It does not turn the current project
7
+ into a universal PostgreSQL, MySQL, or SQLite replacement.
8
+
9
+ ## Deployment decision
10
+
11
+ Choose embedded mode only when one process owns the database directory and the
12
+ application accepts process-local availability. Use server mode when web,
13
+ worker, migration, or administrative processes need concurrent access. Put
14
+ the database directory on storage with documented durability and rename/
15
+ flush semantics. Do not place it on an untested shared filesystem.
16
+
17
+ Before launch, validate the application’s schema, generated SQL, migrations,
18
+ backup/restore path, concurrency profile, and failure behavior against the
19
+ exact RubyDB version and configuration that will be deployed.
20
+
21
+ ## Reference topology
22
+
23
+ ```text
24
+ clients/web/workers -> TLS -> RubyDB server -> private database volume
25
+ |-> WAL/checkpoints
26
+ |-> verified backup destination
27
+ |-> metrics/log sink
28
+ optional replica --------------------^
29
+ ```
30
+
31
+ A replica is not a backup. A backup is not a fencing system. An application
32
+ load balancer health check is not proof that a primary is safe to write. Keep
33
+ these responsibilities separate.
34
+
35
+ ## Complete first deployment
36
+
37
+ The following is a reference deployment for a Rails or regular Ruby
38
+ application. Replace paths, hostnames, users, and limits with values approved
39
+ by your infrastructure team.
40
+
41
+ ### 1. Install and provision the server
42
+
43
+ Pin the RubyDB gem version on the database host. Do not use an unpinned
44
+ prerelease in a production deployment:
45
+
46
+ ```sh
47
+ gem install rubydb -v 0.1.0
48
+ useradd --system --home-dir /var/lib/rubydb --shell /usr/sbin/nologin rubydb
49
+ install -d -o rubydb -g rubydb -m 0700 /var/lib/rubydb/data
50
+ install -d -o rubydb -g rubydb -m 0750 /var/log/rubydb
51
+ install -d -o root -g rubydb -m 0750 /etc/rubydb
52
+ ```
53
+
54
+ Use a persistent local volume for `/var/lib/rubydb/data`. Keep backups on a
55
+ separate failure domain. The server account should not own application source,
56
+ certificate private keys, or unrelated host data.
57
+
58
+ ### 2. Configure the server
59
+
60
+ Start from the repository’s `config/production.yml` and place a reviewed copy
61
+ at `/etc/rubydb/production.yml`. Supply required secrets through the service
62
+ manager or secret store. At minimum, configure:
63
+
64
+ ```text
65
+ RUBYDB_HOST=0.0.0.0
66
+ RUBYDB_PORT=7432
67
+ RUBYDB_DATA_DIR=/var/lib/rubydb/data
68
+ RUBYDB_LOG_DIR=/var/log/rubydb
69
+ RUBYDB_USERNAME=app_rw
70
+ RUBYDB_PASSWORD=<secret-manager-value>
71
+ RUBYDB_SSL_ENABLED=true
72
+ RUBYDB_SSL_CERT_FILE=/etc/rubydb/tls/server.crt
73
+ RUBYDB_SSL_KEY_FILE=/etc/rubydb/tls/server.key
74
+ RUBYDB_SSL_CA_FILE=/etc/rubydb/tls/ca.crt
75
+ RUBYDB_SSL_VERIFY_PEER=true
76
+ ```
77
+
78
+ The server’s TLS private key and application password must be readable only by
79
+ the service or secret-management mechanism. Restrict port `7432` to the Rails
80
+ and worker network; do not expose it to the public internet.
81
+
82
+ ### 3. Start and verify the server
83
+
84
+ Run it under systemd, a supervised container, or an equivalent process
85
+ manager. The CLI configuration options must appear before the command:
86
+
87
+ ```sh
88
+ sudo -u rubydb env RUBYDB_USERNAME=app_rw RUBYDB_PASSWORD='from-secret-store' \
89
+ rubydb --config /etc/rubydb/production.yml --env production start
90
+ ```
91
+
92
+ In a systemd unit, use an `EnvironmentFile` protected with mode `0600` or a
93
+ native secret integration, then use:
94
+
95
+ ```ini
96
+ ExecStart=/usr/local/bin/rubydb --config /etc/rubydb/production.yml --env production start
97
+ Restart=on-failure
98
+ ```
99
+
100
+ Verify from the application network, not only from the database host:
101
+
102
+ ```sh
103
+ rubydb --config /etc/rubydb/production.yml --env production status --json
104
+ rubydb --config /etc/rubydb/production.yml --env production doctor --json
105
+ ```
106
+
107
+ Then run an authenticated TLS smoke query using the Ruby client and the same
108
+ URL the application will use:
109
+
110
+ ```sh
111
+ RUBYDB_URL='rubydbs://app_rw:URL_ENCODED_PASSWORD@db.example.com:7432/app?verify_peer=true&ca_file=%2Fetc%2Frubydb%2Ftls%2Fca.crt' \
112
+ ruby -rrubydb -e 'c=RubyDB::Client::Client.new(url: ENV.fetch("RUBYDB_URL")); p c.query("SELECT 1").to_hash; c.disconnect'
113
+ ```
114
+
115
+ ### 4. Configure a Rails application
116
+
117
+ In the Rails application’s `config/database.yml`, select server mode and read
118
+ the connection string from the deployment environment:
119
+
120
+ ```yaml
121
+ production:
122
+ adapter: rubydb
123
+ embedded: false
124
+ url: <%= ENV.fetch("RUBYDB_URL") %>
125
+ pool: <%= ENV.fetch("RAILS_MAX_THREADS", "5") %>
126
+ ```
127
+
128
+ Set `RUBYDB_URL` through the platform secret store:
129
+
130
+ ```text
131
+ RUBYDB_URL=rubydbs://app_rw:URL_ENCODED_PASSWORD@db.example.com:7432/app?verify_peer=true&ca_file=%2Fetc%2Frubydb%2Ftls%2Fca.crt
132
+ ```
133
+
134
+ Deploy the Rails application, then run the migration once using a controlled
135
+ release job, not concurrently from every web process:
136
+
137
+ ```sh
138
+ RAILS_ENV=production bundle exec rails db:migrate
139
+ RAILS_ENV=production bundle exec rails runner 'puts User.count'
140
+ ```
141
+
142
+ The web and job processes connect to the server endpoint. They never mount or
143
+ open `/var/lib/rubydb/data`.
144
+
145
+ ### 5. Configure a regular Ruby application
146
+
147
+ The regular client uses the same environment value:
148
+
149
+ ```ruby
150
+ require "rubydb"
151
+
152
+ client = RubyDB::Client::Client.new(url: ENV.fetch("RUBYDB_URL"))
153
+ begin
154
+ client.query("SELECT 1")
155
+ client.query("INSERT INTO audit_events (event_name) VALUES (?)", ["boot"])
156
+ ensure
157
+ client.disconnect
158
+ end
159
+ ```
160
+
161
+ Use application-level idempotency for retried writes. A network timeout does
162
+ not by itself prove that a commit was rolled back.
163
+
164
+ ### 6. Accept traffic gradually
165
+
166
+ Run a read/write smoke test, migration status check, backup, and representative
167
+ workload before routing all traffic. Watch p95/p99 latency, errors, lock waits,
168
+ active connections, WAL growth, checkpoint age, disk space, and memory during a
169
+ canary period. Keep the previous application version and verified database
170
+ backup available until the rollback window closes.
171
+
172
+ The Rails URL example and URL option reference are also maintained in [Rails
173
+ database configuration](../rails/database-yml.md).
174
+
175
+ ## Configuration and service identity
176
+
177
+ Run the server as a dedicated least-privilege account. Give it access only to
178
+ the database, WAL, temporary, certificate, and backup paths it needs. Store
179
+ passwords, peer tokens, private keys, and API credentials in a secret manager.
180
+ Do not put secrets in YAML committed to the repository, process arguments, or
181
+ logs.
182
+
183
+ Pin the RubyDB version and configuration for each deployment. Review changes to
184
+ durability mode, WAL retention, checkpoint thresholds, memory, connection
185
+ limits, request deadlines, lock timeouts, and TLS/authentication as production
186
+ changes. Keep a configuration checksum in the deployment record.
187
+
188
+ ## Readiness checklist
189
+
190
+ Before accepting traffic:
191
+
192
+ * database directory is on approved storage with sufficient space and inodes;
193
+ * service account and file permissions are verified;
194
+ * TLS certificate, key, CA, hostname, and expiration are checked;
195
+ * authentication and authorization deny an unauthenticated test client;
196
+ * health and readiness checks exercise a real request path;
197
+ * connection, request, lock, and shutdown timeouts are bounded;
198
+ * schema/migrations have completed and version/checksum is recorded;
199
+ * full backup has been created and restored into a fresh directory;
200
+ * monitoring, alert routing, and log retention are active;
201
+ * rollback and restore owners are named; and
202
+ * a representative smoke query and write have passed.
203
+
204
+ ## Capacity and resource limits
205
+
206
+ Set explicit limits for connections, request duration, lock waits, result size,
207
+ memory, worker count, WAL size, backup space, and file descriptors. Size the
208
+ application pool below the server limit, leaving room for migrations,
209
+ replication, health checks, and administration. A pool that equals the server
210
+ limit can starve the control plane.
211
+
212
+ Alert before exhaustion, not after it. Watch CPU, RSS, open files, disk bytes,
213
+ free inodes, WAL bytes, checkpoint age/duration, active transactions, lock
214
+ waits, pool utilization, errors, cancellations, and p95/p99 latency.
215
+
216
+ ## Backup policy
217
+
218
+ Define RPO and RTO with the application owner. At minimum, maintain verified
219
+ full backups, protect them from the database host, encrypt them at rest and in
220
+ transit, retain multiple generations, and record manifests/checksums. If using
221
+ incremental or differential backups, retain their verified base and ordered
222
+ chain.
223
+
224
+ A successful backup command is not proof of recoverability. Regularly restore
225
+ to an isolated directory, validate checksums and schema, run representative
226
+ queries, compare critical row counts, and record elapsed restore time. Run a
227
+ restore drill after format, backup, storage, or release changes.
228
+
229
+ ## Upgrade procedure
230
+
231
+ 1. Read the release notes, format compatibility, and migration notes.
232
+ 2. Create and verify a new full backup.
233
+ 3. Test the new version against a restored production-like copy.
234
+ 4. Run schema and application smoke tests, including populated-table writes.
235
+ 5. Drain or fence writes according to the deployment topology.
236
+ 6. Upgrade one controlled instance and verify health, WAL, and metrics.
237
+ 7. Re-enable traffic gradually and watch errors and latency.
238
+ 8. Keep the rollback binary and backup available until the validation window
239
+ closes.
240
+
241
+ Never roll back by pointing an older binary at a directory whose format or
242
+ metadata it cannot read. Use the documented restore/rollback path.
243
+
244
+ ## Failover procedure
245
+
246
+ RubyDB’s safe failover model requires a synchronized candidate and a durable
247
+ fencing decision. A manual operator sequence is:
248
+
249
+ 1. declare the incident and stop or isolate application writes;
250
+ 2. verify the primary’s last acknowledged LSN and fence epoch;
251
+ 3. confirm the candidate’s applied LSN and integrity;
252
+ 4. fence the old primary at the process, host, storage, or network layer;
253
+ 5. promote only after fencing is observable and durable;
254
+ 6. point clients at the new primary and run smoke writes/reads;
255
+ 7. monitor replication and stale-writer rejection; and
256
+ 8. recover the old primary as a replica only after its state is understood.
257
+
258
+ Automatic election requires an independently validated quorum, fencing,
259
+ partition behavior, stale-primary rejection, and recovery procedure. Do not
260
+ enable election based solely on a successful same-host test.
261
+
262
+ ## Incident response
263
+
264
+ Contain first: stop unsafe writes, protect the database directory, and record
265
+ the timeline. Preserve logs, metrics, WAL, metadata, configuration, process
266
+ state, and backup manifests. Use [troubleshooting](../troubleshooting.md) and
267
+ [debugging](../debugging.md) for evidence collection.
268
+
269
+ Classify the event as availability, durability, correctness, security, or
270
+ capacity. Assign an incident owner and a recovery owner. Communicate whether
271
+ commit outcomes are known, unknown, or confirmed rolled back. After recovery,
272
+ verify application invariants rather than relying only on process health.
273
+
274
+ ## TLS and secret rotation
275
+
276
+ Stage new certificates and CA material, validate the chain and hostname with a
277
+ test client, then switch through an atomic deployment/configuration change.
278
+ Maintain an overlap window only if clients support it. Confirm old material is
279
+ no longer accepted before revoking it. Rotate database passwords and peer
280
+ tokens through the secret manager; audit access and avoid printing values.
281
+
282
+ ## Maintenance
283
+
284
+ Schedule vacuum, compaction, checkpoint, index maintenance, and backups with
285
+ awareness of active readers and write load. Measure before and after. Use a
286
+ copy for repair or compaction experiments. Verify reopen, checksums, row counts,
287
+ indexes, and application smoke queries after maintenance.
288
+
289
+ ## Production evidence
290
+
291
+ The release record should contain the RubyDB commit, Ruby/Rails versions,
292
+ configuration checksum, schema/migration version, backup manifest, restore
293
+ drill result, benchmark/soak result, monitoring link, security review status,
294
+ and known limitations. See [production readiness](../production-readiness.md)
295
+ for the project-level boundaries.