@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,1369 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Iceberg Snapshot Management and Compaction
|
|
3
|
+
* Task: postgres-iyx - Snapshot management and compaction
|
|
4
|
+
*
|
|
5
|
+
* Provides snapshot lifecycle management and data compaction for Iceberg tables:
|
|
6
|
+
* - Snapshot listing and metadata retrieval
|
|
7
|
+
* - Snapshot expiration/retention
|
|
8
|
+
* - File compaction (merge small files)
|
|
9
|
+
* - Orphan file cleanup
|
|
10
|
+
* - Manifest rewriting for optimization
|
|
11
|
+
* - Background compaction scheduling
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* const manager = createSnapshotManager({
|
|
16
|
+
* bucket: env.ICEBERG_BUCKET,
|
|
17
|
+
* tablePath: 'iceberg/my-table',
|
|
18
|
+
* })
|
|
19
|
+
*
|
|
20
|
+
* await manager.initialize()
|
|
21
|
+
*
|
|
22
|
+
* // List snapshots
|
|
23
|
+
* const snapshots = manager.listSnapshots()
|
|
24
|
+
*
|
|
25
|
+
* // Expire old snapshots
|
|
26
|
+
* await manager.expireSnapshots({
|
|
27
|
+
* maxAgeDays: 30,
|
|
28
|
+
* minSnapshotsToRetain: 5,
|
|
29
|
+
* })
|
|
30
|
+
*
|
|
31
|
+
* // Compact small files
|
|
32
|
+
* await manager.compactFiles({
|
|
33
|
+
* minFileSizeBytes: 10 * 1024 * 1024, // 10 MB
|
|
34
|
+
* maxFilesPerCompaction: 100,
|
|
35
|
+
* })
|
|
36
|
+
*
|
|
37
|
+
* // Cleanup orphan files
|
|
38
|
+
* await manager.cleanupOrphanFiles()
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
import type {
|
|
43
|
+
IcebergTableMetadata,
|
|
44
|
+
IcebergSnapshot,
|
|
45
|
+
IcebergManifestFile,
|
|
46
|
+
IcebergManifestEntry,
|
|
47
|
+
IcebergDataFile,
|
|
48
|
+
IcebergSnapshotSummary,
|
|
49
|
+
} from './types'
|
|
50
|
+
import {
|
|
51
|
+
IcebergMetadataBuilder,
|
|
52
|
+
ManifestBuilder,
|
|
53
|
+
ManifestListBuilder,
|
|
54
|
+
generateMetadataFileName,
|
|
55
|
+
generateManifestFileName,
|
|
56
|
+
generateManifestListFileName,
|
|
57
|
+
} from './metadata'
|
|
58
|
+
import { createLogger, LogLevel, type ILogger } from '@dotdo/postgres-shared'
|
|
59
|
+
|
|
60
|
+
// Module-level logger for snapshot manager errors
|
|
61
|
+
const snapshotLogger: ILogger = createLogger({
|
|
62
|
+
level: LogLevel.ERROR,
|
|
63
|
+
prefix: '[SnapshotManager]',
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
// ========== Types ==========
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Snapshot metadata with additional computed fields
|
|
70
|
+
*/
|
|
71
|
+
export interface SnapshotInfo {
|
|
72
|
+
/** Snapshot ID */
|
|
73
|
+
snapshotId: number
|
|
74
|
+
/** Parent snapshot ID (if any) */
|
|
75
|
+
parentSnapshotId?: number | undefined
|
|
76
|
+
/** Sequence number */
|
|
77
|
+
sequenceNumber: number
|
|
78
|
+
/** Snapshot timestamp */
|
|
79
|
+
timestampMs: number
|
|
80
|
+
/** Operation that created this snapshot */
|
|
81
|
+
operation: string
|
|
82
|
+
/** Summary statistics */
|
|
83
|
+
summary: {
|
|
84
|
+
addedDataFiles: number
|
|
85
|
+
deletedDataFiles: number
|
|
86
|
+
addedRecords: number
|
|
87
|
+
deletedRecords: number
|
|
88
|
+
totalRecords: number
|
|
89
|
+
totalFilesSize: number
|
|
90
|
+
}
|
|
91
|
+
/** Manifest list path */
|
|
92
|
+
manifestListPath: string
|
|
93
|
+
/** Schema ID used */
|
|
94
|
+
schemaId: number
|
|
95
|
+
/** Age of snapshot in milliseconds */
|
|
96
|
+
ageMs: number
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Snapshot retention configuration
|
|
101
|
+
*/
|
|
102
|
+
export interface RetentionConfig {
|
|
103
|
+
/** Maximum age of snapshots to keep (in days) */
|
|
104
|
+
maxAgeDays?: number
|
|
105
|
+
/** Minimum number of snapshots to retain regardless of age */
|
|
106
|
+
minSnapshotsToRetain?: number
|
|
107
|
+
/** Maximum number of snapshots to keep */
|
|
108
|
+
maxSnapshotsToRetain?: number
|
|
109
|
+
/** Specific snapshot IDs to always retain (cherry-pick archival) */
|
|
110
|
+
retainSnapshotIds?: number[]
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Compaction configuration
|
|
115
|
+
*/
|
|
116
|
+
export interface CompactionConfig {
|
|
117
|
+
/** Minimum file size threshold for compaction (bytes) */
|
|
118
|
+
minFileSizeBytes?: number
|
|
119
|
+
/** Maximum number of files to include in a single compaction */
|
|
120
|
+
maxFilesPerCompaction?: number
|
|
121
|
+
/** Maximum total input size for a single compaction (bytes) */
|
|
122
|
+
maxInputSizeBytes?: number
|
|
123
|
+
/** Target output file size (bytes) */
|
|
124
|
+
targetFileSizeBytes?: number
|
|
125
|
+
/** Compaction strategy */
|
|
126
|
+
strategy?: CompactionStrategy
|
|
127
|
+
/** Only compact files in specific partitions */
|
|
128
|
+
partitionFilter?: Record<string, unknown>
|
|
129
|
+
/** Skip compaction if file count is below this threshold */
|
|
130
|
+
minFilesToCompact?: number
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Compaction strategy
|
|
135
|
+
*/
|
|
136
|
+
export type CompactionStrategy =
|
|
137
|
+
| 'bin-pack' // Pack small files into target size
|
|
138
|
+
| 'sort' // Sort and rewrite files
|
|
139
|
+
| 'z-order' // Z-order optimization for multi-column queries
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Result of snapshot expiration
|
|
143
|
+
*/
|
|
144
|
+
export interface ExpireSnapshotsResult {
|
|
145
|
+
/** Number of snapshots expired */
|
|
146
|
+
snapshotsExpired: number
|
|
147
|
+
/** Snapshot IDs that were expired */
|
|
148
|
+
expiredSnapshotIds: number[]
|
|
149
|
+
/** Number of manifests removed */
|
|
150
|
+
manifestsRemoved: number
|
|
151
|
+
/** Number of manifest lists removed */
|
|
152
|
+
manifestListsRemoved: number
|
|
153
|
+
/** Bytes freed from metadata */
|
|
154
|
+
metadataBytesFreed: number
|
|
155
|
+
/** Duration in milliseconds */
|
|
156
|
+
durationMs: number
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Result of file compaction
|
|
161
|
+
*/
|
|
162
|
+
export interface CompactFilesResult {
|
|
163
|
+
/** Number of input files */
|
|
164
|
+
inputFileCount: number
|
|
165
|
+
/** Number of output files */
|
|
166
|
+
outputFileCount: number
|
|
167
|
+
/** Total input size in bytes */
|
|
168
|
+
inputSizeBytes: number
|
|
169
|
+
/** Total output size in bytes */
|
|
170
|
+
outputSizeBytes: number
|
|
171
|
+
/** Size reduction in bytes */
|
|
172
|
+
sizeReductionBytes: number
|
|
173
|
+
/** Records processed */
|
|
174
|
+
recordsProcessed: number
|
|
175
|
+
/** Partitions compacted */
|
|
176
|
+
partitionsCompacted: number
|
|
177
|
+
/** New snapshot created */
|
|
178
|
+
snapshot: IcebergSnapshot | null
|
|
179
|
+
/** Duration in milliseconds */
|
|
180
|
+
durationMs: number
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Result of orphan file cleanup
|
|
185
|
+
*/
|
|
186
|
+
export interface CleanupOrphanFilesResult {
|
|
187
|
+
/** Number of orphan files found */
|
|
188
|
+
orphanFilesFound: number
|
|
189
|
+
/** Number of orphan files deleted */
|
|
190
|
+
orphanFilesDeleted: number
|
|
191
|
+
/** Orphan file paths */
|
|
192
|
+
orphanFilePaths: string[]
|
|
193
|
+
/** Bytes freed */
|
|
194
|
+
bytesFreed: number
|
|
195
|
+
/** Duration in milliseconds */
|
|
196
|
+
durationMs: number
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* File statistics for compaction analysis
|
|
201
|
+
*/
|
|
202
|
+
export interface FileStatistics {
|
|
203
|
+
/** Total number of data files */
|
|
204
|
+
totalFiles: number
|
|
205
|
+
/** Total size of all files in bytes */
|
|
206
|
+
totalSizeBytes: number
|
|
207
|
+
/** Average file size in bytes */
|
|
208
|
+
avgFileSizeBytes: number
|
|
209
|
+
/** Minimum file size in bytes */
|
|
210
|
+
minFileSizeBytes: number
|
|
211
|
+
/** Maximum file size in bytes */
|
|
212
|
+
maxFileSizeBytes: number
|
|
213
|
+
/** Number of files below compaction threshold */
|
|
214
|
+
smallFileCount: number
|
|
215
|
+
/** Size of small files in bytes */
|
|
216
|
+
smallFilesSizeBytes: number
|
|
217
|
+
/** Files by partition */
|
|
218
|
+
filesByPartition: Map<string, number>
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Compaction trigger result
|
|
223
|
+
*/
|
|
224
|
+
export interface CompactionTriggerResult {
|
|
225
|
+
/** Whether compaction should be triggered */
|
|
226
|
+
shouldCompact: boolean
|
|
227
|
+
/** Reason for the decision */
|
|
228
|
+
reason: string
|
|
229
|
+
/** Suggested compaction priority (0-100) */
|
|
230
|
+
priority: number
|
|
231
|
+
/** Estimated benefit (bytes to be freed) */
|
|
232
|
+
estimatedBenefit: number
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Snapshot manager configuration
|
|
237
|
+
*/
|
|
238
|
+
export interface SnapshotManagerConfig {
|
|
239
|
+
/** R2 bucket for Iceberg storage */
|
|
240
|
+
bucket: R2Bucket
|
|
241
|
+
/** Base path for the table in R2 */
|
|
242
|
+
tablePath: string
|
|
243
|
+
/** DO state for storing manager state (optional) */
|
|
244
|
+
state?: DurableObjectState | undefined
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Snapshot manager statistics
|
|
249
|
+
*/
|
|
250
|
+
export interface SnapshotManagerStats {
|
|
251
|
+
/** Total snapshots expired */
|
|
252
|
+
totalSnapshotsExpired: number
|
|
253
|
+
/** Total compactions performed */
|
|
254
|
+
totalCompactions: number
|
|
255
|
+
/** Total bytes freed from expiration */
|
|
256
|
+
totalBytesFreedExpiration: number
|
|
257
|
+
/** Total bytes saved from compaction */
|
|
258
|
+
totalBytesSavedCompaction: number
|
|
259
|
+
/** Total orphan files cleaned */
|
|
260
|
+
totalOrphanFilesCleaned: number
|
|
261
|
+
/** Last expiration timestamp */
|
|
262
|
+
lastExpirationAt: number | null
|
|
263
|
+
/** Last compaction timestamp */
|
|
264
|
+
lastCompactionAt: number | null
|
|
265
|
+
/** Last cleanup timestamp */
|
|
266
|
+
lastCleanupAt: number | null
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// ========== Default Configuration ==========
|
|
270
|
+
|
|
271
|
+
const DEFAULT_RETENTION: Required<RetentionConfig> = {
|
|
272
|
+
maxAgeDays: 30,
|
|
273
|
+
minSnapshotsToRetain: 5,
|
|
274
|
+
maxSnapshotsToRetain: 100,
|
|
275
|
+
retainSnapshotIds: [],
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const DEFAULT_COMPACTION: Required<CompactionConfig> = {
|
|
279
|
+
minFileSizeBytes: 10 * 1024 * 1024, // 10 MB
|
|
280
|
+
maxFilesPerCompaction: 100,
|
|
281
|
+
maxInputSizeBytes: 1024 * 1024 * 1024, // 1 GB
|
|
282
|
+
targetFileSizeBytes: 128 * 1024 * 1024, // 128 MB
|
|
283
|
+
strategy: 'bin-pack',
|
|
284
|
+
partitionFilter: {},
|
|
285
|
+
minFilesToCompact: 5,
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// ========== Snapshot Manager Class ==========
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Iceberg Snapshot Manager
|
|
292
|
+
*
|
|
293
|
+
* Manages snapshot lifecycle including expiration, compaction, and cleanup.
|
|
294
|
+
*/
|
|
295
|
+
export class SnapshotManager {
|
|
296
|
+
private bucket: R2Bucket
|
|
297
|
+
private tablePath: string
|
|
298
|
+
private metadata: IcebergTableMetadata | null = null
|
|
299
|
+
private metadataBuilder: IcebergMetadataBuilder | null = null
|
|
300
|
+
private metadataVersion = 0
|
|
301
|
+
private initialized = false
|
|
302
|
+
|
|
303
|
+
private stats: SnapshotManagerStats = {
|
|
304
|
+
totalSnapshotsExpired: 0,
|
|
305
|
+
totalCompactions: 0,
|
|
306
|
+
totalBytesFreedExpiration: 0,
|
|
307
|
+
totalBytesSavedCompaction: 0,
|
|
308
|
+
totalOrphanFilesCleaned: 0,
|
|
309
|
+
lastExpirationAt: null,
|
|
310
|
+
lastCompactionAt: null,
|
|
311
|
+
lastCleanupAt: null,
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
constructor(config: SnapshotManagerConfig) {
|
|
315
|
+
this.bucket = config.bucket
|
|
316
|
+
this.tablePath = config.tablePath.replace(/\/$/, '')
|
|
317
|
+
// state is accepted for future use but not currently utilized
|
|
318
|
+
void config.state
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Initialize the snapshot manager
|
|
323
|
+
*/
|
|
324
|
+
async initialize(): Promise<void> {
|
|
325
|
+
if (this.initialized) {
|
|
326
|
+
return
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
await this.loadMetadata()
|
|
330
|
+
this.initialized = true
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Ensure initialized
|
|
335
|
+
*/
|
|
336
|
+
private ensureInitialized(): void {
|
|
337
|
+
if (!this.initialized) {
|
|
338
|
+
throw new Error('SnapshotManager not initialized. Call initialize() first.')
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Load table metadata from R2
|
|
344
|
+
*/
|
|
345
|
+
private async loadMetadata(): Promise<void> {
|
|
346
|
+
// Try version hint first
|
|
347
|
+
const versionHint = await this.bucket.get(`${this.tablePath}/metadata/version-hint.text`)
|
|
348
|
+
if (versionHint) {
|
|
349
|
+
this.metadataVersion = parseInt(await versionHint.text(), 10)
|
|
350
|
+
const metadataPath = `${this.tablePath}/metadata/v${this.metadataVersion}.metadata.json`
|
|
351
|
+
const metadataObj = await this.bucket.get(metadataPath)
|
|
352
|
+
if (metadataObj) {
|
|
353
|
+
this.metadata = JSON.parse(await metadataObj.text()) as IcebergTableMetadata
|
|
354
|
+
this.metadataBuilder = IcebergMetadataBuilder.fromMetadata(this.metadata)
|
|
355
|
+
return
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Fall back to listing metadata files
|
|
360
|
+
const list = await this.bucket.list({
|
|
361
|
+
prefix: `${this.tablePath}/metadata/`,
|
|
362
|
+
})
|
|
363
|
+
|
|
364
|
+
const metadataFiles = list.objects
|
|
365
|
+
.filter((obj) => obj.key.endsWith('.metadata.json'))
|
|
366
|
+
.sort((a, b) => {
|
|
367
|
+
const versionA = parseInt(a.key.match(/v(\d+)\.metadata\.json/)?.[1] ?? '0', 10)
|
|
368
|
+
const versionB = parseInt(b.key.match(/v(\d+)\.metadata\.json/)?.[1] ?? '0', 10)
|
|
369
|
+
return versionB - versionA
|
|
370
|
+
})
|
|
371
|
+
|
|
372
|
+
if (metadataFiles.length > 0 && metadataFiles[0]) {
|
|
373
|
+
const metadataObj = await this.bucket.get(metadataFiles[0].key)
|
|
374
|
+
if (metadataObj) {
|
|
375
|
+
this.metadata = JSON.parse(await metadataObj.text()) as IcebergTableMetadata
|
|
376
|
+
this.metadataBuilder = IcebergMetadataBuilder.fromMetadata(this.metadata)
|
|
377
|
+
this.metadataVersion = parseInt(
|
|
378
|
+
metadataFiles[0].key.match(/v(\d+)\.metadata\.json/)?.[1] ?? '0',
|
|
379
|
+
10
|
|
380
|
+
)
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Refresh metadata from R2
|
|
387
|
+
*/
|
|
388
|
+
async refreshMetadata(): Promise<void> {
|
|
389
|
+
this.initialized = false
|
|
390
|
+
this.metadata = null
|
|
391
|
+
this.metadataBuilder = null
|
|
392
|
+
await this.initialize()
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// ========== Snapshot Listing and Metadata ==========
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* List all snapshots with computed metadata
|
|
399
|
+
*/
|
|
400
|
+
listSnapshots(): SnapshotInfo[] {
|
|
401
|
+
this.ensureInitialized()
|
|
402
|
+
|
|
403
|
+
if (!this.metadata?.snapshots) {
|
|
404
|
+
return []
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
const now = Date.now()
|
|
408
|
+
return this.metadata.snapshots.map((snapshot) => this.snapshotToInfo(snapshot, now))
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Get a specific snapshot by ID
|
|
413
|
+
*/
|
|
414
|
+
getSnapshot(snapshotId: number): SnapshotInfo | null {
|
|
415
|
+
this.ensureInitialized()
|
|
416
|
+
|
|
417
|
+
const snapshot = this.metadata?.snapshots?.find((s) => s['snapshot-id'] === snapshotId)
|
|
418
|
+
if (!snapshot) {
|
|
419
|
+
return null
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
return this.snapshotToInfo(snapshot, Date.now())
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Get the current snapshot
|
|
427
|
+
*/
|
|
428
|
+
getCurrentSnapshot(): SnapshotInfo | null {
|
|
429
|
+
this.ensureInitialized()
|
|
430
|
+
|
|
431
|
+
if (!this.metadata?.['current-snapshot-id']) {
|
|
432
|
+
return null
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
return this.getSnapshot(this.metadata['current-snapshot-id'])
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Get snapshot ancestry (parent chain)
|
|
440
|
+
*/
|
|
441
|
+
getSnapshotAncestry(snapshotId: number): SnapshotInfo[] {
|
|
442
|
+
this.ensureInitialized()
|
|
443
|
+
|
|
444
|
+
const ancestry: SnapshotInfo[] = []
|
|
445
|
+
let currentId: number | undefined = snapshotId
|
|
446
|
+
|
|
447
|
+
while (currentId !== undefined) {
|
|
448
|
+
const snapshot = this.getSnapshot(currentId)
|
|
449
|
+
if (!snapshot) {
|
|
450
|
+
break
|
|
451
|
+
}
|
|
452
|
+
ancestry.push(snapshot)
|
|
453
|
+
currentId = snapshot.parentSnapshotId
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
return ancestry
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Convert IcebergSnapshot to SnapshotInfo
|
|
461
|
+
*/
|
|
462
|
+
private snapshotToInfo(snapshot: IcebergSnapshot, now: number): SnapshotInfo {
|
|
463
|
+
const summary = snapshot.summary
|
|
464
|
+
return {
|
|
465
|
+
snapshotId: snapshot['snapshot-id'],
|
|
466
|
+
parentSnapshotId: snapshot['parent-snapshot-id'],
|
|
467
|
+
sequenceNumber: snapshot['sequence-number'],
|
|
468
|
+
timestampMs: snapshot['timestamp-ms'],
|
|
469
|
+
operation: summary.operation,
|
|
470
|
+
summary: {
|
|
471
|
+
addedDataFiles: parseInt(summary['added-data-files'] ?? '0', 10),
|
|
472
|
+
deletedDataFiles: parseInt(summary['deleted-data-files'] ?? '0', 10),
|
|
473
|
+
addedRecords: parseInt(summary['added-records'] ?? '0', 10),
|
|
474
|
+
deletedRecords: parseInt(summary['deleted-records'] ?? '0', 10),
|
|
475
|
+
totalRecords: parseInt(summary['total-records'] ?? '0', 10),
|
|
476
|
+
totalFilesSize: parseInt(summary['total-files-size'] ?? '0', 10),
|
|
477
|
+
},
|
|
478
|
+
manifestListPath: snapshot['manifest-list'],
|
|
479
|
+
schemaId: snapshot['schema-id'] ?? 0,
|
|
480
|
+
ageMs: now - snapshot['timestamp-ms'],
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// ========== Snapshot Expiration ==========
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Expire old snapshots based on retention policy
|
|
488
|
+
*/
|
|
489
|
+
async expireSnapshots(config: RetentionConfig = {}): Promise<ExpireSnapshotsResult> {
|
|
490
|
+
this.ensureInitialized()
|
|
491
|
+
|
|
492
|
+
const startTime = performance.now()
|
|
493
|
+
const retention = { ...DEFAULT_RETENTION, ...config }
|
|
494
|
+
|
|
495
|
+
if (!this.metadata?.snapshots || this.metadata.snapshots.length === 0) {
|
|
496
|
+
return {
|
|
497
|
+
snapshotsExpired: 0,
|
|
498
|
+
expiredSnapshotIds: [],
|
|
499
|
+
manifestsRemoved: 0,
|
|
500
|
+
manifestListsRemoved: 0,
|
|
501
|
+
metadataBytesFreed: 0,
|
|
502
|
+
durationMs: performance.now() - startTime,
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
const now = Date.now()
|
|
507
|
+
const maxAgeMs = retention.maxAgeDays * 24 * 60 * 60 * 1000
|
|
508
|
+
const currentSnapshotId = this.metadata['current-snapshot-id']
|
|
509
|
+
|
|
510
|
+
// Identify snapshots to expire
|
|
511
|
+
const snapshots = [...this.metadata.snapshots]
|
|
512
|
+
const snapshotsToKeep: IcebergSnapshot[] = []
|
|
513
|
+
const snapshotsToExpire: IcebergSnapshot[] = []
|
|
514
|
+
|
|
515
|
+
// Sort by timestamp (newest first) for minSnapshots logic
|
|
516
|
+
snapshots.sort((a, b) => b['timestamp-ms'] - a['timestamp-ms'])
|
|
517
|
+
|
|
518
|
+
for (let i = 0; i < snapshots.length; i++) {
|
|
519
|
+
const snapshot = snapshots[i]!
|
|
520
|
+
const age = now - snapshot['timestamp-ms']
|
|
521
|
+
const isCurrentSnapshot = snapshot['snapshot-id'] === currentSnapshotId
|
|
522
|
+
const isRetainedById = retention.retainSnapshotIds.includes(snapshot['snapshot-id'])
|
|
523
|
+
const withinMinSnapshots = i < retention.minSnapshotsToRetain
|
|
524
|
+
const withinMaxAge = age <= maxAgeMs
|
|
525
|
+
const beyondMaxSnapshots = i >= retention.maxSnapshotsToRetain
|
|
526
|
+
|
|
527
|
+
if (isCurrentSnapshot || isRetainedById || (withinMinSnapshots && !beyondMaxSnapshots)) {
|
|
528
|
+
snapshotsToKeep.push(snapshot)
|
|
529
|
+
} else if (!withinMaxAge || beyondMaxSnapshots) {
|
|
530
|
+
snapshotsToExpire.push(snapshot)
|
|
531
|
+
} else {
|
|
532
|
+
snapshotsToKeep.push(snapshot)
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
if (snapshotsToExpire.length === 0) {
|
|
537
|
+
return {
|
|
538
|
+
snapshotsExpired: 0,
|
|
539
|
+
expiredSnapshotIds: [],
|
|
540
|
+
manifestsRemoved: 0,
|
|
541
|
+
manifestListsRemoved: 0,
|
|
542
|
+
metadataBytesFreed: 0,
|
|
543
|
+
durationMs: performance.now() - startTime,
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// Collect manifest lists and manifests to delete
|
|
548
|
+
const manifestListsToDelete: string[] = []
|
|
549
|
+
const manifestsToDelete: Set<string> = new Set()
|
|
550
|
+
let metadataBytesFreed = 0
|
|
551
|
+
|
|
552
|
+
// Get manifests referenced by snapshots to keep
|
|
553
|
+
const keptManifests = new Set<string>()
|
|
554
|
+
for (const snapshot of snapshotsToKeep) {
|
|
555
|
+
const manifests = await this.loadManifestsFromList(snapshot['manifest-list'])
|
|
556
|
+
for (const manifest of manifests) {
|
|
557
|
+
keptManifests.add(manifest['manifest-path'])
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
// Identify manifest lists and manifests to delete
|
|
562
|
+
for (const snapshot of snapshotsToExpire) {
|
|
563
|
+
manifestListsToDelete.push(snapshot['manifest-list'])
|
|
564
|
+
|
|
565
|
+
const manifests = await this.loadManifestsFromList(snapshot['manifest-list'])
|
|
566
|
+
for (const manifest of manifests) {
|
|
567
|
+
// Only delete if not referenced by a kept snapshot
|
|
568
|
+
if (!keptManifests.has(manifest['manifest-path'])) {
|
|
569
|
+
manifestsToDelete.add(manifest['manifest-path'])
|
|
570
|
+
metadataBytesFreed += manifest['manifest-length']
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// Delete manifest files
|
|
576
|
+
for (const manifestPath of manifestsToDelete) {
|
|
577
|
+
try {
|
|
578
|
+
await this.bucket.delete(manifestPath)
|
|
579
|
+
} catch (error) {
|
|
580
|
+
snapshotLogger.error('Failed to delete manifest', { manifestPath, error: error instanceof Error ? error.message : String(error) })
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// Delete manifest lists
|
|
585
|
+
for (const manifestListPath of manifestListsToDelete) {
|
|
586
|
+
try {
|
|
587
|
+
const obj = await this.bucket.head(manifestListPath)
|
|
588
|
+
if (obj) {
|
|
589
|
+
metadataBytesFreed += obj.size
|
|
590
|
+
}
|
|
591
|
+
await this.bucket.delete(manifestListPath)
|
|
592
|
+
} catch (error) {
|
|
593
|
+
snapshotLogger.error('Failed to delete manifest list', { manifestListPath, error: error instanceof Error ? error.message : String(error) })
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
// Update metadata with remaining snapshots
|
|
598
|
+
await this.updateMetadataWithSnapshots(snapshotsToKeep)
|
|
599
|
+
|
|
600
|
+
// Update stats
|
|
601
|
+
const result: ExpireSnapshotsResult = {
|
|
602
|
+
snapshotsExpired: snapshotsToExpire.length,
|
|
603
|
+
expiredSnapshotIds: snapshotsToExpire.map((s) => s['snapshot-id']),
|
|
604
|
+
manifestsRemoved: manifestsToDelete.size,
|
|
605
|
+
manifestListsRemoved: manifestListsToDelete.length,
|
|
606
|
+
metadataBytesFreed,
|
|
607
|
+
durationMs: performance.now() - startTime,
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
this.stats.totalSnapshotsExpired += result.snapshotsExpired
|
|
611
|
+
this.stats.totalBytesFreedExpiration += result.metadataBytesFreed
|
|
612
|
+
this.stats.lastExpirationAt = Date.now()
|
|
613
|
+
|
|
614
|
+
return result
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* Load manifests from a manifest list
|
|
619
|
+
*/
|
|
620
|
+
private async loadManifestsFromList(manifestListPath: string): Promise<IcebergManifestFile[]> {
|
|
621
|
+
try {
|
|
622
|
+
const obj = await this.bucket.get(manifestListPath)
|
|
623
|
+
if (!obj) {
|
|
624
|
+
return []
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
const data = JSON.parse(await obj.text())
|
|
628
|
+
return data.manifests ?? []
|
|
629
|
+
} catch (error) {
|
|
630
|
+
snapshotLogger.error('Failed to load manifest list', { manifestListPath, error: error instanceof Error ? error.message : String(error) })
|
|
631
|
+
return []
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* Update metadata with new snapshot list
|
|
637
|
+
*/
|
|
638
|
+
private async updateMetadataWithSnapshots(snapshots: IcebergSnapshot[]): Promise<void> {
|
|
639
|
+
if (!this.metadata || !this.metadataBuilder) {
|
|
640
|
+
throw new Error('Metadata not loaded')
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
// Sort snapshots by timestamp
|
|
644
|
+
snapshots.sort((a, b) => a['timestamp-ms'] - b['timestamp-ms'])
|
|
645
|
+
|
|
646
|
+
// Create new metadata
|
|
647
|
+
const newMetadata: IcebergTableMetadata = {
|
|
648
|
+
...this.metadata,
|
|
649
|
+
'last-updated-ms': Date.now(),
|
|
650
|
+
snapshots: snapshots,
|
|
651
|
+
'snapshot-log': snapshots.map((s) => ({
|
|
652
|
+
'timestamp-ms': s['timestamp-ms'],
|
|
653
|
+
'snapshot-id': s['snapshot-id'],
|
|
654
|
+
})),
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
// Update current snapshot if needed
|
|
658
|
+
if (
|
|
659
|
+
newMetadata['current-snapshot-id'] !== undefined &&
|
|
660
|
+
!snapshots.some((s) => s['snapshot-id'] === newMetadata['current-snapshot-id'])
|
|
661
|
+
) {
|
|
662
|
+
// Current snapshot was expired, set to latest
|
|
663
|
+
const latestSnapshot = snapshots[snapshots.length - 1]
|
|
664
|
+
if (latestSnapshot) {
|
|
665
|
+
newMetadata['current-snapshot-id'] = latestSnapshot['snapshot-id']
|
|
666
|
+
} else {
|
|
667
|
+
delete newMetadata['current-snapshot-id']
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
// Write new metadata version
|
|
672
|
+
this.metadataVersion++
|
|
673
|
+
const metadataFileName = generateMetadataFileName(this.metadataVersion)
|
|
674
|
+
const metadataPath = `${this.tablePath}/metadata/${metadataFileName}`
|
|
675
|
+
|
|
676
|
+
await this.bucket.put(metadataPath, JSON.stringify(newMetadata, null, 2), {
|
|
677
|
+
httpMetadata: { contentType: 'application/json' },
|
|
678
|
+
})
|
|
679
|
+
|
|
680
|
+
// Update version hint
|
|
681
|
+
await this.bucket.put(
|
|
682
|
+
`${this.tablePath}/metadata/version-hint.text`,
|
|
683
|
+
String(this.metadataVersion),
|
|
684
|
+
{ httpMetadata: { contentType: 'text/plain' } }
|
|
685
|
+
)
|
|
686
|
+
|
|
687
|
+
// Update internal state
|
|
688
|
+
this.metadata = newMetadata
|
|
689
|
+
this.metadataBuilder = IcebergMetadataBuilder.fromMetadata(newMetadata)
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
// ========== File Compaction ==========
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* Analyze file statistics for compaction decisions
|
|
696
|
+
*/
|
|
697
|
+
async analyzeFileStatistics(threshold: number = DEFAULT_COMPACTION.minFileSizeBytes): Promise<FileStatistics> {
|
|
698
|
+
this.ensureInitialized()
|
|
699
|
+
|
|
700
|
+
const dataFiles = await this.getAllDataFiles()
|
|
701
|
+
|
|
702
|
+
const filesByPartition = new Map<string, number>()
|
|
703
|
+
let totalSize = 0
|
|
704
|
+
let minSize = Infinity
|
|
705
|
+
let maxSize = 0
|
|
706
|
+
let smallFileCount = 0
|
|
707
|
+
let smallFilesSize = 0
|
|
708
|
+
|
|
709
|
+
for (const file of dataFiles) {
|
|
710
|
+
const size = file['file-size-in-bytes']
|
|
711
|
+
totalSize += size
|
|
712
|
+
minSize = Math.min(minSize, size)
|
|
713
|
+
maxSize = Math.max(maxSize, size)
|
|
714
|
+
|
|
715
|
+
if (size < threshold) {
|
|
716
|
+
smallFileCount++
|
|
717
|
+
smallFilesSize += size
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
// Extract partition path
|
|
721
|
+
const partitionPath = this.extractPartitionPath(file['file-path'])
|
|
722
|
+
filesByPartition.set(partitionPath, (filesByPartition.get(partitionPath) ?? 0) + 1)
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
return {
|
|
726
|
+
totalFiles: dataFiles.length,
|
|
727
|
+
totalSizeBytes: totalSize,
|
|
728
|
+
avgFileSizeBytes: dataFiles.length > 0 ? totalSize / dataFiles.length : 0,
|
|
729
|
+
minFileSizeBytes: minSize === Infinity ? 0 : minSize,
|
|
730
|
+
maxFileSizeBytes: maxSize,
|
|
731
|
+
smallFileCount,
|
|
732
|
+
smallFilesSizeBytes: smallFilesSize,
|
|
733
|
+
filesByPartition,
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
/**
|
|
738
|
+
* Check if compaction should be triggered
|
|
739
|
+
*/
|
|
740
|
+
async shouldCompact(config: CompactionConfig = {}): Promise<CompactionTriggerResult> {
|
|
741
|
+
const compactionConfig = { ...DEFAULT_COMPACTION, ...config }
|
|
742
|
+
const stats = await this.analyzeFileStatistics(compactionConfig.minFileSizeBytes)
|
|
743
|
+
|
|
744
|
+
// Check file count threshold
|
|
745
|
+
if (stats.smallFileCount < compactionConfig.minFilesToCompact) {
|
|
746
|
+
return {
|
|
747
|
+
shouldCompact: false,
|
|
748
|
+
reason: `Small file count (${stats.smallFileCount}) below threshold (${compactionConfig.minFilesToCompact})`,
|
|
749
|
+
priority: 0,
|
|
750
|
+
estimatedBenefit: 0,
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
// Calculate compaction benefit
|
|
755
|
+
const avgSmallFileSize = stats.smallFileCount > 0
|
|
756
|
+
? stats.smallFilesSizeBytes / stats.smallFileCount
|
|
757
|
+
: 0
|
|
758
|
+
const targetFileCount = Math.ceil(stats.smallFilesSizeBytes / compactionConfig.targetFileSizeBytes)
|
|
759
|
+
const estimatedOutputFiles = Math.max(targetFileCount, 1)
|
|
760
|
+
const fileReduction = stats.smallFileCount - estimatedOutputFiles
|
|
761
|
+
|
|
762
|
+
// Priority based on file count and size ratio
|
|
763
|
+
const fileCountRatio = stats.smallFileCount / stats.totalFiles
|
|
764
|
+
const sizeRatio = avgSmallFileSize / compactionConfig.targetFileSizeBytes
|
|
765
|
+
const priority = Math.min(100, Math.round((fileCountRatio * 50) + ((1 - sizeRatio) * 50)))
|
|
766
|
+
|
|
767
|
+
return {
|
|
768
|
+
shouldCompact: true,
|
|
769
|
+
reason: `${stats.smallFileCount} small files (${formatBytes(stats.smallFilesSizeBytes)}) can be compacted`,
|
|
770
|
+
priority,
|
|
771
|
+
estimatedBenefit: fileReduction * 1000, // Rough estimate of metadata savings per file
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
/**
|
|
776
|
+
* Compact small files
|
|
777
|
+
*
|
|
778
|
+
* Note: Full compaction requires reading and rewriting Parquet files.
|
|
779
|
+
* This implementation tracks which files should be compacted and creates
|
|
780
|
+
* a new snapshot with the compaction metadata. Actual file rewriting
|
|
781
|
+
* would require Parquet library support.
|
|
782
|
+
*/
|
|
783
|
+
async compactFiles(config: CompactionConfig = {}): Promise<CompactFilesResult> {
|
|
784
|
+
this.ensureInitialized()
|
|
785
|
+
|
|
786
|
+
const startTime = performance.now()
|
|
787
|
+
const compactionConfig = { ...DEFAULT_COMPACTION, ...config }
|
|
788
|
+
|
|
789
|
+
// Get all small files
|
|
790
|
+
const allDataFiles = await this.getAllDataFiles()
|
|
791
|
+
const smallFiles = allDataFiles.filter(
|
|
792
|
+
(f) => f['file-size-in-bytes'] < compactionConfig.minFileSizeBytes
|
|
793
|
+
)
|
|
794
|
+
|
|
795
|
+
// Group by partition
|
|
796
|
+
const filesByPartition = new Map<string, IcebergDataFile[]>()
|
|
797
|
+
for (const file of smallFiles) {
|
|
798
|
+
const partitionPath = this.extractPartitionPath(file['file-path'])
|
|
799
|
+
|
|
800
|
+
// Apply partition filter if specified
|
|
801
|
+
if (Object.keys(compactionConfig.partitionFilter).length > 0) {
|
|
802
|
+
const matches = this.matchesPartitionFilter(file.partition, compactionConfig.partitionFilter)
|
|
803
|
+
if (!matches) {
|
|
804
|
+
continue
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
const files = filesByPartition.get(partitionPath) ?? []
|
|
809
|
+
files.push(file)
|
|
810
|
+
filesByPartition.set(partitionPath, files)
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
// Calculate compaction groups
|
|
814
|
+
const compactionGroups: Array<{
|
|
815
|
+
partition: string
|
|
816
|
+
files: IcebergDataFile[]
|
|
817
|
+
totalSize: number
|
|
818
|
+
}> = []
|
|
819
|
+
|
|
820
|
+
for (const [partition, files] of filesByPartition) {
|
|
821
|
+
if (files.length < compactionConfig.minFilesToCompact) {
|
|
822
|
+
continue
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
// Sort by size (ascending) for bin-packing
|
|
826
|
+
files.sort((a, b) => a['file-size-in-bytes'] - b['file-size-in-bytes'])
|
|
827
|
+
|
|
828
|
+
// Create groups respecting maxFilesPerCompaction and maxInputSizeBytes
|
|
829
|
+
let currentGroup: IcebergDataFile[] = []
|
|
830
|
+
let currentSize = 0
|
|
831
|
+
|
|
832
|
+
for (const file of files) {
|
|
833
|
+
if (
|
|
834
|
+
currentGroup.length >= compactionConfig.maxFilesPerCompaction ||
|
|
835
|
+
currentSize + file['file-size-in-bytes'] > compactionConfig.maxInputSizeBytes
|
|
836
|
+
) {
|
|
837
|
+
if (currentGroup.length >= compactionConfig.minFilesToCompact) {
|
|
838
|
+
compactionGroups.push({
|
|
839
|
+
partition,
|
|
840
|
+
files: currentGroup,
|
|
841
|
+
totalSize: currentSize,
|
|
842
|
+
})
|
|
843
|
+
}
|
|
844
|
+
currentGroup = []
|
|
845
|
+
currentSize = 0
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
currentGroup.push(file)
|
|
849
|
+
currentSize += file['file-size-in-bytes']
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
// Add remaining files
|
|
853
|
+
if (currentGroup.length >= compactionConfig.minFilesToCompact) {
|
|
854
|
+
compactionGroups.push({
|
|
855
|
+
partition,
|
|
856
|
+
files: currentGroup,
|
|
857
|
+
totalSize: currentSize,
|
|
858
|
+
})
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
if (compactionGroups.length === 0) {
|
|
863
|
+
return {
|
|
864
|
+
inputFileCount: 0,
|
|
865
|
+
outputFileCount: 0,
|
|
866
|
+
inputSizeBytes: 0,
|
|
867
|
+
outputSizeBytes: 0,
|
|
868
|
+
sizeReductionBytes: 0,
|
|
869
|
+
recordsProcessed: 0,
|
|
870
|
+
partitionsCompacted: 0,
|
|
871
|
+
snapshot: null,
|
|
872
|
+
durationMs: performance.now() - startTime,
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
// Calculate totals
|
|
877
|
+
let totalInputFiles = 0
|
|
878
|
+
let totalInputSize = 0
|
|
879
|
+
let totalRecords = 0
|
|
880
|
+
const partitionsCompacted = new Set<string>()
|
|
881
|
+
|
|
882
|
+
for (const group of compactionGroups) {
|
|
883
|
+
totalInputFiles += group.files.length
|
|
884
|
+
totalInputSize += group.totalSize
|
|
885
|
+
partitionsCompacted.add(group.partition)
|
|
886
|
+
for (const file of group.files) {
|
|
887
|
+
totalRecords += file['record-count']
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
// Create compaction snapshot
|
|
892
|
+
// Note: In a full implementation, this would:
|
|
893
|
+
// 1. Read all input Parquet files
|
|
894
|
+
// 2. Merge and write new Parquet files
|
|
895
|
+
// 3. Create manifest with DELETED entries for old files and ADDED for new
|
|
896
|
+
// For now, we create a metadata-only compaction marker
|
|
897
|
+
|
|
898
|
+
const snapshot = await this.createCompactionSnapshot(
|
|
899
|
+
compactionGroups,
|
|
900
|
+
compactionConfig.targetFileSizeBytes
|
|
901
|
+
)
|
|
902
|
+
|
|
903
|
+
// Calculate output estimates
|
|
904
|
+
const estimatedOutputFiles = compactionGroups.reduce((sum, group) => {
|
|
905
|
+
return sum + Math.ceil(group.totalSize / compactionConfig.targetFileSizeBytes)
|
|
906
|
+
}, 0)
|
|
907
|
+
|
|
908
|
+
const result: CompactFilesResult = {
|
|
909
|
+
inputFileCount: totalInputFiles,
|
|
910
|
+
outputFileCount: estimatedOutputFiles,
|
|
911
|
+
inputSizeBytes: totalInputSize,
|
|
912
|
+
outputSizeBytes: totalInputSize, // In reality would be slightly different
|
|
913
|
+
sizeReductionBytes: 0, // Actual reduction from file consolidation
|
|
914
|
+
recordsProcessed: totalRecords,
|
|
915
|
+
partitionsCompacted: partitionsCompacted.size,
|
|
916
|
+
snapshot,
|
|
917
|
+
durationMs: performance.now() - startTime,
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
this.stats.totalCompactions++
|
|
921
|
+
this.stats.totalBytesSavedCompaction += result.sizeReductionBytes
|
|
922
|
+
this.stats.lastCompactionAt = Date.now()
|
|
923
|
+
|
|
924
|
+
return result
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
/**
|
|
928
|
+
* Create a compaction snapshot
|
|
929
|
+
*/
|
|
930
|
+
private async createCompactionSnapshot(
|
|
931
|
+
compactionGroups: Array<{
|
|
932
|
+
partition: string
|
|
933
|
+
files: IcebergDataFile[]
|
|
934
|
+
totalSize: number
|
|
935
|
+
}>,
|
|
936
|
+
_targetFileSizeBytes: number
|
|
937
|
+
): Promise<IcebergSnapshot | null> {
|
|
938
|
+
if (!this.metadata || !this.metadataBuilder) {
|
|
939
|
+
return null
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
const snapshotId = Date.now() * 1000 + Math.floor(Math.random() * 1000)
|
|
943
|
+
const sequenceNumber = this.metadataBuilder.getSequenceNumber() + 1
|
|
944
|
+
const partitionSpecId = this.metadata['default-spec-id']
|
|
945
|
+
|
|
946
|
+
// Create manifest builder for compaction
|
|
947
|
+
const manifestBuilder = new ManifestBuilder({
|
|
948
|
+
partitionSpecId,
|
|
949
|
+
sequenceNumber,
|
|
950
|
+
snapshotId,
|
|
951
|
+
})
|
|
952
|
+
|
|
953
|
+
// Mark old files as deleted, add placeholder for compacted files
|
|
954
|
+
let totalDeletedFiles = 0
|
|
955
|
+
let totalDeletedRecords = 0
|
|
956
|
+
|
|
957
|
+
for (const group of compactionGroups) {
|
|
958
|
+
for (const file of group.files) {
|
|
959
|
+
manifestBuilder.deleteDataFile(file)
|
|
960
|
+
totalDeletedFiles++
|
|
961
|
+
totalDeletedRecords += file['record-count']
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
// In a real implementation, we would add the newly compacted files here
|
|
965
|
+
// For now, we just mark the intent to compact
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
// Write manifest
|
|
969
|
+
const manifestFileName = generateManifestFileName(snapshotId)
|
|
970
|
+
const manifestPath = `${this.tablePath}/metadata/${manifestFileName}`
|
|
971
|
+
const manifestContent = manifestBuilder.toJSON()
|
|
972
|
+
const manifestBytes = new TextEncoder().encode(manifestContent)
|
|
973
|
+
|
|
974
|
+
await this.bucket.put(manifestPath, manifestBytes, {
|
|
975
|
+
httpMetadata: { contentType: 'application/json' },
|
|
976
|
+
})
|
|
977
|
+
|
|
978
|
+
const manifestFileMetadata = manifestBuilder.createManifestFileMetadata(
|
|
979
|
+
manifestPath,
|
|
980
|
+
manifestBytes.length
|
|
981
|
+
)
|
|
982
|
+
|
|
983
|
+
// Create manifest list
|
|
984
|
+
const manifestListBuilder = new ManifestListBuilder(snapshotId, sequenceNumber)
|
|
985
|
+
manifestListBuilder.addManifest(manifestFileMetadata)
|
|
986
|
+
|
|
987
|
+
// Include existing manifests
|
|
988
|
+
const currentSnapshot = this.metadata.snapshots?.find(
|
|
989
|
+
(s) => s['snapshot-id'] === this.metadata!['current-snapshot-id']
|
|
990
|
+
)
|
|
991
|
+
if (currentSnapshot) {
|
|
992
|
+
const existingManifests = await this.loadManifestsFromList(currentSnapshot['manifest-list'])
|
|
993
|
+
for (const manifest of existingManifests) {
|
|
994
|
+
manifestListBuilder.addManifest(manifest)
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
// Write manifest list
|
|
999
|
+
const manifestListFileName = generateManifestListFileName(snapshotId)
|
|
1000
|
+
const manifestListPath = `${this.tablePath}/metadata/${manifestListFileName}`
|
|
1001
|
+
const manifestListContent = manifestListBuilder.toJSON()
|
|
1002
|
+
const manifestListBytes = new TextEncoder().encode(manifestListContent)
|
|
1003
|
+
|
|
1004
|
+
await this.bucket.put(manifestListPath, manifestListBytes, {
|
|
1005
|
+
httpMetadata: { contentType: 'application/json' },
|
|
1006
|
+
})
|
|
1007
|
+
|
|
1008
|
+
// Create snapshot
|
|
1009
|
+
const summary: IcebergSnapshotSummary = {
|
|
1010
|
+
operation: 'replace',
|
|
1011
|
+
'added-data-files': '0',
|
|
1012
|
+
'deleted-data-files': String(totalDeletedFiles),
|
|
1013
|
+
'added-records': '0',
|
|
1014
|
+
'deleted-records': String(totalDeletedRecords),
|
|
1015
|
+
'compaction-type': 'bin-pack',
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
const snapshot: IcebergSnapshot = {
|
|
1019
|
+
'snapshot-id': snapshotId,
|
|
1020
|
+
...(this.metadata['current-snapshot-id'] !== undefined && {
|
|
1021
|
+
'parent-snapshot-id': this.metadata['current-snapshot-id'],
|
|
1022
|
+
}),
|
|
1023
|
+
'sequence-number': sequenceNumber,
|
|
1024
|
+
'timestamp-ms': Date.now(),
|
|
1025
|
+
'manifest-list': manifestListPath,
|
|
1026
|
+
summary,
|
|
1027
|
+
'schema-id': this.metadata['current-schema-id'],
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
// Update metadata
|
|
1031
|
+
const newSnapshots = [...(this.metadata.snapshots ?? []), snapshot]
|
|
1032
|
+
await this.updateMetadataWithSnapshots(newSnapshots)
|
|
1033
|
+
|
|
1034
|
+
return snapshot
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
// ========== Orphan File Cleanup ==========
|
|
1038
|
+
|
|
1039
|
+
/**
|
|
1040
|
+
* Find and clean up orphan files
|
|
1041
|
+
*
|
|
1042
|
+
* Orphan files are data files that exist in R2 but are not referenced
|
|
1043
|
+
* by any manifest in any snapshot.
|
|
1044
|
+
*/
|
|
1045
|
+
async cleanupOrphanFiles(dryRun = false): Promise<CleanupOrphanFilesResult> {
|
|
1046
|
+
this.ensureInitialized()
|
|
1047
|
+
|
|
1048
|
+
const startTime = performance.now()
|
|
1049
|
+
|
|
1050
|
+
// Get all referenced data files from all snapshots
|
|
1051
|
+
const referencedFiles = new Set<string>()
|
|
1052
|
+
|
|
1053
|
+
if (this.metadata?.snapshots) {
|
|
1054
|
+
for (const snapshot of this.metadata.snapshots) {
|
|
1055
|
+
const manifests = await this.loadManifestsFromList(snapshot['manifest-list'])
|
|
1056
|
+
for (const manifest of manifests) {
|
|
1057
|
+
const entries = await this.loadManifestEntries(manifest['manifest-path'])
|
|
1058
|
+
for (const entry of entries) {
|
|
1059
|
+
// Only count EXISTING and ADDED files (not DELETED)
|
|
1060
|
+
if (entry.status !== 2) {
|
|
1061
|
+
referencedFiles.add(entry['data-file']['file-path'])
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
// List all data files in R2
|
|
1069
|
+
const orphanFiles: Array<{ key: string; size: number }> = []
|
|
1070
|
+
let cursor: string | undefined
|
|
1071
|
+
|
|
1072
|
+
do {
|
|
1073
|
+
const listOptions: R2ListOptions = {
|
|
1074
|
+
prefix: `${this.tablePath}/data/`,
|
|
1075
|
+
limit: 1000,
|
|
1076
|
+
}
|
|
1077
|
+
if (cursor) {
|
|
1078
|
+
listOptions.cursor = cursor
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
const result = await this.bucket.list(listOptions)
|
|
1082
|
+
|
|
1083
|
+
for (const obj of result.objects) {
|
|
1084
|
+
if (obj.key.endsWith('.parquet') && !referencedFiles.has(obj.key)) {
|
|
1085
|
+
orphanFiles.push({ key: obj.key, size: obj.size })
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
cursor = result.truncated ? result.cursor : undefined
|
|
1090
|
+
} while (cursor)
|
|
1091
|
+
|
|
1092
|
+
// Delete orphan files (unless dry run)
|
|
1093
|
+
let bytesFreed = 0
|
|
1094
|
+
const deletedPaths: string[] = []
|
|
1095
|
+
|
|
1096
|
+
if (!dryRun) {
|
|
1097
|
+
for (const orphan of orphanFiles) {
|
|
1098
|
+
try {
|
|
1099
|
+
await this.bucket.delete(orphan.key)
|
|
1100
|
+
bytesFreed += orphan.size
|
|
1101
|
+
deletedPaths.push(orphan.key)
|
|
1102
|
+
} catch (error) {
|
|
1103
|
+
snapshotLogger.error('Failed to delete orphan file', { key: orphan.key, error: error instanceof Error ? error.message : String(error) })
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
} else {
|
|
1107
|
+
bytesFreed = orphanFiles.reduce((sum, f) => sum + f.size, 0)
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
const result: CleanupOrphanFilesResult = {
|
|
1111
|
+
orphanFilesFound: orphanFiles.length,
|
|
1112
|
+
orphanFilesDeleted: dryRun ? 0 : deletedPaths.length,
|
|
1113
|
+
orphanFilePaths: orphanFiles.map((f) => f.key),
|
|
1114
|
+
bytesFreed,
|
|
1115
|
+
durationMs: performance.now() - startTime,
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
if (!dryRun) {
|
|
1119
|
+
this.stats.totalOrphanFilesCleaned += result.orphanFilesDeleted
|
|
1120
|
+
this.stats.lastCleanupAt = Date.now()
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
return result
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
/**
|
|
1127
|
+
* Load manifest entries from a manifest file
|
|
1128
|
+
*/
|
|
1129
|
+
private async loadManifestEntries(manifestPath: string): Promise<IcebergManifestEntry[]> {
|
|
1130
|
+
try {
|
|
1131
|
+
const obj = await this.bucket.get(manifestPath)
|
|
1132
|
+
if (!obj) {
|
|
1133
|
+
return []
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
const data = JSON.parse(await obj.text())
|
|
1137
|
+
return data.entries ?? []
|
|
1138
|
+
} catch (error) {
|
|
1139
|
+
snapshotLogger.error('Failed to load manifest', { manifestPath, error: error instanceof Error ? error.message : String(error) })
|
|
1140
|
+
return []
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
/**
|
|
1145
|
+
* Get all data files from the current snapshot
|
|
1146
|
+
*/
|
|
1147
|
+
private async getAllDataFiles(): Promise<IcebergDataFile[]> {
|
|
1148
|
+
if (!this.metadata?.['current-snapshot-id']) {
|
|
1149
|
+
return []
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
const currentSnapshot = this.metadata.snapshots?.find(
|
|
1153
|
+
(s) => s['snapshot-id'] === this.metadata!['current-snapshot-id']
|
|
1154
|
+
)
|
|
1155
|
+
|
|
1156
|
+
if (!currentSnapshot) {
|
|
1157
|
+
return []
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
const dataFiles: IcebergDataFile[] = []
|
|
1161
|
+
const manifests = await this.loadManifestsFromList(currentSnapshot['manifest-list'])
|
|
1162
|
+
|
|
1163
|
+
for (const manifest of manifests) {
|
|
1164
|
+
if (manifest.content !== 0) {
|
|
1165
|
+
continue // Skip delete manifests
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
const entries = await this.loadManifestEntries(manifest['manifest-path'])
|
|
1169
|
+
for (const entry of entries) {
|
|
1170
|
+
// Only include EXISTING (0) and ADDED (1) files
|
|
1171
|
+
if (entry.status !== 2) {
|
|
1172
|
+
dataFiles.push(entry['data-file'])
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
return dataFiles
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
/**
|
|
1181
|
+
* Extract partition path from file path
|
|
1182
|
+
*/
|
|
1183
|
+
private extractPartitionPath(filePath: string): string {
|
|
1184
|
+
const dataIndex = filePath.indexOf('/data/')
|
|
1185
|
+
if (dataIndex === -1) {
|
|
1186
|
+
return ''
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
const afterData = filePath.substring(dataIndex + 6) // Skip '/data/'
|
|
1190
|
+
const lastSlash = afterData.lastIndexOf('/')
|
|
1191
|
+
if (lastSlash === -1) {
|
|
1192
|
+
return ''
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
return afterData.substring(0, lastSlash)
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
/**
|
|
1199
|
+
* Check if partition values match filter
|
|
1200
|
+
*/
|
|
1201
|
+
private matchesPartitionFilter(
|
|
1202
|
+
partition: Record<string, unknown>,
|
|
1203
|
+
filter: Record<string, unknown>
|
|
1204
|
+
): boolean {
|
|
1205
|
+
for (const [key, value] of Object.entries(filter)) {
|
|
1206
|
+
if (partition[key] !== value) {
|
|
1207
|
+
return false
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
return true
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
// ========== Utility Methods ==========
|
|
1214
|
+
|
|
1215
|
+
/**
|
|
1216
|
+
* Get manager statistics
|
|
1217
|
+
*/
|
|
1218
|
+
getStats(): SnapshotManagerStats {
|
|
1219
|
+
return { ...this.stats }
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
/**
|
|
1223
|
+
* Get the table metadata
|
|
1224
|
+
*/
|
|
1225
|
+
getMetadata(): IcebergTableMetadata | null {
|
|
1226
|
+
return this.metadata
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
/**
|
|
1230
|
+
* Get the table path
|
|
1231
|
+
*/
|
|
1232
|
+
getTablePath(): string {
|
|
1233
|
+
return this.tablePath
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
/**
|
|
1237
|
+
* Get the current metadata version
|
|
1238
|
+
*/
|
|
1239
|
+
getMetadataVersion(): number {
|
|
1240
|
+
return this.metadataVersion
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
// ========== Factory Function ==========
|
|
1245
|
+
|
|
1246
|
+
/**
|
|
1247
|
+
* Create a snapshot manager
|
|
1248
|
+
*/
|
|
1249
|
+
export function createSnapshotManager(config: SnapshotManagerConfig): SnapshotManager {
|
|
1250
|
+
return new SnapshotManager(config)
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
// ========== Utility Functions ==========
|
|
1254
|
+
|
|
1255
|
+
/**
|
|
1256
|
+
* Format bytes as human-readable string
|
|
1257
|
+
*/
|
|
1258
|
+
function formatBytes(bytes: number): string {
|
|
1259
|
+
const units = ['B', 'KB', 'MB', 'GB', 'TB']
|
|
1260
|
+
let unitIndex = 0
|
|
1261
|
+
let value = bytes
|
|
1262
|
+
|
|
1263
|
+
while (value >= 1024 && unitIndex < units.length - 1) {
|
|
1264
|
+
value /= 1024
|
|
1265
|
+
unitIndex++
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
return `${value.toFixed(2)} ${units[unitIndex]}`
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
// ========== Scheduled Compaction Support ==========
|
|
1272
|
+
|
|
1273
|
+
/**
|
|
1274
|
+
* Compaction scheduler configuration
|
|
1275
|
+
*/
|
|
1276
|
+
export interface CompactionSchedulerConfig {
|
|
1277
|
+
/** Snapshot manager to use */
|
|
1278
|
+
manager: SnapshotManager
|
|
1279
|
+
/** Check interval in milliseconds (default: 1 hour) */
|
|
1280
|
+
checkIntervalMs?: number
|
|
1281
|
+
/** Compaction configuration */
|
|
1282
|
+
compactionConfig?: CompactionConfig
|
|
1283
|
+
/** Retention configuration */
|
|
1284
|
+
retentionConfig?: RetentionConfig
|
|
1285
|
+
/** Enable automatic orphan cleanup */
|
|
1286
|
+
enableOrphanCleanup?: boolean
|
|
1287
|
+
/** Orphan cleanup interval in milliseconds (default: 24 hours) */
|
|
1288
|
+
orphanCleanupIntervalMs?: number
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
/**
|
|
1292
|
+
* Compaction scheduler for background maintenance
|
|
1293
|
+
*
|
|
1294
|
+
* Can be used with Durable Object alarms for scheduled maintenance.
|
|
1295
|
+
*/
|
|
1296
|
+
export class CompactionScheduler {
|
|
1297
|
+
private manager: SnapshotManager
|
|
1298
|
+
private checkIntervalMs: number
|
|
1299
|
+
private compactionConfig: CompactionConfig
|
|
1300
|
+
private retentionConfig: RetentionConfig
|
|
1301
|
+
private enableOrphanCleanup: boolean
|
|
1302
|
+
private orphanCleanupIntervalMs: number
|
|
1303
|
+
private lastOrphanCleanup = 0
|
|
1304
|
+
|
|
1305
|
+
constructor(config: CompactionSchedulerConfig) {
|
|
1306
|
+
this.manager = config.manager
|
|
1307
|
+
this.checkIntervalMs = config.checkIntervalMs ?? 60 * 60 * 1000 // 1 hour
|
|
1308
|
+
this.compactionConfig = config.compactionConfig ?? {}
|
|
1309
|
+
this.retentionConfig = config.retentionConfig ?? {}
|
|
1310
|
+
this.enableOrphanCleanup = config.enableOrphanCleanup ?? true
|
|
1311
|
+
this.orphanCleanupIntervalMs = config.orphanCleanupIntervalMs ?? 24 * 60 * 60 * 1000 // 24 hours
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
/**
|
|
1315
|
+
* Run scheduled maintenance
|
|
1316
|
+
*
|
|
1317
|
+
* This method should be called periodically (e.g., from a DO alarm).
|
|
1318
|
+
*/
|
|
1319
|
+
async runMaintenance(): Promise<{
|
|
1320
|
+
expirationResult: ExpireSnapshotsResult | null
|
|
1321
|
+
compactionResult: CompactFilesResult | null
|
|
1322
|
+
cleanupResult: CleanupOrphanFilesResult | null
|
|
1323
|
+
}> {
|
|
1324
|
+
await this.manager.initialize()
|
|
1325
|
+
|
|
1326
|
+
// Expire old snapshots
|
|
1327
|
+
const expirationResult = await this.manager.expireSnapshots(this.retentionConfig)
|
|
1328
|
+
|
|
1329
|
+
// Check if compaction is needed
|
|
1330
|
+
let compactionResult: CompactFilesResult | null = null
|
|
1331
|
+
const triggerResult = await this.manager.shouldCompact(this.compactionConfig)
|
|
1332
|
+
|
|
1333
|
+
if (triggerResult.shouldCompact) {
|
|
1334
|
+
compactionResult = await this.manager.compactFiles(this.compactionConfig)
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
// Run orphan cleanup if enabled and due
|
|
1338
|
+
let cleanupResult: CleanupOrphanFilesResult | null = null
|
|
1339
|
+
const now = Date.now()
|
|
1340
|
+
|
|
1341
|
+
if (
|
|
1342
|
+
this.enableOrphanCleanup &&
|
|
1343
|
+
now - this.lastOrphanCleanup >= this.orphanCleanupIntervalMs
|
|
1344
|
+
) {
|
|
1345
|
+
cleanupResult = await this.manager.cleanupOrphanFiles()
|
|
1346
|
+
this.lastOrphanCleanup = now
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
return {
|
|
1350
|
+
expirationResult,
|
|
1351
|
+
compactionResult,
|
|
1352
|
+
cleanupResult,
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
/**
|
|
1357
|
+
* Get the check interval
|
|
1358
|
+
*/
|
|
1359
|
+
getCheckIntervalMs(): number {
|
|
1360
|
+
return this.checkIntervalMs
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
/**
|
|
1365
|
+
* Create a compaction scheduler
|
|
1366
|
+
*/
|
|
1367
|
+
export function createCompactionScheduler(config: CompactionSchedulerConfig): CompactionScheduler {
|
|
1368
|
+
return new CompactionScheduler(config)
|
|
1369
|
+
}
|