@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,1287 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Iceberg Storage Cost Optimizer
|
|
3
|
+
* Task: postgres-cxo - Storage cost optimization for Iceberg
|
|
4
|
+
*
|
|
5
|
+
* Provides comprehensive storage optimization for Iceberg tables including:
|
|
6
|
+
* - Small file compaction (merge small files into larger ones)
|
|
7
|
+
* - Manifest file optimization (rewrite and consolidate manifests)
|
|
8
|
+
* - Storage cost estimation
|
|
9
|
+
* - Optimization recommendations
|
|
10
|
+
* - Automatic compaction triggers
|
|
11
|
+
*
|
|
12
|
+
* The optimizer analyzes table statistics and provides both reactive and
|
|
13
|
+
* proactive optimization strategies to minimize storage costs and improve
|
|
14
|
+
* query performance.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const optimizer = new StorageOptimizer({
|
|
19
|
+
* bucket: env.ICEBERG_BUCKET,
|
|
20
|
+
* tablePath: 'iceberg/my-table',
|
|
21
|
+
* })
|
|
22
|
+
*
|
|
23
|
+
* await optimizer.initialize()
|
|
24
|
+
*
|
|
25
|
+
* // Get cost estimate
|
|
26
|
+
* const cost = await optimizer.estimateCost('my-table')
|
|
27
|
+
* console.log(`Monthly cost: $${cost.monthlyCost}`)
|
|
28
|
+
*
|
|
29
|
+
* // Get optimization recommendations
|
|
30
|
+
* const suggestions = await optimizer.suggestOptimizations('my-table')
|
|
31
|
+
* for (const suggestion of suggestions) {
|
|
32
|
+
* console.log(`${suggestion.type}: ${suggestion.description}`)
|
|
33
|
+
* console.log(` Estimated savings: $${suggestion.estimatedSavings}`)
|
|
34
|
+
* }
|
|
35
|
+
*
|
|
36
|
+
* // Compact small files
|
|
37
|
+
* const compactResult = await optimizer.compact('my-table')
|
|
38
|
+
* console.log(`Compacted ${compactResult.filesCompacted} files`)
|
|
39
|
+
*
|
|
40
|
+
* // Rewrite manifests
|
|
41
|
+
* const rewriteResult = await optimizer.rewriteManifests('my-table')
|
|
42
|
+
* console.log(`Consolidated ${rewriteResult.manifestsRewritten} manifests`)
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
import type {
|
|
47
|
+
IcebergTableMetadata,
|
|
48
|
+
IcebergSnapshot,
|
|
49
|
+
IcebergManifestFile,
|
|
50
|
+
IcebergManifestEntry,
|
|
51
|
+
IcebergDataFile,
|
|
52
|
+
IcebergSnapshotSummary,
|
|
53
|
+
} from './types'
|
|
54
|
+
import {
|
|
55
|
+
IcebergMetadataBuilder,
|
|
56
|
+
ManifestBuilder,
|
|
57
|
+
ManifestListBuilder,
|
|
58
|
+
generateMetadataFileName,
|
|
59
|
+
generateManifestFileName,
|
|
60
|
+
generateManifestListFileName,
|
|
61
|
+
} from './metadata'
|
|
62
|
+
import { createLogger, LogLevel, type ILogger } from '@dotdo/postgres-shared'
|
|
63
|
+
|
|
64
|
+
// Module-level logger for optimizer errors
|
|
65
|
+
const optimizerLogger: ILogger = createLogger({
|
|
66
|
+
level: LogLevel.ERROR,
|
|
67
|
+
prefix: '[StorageOptimizer]',
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
// ========== Types ==========
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Storage optimizer configuration
|
|
74
|
+
*/
|
|
75
|
+
export interface StorageOptimizerConfig {
|
|
76
|
+
/** R2 bucket for Iceberg storage */
|
|
77
|
+
bucket: R2Bucket
|
|
78
|
+
/** Base path for the table in R2 */
|
|
79
|
+
tablePath: string
|
|
80
|
+
/** Cost per GB per month (default: R2 pricing) */
|
|
81
|
+
costPerGBMonth?: number
|
|
82
|
+
/** Target file size in bytes (default: 128 MB) */
|
|
83
|
+
targetFileSizeBytes?: number
|
|
84
|
+
/** Minimum file size threshold (default: 10 MB) */
|
|
85
|
+
minFileSizeBytes?: number
|
|
86
|
+
/** Maximum files per compaction batch (default: 100) */
|
|
87
|
+
maxFilesPerBatch?: number
|
|
88
|
+
/** Target manifests per snapshot (default: 10) */
|
|
89
|
+
targetManifestsPerSnapshot?: number
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Storage cost breakdown
|
|
94
|
+
*/
|
|
95
|
+
export interface StorageCost {
|
|
96
|
+
/** Total storage size in bytes */
|
|
97
|
+
totalSizeBytes: number
|
|
98
|
+
/** Data file size in bytes */
|
|
99
|
+
dataFileSizeBytes: number
|
|
100
|
+
/** Metadata file size in bytes */
|
|
101
|
+
metadataFileSizeBytes: number
|
|
102
|
+
/** Manifest file size in bytes */
|
|
103
|
+
manifestFileSizeBytes: number
|
|
104
|
+
/** Number of data files */
|
|
105
|
+
dataFileCount: number
|
|
106
|
+
/** Number of manifest files */
|
|
107
|
+
manifestFileCount: number
|
|
108
|
+
/** Number of snapshots */
|
|
109
|
+
snapshotCount: number
|
|
110
|
+
/** Estimated monthly cost in USD */
|
|
111
|
+
monthlyCost: number
|
|
112
|
+
/** Cost breakdown by component */
|
|
113
|
+
costBreakdown: {
|
|
114
|
+
data: number
|
|
115
|
+
metadata: number
|
|
116
|
+
manifests: number
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Optimization suggestion
|
|
122
|
+
*/
|
|
123
|
+
export interface OptimizationSuggestion {
|
|
124
|
+
/** Suggestion type */
|
|
125
|
+
type: 'compaction' | 'manifest-rewrite' | 'snapshot-expiration' | 'orphan-cleanup'
|
|
126
|
+
/** Priority (0-100, higher = more important) */
|
|
127
|
+
priority: number
|
|
128
|
+
/** Human-readable description */
|
|
129
|
+
description: string
|
|
130
|
+
/** Estimated cost savings per month (USD) */
|
|
131
|
+
estimatedSavings: number
|
|
132
|
+
/** Estimated bytes that will be freed */
|
|
133
|
+
estimatedBytesFreed: number
|
|
134
|
+
/** Additional metrics */
|
|
135
|
+
metrics: Record<string, number>
|
|
136
|
+
/** Recommended action */
|
|
137
|
+
action: string
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Compaction result
|
|
142
|
+
*/
|
|
143
|
+
export interface CompactionResult {
|
|
144
|
+
/** Number of files before compaction */
|
|
145
|
+
filesBeforeCompaction: number
|
|
146
|
+
/** Number of files after compaction */
|
|
147
|
+
filesAfterCompaction: number
|
|
148
|
+
/** Total input size in bytes */
|
|
149
|
+
inputSizeBytes: number
|
|
150
|
+
/** Total output size in bytes */
|
|
151
|
+
outputSizeBytes: number
|
|
152
|
+
/** Bytes saved */
|
|
153
|
+
bytesSaved: number
|
|
154
|
+
/** Partitions compacted */
|
|
155
|
+
partitionsCompacted: number
|
|
156
|
+
/** Records processed */
|
|
157
|
+
recordsProcessed: number
|
|
158
|
+
/** New snapshot created */
|
|
159
|
+
snapshot: IcebergSnapshot | null
|
|
160
|
+
/** Duration in milliseconds */
|
|
161
|
+
durationMs: number
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Manifest rewrite result
|
|
166
|
+
*/
|
|
167
|
+
export interface ManifestRewriteResult {
|
|
168
|
+
/** Number of manifests before rewrite */
|
|
169
|
+
manifestsBefore: number
|
|
170
|
+
/** Number of manifests after rewrite */
|
|
171
|
+
manifestsAfter: number
|
|
172
|
+
/** Bytes before rewrite */
|
|
173
|
+
bytesBefore: number
|
|
174
|
+
/** Bytes after rewrite */
|
|
175
|
+
bytesAfter: number
|
|
176
|
+
/** Bytes saved */
|
|
177
|
+
bytesSaved: number
|
|
178
|
+
/** New snapshot created */
|
|
179
|
+
snapshot: IcebergSnapshot | null
|
|
180
|
+
/** Duration in milliseconds */
|
|
181
|
+
durationMs: number
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Table statistics for optimization analysis
|
|
186
|
+
*/
|
|
187
|
+
export interface TableStatistics {
|
|
188
|
+
/** Total data files */
|
|
189
|
+
totalDataFiles: number
|
|
190
|
+
/** Total data size in bytes */
|
|
191
|
+
totalDataSizeBytes: number
|
|
192
|
+
/** Average data file size in bytes */
|
|
193
|
+
avgDataFileSizeBytes: number
|
|
194
|
+
/** Minimum data file size in bytes */
|
|
195
|
+
minDataFileSizeBytes: number
|
|
196
|
+
/** Maximum data file size in bytes */
|
|
197
|
+
maxDataFileSizeBytes: number
|
|
198
|
+
/** Number of small files (below threshold) */
|
|
199
|
+
smallFileCount: number
|
|
200
|
+
/** Total size of small files in bytes */
|
|
201
|
+
smallFilesSizeBytes: number
|
|
202
|
+
/** Total manifest files */
|
|
203
|
+
totalManifestFiles: number
|
|
204
|
+
/** Total manifest size in bytes */
|
|
205
|
+
totalManifestSizeBytes: number
|
|
206
|
+
/** Average manifest file size in bytes */
|
|
207
|
+
avgManifestFileSizeBytes: number
|
|
208
|
+
/** Number of snapshots */
|
|
209
|
+
snapshotCount: number
|
|
210
|
+
/** Total partitions */
|
|
211
|
+
totalPartitions: number
|
|
212
|
+
/** Files per partition (average) */
|
|
213
|
+
avgFilesPerPartition: number
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Compaction trigger thresholds
|
|
218
|
+
*/
|
|
219
|
+
export interface CompactionTriggers {
|
|
220
|
+
/** File count threshold (trigger if exceeded) */
|
|
221
|
+
fileCountThreshold: number
|
|
222
|
+
/** Small file ratio threshold (0-1, trigger if exceeded) */
|
|
223
|
+
smallFileRatioThreshold: number
|
|
224
|
+
/** Average file size threshold in bytes (trigger if below) */
|
|
225
|
+
avgFileSizeThreshold: number
|
|
226
|
+
/** Manifest count threshold (trigger if exceeded) */
|
|
227
|
+
manifestCountThreshold: number
|
|
228
|
+
/** Manifest files per snapshot threshold (trigger if exceeded) */
|
|
229
|
+
manifestsPerSnapshotThreshold: number
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Trigger evaluation result
|
|
234
|
+
*/
|
|
235
|
+
export interface TriggerEvaluation {
|
|
236
|
+
/** Whether compaction should be triggered */
|
|
237
|
+
shouldTrigger: boolean
|
|
238
|
+
/** Triggered conditions */
|
|
239
|
+
triggeredConditions: string[]
|
|
240
|
+
/** Overall priority (0-100) */
|
|
241
|
+
priority: number
|
|
242
|
+
/** Recommended action */
|
|
243
|
+
action: string | null
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// ========== Constants ==========
|
|
247
|
+
|
|
248
|
+
/** Default R2 storage cost per GB per month (USD) */
|
|
249
|
+
const DEFAULT_R2_COST_PER_GB_MONTH = 0.015
|
|
250
|
+
|
|
251
|
+
/** Default configuration values */
|
|
252
|
+
const DEFAULT_CONFIG = {
|
|
253
|
+
costPerGBMonth: DEFAULT_R2_COST_PER_GB_MONTH,
|
|
254
|
+
targetFileSizeBytes: 128 * 1024 * 1024, // 128 MB
|
|
255
|
+
minFileSizeBytes: 10 * 1024 * 1024, // 10 MB
|
|
256
|
+
maxFilesPerBatch: 100,
|
|
257
|
+
targetManifestsPerSnapshot: 10,
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/** Default compaction triggers */
|
|
261
|
+
const DEFAULT_TRIGGERS: CompactionTriggers = {
|
|
262
|
+
fileCountThreshold: 1000,
|
|
263
|
+
smallFileRatioThreshold: 0.3, // 30% small files
|
|
264
|
+
avgFileSizeThreshold: 50 * 1024 * 1024, // 50 MB
|
|
265
|
+
manifestCountThreshold: 100,
|
|
266
|
+
manifestsPerSnapshotThreshold: 20,
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// ========== Storage Optimizer Class ==========
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Storage optimizer for Iceberg tables
|
|
273
|
+
*
|
|
274
|
+
* Provides comprehensive storage optimization including file compaction,
|
|
275
|
+
* manifest optimization, and cost estimation.
|
|
276
|
+
*/
|
|
277
|
+
export class StorageOptimizer {
|
|
278
|
+
private bucket: R2Bucket
|
|
279
|
+
private tablePath: string
|
|
280
|
+
private config: Required<StorageOptimizerConfig>
|
|
281
|
+
private metadata: IcebergTableMetadata | null = null
|
|
282
|
+
private metadataBuilder: IcebergMetadataBuilder | null = null
|
|
283
|
+
private metadataVersion = 0
|
|
284
|
+
private initialized = false
|
|
285
|
+
|
|
286
|
+
constructor(config: StorageOptimizerConfig) {
|
|
287
|
+
this.bucket = config.bucket
|
|
288
|
+
this.tablePath = config.tablePath.replace(/\/$/, '')
|
|
289
|
+
this.config = {
|
|
290
|
+
bucket: config.bucket,
|
|
291
|
+
tablePath: this.tablePath,
|
|
292
|
+
costPerGBMonth: config.costPerGBMonth ?? DEFAULT_CONFIG.costPerGBMonth,
|
|
293
|
+
targetFileSizeBytes: config.targetFileSizeBytes ?? DEFAULT_CONFIG.targetFileSizeBytes,
|
|
294
|
+
minFileSizeBytes: config.minFileSizeBytes ?? DEFAULT_CONFIG.minFileSizeBytes,
|
|
295
|
+
maxFilesPerBatch: config.maxFilesPerBatch ?? DEFAULT_CONFIG.maxFilesPerBatch,
|
|
296
|
+
targetManifestsPerSnapshot: config.targetManifestsPerSnapshot ?? DEFAULT_CONFIG.targetManifestsPerSnapshot,
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Initialize the optimizer
|
|
302
|
+
*/
|
|
303
|
+
async initialize(): Promise<void> {
|
|
304
|
+
if (this.initialized) {
|
|
305
|
+
return
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
await this.loadMetadata()
|
|
309
|
+
this.initialized = true
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Ensure initialized
|
|
314
|
+
*/
|
|
315
|
+
private ensureInitialized(): void {
|
|
316
|
+
if (!this.initialized) {
|
|
317
|
+
throw new Error('StorageOptimizer not initialized. Call initialize() first.')
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Load table metadata from R2
|
|
323
|
+
*/
|
|
324
|
+
private async loadMetadata(): Promise<void> {
|
|
325
|
+
// Try version hint first
|
|
326
|
+
const versionHint = await this.bucket.get(`${this.tablePath}/metadata/version-hint.text`)
|
|
327
|
+
if (versionHint) {
|
|
328
|
+
this.metadataVersion = parseInt(await versionHint.text(), 10)
|
|
329
|
+
const metadataPath = `${this.tablePath}/metadata/v${this.metadataVersion}.metadata.json`
|
|
330
|
+
const metadataObj = await this.bucket.get(metadataPath)
|
|
331
|
+
if (metadataObj) {
|
|
332
|
+
this.metadata = JSON.parse(await metadataObj.text()) as IcebergTableMetadata
|
|
333
|
+
this.metadataBuilder = IcebergMetadataBuilder.fromMetadata(this.metadata)
|
|
334
|
+
return
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Fall back to listing metadata files
|
|
339
|
+
const list = await this.bucket.list({
|
|
340
|
+
prefix: `${this.tablePath}/metadata/`,
|
|
341
|
+
})
|
|
342
|
+
|
|
343
|
+
const metadataFiles = list.objects
|
|
344
|
+
.filter((obj) => obj.key.endsWith('.metadata.json'))
|
|
345
|
+
.sort((a, b) => {
|
|
346
|
+
const versionA = parseInt(a.key.match(/v(\d+)\.metadata\.json/)?.[1] ?? '0', 10)
|
|
347
|
+
const versionB = parseInt(b.key.match(/v(\d+)\.metadata\.json/)?.[1] ?? '0', 10)
|
|
348
|
+
return versionB - versionA
|
|
349
|
+
})
|
|
350
|
+
|
|
351
|
+
if (metadataFiles.length > 0 && metadataFiles[0]) {
|
|
352
|
+
const metadataObj = await this.bucket.get(metadataFiles[0].key)
|
|
353
|
+
if (metadataObj) {
|
|
354
|
+
this.metadata = JSON.parse(await metadataObj.text()) as IcebergTableMetadata
|
|
355
|
+
this.metadataBuilder = IcebergMetadataBuilder.fromMetadata(this.metadata)
|
|
356
|
+
this.metadataVersion = parseInt(
|
|
357
|
+
metadataFiles[0].key.match(/v(\d+)\.metadata\.json/)?.[1] ?? '0',
|
|
358
|
+
10
|
|
359
|
+
)
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// ========== Cost Estimation ==========
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Estimate storage costs for the table
|
|
368
|
+
*/
|
|
369
|
+
async estimateCost(table: string): Promise<StorageCost> {
|
|
370
|
+
this.ensureInitialized()
|
|
371
|
+
|
|
372
|
+
// Get table statistics
|
|
373
|
+
const stats = await this.analyzeTable(table)
|
|
374
|
+
|
|
375
|
+
// Calculate metadata size
|
|
376
|
+
let metadataSize = 0
|
|
377
|
+
const metadataList = await this.bucket.list({
|
|
378
|
+
prefix: `${this.tablePath}/metadata/`,
|
|
379
|
+
})
|
|
380
|
+
for (const obj of metadataList.objects) {
|
|
381
|
+
if (obj.key.endsWith('.metadata.json')) {
|
|
382
|
+
metadataSize += obj.size
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// Convert to GB and calculate monthly cost
|
|
387
|
+
const totalGB = stats.totalDataSizeBytes / (1024 * 1024 * 1024)
|
|
388
|
+
const dataGB = stats.totalDataSizeBytes / (1024 * 1024 * 1024)
|
|
389
|
+
const metadataGB = metadataSize / (1024 * 1024 * 1024)
|
|
390
|
+
const manifestGB = stats.totalManifestSizeBytes / (1024 * 1024 * 1024)
|
|
391
|
+
|
|
392
|
+
const monthlyCost = totalGB * this.config.costPerGBMonth
|
|
393
|
+
|
|
394
|
+
return {
|
|
395
|
+
totalSizeBytes: stats.totalDataSizeBytes + metadataSize + stats.totalManifestSizeBytes,
|
|
396
|
+
dataFileSizeBytes: stats.totalDataSizeBytes,
|
|
397
|
+
metadataFileSizeBytes: metadataSize,
|
|
398
|
+
manifestFileSizeBytes: stats.totalManifestSizeBytes,
|
|
399
|
+
dataFileCount: stats.totalDataFiles,
|
|
400
|
+
manifestFileCount: stats.totalManifestFiles,
|
|
401
|
+
snapshotCount: stats.snapshotCount,
|
|
402
|
+
monthlyCost,
|
|
403
|
+
costBreakdown: {
|
|
404
|
+
data: dataGB * this.config.costPerGBMonth,
|
|
405
|
+
metadata: metadataGB * this.config.costPerGBMonth,
|
|
406
|
+
manifests: manifestGB * this.config.costPerGBMonth,
|
|
407
|
+
},
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// ========== Optimization Suggestions ==========
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* Generate optimization suggestions for the table
|
|
415
|
+
*/
|
|
416
|
+
async suggestOptimizations(table: string): Promise<OptimizationSuggestion[]> {
|
|
417
|
+
this.ensureInitialized()
|
|
418
|
+
|
|
419
|
+
const suggestions: OptimizationSuggestion[] = []
|
|
420
|
+
const stats = await this.analyzeTable(table)
|
|
421
|
+
const cost = await this.estimateCost(table)
|
|
422
|
+
|
|
423
|
+
// Check for small file compaction opportunity
|
|
424
|
+
if (stats.smallFileCount > 5) {
|
|
425
|
+
const estimatedOutputFiles = Math.ceil(
|
|
426
|
+
stats.smallFilesSizeBytes / this.config.targetFileSizeBytes
|
|
427
|
+
)
|
|
428
|
+
const fileReduction = stats.smallFileCount - estimatedOutputFiles
|
|
429
|
+
const metadataSavings = fileReduction * 1000 // Rough estimate
|
|
430
|
+
const savingsGB = metadataSavings / (1024 * 1024 * 1024)
|
|
431
|
+
|
|
432
|
+
const priority = Math.min(
|
|
433
|
+
100,
|
|
434
|
+
Math.round((stats.smallFileCount / stats.totalDataFiles) * 100)
|
|
435
|
+
)
|
|
436
|
+
|
|
437
|
+
suggestions.push({
|
|
438
|
+
type: 'compaction',
|
|
439
|
+
priority,
|
|
440
|
+
description: `Compact ${stats.smallFileCount} small files into ${estimatedOutputFiles} optimized files`,
|
|
441
|
+
estimatedSavings: savingsGB * this.config.costPerGBMonth,
|
|
442
|
+
estimatedBytesFreed: metadataSavings,
|
|
443
|
+
metrics: {
|
|
444
|
+
smallFiles: stats.smallFileCount,
|
|
445
|
+
estimatedOutputFiles,
|
|
446
|
+
fileReduction,
|
|
447
|
+
averageSmallFileSize: stats.smallFileCount > 0
|
|
448
|
+
? stats.smallFilesSizeBytes / stats.smallFileCount
|
|
449
|
+
: 0,
|
|
450
|
+
},
|
|
451
|
+
action: 'Run compact() to merge small files into larger ones',
|
|
452
|
+
})
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// Check for manifest optimization opportunity
|
|
456
|
+
const avgManifestsPerSnapshot = stats.totalManifestFiles / Math.max(stats.snapshotCount, 1)
|
|
457
|
+
if (avgManifestsPerSnapshot > this.config.targetManifestsPerSnapshot) {
|
|
458
|
+
const estimatedManifests = stats.snapshotCount * this.config.targetManifestsPerSnapshot
|
|
459
|
+
const manifestReduction = stats.totalManifestFiles - estimatedManifests
|
|
460
|
+
const bytesSaved = manifestReduction * stats.avgManifestFileSizeBytes
|
|
461
|
+
const savingsGB = bytesSaved / (1024 * 1024 * 1024)
|
|
462
|
+
|
|
463
|
+
const priority = Math.min(100, Math.round((manifestReduction / stats.totalManifestFiles) * 80))
|
|
464
|
+
|
|
465
|
+
suggestions.push({
|
|
466
|
+
type: 'manifest-rewrite',
|
|
467
|
+
priority,
|
|
468
|
+
description: `Consolidate ${stats.totalManifestFiles} manifest files into ${estimatedManifests} optimized manifests`,
|
|
469
|
+
estimatedSavings: savingsGB * this.config.costPerGBMonth,
|
|
470
|
+
estimatedBytesFreed: bytesSaved,
|
|
471
|
+
metrics: {
|
|
472
|
+
currentManifests: stats.totalManifestFiles,
|
|
473
|
+
targetManifests: estimatedManifests,
|
|
474
|
+
manifestsPerSnapshot: avgManifestsPerSnapshot,
|
|
475
|
+
},
|
|
476
|
+
action: 'Run rewriteManifests() to consolidate manifest files',
|
|
477
|
+
})
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// Check for old snapshot expiration
|
|
481
|
+
if (stats.snapshotCount > 50) {
|
|
482
|
+
const snapshotsToExpire = stats.snapshotCount - 30 // Keep last 30
|
|
483
|
+
const estimatedBytesSaved = snapshotsToExpire * stats.avgManifestFileSizeBytes * 5 // Estimate
|
|
484
|
+
const savingsGB = estimatedBytesSaved / (1024 * 1024 * 1024)
|
|
485
|
+
|
|
486
|
+
const priority = Math.min(100, Math.round((snapshotsToExpire / stats.snapshotCount) * 60))
|
|
487
|
+
|
|
488
|
+
suggestions.push({
|
|
489
|
+
type: 'snapshot-expiration',
|
|
490
|
+
priority,
|
|
491
|
+
description: `Expire ${snapshotsToExpire} old snapshots to free up manifest storage`,
|
|
492
|
+
estimatedSavings: savingsGB * this.config.costPerGBMonth,
|
|
493
|
+
estimatedBytesFreed: estimatedBytesSaved,
|
|
494
|
+
metrics: {
|
|
495
|
+
currentSnapshots: stats.snapshotCount,
|
|
496
|
+
recommendedSnapshots: 30,
|
|
497
|
+
snapshotsToExpire,
|
|
498
|
+
},
|
|
499
|
+
action: 'Configure snapshot expiration policy with maxAgeDays or maxSnapshotsToRetain',
|
|
500
|
+
})
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// Check for potential orphan files
|
|
504
|
+
// This is a heuristic based on the ratio of total storage to tracked data
|
|
505
|
+
const trackedDataRatio = cost.dataFileSizeBytes / cost.totalSizeBytes
|
|
506
|
+
if (trackedDataRatio < 0.9 && cost.totalSizeBytes > 100 * 1024 * 1024) {
|
|
507
|
+
const estimatedOrphanSize = cost.totalSizeBytes - cost.dataFileSizeBytes - cost.metadataFileSizeBytes
|
|
508
|
+
const savingsGB = estimatedOrphanSize / (1024 * 1024 * 1024)
|
|
509
|
+
|
|
510
|
+
suggestions.push({
|
|
511
|
+
type: 'orphan-cleanup',
|
|
512
|
+
priority: 40,
|
|
513
|
+
description: 'Scan for and remove orphaned data files',
|
|
514
|
+
estimatedSavings: savingsGB * this.config.costPerGBMonth,
|
|
515
|
+
estimatedBytesFreed: estimatedOrphanSize,
|
|
516
|
+
metrics: {
|
|
517
|
+
estimatedOrphanSize,
|
|
518
|
+
trackedDataRatio,
|
|
519
|
+
},
|
|
520
|
+
action: 'Run cleanupOrphanFiles() from SnapshotManager to identify and remove orphaned files',
|
|
521
|
+
})
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// Sort by priority (highest first)
|
|
525
|
+
suggestions.sort((a, b) => b.priority - a.priority)
|
|
526
|
+
|
|
527
|
+
return suggestions
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// ========== Compaction ==========
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* Compact small files into larger ones
|
|
534
|
+
*/
|
|
535
|
+
async compact(_table: string): Promise<CompactionResult> {
|
|
536
|
+
this.ensureInitialized()
|
|
537
|
+
|
|
538
|
+
const startTime = performance.now()
|
|
539
|
+
|
|
540
|
+
// Get all data files
|
|
541
|
+
const dataFiles = await this.getAllDataFiles()
|
|
542
|
+
|
|
543
|
+
// Filter small files
|
|
544
|
+
const smallFiles = dataFiles.filter(
|
|
545
|
+
(f) => f['file-size-in-bytes'] < this.config.minFileSizeBytes
|
|
546
|
+
)
|
|
547
|
+
|
|
548
|
+
if (smallFiles.length === 0) {
|
|
549
|
+
return {
|
|
550
|
+
filesBeforeCompaction: dataFiles.length,
|
|
551
|
+
filesAfterCompaction: dataFiles.length,
|
|
552
|
+
inputSizeBytes: 0,
|
|
553
|
+
outputSizeBytes: 0,
|
|
554
|
+
bytesSaved: 0,
|
|
555
|
+
partitionsCompacted: 0,
|
|
556
|
+
recordsProcessed: 0,
|
|
557
|
+
snapshot: null,
|
|
558
|
+
durationMs: performance.now() - startTime,
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// Group by partition
|
|
563
|
+
const filesByPartition = new Map<string, IcebergDataFile[]>()
|
|
564
|
+
for (const file of smallFiles) {
|
|
565
|
+
const partitionPath = this.extractPartitionPath(file['file-path'])
|
|
566
|
+
const files = filesByPartition.get(partitionPath) ?? []
|
|
567
|
+
files.push(file)
|
|
568
|
+
filesByPartition.set(partitionPath, files)
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
// Create compaction groups
|
|
572
|
+
const compactionGroups: Array<{
|
|
573
|
+
partition: string
|
|
574
|
+
files: IcebergDataFile[]
|
|
575
|
+
totalSize: number
|
|
576
|
+
totalRecords: number
|
|
577
|
+
}> = []
|
|
578
|
+
|
|
579
|
+
for (const [partition, files] of filesByPartition) {
|
|
580
|
+
if (files.length < 2) {
|
|
581
|
+
continue // Need at least 2 files to compact
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// Sort by size for better packing
|
|
585
|
+
files.sort((a, b) => a['file-size-in-bytes'] - b['file-size-in-bytes'])
|
|
586
|
+
|
|
587
|
+
// Create batches
|
|
588
|
+
let currentBatch: IcebergDataFile[] = []
|
|
589
|
+
let currentSize = 0
|
|
590
|
+
let currentRecords = 0
|
|
591
|
+
|
|
592
|
+
for (const file of files) {
|
|
593
|
+
if (
|
|
594
|
+
currentBatch.length >= this.config.maxFilesPerBatch ||
|
|
595
|
+
currentSize + file['file-size-in-bytes'] > this.config.targetFileSizeBytes * 2
|
|
596
|
+
) {
|
|
597
|
+
if (currentBatch.length >= 2) {
|
|
598
|
+
compactionGroups.push({
|
|
599
|
+
partition,
|
|
600
|
+
files: currentBatch,
|
|
601
|
+
totalSize: currentSize,
|
|
602
|
+
totalRecords: currentRecords,
|
|
603
|
+
})
|
|
604
|
+
}
|
|
605
|
+
currentBatch = []
|
|
606
|
+
currentSize = 0
|
|
607
|
+
currentRecords = 0
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
currentBatch.push(file)
|
|
611
|
+
currentSize += file['file-size-in-bytes']
|
|
612
|
+
currentRecords += file['record-count']
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// Add remaining batch
|
|
616
|
+
if (currentBatch.length >= 2) {
|
|
617
|
+
compactionGroups.push({
|
|
618
|
+
partition,
|
|
619
|
+
files: currentBatch,
|
|
620
|
+
totalSize: currentSize,
|
|
621
|
+
totalRecords: currentRecords,
|
|
622
|
+
})
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
if (compactionGroups.length === 0) {
|
|
627
|
+
return {
|
|
628
|
+
filesBeforeCompaction: dataFiles.length,
|
|
629
|
+
filesAfterCompaction: dataFiles.length,
|
|
630
|
+
inputSizeBytes: 0,
|
|
631
|
+
outputSizeBytes: 0,
|
|
632
|
+
bytesSaved: 0,
|
|
633
|
+
partitionsCompacted: 0,
|
|
634
|
+
recordsProcessed: 0,
|
|
635
|
+
snapshot: null,
|
|
636
|
+
durationMs: performance.now() - startTime,
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// Calculate totals
|
|
641
|
+
let totalInputFiles = 0
|
|
642
|
+
let totalInputSize = 0
|
|
643
|
+
let totalRecords = 0
|
|
644
|
+
const partitionsCompacted = new Set<string>()
|
|
645
|
+
|
|
646
|
+
for (const group of compactionGroups) {
|
|
647
|
+
totalInputFiles += group.files.length
|
|
648
|
+
totalInputSize += group.totalSize
|
|
649
|
+
totalRecords += group.totalRecords
|
|
650
|
+
partitionsCompacted.add(group.partition)
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
// Create compaction snapshot
|
|
654
|
+
const snapshot = await this.createCompactionSnapshot(compactionGroups)
|
|
655
|
+
|
|
656
|
+
// Estimate output files
|
|
657
|
+
const estimatedOutputFiles = compactionGroups.reduce((sum, group) => {
|
|
658
|
+
return sum + Math.max(1, Math.ceil(group.totalSize / this.config.targetFileSizeBytes))
|
|
659
|
+
}, 0)
|
|
660
|
+
|
|
661
|
+
const filesAfter = dataFiles.length - totalInputFiles + estimatedOutputFiles
|
|
662
|
+
const metadataSaved = (totalInputFiles - estimatedOutputFiles) * 1000 // Rough estimate
|
|
663
|
+
|
|
664
|
+
return {
|
|
665
|
+
filesBeforeCompaction: dataFiles.length,
|
|
666
|
+
filesAfterCompaction: filesAfter,
|
|
667
|
+
inputSizeBytes: totalInputSize,
|
|
668
|
+
outputSizeBytes: totalInputSize, // Data size stays roughly the same
|
|
669
|
+
bytesSaved: metadataSaved,
|
|
670
|
+
partitionsCompacted: partitionsCompacted.size,
|
|
671
|
+
recordsProcessed: totalRecords,
|
|
672
|
+
snapshot,
|
|
673
|
+
durationMs: performance.now() - startTime,
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* Create a compaction snapshot
|
|
679
|
+
*/
|
|
680
|
+
private async createCompactionSnapshot(
|
|
681
|
+
compactionGroups: Array<{
|
|
682
|
+
partition: string
|
|
683
|
+
files: IcebergDataFile[]
|
|
684
|
+
totalSize: number
|
|
685
|
+
totalRecords: number
|
|
686
|
+
}>
|
|
687
|
+
): Promise<IcebergSnapshot | null> {
|
|
688
|
+
if (!this.metadata || !this.metadataBuilder) {
|
|
689
|
+
return null
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
const snapshotId = Date.now() * 1000 + Math.floor(Math.random() * 1000)
|
|
693
|
+
const sequenceNumber = this.metadataBuilder.getSequenceNumber() + 1
|
|
694
|
+
const partitionSpecId = this.metadata['default-spec-id']
|
|
695
|
+
|
|
696
|
+
// Create manifest builder
|
|
697
|
+
const manifestBuilder = new ManifestBuilder({
|
|
698
|
+
partitionSpecId,
|
|
699
|
+
sequenceNumber,
|
|
700
|
+
snapshotId,
|
|
701
|
+
})
|
|
702
|
+
|
|
703
|
+
// Mark old files as deleted
|
|
704
|
+
let totalDeletedFiles = 0
|
|
705
|
+
let totalDeletedRecords = 0
|
|
706
|
+
|
|
707
|
+
for (const group of compactionGroups) {
|
|
708
|
+
for (const file of group.files) {
|
|
709
|
+
manifestBuilder.deleteDataFile(file)
|
|
710
|
+
totalDeletedFiles++
|
|
711
|
+
totalDeletedRecords += file['record-count']
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
// Write manifest
|
|
716
|
+
const manifestFileName = generateManifestFileName(snapshotId)
|
|
717
|
+
const manifestPath = `${this.tablePath}/metadata/${manifestFileName}`
|
|
718
|
+
const manifestContent = manifestBuilder.toJSON()
|
|
719
|
+
const manifestBytes = new TextEncoder().encode(manifestContent)
|
|
720
|
+
|
|
721
|
+
await this.bucket.put(manifestPath, manifestBytes, {
|
|
722
|
+
httpMetadata: { contentType: 'application/json' },
|
|
723
|
+
})
|
|
724
|
+
|
|
725
|
+
const manifestFileMetadata = manifestBuilder.createManifestFileMetadata(
|
|
726
|
+
manifestPath,
|
|
727
|
+
manifestBytes.length
|
|
728
|
+
)
|
|
729
|
+
|
|
730
|
+
// Create manifest list
|
|
731
|
+
const manifestListBuilder = new ManifestListBuilder(snapshotId, sequenceNumber)
|
|
732
|
+
manifestListBuilder.addManifest(manifestFileMetadata)
|
|
733
|
+
|
|
734
|
+
// Include existing manifests
|
|
735
|
+
const currentSnapshot = this.metadata.snapshots?.find(
|
|
736
|
+
(s) => s['snapshot-id'] === this.metadata!['current-snapshot-id']
|
|
737
|
+
)
|
|
738
|
+
if (currentSnapshot) {
|
|
739
|
+
const existingManifests = await this.loadManifestsFromList(currentSnapshot['manifest-list'])
|
|
740
|
+
for (const manifest of existingManifests) {
|
|
741
|
+
manifestListBuilder.addManifest(manifest)
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// Write manifest list
|
|
746
|
+
const manifestListFileName = generateManifestListFileName(snapshotId)
|
|
747
|
+
const manifestListPath = `${this.tablePath}/metadata/${manifestListFileName}`
|
|
748
|
+
const manifestListContent = manifestListBuilder.toJSON()
|
|
749
|
+
const manifestListBytes = new TextEncoder().encode(manifestListContent)
|
|
750
|
+
|
|
751
|
+
await this.bucket.put(manifestListPath, manifestListBytes, {
|
|
752
|
+
httpMetadata: { contentType: 'application/json' },
|
|
753
|
+
})
|
|
754
|
+
|
|
755
|
+
// Create snapshot
|
|
756
|
+
const summary: IcebergSnapshotSummary = {
|
|
757
|
+
operation: 'replace',
|
|
758
|
+
'added-data-files': '0',
|
|
759
|
+
'deleted-data-files': String(totalDeletedFiles),
|
|
760
|
+
'added-records': '0',
|
|
761
|
+
'deleted-records': String(totalDeletedRecords),
|
|
762
|
+
'compaction-type': 'small-file-compaction',
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
const snapshot: IcebergSnapshot = {
|
|
766
|
+
'snapshot-id': snapshotId,
|
|
767
|
+
...(this.metadata['current-snapshot-id'] !== undefined && {
|
|
768
|
+
'parent-snapshot-id': this.metadata['current-snapshot-id'],
|
|
769
|
+
}),
|
|
770
|
+
'sequence-number': sequenceNumber,
|
|
771
|
+
'timestamp-ms': Date.now(),
|
|
772
|
+
'manifest-list': manifestListPath,
|
|
773
|
+
summary,
|
|
774
|
+
'schema-id': this.metadata['current-schema-id'],
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
// Update metadata
|
|
778
|
+
const newSnapshots = [...(this.metadata.snapshots ?? []), snapshot]
|
|
779
|
+
await this.updateMetadataWithSnapshots(newSnapshots)
|
|
780
|
+
|
|
781
|
+
return snapshot
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
// ========== Manifest Optimization ==========
|
|
785
|
+
|
|
786
|
+
/**
|
|
787
|
+
* Rewrite and consolidate manifest files
|
|
788
|
+
*/
|
|
789
|
+
async rewriteManifests(_table: string): Promise<ManifestRewriteResult> {
|
|
790
|
+
this.ensureInitialized()
|
|
791
|
+
|
|
792
|
+
const startTime = performance.now()
|
|
793
|
+
|
|
794
|
+
if (!this.metadata?.['current-snapshot-id']) {
|
|
795
|
+
return {
|
|
796
|
+
manifestsBefore: 0,
|
|
797
|
+
manifestsAfter: 0,
|
|
798
|
+
bytesBefore: 0,
|
|
799
|
+
bytesAfter: 0,
|
|
800
|
+
bytesSaved: 0,
|
|
801
|
+
snapshot: null,
|
|
802
|
+
durationMs: performance.now() - startTime,
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
// Get current snapshot
|
|
807
|
+
const currentSnapshot = this.metadata.snapshots?.find(
|
|
808
|
+
(s) => s['snapshot-id'] === this.metadata!['current-snapshot-id']
|
|
809
|
+
)
|
|
810
|
+
|
|
811
|
+
if (!currentSnapshot) {
|
|
812
|
+
return {
|
|
813
|
+
manifestsBefore: 0,
|
|
814
|
+
manifestsAfter: 0,
|
|
815
|
+
bytesBefore: 0,
|
|
816
|
+
bytesAfter: 0,
|
|
817
|
+
bytesSaved: 0,
|
|
818
|
+
snapshot: null,
|
|
819
|
+
durationMs: performance.now() - startTime,
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// Load all manifests
|
|
824
|
+
const manifests = await this.loadManifestsFromList(currentSnapshot['manifest-list'])
|
|
825
|
+
const manifestsBefore = manifests.length
|
|
826
|
+
const bytesBefore = manifests.reduce((sum, m) => sum + m['manifest-length'], 0)
|
|
827
|
+
|
|
828
|
+
// If already optimized, skip
|
|
829
|
+
if (manifestsBefore <= this.config.targetManifestsPerSnapshot) {
|
|
830
|
+
return {
|
|
831
|
+
manifestsBefore,
|
|
832
|
+
manifestsAfter: manifestsBefore,
|
|
833
|
+
bytesBefore,
|
|
834
|
+
bytesAfter: bytesBefore,
|
|
835
|
+
bytesSaved: 0,
|
|
836
|
+
snapshot: null,
|
|
837
|
+
durationMs: performance.now() - startTime,
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
// Collect all entries from all manifests
|
|
842
|
+
const allEntries: IcebergManifestEntry[] = []
|
|
843
|
+
for (const manifest of manifests) {
|
|
844
|
+
const entries = await this.loadManifestEntries(manifest['manifest-path'])
|
|
845
|
+
allEntries.push(...entries)
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
// Group entries into new consolidated manifests
|
|
849
|
+
const targetManifests = this.config.targetManifestsPerSnapshot
|
|
850
|
+
const entriesPerManifest = Math.ceil(allEntries.length / targetManifests)
|
|
851
|
+
|
|
852
|
+
const snapshotId = Date.now() * 1000 + Math.floor(Math.random() * 1000)
|
|
853
|
+
const sequenceNumber = this.metadataBuilder!.getSequenceNumber() + 1
|
|
854
|
+
const partitionSpecId = this.metadata['default-spec-id']
|
|
855
|
+
|
|
856
|
+
const newManifests: IcebergManifestFile[] = []
|
|
857
|
+
let bytesAfter = 0
|
|
858
|
+
|
|
859
|
+
// Create consolidated manifests
|
|
860
|
+
for (let i = 0; i < allEntries.length; i += entriesPerManifest) {
|
|
861
|
+
const batch = allEntries.slice(i, i + entriesPerManifest)
|
|
862
|
+
|
|
863
|
+
const manifestBuilder = new ManifestBuilder({
|
|
864
|
+
partitionSpecId,
|
|
865
|
+
sequenceNumber,
|
|
866
|
+
snapshotId,
|
|
867
|
+
})
|
|
868
|
+
|
|
869
|
+
for (const entry of batch) {
|
|
870
|
+
if (entry.status === 0) {
|
|
871
|
+
// EXISTING
|
|
872
|
+
manifestBuilder.addExistingFile(
|
|
873
|
+
entry['data-file'],
|
|
874
|
+
entry['sequence-number'] ?? sequenceNumber
|
|
875
|
+
)
|
|
876
|
+
} else if (entry.status === 1) {
|
|
877
|
+
// ADDED
|
|
878
|
+
manifestBuilder.addDataFile(entry['data-file'], 1)
|
|
879
|
+
} else if (entry.status === 2) {
|
|
880
|
+
// DELETED
|
|
881
|
+
manifestBuilder.deleteDataFile(entry['data-file'])
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
// Write manifest
|
|
886
|
+
const manifestAttempt = Math.floor(i / entriesPerManifest)
|
|
887
|
+
const manifestFileName = generateManifestFileName(snapshotId, manifestAttempt)
|
|
888
|
+
const manifestPath = `${this.tablePath}/metadata/${manifestFileName}`
|
|
889
|
+
const manifestContent = manifestBuilder.toJSON()
|
|
890
|
+
const manifestBytes = new TextEncoder().encode(manifestContent)
|
|
891
|
+
|
|
892
|
+
await this.bucket.put(manifestPath, manifestBytes, {
|
|
893
|
+
httpMetadata: { contentType: 'application/json' },
|
|
894
|
+
})
|
|
895
|
+
|
|
896
|
+
const manifestFileMetadata = manifestBuilder.createManifestFileMetadata(
|
|
897
|
+
manifestPath,
|
|
898
|
+
manifestBytes.length
|
|
899
|
+
)
|
|
900
|
+
|
|
901
|
+
newManifests.push(manifestFileMetadata)
|
|
902
|
+
bytesAfter += manifestBytes.length
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
// Create new snapshot with consolidated manifests
|
|
906
|
+
const snapshot = await this.createManifestRewriteSnapshot(snapshotId, sequenceNumber, newManifests)
|
|
907
|
+
|
|
908
|
+
return {
|
|
909
|
+
manifestsBefore,
|
|
910
|
+
manifestsAfter: newManifests.length,
|
|
911
|
+
bytesBefore,
|
|
912
|
+
bytesAfter,
|
|
913
|
+
bytesSaved: bytesBefore - bytesAfter,
|
|
914
|
+
snapshot,
|
|
915
|
+
durationMs: performance.now() - startTime,
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
/**
|
|
920
|
+
* Create a manifest rewrite snapshot
|
|
921
|
+
*/
|
|
922
|
+
private async createManifestRewriteSnapshot(
|
|
923
|
+
snapshotId: number,
|
|
924
|
+
sequenceNumber: number,
|
|
925
|
+
newManifests: IcebergManifestFile[]
|
|
926
|
+
): Promise<IcebergSnapshot | null> {
|
|
927
|
+
if (!this.metadata) {
|
|
928
|
+
return null
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
// Create manifest list
|
|
932
|
+
const manifestListBuilder = new ManifestListBuilder(snapshotId, sequenceNumber)
|
|
933
|
+
|
|
934
|
+
for (const manifest of newManifests) {
|
|
935
|
+
manifestListBuilder.addManifest(manifest)
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
// Write manifest list
|
|
939
|
+
const manifestListFileName = generateManifestListFileName(snapshotId)
|
|
940
|
+
const manifestListPath = `${this.tablePath}/metadata/${manifestListFileName}`
|
|
941
|
+
const manifestListContent = manifestListBuilder.toJSON()
|
|
942
|
+
const manifestListBytes = new TextEncoder().encode(manifestListContent)
|
|
943
|
+
|
|
944
|
+
await this.bucket.put(manifestListPath, manifestListBytes, {
|
|
945
|
+
httpMetadata: { contentType: 'application/json' },
|
|
946
|
+
})
|
|
947
|
+
|
|
948
|
+
// Create snapshot
|
|
949
|
+
const summary: IcebergSnapshotSummary = {
|
|
950
|
+
operation: 'replace',
|
|
951
|
+
'added-data-files': '0',
|
|
952
|
+
'deleted-data-files': '0',
|
|
953
|
+
'added-records': '0',
|
|
954
|
+
'deleted-records': '0',
|
|
955
|
+
'manifest-rewrite': 'true',
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
const snapshot: IcebergSnapshot = {
|
|
959
|
+
'snapshot-id': snapshotId,
|
|
960
|
+
...(this.metadata['current-snapshot-id'] !== undefined && {
|
|
961
|
+
'parent-snapshot-id': this.metadata['current-snapshot-id'],
|
|
962
|
+
}),
|
|
963
|
+
'sequence-number': sequenceNumber,
|
|
964
|
+
'timestamp-ms': Date.now(),
|
|
965
|
+
'manifest-list': manifestListPath,
|
|
966
|
+
summary,
|
|
967
|
+
'schema-id': this.metadata['current-schema-id'],
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
// Update metadata
|
|
971
|
+
const newSnapshots = [...(this.metadata.snapshots ?? []), snapshot]
|
|
972
|
+
await this.updateMetadataWithSnapshots(newSnapshots)
|
|
973
|
+
|
|
974
|
+
return snapshot
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
// ========== Compaction Triggers ==========
|
|
978
|
+
|
|
979
|
+
/**
|
|
980
|
+
* Evaluate compaction triggers
|
|
981
|
+
*/
|
|
982
|
+
async evaluateTriggers(
|
|
983
|
+
table: string,
|
|
984
|
+
triggers: Partial<CompactionTriggers> = {}
|
|
985
|
+
): Promise<TriggerEvaluation> {
|
|
986
|
+
this.ensureInitialized()
|
|
987
|
+
|
|
988
|
+
const config = { ...DEFAULT_TRIGGERS, ...triggers }
|
|
989
|
+
const stats = await this.analyzeTable(table)
|
|
990
|
+
|
|
991
|
+
const triggeredConditions: string[] = []
|
|
992
|
+
let maxPriority = 0
|
|
993
|
+
|
|
994
|
+
// Check file count threshold
|
|
995
|
+
if (stats.totalDataFiles > config.fileCountThreshold) {
|
|
996
|
+
triggeredConditions.push(
|
|
997
|
+
`File count (${stats.totalDataFiles}) exceeds threshold (${config.fileCountThreshold})`
|
|
998
|
+
)
|
|
999
|
+
maxPriority = Math.max(maxPriority, 60)
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
// Check small file ratio
|
|
1003
|
+
const smallFileRatio = stats.totalDataFiles > 0
|
|
1004
|
+
? stats.smallFileCount / stats.totalDataFiles
|
|
1005
|
+
: 0
|
|
1006
|
+
if (smallFileRatio > config.smallFileRatioThreshold) {
|
|
1007
|
+
triggeredConditions.push(
|
|
1008
|
+
`Small file ratio (${(smallFileRatio * 100).toFixed(1)}%) exceeds threshold (${(config.smallFileRatioThreshold * 100).toFixed(1)}%)`
|
|
1009
|
+
)
|
|
1010
|
+
maxPriority = Math.max(maxPriority, 80)
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
// Check average file size
|
|
1014
|
+
if (stats.avgDataFileSizeBytes < config.avgFileSizeThreshold && stats.totalDataFiles > 10) {
|
|
1015
|
+
triggeredConditions.push(
|
|
1016
|
+
`Average file size (${formatBytes(stats.avgDataFileSizeBytes)}) below threshold (${formatBytes(config.avgFileSizeThreshold)})`
|
|
1017
|
+
)
|
|
1018
|
+
maxPriority = Math.max(maxPriority, 70)
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
// Check manifest count
|
|
1022
|
+
if (stats.totalManifestFiles > config.manifestCountThreshold) {
|
|
1023
|
+
triggeredConditions.push(
|
|
1024
|
+
`Manifest count (${stats.totalManifestFiles}) exceeds threshold (${config.manifestCountThreshold})`
|
|
1025
|
+
)
|
|
1026
|
+
maxPriority = Math.max(maxPriority, 50)
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
// Check manifests per snapshot
|
|
1030
|
+
const manifestsPerSnapshot = stats.snapshotCount > 0
|
|
1031
|
+
? stats.totalManifestFiles / stats.snapshotCount
|
|
1032
|
+
: 0
|
|
1033
|
+
if (manifestsPerSnapshot > config.manifestsPerSnapshotThreshold) {
|
|
1034
|
+
triggeredConditions.push(
|
|
1035
|
+
`Manifests per snapshot (${manifestsPerSnapshot.toFixed(1)}) exceeds threshold (${config.manifestsPerSnapshotThreshold})`
|
|
1036
|
+
)
|
|
1037
|
+
maxPriority = Math.max(maxPriority, 55)
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
// Determine recommended action
|
|
1041
|
+
let action: string | null = null
|
|
1042
|
+
if (triggeredConditions.length > 0) {
|
|
1043
|
+
if (smallFileRatio > config.smallFileRatioThreshold ||
|
|
1044
|
+
stats.avgDataFileSizeBytes < config.avgFileSizeThreshold) {
|
|
1045
|
+
action = 'compact'
|
|
1046
|
+
} else if (manifestsPerSnapshot > config.manifestsPerSnapshotThreshold) {
|
|
1047
|
+
action = 'rewriteManifests'
|
|
1048
|
+
} else {
|
|
1049
|
+
action = 'compact' // Default to compaction
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
return {
|
|
1054
|
+
shouldTrigger: triggeredConditions.length > 0,
|
|
1055
|
+
triggeredConditions,
|
|
1056
|
+
priority: maxPriority,
|
|
1057
|
+
action,
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
// ========== Analysis Utilities ==========
|
|
1062
|
+
|
|
1063
|
+
/**
|
|
1064
|
+
* Analyze table statistics
|
|
1065
|
+
*/
|
|
1066
|
+
private async analyzeTable(_table: string): Promise<TableStatistics> {
|
|
1067
|
+
const dataFiles = await this.getAllDataFiles()
|
|
1068
|
+
|
|
1069
|
+
let totalDataSize = 0
|
|
1070
|
+
let minSize = Infinity
|
|
1071
|
+
let maxSize = 0
|
|
1072
|
+
let smallFileCount = 0
|
|
1073
|
+
let smallFilesSize = 0
|
|
1074
|
+
const partitions = new Set<string>()
|
|
1075
|
+
|
|
1076
|
+
for (const file of dataFiles) {
|
|
1077
|
+
const size = file['file-size-in-bytes']
|
|
1078
|
+
totalDataSize += size
|
|
1079
|
+
minSize = Math.min(minSize, size)
|
|
1080
|
+
maxSize = Math.max(maxSize, size)
|
|
1081
|
+
|
|
1082
|
+
if (size < this.config.minFileSizeBytes) {
|
|
1083
|
+
smallFileCount++
|
|
1084
|
+
smallFilesSize += size
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
const partitionPath = this.extractPartitionPath(file['file-path'])
|
|
1088
|
+
if (partitionPath) {
|
|
1089
|
+
partitions.add(partitionPath)
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
// Analyze manifests
|
|
1094
|
+
let totalManifestFiles = 0
|
|
1095
|
+
let totalManifestSize = 0
|
|
1096
|
+
|
|
1097
|
+
if (this.metadata?.snapshots) {
|
|
1098
|
+
for (const snapshot of this.metadata.snapshots) {
|
|
1099
|
+
const manifests = await this.loadManifestsFromList(snapshot['manifest-list'])
|
|
1100
|
+
totalManifestFiles += manifests.length
|
|
1101
|
+
totalManifestSize += manifests.reduce((sum, m) => sum + m['manifest-length'], 0)
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
const snapshotCount = this.metadata?.snapshots?.length ?? 0
|
|
1106
|
+
|
|
1107
|
+
return {
|
|
1108
|
+
totalDataFiles: dataFiles.length,
|
|
1109
|
+
totalDataSizeBytes: totalDataSize,
|
|
1110
|
+
avgDataFileSizeBytes: dataFiles.length > 0 ? totalDataSize / dataFiles.length : 0,
|
|
1111
|
+
minDataFileSizeBytes: minSize === Infinity ? 0 : minSize,
|
|
1112
|
+
maxDataFileSizeBytes: maxSize,
|
|
1113
|
+
smallFileCount,
|
|
1114
|
+
smallFilesSizeBytes: smallFilesSize,
|
|
1115
|
+
totalManifestFiles,
|
|
1116
|
+
totalManifestSizeBytes: totalManifestSize,
|
|
1117
|
+
avgManifestFileSizeBytes: totalManifestFiles > 0 ? totalManifestSize / totalManifestFiles : 0,
|
|
1118
|
+
snapshotCount,
|
|
1119
|
+
totalPartitions: partitions.size,
|
|
1120
|
+
avgFilesPerPartition: partitions.size > 0 ? dataFiles.length / partitions.size : 0,
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
/**
|
|
1125
|
+
* Get all data files from the current snapshot
|
|
1126
|
+
*/
|
|
1127
|
+
private async getAllDataFiles(): Promise<IcebergDataFile[]> {
|
|
1128
|
+
if (!this.metadata?.['current-snapshot-id']) {
|
|
1129
|
+
return []
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
const currentSnapshot = this.metadata.snapshots?.find(
|
|
1133
|
+
(s) => s['snapshot-id'] === this.metadata!['current-snapshot-id']
|
|
1134
|
+
)
|
|
1135
|
+
|
|
1136
|
+
if (!currentSnapshot) {
|
|
1137
|
+
return []
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
const dataFiles: IcebergDataFile[] = []
|
|
1141
|
+
const manifests = await this.loadManifestsFromList(currentSnapshot['manifest-list'])
|
|
1142
|
+
|
|
1143
|
+
for (const manifest of manifests) {
|
|
1144
|
+
if (manifest.content !== 0) {
|
|
1145
|
+
continue // Skip delete manifests
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
const entries = await this.loadManifestEntries(manifest['manifest-path'])
|
|
1149
|
+
for (const entry of entries) {
|
|
1150
|
+
// Only include EXISTING (0) and ADDED (1) files
|
|
1151
|
+
if (entry.status !== 2) {
|
|
1152
|
+
dataFiles.push(entry['data-file'])
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
return dataFiles
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
/**
|
|
1161
|
+
* Load manifests from a manifest list
|
|
1162
|
+
*/
|
|
1163
|
+
private async loadManifestsFromList(manifestListPath: string): Promise<IcebergManifestFile[]> {
|
|
1164
|
+
try {
|
|
1165
|
+
const obj = await this.bucket.get(manifestListPath)
|
|
1166
|
+
if (!obj) {
|
|
1167
|
+
return []
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
const data = JSON.parse(await obj.text())
|
|
1171
|
+
return data.manifests ?? []
|
|
1172
|
+
} catch (error) {
|
|
1173
|
+
optimizerLogger.error('Failed to load manifest list', { manifestListPath, error: error instanceof Error ? error.message : String(error) })
|
|
1174
|
+
return []
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
/**
|
|
1179
|
+
* Load manifest entries from a manifest file
|
|
1180
|
+
*/
|
|
1181
|
+
private async loadManifestEntries(manifestPath: string): Promise<IcebergManifestEntry[]> {
|
|
1182
|
+
try {
|
|
1183
|
+
const obj = await this.bucket.get(manifestPath)
|
|
1184
|
+
if (!obj) {
|
|
1185
|
+
return []
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
const data = JSON.parse(await obj.text())
|
|
1189
|
+
return data.entries ?? []
|
|
1190
|
+
} catch (error) {
|
|
1191
|
+
optimizerLogger.error('Failed to load manifest', { manifestPath, error: error instanceof Error ? error.message : String(error) })
|
|
1192
|
+
return []
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
/**
|
|
1197
|
+
* Extract partition path from file path
|
|
1198
|
+
*/
|
|
1199
|
+
private extractPartitionPath(filePath: string): string {
|
|
1200
|
+
const dataIndex = filePath.indexOf('/data/')
|
|
1201
|
+
if (dataIndex === -1) {
|
|
1202
|
+
return ''
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
const afterData = filePath.substring(dataIndex + 6) // Skip '/data/'
|
|
1206
|
+
const lastSlash = afterData.lastIndexOf('/')
|
|
1207
|
+
if (lastSlash === -1) {
|
|
1208
|
+
return ''
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
return afterData.substring(0, lastSlash)
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
/**
|
|
1215
|
+
* Update metadata with new snapshot list
|
|
1216
|
+
*/
|
|
1217
|
+
private async updateMetadataWithSnapshots(snapshots: IcebergSnapshot[]): Promise<void> {
|
|
1218
|
+
if (!this.metadata || !this.metadataBuilder) {
|
|
1219
|
+
throw new Error('Metadata not loaded')
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
// Sort snapshots by timestamp
|
|
1223
|
+
snapshots.sort((a, b) => a['timestamp-ms'] - b['timestamp-ms'])
|
|
1224
|
+
|
|
1225
|
+
// Create new metadata
|
|
1226
|
+
const newMetadata: IcebergTableMetadata = {
|
|
1227
|
+
...this.metadata,
|
|
1228
|
+
'last-updated-ms': Date.now(),
|
|
1229
|
+
snapshots: snapshots,
|
|
1230
|
+
'snapshot-log': snapshots.map((s) => ({
|
|
1231
|
+
'timestamp-ms': s['timestamp-ms'],
|
|
1232
|
+
'snapshot-id': s['snapshot-id'],
|
|
1233
|
+
})),
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
// Set current snapshot to latest
|
|
1237
|
+
const latestSnapshot = snapshots[snapshots.length - 1]
|
|
1238
|
+
if (latestSnapshot) {
|
|
1239
|
+
newMetadata['current-snapshot-id'] = latestSnapshot['snapshot-id']
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
// Write new metadata version
|
|
1243
|
+
this.metadataVersion++
|
|
1244
|
+
const metadataFileName = generateMetadataFileName(this.metadataVersion)
|
|
1245
|
+
const metadataPath = `${this.tablePath}/metadata/${metadataFileName}`
|
|
1246
|
+
|
|
1247
|
+
await this.bucket.put(metadataPath, JSON.stringify(newMetadata, null, 2), {
|
|
1248
|
+
httpMetadata: { contentType: 'application/json' },
|
|
1249
|
+
})
|
|
1250
|
+
|
|
1251
|
+
// Update version hint
|
|
1252
|
+
await this.bucket.put(
|
|
1253
|
+
`${this.tablePath}/metadata/version-hint.text`,
|
|
1254
|
+
String(this.metadataVersion),
|
|
1255
|
+
{ httpMetadata: { contentType: 'text/plain' } }
|
|
1256
|
+
)
|
|
1257
|
+
|
|
1258
|
+
// Update internal state
|
|
1259
|
+
this.metadata = newMetadata
|
|
1260
|
+
this.metadataBuilder = IcebergMetadataBuilder.fromMetadata(newMetadata)
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
// ========== Utility Functions ==========
|
|
1265
|
+
|
|
1266
|
+
/**
|
|
1267
|
+
* Format bytes as human-readable string
|
|
1268
|
+
*/
|
|
1269
|
+
function formatBytes(bytes: number): string {
|
|
1270
|
+
const units = ['B', 'KB', 'MB', 'GB', 'TB']
|
|
1271
|
+
let unitIndex = 0
|
|
1272
|
+
let value = bytes
|
|
1273
|
+
|
|
1274
|
+
while (value >= 1024 && unitIndex < units.length - 1) {
|
|
1275
|
+
value /= 1024
|
|
1276
|
+
unitIndex++
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
return `${value.toFixed(2)} ${units[unitIndex]}`
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
/**
|
|
1283
|
+
* Create a storage optimizer
|
|
1284
|
+
*/
|
|
1285
|
+
export function createStorageOptimizer(config: StorageOptimizerConfig): StorageOptimizer {
|
|
1286
|
+
return new StorageOptimizer(config)
|
|
1287
|
+
}
|