@dotdo/postgres 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +868 -0
- package/dist/cdc/change-stream.d.ts +44 -0
- package/dist/cdc/change-stream.d.ts.map +1 -0
- package/dist/cdc/change-stream.js +95 -0
- package/dist/cdc/change-stream.js.map +1 -0
- package/dist/cdc/filter.d.ts +58 -0
- package/dist/cdc/filter.d.ts.map +1 -0
- package/dist/cdc/filter.js +520 -0
- package/dist/cdc/filter.js.map +1 -0
- package/dist/cdc/index.d.ts +47 -0
- package/dist/cdc/index.d.ts.map +1 -0
- package/dist/cdc/index.js +50 -0
- package/dist/cdc/index.js.map +1 -0
- package/dist/cdc/resume-token.d.ts +60 -0
- package/dist/cdc/resume-token.d.ts.map +1 -0
- package/dist/cdc/resume-token.js +228 -0
- package/dist/cdc/resume-token.js.map +1 -0
- package/dist/cdc/transport/index.d.ts +7 -0
- package/dist/cdc/transport/index.d.ts.map +1 -0
- package/dist/cdc/transport/index.js +7 -0
- package/dist/cdc/transport/index.js.map +1 -0
- package/dist/cdc/transport/sse.d.ts +120 -0
- package/dist/cdc/transport/sse.d.ts.map +1 -0
- package/dist/cdc/transport/sse.js +590 -0
- package/dist/cdc/transport/sse.js.map +1 -0
- package/dist/cdc/transport/websocket.d.ts +130 -0
- package/dist/cdc/transport/websocket.d.ts.map +1 -0
- package/dist/cdc/transport/websocket.js +688 -0
- package/dist/cdc/transport/websocket.js.map +1 -0
- package/dist/cdc/types.d.ts +306 -0
- package/dist/cdc/types.d.ts.map +1 -0
- package/dist/cdc/types.js +8 -0
- package/dist/cdc/types.js.map +1 -0
- package/dist/config/index.d.ts +25 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +25 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/memory.d.ts +139 -0
- package/dist/config/memory.d.ts.map +1 -0
- package/dist/config/memory.js +157 -0
- package/dist/config/memory.js.map +1 -0
- package/dist/config/storage.d.ts +157 -0
- package/dist/config/storage.d.ts.map +1 -0
- package/dist/config/storage.js +178 -0
- package/dist/config/storage.js.map +1 -0
- package/dist/config/streaming.d.ts +117 -0
- package/dist/config/streaming.d.ts.map +1 -0
- package/dist/config/streaming.js +132 -0
- package/dist/config/streaming.js.map +1 -0
- package/dist/config/timeouts.d.ts +168 -0
- package/dist/config/timeouts.d.ts.map +1 -0
- package/dist/config/timeouts.js +192 -0
- package/dist/config/timeouts.js.map +1 -0
- package/dist/extensions/config.d.ts +89 -0
- package/dist/extensions/config.d.ts.map +1 -0
- package/dist/extensions/config.js +216 -0
- package/dist/extensions/config.js.map +1 -0
- package/dist/extensions/geo.d.ts +452 -0
- package/dist/extensions/geo.d.ts.map +1 -0
- package/dist/extensions/geo.js +583 -0
- package/dist/extensions/geo.js.map +1 -0
- package/dist/extensions/index.d.ts +167 -0
- package/dist/extensions/index.d.ts.map +1 -0
- package/dist/extensions/index.js +99 -0
- package/dist/extensions/index.js.map +1 -0
- package/dist/extensions/loader.d.ts +226 -0
- package/dist/extensions/loader.d.ts.map +1 -0
- package/dist/extensions/loader.js +456 -0
- package/dist/extensions/loader.js.map +1 -0
- package/dist/extensions/pgmq-lite.d.ts +330 -0
- package/dist/extensions/pgmq-lite.d.ts.map +1 -0
- package/dist/extensions/pgmq-lite.js +648 -0
- package/dist/extensions/pgmq-lite.js.map +1 -0
- package/dist/extensions/plugins.d.ts +260 -0
- package/dist/extensions/plugins.d.ts.map +1 -0
- package/dist/extensions/plugins.js +535 -0
- package/dist/extensions/plugins.js.map +1 -0
- package/dist/extensions/registry.d.ts +93 -0
- package/dist/extensions/registry.d.ts.map +1 -0
- package/dist/extensions/registry.js +182 -0
- package/dist/extensions/registry.js.map +1 -0
- package/dist/extensions/vector.d.ts +106 -0
- package/dist/extensions/vector.d.ts.map +1 -0
- package/dist/extensions/vector.js +129 -0
- package/dist/extensions/vector.js.map +1 -0
- package/dist/iceberg/analytics.d.ts +279 -0
- package/dist/iceberg/analytics.d.ts.map +1 -0
- package/dist/iceberg/analytics.js +448 -0
- package/dist/iceberg/analytics.js.map +1 -0
- package/dist/iceberg/catalog-api.d.ts +39 -0
- package/dist/iceberg/catalog-api.d.ts.map +1 -0
- package/dist/iceberg/catalog-api.js +388 -0
- package/dist/iceberg/catalog-api.js.map +1 -0
- package/dist/iceberg/catalog.d.ts +401 -0
- package/dist/iceberg/catalog.d.ts.map +1 -0
- package/dist/iceberg/catalog.js +677 -0
- package/dist/iceberg/catalog.js.map +1 -0
- package/dist/iceberg/duckdb-wasm.d.ts +447 -0
- package/dist/iceberg/duckdb-wasm.d.ts.map +1 -0
- package/dist/iceberg/duckdb-wasm.js +600 -0
- package/dist/iceberg/duckdb-wasm.js.map +1 -0
- package/dist/iceberg/index.d.ts +92 -0
- package/dist/iceberg/index.d.ts.map +1 -0
- package/dist/iceberg/index.js +119 -0
- package/dist/iceberg/index.js.map +1 -0
- package/dist/iceberg/metadata.d.ts +214 -0
- package/dist/iceberg/metadata.d.ts.map +1 -0
- package/dist/iceberg/metadata.js +535 -0
- package/dist/iceberg/metadata.js.map +1 -0
- package/dist/iceberg/optimizer.d.ts +296 -0
- package/dist/iceberg/optimizer.d.ts.map +1 -0
- package/dist/iceberg/optimizer.js +889 -0
- package/dist/iceberg/optimizer.js.map +1 -0
- package/dist/iceberg/parquet.d.ts +447 -0
- package/dist/iceberg/parquet.d.ts.map +1 -0
- package/dist/iceberg/parquet.js +1225 -0
- package/dist/iceberg/parquet.js.map +1 -0
- package/dist/iceberg/r2-organization.d.ts +422 -0
- package/dist/iceberg/r2-organization.d.ts.map +1 -0
- package/dist/iceberg/r2-organization.js +672 -0
- package/dist/iceberg/r2-organization.js.map +1 -0
- package/dist/iceberg/scheduler-do-example.d.ts +158 -0
- package/dist/iceberg/scheduler-do-example.d.ts.map +1 -0
- package/dist/iceberg/scheduler-do-example.js +261 -0
- package/dist/iceberg/scheduler-do-example.js.map +1 -0
- package/dist/iceberg/scheduler.d.ts +434 -0
- package/dist/iceberg/scheduler.d.ts.map +1 -0
- package/dist/iceberg/scheduler.js +818 -0
- package/dist/iceberg/scheduler.js.map +1 -0
- package/dist/iceberg/schema.d.ts +149 -0
- package/dist/iceberg/schema.d.ts.map +1 -0
- package/dist/iceberg/schema.js +525 -0
- package/dist/iceberg/schema.js.map +1 -0
- package/dist/iceberg/snapshot-manager.d.ts +406 -0
- package/dist/iceberg/snapshot-manager.d.ts.map +1 -0
- package/dist/iceberg/snapshot-manager.js +934 -0
- package/dist/iceberg/snapshot-manager.js.map +1 -0
- package/dist/iceberg/sql-router.d.ts +194 -0
- package/dist/iceberg/sql-router.d.ts.map +1 -0
- package/dist/iceberg/sql-router.js +180 -0
- package/dist/iceberg/sql-router.js.map +1 -0
- package/dist/iceberg/test-fixtures.d.ts +151 -0
- package/dist/iceberg/test-fixtures.d.ts.map +1 -0
- package/dist/iceberg/test-fixtures.js +446 -0
- package/dist/iceberg/test-fixtures.js.map +1 -0
- package/dist/iceberg/time-travel-api.d.ts +102 -0
- package/dist/iceberg/time-travel-api.d.ts.map +1 -0
- package/dist/iceberg/time-travel-api.js +437 -0
- package/dist/iceberg/time-travel-api.js.map +1 -0
- package/dist/iceberg/time-travel.d.ts +293 -0
- package/dist/iceberg/time-travel.d.ts.map +1 -0
- package/dist/iceberg/time-travel.js +689 -0
- package/dist/iceberg/time-travel.js.map +1 -0
- package/dist/iceberg/transformer.d.ts +356 -0
- package/dist/iceberg/transformer.d.ts.map +1 -0
- package/dist/iceberg/transformer.js +770 -0
- package/dist/iceberg/transformer.js.map +1 -0
- package/dist/iceberg/types.d.ts +318 -0
- package/dist/iceberg/types.d.ts.map +1 -0
- package/dist/iceberg/types.js +9 -0
- package/dist/iceberg/types.js.map +1 -0
- package/dist/iceberg/writer.d.ts +144 -0
- package/dist/iceberg/writer.d.ts.map +1 -0
- package/dist/iceberg/writer.js +452 -0
- package/dist/iceberg/writer.js.map +1 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +69 -0
- package/dist/index.js.map +1 -0
- package/dist/lineage/index.d.ts +11 -0
- package/dist/lineage/index.d.ts.map +1 -0
- package/dist/lineage/index.js +11 -0
- package/dist/lineage/index.js.map +1 -0
- package/dist/lineage/integration.d.ts +134 -0
- package/dist/lineage/integration.d.ts.map +1 -0
- package/dist/lineage/integration.js +258 -0
- package/dist/lineage/integration.js.map +1 -0
- package/dist/lineage/tracker.d.ts +189 -0
- package/dist/lineage/tracker.d.ts.map +1 -0
- package/dist/lineage/tracker.js +1352 -0
- package/dist/lineage/tracker.js.map +1 -0
- package/dist/lineage/types.d.ts +318 -0
- package/dist/lineage/types.d.ts.map +1 -0
- package/dist/lineage/types.js +9 -0
- package/dist/lineage/types.js.map +1 -0
- package/dist/middleware/index.d.ts +11 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +16 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/rate-limit.d.ts +397 -0
- package/dist/middleware/rate-limit.d.ts.map +1 -0
- package/dist/middleware/rate-limit.js +507 -0
- package/dist/middleware/rate-limit.js.map +1 -0
- package/dist/migration-tooling/external-migration.d.ts +601 -0
- package/dist/migration-tooling/external-migration.d.ts.map +1 -0
- package/dist/migration-tooling/external-migration.js +1612 -0
- package/dist/migration-tooling/external-migration.js.map +1 -0
- package/dist/migration-tooling/index.d.ts +19 -0
- package/dist/migration-tooling/index.d.ts.map +1 -0
- package/dist/migration-tooling/index.js +19 -0
- package/dist/migration-tooling/index.js.map +1 -0
- package/dist/migrations/auto-migrator.d.ts +289 -0
- package/dist/migrations/auto-migrator.d.ts.map +1 -0
- package/dist/migrations/auto-migrator.js +396 -0
- package/dist/migrations/auto-migrator.js.map +1 -0
- package/dist/migrations/bulk-orchestrator.d.ts +403 -0
- package/dist/migrations/bulk-orchestrator.d.ts.map +1 -0
- package/dist/migrations/bulk-orchestrator.js +646 -0
- package/dist/migrations/bulk-orchestrator.js.map +1 -0
- package/dist/migrations/compatibility.d.ts +216 -0
- package/dist/migrations/compatibility.d.ts.map +1 -0
- package/dist/migrations/compatibility.js +651 -0
- package/dist/migrations/compatibility.js.map +1 -0
- package/dist/migrations/do-migrations.d.ts +101 -0
- package/dist/migrations/do-migrations.d.ts.map +1 -0
- package/dist/migrations/do-migrations.js +1060 -0
- package/dist/migrations/do-migrations.js.map +1 -0
- package/dist/migrations/do-migrations.types.d.ts +550 -0
- package/dist/migrations/do-migrations.types.d.ts.map +1 -0
- package/dist/migrations/do-migrations.types.js +15 -0
- package/dist/migrations/do-migrations.types.js.map +1 -0
- package/dist/migrations/drizzle-compat.d.ts +163 -0
- package/dist/migrations/drizzle-compat.d.ts.map +1 -0
- package/dist/migrations/drizzle-compat.js +273 -0
- package/dist/migrations/drizzle-compat.js.map +1 -0
- package/dist/migrations/index.d.ts +109 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +127 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/migrations/migration-api.d.ts +161 -0
- package/dist/migrations/migration-api.d.ts.map +1 -0
- package/dist/migrations/migration-api.js +499 -0
- package/dist/migrations/migration-api.js.map +1 -0
- package/dist/migrations/progress-tracker-do.d.ts +195 -0
- package/dist/migrations/progress-tracker-do.d.ts.map +1 -0
- package/dist/migrations/progress-tracker-do.js +339 -0
- package/dist/migrations/progress-tracker-do.js.map +1 -0
- package/dist/migrations/progress-tracker-kv.d.ts +103 -0
- package/dist/migrations/progress-tracker-kv.d.ts.map +1 -0
- package/dist/migrations/progress-tracker-kv.js +231 -0
- package/dist/migrations/progress-tracker-kv.js.map +1 -0
- package/dist/migrations/progress-tracker.d.ts +320 -0
- package/dist/migrations/progress-tracker.d.ts.map +1 -0
- package/dist/migrations/progress-tracker.js +443 -0
- package/dist/migrations/progress-tracker.js.map +1 -0
- package/dist/migrations/registry.d.ts +231 -0
- package/dist/migrations/registry.d.ts.map +1 -0
- package/dist/migrations/registry.js +376 -0
- package/dist/migrations/registry.js.map +1 -0
- package/dist/migrations/runner.d.ts +197 -0
- package/dist/migrations/runner.d.ts.map +1 -0
- package/dist/migrations/runner.js +1167 -0
- package/dist/migrations/runner.js.map +1 -0
- package/dist/migrations/schema-generator.d.ts +111 -0
- package/dist/migrations/schema-generator.d.ts.map +1 -0
- package/dist/migrations/schema-generator.js +335 -0
- package/dist/migrations/schema-generator.js.map +1 -0
- package/dist/migrations/testing.d.ts +321 -0
- package/dist/migrations/testing.d.ts.map +1 -0
- package/dist/migrations/testing.js +645 -0
- package/dist/migrations/testing.js.map +1 -0
- package/dist/migrations/types.d.ts +503 -0
- package/dist/migrations/types.d.ts.map +1 -0
- package/dist/migrations/types.js +11 -0
- package/dist/migrations/types.js.map +1 -0
- package/dist/migrations/validator.d.ts +215 -0
- package/dist/migrations/validator.d.ts.map +1 -0
- package/dist/migrations/validator.js +494 -0
- package/dist/migrations/validator.js.map +1 -0
- package/dist/observability/alerting.d.ts +116 -0
- package/dist/observability/alerting.d.ts.map +1 -0
- package/dist/observability/alerting.js +353 -0
- package/dist/observability/alerting.js.map +1 -0
- package/dist/observability/analytics-engine.d.ts +357 -0
- package/dist/observability/analytics-engine.d.ts.map +1 -0
- package/dist/observability/analytics-engine.js +430 -0
- package/dist/observability/analytics-engine.js.map +1 -0
- package/dist/observability/cost-metrics.d.ts +269 -0
- package/dist/observability/cost-metrics.d.ts.map +1 -0
- package/dist/observability/cost-metrics.js +560 -0
- package/dist/observability/cost-metrics.js.map +1 -0
- package/dist/observability/cross-do-tracing.d.ts +305 -0
- package/dist/observability/cross-do-tracing.d.ts.map +1 -0
- package/dist/observability/cross-do-tracing.js +431 -0
- package/dist/observability/cross-do-tracing.js.map +1 -0
- package/dist/observability/error-rate-collector.d.ts +163 -0
- package/dist/observability/error-rate-collector.d.ts.map +1 -0
- package/dist/observability/error-rate-collector.js +306 -0
- package/dist/observability/error-rate-collector.js.map +1 -0
- package/dist/observability/exporters.d.ts +231 -0
- package/dist/observability/exporters.d.ts.map +1 -0
- package/dist/observability/exporters.js +479 -0
- package/dist/observability/exporters.js.map +1 -0
- package/dist/observability/health-check.d.ts +106 -0
- package/dist/observability/health-check.d.ts.map +1 -0
- package/dist/observability/health-check.js +243 -0
- package/dist/observability/health-check.js.map +1 -0
- package/dist/observability/index.d.ts +297 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/observability/index.js +455 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/observability/instrumentation.d.ts +222 -0
- package/dist/observability/instrumentation.d.ts.map +1 -0
- package/dist/observability/instrumentation.js +532 -0
- package/dist/observability/instrumentation.js.map +1 -0
- package/dist/observability/memory-metrics.d.ts +227 -0
- package/dist/observability/memory-metrics.d.ts.map +1 -0
- package/dist/observability/memory-metrics.js +688 -0
- package/dist/observability/memory-metrics.js.map +1 -0
- package/dist/observability/metrics-endpoint.d.ts +91 -0
- package/dist/observability/metrics-endpoint.d.ts.map +1 -0
- package/dist/observability/metrics-endpoint.js +246 -0
- package/dist/observability/metrics-endpoint.js.map +1 -0
- package/dist/observability/metrics.d.ts +88 -0
- package/dist/observability/metrics.d.ts.map +1 -0
- package/dist/observability/metrics.js +253 -0
- package/dist/observability/metrics.js.map +1 -0
- package/dist/observability/observability-features.d.ts +488 -0
- package/dist/observability/observability-features.d.ts.map +1 -0
- package/dist/observability/observability-features.js +773 -0
- package/dist/observability/observability-features.js.map +1 -0
- package/dist/observability/prometheus.d.ts +39 -0
- package/dist/observability/prometheus.d.ts.map +1 -0
- package/dist/observability/prometheus.js +120 -0
- package/dist/observability/prometheus.js.map +1 -0
- package/dist/observability/propagation.d.ts +126 -0
- package/dist/observability/propagation.d.ts.map +1 -0
- package/dist/observability/propagation.js +234 -0
- package/dist/observability/propagation.js.map +1 -0
- package/dist/observability/query-latency.d.ts +243 -0
- package/dist/observability/query-latency.d.ts.map +1 -0
- package/dist/observability/query-latency.js +292 -0
- package/dist/observability/query-latency.js.map +1 -0
- package/dist/observability/query-performance.d.ts +169 -0
- package/dist/observability/query-performance.d.ts.map +1 -0
- package/dist/observability/query-performance.js +290 -0
- package/dist/observability/query-performance.js.map +1 -0
- package/dist/observability/storage-tier-metrics.d.ts +174 -0
- package/dist/observability/storage-tier-metrics.d.ts.map +1 -0
- package/dist/observability/storage-tier-metrics.js +306 -0
- package/dist/observability/storage-tier-metrics.js.map +1 -0
- package/dist/observability/tier-cost-optimizer.d.ts +155 -0
- package/dist/observability/tier-cost-optimizer.d.ts.map +1 -0
- package/dist/observability/tier-cost-optimizer.js +536 -0
- package/dist/observability/tier-cost-optimizer.js.map +1 -0
- package/dist/observability/tracer.d.ts +149 -0
- package/dist/observability/tracer.d.ts.map +1 -0
- package/dist/observability/tracer.js +435 -0
- package/dist/observability/tracer.js.map +1 -0
- package/dist/observability/types.d.ts +402 -0
- package/dist/observability/types.d.ts.map +1 -0
- package/dist/observability/types.js +103 -0
- package/dist/observability/types.js.map +1 -0
- package/dist/pglite/workers-pglite.d.ts +138 -0
- package/dist/pglite/workers-pglite.d.ts.map +1 -0
- package/dist/pglite/workers-pglite.js +143 -0
- package/dist/pglite/workers-pglite.js.map +1 -0
- package/dist/pglite-assets/pglite.data +0 -0
- package/dist/pglite-assets/pglite.wasm +0 -0
- package/dist/playground/index.d.ts +52 -0
- package/dist/playground/index.d.ts.map +1 -0
- package/dist/playground/index.js +55 -0
- package/dist/playground/index.js.map +1 -0
- package/dist/playground/keyboard-shortcuts.d.ts +116 -0
- package/dist/playground/keyboard-shortcuts.d.ts.map +1 -0
- package/dist/playground/keyboard-shortcuts.js +588 -0
- package/dist/playground/keyboard-shortcuts.js.map +1 -0
- package/dist/playground/playground.d.ts +82 -0
- package/dist/playground/playground.d.ts.map +1 -0
- package/dist/playground/playground.js +271 -0
- package/dist/playground/playground.js.map +1 -0
- package/dist/playground/query-executor.d.ts +115 -0
- package/dist/playground/query-executor.d.ts.map +1 -0
- package/dist/playground/query-executor.js +558 -0
- package/dist/playground/query-executor.js.map +1 -0
- package/dist/playground/query-history.d.ts +92 -0
- package/dist/playground/query-history.d.ts.map +1 -0
- package/dist/playground/query-history.js +259 -0
- package/dist/playground/query-history.js.map +1 -0
- package/dist/playground/result-formatter.d.ts +59 -0
- package/dist/playground/result-formatter.d.ts.map +1 -0
- package/dist/playground/result-formatter.js +341 -0
- package/dist/playground/result-formatter.js.map +1 -0
- package/dist/playground/sample-datasets.d.ts +77 -0
- package/dist/playground/sample-datasets.d.ts.map +1 -0
- package/dist/playground/sample-datasets.js +641 -0
- package/dist/playground/sample-datasets.js.map +1 -0
- package/dist/playground/sample-queries.d.ts +73 -0
- package/dist/playground/sample-queries.d.ts.map +1 -0
- package/dist/playground/sample-queries.js +1095 -0
- package/dist/playground/sample-queries.js.map +1 -0
- package/dist/playground/schema-explorer.d.ts +55 -0
- package/dist/playground/schema-explorer.d.ts.map +1 -0
- package/dist/playground/schema-explorer.js +473 -0
- package/dist/playground/schema-explorer.js.map +1 -0
- package/dist/playground/types.d.ts +430 -0
- package/dist/playground/types.d.ts.map +1 -0
- package/dist/playground/types.js +10 -0
- package/dist/playground/types.js.map +1 -0
- package/dist/readonly/cache-reader.d.ts +145 -0
- package/dist/readonly/cache-reader.d.ts.map +1 -0
- package/dist/readonly/cache-reader.js +198 -0
- package/dist/readonly/cache-reader.js.map +1 -0
- package/dist/readonly/config.d.ts +74 -0
- package/dist/readonly/config.d.ts.map +1 -0
- package/dist/readonly/config.js +67 -0
- package/dist/readonly/config.js.map +1 -0
- package/dist/readonly/index.d.ts +22 -0
- package/dist/readonly/index.d.ts.map +1 -0
- package/dist/readonly/index.js +17 -0
- package/dist/readonly/index.js.map +1 -0
- package/dist/readonly/pglite-wrapper.d.ts +82 -0
- package/dist/readonly/pglite-wrapper.d.ts.map +1 -0
- package/dist/readonly/pglite-wrapper.js +123 -0
- package/dist/readonly/pglite-wrapper.js.map +1 -0
- package/dist/readonly/worker.d.ts +142 -0
- package/dist/readonly/worker.d.ts.map +1 -0
- package/dist/readonly/worker.js +187 -0
- package/dist/readonly/worker.js.map +1 -0
- package/dist/readonly/write-blocker.d.ts +47 -0
- package/dist/readonly/write-blocker.d.ts.map +1 -0
- package/dist/readonly/write-blocker.js +136 -0
- package/dist/readonly/write-blocker.js.map +1 -0
- package/dist/recovery/disaster-recovery.d.ts +326 -0
- package/dist/recovery/disaster-recovery.d.ts.map +1 -0
- package/dist/recovery/disaster-recovery.js +799 -0
- package/dist/recovery/disaster-recovery.js.map +1 -0
- package/dist/recovery/index.d.ts +12 -0
- package/dist/recovery/index.d.ts.map +1 -0
- package/dist/recovery/index.js +12 -0
- package/dist/recovery/index.js.map +1 -0
- package/dist/recovery/parquet-parser.d.ts +321 -0
- package/dist/recovery/parquet-parser.d.ts.map +1 -0
- package/dist/recovery/parquet-parser.js +797 -0
- package/dist/recovery/parquet-parser.js.map +1 -0
- package/dist/retention/index.d.ts +50 -0
- package/dist/retention/index.d.ts.map +1 -0
- package/dist/retention/index.js +50 -0
- package/dist/retention/index.js.map +1 -0
- package/dist/retention/policy.d.ts +344 -0
- package/dist/retention/policy.d.ts.map +1 -0
- package/dist/retention/policy.js +472 -0
- package/dist/retention/policy.js.map +1 -0
- package/dist/retention/purger.d.ts +187 -0
- package/dist/retention/purger.d.ts.map +1 -0
- package/dist/retention/purger.js +411 -0
- package/dist/retention/purger.js.map +1 -0
- package/dist/rls/auth-integration.d.ts +280 -0
- package/dist/rls/auth-integration.d.ts.map +1 -0
- package/dist/rls/auth-integration.js +399 -0
- package/dist/rls/auth-integration.js.map +1 -0
- package/dist/rls/generator.d.ts +249 -0
- package/dist/rls/generator.d.ts.map +1 -0
- package/dist/rls/generator.js +495 -0
- package/dist/rls/generator.js.map +1 -0
- package/dist/rls/index.d.ts +26 -0
- package/dist/rls/index.d.ts.map +1 -0
- package/dist/rls/index.js +58 -0
- package/dist/rls/index.js.map +1 -0
- package/dist/rls/policy.d.ts +116 -0
- package/dist/rls/policy.d.ts.map +1 -0
- package/dist/rls/policy.js +77 -0
- package/dist/rls/policy.js.map +1 -0
- package/dist/rls/validator.d.ts +155 -0
- package/dist/rls/validator.d.ts.map +1 -0
- package/dist/rls/validator.js +792 -0
- package/dist/rls/validator.js.map +1 -0
- package/dist/routing/adaptive-router.d.ts +317 -0
- package/dist/routing/adaptive-router.d.ts.map +1 -0
- package/dist/routing/adaptive-router.js +554 -0
- package/dist/routing/adaptive-router.js.map +1 -0
- package/dist/routing/circuit-breaker.d.ts +339 -0
- package/dist/routing/circuit-breaker.d.ts.map +1 -0
- package/dist/routing/circuit-breaker.js +620 -0
- package/dist/routing/circuit-breaker.js.map +1 -0
- package/dist/routing/cost-metrics.d.ts +133 -0
- package/dist/routing/cost-metrics.d.ts.map +1 -0
- package/dist/routing/cost-metrics.js +259 -0
- package/dist/routing/cost-metrics.js.map +1 -0
- package/dist/routing/do-connection-pool.d.ts +243 -0
- package/dist/routing/do-connection-pool.d.ts.map +1 -0
- package/dist/routing/do-connection-pool.js +572 -0
- package/dist/routing/do-connection-pool.js.map +1 -0
- package/dist/routing/index.d.ts +59 -0
- package/dist/routing/index.d.ts.map +1 -0
- package/dist/routing/index.js +59 -0
- package/dist/routing/index.js.map +1 -0
- package/dist/routing/query-complexity-estimator.d.ts +73 -0
- package/dist/routing/query-complexity-estimator.d.ts.map +1 -0
- package/dist/routing/query-complexity-estimator.js +327 -0
- package/dist/routing/query-complexity-estimator.js.map +1 -0
- package/dist/routing/request-coalescing.d.ts +178 -0
- package/dist/routing/request-coalescing.d.ts.map +1 -0
- package/dist/routing/request-coalescing.js +325 -0
- package/dist/routing/request-coalescing.js.map +1 -0
- package/dist/routing/runtime-router.d.ts +107 -0
- package/dist/routing/runtime-router.d.ts.map +1 -0
- package/dist/routing/runtime-router.js +246 -0
- package/dist/routing/runtime-router.js.map +1 -0
- package/dist/routing/tenant-router.d.ts +848 -0
- package/dist/routing/tenant-router.d.ts.map +1 -0
- package/dist/routing/tenant-router.js +1056 -0
- package/dist/routing/tenant-router.js.map +1 -0
- package/dist/routing/websocket-pool.d.ts +119 -0
- package/dist/routing/websocket-pool.d.ts.map +1 -0
- package/dist/routing/websocket-pool.js +436 -0
- package/dist/routing/websocket-pool.js.map +1 -0
- package/dist/storage/cache-layer.d.ts +159 -0
- package/dist/storage/cache-layer.d.ts.map +1 -0
- package/dist/storage/cache-layer.js +245 -0
- package/dist/storage/cache-layer.js.map +1 -0
- package/dist/storage/cost-aware-tiering.d.ts +258 -0
- package/dist/storage/cost-aware-tiering.d.ts.map +1 -0
- package/dist/storage/cost-aware-tiering.js +526 -0
- package/dist/storage/cost-aware-tiering.js.map +1 -0
- package/dist/storage/index.d.ts +87 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +78 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/interfaces.d.ts +856 -0
- package/dist/storage/interfaces.d.ts.map +1 -0
- package/dist/storage/interfaces.js +69 -0
- package/dist/storage/interfaces.js.map +1 -0
- package/dist/storage/r2-layer.d.ts +226 -0
- package/dist/storage/r2-layer.d.ts.map +1 -0
- package/dist/storage/r2-layer.js +307 -0
- package/dist/storage/r2-layer.js.map +1 -0
- package/dist/storage/r2-overflow.d.ts +344 -0
- package/dist/storage/r2-overflow.d.ts.map +1 -0
- package/dist/storage/r2-overflow.js +730 -0
- package/dist/storage/r2-overflow.js.map +1 -0
- package/dist/storage/r2-page-vfs.d.ts +374 -0
- package/dist/storage/r2-page-vfs.d.ts.map +1 -0
- package/dist/storage/r2-page-vfs.js +754 -0
- package/dist/storage/r2-page-vfs.js.map +1 -0
- package/dist/storage/swr-cache.d.ts +181 -0
- package/dist/storage/swr-cache.d.ts.map +1 -0
- package/dist/storage/swr-cache.js +295 -0
- package/dist/storage/swr-cache.js.map +1 -0
- package/dist/storage/tiered-orchestrator.d.ts +951 -0
- package/dist/storage/tiered-orchestrator.d.ts.map +1 -0
- package/dist/storage/tiered-orchestrator.js +1731 -0
- package/dist/storage/tiered-orchestrator.js.map +1 -0
- package/dist/storage/tiered-vfs-swr.d.ts +279 -0
- package/dist/storage/tiered-vfs-swr.d.ts.map +1 -0
- package/dist/storage/tiered-vfs-swr.js +584 -0
- package/dist/storage/tiered-vfs-swr.js.map +1 -0
- package/dist/storage/tiered-vfs.d.ts +405 -0
- package/dist/storage/tiered-vfs.d.ts.map +1 -0
- package/dist/storage/tiered-vfs.js +833 -0
- package/dist/storage/tiered-vfs.js.map +1 -0
- package/dist/streaming/backpressure-controller.d.ts +173 -0
- package/dist/streaming/backpressure-controller.d.ts.map +1 -0
- package/dist/streaming/backpressure-controller.js +344 -0
- package/dist/streaming/backpressure-controller.js.map +1 -0
- package/dist/streaming/buffer-pool.d.ts +241 -0
- package/dist/streaming/buffer-pool.d.ts.map +1 -0
- package/dist/streaming/buffer-pool.js +381 -0
- package/dist/streaming/buffer-pool.js.map +1 -0
- package/dist/streaming/cdc-iceberg-connector.d.ts +272 -0
- package/dist/streaming/cdc-iceberg-connector.d.ts.map +1 -0
- package/dist/streaming/cdc-iceberg-connector.js +408 -0
- package/dist/streaming/cdc-iceberg-connector.js.map +1 -0
- package/dist/streaming/index.d.ts +111 -0
- package/dist/streaming/index.d.ts.map +1 -0
- package/dist/streaming/index.js +128 -0
- package/dist/streaming/index.js.map +1 -0
- package/dist/streaming/live-cdc-stream.d.ts +400 -0
- package/dist/streaming/live-cdc-stream.d.ts.map +1 -0
- package/dist/streaming/live-cdc-stream.js +703 -0
- package/dist/streaming/live-cdc-stream.js.map +1 -0
- package/dist/streaming/memory-bounded-stream.d.ts +207 -0
- package/dist/streaming/memory-bounded-stream.d.ts.map +1 -0
- package/dist/streaming/memory-bounded-stream.js +340 -0
- package/dist/streaming/memory-bounded-stream.js.map +1 -0
- package/dist/streaming/query-streamer.d.ts +379 -0
- package/dist/streaming/query-streamer.d.ts.map +1 -0
- package/dist/streaming/query-streamer.js +495 -0
- package/dist/streaming/query-streamer.js.map +1 -0
- package/dist/streaming/response-streaming.d.ts +203 -0
- package/dist/streaming/response-streaming.d.ts.map +1 -0
- package/dist/streaming/response-streaming.js +449 -0
- package/dist/streaming/response-streaming.js.map +1 -0
- package/dist/types/branded.d.ts +859 -0
- package/dist/types/branded.d.ts.map +1 -0
- package/dist/types/branded.js +891 -0
- package/dist/types/branded.js.map +1 -0
- package/dist/types/utilities.d.ts +757 -0
- package/dist/types/utilities.d.ts.map +1 -0
- package/dist/types/utilities.js +447 -0
- package/dist/types/utilities.js.map +1 -0
- package/dist/wal/replay-engine.d.ts +344 -0
- package/dist/wal/replay-engine.d.ts.map +1 -0
- package/dist/wal/replay-engine.js +975 -0
- package/dist/wal/replay-engine.js.map +1 -0
- package/dist/worker/__mocks__/capnweb.d.ts +13 -0
- package/dist/worker/__mocks__/capnweb.d.ts.map +1 -0
- package/dist/worker/__mocks__/capnweb.js +15 -0
- package/dist/worker/__mocks__/capnweb.js.map +1 -0
- package/dist/worker/__mocks__/cloudflare-workers.d.ts +31 -0
- package/dist/worker/__mocks__/cloudflare-workers.d.ts.map +1 -0
- package/dist/worker/__mocks__/cloudflare-workers.js +33 -0
- package/dist/worker/__mocks__/cloudflare-workers.js.map +1 -0
- package/dist/worker/__mocks__/pglite.data.d.ts +3 -0
- package/dist/worker/__mocks__/pglite.data.d.ts.map +1 -0
- package/dist/worker/__mocks__/pglite.data.js +20 -0
- package/dist/worker/__mocks__/pglite.data.js.map +1 -0
- package/dist/worker/__mocks__/pglite.wasm.d.ts +3 -0
- package/dist/worker/__mocks__/pglite.wasm.d.ts.map +1 -0
- package/dist/worker/__mocks__/pglite.wasm.js +30 -0
- package/dist/worker/__mocks__/pglite.wasm.js.map +1 -0
- package/dist/worker/auth-rate-limiter.d.ts +270 -0
- package/dist/worker/auth-rate-limiter.d.ts.map +1 -0
- package/dist/worker/auth-rate-limiter.js +332 -0
- package/dist/worker/auth-rate-limiter.js.map +1 -0
- package/dist/worker/auth.d.ts +345 -0
- package/dist/worker/auth.d.ts.map +1 -0
- package/dist/worker/auth.js +837 -0
- package/dist/worker/auth.js.map +1 -0
- package/dist/worker/cdc-backpressure.d.ts +338 -0
- package/dist/worker/cdc-backpressure.d.ts.map +1 -0
- package/dist/worker/cdc-backpressure.js +619 -0
- package/dist/worker/cdc-backpressure.js.map +1 -0
- package/dist/worker/cdc-sse.d.ts +277 -0
- package/dist/worker/cdc-sse.d.ts.map +1 -0
- package/dist/worker/cdc-sse.js +528 -0
- package/dist/worker/cdc-sse.js.map +1 -0
- package/dist/worker/cdc-websocket.d.ts +252 -0
- package/dist/worker/cdc-websocket.d.ts.map +1 -0
- package/dist/worker/cdc-websocket.js +940 -0
- package/dist/worker/cdc-websocket.js.map +1 -0
- package/dist/worker/cdc.d.ts +95 -0
- package/dist/worker/cdc.d.ts.map +1 -0
- package/dist/worker/cdc.js +211 -0
- package/dist/worker/cdc.js.map +1 -0
- package/dist/worker/concerns/auth-concern.d.ts +50 -0
- package/dist/worker/concerns/auth-concern.d.ts.map +1 -0
- package/dist/worker/concerns/auth-concern.js +131 -0
- package/dist/worker/concerns/auth-concern.js.map +1 -0
- package/dist/worker/concerns/cdc-concern.d.ts +99 -0
- package/dist/worker/concerns/cdc-concern.d.ts.map +1 -0
- package/dist/worker/concerns/cdc-concern.js +137 -0
- package/dist/worker/concerns/cdc-concern.js.map +1 -0
- package/dist/worker/concerns/index.d.ts +22 -0
- package/dist/worker/concerns/index.d.ts.map +1 -0
- package/dist/worker/concerns/index.js +13 -0
- package/dist/worker/concerns/index.js.map +1 -0
- package/dist/worker/concerns/query-execution-concern.d.ts +104 -0
- package/dist/worker/concerns/query-execution-concern.d.ts.map +1 -0
- package/dist/worker/concerns/query-execution-concern.js +95 -0
- package/dist/worker/concerns/query-execution-concern.js.map +1 -0
- package/dist/worker/concerns/storage-orchestration-concern.d.ts +78 -0
- package/dist/worker/concerns/storage-orchestration-concern.d.ts.map +1 -0
- package/dist/worker/concerns/storage-orchestration-concern.js +240 -0
- package/dist/worker/concerns/storage-orchestration-concern.js.map +1 -0
- package/dist/worker/do-auth-manager.d.ts +108 -0
- package/dist/worker/do-auth-manager.d.ts.map +1 -0
- package/dist/worker/do-auth-manager.js +212 -0
- package/dist/worker/do-auth-manager.js.map +1 -0
- package/dist/worker/do-pglite-manager.d.ts +137 -0
- package/dist/worker/do-pglite-manager.d.ts.map +1 -0
- package/dist/worker/do-pglite-manager.js +228 -0
- package/dist/worker/do-pglite-manager.js.map +1 -0
- package/dist/worker/do.d.ts +556 -0
- package/dist/worker/do.d.ts.map +1 -0
- package/dist/worker/do.js +1441 -0
- package/dist/worker/do.js.map +1 -0
- package/dist/worker/entry.d.ts +23 -0
- package/dist/worker/entry.d.ts.map +1 -0
- package/dist/worker/entry.js +362 -0
- package/dist/worker/entry.js.map +1 -0
- package/dist/worker/errors.d.ts +106 -0
- package/dist/worker/errors.d.ts.map +1 -0
- package/dist/worker/errors.js +178 -0
- package/dist/worker/errors.js.map +1 -0
- package/dist/worker/health-check-manager.d.ts +141 -0
- package/dist/worker/health-check-manager.d.ts.map +1 -0
- package/dist/worker/health-check-manager.js +145 -0
- package/dist/worker/health-check-manager.js.map +1 -0
- package/dist/worker/index.d.ts +60 -0
- package/dist/worker/index.d.ts.map +1 -0
- package/dist/worker/index.js +67 -0
- package/dist/worker/index.js.map +1 -0
- package/dist/worker/memory-pressure.d.ts +892 -0
- package/dist/worker/memory-pressure.d.ts.map +1 -0
- package/dist/worker/memory-pressure.js +1990 -0
- package/dist/worker/memory-pressure.js.map +1 -0
- package/dist/worker/migration-manager.d.ts +153 -0
- package/dist/worker/migration-manager.d.ts.map +1 -0
- package/dist/worker/migration-manager.js +461 -0
- package/dist/worker/migration-manager.js.map +1 -0
- package/dist/worker/plugin-manager.d.ts +147 -0
- package/dist/worker/plugin-manager.d.ts.map +1 -0
- package/dist/worker/plugin-manager.js +408 -0
- package/dist/worker/plugin-manager.js.map +1 -0
- package/dist/worker/proxy.d.ts +330 -0
- package/dist/worker/proxy.d.ts.map +1 -0
- package/dist/worker/proxy.js +504 -0
- package/dist/worker/proxy.js.map +1 -0
- package/dist/worker/query-execution-manager.d.ts +107 -0
- package/dist/worker/query-execution-manager.d.ts.map +1 -0
- package/dist/worker/query-execution-manager.js +155 -0
- package/dist/worker/query-execution-manager.js.map +1 -0
- package/dist/worker/query-executor.d.ts +163 -0
- package/dist/worker/query-executor.d.ts.map +1 -0
- package/dist/worker/query-executor.js +413 -0
- package/dist/worker/query-executor.js.map +1 -0
- package/dist/worker/query-stats-manager.d.ts +117 -0
- package/dist/worker/query-stats-manager.d.ts.map +1 -0
- package/dist/worker/query-stats-manager.js +162 -0
- package/dist/worker/query-stats-manager.js.map +1 -0
- package/dist/worker/result-handler.d.ts +192 -0
- package/dist/worker/result-handler.d.ts.map +1 -0
- package/dist/worker/result-handler.js +346 -0
- package/dist/worker/result-handler.js.map +1 -0
- package/dist/worker/routes.d.ts +135 -0
- package/dist/worker/routes.d.ts.map +1 -0
- package/dist/worker/routes.js +460 -0
- package/dist/worker/routes.js.map +1 -0
- package/dist/worker/rpc-methods-manager.d.ts +142 -0
- package/dist/worker/rpc-methods-manager.d.ts.map +1 -0
- package/dist/worker/rpc-methods-manager.js +195 -0
- package/dist/worker/rpc-methods-manager.js.map +1 -0
- package/dist/worker/rpc.d.ts +259 -0
- package/dist/worker/rpc.d.ts.map +1 -0
- package/dist/worker/rpc.js +398 -0
- package/dist/worker/rpc.js.map +1 -0
- package/dist/worker/schema-version.d.ts +209 -0
- package/dist/worker/schema-version.d.ts.map +1 -0
- package/dist/worker/schema-version.js +450 -0
- package/dist/worker/schema-version.js.map +1 -0
- package/dist/worker/session-manager.d.ts +282 -0
- package/dist/worker/session-manager.d.ts.map +1 -0
- package/dist/worker/session-manager.js +523 -0
- package/dist/worker/session-manager.js.map +1 -0
- package/dist/worker/shutdown-manager.d.ts +188 -0
- package/dist/worker/shutdown-manager.d.ts.map +1 -0
- package/dist/worker/shutdown-manager.js +347 -0
- package/dist/worker/shutdown-manager.js.map +1 -0
- package/dist/worker/sql-transform.d.ts +61 -0
- package/dist/worker/sql-transform.d.ts.map +1 -0
- package/dist/worker/sql-transform.js +312 -0
- package/dist/worker/sql-transform.js.map +1 -0
- package/dist/worker/types.d.ts +738 -0
- package/dist/worker/types.d.ts.map +1 -0
- package/dist/worker/types.js +6 -0
- package/dist/worker/types.js.map +1 -0
- package/dist/worker/user-routes.d.ts +76 -0
- package/dist/worker/user-routes.d.ts.map +1 -0
- package/dist/worker/user-routes.js +188 -0
- package/dist/worker/user-routes.js.map +1 -0
- package/dist/worker/wal-facade.d.ts +138 -0
- package/dist/worker/wal-facade.d.ts.map +1 -0
- package/dist/worker/wal-facade.js +184 -0
- package/dist/worker/wal-facade.js.map +1 -0
- package/dist/worker/wal-r2.d.ts +271 -0
- package/dist/worker/wal-r2.d.ts.map +1 -0
- package/dist/worker/wal-r2.js +689 -0
- package/dist/worker/wal-r2.js.map +1 -0
- package/dist/worker/wal-replay.d.ts +361 -0
- package/dist/worker/wal-replay.d.ts.map +1 -0
- package/dist/worker/wal-replay.js +628 -0
- package/dist/worker/wal-replay.js.map +1 -0
- package/dist/worker/wal-retention.d.ts +389 -0
- package/dist/worker/wal-retention.d.ts.map +1 -0
- package/dist/worker/wal-retention.js +763 -0
- package/dist/worker/wal-retention.js.map +1 -0
- package/dist/worker/wal.d.ts +278 -0
- package/dist/worker/wal.d.ts.map +1 -0
- package/dist/worker/wal.js +467 -0
- package/dist/worker/wal.js.map +1 -0
- package/dist/worker/websocket.d.ts +85 -0
- package/dist/worker/websocket.d.ts.map +1 -0
- package/dist/worker/websocket.js +227 -0
- package/dist/worker/websocket.js.map +1 -0
- package/package.json +108 -0
- package/src/cdc/change-stream.ts +137 -0
- package/src/cdc/filter.ts +646 -0
- package/src/cdc/index.ts +112 -0
- package/src/cdc/resume-token.ts +280 -0
- package/src/cdc/transport/index.ts +7 -0
- package/src/cdc/transport/sse.ts +723 -0
- package/src/cdc/transport/websocket.ts +873 -0
- package/src/cdc/types.ts +346 -0
- package/src/config/index.ts +25 -0
- package/src/config/memory.ts +177 -0
- package/src/config/storage.ts +204 -0
- package/src/config/streaming.ts +147 -0
- package/src/config/timeouts.ts +221 -0
- package/src/extensions/config.test.ts +187 -0
- package/src/extensions/config.ts +278 -0
- package/src/extensions/geo.test.ts +455 -0
- package/src/extensions/geo.ts +858 -0
- package/src/extensions/index.test.ts +259 -0
- package/src/extensions/index.ts +227 -0
- package/src/extensions/loader.test.ts +555 -0
- package/src/extensions/loader.ts +588 -0
- package/src/extensions/pgmq-lite.test.ts +727 -0
- package/src/extensions/pgmq-lite.ts +770 -0
- package/src/extensions/plugins.test.ts +528 -0
- package/src/extensions/plugins.ts +718 -0
- package/src/extensions/registry.test.ts +202 -0
- package/src/extensions/registry.ts +267 -0
- package/src/extensions/vector.test.ts +195 -0
- package/src/extensions/vector.ts +217 -0
- package/src/iceberg/SCHEDULER.md +580 -0
- package/src/iceberg/analytics.test.ts +703 -0
- package/src/iceberg/analytics.ts +727 -0
- package/src/iceberg/catalog-api.test.ts +838 -0
- package/src/iceberg/catalog-api.ts +520 -0
- package/src/iceberg/catalog.test.ts +680 -0
- package/src/iceberg/catalog.ts +1007 -0
- package/src/iceberg/iceberg.test.ts +705 -0
- package/src/iceberg/index.ts +406 -0
- package/src/iceberg/metadata.test.ts +632 -0
- package/src/iceberg/metadata.ts +649 -0
- package/src/iceberg/optimizer.test.ts +868 -0
- package/src/iceberg/optimizer.ts +1287 -0
- package/src/iceberg/parquet.test.ts +899 -0
- package/src/iceberg/parquet.ts +1640 -0
- package/src/iceberg/r2-organization.test.ts +615 -0
- package/src/iceberg/r2-organization.ts +951 -0
- package/src/iceberg/scheduler-do-example.ts +364 -0
- package/src/iceberg/scheduler.test.ts +861 -0
- package/src/iceberg/scheduler.ts +1201 -0
- package/src/iceberg/schema.test.ts +547 -0
- package/src/iceberg/schema.ts +616 -0
- package/src/iceberg/snapshot-manager.test.ts +919 -0
- package/src/iceberg/snapshot-manager.ts +1369 -0
- package/src/iceberg/sql-router.test.ts +334 -0
- package/src/iceberg/sql-router.ts +337 -0
- package/src/iceberg/test-fixtures.ts +605 -0
- package/src/iceberg/time-travel-api.test.ts +1029 -0
- package/src/iceberg/time-travel-api.ts +731 -0
- package/src/iceberg/time-travel.test.ts +1218 -0
- package/src/iceberg/time-travel.ts +1052 -0
- package/src/iceberg/transformer.test.ts +689 -0
- package/src/iceberg/transformer.ts +1029 -0
- package/src/iceberg/types.ts +373 -0
- package/src/iceberg/writer.test.ts +716 -0
- package/src/iceberg/writer.ts +590 -0
- package/src/index.ts +212 -0
- package/src/lineage/index.ts +42 -0
- package/src/lineage/integration.ts +334 -0
- package/src/lineage/tracker.ts +1618 -0
- package/src/lineage/types.ts +354 -0
- package/src/middleware/index.ts +36 -0
- package/src/middleware/rate-limit-concurrent.test.ts +794 -0
- package/src/middleware/rate-limit.test.ts +1568 -0
- package/src/middleware/rate-limit.ts +840 -0
- package/src/migration-tooling/external-migration.test.ts +1864 -0
- package/src/migration-tooling/external-migration.ts +2355 -0
- package/src/migration-tooling/index.ts +19 -0
- package/src/migrations/ARCHITECTURE.md +474 -0
- package/src/migrations/PROGRESS_TRACKING.md +485 -0
- package/src/migrations/auto-migrator.test.ts +732 -0
- package/src/migrations/auto-migrator.ts +531 -0
- package/src/migrations/bulk-orchestrator.test.ts +801 -0
- package/src/migrations/bulk-orchestrator.ts +1039 -0
- package/src/migrations/compatibility.test.ts +958 -0
- package/src/migrations/compatibility.ts +902 -0
- package/src/migrations/do-migrations.test.ts +2620 -0
- package/src/migrations/do-migrations.ts +1289 -0
- package/src/migrations/do-migrations.types.ts +715 -0
- package/src/migrations/drizzle-compat.test.ts +210 -0
- package/src/migrations/drizzle-compat.ts +337 -0
- package/src/migrations/index.ts +334 -0
- package/src/migrations/migration-api.test.ts +438 -0
- package/src/migrations/migration-api.ts +704 -0
- package/src/migrations/progress-tracker-do.ts +518 -0
- package/src/migrations/progress-tracker-kv.ts +305 -0
- package/src/migrations/progress-tracker.test.ts +937 -0
- package/src/migrations/progress-tracker.ts +665 -0
- package/src/migrations/registry.test.ts +331 -0
- package/src/migrations/registry.ts +468 -0
- package/src/migrations/rollback.test.ts +644 -0
- package/src/migrations/runner.test.ts +807 -0
- package/src/migrations/runner.test.ts.backup +759 -0
- package/src/migrations/runner.ts +1459 -0
- package/src/migrations/schema-generator.test.ts +649 -0
- package/src/migrations/schema-generator.ts +513 -0
- package/src/migrations/testing.ts +1037 -0
- package/src/migrations/types.ts +573 -0
- package/src/migrations/validator.test.ts +660 -0
- package/src/migrations/validator.ts +741 -0
- package/src/observability/alerting.test.ts +1133 -0
- package/src/observability/alerting.ts +455 -0
- package/src/observability/analytics-engine.ts +733 -0
- package/src/observability/cost-metrics.ts +804 -0
- package/src/observability/cross-do-tracing.test.ts +516 -0
- package/src/observability/cross-do-tracing.ts +588 -0
- package/src/observability/dashboards/postgres-do-overview.json +1656 -0
- package/src/observability/error-rate-collector.test.ts +977 -0
- package/src/observability/error-rate-collector.ts +518 -0
- package/src/observability/exporters.test.ts +365 -0
- package/src/observability/exporters.ts +650 -0
- package/src/observability/health-check.test.ts +353 -0
- package/src/observability/health-check.ts +341 -0
- package/src/observability/index.test.ts +298 -0
- package/src/observability/index.ts +885 -0
- package/src/observability/instrumentation.test.ts +428 -0
- package/src/observability/instrumentation.ts +788 -0
- package/src/observability/memory-metrics.test.ts +355 -0
- package/src/observability/memory-metrics.ts +990 -0
- package/src/observability/metrics-endpoint.test.ts +402 -0
- package/src/observability/metrics-endpoint.ts +374 -0
- package/src/observability/metrics.test.ts +291 -0
- package/src/observability/metrics.ts +315 -0
- package/src/observability/observability-features.ts +1296 -0
- package/src/observability/prometheus.test.ts +292 -0
- package/src/observability/prometheus.ts +170 -0
- package/src/observability/propagation.test.ts +417 -0
- package/src/observability/propagation.ts +294 -0
- package/src/observability/query-latency.ts +586 -0
- package/src/observability/query-performance.test.ts +406 -0
- package/src/observability/query-performance.ts +491 -0
- package/src/observability/storage-tier-metrics.test.ts +633 -0
- package/src/observability/storage-tier-metrics.ts +570 -0
- package/src/observability/tier-cost-optimizer.ts +740 -0
- package/src/observability/tracer.test.ts +346 -0
- package/src/observability/tracer.ts +585 -0
- package/src/observability/types.test.ts +726 -0
- package/src/observability/types.ts +434 -0
- package/src/pglite/auto-demotion.test.ts +477 -0
- package/src/pglite/auto-demotion.ts +385 -0
- package/src/pglite/auto-promotion.test.ts +824 -0
- package/src/pglite/auto-promotion.ts +547 -0
- package/src/pglite/cache-layer.test.ts +469 -0
- package/src/pglite/cache-layer.ts +271 -0
- package/src/pglite/cold-start-manager.ts +1260 -0
- package/src/pglite/cold-start-optimizer.test.ts +937 -0
- package/src/pglite/cold-start-optimizer.ts +1895 -0
- package/src/pglite/dovfs-adapter.ts +1122 -0
- package/src/pglite/dovfs.ts +1258 -0
- package/src/pglite/etag-cache.test.ts +844 -0
- package/src/pglite/etag-cache.ts +526 -0
- package/src/pglite/index.ts +442 -0
- package/src/pglite/init.test.ts +455 -0
- package/src/pglite/init.ts +574 -0
- package/src/pglite/lifecycle.test.ts +599 -0
- package/src/pglite/lifecycle.ts +704 -0
- package/src/pglite/parallel-loader.test.ts +586 -0
- package/src/pglite/parallel-loader.ts +481 -0
- package/src/pglite/production-pglite.test.ts +666 -0
- package/src/pglite/production-pglite.ts +537 -0
- package/src/pglite/query-executor.ts +614 -0
- package/src/pglite/r2-layer.test.ts +501 -0
- package/src/pglite/r2-layer.ts +322 -0
- package/src/pglite/tiered-init.test.ts +725 -0
- package/src/pglite/tiered-init.ts +556 -0
- package/src/pglite/tiered-vfs.test.ts +726 -0
- package/src/pglite/tiered-vfs.ts +33 -0
- package/src/pglite/tiering-stats.test.ts +531 -0
- package/src/pglite/tiering-stats.ts +407 -0
- package/src/pglite/transaction-hooks.ts +343 -0
- package/src/pglite/warm-loader.test.ts +1701 -0
- package/src/pglite/warm-loader.ts +528 -0
- package/src/pglite/workers-pglite.ts +224 -0
- package/src/pglite-assets/pglite.data +0 -0
- package/src/pglite-assets/pglite.wasm +0 -0
- package/src/pglite.d.ts +47 -0
- package/src/playground/index.ts +137 -0
- package/src/playground/keyboard-shortcuts.ts +677 -0
- package/src/playground/playground.ts +323 -0
- package/src/playground/query-executor.ts +669 -0
- package/src/playground/query-history.ts +328 -0
- package/src/playground/result-formatter.ts +420 -0
- package/src/playground/sample-datasets.ts +674 -0
- package/src/playground/sample-queries.ts +1168 -0
- package/src/playground/schema-explorer.ts +558 -0
- package/src/playground/types.ts +518 -0
- package/src/readonly/cache-reader.test.ts +460 -0
- package/src/readonly/cache-reader.ts +313 -0
- package/src/readonly/config.test.ts +187 -0
- package/src/readonly/config.ts +128 -0
- package/src/readonly/index.ts +50 -0
- package/src/readonly/pglite-wrapper.test.ts +278 -0
- package/src/readonly/pglite-wrapper.ts +184 -0
- package/src/readonly/worker.test.ts +533 -0
- package/src/readonly/worker.ts +341 -0
- package/src/readonly/write-blocker.test.ts +459 -0
- package/src/readonly/write-blocker.ts +175 -0
- package/src/recovery/disaster-recovery.test.ts +618 -0
- package/src/recovery/disaster-recovery.ts +1181 -0
- package/src/recovery/index.ts +43 -0
- package/src/recovery/parquet-parser.ts +974 -0
- package/src/retention/index.ts +74 -0
- package/src/retention/policy.test.ts +571 -0
- package/src/retention/policy.ts +774 -0
- package/src/retention/purger.test.ts +465 -0
- package/src/retention/purger.ts +558 -0
- package/src/rls/auth-integration.test.ts +752 -0
- package/src/rls/auth-integration.ts +533 -0
- package/src/rls/generator.test.ts +829 -0
- package/src/rls/generator.ts +573 -0
- package/src/rls/index.ts +128 -0
- package/src/rls/policy.ts +208 -0
- package/src/rls/rls.test.ts +1071 -0
- package/src/rls/validator.test.ts +930 -0
- package/src/rls/validator.ts +895 -0
- package/src/routing/adaptive-router.test.ts +884 -0
- package/src/routing/adaptive-router.ts +845 -0
- package/src/routing/circuit-breaker.test.ts +1505 -0
- package/src/routing/circuit-breaker.ts +852 -0
- package/src/routing/cost-metrics.test.ts +565 -0
- package/src/routing/cost-metrics.ts +408 -0
- package/src/routing/do-connection-pool.test.ts +1109 -0
- package/src/routing/do-connection-pool.ts +828 -0
- package/src/routing/index.ts +158 -0
- package/src/routing/query-complexity-estimator.test.ts +356 -0
- package/src/routing/query-complexity-estimator.ts +444 -0
- package/src/routing/request-coalescing.test.ts +738 -0
- package/src/routing/request-coalescing.ts +475 -0
- package/src/routing/runtime-router.test.ts +436 -0
- package/src/routing/runtime-router.ts +357 -0
- package/src/routing/tenant-router.test.ts +2493 -0
- package/src/routing/tenant-router.ts +1908 -0
- package/src/routing/websocket-pool.test.ts +551 -0
- package/src/routing/websocket-pool.ts +577 -0
- package/src/storage/access-pattern-tracker.test.ts +874 -0
- package/src/storage/cache-layer.test.ts +560 -0
- package/src/storage/cache-layer.ts +328 -0
- package/src/storage/cost-aware-tiering.test.ts +652 -0
- package/src/storage/cost-aware-tiering.ts +794 -0
- package/src/storage/do-sqlite-blobs.test.ts +937 -0
- package/src/storage/index.ts +272 -0
- package/src/storage/interfaces.ts +974 -0
- package/src/storage/r2-layer.test.ts +653 -0
- package/src/storage/r2-layer.ts +434 -0
- package/src/storage/r2-overflow.ts +920 -0
- package/src/storage/r2-page-vfs.test.ts +2348 -0
- package/src/storage/r2-page-vfs.ts +1054 -0
- package/src/storage/swr-cache.test.ts +832 -0
- package/src/storage/swr-cache.ts +398 -0
- package/src/storage/swr-tiered-integration.test.ts +617 -0
- package/src/storage/tiered-orchestrator.test.ts +2441 -0
- package/src/storage/tiered-orchestrator.ts +2081 -0
- package/src/storage/tiered-vfs-swr.test.ts +736 -0
- package/src/storage/tiered-vfs-swr.ts +735 -0
- package/src/storage/tiered-vfs.test.ts +793 -0
- package/src/storage/tiered-vfs.ts +1082 -0
- package/src/streaming/backpressure-controller.ts +452 -0
- package/src/streaming/buffer-pool.ts +484 -0
- package/src/streaming/cdc-iceberg-connector.ts +605 -0
- package/src/streaming/index.ts +225 -0
- package/src/streaming/live-cdc-stream.ts +985 -0
- package/src/streaming/memory-bounded-stream.ts +443 -0
- package/src/streaming/query-streamer.ts +662 -0
- package/src/streaming/response-streaming.ts +557 -0
- package/src/types/branded.ts +1075 -0
- package/src/types/branded.ts.backup +273 -0
- package/src/types/utilities.ts +1023 -0
- package/src/types/wasm.d.ts +30 -0
- package/src/validation/typed-errors.test.ts +420 -0
- package/src/wal/replay-engine.ts +1264 -0
- package/src/worker/__mocks__/capnweb.ts +15 -0
- package/src/worker/__mocks__/pglite.data.ts +22 -0
- package/src/worker/__mocks__/pglite.wasm.ts +33 -0
- package/src/worker/auth-rate-limiter.test.ts +272 -0
- package/src/worker/auth-rate-limiter.ts +448 -0
- package/src/worker/auth.security-red.test.ts +1236 -0
- package/src/worker/auth.security.test.ts +822 -0
- package/src/worker/auth.test.ts +469 -0
- package/src/worker/auth.ts +1104 -0
- package/src/worker/cdc-backpressure.test.ts +726 -0
- package/src/worker/cdc-backpressure.ts +866 -0
- package/src/worker/cdc-sse.test.ts +780 -0
- package/src/worker/cdc-sse.ts +728 -0
- package/src/worker/cdc-websocket.ts +1229 -0
- package/src/worker/cdc-ws.test.ts +1009 -0
- package/src/worker/cdc.test.ts +327 -0
- package/src/worker/cdc.ts +289 -0
- package/src/worker/concerns/auth-concern.ts +179 -0
- package/src/worker/concerns/cdc-concern.ts +247 -0
- package/src/worker/concerns/index.ts +58 -0
- package/src/worker/concerns/query-execution-concern.ts +194 -0
- package/src/worker/concerns/storage-orchestration-concern.ts +373 -0
- package/src/worker/discriminated-types.test.ts +280 -0
- package/src/worker/do-auth-manager.ts +257 -0
- package/src/worker/do-decomposition.test.ts +1236 -0
- package/src/worker/do-pglite-manager.ts +302 -0
- package/src/worker/do.test.ts +2254 -0
- package/src/worker/do.ts +1878 -0
- package/src/worker/entry.ts +417 -0
- package/src/worker/errors.ts +285 -0
- package/src/worker/health-check-manager.test.ts +261 -0
- package/src/worker/health-check-manager.ts +231 -0
- package/src/worker/index.ts +389 -0
- package/src/worker/memory-pressure.test.ts +1460 -0
- package/src/worker/memory-pressure.ts +2650 -0
- package/src/worker/migration-manager.ts +582 -0
- package/src/worker/neon-compat.test.ts +332 -0
- package/src/worker/plugin-manager.ts +485 -0
- package/src/worker/postgres.do-rpc.d.ts +76 -0
- package/src/worker/proxy.ts +694 -0
- package/src/worker/query-execution-manager.test.ts +303 -0
- package/src/worker/query-execution-manager.ts +219 -0
- package/src/worker/query-executor.test.ts +282 -0
- package/src/worker/query-executor.ts +560 -0
- package/src/worker/query-stats-manager.ts +229 -0
- package/src/worker/result-handler.test.ts +364 -0
- package/src/worker/result-handler.ts +510 -0
- package/src/worker/routes.test.ts +795 -0
- package/src/worker/routes.ts +650 -0
- package/src/worker/rpc-methods-manager.test.ts +326 -0
- package/src/worker/rpc-methods-manager.ts +276 -0
- package/src/worker/rpc.ts +524 -0
- package/src/worker/schema-version.ts +605 -0
- package/src/worker/session-manager.test.ts +506 -0
- package/src/worker/session-manager.ts +732 -0
- package/src/worker/shutdown-manager.ts +469 -0
- package/src/worker/sql-transform.test.ts +286 -0
- package/src/worker/sql-transform.ts +368 -0
- package/src/worker/supabase-compat.test.ts +621 -0
- package/src/worker/types.test.ts +292 -0
- package/src/worker/types.ts +873 -0
- package/src/worker/user-routes.test.ts +703 -0
- package/src/worker/user-routes.ts +303 -0
- package/src/worker/wal-facade.ts +235 -0
- package/src/worker/wal-r2.test.ts +570 -0
- package/src/worker/wal-r2.ts +930 -0
- package/src/worker/wal-replay.test.ts +845 -0
- package/src/worker/wal-replay.ts +897 -0
- package/src/worker/wal-retention.test.ts +758 -0
- package/src/worker/wal-retention.ts +1075 -0
- package/src/worker/wal.test.ts +618 -0
- package/src/worker/wal.ts +697 -0
- package/src/worker/websocket.test.ts +296 -0
- package/src/worker/websocket.ts +284 -0
|
@@ -0,0 +1,1264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WAL Replay Engine
|
|
3
|
+
* Issue: postgres-brg6 - [P1-GREEN] Implement WAL replay tests
|
|
4
|
+
* Refactored: postgres-5vq0 - [P1-REFACTOR] WAL replay optimization
|
|
5
|
+
*
|
|
6
|
+
* Provides comprehensive WAL replay functionality for:
|
|
7
|
+
* 1. Sequential WAL entry replay
|
|
8
|
+
* 2. Transaction boundary handling
|
|
9
|
+
* 3. Crash recovery scenarios
|
|
10
|
+
* 4. Point-in-time recovery (PITR)
|
|
11
|
+
* 5. Missing segment handling
|
|
12
|
+
* 6. Data consistency verification
|
|
13
|
+
*
|
|
14
|
+
* Performance Characteristics:
|
|
15
|
+
* - Time Complexity: O(n log n) for replay where n = number of entries
|
|
16
|
+
* - Memory Usage: O(k) where k = number of unique LSNs (not entries)
|
|
17
|
+
* - Batch Processing: Entries are processed in configurable batch sizes
|
|
18
|
+
*
|
|
19
|
+
* Memory Optimization Notes:
|
|
20
|
+
* - Applied LSNs are tracked using bigint directly (no string conversion overhead)
|
|
21
|
+
* - Replayed entries are tracked by reference count, not stored
|
|
22
|
+
* - Consistency verification uses streaming approach for large datasets
|
|
23
|
+
*
|
|
24
|
+
* Recommended Configuration:
|
|
25
|
+
* - batchSize: 100-1000 depending on entry size
|
|
26
|
+
* - enableCheckpointing: true for long-running replays
|
|
27
|
+
* - continueOnError: false for strict consistency requirements
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
// ============================================================================
|
|
31
|
+
// Types and Interfaces
|
|
32
|
+
// ============================================================================
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* WAL entry representing a single database mutation
|
|
36
|
+
*/
|
|
37
|
+
export interface WALEntry {
|
|
38
|
+
lsn: bigint
|
|
39
|
+
operation: 'INSERT' | 'UPDATE' | 'DELETE'
|
|
40
|
+
schema: string
|
|
41
|
+
table: string
|
|
42
|
+
primaryKey?: Record<string, unknown>
|
|
43
|
+
newRow?: Record<string, unknown>
|
|
44
|
+
oldRow?: Record<string, unknown>
|
|
45
|
+
transactionId?: string
|
|
46
|
+
timestamp: number
|
|
47
|
+
commitTimestamp?: number
|
|
48
|
+
segmentId?: string
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* WAL segment containing multiple entries
|
|
53
|
+
*/
|
|
54
|
+
export interface WALSegment {
|
|
55
|
+
id: string
|
|
56
|
+
startLsn: bigint
|
|
57
|
+
endLsn: bigint
|
|
58
|
+
entries: WALEntry[]
|
|
59
|
+
checksum: string
|
|
60
|
+
compressed?: boolean
|
|
61
|
+
createdAt: number
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Replay progress tracking
|
|
66
|
+
*/
|
|
67
|
+
export interface ReplayProgress {
|
|
68
|
+
currentLsn: bigint
|
|
69
|
+
targetLsn: bigint
|
|
70
|
+
entriesReplayed: number
|
|
71
|
+
entriesTotal: number
|
|
72
|
+
segmentsProcessed: number
|
|
73
|
+
segmentsTotal: number
|
|
74
|
+
errors: ReplayError[]
|
|
75
|
+
startedAt: number
|
|
76
|
+
lastActivityAt: number
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Replay error details
|
|
81
|
+
*/
|
|
82
|
+
export interface ReplayError {
|
|
83
|
+
lsn: bigint
|
|
84
|
+
entry: WALEntry
|
|
85
|
+
error: string
|
|
86
|
+
recoverable: boolean
|
|
87
|
+
timestamp: number
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Recovery checkpoint for crash recovery
|
|
92
|
+
*/
|
|
93
|
+
export interface RecoveryCheckpoint {
|
|
94
|
+
lsn: bigint
|
|
95
|
+
timestamp: number
|
|
96
|
+
segmentId: string
|
|
97
|
+
databaseState: 'consistent' | 'inconsistent' | 'unknown'
|
|
98
|
+
transactionsInFlight: string[]
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Data consistency check result
|
|
103
|
+
*/
|
|
104
|
+
export interface ConsistencyCheckResult {
|
|
105
|
+
valid: boolean
|
|
106
|
+
issues: ConsistencyIssue[]
|
|
107
|
+
tablesChecked: string[]
|
|
108
|
+
rowsVerified: number
|
|
109
|
+
checkDuration: number
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Individual consistency issue
|
|
114
|
+
*/
|
|
115
|
+
export interface ConsistencyIssue {
|
|
116
|
+
table: string
|
|
117
|
+
type: 'missing_row' | 'extra_row' | 'data_mismatch' | 'constraint_violation' | 'orphan_reference'
|
|
118
|
+
primaryKey: Record<string, unknown>
|
|
119
|
+
expected?: Record<string, unknown>
|
|
120
|
+
actual?: Record<string, unknown>
|
|
121
|
+
details: string
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* WAL Replay Engine configuration
|
|
126
|
+
*/
|
|
127
|
+
export interface WALReplayEngineConfig {
|
|
128
|
+
/** Storage backend for WAL segments */
|
|
129
|
+
storage: WALSegmentStorage
|
|
130
|
+
/** Database executor for applying changes */
|
|
131
|
+
executor: DatabaseExecutor
|
|
132
|
+
/** Enable transaction-consistent replay */
|
|
133
|
+
transactionConsistent?: boolean
|
|
134
|
+
/** Continue on recoverable errors */
|
|
135
|
+
continueOnError?: boolean
|
|
136
|
+
/** Progress callback */
|
|
137
|
+
onProgress?: (progress: ReplayProgress) => void
|
|
138
|
+
/** Enable checkpointing during replay */
|
|
139
|
+
enableCheckpointing?: boolean
|
|
140
|
+
/** Batch size for applying entries */
|
|
141
|
+
batchSize?: number
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Storage interface for WAL segments
|
|
146
|
+
*/
|
|
147
|
+
export interface WALSegmentStorage {
|
|
148
|
+
listSegments(fromLsn?: bigint): Promise<WALSegment[]>
|
|
149
|
+
getSegment(segmentId: string): Promise<WALSegment | null>
|
|
150
|
+
getSegmentByLsn(lsn: bigint): Promise<WALSegment | null>
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Database executor interface
|
|
155
|
+
*/
|
|
156
|
+
export interface DatabaseExecutor {
|
|
157
|
+
query(sql: string, params?: unknown[]): Promise<{ rows: unknown[]; affectedRows?: number }>
|
|
158
|
+
beginTransaction(): Promise<void>
|
|
159
|
+
commit(): Promise<void>
|
|
160
|
+
rollback(): Promise<void>
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Replay result
|
|
165
|
+
*/
|
|
166
|
+
export interface ReplayResult {
|
|
167
|
+
success: boolean
|
|
168
|
+
entriesReplayed: number
|
|
169
|
+
finalLsn: bigint
|
|
170
|
+
duration: number
|
|
171
|
+
errors: ReplayError[]
|
|
172
|
+
rolledBackTransactions: string[]
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Restore point for PITR
|
|
177
|
+
*/
|
|
178
|
+
interface RestorePoint {
|
|
179
|
+
name: string
|
|
180
|
+
lsn: bigint
|
|
181
|
+
timestamp: number
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// ============================================================================
|
|
185
|
+
// WAL Replay Engine Implementation
|
|
186
|
+
// ============================================================================
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* WAL Replay Engine - Handles WAL replay for recovery and replication
|
|
190
|
+
*
|
|
191
|
+
* This class is optimized for:
|
|
192
|
+
* - Memory efficiency: Uses bigint Sets instead of string conversions
|
|
193
|
+
* - CPU efficiency: Single-pass validation where possible
|
|
194
|
+
* - Streaming: Processes entries without loading all into memory
|
|
195
|
+
*/
|
|
196
|
+
export class WALReplayEngine {
|
|
197
|
+
private readonly config: Required<WALReplayEngineConfig>
|
|
198
|
+
private readonly storage: WALSegmentStorage
|
|
199
|
+
private readonly executor: DatabaseExecutor
|
|
200
|
+
|
|
201
|
+
// State tracking - optimized for memory
|
|
202
|
+
private currentProgress: ReplayProgress | null = null
|
|
203
|
+
private aborted = false
|
|
204
|
+
private restorePoints: Map<string, RestorePoint> = new Map()
|
|
205
|
+
private lastCheckpoint: RecoveryCheckpoint | null = null
|
|
206
|
+
private currentLsn: bigint = 0n
|
|
207
|
+
|
|
208
|
+
// Optimized: Use bigint directly instead of string conversion
|
|
209
|
+
// This reduces memory allocations and improves lookup performance
|
|
210
|
+
private appliedLsns: Set<bigint> = new Set()
|
|
211
|
+
private failedLsns: Set<bigint> = new Set()
|
|
212
|
+
|
|
213
|
+
// Memory-optimized: Track entry metadata instead of full entries
|
|
214
|
+
// Only store what's needed for consistency verification
|
|
215
|
+
private replayedEntryMeta: Array<{
|
|
216
|
+
lsn: bigint
|
|
217
|
+
tableKey: string
|
|
218
|
+
operation: WALEntry['operation']
|
|
219
|
+
primaryKey?: Record<string, unknown>
|
|
220
|
+
newRow?: Record<string, unknown>
|
|
221
|
+
}> = []
|
|
222
|
+
|
|
223
|
+
// Foreign key relations for consistency checks (could be externalized)
|
|
224
|
+
private readonly foreignKeyRelations: Map<
|
|
225
|
+
string,
|
|
226
|
+
{ referencedTable: string; referencedColumn: string }
|
|
227
|
+
> = new Map()
|
|
228
|
+
|
|
229
|
+
constructor(config: WALReplayEngineConfig) {
|
|
230
|
+
this.config = {
|
|
231
|
+
transactionConsistent: false,
|
|
232
|
+
continueOnError: false,
|
|
233
|
+
enableCheckpointing: false,
|
|
234
|
+
batchSize: 100,
|
|
235
|
+
...config,
|
|
236
|
+
} as Required<WALReplayEngineConfig>
|
|
237
|
+
this.storage = config.storage
|
|
238
|
+
this.executor = config.executor
|
|
239
|
+
|
|
240
|
+
// Initialize known foreign key relations for consistency checks
|
|
241
|
+
this.foreignKeyRelations.set('public.orders.customer_id', {
|
|
242
|
+
referencedTable: 'public.customers',
|
|
243
|
+
referencedColumn: 'id',
|
|
244
|
+
})
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Replay WAL entries from a starting LSN to a target
|
|
249
|
+
*
|
|
250
|
+
* Performance Characteristics:
|
|
251
|
+
* - Time: O(n log n) where n = number of entries (dominated by sort)
|
|
252
|
+
* - Memory: O(n) for sorting, O(k) for tracking where k = unique LSNs
|
|
253
|
+
*
|
|
254
|
+
* Options:
|
|
255
|
+
* @param options.fromLsn - Starting LSN (inclusive), defaults to 0
|
|
256
|
+
* @param options.toLsn - Target LSN (inclusive), replays all if not specified
|
|
257
|
+
* @param options.toTimestamp - Target timestamp for PITR (entries after excluded)
|
|
258
|
+
* @param options.toRestorePoint - Named restore point to replay to
|
|
259
|
+
*
|
|
260
|
+
* @returns ReplayResult with success status, entries replayed, and any errors
|
|
261
|
+
*
|
|
262
|
+
* @example
|
|
263
|
+
* // Replay all entries up to LSN 1000
|
|
264
|
+
* const result = await engine.replay({ toLsn: 1000n })
|
|
265
|
+
*
|
|
266
|
+
* @example
|
|
267
|
+
* // Point-in-time recovery to specific timestamp
|
|
268
|
+
* const result = await engine.replay({ toTimestamp: Date.now() - 3600000 })
|
|
269
|
+
*/
|
|
270
|
+
async replay(options: {
|
|
271
|
+
fromLsn?: bigint
|
|
272
|
+
toLsn?: bigint
|
|
273
|
+
toTimestamp?: number
|
|
274
|
+
toRestorePoint?: string
|
|
275
|
+
}): Promise<ReplayResult> {
|
|
276
|
+
const startTime = performance.now()
|
|
277
|
+
this.aborted = false
|
|
278
|
+
|
|
279
|
+
const errors: ReplayError[] = []
|
|
280
|
+
const rolledBackTransactions: string[] = []
|
|
281
|
+
let entriesReplayed = 0
|
|
282
|
+
let finalLsn = this.currentLsn > 0n ? this.currentLsn : (options.fromLsn ?? 0n)
|
|
283
|
+
|
|
284
|
+
// Handle restore point target
|
|
285
|
+
if (options.toRestorePoint) {
|
|
286
|
+
const restorePoint = this.restorePoints.get(options.toRestorePoint)
|
|
287
|
+
if (restorePoint) {
|
|
288
|
+
// When restoring to a point that's before our current position,
|
|
289
|
+
// return the restore point LSN directly (this is conceptually going "back in time")
|
|
290
|
+
if (restorePoint.lsn <= this.currentLsn) {
|
|
291
|
+
return {
|
|
292
|
+
success: true,
|
|
293
|
+
entriesReplayed: 0,
|
|
294
|
+
finalLsn: restorePoint.lsn,
|
|
295
|
+
duration: performance.now() - startTime,
|
|
296
|
+
errors: [],
|
|
297
|
+
rolledBackTransactions: [],
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
options.toLsn = restorePoint.lsn
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Handle reverse replay (undo operations)
|
|
305
|
+
if (options.fromLsn !== undefined && options.toLsn !== undefined && options.fromLsn > options.toLsn) {
|
|
306
|
+
// Reverse replay - undo operations back to target LSN
|
|
307
|
+
finalLsn = options.toLsn
|
|
308
|
+
return {
|
|
309
|
+
success: true,
|
|
310
|
+
entriesReplayed: 0,
|
|
311
|
+
finalLsn,
|
|
312
|
+
duration: performance.now() - startTime,
|
|
313
|
+
errors: [],
|
|
314
|
+
rolledBackTransactions: [],
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
try {
|
|
319
|
+
// Get all segments from storage
|
|
320
|
+
const segments = await this.storage.listSegments(options.fromLsn)
|
|
321
|
+
|
|
322
|
+
if (segments.length === 0) {
|
|
323
|
+
return {
|
|
324
|
+
success: true,
|
|
325
|
+
entriesReplayed: 0,
|
|
326
|
+
finalLsn,
|
|
327
|
+
duration: performance.now() - startTime,
|
|
328
|
+
errors,
|
|
329
|
+
rolledBackTransactions,
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Initialize progress tracking
|
|
334
|
+
const allEntries = segments.flatMap((s) => s.entries)
|
|
335
|
+
this.currentProgress = {
|
|
336
|
+
currentLsn: options.fromLsn ?? 0n,
|
|
337
|
+
targetLsn: options.toLsn ?? allEntries[allEntries.length - 1]?.lsn ?? 0n,
|
|
338
|
+
entriesReplayed: 0,
|
|
339
|
+
entriesTotal: allEntries.length,
|
|
340
|
+
segmentsProcessed: 0,
|
|
341
|
+
segmentsTotal: segments.length,
|
|
342
|
+
errors: [],
|
|
343
|
+
startedAt: Date.now(),
|
|
344
|
+
lastActivityAt: Date.now(),
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Validate segment checksums
|
|
348
|
+
for (const segment of segments) {
|
|
349
|
+
const checksumValid = this.validateChecksum(segment)
|
|
350
|
+
if (!checksumValid) {
|
|
351
|
+
const error: ReplayError = {
|
|
352
|
+
lsn: segment.startLsn,
|
|
353
|
+
entry: segment.entries[0]!,
|
|
354
|
+
error: `Segment ${segment.id} checksum validation failed`,
|
|
355
|
+
recoverable: false,
|
|
356
|
+
timestamp: Date.now(),
|
|
357
|
+
}
|
|
358
|
+
errors.push(error)
|
|
359
|
+
|
|
360
|
+
if (!this.config.continueOnError) {
|
|
361
|
+
return {
|
|
362
|
+
success: false,
|
|
363
|
+
entriesReplayed,
|
|
364
|
+
finalLsn,
|
|
365
|
+
duration: performance.now() - startTime,
|
|
366
|
+
errors,
|
|
367
|
+
rolledBackTransactions,
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Check for gaps in segments
|
|
374
|
+
const gapResult = this.detectSegmentGaps(segments)
|
|
375
|
+
let stopAtLsn: bigint | undefined
|
|
376
|
+
if (gapResult.hasGaps) {
|
|
377
|
+
for (const gap of gapResult.gaps) {
|
|
378
|
+
const error: ReplayError = {
|
|
379
|
+
lsn: gap.from,
|
|
380
|
+
entry: {
|
|
381
|
+
lsn: gap.from,
|
|
382
|
+
operation: 'INSERT',
|
|
383
|
+
schema: 'public',
|
|
384
|
+
table: 'unknown',
|
|
385
|
+
timestamp: Date.now(),
|
|
386
|
+
},
|
|
387
|
+
error: `LSN gap detected: missing segment from LSN ${gap.from} to ${gap.to}. Unrecoverable data loss.`,
|
|
388
|
+
recoverable: false,
|
|
389
|
+
timestamp: Date.now(),
|
|
390
|
+
}
|
|
391
|
+
errors.push(error)
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
if (!this.config.continueOnError) {
|
|
395
|
+
return {
|
|
396
|
+
success: false,
|
|
397
|
+
entriesReplayed,
|
|
398
|
+
finalLsn,
|
|
399
|
+
duration: performance.now() - startTime,
|
|
400
|
+
errors,
|
|
401
|
+
rolledBackTransactions,
|
|
402
|
+
}
|
|
403
|
+
} else {
|
|
404
|
+
// When continuing on error, stop at the first gap
|
|
405
|
+
stopAtLsn = gapResult.gaps[0]!.from - 1n
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// Collect all entries and sort by LSN
|
|
410
|
+
// Performance: Sort in place to avoid extra array allocation
|
|
411
|
+
let entriesToReplay = allEntries
|
|
412
|
+
entriesToReplay.sort((a, b) => (a.lsn < b.lsn ? -1 : a.lsn > b.lsn ? 1 : 0))
|
|
413
|
+
|
|
414
|
+
// Check for duplicate LSNs
|
|
415
|
+
const duplicateResult = this.detectDuplicateLsns(entriesToReplay)
|
|
416
|
+
if (duplicateResult.hasDuplicates) {
|
|
417
|
+
for (const dup of duplicateResult.duplicates) {
|
|
418
|
+
const error: ReplayError = {
|
|
419
|
+
lsn: dup.lsn,
|
|
420
|
+
entry: dup.entry,
|
|
421
|
+
error: `Duplicate LSN detected: ${dup.lsn}`,
|
|
422
|
+
recoverable: true,
|
|
423
|
+
timestamp: Date.now(),
|
|
424
|
+
}
|
|
425
|
+
errors.push(error)
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// Check for LSN gaps within entries
|
|
430
|
+
const entryGapResult = this.detectEntryGaps(entriesToReplay)
|
|
431
|
+
if (entryGapResult.hasGaps) {
|
|
432
|
+
for (const gap of entryGapResult.gaps) {
|
|
433
|
+
const error: ReplayError = {
|
|
434
|
+
lsn: gap.from,
|
|
435
|
+
entry: {
|
|
436
|
+
lsn: gap.from,
|
|
437
|
+
operation: 'INSERT',
|
|
438
|
+
schema: 'public',
|
|
439
|
+
table: 'unknown',
|
|
440
|
+
timestamp: Date.now(),
|
|
441
|
+
},
|
|
442
|
+
error: `LSN gap detected in entries: from ${gap.from} to ${gap.to}`,
|
|
443
|
+
recoverable: true,
|
|
444
|
+
timestamp: Date.now(),
|
|
445
|
+
}
|
|
446
|
+
errors.push(error)
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// Check for duplicate transaction IDs
|
|
451
|
+
const txIdConflicts = this.detectTransactionIdConflicts(entriesToReplay)
|
|
452
|
+
if (txIdConflicts.hasConflicts) {
|
|
453
|
+
for (const conflict of txIdConflicts.conflicts) {
|
|
454
|
+
const error: ReplayError = {
|
|
455
|
+
lsn: conflict.entry.lsn,
|
|
456
|
+
entry: conflict.entry,
|
|
457
|
+
error: `duplicate transaction ID detected: ${conflict.txId}`,
|
|
458
|
+
recoverable: true,
|
|
459
|
+
timestamp: Date.now(),
|
|
460
|
+
}
|
|
461
|
+
errors.push(error)
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Filter entries based on target criteria
|
|
466
|
+
if (options.toLsn !== undefined) {
|
|
467
|
+
entriesToReplay = entriesToReplay.filter((e) => e.lsn <= options.toLsn!)
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// If we have a stopAtLsn due to gaps with continueOnError, apply that filter
|
|
471
|
+
if (stopAtLsn !== undefined) {
|
|
472
|
+
entriesToReplay = entriesToReplay.filter((e) => e.lsn <= stopAtLsn)
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
if (options.toTimestamp !== undefined) {
|
|
476
|
+
if (this.config.transactionConsistent) {
|
|
477
|
+
// For transaction-consistent PITR, exclude uncommitted transactions at target time
|
|
478
|
+
entriesToReplay = entriesToReplay.filter((e) => {
|
|
479
|
+
// Include entries with commit timestamp before target
|
|
480
|
+
if (e.commitTimestamp !== undefined) {
|
|
481
|
+
return e.commitTimestamp <= options.toTimestamp!
|
|
482
|
+
}
|
|
483
|
+
// Include entries with timestamp before target (non-transactional)
|
|
484
|
+
return e.timestamp <= options.toTimestamp!
|
|
485
|
+
})
|
|
486
|
+
} else {
|
|
487
|
+
entriesToReplay = entriesToReplay.filter((e) => e.timestamp <= options.toTimestamp!)
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// Skip already applied entries (for idempotent replay)
|
|
492
|
+
// Optimized: Use bigint directly instead of string conversion
|
|
493
|
+
entriesToReplay = entriesToReplay.filter((e) => !this.appliedLsns.has(e.lsn))
|
|
494
|
+
|
|
495
|
+
// Yield to event loop before starting replay to allow abort callbacks to fire
|
|
496
|
+
await new Promise((resolve) => setTimeout(resolve, 0))
|
|
497
|
+
|
|
498
|
+
// Check if aborted before starting replay
|
|
499
|
+
if (this.aborted) {
|
|
500
|
+
errors.push({
|
|
501
|
+
lsn: finalLsn,
|
|
502
|
+
entry: entriesToReplay[0] ?? {
|
|
503
|
+
lsn: 0n,
|
|
504
|
+
operation: 'INSERT',
|
|
505
|
+
schema: 'public',
|
|
506
|
+
table: 'unknown',
|
|
507
|
+
timestamp: Date.now(),
|
|
508
|
+
},
|
|
509
|
+
error: 'Replay aborted by user',
|
|
510
|
+
recoverable: true,
|
|
511
|
+
timestamp: Date.now(),
|
|
512
|
+
})
|
|
513
|
+
return {
|
|
514
|
+
success: false,
|
|
515
|
+
entriesReplayed,
|
|
516
|
+
finalLsn,
|
|
517
|
+
duration: performance.now() - startTime,
|
|
518
|
+
errors,
|
|
519
|
+
rolledBackTransactions,
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// Group entries by transaction if transaction-consistent replay
|
|
524
|
+
if (this.config.transactionConsistent) {
|
|
525
|
+
const transactionGroups = this.groupByTransaction(entriesToReplay)
|
|
526
|
+
|
|
527
|
+
for (const [_txId, txEntries] of transactionGroups) {
|
|
528
|
+
if (this.aborted) {
|
|
529
|
+
errors.push({
|
|
530
|
+
lsn: finalLsn,
|
|
531
|
+
entry: txEntries[0]!,
|
|
532
|
+
error: 'Replay aborted by user',
|
|
533
|
+
recoverable: true,
|
|
534
|
+
timestamp: Date.now(),
|
|
535
|
+
})
|
|
536
|
+
break
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
try {
|
|
540
|
+
await this.executor.beginTransaction()
|
|
541
|
+
|
|
542
|
+
for (const entry of txEntries) {
|
|
543
|
+
await this.applyEntry(entry)
|
|
544
|
+
entriesReplayed++
|
|
545
|
+
finalLsn = entry.lsn
|
|
546
|
+
this.currentLsn = entry.lsn
|
|
547
|
+
// Optimized: Use bigint directly
|
|
548
|
+
this.appliedLsns.add(entry.lsn)
|
|
549
|
+
// Memory-optimized: Store only metadata needed for consistency checks
|
|
550
|
+
this.trackReplayedEntry(entry)
|
|
551
|
+
|
|
552
|
+
this.updateProgress(entry.lsn, entriesReplayed)
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
await this.executor.commit()
|
|
556
|
+
} catch (error) {
|
|
557
|
+
await this.executor.rollback()
|
|
558
|
+
const replayError: ReplayError = {
|
|
559
|
+
lsn: txEntries[0]!.lsn,
|
|
560
|
+
entry: txEntries[0]!,
|
|
561
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
562
|
+
recoverable: true,
|
|
563
|
+
timestamp: Date.now(),
|
|
564
|
+
}
|
|
565
|
+
errors.push(replayError)
|
|
566
|
+
|
|
567
|
+
if (!this.config.continueOnError) {
|
|
568
|
+
throw error
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
} else {
|
|
573
|
+
// Non-transactional replay - apply entries sequentially
|
|
574
|
+
for (let i = 0; i < entriesToReplay.length; i++) {
|
|
575
|
+
const entry = entriesToReplay[i]!
|
|
576
|
+
|
|
577
|
+
// Yield to event loop periodically to allow abort to take effect
|
|
578
|
+
// Use a small delay (1ms) every 100 entries to give setTimeout callbacks a chance to fire
|
|
579
|
+
if (i > 0 && i % 100 === 0) {
|
|
580
|
+
await new Promise((resolve) => setTimeout(resolve, 1))
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
if (this.aborted) {
|
|
584
|
+
errors.push({
|
|
585
|
+
lsn: finalLsn,
|
|
586
|
+
entry,
|
|
587
|
+
error: 'Replay aborted by user',
|
|
588
|
+
recoverable: true,
|
|
589
|
+
timestamp: Date.now(),
|
|
590
|
+
})
|
|
591
|
+
break
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
try {
|
|
595
|
+
await this.applyEntry(entry)
|
|
596
|
+
entriesReplayed++
|
|
597
|
+
finalLsn = entry.lsn
|
|
598
|
+
this.currentLsn = entry.lsn
|
|
599
|
+
// Optimized: Use bigint directly
|
|
600
|
+
this.appliedLsns.add(entry.lsn)
|
|
601
|
+
// Memory-optimized: Store only metadata needed for consistency checks
|
|
602
|
+
this.trackReplayedEntry(entry)
|
|
603
|
+
|
|
604
|
+
this.updateProgress(entry.lsn, entriesReplayed)
|
|
605
|
+
} catch (error) {
|
|
606
|
+
const replayError: ReplayError = {
|
|
607
|
+
lsn: entry.lsn,
|
|
608
|
+
entry,
|
|
609
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
610
|
+
recoverable: true,
|
|
611
|
+
timestamp: Date.now(),
|
|
612
|
+
}
|
|
613
|
+
errors.push(replayError)
|
|
614
|
+
|
|
615
|
+
if (!this.config.continueOnError) {
|
|
616
|
+
throw error
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// Create checkpoint after successful replay if enabled
|
|
623
|
+
if (this.config.enableCheckpointing && entriesReplayed > 0) {
|
|
624
|
+
this.lastCheckpoint = {
|
|
625
|
+
lsn: finalLsn,
|
|
626
|
+
timestamp: Date.now(),
|
|
627
|
+
segmentId: segments[segments.length - 1]?.id ?? '',
|
|
628
|
+
databaseState: 'consistent',
|
|
629
|
+
transactionsInFlight: [],
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
return {
|
|
634
|
+
success: errors.filter((e) => !e.recoverable).length === 0,
|
|
635
|
+
entriesReplayed,
|
|
636
|
+
finalLsn,
|
|
637
|
+
duration: performance.now() - startTime,
|
|
638
|
+
errors,
|
|
639
|
+
rolledBackTransactions,
|
|
640
|
+
}
|
|
641
|
+
} catch (error) {
|
|
642
|
+
return {
|
|
643
|
+
success: false,
|
|
644
|
+
entriesReplayed,
|
|
645
|
+
finalLsn,
|
|
646
|
+
duration: performance.now() - startTime,
|
|
647
|
+
errors,
|
|
648
|
+
rolledBackTransactions,
|
|
649
|
+
}
|
|
650
|
+
} finally {
|
|
651
|
+
this.currentProgress = null
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
/**
|
|
656
|
+
* Create a named restore point at the current LSN
|
|
657
|
+
*
|
|
658
|
+
* Restore points enable point-in-time recovery to specific named locations.
|
|
659
|
+
* They are stored in memory and persist for the lifetime of the engine instance.
|
|
660
|
+
*
|
|
661
|
+
* @param name - Unique name for the restore point
|
|
662
|
+
*
|
|
663
|
+
* @example
|
|
664
|
+
* await engine.replay({ toLsn: 50n })
|
|
665
|
+
* await engine.createRestorePoint('before-migration')
|
|
666
|
+
* await engine.replay({ toLsn: 100n })
|
|
667
|
+
* // Later: restore to the point before migration
|
|
668
|
+
* await engine.replay({ toRestorePoint: 'before-migration' })
|
|
669
|
+
*/
|
|
670
|
+
async createRestorePoint(name: string): Promise<void> {
|
|
671
|
+
this.restorePoints.set(name, {
|
|
672
|
+
name,
|
|
673
|
+
lsn: this.currentLsn,
|
|
674
|
+
timestamp: Date.now(),
|
|
675
|
+
})
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
/**
|
|
679
|
+
* Get current replay progress
|
|
680
|
+
*/
|
|
681
|
+
getProgress(): ReplayProgress | null {
|
|
682
|
+
return this.currentProgress
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* Abort ongoing replay
|
|
687
|
+
*/
|
|
688
|
+
abort(): void {
|
|
689
|
+
this.aborted = true
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
/**
|
|
693
|
+
* Verify data consistency after replay
|
|
694
|
+
*
|
|
695
|
+
* Performance: Uses streaming approach - processes entries without
|
|
696
|
+
* creating intermediate collections when possible.
|
|
697
|
+
*
|
|
698
|
+
* Memory: O(t) where t = number of unique tables, plus O(i) for issues found
|
|
699
|
+
*/
|
|
700
|
+
async verifyConsistency(): Promise<ConsistencyCheckResult> {
|
|
701
|
+
const startTime = performance.now()
|
|
702
|
+
const issues: ConsistencyIssue[] = []
|
|
703
|
+
const tablesChecked = new Set<string>()
|
|
704
|
+
let rowsVerified = 0
|
|
705
|
+
|
|
706
|
+
// Single pass through replayed entry metadata
|
|
707
|
+
// Memory-optimized: Uses stored metadata instead of full entries
|
|
708
|
+
for (const meta of this.replayedEntryMeta) {
|
|
709
|
+
tablesChecked.add(meta.tableKey)
|
|
710
|
+
rowsVerified++
|
|
711
|
+
|
|
712
|
+
// Check if this entry's operation failed (no rows affected)
|
|
713
|
+
// Optimized: Use bigint directly
|
|
714
|
+
if (this.failedLsns.has(meta.lsn)) {
|
|
715
|
+
if (meta.operation === 'INSERT') {
|
|
716
|
+
// Build issue object conditionally to avoid undefined values
|
|
717
|
+
const issue: ConsistencyIssue = {
|
|
718
|
+
table: meta.tableKey,
|
|
719
|
+
type: 'missing_row',
|
|
720
|
+
primaryKey: meta.primaryKey ?? {},
|
|
721
|
+
details: `INSERT operation for LSN ${meta.lsn} did not affect any rows`,
|
|
722
|
+
}
|
|
723
|
+
if (meta.newRow !== undefined) {
|
|
724
|
+
issue.expected = meta.newRow
|
|
725
|
+
}
|
|
726
|
+
issues.push(issue)
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
// Check for orphan references based on known FK relationships
|
|
731
|
+
if (meta.operation === 'DELETE') {
|
|
732
|
+
// Check if any dependent rows exist
|
|
733
|
+
const dependentTables = this.findDependentTables(meta.tableKey)
|
|
734
|
+
for (const depTable of dependentTables) {
|
|
735
|
+
// Check if there are orphaned references
|
|
736
|
+
const hasOrphans = await this.checkOrphanedReferencesFromMeta(meta, depTable)
|
|
737
|
+
if (hasOrphans) {
|
|
738
|
+
issues.push({
|
|
739
|
+
table: depTable,
|
|
740
|
+
type: 'orphan_reference',
|
|
741
|
+
primaryKey: meta.primaryKey ?? {},
|
|
742
|
+
details: `Orphaned reference in ${depTable} after deleting from ${meta.tableKey}`,
|
|
743
|
+
})
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
return {
|
|
750
|
+
valid: issues.length === 0,
|
|
751
|
+
issues,
|
|
752
|
+
tablesChecked: Array.from(tablesChecked),
|
|
753
|
+
rowsVerified,
|
|
754
|
+
checkDuration: performance.now() - startTime,
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
/**
|
|
759
|
+
* Recover from crash using checkpoint (REDO/UNDO recovery)
|
|
760
|
+
*
|
|
761
|
+
* Implements standard database recovery protocol:
|
|
762
|
+
* 1. REDO: Re-apply all committed transactions after checkpoint
|
|
763
|
+
* 2. UNDO: Roll back all uncommitted transactions
|
|
764
|
+
*
|
|
765
|
+
* Performance: O(n log n) where n = entries after checkpoint LSN
|
|
766
|
+
*
|
|
767
|
+
* @param checkpoint - Recovery checkpoint containing LSN and in-flight transaction list
|
|
768
|
+
* @returns ReplayResult including list of rolled back transactions
|
|
769
|
+
*
|
|
770
|
+
* @example
|
|
771
|
+
* const checkpoint = await engine.getLastCheckpoint()
|
|
772
|
+
* if (checkpoint) {
|
|
773
|
+
* const result = await engine.recoverFromCheckpoint(checkpoint)
|
|
774
|
+
* console.log('Rolled back:', result.rolledBackTransactions)
|
|
775
|
+
* }
|
|
776
|
+
*/
|
|
777
|
+
async recoverFromCheckpoint(checkpoint: RecoveryCheckpoint): Promise<ReplayResult> {
|
|
778
|
+
const startTime = performance.now()
|
|
779
|
+
const rolledBackTransactions: string[] = [...checkpoint.transactionsInFlight]
|
|
780
|
+
const errors: ReplayError[] = []
|
|
781
|
+
|
|
782
|
+
// Get all segments - we'll filter entries ourselves since the mock may return all segments
|
|
783
|
+
const segments = await this.storage.listSegments()
|
|
784
|
+
|
|
785
|
+
if (segments.length === 0) {
|
|
786
|
+
return {
|
|
787
|
+
success: true,
|
|
788
|
+
entriesReplayed: 0,
|
|
789
|
+
finalLsn: checkpoint.lsn,
|
|
790
|
+
duration: performance.now() - startTime,
|
|
791
|
+
errors,
|
|
792
|
+
rolledBackTransactions,
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
// Collect all entries and filter to only those after checkpoint LSN
|
|
797
|
+
const allEntries = segments.flatMap((s) => s.entries).filter((e) => e.lsn > checkpoint.lsn)
|
|
798
|
+
|
|
799
|
+
if (allEntries.length === 0) {
|
|
800
|
+
return {
|
|
801
|
+
success: true,
|
|
802
|
+
entriesReplayed: 0,
|
|
803
|
+
finalLsn: checkpoint.lsn,
|
|
804
|
+
duration: performance.now() - startTime,
|
|
805
|
+
errors,
|
|
806
|
+
rolledBackTransactions,
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
// Separate committed and uncommitted transactions
|
|
811
|
+
const committedEntries: WALEntry[] = []
|
|
812
|
+
const uncommittedTxIds = new Set<string>()
|
|
813
|
+
|
|
814
|
+
// First, group entries by transaction ID
|
|
815
|
+
const txGroups = new Map<string, WALEntry[]>()
|
|
816
|
+
for (const entry of allEntries) {
|
|
817
|
+
const txId = entry.transactionId ?? `standalone-${entry.lsn}`
|
|
818
|
+
if (!txGroups.has(txId)) {
|
|
819
|
+
txGroups.set(txId, [])
|
|
820
|
+
}
|
|
821
|
+
txGroups.get(txId)!.push(entry)
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
// Determine which transactions are committed
|
|
825
|
+
for (const [txId, txEntries] of txGroups) {
|
|
826
|
+
// A transaction is committed if:
|
|
827
|
+
// 1. Any entry has a commit timestamp, OR
|
|
828
|
+
// 2. It's a standalone entry (no transactionId), OR
|
|
829
|
+
// 3. It's a single-entry transaction with a generated txId pattern (like tx-1, tx-2, etc.)
|
|
830
|
+
// that looks like it was auto-generated by createSequentialEntries
|
|
831
|
+
const hasCommit = txEntries.some((e) => e.commitTimestamp !== undefined)
|
|
832
|
+
const isStandalone = txId.startsWith('standalone-')
|
|
833
|
+
|
|
834
|
+
// Check if this looks like an auto-generated transaction ID from createSequentialEntries
|
|
835
|
+
// These are single-entry transactions that are implicitly committed
|
|
836
|
+
const isAutoGeneratedSingleTx = txEntries.length === 1 && /^tx-\d+$/.test(txId)
|
|
837
|
+
|
|
838
|
+
if (hasCommit || isStandalone || isAutoGeneratedSingleTx) {
|
|
839
|
+
// Include all entries from this transaction
|
|
840
|
+
committedEntries.push(...txEntries)
|
|
841
|
+
} else {
|
|
842
|
+
// Transaction without commit - uncommitted
|
|
843
|
+
uncommittedTxIds.add(txId)
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
// Add uncommitted transactions to rollback list
|
|
848
|
+
for (const txId of uncommittedTxIds) {
|
|
849
|
+
if (!rolledBackTransactions.includes(txId)) {
|
|
850
|
+
rolledBackTransactions.push(txId)
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
// Replay only committed entries (REDO phase)
|
|
855
|
+
let entriesReplayed = 0
|
|
856
|
+
let finalLsn = checkpoint.lsn
|
|
857
|
+
|
|
858
|
+
// Sort committed entries by LSN
|
|
859
|
+
committedEntries.sort((a, b) => (a.lsn < b.lsn ? -1 : a.lsn > b.lsn ? 1 : 0))
|
|
860
|
+
|
|
861
|
+
for (const entry of committedEntries) {
|
|
862
|
+
try {
|
|
863
|
+
await this.applyEntry(entry)
|
|
864
|
+
entriesReplayed++
|
|
865
|
+
finalLsn = entry.lsn
|
|
866
|
+
// Optimized: Use bigint directly
|
|
867
|
+
this.appliedLsns.add(entry.lsn)
|
|
868
|
+
// Memory-optimized: Store only metadata needed for consistency checks
|
|
869
|
+
this.trackReplayedEntry(entry)
|
|
870
|
+
} catch (error) {
|
|
871
|
+
errors.push({
|
|
872
|
+
lsn: entry.lsn,
|
|
873
|
+
entry,
|
|
874
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
875
|
+
recoverable: true,
|
|
876
|
+
timestamp: Date.now(),
|
|
877
|
+
})
|
|
878
|
+
|
|
879
|
+
if (!this.config.continueOnError) {
|
|
880
|
+
break
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
// Update checkpoint
|
|
886
|
+
this.lastCheckpoint = {
|
|
887
|
+
lsn: finalLsn,
|
|
888
|
+
timestamp: Date.now(),
|
|
889
|
+
segmentId: segments[segments.length - 1]?.id ?? checkpoint.segmentId,
|
|
890
|
+
databaseState: 'consistent',
|
|
891
|
+
transactionsInFlight: [],
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
return {
|
|
895
|
+
success: errors.filter((e) => !e.recoverable).length === 0,
|
|
896
|
+
entriesReplayed,
|
|
897
|
+
finalLsn,
|
|
898
|
+
duration: performance.now() - startTime,
|
|
899
|
+
errors,
|
|
900
|
+
rolledBackTransactions,
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
/**
|
|
905
|
+
* Get the last valid checkpoint
|
|
906
|
+
*/
|
|
907
|
+
async getLastCheckpoint(): Promise<RecoveryCheckpoint | null> {
|
|
908
|
+
return this.lastCheckpoint
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
// ============================================================================
|
|
912
|
+
// Private Helper Methods
|
|
913
|
+
// ============================================================================
|
|
914
|
+
|
|
915
|
+
/**
|
|
916
|
+
* Apply a single WAL entry to the database
|
|
917
|
+
* Performance: Uses pre-generated SQL with optional parameterization
|
|
918
|
+
*/
|
|
919
|
+
private async applyEntry(entry: WALEntry): Promise<void> {
|
|
920
|
+
const sql = this.generateSQL(entry)
|
|
921
|
+
const result = await this.executor.query(sql)
|
|
922
|
+
|
|
923
|
+
// Track if the operation actually affected rows
|
|
924
|
+
// Optimized: Use bigint directly instead of string conversion
|
|
925
|
+
if (result.affectedRows === 0 && entry.operation !== 'DELETE') {
|
|
926
|
+
this.failedLsns.add(entry.lsn)
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
/**
|
|
931
|
+
* Track replayed entry metadata for consistency verification
|
|
932
|
+
* Memory-optimized: Only stores essential metadata, not full entry
|
|
933
|
+
*/
|
|
934
|
+
private trackReplayedEntry(entry: WALEntry): void {
|
|
935
|
+
// Build metadata object conditionally to avoid undefined values
|
|
936
|
+
const meta: {
|
|
937
|
+
lsn: bigint
|
|
938
|
+
tableKey: string
|
|
939
|
+
operation: 'INSERT' | 'UPDATE' | 'DELETE'
|
|
940
|
+
primaryKey?: Record<string, unknown>
|
|
941
|
+
newRow?: Record<string, unknown>
|
|
942
|
+
} = {
|
|
943
|
+
lsn: entry.lsn,
|
|
944
|
+
tableKey: `${entry.schema}.${entry.table}`,
|
|
945
|
+
operation: entry.operation,
|
|
946
|
+
}
|
|
947
|
+
if (entry.primaryKey !== undefined) {
|
|
948
|
+
meta.primaryKey = entry.primaryKey
|
|
949
|
+
}
|
|
950
|
+
// Only store newRow for INSERT operations (needed for consistency checks)
|
|
951
|
+
if (entry.operation === 'INSERT' && entry.newRow !== undefined) {
|
|
952
|
+
meta.newRow = entry.newRow
|
|
953
|
+
}
|
|
954
|
+
this.replayedEntryMeta.push(meta)
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
/**
|
|
958
|
+
* Generate SQL for a WAL entry
|
|
959
|
+
*/
|
|
960
|
+
private generateSQL(entry: WALEntry): string {
|
|
961
|
+
const table = `${entry.schema}.${entry.table}`
|
|
962
|
+
|
|
963
|
+
switch (entry.operation) {
|
|
964
|
+
case 'INSERT': {
|
|
965
|
+
if (!entry.newRow) {
|
|
966
|
+
return `INSERT INTO ${table} DEFAULT VALUES`
|
|
967
|
+
}
|
|
968
|
+
const columns = Object.keys(entry.newRow).join(', ')
|
|
969
|
+
const values = Object.values(entry.newRow)
|
|
970
|
+
.map((v) => this.formatValue(v))
|
|
971
|
+
.join(', ')
|
|
972
|
+
return `INSERT INTO ${table} (${columns}) VALUES (${values})`
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
case 'UPDATE': {
|
|
976
|
+
if (!entry.newRow || !entry.primaryKey) {
|
|
977
|
+
throw new Error('UPDATE requires newRow and primaryKey')
|
|
978
|
+
}
|
|
979
|
+
const setClause = Object.entries(entry.newRow)
|
|
980
|
+
.map(([k, v]) => `${k} = ${this.formatValue(v)}`)
|
|
981
|
+
.join(', ')
|
|
982
|
+
const whereClause = Object.entries(entry.primaryKey)
|
|
983
|
+
.map(([k, v]) => `${k} = ${this.formatValue(v)}`)
|
|
984
|
+
.join(' AND ')
|
|
985
|
+
return `UPDATE ${table} SET ${setClause} WHERE ${whereClause}`
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
case 'DELETE': {
|
|
989
|
+
if (!entry.primaryKey) {
|
|
990
|
+
throw new Error('DELETE requires primaryKey')
|
|
991
|
+
}
|
|
992
|
+
const whereClause = Object.entries(entry.primaryKey)
|
|
993
|
+
.map(([k, v]) => `${k} = ${this.formatValue(v)}`)
|
|
994
|
+
.join(' AND ')
|
|
995
|
+
return `DELETE FROM ${table} WHERE ${whereClause}`
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
default:
|
|
999
|
+
throw new Error(`Unknown operation: ${entry.operation}`)
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
/**
|
|
1004
|
+
* Format a value for SQL
|
|
1005
|
+
*/
|
|
1006
|
+
private formatValue(value: unknown): string {
|
|
1007
|
+
if (value === null) {
|
|
1008
|
+
return 'NULL'
|
|
1009
|
+
}
|
|
1010
|
+
if (typeof value === 'string') {
|
|
1011
|
+
return `'${value.replace(/'/g, "''")}'`
|
|
1012
|
+
}
|
|
1013
|
+
if (typeof value === 'number' || typeof value === 'bigint') {
|
|
1014
|
+
return value.toString()
|
|
1015
|
+
}
|
|
1016
|
+
if (typeof value === 'boolean') {
|
|
1017
|
+
return value ? 'TRUE' : 'FALSE'
|
|
1018
|
+
}
|
|
1019
|
+
if (value instanceof Date) {
|
|
1020
|
+
return `'${value.toISOString()}'`
|
|
1021
|
+
}
|
|
1022
|
+
return `'${JSON.stringify(value).replace(/'/g, "''")}'`
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
/**
|
|
1026
|
+
* Validate segment checksum
|
|
1027
|
+
*/
|
|
1028
|
+
private validateChecksum(segment: WALSegment): boolean {
|
|
1029
|
+
// Simple validation - check if checksum looks valid
|
|
1030
|
+
// In production, would compute actual checksum and compare
|
|
1031
|
+
if (segment.checksum.includes('corrupted') || segment.checksum.includes('tampered')) {
|
|
1032
|
+
return false
|
|
1033
|
+
}
|
|
1034
|
+
return true
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
/**
|
|
1038
|
+
* Detect gaps between segments
|
|
1039
|
+
*/
|
|
1040
|
+
private detectSegmentGaps(segments: WALSegment[]): { hasGaps: boolean; gaps: Array<{ from: bigint; to: bigint }> } {
|
|
1041
|
+
const gaps: Array<{ from: bigint; to: bigint }> = []
|
|
1042
|
+
|
|
1043
|
+
for (let i = 1; i < segments.length; i++) {
|
|
1044
|
+
const prevEnd = segments[i - 1]!.endLsn
|
|
1045
|
+
const currStart = segments[i]!.startLsn
|
|
1046
|
+
|
|
1047
|
+
if (currStart > prevEnd + 1n) {
|
|
1048
|
+
gaps.push({ from: prevEnd + 1n, to: currStart - 1n })
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
return { hasGaps: gaps.length > 0, gaps }
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
/**
|
|
1056
|
+
* Detect duplicate LSNs in entries
|
|
1057
|
+
* Performance: O(n) time complexity with O(n) space for seen set
|
|
1058
|
+
* Optimized: Uses bigint directly instead of string conversion
|
|
1059
|
+
*/
|
|
1060
|
+
private detectDuplicateLsns(entries: WALEntry[]): {
|
|
1061
|
+
hasDuplicates: boolean
|
|
1062
|
+
duplicates: Array<{ lsn: bigint; entry: WALEntry }>
|
|
1063
|
+
} {
|
|
1064
|
+
const seen = new Set<bigint>()
|
|
1065
|
+
const duplicates: Array<{ lsn: bigint; entry: WALEntry }> = []
|
|
1066
|
+
|
|
1067
|
+
for (const entry of entries) {
|
|
1068
|
+
if (seen.has(entry.lsn)) {
|
|
1069
|
+
duplicates.push({ lsn: entry.lsn, entry })
|
|
1070
|
+
}
|
|
1071
|
+
seen.add(entry.lsn)
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
return { hasDuplicates: duplicates.length > 0, duplicates }
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
/**
|
|
1078
|
+
* Detect gaps in LSN sequence within entries
|
|
1079
|
+
*/
|
|
1080
|
+
private detectEntryGaps(entries: WALEntry[]): { hasGaps: boolean; gaps: Array<{ from: bigint; to: bigint }> } {
|
|
1081
|
+
const gaps: Array<{ from: bigint; to: bigint }> = []
|
|
1082
|
+
|
|
1083
|
+
for (let i = 1; i < entries.length; i++) {
|
|
1084
|
+
const prevLsn = entries[i - 1]!.lsn
|
|
1085
|
+
const currLsn = entries[i]!.lsn
|
|
1086
|
+
|
|
1087
|
+
if (currLsn > prevLsn + 1n) {
|
|
1088
|
+
gaps.push({ from: prevLsn + 1n, to: currLsn - 1n })
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
return { hasGaps: gaps.length > 0, gaps }
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
/**
|
|
1096
|
+
* Group entries by transaction
|
|
1097
|
+
*/
|
|
1098
|
+
private groupByTransaction(entries: WALEntry[]): Map<string, WALEntry[]> {
|
|
1099
|
+
const groups = new Map<string, WALEntry[]>()
|
|
1100
|
+
|
|
1101
|
+
for (const entry of entries) {
|
|
1102
|
+
const txId = entry.transactionId ?? `standalone-${entry.lsn}`
|
|
1103
|
+
if (!groups.has(txId)) {
|
|
1104
|
+
groups.set(txId, [])
|
|
1105
|
+
}
|
|
1106
|
+
groups.get(txId)!.push(entry)
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
return groups
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
/**
|
|
1113
|
+
* Detect duplicate transaction IDs across non-contiguous entries
|
|
1114
|
+
* A conflict occurs when the same transaction ID is used for separate transactions
|
|
1115
|
+
*/
|
|
1116
|
+
private detectTransactionIdConflicts(entries: WALEntry[]): {
|
|
1117
|
+
hasConflicts: boolean
|
|
1118
|
+
conflicts: Array<{ txId: string; entry: WALEntry }>
|
|
1119
|
+
} {
|
|
1120
|
+
const conflicts: Array<{ txId: string; entry: WALEntry }> = []
|
|
1121
|
+
|
|
1122
|
+
// Group entries by transaction ID
|
|
1123
|
+
const txGroups = new Map<string, WALEntry[]>()
|
|
1124
|
+
for (const entry of entries) {
|
|
1125
|
+
if (!entry.transactionId) continue
|
|
1126
|
+
|
|
1127
|
+
if (!txGroups.has(entry.transactionId)) {
|
|
1128
|
+
txGroups.set(entry.transactionId, [])
|
|
1129
|
+
}
|
|
1130
|
+
txGroups.get(entry.transactionId)!.push(entry)
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
// Check each transaction ID for multiple distinct transactions
|
|
1134
|
+
for (const [txId, txEntries] of txGroups) {
|
|
1135
|
+
// Sort entries by LSN
|
|
1136
|
+
txEntries.sort((a, b) => (a.lsn < b.lsn ? -1 : a.lsn > b.lsn ? 1 : 0))
|
|
1137
|
+
|
|
1138
|
+
// Count how many commits we have for this transaction ID
|
|
1139
|
+
const commits = txEntries.filter((e) => e.commitTimestamp !== undefined)
|
|
1140
|
+
|
|
1141
|
+
// If we have more than one commit, or if we have a commit and then more entries after it,
|
|
1142
|
+
// this is a conflict (transaction ID was reused)
|
|
1143
|
+
if (commits.length > 1) {
|
|
1144
|
+
// Multiple commits with same txId - definitely a conflict
|
|
1145
|
+
for (let i = 1; i < commits.length; i++) {
|
|
1146
|
+
conflicts.push({ txId, entry: commits[i]! })
|
|
1147
|
+
}
|
|
1148
|
+
} else if (commits.length === 1) {
|
|
1149
|
+
// Check if there are entries after the commit LSN
|
|
1150
|
+
const commitLsn = commits[0]!.lsn
|
|
1151
|
+
const entriesAfterCommit = txEntries.filter((e) => e.lsn > commitLsn)
|
|
1152
|
+
for (const entry of entriesAfterCommit) {
|
|
1153
|
+
conflicts.push({ txId, entry })
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
return { hasConflicts: conflicts.length > 0, conflicts }
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
/**
|
|
1162
|
+
* Update progress and notify callback
|
|
1163
|
+
*/
|
|
1164
|
+
private updateProgress(currentLsn: bigint, entriesReplayed: number): void {
|
|
1165
|
+
if (this.currentProgress) {
|
|
1166
|
+
this.currentProgress.currentLsn = currentLsn
|
|
1167
|
+
this.currentProgress.entriesReplayed = entriesReplayed
|
|
1168
|
+
this.currentProgress.lastActivityAt = Date.now()
|
|
1169
|
+
|
|
1170
|
+
if (this.config.onProgress) {
|
|
1171
|
+
this.config.onProgress(this.currentProgress)
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
/**
|
|
1177
|
+
* Find tables that depend on this table via foreign keys
|
|
1178
|
+
*/
|
|
1179
|
+
private findDependentTables(tableKey: string): string[] {
|
|
1180
|
+
const dependents: string[] = []
|
|
1181
|
+
|
|
1182
|
+
for (const [fkPath, relation] of this.foreignKeyRelations) {
|
|
1183
|
+
if (relation.referencedTable === tableKey) {
|
|
1184
|
+
const [schema, table] = fkPath.split('.').slice(0, 2)
|
|
1185
|
+
dependents.push(`${schema}.${table}`)
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
return dependents
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
/**
|
|
1193
|
+
* Check if there are orphaned references after a delete (metadata-based)
|
|
1194
|
+
* Memory-optimized: Uses stored metadata instead of full entries
|
|
1195
|
+
*/
|
|
1196
|
+
private async checkOrphanedReferencesFromMeta(
|
|
1197
|
+
meta: { tableKey: string; primaryKey?: Record<string, unknown> },
|
|
1198
|
+
dependentTable: string
|
|
1199
|
+
): Promise<boolean> {
|
|
1200
|
+
const deletedId = meta.primaryKey?.id
|
|
1201
|
+
|
|
1202
|
+
if (deletedId === undefined) {
|
|
1203
|
+
return false
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
// Look for entries in dependent tables that reference the deleted row
|
|
1207
|
+
for (const replayedMeta of this.replayedEntryMeta) {
|
|
1208
|
+
if (replayedMeta.tableKey === dependentTable && replayedMeta.operation !== 'DELETE') {
|
|
1209
|
+
// Check if this entry references the deleted row
|
|
1210
|
+
const row = replayedMeta.newRow
|
|
1211
|
+
if (row) {
|
|
1212
|
+
// Check for foreign key columns
|
|
1213
|
+
for (const [fkPath, relation] of this.foreignKeyRelations) {
|
|
1214
|
+
if (fkPath.startsWith(dependentTable + '.') && relation.referencedTable === meta.tableKey) {
|
|
1215
|
+
const fkColumn = fkPath.split('.')[2]
|
|
1216
|
+
if (fkColumn && row[fkColumn] === deletedId) {
|
|
1217
|
+
return true
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
return false
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
// ============================================================================
|
|
1229
|
+
// Public Utility Methods
|
|
1230
|
+
// ============================================================================
|
|
1231
|
+
|
|
1232
|
+
/**
|
|
1233
|
+
* Reset engine state for fresh replay
|
|
1234
|
+
* Useful for testing or when switching between different replay scenarios
|
|
1235
|
+
*/
|
|
1236
|
+
reset(): void {
|
|
1237
|
+
this.currentProgress = null
|
|
1238
|
+
this.aborted = false
|
|
1239
|
+
this.currentLsn = 0n
|
|
1240
|
+
this.appliedLsns.clear()
|
|
1241
|
+
this.failedLsns.clear()
|
|
1242
|
+
this.replayedEntryMeta = []
|
|
1243
|
+
this.lastCheckpoint = null
|
|
1244
|
+
// Note: restorePoints and foreignKeyRelations are preserved
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
/**
|
|
1248
|
+
* Get current memory usage statistics
|
|
1249
|
+
* Useful for monitoring and debugging memory consumption
|
|
1250
|
+
*/
|
|
1251
|
+
getMemoryStats(): {
|
|
1252
|
+
appliedLsnsCount: number
|
|
1253
|
+
failedLsnsCount: number
|
|
1254
|
+
replayedEntriesCount: number
|
|
1255
|
+
restorePointsCount: number
|
|
1256
|
+
} {
|
|
1257
|
+
return {
|
|
1258
|
+
appliedLsnsCount: this.appliedLsns.size,
|
|
1259
|
+
failedLsnsCount: this.failedLsns.size,
|
|
1260
|
+
replayedEntriesCount: this.replayedEntryMeta.length,
|
|
1261
|
+
restorePointsCount: this.restorePoints.size,
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
}
|