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.
- checksums.yaml +4 -4
- data/.github/PULL_REQUEST_TEMPLATE.md +15 -15
- data/.github/workflows/benchmark.yml +26 -26
- data/.github/workflows/compatibility.yml +63 -63
- data/.github/workflows/fuzz.yml +33 -33
- data/.github/workflows/lint.yml +21 -21
- data/.github/workflows/operations.yml +24 -24
- data/.github/workflows/production-validation.yml +111 -111
- data/.github/workflows/release.yml +77 -77
- data/.github/workflows/security.yml +39 -37
- data/.github/workflows/test.yml +26 -26
- data/.github/workflows/workload.yml +58 -58
- data/.gitignore +16 -5
- data/.rubocop.yml +50 -44
- data/.standard.yml +9 -14
- data/ARCHITECTURE.md +21 -21
- data/CHANGELOG.md +57 -27
- data/CODE_OF_CONDUCT.md +13 -13
- data/CONTRIBUTING.md +29 -29
- data/GOVERNANCE.md +16 -16
- data/Gemfile +18 -17
- data/Gemfile.lock +125 -71
- data/README.md +168 -12
- data/ROADMAP.md +27 -27
- data/Rakefile +76 -71
- data/SECURITY.md +54 -54
- data/SUPPORT.md +14 -14
- data/accelerator/bin/SHA256SUMS +6 -0
- data/accelerator/bin/rubydb-accelerator-darwin-amd64 +0 -0
- data/accelerator/bin/rubydb-accelerator-darwin-arm64 +0 -0
- data/accelerator/bin/rubydb-accelerator-linux-amd64 +0 -0
- data/accelerator/bin/rubydb-accelerator-linux-arm64 +0 -0
- data/accelerator/bin/rubydb-accelerator-windows-amd64.exe +0 -0
- data/accelerator/bin/rubydb-accelerator-windows-arm64.exe +0 -0
- data/accelerator/cmd/rubydb-accelerator/main.go +11 -0
- data/accelerator/go.mod +3 -0
- data/accelerator/internal/execution/aggregate.go +94 -0
- data/accelerator/internal/execution/distinct.go +22 -0
- data/accelerator/internal/execution/filter.go +73 -0
- data/accelerator/internal/execution/join.go +79 -0
- data/accelerator/internal/execution/operators.go +167 -0
- data/accelerator/internal/execution/scan.go +20 -0
- data/accelerator/internal/execution/sort.go +62 -0
- data/accelerator/internal/execution/types.go +136 -0
- data/accelerator/internal/execution/value.go +67 -0
- data/accelerator/internal/memory/arena.go +47 -0
- data/accelerator/internal/memory/reuse.go +22 -0
- data/accelerator/internal/metrics/registry.go +67 -0
- data/accelerator/internal/parallel/bounded_queue.go +56 -0
- data/accelerator/internal/parallel/scheduler.go +47 -0
- data/accelerator/internal/parallel/worker_pool.go +53 -0
- data/accelerator/internal/protocol/cancellation.go +48 -0
- data/accelerator/internal/protocol/columnar.go +263 -0
- data/accelerator/internal/protocol/frame.go +187 -0
- data/accelerator/internal/runtime/worker.go +521 -0
- data/accelerator/internal/storage/page_reader.go +81 -0
- data/accelerator/internal/storage/snapshot_scan.go +539 -0
- data/accelerator/internal/wal/checksum.go +13 -0
- data/accelerator/internal/wal/compression.go +41 -0
- data/accelerator/internal/wal/group_commit.go +24 -0
- data/accelerator/internal/wal/record_encoder.go +40 -0
- data/adapters/activerecord/Gemfile +11 -11
- data/adapters/activerecord/README.md +8 -3
- data/adapters/activerecord/lib/active_record/connection_adapters/rubydb_adapter.rb +881 -879
- data/adapters/activerecord/rubydb-activerecord.gemspec +21 -21
- data/adapters/activerecord/spec/rubydb_adapter_integration_spec.rb +143 -143
- data/adapters/ruby/README.md +18 -18
- data/adapters/sequel/README.md +11 -11
- data/config/monitoring/prometheus-alerts.yml +39 -39
- data/config/production.yml +36 -36
- data/docs/README.md +77 -71
- data/docs/architecture/concurrency.md +14 -14
- data/docs/architecture/current-state.md +125 -125
- data/docs/architecture/execution-engine.md +25 -25
- data/docs/architecture/go-accelerator.md +179 -0
- data/docs/architecture/indexes.md +19 -19
- data/docs/architecture/mvcc.md +19 -19
- data/docs/architecture/overview.md +13 -13
- data/docs/architecture/pages.md +11 -11
- data/docs/architecture/production-roadmap.md +82 -82
- data/docs/architecture/query-planner.md +20 -20
- data/docs/architecture/recovery.md +18 -18
- data/docs/architecture/sql-engine.md +12 -12
- data/docs/architecture/storage-engine.md +14 -14
- data/docs/architecture/transactions.md +10 -10
- data/docs/architecture/wal.md +28 -28
- data/docs/cli-cheatsheet.md +98 -98
- data/docs/cli.md +299 -275
- data/docs/contributing/architecture.md +9 -9
- data/docs/contributing/benchmarking.md +30 -14
- data/docs/contributing/development.md +16 -16
- data/docs/contributing/release-process.md +49 -49
- data/docs/contributing/testing.md +16 -16
- data/docs/debugging.md +229 -229
- data/docs/developer/branching.md +10 -10
- data/docs/developer/database-diff.md +10 -10
- data/docs/developer/local-development.md +49 -17
- data/docs/developer/snapshots.md +9 -9
- data/docs/developer/temporal-data.md +10 -10
- data/docs/developer-guide.md +297 -297
- data/docs/getting-started/first-database.md +16 -16
- data/docs/getting-started/first-query.md +13 -13
- data/docs/getting-started/installation.md +19 -19
- data/docs/getting-started/local-to-production.md +300 -300
- data/docs/getting-started/quickstart.md +17 -17
- data/docs/getting-started/rails.md +16 -16
- data/docs/hardening_backlog.md +93 -93
- data/docs/lessons-learned.md +112 -112
- data/docs/operations/backups.md +33 -33
- data/docs/operations/disaster-recovery.md +31 -31
- data/docs/operations/failover.md +30 -30
- data/docs/operations/monitoring.md +25 -25
- data/docs/operations/production-guide.md +295 -295
- data/docs/operations/production-runbook.md +45 -45
- data/docs/operations/replication.md +33 -33
- data/docs/operations/restore.md +6 -6
- data/docs/operations/runbook.md +34 -34
- data/docs/operations/upgrades.md +14 -14
- data/docs/operations/workload-testing.md +17 -17
- data/docs/production-readiness.md +118 -118
- data/docs/production_validation.md +150 -150
- data/docs/rails/active-record.md +11 -11
- data/docs/rails/compatibility-guide.md +90 -90
- data/docs/rails/database-yml.md +92 -92
- data/docs/rails/installation.md +17 -17
- data/docs/rails/migrations.md +17 -17
- data/docs/rails/production.md +82 -82
- data/docs/rails/troubleshooting.md +18 -18
- data/docs/release.md +25 -25
- data/docs/server/architecture.md +10 -10
- data/docs/server/authentication.md +10 -10
- data/docs/server/configuration.md +16 -16
- data/docs/server/connection-pooling.md +10 -10
- data/docs/server/deployment.md +10 -10
- data/docs/server/protocol.md +12 -12
- data/docs/sql/compatibility-guide.md +82 -82
- data/docs/sql/compatibility.md +39 -39
- data/docs/sql/data-types.md +10 -10
- data/docs/sql/functions.md +9 -9
- data/docs/sql/joins.md +9 -9
- data/docs/sql/operators.md +9 -9
- data/docs/sql/sqlite-compatibility.md +21 -21
- data/docs/sql/syntax.md +10 -10
- data/docs/sql/transactions.md +10 -10
- data/docs/troubleshooting.md +244 -244
- data/lessons/01-foundations.md +73 -0
- data/lessons/02-local-development.md +121 -0
- data/lessons/03-embedded-rubydb.md +99 -0
- data/lessons/04-rails-complex-apps.md +138 -0
- data/lessons/05-rubydb-production-server.md +237 -0
- data/lessons/06-postgresql-massive-apps.md +96 -0
- data/lessons/07-hybrid-microservices.md +179 -0
- data/lessons/08-migrations-backups-recovery.md +86 -0
- data/lessons/09-observability-security-scale.md +87 -0
- data/lessons/10-release-readiness.md +192 -0
- data/lessons/11-community-adapter.md +323 -0
- data/lessons/12-rails-ecommerce-pressure.md +263 -0
- data/lib/rubydb/accelerator/client.rb +451 -0
- data/lib/rubydb/accelerator/error.rb +22 -0
- data/lib/rubydb/accelerator/manager.rb +606 -0
- data/lib/rubydb/accelerator.rb +13 -0
- data/lib/rubydb/backup/archive.rb +332 -334
- data/lib/rubydb/backup/backup.rb +400 -401
- data/lib/rubydb/backup/incremental.rb +349 -353
- data/lib/rubydb/backup/restore.rb +289 -290
- data/lib/rubydb/backup/snapshot.rb +265 -267
- data/lib/rubydb/backup/verification.rb +276 -279
- data/lib/rubydb/branching/branch.rb +181 -181
- data/lib/rubydb/branching/branch_manager.rb +307 -311
- data/lib/rubydb/branching/branch_metadata.rb +140 -140
- data/lib/rubydb/branching/checkout.rb +165 -166
- data/lib/rubydb/branching/copy_on_write.rb +272 -272
- data/lib/rubydb/branching/diff.rb +137 -138
- data/lib/rubydb/branching/merge.rb +282 -285
- data/lib/rubydb/build_info.rb +15 -15
- data/lib/rubydb/catalog/catalog.rb +391 -391
- data/lib/rubydb/catalog/column.rb +112 -112
- data/lib/rubydb/catalog/constraint.rb +180 -180
- data/lib/rubydb/catalog/database.rb +184 -184
- data/lib/rubydb/catalog/index.rb +97 -97
- data/lib/rubydb/catalog/schema.rb +103 -103
- data/lib/rubydb/catalog/sequence.rb +90 -90
- data/lib/rubydb/catalog/system_catalog.rb +698 -698
- data/lib/rubydb/catalog/table.rb +178 -178
- data/lib/rubydb/catalog/trigger.rb +102 -102
- data/lib/rubydb/catalog/view.rb +66 -66
- data/lib/rubydb/cli/application.rb +168 -163
- data/lib/rubydb/cli/commands/accelerator.rb +72 -0
- data/lib/rubydb/cli/commands/backup.rb +80 -81
- data/lib/rubydb/cli/commands/branch.rb +72 -72
- data/lib/rubydb/cli/commands/checkout.rb +54 -54
- data/lib/rubydb/cli/commands/create.rb +58 -58
- data/lib/rubydb/cli/commands/diff.rb +76 -77
- data/lib/rubydb/cli/commands/doctor.rb +77 -74
- data/lib/rubydb/cli/commands/drop.rb +57 -57
- data/lib/rubydb/cli/commands/init.rb +101 -102
- data/lib/rubydb/cli/commands/inspect.rb +95 -95
- data/lib/rubydb/cli/commands/merge.rb +63 -63
- data/lib/rubydb/cli/commands/migrate.rb +62 -62
- data/lib/rubydb/cli/commands/restart.rb +42 -39
- data/lib/rubydb/cli/commands/restore.rb +121 -121
- data/lib/rubydb/cli/commands/shell.rb +365 -365
- data/lib/rubydb/cli/commands/snapshot.rb +79 -79
- data/lib/rubydb/cli/commands/start.rb +88 -82
- data/lib/rubydb/cli/commands/status.rb +96 -92
- data/lib/rubydb/cli/commands/stop.rb +47 -47
- data/lib/rubydb/cli/commands/vacuum.rb +58 -58
- data/lib/rubydb/cli/formatter.rb +221 -221
- data/lib/rubydb/cli/output.rb +168 -168
- data/lib/rubydb/client/client.rb +309 -304
- data/lib/rubydb/client/connection.rb +429 -415
- data/lib/rubydb/client/connection_pool.rb +168 -168
- data/lib/rubydb/client/connection_url.rb +96 -96
- data/lib/rubydb/client/prepared_statement.rb +60 -60
- data/lib/rubydb/client/result.rb +127 -123
- data/lib/rubydb/client/statement.rb +52 -52
- data/lib/rubydb/client/transaction.rb +130 -130
- data/lib/rubydb/concurrency/concurrency.rb +19 -19
- data/lib/rubydb/concurrency/deadlock_detector.rb +148 -150
- data/lib/rubydb/concurrency/latch.rb +101 -101
- data/lib/rubydb/concurrency/lock_graph.rb +163 -165
- data/lib/rubydb/concurrency/mutex.rb +181 -183
- data/lib/rubydb/concurrency/rw_lock.rb +180 -180
- data/lib/rubydb/concurrency/scheduler.rb +248 -250
- data/lib/rubydb/concurrency/worker_pool.rb +145 -143
- data/lib/rubydb/configuration/config.rb +170 -170
- data/lib/rubydb/configuration/defaults.rb +191 -179
- data/lib/rubydb/configuration/environment.rb +152 -152
- data/lib/rubydb/configuration/parser.rb +185 -185
- data/lib/rubydb/configuration/validation.rb +228 -221
- data/lib/rubydb/constants.rb +74 -74
- data/lib/rubydb/constraints/check.rb +181 -181
- data/lib/rubydb/constraints/constraint.rb +101 -101
- data/lib/rubydb/constraints/foreign_key.rb +130 -130
- data/lib/rubydb/constraints/not_null.rb +64 -64
- data/lib/rubydb/constraints/primary_key.rb +99 -99
- data/lib/rubydb/constraints/unique.rb +106 -108
- data/lib/rubydb/constraints/validator.rb +349 -350
- data/lib/rubydb/errors/authentication_error.rb +10 -10
- data/lib/rubydb/errors/authorization_error.rb +23 -23
- data/lib/rubydb/errors/client_error.rb +10 -10
- data/lib/rubydb/errors/configuration_error.rb +10 -10
- data/lib/rubydb/errors/connection_error.rb +10 -10
- data/lib/rubydb/errors/constraint_error.rb +23 -23
- data/lib/rubydb/errors/corruption_error.rb +10 -10
- data/lib/rubydb/errors/database_error.rb +10 -10
- data/lib/rubydb/errors/error.rb +20 -20
- data/lib/rubydb/errors/execution_error.rb +10 -10
- data/lib/rubydb/errors/parser_error.rb +10 -10
- data/lib/rubydb/errors/recovery_error.rb +10 -10
- data/lib/rubydb/errors/replication_error.rb +10 -10
- data/lib/rubydb/errors/server_error.rb +6 -6
- data/lib/rubydb/errors/storage_error.rb +10 -10
- data/lib/rubydb/errors/transaction_error.rb +10 -10
- data/lib/rubydb/execution/accelerator_dispatch.rb +30 -0
- data/lib/rubydb/execution/aggregate_executor.rb +134 -138
- data/lib/rubydb/execution/cost_model.rb +72 -0
- data/lib/rubydb/execution/delete_executor.rb +110 -112
- data/lib/rubydb/execution/distinct_executor.rb +131 -135
- data/lib/rubydb/execution/executor.rb +1544 -1188
- data/lib/rubydb/execution/expression.rb +191 -193
- data/lib/rubydb/execution/index_scan.rb +142 -142
- data/lib/rubydb/execution/insert_executor.rb +215 -217
- data/lib/rubydb/execution/join_executor.rb +243 -249
- data/lib/rubydb/execution/limit_executor.rb +83 -85
- data/lib/rubydb/execution/operator_selection.rb +57 -0
- data/lib/rubydb/execution/optimizer.rb +227 -215
- data/lib/rubydb/execution/physical_plan.rb +47 -0
- data/lib/rubydb/execution/plan.rb +355 -353
- data/lib/rubydb/execution/planner.rb +508 -536
- data/lib/rubydb/execution/predicate.rb +235 -235
- data/lib/rubydb/execution/scan.rb +49 -49
- data/lib/rubydb/execution/sequential_scan.rb +63 -63
- data/lib/rubydb/execution/sort_executor.rb +194 -185
- data/lib/rubydb/execution/update_executor.rb +160 -162
- data/lib/rubydb/functions/aggregate.rb +70 -70
- data/lib/rubydb/functions/date_functions.rb +274 -278
- data/lib/rubydb/functions/function.rb +85 -85
- data/lib/rubydb/functions/json_functions.rb +231 -215
- data/lib/rubydb/functions/numeric_functions.rb +346 -346
- data/lib/rubydb/functions/scalar.rb +52 -52
- data/lib/rubydb/functions/string_functions.rb +383 -383
- data/lib/rubydb/functions/system_functions.rb +258 -246
- data/lib/rubydb/history/as_of.rb +238 -238
- data/lib/rubydb/history/change.rb +105 -105
- data/lib/rubydb/history/history.rb +131 -131
- data/lib/rubydb/history/history_manager.rb +228 -229
- data/lib/rubydb/history/temporal_query.rb +202 -202
- data/lib/rubydb/history/timeline.rb +144 -144
- data/lib/rubydb/indexes/btree.rb +215 -186
- data/lib/rubydb/indexes/btree_cursor.rb +258 -258
- data/lib/rubydb/indexes/btree_node.rb +384 -385
- data/lib/rubydb/indexes/hash_index.rb +150 -150
- data/lib/rubydb/indexes/index.rb +71 -71
- data/lib/rubydb/indexes/index_manager.rb +408 -406
- data/lib/rubydb/indexes/index_scan.rb +466 -470
- data/lib/rubydb/migrations/migration.rb +253 -254
- data/lib/rubydb/migrations/migration_lock.rb +146 -146
- data/lib/rubydb/migrations/migration_manager.rb +187 -176
- data/lib/rubydb/migrations/migration_version.rb +71 -71
- data/lib/rubydb/migrations/schema_diff.rb +211 -211
- data/lib/rubydb/migrations/schema_version.rb +64 -64
- data/lib/rubydb/monitoring/events.rb +155 -160
- data/lib/rubydb/monitoring/health.rb +216 -222
- data/lib/rubydb/monitoring/logger.rb +188 -193
- data/lib/rubydb/monitoring/metrics.rb +363 -359
- data/lib/rubydb/monitoring/performance.rb +176 -176
- data/lib/rubydb/monitoring/statistics.rb +168 -170
- data/lib/rubydb/mvcc/garbage_collector.rb +199 -199
- data/lib/rubydb/mvcc/mvcc.rb +16 -16
- data/lib/rubydb/mvcc/snapshot.rb +146 -147
- data/lib/rubydb/mvcc/vacuum.rb +180 -180
- data/lib/rubydb/mvcc/version.rb +106 -106
- data/lib/rubydb/mvcc/version_store.rb +396 -398
- data/lib/rubydb/mvcc/visibility.rb +107 -109
- data/lib/rubydb/protocol/capabilities.rb +125 -125
- data/lib/rubydb/protocol/decoder.rb +142 -145
- data/lib/rubydb/protocol/encoder.rb +131 -136
- data/lib/rubydb/protocol/handshake.rb +306 -305
- data/lib/rubydb/protocol/message.rb +121 -121
- data/lib/rubydb/protocol/parameter_binder.rb +101 -0
- data/lib/rubydb/protocol/protocol.rb +276 -277
- data/lib/rubydb/protocol/version.rb +54 -54
- data/lib/rubydb/rails/adapter.rb +245 -239
- data/lib/rubydb/rails/connection.rb +312 -314
- data/lib/rubydb/rails/database_statements.rb +122 -122
- data/lib/rubydb/rails/migration.rb +131 -131
- data/lib/rubydb/rails/quoting.rb +109 -109
- data/lib/rubydb/rails/result.rb +117 -117
- data/lib/rubydb/rails/schema_statements.rb +339 -339
- data/lib/rubydb/rails/transaction.rb +105 -105
- data/lib/rubydb/rails/type.rb +126 -126
- data/lib/rubydb/recovery/checkpoint.rb +261 -257
- data/lib/rubydb/recovery/consistency.rb +457 -467
- data/lib/rubydb/recovery/corruption_detector.rb +5 -5
- data/lib/rubydb/recovery/crash_recovery.rb +381 -387
- data/lib/rubydb/recovery/recovery_manager.rb +204 -206
- data/lib/rubydb/recovery/redo.rb +235 -237
- data/lib/rubydb/recovery/undo.rb +204 -206
- data/lib/rubydb/replication/failover.rb +5 -5
- data/lib/rubydb/replication/fencing.rb +63 -63
- data/lib/rubydb/replication/primary.rb +461 -450
- data/lib/rubydb/replication/replica.rb +382 -384
- data/lib/rubydb/replication/replication_log.rb +194 -200
- data/lib/rubydb/replication/replication_manager.rb +307 -308
- data/lib/rubydb/replication/replication_slot.rb +293 -295
- data/lib/rubydb/replication/replication_stream.rb +198 -201
- data/lib/rubydb/rubydb.rb +570 -560
- data/lib/rubydb/security/access_control.rb +252 -254
- data/lib/rubydb/security/audit_log.rb +209 -213
- data/lib/rubydb/security/authentication.rb +302 -302
- data/lib/rubydb/security/authorization.rb +282 -282
- data/lib/rubydb/security/credentials.rb +192 -196
- data/lib/rubydb/security/password.rb +205 -215
- data/lib/rubydb/security/permissions.rb +74 -74
- data/lib/rubydb/security/role.rb +99 -101
- data/lib/rubydb/security/user.rb +86 -86
- data/lib/rubydb/server/connection.rb +383 -366
- data/lib/rubydb/server/connection_pool.rb +193 -193
- data/lib/rubydb/server/lifecycle.rb +227 -228
- data/lib/rubydb/server/listener.rb +139 -136
- data/lib/rubydb/server/request_handler.rb +277 -276
- data/lib/rubydb/server/server.rb +363 -364
- data/lib/rubydb/server/session.rb +416 -369
- data/lib/rubydb/server/worker.rb +206 -210
- data/lib/rubydb/server/worker_pool.rb +168 -168
- data/lib/rubydb/sql/ast/alter_table.rb +169 -169
- data/lib/rubydb/sql/ast/begin_transaction.rb +47 -47
- data/lib/rubydb/sql/ast/commit.rb +37 -37
- data/lib/rubydb/sql/ast/constraint.rb +92 -83
- data/lib/rubydb/sql/ast/create_database.rb +41 -41
- data/lib/rubydb/sql/ast/create_index.rb +61 -61
- data/lib/rubydb/sql/ast/create_schema.rb +52 -52
- data/lib/rubydb/sql/ast/create_table.rb +187 -187
- data/lib/rubydb/sql/ast/delete.rb +54 -54
- data/lib/rubydb/sql/ast/drop_database.rb +41 -41
- data/lib/rubydb/sql/ast/drop_index.rb +41 -41
- data/lib/rubydb/sql/ast/drop_schema.rb +49 -49
- data/lib/rubydb/sql/ast/drop_table.rb +49 -49
- data/lib/rubydb/sql/ast/explain.rb +64 -64
- data/lib/rubydb/sql/ast/expression.rb +617 -604
- data/lib/rubydb/sql/ast/insert.rb +66 -66
- data/lib/rubydb/sql/ast/node.rb +42 -42
- data/lib/rubydb/sql/ast/rollback.rb +63 -63
- data/lib/rubydb/sql/ast/savepoint.rb +59 -59
- data/lib/rubydb/sql/ast/select.rb +88 -88
- data/lib/rubydb/sql/ast/set_operation.rb +22 -20
- data/lib/rubydb/sql/ast/trigger.rb +35 -29
- data/lib/rubydb/sql/ast/update.rb +88 -88
- data/lib/rubydb/sql/ast/vacuum.rb +19 -19
- data/lib/rubydb/sql/ast/view.rb +38 -32
- data/lib/rubydb/sql/ast/with.rb +32 -32
- data/lib/rubydb/sql/grammar.rb +86 -86
- data/lib/rubydb/sql/keywords.rb +156 -156
- data/lib/rubydb/sql/lexer.rb +209 -214
- data/lib/rubydb/sql/operators.rb +100 -100
- data/lib/rubydb/sql/parser.rb +1167 -1170
- data/lib/rubydb/sql/planner/analyzer.rb +283 -302
- data/lib/rubydb/sql/planner/binder.rb +537 -550
- data/lib/rubydb/sql/planner/type_checker.rb +427 -431
- data/lib/rubydb/sql/token.rb +210 -210
- data/lib/rubydb/storage/buffer_frame.rb +44 -44
- data/lib/rubydb/storage/buffer_pool.rb +155 -155
- data/lib/rubydb/storage/database_lock.rb +74 -74
- data/lib/rubydb/storage/deserializer.rb +332 -342
- data/lib/rubydb/storage/engine.rb +2409 -2330
- data/lib/rubydb/storage/file_manager.rb +191 -187
- data/lib/rubydb/storage/free_space_map.rb +79 -81
- data/lib/rubydb/storage/page.rb +92 -94
- data/lib/rubydb/storage/page_allocator.rb +852 -855
- data/lib/rubydb/storage/page_header.rb +63 -67
- data/lib/rubydb/storage/page_manager.rb +127 -131
- data/lib/rubydb/storage/record.rb +58 -58
- data/lib/rubydb/storage/row.rb +78 -78
- data/lib/rubydb/storage/serializer.rb +51 -51
- data/lib/rubydb/storage/snapshot_reader.rb +167 -0
- data/lib/rubydb/storage/storage_layout.rb +151 -151
- data/lib/rubydb/storage/storage_manager.rb +114 -114
- data/lib/rubydb/storage/tuple.rb +458 -461
- data/lib/rubydb/storage/visibility_map.rb +964 -973
- data/lib/rubydb/transactions/commit_manager.rb +219 -220
- data/lib/rubydb/transactions/isolation.rb +98 -98
- data/lib/rubydb/transactions/lock.rb +76 -76
- data/lib/rubydb/transactions/lock_manager.rb +359 -362
- data/lib/rubydb/transactions/savepoint.rb +142 -143
- data/lib/rubydb/transactions/transaction.rb +214 -215
- data/lib/rubydb/transactions/transaction_id.rb +84 -84
- data/lib/rubydb/transactions/transaction_log.rb +256 -257
- data/lib/rubydb/transactions/transaction_manager.rb +434 -435
- data/lib/rubydb/types/bigint.rb +36 -36
- data/lib/rubydb/types/blob.rb +37 -37
- data/lib/rubydb/types/boolean.rb +34 -34
- data/lib/rubydb/types/date.rb +39 -39
- data/lib/rubydb/types/decimal.rb +48 -48
- data/lib/rubydb/types/float.rb +34 -34
- data/lib/rubydb/types/integer.rb +36 -36
- data/lib/rubydb/types/json.rb +41 -41
- data/lib/rubydb/types/null.rb +34 -34
- data/lib/rubydb/types/smallint.rb +36 -36
- data/lib/rubydb/types/text.rb +37 -37
- data/lib/rubydb/types/time.rb +46 -46
- data/lib/rubydb/types/timestamp.rb +39 -39
- data/lib/rubydb/types/type.rb +119 -119
- data/lib/rubydb/types/uuid.rb +47 -47
- data/lib/rubydb/types/varchar.rb +37 -37
- data/lib/rubydb/version.rb +32 -32
- data/lib/rubydb/wal/archive.rb +207 -193
- data/lib/rubydb/wal/checkpoint.rb +181 -183
- data/lib/rubydb/wal/lsn.rb +94 -94
- data/lib/rubydb/wal/reader.rb +259 -260
- data/lib/rubydb/wal/record.rb +105 -105
- data/lib/rubydb/wal/segment.rb +193 -193
- data/lib/rubydb/wal/wal.rb +481 -452
- data/lib/rubydb/wal/writer.rb +236 -236
- data/lib/rubydb.rb +7 -7
- data/packaging/docker/docker-compose.failover.yml +43 -43
- data/packaging/homebrew/rubydb.rb +19 -19
- data/rubydb.gemspec +70 -57
- data/scripts/benchmark +7 -7
- data/scripts/build_accelerator +49 -0
- data/scripts/durability_drill +37 -37
- data/scripts/fuzz +63 -63
- data/scripts/release +77 -42
- data/scripts/release_check +43 -43
- data/scripts/replication_failover_drill +268 -250
- data/scripts/replication_network_failover_drill +287 -255
- data/scripts/restore_drill +45 -45
- data/scripts/security +45 -0
- metadata +102 -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.
|