rubydb 0.1.4 → 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.
- 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 +12 -5
- data/.rubocop.yml +50 -44
- data/.standard.yml +9 -14
- data/ARCHITECTURE.md +21 -21
- data/CHANGELOG.md +43 -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 +249 -162
- data/ROADMAP.md +27 -27
- data/Rakefile +71 -71
- data/SECURITY.md +54 -54
- data/SUPPORT.md +14 -14
- data/adapters/activerecord/Gemfile +11 -11
- data/adapters/activerecord/lib/active_record/connection_adapters/rubydb_adapter.rb +873 -879
- data/adapters/activerecord/rubydb-activerecord.gemspec +20 -20
- 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 +75 -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/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 +275 -275
- data/docs/contributing/architecture.md +9 -9
- data/docs/contributing/benchmarking.md +14 -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 +17 -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 +94 -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 +125 -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 +163 -163
- 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 +74 -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 +302 -304
- data/lib/rubydb/client/connection.rb +414 -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 +123 -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 +179 -179
- data/lib/rubydb/configuration/environment.rb +152 -152
- data/lib/rubydb/configuration/parser.rb +185 -185
- data/lib/rubydb/configuration/validation.rb +221 -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/aggregate_executor.rb +134 -138
- data/lib/rubydb/execution/delete_executor.rb +110 -112
- data/lib/rubydb/execution/distinct_executor.rb +131 -135
- data/lib/rubydb/execution/executor.rb +1182 -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/optimizer.rb +227 -215
- data/lib/rubydb/execution/plan.rb +355 -353
- data/lib/rubydb/execution/planner.rb +542 -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 +180 -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 +186 -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 +564 -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 +371 -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 +2347 -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/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 +190 -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 +480 -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 +60 -57
- data/scripts/benchmark +7 -7
- data/scripts/durability_drill +37 -37
- data/scripts/fuzz +63 -63
- data/scripts/release +45 -40
- 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 +54 -1
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
Gem::Specification.new do |spec|
|
|
4
|
-
spec.name = "rubydb-activerecord"
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |spec|
|
|
4
|
+
spec.name = "rubydb-activerecord"
|
|
5
5
|
spec.version = "0.1.2"
|
|
6
|
-
spec.authors = ["Aldane Hutchinson"]
|
|
7
|
-
spec.email = ["aldanehutchinson5@gmail.com"]
|
|
8
|
-
|
|
9
|
-
spec.summary = "ActiveRecord adapter for RubyDB"
|
|
10
|
-
spec.description = "ActiveRecord adapter for the RubyDB database"
|
|
11
|
-
spec.homepage = "https://github.com/aldanedev-create/rubydb"
|
|
12
|
-
spec.license = "MIT"
|
|
6
|
+
spec.authors = ["Aldane Hutchinson"]
|
|
7
|
+
spec.email = ["aldanehutchinson5@gmail.com"]
|
|
8
|
+
|
|
9
|
+
spec.summary = "ActiveRecord adapter for RubyDB"
|
|
10
|
+
spec.description = "ActiveRecord adapter for the RubyDB database"
|
|
11
|
+
spec.homepage = "https://github.com/aldanedev-create/rubydb"
|
|
12
|
+
spec.license = "MIT"
|
|
13
13
|
# rubydb itself requires Ruby 3.3 or newer. Keep the adapter's runtime
|
|
14
14
|
# contract aligned so Bundler cannot select an unsupported combination.
|
|
15
15
|
spec.required_ruby_version = ">= 3.3.0"
|
|
@@ -21,12 +21,12 @@ Gem::Specification.new do |spec|
|
|
|
21
21
|
spec.metadata["documentation_uri"] = "https://github.com/aldanedev-create/rubydb/tree/main/docs"
|
|
22
22
|
|
|
23
23
|
spec.files = Dir.glob("lib/**/*.rb") + %w[README.md rubydb-activerecord.gemspec]
|
|
24
|
-
spec.require_paths = ["lib"]
|
|
25
|
-
|
|
26
|
-
spec.add_dependency "activerecord", ">= 7.1", "< 8.1"
|
|
27
|
-
spec.add_dependency "rubydb", "~> 0.1.0"
|
|
28
|
-
|
|
29
|
-
spec.add_development_dependency "rake", "~> 13.2"
|
|
30
|
-
spec.add_development_dependency "rspec", "~> 3.13"
|
|
31
|
-
spec.add_development_dependency "rubocop", "~> 1.60"
|
|
32
|
-
end
|
|
24
|
+
spec.require_paths = ["lib"]
|
|
25
|
+
|
|
26
|
+
spec.add_dependency "activerecord", ">= 7.1", "< 8.1"
|
|
27
|
+
spec.add_dependency "rubydb", "~> 0.1.0"
|
|
28
|
+
|
|
29
|
+
spec.add_development_dependency "rake", "~> 13.2"
|
|
30
|
+
spec.add_development_dependency "rspec", "~> 3.13"
|
|
31
|
+
spec.add_development_dependency "rubocop", "~> 1.60"
|
|
32
|
+
end
|
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "tmpdir"
|
|
4
|
-
|
|
5
|
-
$LOAD_PATH.unshift(File.expand_path("../../../lib", __dir__))
|
|
6
|
-
$LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
|
|
7
|
-
|
|
8
|
-
require "rubydb"
|
|
9
|
-
require "active_record"
|
|
10
|
-
require "active_record/connection_adapters/rubydb_adapter"
|
|
11
|
-
|
|
12
|
-
RSpec.describe ActiveRecord::ConnectionAdapters::RubyDBAdapter do
|
|
13
|
-
def migration_version
|
|
14
|
-
"#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
let(:model) do
|
|
18
|
-
Class.new(ActiveRecord::Base) do
|
|
19
|
-
self.table_name = "accounts"
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
around do |example|
|
|
24
|
-
Dir.mktmpdir("rubydb-active-record") do |directory|
|
|
25
|
-
engine = RubyDB::Storage::Engine.new(File.join(directory, "accounts.rdb"), auto_cleanup: false, auto_vacuum: false)
|
|
26
|
-
ActiveRecord::Base.establish_connection(adapter: "rubydb", engine: engine)
|
|
27
|
-
example.run
|
|
28
|
-
ensure
|
|
29
|
-
ActiveRecord::Base.connection_pool.disconnect! if ActiveRecord::Base.connected?
|
|
30
|
-
engine&.close
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "tmpdir"
|
|
4
|
+
|
|
5
|
+
$LOAD_PATH.unshift(File.expand_path("../../../lib", __dir__))
|
|
6
|
+
$LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
|
|
7
|
+
|
|
8
|
+
require "rubydb"
|
|
9
|
+
require "active_record"
|
|
10
|
+
require "active_record/connection_adapters/rubydb_adapter"
|
|
11
|
+
|
|
12
|
+
RSpec.describe ActiveRecord::ConnectionAdapters::RubyDBAdapter do
|
|
13
|
+
def migration_version
|
|
14
|
+
"#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
let(:model) do
|
|
18
|
+
Class.new(ActiveRecord::Base) do
|
|
19
|
+
self.table_name = "accounts"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
around do |example|
|
|
24
|
+
Dir.mktmpdir("rubydb-active-record") do |directory|
|
|
25
|
+
engine = RubyDB::Storage::Engine.new(File.join(directory, "accounts.rdb"), auto_cleanup: false, auto_vacuum: false)
|
|
26
|
+
ActiveRecord::Base.establish_connection(adapter: "rubydb", engine: engine)
|
|
27
|
+
example.run
|
|
28
|
+
ensure
|
|
29
|
+
ActiveRecord::Base.connection_pool.disconnect! if ActiveRecord::Base.connected?
|
|
30
|
+
engine&.close
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
34
|
it "creates and finds an ActiveRecord model through the embedded engine" do
|
|
35
|
-
connection = ActiveRecord::Base.connection
|
|
36
|
-
connection.execute("CREATE TABLE accounts (id INTEGER PRIMARY KEY, email VARCHAR(255) NOT NULL, active BOOLEAN NOT NULL)")
|
|
37
|
-
|
|
38
|
-
created = model.create!(id: 1, email: "ada@example.test", active: true)
|
|
39
|
-
loaded = model.find(created.id)
|
|
40
|
-
|
|
35
|
+
connection = ActiveRecord::Base.connection
|
|
36
|
+
connection.execute("CREATE TABLE accounts (id INTEGER PRIMARY KEY, email VARCHAR(255) NOT NULL, active BOOLEAN NOT NULL)")
|
|
37
|
+
|
|
38
|
+
created = model.create!(id: 1, email: "ada@example.test", active: true)
|
|
39
|
+
loaded = model.find(created.id)
|
|
40
|
+
|
|
41
41
|
expect(loaded.attributes).to include("id" => 1, "email" => "ada@example.test", "active" => true)
|
|
42
42
|
end
|
|
43
43
|
|
|
@@ -50,30 +50,30 @@ RSpec.describe ActiveRecord::ConnectionAdapters::RubyDBAdapter do
|
|
|
50
50
|
|
|
51
51
|
expect(result.first).to include("enabled" => false, "attempts" => 0)
|
|
52
52
|
end
|
|
53
|
-
|
|
53
|
+
|
|
54
54
|
it "runs a Rails migration that creates a table, adds a column, and adds an index" do
|
|
55
|
-
migration = Class.new(ActiveRecord::Migration[migration_version]) do
|
|
56
|
-
def change
|
|
57
|
-
create_table :projects do |table|
|
|
58
|
-
table.string :name, null: false
|
|
59
|
-
end
|
|
60
|
-
add_column :projects, :active, :boolean, default: true, null: false
|
|
61
|
-
add_index :projects, :name, unique: true
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
migration.new.migrate(:up)
|
|
66
|
-
connection = ActiveRecord::Base.connection
|
|
67
|
-
|
|
68
|
-
expect(connection.table_exists?(:projects)).to be(true)
|
|
69
|
-
expect(connection.columns(:projects).map(&:name)).to include("id", "name", "active")
|
|
70
|
-
expect(connection.indexes(:projects)).to include(an_object_having_attributes(name: "idx_projects_name", unique: true))
|
|
71
|
-
schema = connection.dump_schema
|
|
72
|
-
expect(schema).to include('t.boolean "active", default: true, null: false')
|
|
73
|
-
expect(schema).to include('add_index "projects", ["name"], unique: true')
|
|
74
|
-
expect(schema).not_to include('t.integer "id"')
|
|
75
|
-
|
|
76
|
-
migration.new.migrate(:down)
|
|
55
|
+
migration = Class.new(ActiveRecord::Migration[migration_version]) do
|
|
56
|
+
def change
|
|
57
|
+
create_table :projects do |table|
|
|
58
|
+
table.string :name, null: false
|
|
59
|
+
end
|
|
60
|
+
add_column :projects, :active, :boolean, default: true, null: false
|
|
61
|
+
add_index :projects, :name, unique: true
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
migration.new.migrate(:up)
|
|
66
|
+
connection = ActiveRecord::Base.connection
|
|
67
|
+
|
|
68
|
+
expect(connection.table_exists?(:projects)).to be(true)
|
|
69
|
+
expect(connection.columns(:projects).map(&:name)).to include("id", "name", "active")
|
|
70
|
+
expect(connection.indexes(:projects)).to include(an_object_having_attributes(name: "idx_projects_name", unique: true))
|
|
71
|
+
schema = connection.dump_schema
|
|
72
|
+
expect(schema).to include('t.boolean "active", default: true, null: false')
|
|
73
|
+
expect(schema).to include('add_index "projects", ["name"], unique: true')
|
|
74
|
+
expect(schema).not_to include('t.integer "id"')
|
|
75
|
+
|
|
76
|
+
migration.new.migrate(:down)
|
|
77
77
|
expect(connection.table_exists?(:projects)).to be(false)
|
|
78
78
|
end
|
|
79
79
|
|
|
@@ -102,84 +102,84 @@ RSpec.describe ActiveRecord::ConnectionAdapters::RubyDBAdapter do
|
|
|
102
102
|
end
|
|
103
103
|
|
|
104
104
|
it "executes an ActiveRecord association join with qualified filtering" do
|
|
105
|
-
stub_const("RubydbAccount", Class.new(ActiveRecord::Base) do
|
|
106
|
-
self.table_name = "accounts"
|
|
107
|
-
has_many :rubydb_projects, class_name: "RubydbProject", foreign_key: :account_id
|
|
108
|
-
end)
|
|
109
|
-
stub_const("RubydbProject", Class.new(ActiveRecord::Base) do
|
|
110
|
-
self.table_name = "projects"
|
|
111
|
-
belongs_to :rubydb_account, class_name: "RubydbAccount", foreign_key: :account_id
|
|
112
|
-
end)
|
|
113
|
-
|
|
114
|
-
connection = ActiveRecord::Base.connection
|
|
115
|
-
connection.execute("CREATE TABLE accounts (id INTEGER PRIMARY KEY, email VARCHAR(255) NOT NULL)")
|
|
116
|
-
connection.execute("CREATE TABLE projects (id INTEGER PRIMARY KEY, account_id INTEGER NOT NULL, name VARCHAR(255) NOT NULL)")
|
|
117
|
-
account = RubydbAccount.create!(id: 1, email: "ada@example.test")
|
|
118
|
-
RubydbProject.create!(id: 10, account_id: account.id, name: "RubyDB")
|
|
119
|
-
|
|
120
|
-
projects = RubydbProject.joins(:rubydb_account).where(accounts: {
|
|
121
|
-
|
|
122
|
-
expect(projects.map(&:attributes)).to include(hash_including("id" => 10, "name" => "RubyDB", "account_id" => 1))
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
it "loads nested associations and ordered join results from populated tables" do
|
|
126
|
-
stub_const("RubydbAuthor", Class.new(ActiveRecord::Base) do
|
|
127
|
-
self.table_name = "authors"
|
|
128
|
-
has_many :rubydb_books, class_name: "RubydbBook", foreign_key: :author_id
|
|
129
|
-
end)
|
|
130
|
-
stub_const("RubydbBook", Class.new(ActiveRecord::Base) do
|
|
131
|
-
self.table_name = "books"
|
|
132
|
-
belongs_to :rubydb_author, class_name: "RubydbAuthor", foreign_key: :author_id
|
|
133
|
-
has_many :rubydb_reviews, class_name: "RubydbReview", foreign_key: :book_id
|
|
134
|
-
end)
|
|
135
|
-
stub_const("RubydbReview", Class.new(ActiveRecord::Base) do
|
|
136
|
-
self.table_name = "reviews"
|
|
137
|
-
belongs_to :rubydb_book, class_name: "RubydbBook", foreign_key: :book_id
|
|
138
|
-
end)
|
|
139
|
-
|
|
140
|
-
connection = ActiveRecord::Base.connection
|
|
141
|
-
connection.execute("CREATE TABLE authors (id INTEGER PRIMARY KEY, email VARCHAR(255) NOT NULL)")
|
|
142
|
-
connection.execute("CREATE TABLE books (id INTEGER PRIMARY KEY, author_id INTEGER NOT NULL, title VARCHAR(255) NOT NULL)")
|
|
143
|
-
connection.execute("CREATE TABLE reviews (id INTEGER PRIMARY KEY, book_id INTEGER NOT NULL, rating INTEGER NOT NULL)")
|
|
144
|
-
author = RubydbAuthor.create!(id: 1, email: "ada@example.test")
|
|
145
|
-
other = RubydbAuthor.create!(id: 2, email: "other@example.test")
|
|
146
|
-
first = RubydbBook.create!(id: 10, author_id: author.id, title: "A")
|
|
147
|
-
second = RubydbBook.create!(id: 11, author_id: author.id, title: "B")
|
|
148
|
-
RubydbBook.create!(id: 12, author_id: other.id, title: "C")
|
|
149
|
-
RubydbReview.create!(id: 20, book_id: first.id, rating: 5)
|
|
150
|
-
RubydbReview.create!(id: 21, book_id: second.id, rating: 4)
|
|
151
|
-
|
|
152
|
-
loaded = RubydbAuthor.includes(rubydb_books: :rubydb_reviews)
|
|
153
|
-
|
|
154
|
-
joined_titles = RubydbBook.joins(:rubydb_author)
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
expect(loaded.first.rubydb_books.map(&:title)).to contain_exactly("A", "B")
|
|
159
|
-
expect(loaded.first.rubydb_books.flat_map { |book| book.rubydb_reviews.map(&:rating) })
|
|
160
|
-
.to contain_exactly(5, 4)
|
|
161
|
-
expect(joined_titles).to eq(["B", "A"])
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
it "round-trips a migration on a populated table" do
|
|
165
|
-
connection = ActiveRecord::Base.connection
|
|
166
|
-
connection.execute("CREATE TABLE accounts (id INTEGER PRIMARY KEY, email VARCHAR(255) NOT NULL)")
|
|
167
|
-
connection.execute("INSERT INTO accounts (id, email) VALUES (1, 'ada@example.test')")
|
|
168
|
-
|
|
169
|
-
migration = Class.new(ActiveRecord::Migration[migration_version]) do
|
|
170
|
-
def change
|
|
171
|
-
add_column :accounts, :status, :string, default: "new", null: false
|
|
172
|
-
add_index :accounts, :status
|
|
173
|
-
end
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
migration.new.migrate(:up)
|
|
177
|
-
loaded = connection.select_one("SELECT status FROM accounts WHERE id = 1")
|
|
178
|
-
|
|
179
|
-
expect(loaded["status"] || loaded[:status]).to eq("new")
|
|
180
|
-
expect(connection.indexes(:accounts)).to include(an_object_having_attributes(columns: ["status"]))
|
|
181
|
-
|
|
182
|
-
migration.new.migrate(:down)
|
|
183
|
-
expect(connection.columns(:accounts).map(&:name)).not_to include("status")
|
|
184
|
-
end
|
|
185
|
-
end
|
|
105
|
+
stub_const("RubydbAccount", Class.new(ActiveRecord::Base) do
|
|
106
|
+
self.table_name = "accounts"
|
|
107
|
+
has_many :rubydb_projects, class_name: "RubydbProject", foreign_key: :account_id
|
|
108
|
+
end)
|
|
109
|
+
stub_const("RubydbProject", Class.new(ActiveRecord::Base) do
|
|
110
|
+
self.table_name = "projects"
|
|
111
|
+
belongs_to :rubydb_account, class_name: "RubydbAccount", foreign_key: :account_id
|
|
112
|
+
end)
|
|
113
|
+
|
|
114
|
+
connection = ActiveRecord::Base.connection
|
|
115
|
+
connection.execute("CREATE TABLE accounts (id INTEGER PRIMARY KEY, email VARCHAR(255) NOT NULL)")
|
|
116
|
+
connection.execute("CREATE TABLE projects (id INTEGER PRIMARY KEY, account_id INTEGER NOT NULL, name VARCHAR(255) NOT NULL)")
|
|
117
|
+
account = RubydbAccount.create!(id: 1, email: "ada@example.test")
|
|
118
|
+
RubydbProject.create!(id: 10, account_id: account.id, name: "RubyDB")
|
|
119
|
+
|
|
120
|
+
projects = RubydbProject.joins(:rubydb_account).where(accounts: {email: "ada@example.test"}).to_a
|
|
121
|
+
|
|
122
|
+
expect(projects.map(&:attributes)).to include(hash_including("id" => 10, "name" => "RubyDB", "account_id" => 1))
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it "loads nested associations and ordered join results from populated tables" do
|
|
126
|
+
stub_const("RubydbAuthor", Class.new(ActiveRecord::Base) do
|
|
127
|
+
self.table_name = "authors"
|
|
128
|
+
has_many :rubydb_books, class_name: "RubydbBook", foreign_key: :author_id
|
|
129
|
+
end)
|
|
130
|
+
stub_const("RubydbBook", Class.new(ActiveRecord::Base) do
|
|
131
|
+
self.table_name = "books"
|
|
132
|
+
belongs_to :rubydb_author, class_name: "RubydbAuthor", foreign_key: :author_id
|
|
133
|
+
has_many :rubydb_reviews, class_name: "RubydbReview", foreign_key: :book_id
|
|
134
|
+
end)
|
|
135
|
+
stub_const("RubydbReview", Class.new(ActiveRecord::Base) do
|
|
136
|
+
self.table_name = "reviews"
|
|
137
|
+
belongs_to :rubydb_book, class_name: "RubydbBook", foreign_key: :book_id
|
|
138
|
+
end)
|
|
139
|
+
|
|
140
|
+
connection = ActiveRecord::Base.connection
|
|
141
|
+
connection.execute("CREATE TABLE authors (id INTEGER PRIMARY KEY, email VARCHAR(255) NOT NULL)")
|
|
142
|
+
connection.execute("CREATE TABLE books (id INTEGER PRIMARY KEY, author_id INTEGER NOT NULL, title VARCHAR(255) NOT NULL)")
|
|
143
|
+
connection.execute("CREATE TABLE reviews (id INTEGER PRIMARY KEY, book_id INTEGER NOT NULL, rating INTEGER NOT NULL)")
|
|
144
|
+
author = RubydbAuthor.create!(id: 1, email: "ada@example.test")
|
|
145
|
+
other = RubydbAuthor.create!(id: 2, email: "other@example.test")
|
|
146
|
+
first = RubydbBook.create!(id: 10, author_id: author.id, title: "A")
|
|
147
|
+
second = RubydbBook.create!(id: 11, author_id: author.id, title: "B")
|
|
148
|
+
RubydbBook.create!(id: 12, author_id: other.id, title: "C")
|
|
149
|
+
RubydbReview.create!(id: 20, book_id: first.id, rating: 5)
|
|
150
|
+
RubydbReview.create!(id: 21, book_id: second.id, rating: 4)
|
|
151
|
+
|
|
152
|
+
loaded = RubydbAuthor.includes(rubydb_books: :rubydb_reviews)
|
|
153
|
+
.where(email: "ada@example.test").to_a
|
|
154
|
+
joined_titles = RubydbBook.joins(:rubydb_author)
|
|
155
|
+
.where(rubydb_authors: {email: "ada@example.test"})
|
|
156
|
+
.order(title: :desc).pluck(:title)
|
|
157
|
+
|
|
158
|
+
expect(loaded.first.rubydb_books.map(&:title)).to contain_exactly("A", "B")
|
|
159
|
+
expect(loaded.first.rubydb_books.flat_map { |book| book.rubydb_reviews.map(&:rating) })
|
|
160
|
+
.to contain_exactly(5, 4)
|
|
161
|
+
expect(joined_titles).to eq(["B", "A"])
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
it "round-trips a migration on a populated table" do
|
|
165
|
+
connection = ActiveRecord::Base.connection
|
|
166
|
+
connection.execute("CREATE TABLE accounts (id INTEGER PRIMARY KEY, email VARCHAR(255) NOT NULL)")
|
|
167
|
+
connection.execute("INSERT INTO accounts (id, email) VALUES (1, 'ada@example.test')")
|
|
168
|
+
|
|
169
|
+
migration = Class.new(ActiveRecord::Migration[migration_version]) do
|
|
170
|
+
def change
|
|
171
|
+
add_column :accounts, :status, :string, default: "new", null: false
|
|
172
|
+
add_index :accounts, :status
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
migration.new.migrate(:up)
|
|
177
|
+
loaded = connection.select_one("SELECT status FROM accounts WHERE id = 1")
|
|
178
|
+
|
|
179
|
+
expect(loaded["status"] || loaded[:status]).to eq("new")
|
|
180
|
+
expect(connection.indexes(:accounts)).to include(an_object_having_attributes(columns: ["status"]))
|
|
181
|
+
|
|
182
|
+
migration.new.migrate(:down)
|
|
183
|
+
expect(connection.columns(:accounts).map(&:name)).not_to include("status")
|
|
184
|
+
end
|
|
185
|
+
end
|
data/adapters/ruby/README.md
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
# RubyDB Ruby adapter
|
|
2
|
-
|
|
3
|
-
The Ruby adapter is the direct Ruby API for embedded and client/server use.
|
|
4
|
-
For one owning process, open an embedded engine:
|
|
5
|
-
|
|
6
|
-
```ruby
|
|
7
|
-
require "rubydb"
|
|
8
|
-
|
|
9
|
-
engine = RubyDB::Storage::Engine.new("tmp/app.rdb")
|
|
10
|
-
engine.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)")
|
|
11
|
-
engine.execute("INSERT INTO users (id, name) VALUES (1, 'Aldane')")
|
|
12
|
-
engine.close
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
An embedded path has exclusive ownership. Multiple application processes must
|
|
16
|
-
connect to a managed RubyDB server through `RubyDB::Client::Client`. Validate
|
|
17
|
-
the exact RubyDB SQL subset, backup, restore, workload, and recovery procedure
|
|
18
|
-
before using important data. See the root README and `docs/production-readiness.md`.
|
|
1
|
+
# RubyDB Ruby adapter
|
|
2
|
+
|
|
3
|
+
The Ruby adapter is the direct Ruby API for embedded and client/server use.
|
|
4
|
+
For one owning process, open an embedded engine:
|
|
5
|
+
|
|
6
|
+
```ruby
|
|
7
|
+
require "rubydb"
|
|
8
|
+
|
|
9
|
+
engine = RubyDB::Storage::Engine.new("tmp/app.rdb")
|
|
10
|
+
engine.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)")
|
|
11
|
+
engine.execute("INSERT INTO users (id, name) VALUES (1, 'Aldane')")
|
|
12
|
+
engine.close
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
An embedded path has exclusive ownership. Multiple application processes must
|
|
16
|
+
connect to a managed RubyDB server through `RubyDB::Client::Client`. Validate
|
|
17
|
+
the exact RubyDB SQL subset, backup, restore, workload, and recovery procedure
|
|
18
|
+
before using important data. See the root README and `docs/production-readiness.md`.
|
data/adapters/sequel/README.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
# RubyDB Sequel adapter
|
|
2
|
-
|
|
3
|
-
The Sequel adapter is an integration surface for applications that use Sequel.
|
|
4
|
-
It should be configured with a RubyDB connection and kept within the SQL and
|
|
5
|
-
schema features documented by RubyDB. Use one embedded owner or point all
|
|
6
|
-
processes at a RubyDB server; never open the same embedded path independently
|
|
7
|
-
from multiple workers.
|
|
8
|
-
|
|
9
|
-
Before production use, run the application's Sequel schema, query, transaction,
|
|
10
|
-
pool, migration, backup, restore, and failure tests. Compatibility is feature-
|
|
11
|
-
specific and is not a claim of complete PostgreSQL, MySQL, or SQLite behavior.
|
|
1
|
+
# RubyDB Sequel adapter
|
|
2
|
+
|
|
3
|
+
The Sequel adapter is an integration surface for applications that use Sequel.
|
|
4
|
+
It should be configured with a RubyDB connection and kept within the SQL and
|
|
5
|
+
schema features documented by RubyDB. Use one embedded owner or point all
|
|
6
|
+
processes at a RubyDB server; never open the same embedded path independently
|
|
7
|
+
from multiple workers.
|
|
8
|
+
|
|
9
|
+
Before production use, run the application's Sequel schema, query, transaction,
|
|
10
|
+
pool, migration, backup, restore, and failure tests. Compatibility is feature-
|
|
11
|
+
specific and is not a claim of complete PostgreSQL, MySQL, or SQLite behavior.
|
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
groups:
|
|
2
|
-
- name: rubydb-production
|
|
3
|
-
rules:
|
|
4
|
-
- alert: RubyDBNotReady
|
|
5
|
-
expr: rubydb_health_ready == 0
|
|
6
|
-
for: 2m
|
|
7
|
-
labels:
|
|
8
|
-
severity: critical
|
|
9
|
-
annotations:
|
|
10
|
-
summary: RubyDB is not ready to serve traffic
|
|
11
|
-
description: Readiness has been false for more than two minutes.
|
|
12
|
-
- alert: RubyDBConnectionsNearLimit
|
|
13
|
-
expr: rubydb_connections_active / rubydb_connections_max > 0.85
|
|
14
|
-
for: 10m
|
|
15
|
-
labels:
|
|
16
|
-
severity: warning
|
|
17
|
-
annotations:
|
|
18
|
-
summary: RubyDB connection capacity is nearly exhausted
|
|
19
|
-
- alert: RubyDBRequestFailures
|
|
20
|
-
expr: increase(rubydb_requests_failed_total[5m]) > 0
|
|
21
|
-
for: 5m
|
|
22
|
-
labels:
|
|
23
|
-
severity: warning
|
|
24
|
-
annotations:
|
|
25
|
-
summary: RubyDB requests are failing
|
|
26
|
-
- alert: RubyDBReplicationLag
|
|
27
|
-
expr: rubydb_replication_lag_seconds > 10
|
|
28
|
-
for: 2m
|
|
29
|
-
labels:
|
|
30
|
-
severity: critical
|
|
31
|
-
annotations:
|
|
32
|
-
summary: RubyDB replica lag exceeds the promotion threshold
|
|
33
|
-
- alert: RubyDBDiskSpaceLow
|
|
34
|
-
expr: rubydb_disk_free_ratio < 0.15
|
|
35
|
-
for: 5m
|
|
36
|
-
labels:
|
|
37
|
-
severity: critical
|
|
38
|
-
annotations:
|
|
39
|
-
summary: RubyDB storage is running low
|
|
1
|
+
groups:
|
|
2
|
+
- name: rubydb-production
|
|
3
|
+
rules:
|
|
4
|
+
- alert: RubyDBNotReady
|
|
5
|
+
expr: rubydb_health_ready == 0
|
|
6
|
+
for: 2m
|
|
7
|
+
labels:
|
|
8
|
+
severity: critical
|
|
9
|
+
annotations:
|
|
10
|
+
summary: RubyDB is not ready to serve traffic
|
|
11
|
+
description: Readiness has been false for more than two minutes.
|
|
12
|
+
- alert: RubyDBConnectionsNearLimit
|
|
13
|
+
expr: rubydb_connections_active / rubydb_connections_max > 0.85
|
|
14
|
+
for: 10m
|
|
15
|
+
labels:
|
|
16
|
+
severity: warning
|
|
17
|
+
annotations:
|
|
18
|
+
summary: RubyDB connection capacity is nearly exhausted
|
|
19
|
+
- alert: RubyDBRequestFailures
|
|
20
|
+
expr: increase(rubydb_requests_failed_total[5m]) > 0
|
|
21
|
+
for: 5m
|
|
22
|
+
labels:
|
|
23
|
+
severity: warning
|
|
24
|
+
annotations:
|
|
25
|
+
summary: RubyDB requests are failing
|
|
26
|
+
- alert: RubyDBReplicationLag
|
|
27
|
+
expr: rubydb_replication_lag_seconds > 10
|
|
28
|
+
for: 2m
|
|
29
|
+
labels:
|
|
30
|
+
severity: critical
|
|
31
|
+
annotations:
|
|
32
|
+
summary: RubyDB replica lag exceeds the promotion threshold
|
|
33
|
+
- alert: RubyDBDiskSpaceLow
|
|
34
|
+
expr: rubydb_disk_free_ratio < 0.15
|
|
35
|
+
for: 5m
|
|
36
|
+
labels:
|
|
37
|
+
severity: critical
|
|
38
|
+
annotations:
|
|
39
|
+
summary: RubyDB storage is running low
|
data/config/production.yml
CHANGED
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
server:
|
|
2
|
-
host: <%= ENV.fetch("RUBYDB_HOST", "127.0.0.1").to_json %>
|
|
3
|
-
port: <%= ENV.fetch("RUBYDB_PORT", "7432") %>
|
|
4
|
-
max_connections: <%= ENV.fetch("RUBYDB_MAX_CONNECTIONS", "100") %>
|
|
5
|
-
min_workers: <%= ENV.fetch("RUBYDB_MIN_WORKERS", "2") %>
|
|
6
|
-
max_workers: <%= ENV.fetch("RUBYDB_MAX_WORKERS", "20") %>
|
|
7
|
-
worker_queue_size: <%= ENV.fetch("RUBYDB_WORKER_QUEUE_SIZE", "1000") %>
|
|
8
|
-
read_timeout: <%= ENV.fetch("RUBYDB_READ_TIMEOUT", "30") %>
|
|
9
|
-
write_timeout: <%= ENV.fetch("RUBYDB_WRITE_TIMEOUT", "30") %>
|
|
10
|
-
idle_timeout: <%= ENV.fetch("RUBYDB_IDLE_TIMEOUT", "300") %>
|
|
11
|
-
max_request_size: <%= ENV.fetch("RUBYDB_MAX_REQUEST_SIZE", "10485760") %>
|
|
12
|
-
daemonize: false
|
|
13
|
-
pid_file: <%= ENV.fetch("RUBYDB_PID_FILE", "rubydb.pid").to_json %>
|
|
14
|
-
|
|
15
|
-
storage:
|
|
16
|
-
data_dir: <%= ENV.fetch("RUBYDB_DATA_DIR", "/var/lib/rubydb/data").to_json %>
|
|
17
|
-
fsync: true
|
|
18
|
-
wal_enabled: true
|
|
19
|
-
|
|
20
|
-
logging:
|
|
21
|
-
log_dir: <%= ENV.fetch("RUBYDB_LOG_DIR", "/var/log/rubydb").to_json %>
|
|
22
|
-
log_level: <%= ENV.fetch("RUBYDB_LOG_LEVEL", "info").to_json %>
|
|
23
|
-
|
|
24
|
-
auth:
|
|
25
|
-
method: password
|
|
26
|
-
credentials:
|
|
27
|
-
username: <%= ENV.fetch("RUBYDB_USERNAME").to_json %>
|
|
28
|
-
password: <%= ENV.fetch("RUBYDB_PASSWORD").to_json %>
|
|
29
|
-
|
|
30
|
-
ssl:
|
|
31
|
-
enabled: <%= ENV.fetch("RUBYDB_SSL_ENABLED", "true") %>
|
|
32
|
-
cert_file: <%= ENV.fetch("RUBYDB_SSL_CERT_FILE", "/etc/rubydb/tls/server.crt").to_json %>
|
|
33
|
-
key_file: <%= ENV.fetch("RUBYDB_SSL_KEY_FILE", "/etc/rubydb/tls/server.key").to_json %>
|
|
34
|
-
ca_file: <%= ENV.fetch("RUBYDB_SSL_CA_FILE", "/etc/rubydb/tls/ca.crt").to_json %>
|
|
35
|
-
verify_peer: <%= ENV.fetch("RUBYDB_SSL_VERIFY_PEER", "false") %>
|
|
36
|
-
min_version: TLS1_2
|
|
1
|
+
server:
|
|
2
|
+
host: <%= ENV.fetch("RUBYDB_HOST", "127.0.0.1").to_json %>
|
|
3
|
+
port: <%= ENV.fetch("RUBYDB_PORT", "7432") %>
|
|
4
|
+
max_connections: <%= ENV.fetch("RUBYDB_MAX_CONNECTIONS", "100") %>
|
|
5
|
+
min_workers: <%= ENV.fetch("RUBYDB_MIN_WORKERS", "2") %>
|
|
6
|
+
max_workers: <%= ENV.fetch("RUBYDB_MAX_WORKERS", "20") %>
|
|
7
|
+
worker_queue_size: <%= ENV.fetch("RUBYDB_WORKER_QUEUE_SIZE", "1000") %>
|
|
8
|
+
read_timeout: <%= ENV.fetch("RUBYDB_READ_TIMEOUT", "30") %>
|
|
9
|
+
write_timeout: <%= ENV.fetch("RUBYDB_WRITE_TIMEOUT", "30") %>
|
|
10
|
+
idle_timeout: <%= ENV.fetch("RUBYDB_IDLE_TIMEOUT", "300") %>
|
|
11
|
+
max_request_size: <%= ENV.fetch("RUBYDB_MAX_REQUEST_SIZE", "10485760") %>
|
|
12
|
+
daemonize: false
|
|
13
|
+
pid_file: <%= ENV.fetch("RUBYDB_PID_FILE", "rubydb.pid").to_json %>
|
|
14
|
+
|
|
15
|
+
storage:
|
|
16
|
+
data_dir: <%= ENV.fetch("RUBYDB_DATA_DIR", "/var/lib/rubydb/data").to_json %>
|
|
17
|
+
fsync: true
|
|
18
|
+
wal_enabled: true
|
|
19
|
+
|
|
20
|
+
logging:
|
|
21
|
+
log_dir: <%= ENV.fetch("RUBYDB_LOG_DIR", "/var/log/rubydb").to_json %>
|
|
22
|
+
log_level: <%= ENV.fetch("RUBYDB_LOG_LEVEL", "info").to_json %>
|
|
23
|
+
|
|
24
|
+
auth:
|
|
25
|
+
method: password
|
|
26
|
+
credentials:
|
|
27
|
+
username: <%= ENV.fetch("RUBYDB_USERNAME").to_json %>
|
|
28
|
+
password: <%= ENV.fetch("RUBYDB_PASSWORD").to_json %>
|
|
29
|
+
|
|
30
|
+
ssl:
|
|
31
|
+
enabled: <%= ENV.fetch("RUBYDB_SSL_ENABLED", "true") %>
|
|
32
|
+
cert_file: <%= ENV.fetch("RUBYDB_SSL_CERT_FILE", "/etc/rubydb/tls/server.crt").to_json %>
|
|
33
|
+
key_file: <%= ENV.fetch("RUBYDB_SSL_KEY_FILE", "/etc/rubydb/tls/server.key").to_json %>
|
|
34
|
+
ca_file: <%= ENV.fetch("RUBYDB_SSL_CA_FILE", "/etc/rubydb/tls/ca.crt").to_json %>
|
|
35
|
+
verify_peer: <%= ENV.fetch("RUBYDB_SSL_VERIFY_PEER", "false") %>
|
|
36
|
+
min_version: TLS1_2
|