@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,1460 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Memory Pressure Monitoring and OOM Protection
|
|
3
|
+
*
|
|
4
|
+
* Task: postgres-2x4k - Add memory pressure monitoring and OOM protection in PostgresDO
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
|
7
|
+
|
|
8
|
+
import { MemoryPressureManager, createMemoryPressureManager } from './memory-pressure'
|
|
9
|
+
import type {
|
|
10
|
+
MemoryPressureLevel,
|
|
11
|
+
MemoryPressureEvent,
|
|
12
|
+
MemoryPressureConfig,
|
|
13
|
+
} from './types'
|
|
14
|
+
|
|
15
|
+
describe('MemoryPressureManager', () => {
|
|
16
|
+
let manager: MemoryPressureManager
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
manager = new MemoryPressureManager()
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
manager.dispose()
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
describe('constructor and configuration', () => {
|
|
27
|
+
it('should create with default configuration', () => {
|
|
28
|
+
const config = manager.getConfig()
|
|
29
|
+
|
|
30
|
+
expect(config.enabled).toBe(true)
|
|
31
|
+
expect(config.memoryLimitBytes).toBe(128 * 1024 * 1024) // 128MB
|
|
32
|
+
expect(config.warningThresholdPercent).toBe(70)
|
|
33
|
+
expect(config.criticalThresholdPercent).toBe(85)
|
|
34
|
+
expect(config.oomThresholdPercent).toBe(95)
|
|
35
|
+
expect(config.autoUnloadExtensions).toBe(true)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('should accept custom configuration', () => {
|
|
39
|
+
const customConfig: MemoryPressureConfig = {
|
|
40
|
+
enabled: false,
|
|
41
|
+
memoryLimitBytes: 64 * 1024 * 1024,
|
|
42
|
+
warningThresholdPercent: 60,
|
|
43
|
+
criticalThresholdPercent: 80,
|
|
44
|
+
oomThresholdPercent: 90,
|
|
45
|
+
autoUnloadExtensions: false,
|
|
46
|
+
maxListeners: 25,
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const customManager = new MemoryPressureManager(customConfig)
|
|
50
|
+
const config = customManager.getConfig()
|
|
51
|
+
|
|
52
|
+
expect(config.enabled).toBe(false)
|
|
53
|
+
expect(config.memoryLimitBytes).toBe(64 * 1024 * 1024)
|
|
54
|
+
expect(config.warningThresholdPercent).toBe(60)
|
|
55
|
+
expect(config.criticalThresholdPercent).toBe(80)
|
|
56
|
+
expect(config.oomThresholdPercent).toBe(90)
|
|
57
|
+
expect(config.autoUnloadExtensions).toBe(false)
|
|
58
|
+
expect(config.maxListeners).toBe(25)
|
|
59
|
+
|
|
60
|
+
customManager.dispose()
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('should update configuration', () => {
|
|
64
|
+
manager.setConfig({
|
|
65
|
+
warningThresholdPercent: 65,
|
|
66
|
+
criticalThresholdPercent: 82,
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
const config = manager.getConfig()
|
|
70
|
+
expect(config.warningThresholdPercent).toBe(65)
|
|
71
|
+
expect(config.criticalThresholdPercent).toBe(82)
|
|
72
|
+
// Other values should remain unchanged
|
|
73
|
+
expect(config.oomThresholdPercent).toBe(95)
|
|
74
|
+
})
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
describe('getMemoryStats', () => {
|
|
78
|
+
it('should return memory statistics', () => {
|
|
79
|
+
const stats = manager.getMemoryStats()
|
|
80
|
+
|
|
81
|
+
expect(stats).toHaveProperty('heapUsed')
|
|
82
|
+
expect(stats).toHaveProperty('heapLimit')
|
|
83
|
+
expect(stats).toHaveProperty('usagePercent')
|
|
84
|
+
expect(stats).toHaveProperty('pressureLevel')
|
|
85
|
+
expect(stats).toHaveProperty('timestamp')
|
|
86
|
+
|
|
87
|
+
expect(typeof stats.heapUsed).toBe('number')
|
|
88
|
+
expect(typeof stats.heapLimit).toBe('number')
|
|
89
|
+
expect(typeof stats.usagePercent).toBe('number')
|
|
90
|
+
expect(stats.timestamp).toBeInstanceOf(Date)
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
it('should have heapLimit equal to configured memory limit', () => {
|
|
94
|
+
const stats = manager.getMemoryStats()
|
|
95
|
+
expect(stats.heapLimit).toBe(128 * 1024 * 1024)
|
|
96
|
+
})
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
describe('getPressureLevel', () => {
|
|
100
|
+
it('should return current pressure level', () => {
|
|
101
|
+
const level = manager.getPressureLevel()
|
|
102
|
+
expect(['normal', 'warning', 'critical', 'oom']).toContain(level)
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
describe('isPressureAtOrAbove', () => {
|
|
107
|
+
it('should correctly compare pressure levels', () => {
|
|
108
|
+
// Force a known pressure level for testing
|
|
109
|
+
manager._forceMemoryPressure('warning')
|
|
110
|
+
|
|
111
|
+
expect(manager.isPressureAtOrAbove('normal')).toBe(true)
|
|
112
|
+
expect(manager.isPressureAtOrAbove('warning')).toBe(true)
|
|
113
|
+
expect(manager.isPressureAtOrAbove('critical')).toBe(false)
|
|
114
|
+
expect(manager.isPressureAtOrAbove('oom')).toBe(false)
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
it('should handle critical level', () => {
|
|
118
|
+
manager._forceMemoryPressure('critical')
|
|
119
|
+
|
|
120
|
+
expect(manager.isPressureAtOrAbove('normal')).toBe(true)
|
|
121
|
+
expect(manager.isPressureAtOrAbove('warning')).toBe(true)
|
|
122
|
+
expect(manager.isPressureAtOrAbove('critical')).toBe(true)
|
|
123
|
+
expect(manager.isPressureAtOrAbove('oom')).toBe(false)
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
it('should handle oom level', () => {
|
|
127
|
+
manager._forceMemoryPressure('oom')
|
|
128
|
+
|
|
129
|
+
expect(manager.isPressureAtOrAbove('normal')).toBe(true)
|
|
130
|
+
expect(manager.isPressureAtOrAbove('warning')).toBe(true)
|
|
131
|
+
expect(manager.isPressureAtOrAbove('critical')).toBe(true)
|
|
132
|
+
expect(manager.isPressureAtOrAbove('oom')).toBe(true)
|
|
133
|
+
})
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
describe('event listeners', () => {
|
|
137
|
+
it('should register and call listeners', () => {
|
|
138
|
+
const listener = vi.fn()
|
|
139
|
+
manager.onPressureChange(listener)
|
|
140
|
+
|
|
141
|
+
// Force a pressure change
|
|
142
|
+
manager._forceMemoryPressure('warning')
|
|
143
|
+
|
|
144
|
+
expect(listener).toHaveBeenCalledTimes(1)
|
|
145
|
+
const event = listener.mock.calls[0][0] as MemoryPressureEvent
|
|
146
|
+
expect(event.previousLevel).toBe('normal')
|
|
147
|
+
expect(event.currentLevel).toBe('warning')
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
it('should allow unsubscribing', () => {
|
|
151
|
+
const listener = vi.fn()
|
|
152
|
+
const unsubscribe = manager.onPressureChange(listener)
|
|
153
|
+
|
|
154
|
+
unsubscribe()
|
|
155
|
+
|
|
156
|
+
manager._forceMemoryPressure('warning')
|
|
157
|
+
|
|
158
|
+
expect(listener).not.toHaveBeenCalled()
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
it('should track listener count', () => {
|
|
162
|
+
expect(manager.getListenerCount()).toBe(0)
|
|
163
|
+
|
|
164
|
+
const unsub1 = manager.onPressureChange(() => {})
|
|
165
|
+
expect(manager.getListenerCount()).toBe(1)
|
|
166
|
+
|
|
167
|
+
const unsub2 = manager.onPressureChange(() => {})
|
|
168
|
+
expect(manager.getListenerCount()).toBe(2)
|
|
169
|
+
|
|
170
|
+
unsub1()
|
|
171
|
+
expect(manager.getListenerCount()).toBe(1)
|
|
172
|
+
|
|
173
|
+
unsub2()
|
|
174
|
+
expect(manager.getListenerCount()).toBe(0)
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
it('should limit max listeners to prevent memory leaks', () => {
|
|
178
|
+
const customManager = new MemoryPressureManager({ maxListeners: 5 })
|
|
179
|
+
|
|
180
|
+
// Add more listeners than the limit
|
|
181
|
+
for (let i = 0; i < 10; i++) {
|
|
182
|
+
customManager.onPressureChange(() => {})
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
expect(customManager.getListenerCount()).toBeLessThanOrEqual(5)
|
|
186
|
+
|
|
187
|
+
customManager.dispose()
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
it('should warn when approaching listener limit', () => {
|
|
191
|
+
const customManager = new MemoryPressureManager({ maxListeners: 10 })
|
|
192
|
+
const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
|
193
|
+
|
|
194
|
+
// Add 9 listeners (90% of limit)
|
|
195
|
+
for (let i = 0; i < 9; i++) {
|
|
196
|
+
customManager.onPressureChange(() => {})
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
200
|
+
expect.stringContaining('Approaching memory pressure listener limit')
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
consoleSpy.mockRestore()
|
|
204
|
+
customManager.dispose()
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
it('should not emit event when pressure level unchanged', () => {
|
|
208
|
+
const listener = vi.fn()
|
|
209
|
+
manager.onPressureChange(listener)
|
|
210
|
+
|
|
211
|
+
// Force to warning
|
|
212
|
+
manager._forceMemoryPressure('warning')
|
|
213
|
+
expect(listener).toHaveBeenCalledTimes(1)
|
|
214
|
+
|
|
215
|
+
// Try to force to warning again - should not emit
|
|
216
|
+
const result = manager._forceMemoryPressure('warning')
|
|
217
|
+
expect(result).toBeNull()
|
|
218
|
+
expect(listener).toHaveBeenCalledTimes(1)
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
it('should emit event with correct data', () => {
|
|
222
|
+
const listener = vi.fn()
|
|
223
|
+
manager.onPressureChange(listener)
|
|
224
|
+
|
|
225
|
+
manager._forceMemoryPressure('critical')
|
|
226
|
+
|
|
227
|
+
const event = listener.mock.calls[0][0] as MemoryPressureEvent
|
|
228
|
+
expect(event).toHaveProperty('previousLevel')
|
|
229
|
+
expect(event).toHaveProperty('currentLevel')
|
|
230
|
+
expect(event).toHaveProperty('stats')
|
|
231
|
+
expect(event).toHaveProperty('actionsTaken')
|
|
232
|
+
expect(event).toHaveProperty('timestamp')
|
|
233
|
+
|
|
234
|
+
expect(event.previousLevel).toBe('normal')
|
|
235
|
+
expect(event.currentLevel).toBe('critical')
|
|
236
|
+
expect(event.stats.pressureLevel).toBe('critical')
|
|
237
|
+
expect(event.timestamp).toBeInstanceOf(Date)
|
|
238
|
+
})
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
describe('monitoring lifecycle', () => {
|
|
242
|
+
it('should start and stop monitoring', () => {
|
|
243
|
+
manager.startMonitoring()
|
|
244
|
+
// No error should occur
|
|
245
|
+
|
|
246
|
+
manager.stopMonitoring()
|
|
247
|
+
// No error should occur
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
it('should not start monitoring when disabled', () => {
|
|
251
|
+
const disabledManager = new MemoryPressureManager({ enabled: false })
|
|
252
|
+
|
|
253
|
+
disabledManager.startMonitoring()
|
|
254
|
+
// Should not throw and interval should not be set
|
|
255
|
+
|
|
256
|
+
disabledManager.dispose()
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
it('should dispose cleanly', () => {
|
|
260
|
+
manager.startMonitoring()
|
|
261
|
+
manager.onPressureChange(() => {})
|
|
262
|
+
|
|
263
|
+
manager.dispose()
|
|
264
|
+
|
|
265
|
+
expect(manager.getListenerCount()).toBe(0)
|
|
266
|
+
})
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
describe('checkMemoryPressure', () => {
|
|
270
|
+
it('should return null when disabled', async () => {
|
|
271
|
+
const disabledManager = new MemoryPressureManager({ enabled: false })
|
|
272
|
+
|
|
273
|
+
const result = await disabledManager.checkMemoryPressure()
|
|
274
|
+
expect(result).toBeNull()
|
|
275
|
+
|
|
276
|
+
disabledManager.dispose()
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
it('should return null when pressure level unchanged', async () => {
|
|
280
|
+
// Run once to establish baseline
|
|
281
|
+
await manager.checkMemoryPressure()
|
|
282
|
+
|
|
283
|
+
// Run again - should return null if level unchanged
|
|
284
|
+
const result = await manager.checkMemoryPressure()
|
|
285
|
+
expect(result).toBeNull()
|
|
286
|
+
})
|
|
287
|
+
})
|
|
288
|
+
|
|
289
|
+
describe('extension unloading', () => {
|
|
290
|
+
it('should return error when PGlite not available', async () => {
|
|
291
|
+
const result = await manager.unloadLeastImportantExtension()
|
|
292
|
+
|
|
293
|
+
expect(result.success).toBe(false)
|
|
294
|
+
expect(result.error).toBe('PGlite not available')
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
it('should unload extension when available', async () => {
|
|
298
|
+
const mockPGlite = {
|
|
299
|
+
query: vi.fn()
|
|
300
|
+
// First call: get installed extensions
|
|
301
|
+
.mockResolvedValueOnce({
|
|
302
|
+
rows: [
|
|
303
|
+
{ extname: 'tablefunc' },
|
|
304
|
+
{ extname: 'vector' },
|
|
305
|
+
],
|
|
306
|
+
fields: [],
|
|
307
|
+
})
|
|
308
|
+
// Second call: DROP EXTENSION
|
|
309
|
+
.mockResolvedValueOnce({ rows: [], fields: [] }),
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
manager.setPGlite(mockPGlite)
|
|
313
|
+
|
|
314
|
+
const result = await manager.unloadLeastImportantExtension()
|
|
315
|
+
|
|
316
|
+
expect(result.success).toBe(true)
|
|
317
|
+
expect(result.extensionName).toBe('tablefunc') // Lowest priority
|
|
318
|
+
expect(mockPGlite.query).toHaveBeenCalledWith(
|
|
319
|
+
expect.stringContaining('DROP EXTENSION IF EXISTS "tablefunc" CASCADE')
|
|
320
|
+
)
|
|
321
|
+
})
|
|
322
|
+
|
|
323
|
+
it('should track unloaded extensions', async () => {
|
|
324
|
+
const mockPGlite = {
|
|
325
|
+
query: vi.fn()
|
|
326
|
+
.mockResolvedValueOnce({
|
|
327
|
+
rows: [{ extname: 'tablefunc' }],
|
|
328
|
+
fields: [],
|
|
329
|
+
})
|
|
330
|
+
.mockResolvedValueOnce({ rows: [], fields: [] }),
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
manager.setPGlite(mockPGlite)
|
|
334
|
+
|
|
335
|
+
await manager.unloadLeastImportantExtension()
|
|
336
|
+
|
|
337
|
+
expect(manager.wasExtensionUnloaded('tablefunc')).toBe(true)
|
|
338
|
+
expect(manager.wasExtensionUnloaded('vector')).toBe(false)
|
|
339
|
+
expect(manager.getUnloadedExtensions()).toContain('tablefunc')
|
|
340
|
+
})
|
|
341
|
+
|
|
342
|
+
it('should not unload already unloaded extensions', async () => {
|
|
343
|
+
const mockPGlite = {
|
|
344
|
+
query: vi.fn()
|
|
345
|
+
// First unload attempt
|
|
346
|
+
.mockResolvedValueOnce({
|
|
347
|
+
rows: [{ extname: 'tablefunc' }, { extname: 'fuzzystrmatch' }],
|
|
348
|
+
fields: [],
|
|
349
|
+
})
|
|
350
|
+
.mockResolvedValueOnce({ rows: [], fields: [] })
|
|
351
|
+
// Second unload attempt - tablefunc already unloaded
|
|
352
|
+
.mockResolvedValueOnce({
|
|
353
|
+
rows: [{ extname: 'tablefunc' }, { extname: 'fuzzystrmatch' }],
|
|
354
|
+
fields: [],
|
|
355
|
+
})
|
|
356
|
+
.mockResolvedValueOnce({ rows: [], fields: [] }),
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
manager.setPGlite(mockPGlite)
|
|
360
|
+
|
|
361
|
+
// First unload
|
|
362
|
+
const result1 = await manager.unloadLeastImportantExtension()
|
|
363
|
+
expect(result1.extensionName).toBe('tablefunc')
|
|
364
|
+
|
|
365
|
+
// Second unload - should get fuzzystrmatch since tablefunc is tracked
|
|
366
|
+
const result2 = await manager.unloadLeastImportantExtension()
|
|
367
|
+
expect(result2.extensionName).toBe('fuzzystrmatch')
|
|
368
|
+
})
|
|
369
|
+
|
|
370
|
+
it('should return error when no extensions available to unload', async () => {
|
|
371
|
+
const mockPGlite = {
|
|
372
|
+
query: vi.fn().mockResolvedValueOnce({
|
|
373
|
+
rows: [], // No extensions installed
|
|
374
|
+
fields: [],
|
|
375
|
+
}),
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
manager.setPGlite(mockPGlite)
|
|
379
|
+
|
|
380
|
+
const result = await manager.unloadLeastImportantExtension()
|
|
381
|
+
|
|
382
|
+
expect(result.success).toBe(false)
|
|
383
|
+
expect(result.error).toBe('No extensions available to unload')
|
|
384
|
+
})
|
|
385
|
+
|
|
386
|
+
it('should clear unloaded extensions list', () => {
|
|
387
|
+
// Manually add to unloaded set via internal state
|
|
388
|
+
manager['unloadedExtensions'].add('test-ext')
|
|
389
|
+
|
|
390
|
+
expect(manager.wasExtensionUnloaded('test-ext')).toBe(true)
|
|
391
|
+
|
|
392
|
+
manager.clearUnloadedExtensions()
|
|
393
|
+
|
|
394
|
+
expect(manager.wasExtensionUnloaded('test-ext')).toBe(false)
|
|
395
|
+
expect(manager.getUnloadedExtensions()).toHaveLength(0)
|
|
396
|
+
})
|
|
397
|
+
|
|
398
|
+
it('should use custom extension priority', async () => {
|
|
399
|
+
const customManager = new MemoryPressureManager({
|
|
400
|
+
extensionUnloadPriority: ['vector', 'pg_trgm', 'hstore'],
|
|
401
|
+
})
|
|
402
|
+
|
|
403
|
+
const mockPGlite = {
|
|
404
|
+
query: vi.fn()
|
|
405
|
+
.mockResolvedValueOnce({
|
|
406
|
+
rows: [
|
|
407
|
+
{ extname: 'vector' },
|
|
408
|
+
{ extname: 'pg_trgm' },
|
|
409
|
+
{ extname: 'hstore' },
|
|
410
|
+
],
|
|
411
|
+
fields: [],
|
|
412
|
+
})
|
|
413
|
+
.mockResolvedValueOnce({ rows: [], fields: [] }),
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
customManager.setPGlite(mockPGlite)
|
|
417
|
+
|
|
418
|
+
const result = await customManager.unloadLeastImportantExtension()
|
|
419
|
+
|
|
420
|
+
expect(result.extensionName).toBe('vector') // First in custom priority
|
|
421
|
+
|
|
422
|
+
customManager.dispose()
|
|
423
|
+
})
|
|
424
|
+
})
|
|
425
|
+
|
|
426
|
+
describe('forced pressure for testing', () => {
|
|
427
|
+
it('should force pressure level and emit event', () => {
|
|
428
|
+
const listener = vi.fn()
|
|
429
|
+
manager.onPressureChange(listener)
|
|
430
|
+
|
|
431
|
+
const event = manager._forceMemoryPressure('critical')
|
|
432
|
+
|
|
433
|
+
expect(event).not.toBeNull()
|
|
434
|
+
expect(event!.currentLevel).toBe('critical')
|
|
435
|
+
expect(listener).toHaveBeenCalled()
|
|
436
|
+
})
|
|
437
|
+
|
|
438
|
+
it('should return null when forcing same level', () => {
|
|
439
|
+
manager._forceMemoryPressure('warning')
|
|
440
|
+
|
|
441
|
+
const event = manager._forceMemoryPressure('warning')
|
|
442
|
+
|
|
443
|
+
expect(event).toBeNull()
|
|
444
|
+
})
|
|
445
|
+
|
|
446
|
+
it('should calculate correct usage stats for forced levels', () => {
|
|
447
|
+
const event = manager._forceMemoryPressure('oom')
|
|
448
|
+
|
|
449
|
+
expect(event!.stats.usagePercent).toBe(96)
|
|
450
|
+
expect(event!.stats.pressureLevel).toBe('oom')
|
|
451
|
+
})
|
|
452
|
+
})
|
|
453
|
+
|
|
454
|
+
describe('createMemoryPressureManager factory', () => {
|
|
455
|
+
it('should create manager with default config', () => {
|
|
456
|
+
const created = createMemoryPressureManager()
|
|
457
|
+
expect(created).toBeInstanceOf(MemoryPressureManager)
|
|
458
|
+
created.dispose()
|
|
459
|
+
})
|
|
460
|
+
|
|
461
|
+
it('should create manager with custom config', () => {
|
|
462
|
+
const created = createMemoryPressureManager({
|
|
463
|
+
warningThresholdPercent: 50,
|
|
464
|
+
})
|
|
465
|
+
|
|
466
|
+
expect(created.getConfig().warningThresholdPercent).toBe(50)
|
|
467
|
+
created.dispose()
|
|
468
|
+
})
|
|
469
|
+
})
|
|
470
|
+
})
|
|
471
|
+
|
|
472
|
+
// Mock cloudflare:workers
|
|
473
|
+
vi.mock('cloudflare:workers', () => ({
|
|
474
|
+
DurableObject: class DurableObject {
|
|
475
|
+
ctx: unknown
|
|
476
|
+
env: unknown
|
|
477
|
+
constructor(ctx: unknown, env: unknown) {
|
|
478
|
+
this.ctx = ctx
|
|
479
|
+
this.env = env
|
|
480
|
+
}
|
|
481
|
+
},
|
|
482
|
+
}))
|
|
483
|
+
|
|
484
|
+
// Mock WASM and data imports
|
|
485
|
+
vi.mock('../pglite-assets/pglite.wasm', () => ({ default: {} }))
|
|
486
|
+
vi.mock('../pglite-assets/pglite.data', () => ({ default: {} }))
|
|
487
|
+
|
|
488
|
+
// Mock workers-pglite
|
|
489
|
+
vi.mock('../pglite/workers-pglite', () => ({
|
|
490
|
+
createWorkersPGLite: vi.fn(),
|
|
491
|
+
WorkersPGLite: class {},
|
|
492
|
+
}))
|
|
493
|
+
|
|
494
|
+
import { PostgresDO, createPostgresDOWithMemoryProtection } from './do'
|
|
495
|
+
import type { Env } from './types'
|
|
496
|
+
|
|
497
|
+
describe('PostgresDO Memory Pressure Integration', () => {
|
|
498
|
+
|
|
499
|
+
const createMockState = () => ({
|
|
500
|
+
id: {
|
|
501
|
+
toString: () => 'test-do-id',
|
|
502
|
+
name: 'test-database',
|
|
503
|
+
},
|
|
504
|
+
storage: {
|
|
505
|
+
get: vi.fn(),
|
|
506
|
+
put: vi.fn(),
|
|
507
|
+
delete: vi.fn(),
|
|
508
|
+
list: vi.fn(() => Promise.resolve(new Map())),
|
|
509
|
+
getAlarm: vi.fn(),
|
|
510
|
+
setAlarm: vi.fn(),
|
|
511
|
+
deleteAlarm: vi.fn(),
|
|
512
|
+
},
|
|
513
|
+
blockConcurrencyWhile: vi.fn((fn) => fn()),
|
|
514
|
+
waitUntil: vi.fn(),
|
|
515
|
+
acceptWebSocket: vi.fn(),
|
|
516
|
+
getWebSockets: vi.fn(() => []),
|
|
517
|
+
})
|
|
518
|
+
|
|
519
|
+
const createMockPGlite = () => ({
|
|
520
|
+
query: vi.fn(() => Promise.resolve({
|
|
521
|
+
rows: [],
|
|
522
|
+
fields: [],
|
|
523
|
+
affectedRows: 0,
|
|
524
|
+
})),
|
|
525
|
+
exec: vi.fn(() => Promise.resolve({ rows: [], fields: [] })),
|
|
526
|
+
close: vi.fn(() => Promise.resolve()),
|
|
527
|
+
ready: Promise.resolve(),
|
|
528
|
+
})
|
|
529
|
+
|
|
530
|
+
const createMockEnv = (): Env => ({
|
|
531
|
+
POSTGRES_DO: {} as DurableObjectNamespace,
|
|
532
|
+
POSTGRES_DEFAULT_DB: 'postgres',
|
|
533
|
+
})
|
|
534
|
+
|
|
535
|
+
describe('memory pressure methods on PostgresDO', () => {
|
|
536
|
+
it('should expose getMemoryStats method', () => {
|
|
537
|
+
const state = createMockState()
|
|
538
|
+
const env = createMockEnv()
|
|
539
|
+
const doo = new PostgresDO(state as any, env)
|
|
540
|
+
|
|
541
|
+
const stats = doo.getMemoryStats()
|
|
542
|
+
|
|
543
|
+
expect(stats).toHaveProperty('heapUsed')
|
|
544
|
+
expect(stats).toHaveProperty('heapLimit')
|
|
545
|
+
expect(stats).toHaveProperty('usagePercent')
|
|
546
|
+
expect(stats).toHaveProperty('pressureLevel')
|
|
547
|
+
})
|
|
548
|
+
|
|
549
|
+
it('should expose getMemoryPressureLevel method', () => {
|
|
550
|
+
const state = createMockState()
|
|
551
|
+
const env = createMockEnv()
|
|
552
|
+
const doo = new PostgresDO(state as any, env)
|
|
553
|
+
|
|
554
|
+
const level = doo.getMemoryPressureLevel()
|
|
555
|
+
|
|
556
|
+
expect(['normal', 'warning', 'critical', 'oom']).toContain(level)
|
|
557
|
+
})
|
|
558
|
+
|
|
559
|
+
it('should expose onMemoryPressure for event listening', () => {
|
|
560
|
+
const state = createMockState()
|
|
561
|
+
const env = createMockEnv()
|
|
562
|
+
const doo = new PostgresDO(state as any, env)
|
|
563
|
+
|
|
564
|
+
const listener = vi.fn()
|
|
565
|
+
const unsubscribe = doo.onMemoryPressure(listener)
|
|
566
|
+
|
|
567
|
+
expect(typeof unsubscribe).toBe('function')
|
|
568
|
+
expect(doo.getMemoryPressureListenerCount()).toBe(1)
|
|
569
|
+
|
|
570
|
+
unsubscribe()
|
|
571
|
+
expect(doo.getMemoryPressureListenerCount()).toBe(0)
|
|
572
|
+
})
|
|
573
|
+
|
|
574
|
+
it('should allow configuring memory pressure settings', () => {
|
|
575
|
+
const state = createMockState()
|
|
576
|
+
const env = createMockEnv()
|
|
577
|
+
const doo = new PostgresDO(state as any, env)
|
|
578
|
+
|
|
579
|
+
doo.setMemoryPressureConfig({
|
|
580
|
+
warningThresholdPercent: 60,
|
|
581
|
+
criticalThresholdPercent: 75,
|
|
582
|
+
})
|
|
583
|
+
|
|
584
|
+
const config = doo.getMemoryPressureConfig()
|
|
585
|
+
expect(config.warningThresholdPercent).toBe(60)
|
|
586
|
+
expect(config.criticalThresholdPercent).toBe(75)
|
|
587
|
+
})
|
|
588
|
+
|
|
589
|
+
it('should track unloaded extensions', async () => {
|
|
590
|
+
const state = createMockState()
|
|
591
|
+
const env = createMockEnv()
|
|
592
|
+
const doo = new PostgresDO(state as any, env)
|
|
593
|
+
|
|
594
|
+
const mockPGlite = createMockPGlite()
|
|
595
|
+
mockPGlite.query
|
|
596
|
+
.mockResolvedValueOnce({
|
|
597
|
+
rows: [{ extname: 'tablefunc' }],
|
|
598
|
+
fields: [],
|
|
599
|
+
affectedRows: 0,
|
|
600
|
+
})
|
|
601
|
+
.mockResolvedValueOnce({ rows: [], fields: [], affectedRows: 0 })
|
|
602
|
+
|
|
603
|
+
vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
|
|
604
|
+
await doo.initPGlite()
|
|
605
|
+
|
|
606
|
+
const result = await doo.unloadExtensionForMemory()
|
|
607
|
+
|
|
608
|
+
expect(result.success).toBe(true)
|
|
609
|
+
expect(doo.wasExtensionUnloaded('tablefunc')).toBe(true)
|
|
610
|
+
expect(doo.getUnloadedExtensions()).toContain('tablefunc')
|
|
611
|
+
})
|
|
612
|
+
})
|
|
613
|
+
|
|
614
|
+
describe('createPostgresDOWithMemoryProtection factory', () => {
|
|
615
|
+
it('should create PostgresDO with memory protection enabled', () => {
|
|
616
|
+
const PostgresDOClass = createPostgresDOWithMemoryProtection({
|
|
617
|
+
database: 'testdb',
|
|
618
|
+
})
|
|
619
|
+
|
|
620
|
+
const state = createMockState()
|
|
621
|
+
const env = createMockEnv()
|
|
622
|
+
const doo = new PostgresDOClass(state as any, env)
|
|
623
|
+
|
|
624
|
+
const config = doo.getMemoryPressureConfig()
|
|
625
|
+
expect(config.enabled).toBe(true)
|
|
626
|
+
expect(config.autoUnloadExtensions).toBe(true)
|
|
627
|
+
})
|
|
628
|
+
|
|
629
|
+
it('should accept custom memory pressure config', () => {
|
|
630
|
+
const PostgresDOClass = createPostgresDOWithMemoryProtection(
|
|
631
|
+
{ database: 'testdb' },
|
|
632
|
+
{
|
|
633
|
+
warningThresholdPercent: 50,
|
|
634
|
+
criticalThresholdPercent: 70,
|
|
635
|
+
}
|
|
636
|
+
)
|
|
637
|
+
|
|
638
|
+
const state = createMockState()
|
|
639
|
+
const env = createMockEnv()
|
|
640
|
+
const doo = new PostgresDOClass(state as any, env)
|
|
641
|
+
|
|
642
|
+
const config = doo.getMemoryPressureConfig()
|
|
643
|
+
expect(config.warningThresholdPercent).toBe(50)
|
|
644
|
+
expect(config.criticalThresholdPercent).toBe(70)
|
|
645
|
+
})
|
|
646
|
+
})
|
|
647
|
+
|
|
648
|
+
describe('shutdown integration', () => {
|
|
649
|
+
it('should dispose memory manager on shutdown', async () => {
|
|
650
|
+
const state = createMockState()
|
|
651
|
+
const env = createMockEnv()
|
|
652
|
+
const doo = new PostgresDO(state as any, env)
|
|
653
|
+
|
|
654
|
+
const mockPGlite = createMockPGlite()
|
|
655
|
+
vi.spyOn(doo as any, 'createPGliteInstance').mockResolvedValue(mockPGlite)
|
|
656
|
+
await doo.initPGlite()
|
|
657
|
+
|
|
658
|
+
// Add a listener to verify disposal
|
|
659
|
+
const listener = vi.fn()
|
|
660
|
+
doo.onMemoryPressure(listener)
|
|
661
|
+
expect(doo.getMemoryPressureListenerCount()).toBe(1)
|
|
662
|
+
|
|
663
|
+
await doo.shutdown({ gracePeriodMs: 100 })
|
|
664
|
+
|
|
665
|
+
// After shutdown, accessing the memory manager should create a new one
|
|
666
|
+
// with zero listeners
|
|
667
|
+
expect(doo.getMemoryPressureListenerCount()).toBe(0)
|
|
668
|
+
})
|
|
669
|
+
})
|
|
670
|
+
})
|
|
671
|
+
|
|
672
|
+
/**
|
|
673
|
+
* ========================================================================
|
|
674
|
+
* RED TESTS: Memory Pressure + Tiered Storage Demotion Integration
|
|
675
|
+
* Issue: postgres-ksrv - Integrate memory pressure with tiered storage
|
|
676
|
+
*
|
|
677
|
+
* These tests define the expected behavior for:
|
|
678
|
+
* 1. Demotion triggers on memory pressure
|
|
679
|
+
* 2. Connection to TieredStorageOrchestrator
|
|
680
|
+
* 3. Metrics for pressure-triggered demotions
|
|
681
|
+
* 4. Memory pressure scenarios
|
|
682
|
+
* ========================================================================
|
|
683
|
+
*/
|
|
684
|
+
describe('MemoryPressureManager - Tiered Storage Integration [GREEN - postgres-ksrv]', () => {
|
|
685
|
+
let manager: MemoryPressureManager
|
|
686
|
+
|
|
687
|
+
beforeEach(() => {
|
|
688
|
+
manager = new MemoryPressureManager()
|
|
689
|
+
})
|
|
690
|
+
|
|
691
|
+
afterEach(() => {
|
|
692
|
+
manager.dispose()
|
|
693
|
+
})
|
|
694
|
+
|
|
695
|
+
describe('setTieredStorageOrchestrator()', () => {
|
|
696
|
+
it('should accept a TieredStorageOrchestrator instance', () => {
|
|
697
|
+
const mockOrchestrator = createMockOrchestrator()
|
|
698
|
+
|
|
699
|
+
// This method should exist to connect the orchestrator
|
|
700
|
+
manager.setTieredStorageOrchestrator(mockOrchestrator)
|
|
701
|
+
|
|
702
|
+
// Should not throw
|
|
703
|
+
expect(manager.hasTieredStorageOrchestrator()).toBe(true)
|
|
704
|
+
})
|
|
705
|
+
|
|
706
|
+
it('should allow null to disconnect orchestrator', () => {
|
|
707
|
+
const mockOrchestrator = createMockOrchestrator()
|
|
708
|
+
|
|
709
|
+
manager.setTieredStorageOrchestrator(mockOrchestrator)
|
|
710
|
+
expect(manager.hasTieredStorageOrchestrator()).toBe(true)
|
|
711
|
+
|
|
712
|
+
manager.setTieredStorageOrchestrator(null)
|
|
713
|
+
expect(manager.hasTieredStorageOrchestrator()).toBe(false)
|
|
714
|
+
})
|
|
715
|
+
})
|
|
716
|
+
|
|
717
|
+
describe('pressure-triggered demotion', () => {
|
|
718
|
+
it('should trigger hot tier demotion on warning pressure', async () => {
|
|
719
|
+
const mockOrchestrator = createMockOrchestrator()
|
|
720
|
+
manager.setTieredStorageOrchestrator(mockOrchestrator)
|
|
721
|
+
|
|
722
|
+
// Configure to trigger demotion on warning
|
|
723
|
+
manager.setConfig({
|
|
724
|
+
warningThresholdPercent: 70,
|
|
725
|
+
})
|
|
726
|
+
|
|
727
|
+
// Force warning pressure
|
|
728
|
+
manager._forceMemoryPressure('warning')
|
|
729
|
+
|
|
730
|
+
// Allow async demotion to complete
|
|
731
|
+
await new Promise(resolve => setTimeout(resolve, 10))
|
|
732
|
+
|
|
733
|
+
// Should have triggered hot tier demotion
|
|
734
|
+
expect(mockOrchestrator.evictLRUFromHot).toHaveBeenCalled()
|
|
735
|
+
})
|
|
736
|
+
|
|
737
|
+
it('should trigger aggressive demotion on critical pressure', async () => {
|
|
738
|
+
const mockOrchestrator = createMockOrchestrator()
|
|
739
|
+
manager.setTieredStorageOrchestrator(mockOrchestrator)
|
|
740
|
+
|
|
741
|
+
// Force critical pressure
|
|
742
|
+
manager._forceMemoryPressure('critical')
|
|
743
|
+
|
|
744
|
+
// Allow async demotion to complete
|
|
745
|
+
await new Promise(resolve => setTimeout(resolve, 10))
|
|
746
|
+
|
|
747
|
+
// Should have triggered both hot and warm tier demotions
|
|
748
|
+
expect(mockOrchestrator.evictLRUFromHot).toHaveBeenCalled()
|
|
749
|
+
expect(mockOrchestrator.runDemotionCycle).toHaveBeenCalled()
|
|
750
|
+
})
|
|
751
|
+
|
|
752
|
+
it('should trigger emergency demotion on OOM pressure', async () => {
|
|
753
|
+
const mockOrchestrator = createMockOrchestrator()
|
|
754
|
+
manager.setTieredStorageOrchestrator(mockOrchestrator)
|
|
755
|
+
|
|
756
|
+
// Force OOM pressure
|
|
757
|
+
manager._forceMemoryPressure('oom')
|
|
758
|
+
|
|
759
|
+
// Allow async demotion to complete
|
|
760
|
+
await new Promise(resolve => setTimeout(resolve, 10))
|
|
761
|
+
|
|
762
|
+
// Should have triggered aggressive demotions with higher counts
|
|
763
|
+
expect(mockOrchestrator.evictLRUFromHot).toHaveBeenCalledWith(
|
|
764
|
+
expect.any(Number)
|
|
765
|
+
)
|
|
766
|
+
// On OOM, we should demote more aggressively (higher count)
|
|
767
|
+
const callArgs = mockOrchestrator.evictLRUFromHot.mock.calls[0]
|
|
768
|
+
expect(callArgs[0]).toBeGreaterThan(10) // Emergency eviction count
|
|
769
|
+
})
|
|
770
|
+
|
|
771
|
+
it('should not trigger demotion on normal pressure', async () => {
|
|
772
|
+
const mockOrchestrator = createMockOrchestrator()
|
|
773
|
+
manager.setTieredStorageOrchestrator(mockOrchestrator)
|
|
774
|
+
|
|
775
|
+
// Force warning first, then back to normal
|
|
776
|
+
manager._forceMemoryPressure('warning')
|
|
777
|
+
await new Promise(resolve => setTimeout(resolve, 10))
|
|
778
|
+
|
|
779
|
+
// Clear mock calls
|
|
780
|
+
mockOrchestrator.evictLRUFromHot.mockClear()
|
|
781
|
+
mockOrchestrator.runDemotionCycle.mockClear()
|
|
782
|
+
|
|
783
|
+
// Force normal pressure
|
|
784
|
+
manager._forceMemoryPressure('normal')
|
|
785
|
+
|
|
786
|
+
await new Promise(resolve => setTimeout(resolve, 10))
|
|
787
|
+
|
|
788
|
+
// Should NOT have triggered any demotions
|
|
789
|
+
expect(mockOrchestrator.evictLRUFromHot).not.toHaveBeenCalled()
|
|
790
|
+
expect(mockOrchestrator.runDemotionCycle).not.toHaveBeenCalled()
|
|
791
|
+
})
|
|
792
|
+
})
|
|
793
|
+
|
|
794
|
+
describe('demotion configuration', () => {
|
|
795
|
+
it('should respect autoDemoteOnPressure config option', async () => {
|
|
796
|
+
const mockOrchestrator = createMockOrchestrator()
|
|
797
|
+
|
|
798
|
+
// Create manager with auto-demotion disabled
|
|
799
|
+
const customManager = new MemoryPressureManager({
|
|
800
|
+
autoDemoteOnPressure: false,
|
|
801
|
+
})
|
|
802
|
+
customManager.setTieredStorageOrchestrator(mockOrchestrator)
|
|
803
|
+
|
|
804
|
+
// Force critical pressure
|
|
805
|
+
customManager._forceMemoryPressure('critical')
|
|
806
|
+
|
|
807
|
+
await new Promise(resolve => setTimeout(resolve, 10))
|
|
808
|
+
|
|
809
|
+
// Should NOT have triggered any demotions
|
|
810
|
+
expect(mockOrchestrator.evictLRUFromHot).not.toHaveBeenCalled()
|
|
811
|
+
expect(mockOrchestrator.runDemotionCycle).not.toHaveBeenCalled()
|
|
812
|
+
|
|
813
|
+
customManager.dispose()
|
|
814
|
+
})
|
|
815
|
+
|
|
816
|
+
it('should allow configuring demotion counts per pressure level', async () => {
|
|
817
|
+
const mockOrchestrator = createMockOrchestrator()
|
|
818
|
+
|
|
819
|
+
const customManager = new MemoryPressureManager({
|
|
820
|
+
demotionConfig: {
|
|
821
|
+
warning: { hotEvictCount: 5, warmDemoteCount: 0 },
|
|
822
|
+
critical: { hotEvictCount: 20, warmDemoteCount: 10 },
|
|
823
|
+
oom: { hotEvictCount: 50, warmDemoteCount: 25 },
|
|
824
|
+
},
|
|
825
|
+
})
|
|
826
|
+
customManager.setTieredStorageOrchestrator(mockOrchestrator)
|
|
827
|
+
|
|
828
|
+
// Force warning pressure
|
|
829
|
+
customManager._forceMemoryPressure('warning')
|
|
830
|
+
|
|
831
|
+
await new Promise(resolve => setTimeout(resolve, 10))
|
|
832
|
+
|
|
833
|
+
expect(mockOrchestrator.evictLRUFromHot).toHaveBeenCalledWith(5)
|
|
834
|
+
|
|
835
|
+
customManager.dispose()
|
|
836
|
+
})
|
|
837
|
+
})
|
|
838
|
+
|
|
839
|
+
describe('demotion metrics', () => {
|
|
840
|
+
it('should track pressure-triggered demotion count', async () => {
|
|
841
|
+
const mockOrchestrator = createMockOrchestrator()
|
|
842
|
+
mockOrchestrator.evictLRUFromHot.mockResolvedValue([
|
|
843
|
+
{ key: 'page-1', fromTier: 'hot', toTier: 'warm', success: true, timestamp: Date.now(), reason: 'lru_eviction' },
|
|
844
|
+
{ key: 'page-2', fromTier: 'hot', toTier: 'warm', success: true, timestamp: Date.now(), reason: 'lru_eviction' },
|
|
845
|
+
])
|
|
846
|
+
|
|
847
|
+
manager.setTieredStorageOrchestrator(mockOrchestrator)
|
|
848
|
+
|
|
849
|
+
// Force warning pressure
|
|
850
|
+
manager._forceMemoryPressure('warning')
|
|
851
|
+
|
|
852
|
+
await new Promise(resolve => setTimeout(resolve, 10))
|
|
853
|
+
|
|
854
|
+
const metrics = manager.getDemotionMetrics()
|
|
855
|
+
expect(metrics.pressureTriggeredDemotions).toBeGreaterThan(0)
|
|
856
|
+
})
|
|
857
|
+
|
|
858
|
+
it('should track demotions by pressure level', async () => {
|
|
859
|
+
const mockOrchestrator = createMockOrchestrator()
|
|
860
|
+
mockOrchestrator.evictLRUFromHot.mockResolvedValue([
|
|
861
|
+
{ key: 'page-1', fromTier: 'hot', toTier: 'warm', success: true, timestamp: Date.now(), reason: 'lru_eviction' },
|
|
862
|
+
])
|
|
863
|
+
|
|
864
|
+
manager.setTieredStorageOrchestrator(mockOrchestrator)
|
|
865
|
+
|
|
866
|
+
// Force warning pressure
|
|
867
|
+
manager._forceMemoryPressure('warning')
|
|
868
|
+
await new Promise(resolve => setTimeout(resolve, 10))
|
|
869
|
+
|
|
870
|
+
// Force critical pressure
|
|
871
|
+
manager._forceMemoryPressure('critical')
|
|
872
|
+
await new Promise(resolve => setTimeout(resolve, 10))
|
|
873
|
+
|
|
874
|
+
const metrics = manager.getDemotionMetrics()
|
|
875
|
+
expect(metrics.demotionsByPressureLevel.warning).toBeGreaterThanOrEqual(0)
|
|
876
|
+
expect(metrics.demotionsByPressureLevel.critical).toBeGreaterThanOrEqual(0)
|
|
877
|
+
})
|
|
878
|
+
|
|
879
|
+
it('should track demotion failures', async () => {
|
|
880
|
+
const mockOrchestrator = createMockOrchestrator()
|
|
881
|
+
mockOrchestrator.evictLRUFromHot.mockResolvedValue([
|
|
882
|
+
{ key: 'page-1', fromTier: 'hot', toTier: 'warm', success: false, error: 'Test error', timestamp: Date.now(), reason: 'lru_eviction' },
|
|
883
|
+
])
|
|
884
|
+
|
|
885
|
+
manager.setTieredStorageOrchestrator(mockOrchestrator)
|
|
886
|
+
|
|
887
|
+
// Force warning pressure
|
|
888
|
+
manager._forceMemoryPressure('warning')
|
|
889
|
+
|
|
890
|
+
await new Promise(resolve => setTimeout(resolve, 10))
|
|
891
|
+
|
|
892
|
+
const metrics = manager.getDemotionMetrics()
|
|
893
|
+
expect(metrics.failedDemotions).toBeGreaterThan(0)
|
|
894
|
+
})
|
|
895
|
+
|
|
896
|
+
it('should track bytes freed by demotions', async () => {
|
|
897
|
+
const mockOrchestrator = createMockOrchestrator()
|
|
898
|
+
mockOrchestrator.evictLRUFromHot.mockResolvedValue([
|
|
899
|
+
{ key: 'page-1', fromTier: 'hot', toTier: 'warm', success: true, timestamp: Date.now(), reason: 'lru_eviction' },
|
|
900
|
+
])
|
|
901
|
+
// Mock the index entry to have size info
|
|
902
|
+
mockOrchestrator.getIndexEntry = vi.fn().mockReturnValue({
|
|
903
|
+
key: 'page-1',
|
|
904
|
+
tier: 'hot',
|
|
905
|
+
size: 8192,
|
|
906
|
+
lastAccess: Date.now(),
|
|
907
|
+
accessCount: 1,
|
|
908
|
+
created: Date.now(),
|
|
909
|
+
modified: Date.now(),
|
|
910
|
+
dirty: false,
|
|
911
|
+
})
|
|
912
|
+
|
|
913
|
+
manager.setTieredStorageOrchestrator(mockOrchestrator)
|
|
914
|
+
|
|
915
|
+
// Force warning pressure
|
|
916
|
+
manager._forceMemoryPressure('warning')
|
|
917
|
+
|
|
918
|
+
await new Promise(resolve => setTimeout(resolve, 10))
|
|
919
|
+
|
|
920
|
+
const metrics = manager.getDemotionMetrics()
|
|
921
|
+
expect(metrics.bytesFreedByDemotion).toBeGreaterThanOrEqual(0)
|
|
922
|
+
})
|
|
923
|
+
|
|
924
|
+
it('should include demotion metrics in Prometheus export', async () => {
|
|
925
|
+
const mockOrchestrator = createMockOrchestrator()
|
|
926
|
+
mockOrchestrator.evictLRUFromHot.mockResolvedValue([
|
|
927
|
+
{ key: 'page-1', fromTier: 'hot', toTier: 'warm', success: true, timestamp: Date.now(), reason: 'lru_eviction' },
|
|
928
|
+
])
|
|
929
|
+
|
|
930
|
+
manager.setTieredStorageOrchestrator(mockOrchestrator)
|
|
931
|
+
manager._forceMemoryPressure('warning')
|
|
932
|
+
|
|
933
|
+
await new Promise(resolve => setTimeout(resolve, 10))
|
|
934
|
+
|
|
935
|
+
const prometheusMetrics = manager.exportPrometheusMetrics()
|
|
936
|
+
|
|
937
|
+
expect(prometheusMetrics).toContain('postgres_memory_pressure_demotions_total')
|
|
938
|
+
})
|
|
939
|
+
|
|
940
|
+
it('should include demotion metrics in JSON export', async () => {
|
|
941
|
+
const mockOrchestrator = createMockOrchestrator()
|
|
942
|
+
mockOrchestrator.evictLRUFromHot.mockResolvedValue([
|
|
943
|
+
{ key: 'page-1', fromTier: 'hot', toTier: 'warm', success: true, timestamp: Date.now(), reason: 'lru_eviction' },
|
|
944
|
+
])
|
|
945
|
+
|
|
946
|
+
manager.setTieredStorageOrchestrator(mockOrchestrator)
|
|
947
|
+
manager._forceMemoryPressure('warning')
|
|
948
|
+
|
|
949
|
+
await new Promise(resolve => setTimeout(resolve, 10))
|
|
950
|
+
|
|
951
|
+
const jsonMetrics = manager.exportJSONMetrics()
|
|
952
|
+
|
|
953
|
+
expect(jsonMetrics.aggregates).toHaveProperty('pressureTriggeredDemotions')
|
|
954
|
+
})
|
|
955
|
+
})
|
|
956
|
+
|
|
957
|
+
describe('demotion callbacks', () => {
|
|
958
|
+
it('should emit demotion event when pressure-triggered demotion occurs', async () => {
|
|
959
|
+
const mockOrchestrator = createMockOrchestrator()
|
|
960
|
+
mockOrchestrator.evictLRUFromHot.mockResolvedValue([
|
|
961
|
+
{ key: 'page-1', fromTier: 'hot', toTier: 'warm', success: true, timestamp: Date.now(), reason: 'lru_eviction' },
|
|
962
|
+
])
|
|
963
|
+
|
|
964
|
+
manager.setTieredStorageOrchestrator(mockOrchestrator)
|
|
965
|
+
|
|
966
|
+
const demotionListener = vi.fn()
|
|
967
|
+
manager.onPressureDemotion(demotionListener)
|
|
968
|
+
|
|
969
|
+
// Force warning pressure
|
|
970
|
+
manager._forceMemoryPressure('warning')
|
|
971
|
+
|
|
972
|
+
await new Promise(resolve => setTimeout(resolve, 10))
|
|
973
|
+
|
|
974
|
+
expect(demotionListener).toHaveBeenCalledWith(
|
|
975
|
+
expect.objectContaining({
|
|
976
|
+
pressureLevel: 'warning',
|
|
977
|
+
demotions: expect.any(Array),
|
|
978
|
+
totalDemoted: expect.any(Number),
|
|
979
|
+
})
|
|
980
|
+
)
|
|
981
|
+
})
|
|
982
|
+
|
|
983
|
+
it('should allow unsubscribing from demotion events', async () => {
|
|
984
|
+
const mockOrchestrator = createMockOrchestrator()
|
|
985
|
+
mockOrchestrator.evictLRUFromHot.mockResolvedValue([
|
|
986
|
+
{ key: 'page-1', fromTier: 'hot', toTier: 'warm', success: true, timestamp: Date.now(), reason: 'lru_eviction' },
|
|
987
|
+
])
|
|
988
|
+
|
|
989
|
+
manager.setTieredStorageOrchestrator(mockOrchestrator)
|
|
990
|
+
|
|
991
|
+
const demotionListener = vi.fn()
|
|
992
|
+
const unsubscribe = manager.onPressureDemotion(demotionListener)
|
|
993
|
+
|
|
994
|
+
unsubscribe()
|
|
995
|
+
|
|
996
|
+
// Force warning pressure
|
|
997
|
+
manager._forceMemoryPressure('warning')
|
|
998
|
+
|
|
999
|
+
await new Promise(resolve => setTimeout(resolve, 10))
|
|
1000
|
+
|
|
1001
|
+
expect(demotionListener).not.toHaveBeenCalled()
|
|
1002
|
+
})
|
|
1003
|
+
})
|
|
1004
|
+
|
|
1005
|
+
describe('manual demotion trigger', () => {
|
|
1006
|
+
it('should allow manually triggering demotions', async () => {
|
|
1007
|
+
const mockOrchestrator = createMockOrchestrator()
|
|
1008
|
+
mockOrchestrator.evictLRUFromHot.mockResolvedValue([
|
|
1009
|
+
{ key: 'page-1', fromTier: 'hot', toTier: 'warm', success: true, timestamp: Date.now(), reason: 'lru_eviction' },
|
|
1010
|
+
])
|
|
1011
|
+
|
|
1012
|
+
manager.setTieredStorageOrchestrator(mockOrchestrator)
|
|
1013
|
+
|
|
1014
|
+
// Manually trigger demotion
|
|
1015
|
+
const result = await manager.triggerDemotion({
|
|
1016
|
+
hotEvictCount: 5,
|
|
1017
|
+
warmDemoteCount: 2,
|
|
1018
|
+
})
|
|
1019
|
+
|
|
1020
|
+
expect(result.success).toBe(true)
|
|
1021
|
+
expect(result.demotedCount).toBeGreaterThan(0)
|
|
1022
|
+
expect(mockOrchestrator.evictLRUFromHot).toHaveBeenCalledWith(5)
|
|
1023
|
+
})
|
|
1024
|
+
|
|
1025
|
+
it('should return error when orchestrator not connected', async () => {
|
|
1026
|
+
// No orchestrator connected
|
|
1027
|
+
|
|
1028
|
+
const result = await manager.triggerDemotion({
|
|
1029
|
+
hotEvictCount: 5,
|
|
1030
|
+
warmDemoteCount: 2,
|
|
1031
|
+
})
|
|
1032
|
+
|
|
1033
|
+
expect(result.success).toBe(false)
|
|
1034
|
+
expect(result.error).toContain('orchestrator')
|
|
1035
|
+
})
|
|
1036
|
+
})
|
|
1037
|
+
|
|
1038
|
+
describe('memory pressure scenarios', () => {
|
|
1039
|
+
it('should handle rapid pressure escalation', async () => {
|
|
1040
|
+
const mockOrchestrator = createMockOrchestrator()
|
|
1041
|
+
let demotionCount = 0
|
|
1042
|
+
mockOrchestrator.evictLRUFromHot.mockImplementation(() => {
|
|
1043
|
+
demotionCount++
|
|
1044
|
+
return Promise.resolve([
|
|
1045
|
+
{ key: `page-${demotionCount}`, fromTier: 'hot', toTier: 'warm', success: true, timestamp: Date.now(), reason: 'lru_eviction' },
|
|
1046
|
+
])
|
|
1047
|
+
})
|
|
1048
|
+
|
|
1049
|
+
manager.setTieredStorageOrchestrator(mockOrchestrator)
|
|
1050
|
+
|
|
1051
|
+
// Rapid escalation: normal -> warning -> critical -> oom
|
|
1052
|
+
manager._forceMemoryPressure('warning')
|
|
1053
|
+
await new Promise(resolve => setTimeout(resolve, 5))
|
|
1054
|
+
manager._forceMemoryPressure('critical')
|
|
1055
|
+
await new Promise(resolve => setTimeout(resolve, 5))
|
|
1056
|
+
manager._forceMemoryPressure('oom')
|
|
1057
|
+
await new Promise(resolve => setTimeout(resolve, 10))
|
|
1058
|
+
|
|
1059
|
+
// Should have triggered multiple demotions
|
|
1060
|
+
expect(mockOrchestrator.evictLRUFromHot.mock.calls.length).toBeGreaterThanOrEqual(3)
|
|
1061
|
+
})
|
|
1062
|
+
|
|
1063
|
+
it('should handle pressure oscillation without thrashing', async () => {
|
|
1064
|
+
const mockOrchestrator = createMockOrchestrator()
|
|
1065
|
+
mockOrchestrator.evictLRUFromHot.mockResolvedValue([
|
|
1066
|
+
{ key: 'page-1', fromTier: 'hot', toTier: 'warm', success: true, timestamp: Date.now(), reason: 'lru_eviction' },
|
|
1067
|
+
])
|
|
1068
|
+
|
|
1069
|
+
// Configure with minimum interval between demotions
|
|
1070
|
+
const customManager = new MemoryPressureManager({
|
|
1071
|
+
demotionMinIntervalMs: 1000, // 1 second minimum between demotions
|
|
1072
|
+
})
|
|
1073
|
+
customManager.setTieredStorageOrchestrator(mockOrchestrator)
|
|
1074
|
+
|
|
1075
|
+
// Oscillate between warning and normal rapidly
|
|
1076
|
+
customManager._forceMemoryPressure('warning')
|
|
1077
|
+
await new Promise(resolve => setTimeout(resolve, 10))
|
|
1078
|
+
customManager._forceMemoryPressure('normal')
|
|
1079
|
+
await new Promise(resolve => setTimeout(resolve, 10))
|
|
1080
|
+
customManager._forceMemoryPressure('warning')
|
|
1081
|
+
await new Promise(resolve => setTimeout(resolve, 10))
|
|
1082
|
+
customManager._forceMemoryPressure('normal')
|
|
1083
|
+
await new Promise(resolve => setTimeout(resolve, 10))
|
|
1084
|
+
|
|
1085
|
+
// Should only have triggered demotion once due to rate limiting
|
|
1086
|
+
expect(mockOrchestrator.evictLRUFromHot.mock.calls.length).toBeLessThanOrEqual(2)
|
|
1087
|
+
|
|
1088
|
+
customManager.dispose()
|
|
1089
|
+
})
|
|
1090
|
+
|
|
1091
|
+
it('should coordinate with GC hints before demotion', async () => {
|
|
1092
|
+
const mockOrchestrator = createMockOrchestrator()
|
|
1093
|
+
const gcHintCalled = vi.fn()
|
|
1094
|
+
|
|
1095
|
+
const customManager = new MemoryPressureManager({
|
|
1096
|
+
onGCHint: gcHintCalled,
|
|
1097
|
+
gcBeforeDemotion: true, // Try GC before demotion
|
|
1098
|
+
})
|
|
1099
|
+
customManager.setTieredStorageOrchestrator(mockOrchestrator)
|
|
1100
|
+
|
|
1101
|
+
// Force warning pressure
|
|
1102
|
+
customManager._forceMemoryPressure('warning')
|
|
1103
|
+
|
|
1104
|
+
await new Promise(resolve => setTimeout(resolve, 10))
|
|
1105
|
+
|
|
1106
|
+
// GC hint should be called before demotion
|
|
1107
|
+
expect(gcHintCalled).toHaveBeenCalled()
|
|
1108
|
+
|
|
1109
|
+
customManager.dispose()
|
|
1110
|
+
})
|
|
1111
|
+
})
|
|
1112
|
+
})
|
|
1113
|
+
|
|
1114
|
+
// Helper function to create a mock TieredStorageOrchestrator
|
|
1115
|
+
function createMockOrchestrator() {
|
|
1116
|
+
return {
|
|
1117
|
+
evictLRUFromHot: vi.fn().mockResolvedValue([]),
|
|
1118
|
+
runDemotionCycle: vi.fn().mockResolvedValue([]),
|
|
1119
|
+
demoteFromHot: vi.fn().mockResolvedValue({ success: true }),
|
|
1120
|
+
demoteFromWarm: vi.fn().mockResolvedValue({ success: true }),
|
|
1121
|
+
getIndexEntry: vi.fn().mockReturnValue(undefined),
|
|
1122
|
+
getStats: vi.fn().mockReturnValue({
|
|
1123
|
+
index: { totalEntries: 0, byTier: { hot: 0, warm: 0, cold: 0 }, totalSize: 0, dirtyEntries: 0, memoryBytes: 0 },
|
|
1124
|
+
hot: { hits: 0, misses: 0, writes: 0, bytesRead: 0, bytesWritten: 0, errors: 0, hitRatio: 0 },
|
|
1125
|
+
warm: { reads: 0, writes: 0, deletes: 0, bytesRead: 0, bytesWritten: 0 },
|
|
1126
|
+
cold: { reads: 0, writes: 0, deletes: 0, bytesRead: 0, bytesWritten: 0, rangeReads: 0, errors: 0, headRequests: 0, listRequests: 0 },
|
|
1127
|
+
promotions: { coldToWarm: 0, warmToHot: 0, failed: 0 },
|
|
1128
|
+
demotions: { hotToWarm: 0, warmToCold: 0, failed: 0 },
|
|
1129
|
+
health: { hot: 'healthy', warm: 'healthy', cold: 'healthy' },
|
|
1130
|
+
errors: { hot: 0, warm: 0, cold: 0 },
|
|
1131
|
+
}),
|
|
1132
|
+
read: vi.fn(),
|
|
1133
|
+
write: vi.fn(),
|
|
1134
|
+
delete: vi.fn(),
|
|
1135
|
+
promoteToHot: vi.fn(),
|
|
1136
|
+
promoteToWarm: vi.fn(),
|
|
1137
|
+
hasInIndex: vi.fn(),
|
|
1138
|
+
getTier: vi.fn(),
|
|
1139
|
+
clearIndex: vi.fn(),
|
|
1140
|
+
resetStats: vi.fn(),
|
|
1141
|
+
resetHealth: vi.fn(),
|
|
1142
|
+
getConfig: vi.fn(),
|
|
1143
|
+
onMigration: vi.fn(),
|
|
1144
|
+
onError: vi.fn(),
|
|
1145
|
+
onCircuitBreakerChange: vi.fn(),
|
|
1146
|
+
syncDirtyToCold: vi.fn(),
|
|
1147
|
+
} as unknown as any
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
/**
|
|
1151
|
+
* ========================================================================
|
|
1152
|
+
* REFACTOR TESTS: Optimized Memory Pressure Heuristics
|
|
1153
|
+
* Issue: postgres-ksrv.3 - Optimize memory pressure heuristics
|
|
1154
|
+
*
|
|
1155
|
+
* These tests verify the optimized heuristics:
|
|
1156
|
+
* 1. Smoothed pressure detection (EMA)
|
|
1157
|
+
* 2. Adaptive thresholds
|
|
1158
|
+
* 3. Improved OOM prediction
|
|
1159
|
+
* 4. Enhanced metrics
|
|
1160
|
+
* ========================================================================
|
|
1161
|
+
*/
|
|
1162
|
+
describe('MemoryPressureManager - Optimized Heuristics [REFACTOR - postgres-ksrv.3]', () => {
|
|
1163
|
+
let manager: MemoryPressureManager
|
|
1164
|
+
|
|
1165
|
+
beforeEach(() => {
|
|
1166
|
+
manager = new MemoryPressureManager()
|
|
1167
|
+
})
|
|
1168
|
+
|
|
1169
|
+
afterEach(() => {
|
|
1170
|
+
manager.dispose()
|
|
1171
|
+
})
|
|
1172
|
+
|
|
1173
|
+
describe('Smoothed Pressure Detection (EMA)', () => {
|
|
1174
|
+
it('should provide smoothed pressure state', () => {
|
|
1175
|
+
const state = manager.getSmoothedPressureState()
|
|
1176
|
+
|
|
1177
|
+
expect(state).toHaveProperty('emaHeapUsage')
|
|
1178
|
+
expect(state).toHaveProperty('emaPressureLevel')
|
|
1179
|
+
expect(state).toHaveProperty('recentVariance')
|
|
1180
|
+
expect(state).toHaveProperty('trend')
|
|
1181
|
+
expect(state).toHaveProperty('lastRawHeapUsage')
|
|
1182
|
+
})
|
|
1183
|
+
|
|
1184
|
+
it('should update EMA when recording samples', () => {
|
|
1185
|
+
// Force heap usage for testing
|
|
1186
|
+
manager._setCurrentHeapUsage(60 * 1024 * 1024) // 60MB
|
|
1187
|
+
manager.recordMetricSample()
|
|
1188
|
+
|
|
1189
|
+
const state1 = manager.getSmoothedPressureState()
|
|
1190
|
+
|
|
1191
|
+
// Increase heap usage
|
|
1192
|
+
manager._setCurrentHeapUsage(70 * 1024 * 1024) // 70MB
|
|
1193
|
+
manager.recordMetricSample()
|
|
1194
|
+
|
|
1195
|
+
const state2 = manager.getSmoothedPressureState()
|
|
1196
|
+
|
|
1197
|
+
// EMA should have increased
|
|
1198
|
+
expect(state2.emaHeapUsage).toBeGreaterThan(state1.emaHeapUsage)
|
|
1199
|
+
})
|
|
1200
|
+
|
|
1201
|
+
it('should provide smoothed pressure level', () => {
|
|
1202
|
+
const level = manager.getSmoothedPressureLevel()
|
|
1203
|
+
expect(['normal', 'warning', 'critical', 'oom']).toContain(level)
|
|
1204
|
+
})
|
|
1205
|
+
|
|
1206
|
+
it('should detect pressure volatility', () => {
|
|
1207
|
+
// Record samples with varying heap usage to simulate volatility
|
|
1208
|
+
for (let i = 0; i < 10; i++) {
|
|
1209
|
+
const baseUsage = 60 * 1024 * 1024
|
|
1210
|
+
// Alternate high variance
|
|
1211
|
+
const variance = i % 2 === 0 ? 10 * 1024 * 1024 : -10 * 1024 * 1024
|
|
1212
|
+
manager._setCurrentHeapUsage(baseUsage + variance)
|
|
1213
|
+
manager.recordMetricSample()
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
// With high variance, should be volatile
|
|
1217
|
+
const isVolatile = manager.isPressureVolatile()
|
|
1218
|
+
expect(typeof isVolatile).toBe('boolean')
|
|
1219
|
+
})
|
|
1220
|
+
})
|
|
1221
|
+
|
|
1222
|
+
describe('Adaptive Thresholds', () => {
|
|
1223
|
+
it('should return base thresholds with insufficient data', () => {
|
|
1224
|
+
const thresholds = manager.getAdaptiveThresholds()
|
|
1225
|
+
|
|
1226
|
+
expect(thresholds.warningThresholdPercent).toBe(70)
|
|
1227
|
+
expect(thresholds.criticalThresholdPercent).toBe(85)
|
|
1228
|
+
expect(thresholds.oomThresholdPercent).toBe(95)
|
|
1229
|
+
})
|
|
1230
|
+
|
|
1231
|
+
it('should adjust thresholds based on growth rate', async () => {
|
|
1232
|
+
// Record enough samples to enable adaptive thresholds
|
|
1233
|
+
// Simulate rapid growth with time spread
|
|
1234
|
+
for (let i = 0; i < 10; i++) {
|
|
1235
|
+
manager._setCurrentHeapUsage(50 * 1024 * 1024 + i * 5 * 1024 * 1024)
|
|
1236
|
+
manager.recordMetricSample()
|
|
1237
|
+
// Add small delay to spread timestamps for growth rate calculation
|
|
1238
|
+
await new Promise(resolve => setTimeout(resolve, 5))
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
const thresholds = manager.getAdaptiveThresholds()
|
|
1242
|
+
|
|
1243
|
+
// With samples, thresholds should be within valid range
|
|
1244
|
+
// (exact value depends on calculated growth rate and volatility)
|
|
1245
|
+
expect(thresholds.warningThresholdPercent).toBeGreaterThanOrEqual(50)
|
|
1246
|
+
expect(thresholds.warningThresholdPercent).toBeLessThanOrEqual(80)
|
|
1247
|
+
})
|
|
1248
|
+
|
|
1249
|
+
it('should provide adaptive pressure level', () => {
|
|
1250
|
+
const level = manager.getAdaptivePressureLevel()
|
|
1251
|
+
expect(['normal', 'warning', 'critical', 'oom']).toContain(level)
|
|
1252
|
+
})
|
|
1253
|
+
})
|
|
1254
|
+
|
|
1255
|
+
describe('Improved OOM Prediction', () => {
|
|
1256
|
+
it('should return enhanced OOM prediction', () => {
|
|
1257
|
+
const prediction = manager.predictTimeToOOM()
|
|
1258
|
+
|
|
1259
|
+
expect(prediction).toHaveProperty('estimatedMs')
|
|
1260
|
+
expect(prediction).toHaveProperty('confidence')
|
|
1261
|
+
expect(prediction).toHaveProperty('willOOM')
|
|
1262
|
+
// Enhanced fields are optional
|
|
1263
|
+
expect(typeof prediction.estimatedMs).toBe('number')
|
|
1264
|
+
expect(typeof prediction.confidence).toBe('number')
|
|
1265
|
+
expect(typeof prediction.willOOM).toBe('boolean')
|
|
1266
|
+
})
|
|
1267
|
+
|
|
1268
|
+
it('should have low confidence with few samples', () => {
|
|
1269
|
+
const prediction = manager.predictTimeToOOM()
|
|
1270
|
+
expect(prediction.confidence).toBe(0)
|
|
1271
|
+
})
|
|
1272
|
+
|
|
1273
|
+
it('should increase confidence with more samples', async () => {
|
|
1274
|
+
// Record multiple samples with consistent growth and time spread
|
|
1275
|
+
for (let i = 0; i < 15; i++) {
|
|
1276
|
+
manager._setCurrentHeapUsage(50 * 1024 * 1024 + i * 2 * 1024 * 1024)
|
|
1277
|
+
manager.recordMetricSample()
|
|
1278
|
+
// Add small delay for time spread
|
|
1279
|
+
await new Promise(resolve => setTimeout(resolve, 5))
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
const prediction = manager.predictTimeToOOM()
|
|
1283
|
+
// With samples, should have some confidence (may be 0 if growth rate is low)
|
|
1284
|
+
expect(prediction.confidence).toBeGreaterThanOrEqual(0)
|
|
1285
|
+
})
|
|
1286
|
+
|
|
1287
|
+
it('should return Infinity when not growing', () => {
|
|
1288
|
+
// Record samples with stable/decreasing memory
|
|
1289
|
+
for (let i = 0; i < 10; i++) {
|
|
1290
|
+
manager._setCurrentHeapUsage(60 * 1024 * 1024 - i * 1024 * 1024)
|
|
1291
|
+
manager.recordMetricSample()
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
const prediction = manager.predictTimeToOOM()
|
|
1295
|
+
expect(prediction.estimatedMs).toBe(Infinity)
|
|
1296
|
+
expect(prediction.willOOM).toBe(false)
|
|
1297
|
+
})
|
|
1298
|
+
|
|
1299
|
+
it('should predict OOM when growing rapidly', async () => {
|
|
1300
|
+
// Simulate rapid memory growth towards OOM with time spread
|
|
1301
|
+
const memoryLimit = 128 * 1024 * 1024
|
|
1302
|
+
for (let i = 0; i < 15; i++) {
|
|
1303
|
+
// Start at 80% and grow rapidly
|
|
1304
|
+
const usage = memoryLimit * 0.8 + i * 1024 * 1024
|
|
1305
|
+
manager._setCurrentHeapUsage(usage)
|
|
1306
|
+
manager.recordMetricSample()
|
|
1307
|
+
// Add small delay for time spread
|
|
1308
|
+
await new Promise(resolve => setTimeout(resolve, 5))
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
const prediction = manager.predictTimeToOOM()
|
|
1312
|
+
// With rapid growth and time spread, should predict OOM or at least have valid estimate
|
|
1313
|
+
expect(prediction).toHaveProperty('estimatedMs')
|
|
1314
|
+
expect(typeof prediction.estimatedMs).toBe('number')
|
|
1315
|
+
})
|
|
1316
|
+
})
|
|
1317
|
+
|
|
1318
|
+
describe('Enhanced Metrics', () => {
|
|
1319
|
+
it('should include heuristics in JSON export', () => {
|
|
1320
|
+
const metrics = manager.exportJSONMetrics()
|
|
1321
|
+
|
|
1322
|
+
expect(metrics).toHaveProperty('heuristics')
|
|
1323
|
+
expect(metrics.heuristics).toHaveProperty('smoothedState')
|
|
1324
|
+
expect(metrics.heuristics).toHaveProperty('adaptiveThresholds')
|
|
1325
|
+
expect(metrics.heuristics).toHaveProperty('oomPrediction')
|
|
1326
|
+
expect(metrics.heuristics).toHaveProperty('growthRate')
|
|
1327
|
+
expect(metrics.heuristics).toHaveProperty('isVolatile')
|
|
1328
|
+
})
|
|
1329
|
+
|
|
1330
|
+
it('should include growth rate metrics in Prometheus export', () => {
|
|
1331
|
+
const prometheus = manager.exportPrometheusMetrics()
|
|
1332
|
+
|
|
1333
|
+
expect(prometheus).toContain('postgres_memory_growth_rate_bytes_per_sec')
|
|
1334
|
+
expect(prometheus).toContain('postgres_memory_growth_trend')
|
|
1335
|
+
expect(prometheus).toContain('postgres_memory_oom_prediction_ms')
|
|
1336
|
+
expect(prometheus).toContain('postgres_memory_oom_prediction_confidence')
|
|
1337
|
+
})
|
|
1338
|
+
|
|
1339
|
+
it('should include EMA metrics in Prometheus export', () => {
|
|
1340
|
+
const prometheus = manager.exportPrometheusMetrics()
|
|
1341
|
+
|
|
1342
|
+
expect(prometheus).toContain('postgres_memory_heap_ema_bytes')
|
|
1343
|
+
expect(prometheus).toContain('postgres_memory_pressure_volatile')
|
|
1344
|
+
})
|
|
1345
|
+
|
|
1346
|
+
it('should include adaptive threshold metrics in Prometheus export', () => {
|
|
1347
|
+
const prometheus = manager.exportPrometheusMetrics()
|
|
1348
|
+
|
|
1349
|
+
expect(prometheus).toContain('postgres_memory_adaptive_warning_threshold')
|
|
1350
|
+
expect(prometheus).toContain('postgres_memory_adaptive_critical_threshold')
|
|
1351
|
+
})
|
|
1352
|
+
})
|
|
1353
|
+
|
|
1354
|
+
describe('Memory Growth Rate Calculation', () => {
|
|
1355
|
+
it('should return stable for no samples', () => {
|
|
1356
|
+
const rate = manager.getMemoryGrowthRate()
|
|
1357
|
+
expect(rate.trend).toBe('stable')
|
|
1358
|
+
expect(rate.bytesPerSecond).toBe(0)
|
|
1359
|
+
})
|
|
1360
|
+
|
|
1361
|
+
it('should detect increasing trend', async () => {
|
|
1362
|
+
// Record samples with increasing memory and time spread
|
|
1363
|
+
for (let i = 0; i < 10; i++) {
|
|
1364
|
+
manager._setCurrentHeapUsage(50 * 1024 * 1024 + i * 5 * 1024 * 1024)
|
|
1365
|
+
manager.recordMetricSample()
|
|
1366
|
+
// Add small delay for time spread
|
|
1367
|
+
await new Promise(resolve => setTimeout(resolve, 5))
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
const rate = manager.getMemoryGrowthRate()
|
|
1371
|
+
// With time spread, should detect trend or at least positive rate
|
|
1372
|
+
expect(rate.bytesPerSecond).toBeGreaterThanOrEqual(0)
|
|
1373
|
+
expect(['stable', 'increasing']).toContain(rate.trend)
|
|
1374
|
+
})
|
|
1375
|
+
|
|
1376
|
+
it('should detect decreasing trend', async () => {
|
|
1377
|
+
// Record samples with decreasing memory and time spread
|
|
1378
|
+
for (let i = 0; i < 10; i++) {
|
|
1379
|
+
manager._setCurrentHeapUsage(90 * 1024 * 1024 - i * 5 * 1024 * 1024)
|
|
1380
|
+
manager.recordMetricSample()
|
|
1381
|
+
// Add small delay for time spread
|
|
1382
|
+
await new Promise(resolve => setTimeout(resolve, 5))
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
const rate = manager.getMemoryGrowthRate()
|
|
1386
|
+
// With time spread, should detect trend or at least negative rate
|
|
1387
|
+
expect(rate.bytesPerSecond).toBeLessThanOrEqual(0)
|
|
1388
|
+
expect(['stable', 'decreasing']).toContain(rate.trend)
|
|
1389
|
+
})
|
|
1390
|
+
|
|
1391
|
+
it('should handle stable memory usage', () => {
|
|
1392
|
+
// Record samples with stable memory (small variations)
|
|
1393
|
+
for (let i = 0; i < 10; i++) {
|
|
1394
|
+
manager._setCurrentHeapUsage(60 * 1024 * 1024 + (i % 2 === 0 ? 100 : -100))
|
|
1395
|
+
manager.recordMetricSample()
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
const rate = manager.getMemoryGrowthRate()
|
|
1399
|
+
expect(rate.trend).toBe('stable')
|
|
1400
|
+
})
|
|
1401
|
+
})
|
|
1402
|
+
|
|
1403
|
+
describe('Heap Sampling Performance', () => {
|
|
1404
|
+
it('should handle empty heap', () => {
|
|
1405
|
+
// Create manager with mock WASM module
|
|
1406
|
+
const mockHeap = new Uint8Array(0)
|
|
1407
|
+
manager.setWasmHeapSource({ HEAPU8: mockHeap })
|
|
1408
|
+
|
|
1409
|
+
const stats = manager.getMemoryStats()
|
|
1410
|
+
expect(stats.heapUsed).toBe(0)
|
|
1411
|
+
})
|
|
1412
|
+
|
|
1413
|
+
it('should sample large heap efficiently', () => {
|
|
1414
|
+
// Create a large mock heap (64MB)
|
|
1415
|
+
const heapSize = 64 * 1024 * 1024
|
|
1416
|
+
const mockHeap = new Uint8Array(heapSize)
|
|
1417
|
+
|
|
1418
|
+
// Fill ~50% with non-zero data
|
|
1419
|
+
for (let i = 0; i < heapSize; i += 2) {
|
|
1420
|
+
mockHeap[i] = 1
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
manager.setWasmHeapSource({ HEAPU8: mockHeap })
|
|
1424
|
+
|
|
1425
|
+
const start = performance.now()
|
|
1426
|
+
const stats = manager.getMemoryStats()
|
|
1427
|
+
const duration = performance.now() - start
|
|
1428
|
+
|
|
1429
|
+
// Sampling should be fast (< 50ms for 64MB heap in test environment)
|
|
1430
|
+
expect(duration).toBeLessThan(50)
|
|
1431
|
+
|
|
1432
|
+
// Stats should be returned (exact value depends on sampling algorithm)
|
|
1433
|
+
expect(stats).toHaveProperty('heapUsed')
|
|
1434
|
+
expect(typeof stats.heapUsed).toBe('number')
|
|
1435
|
+
})
|
|
1436
|
+
})
|
|
1437
|
+
|
|
1438
|
+
describe('Pressure Level Hysteresis', () => {
|
|
1439
|
+
it('should not oscillate near threshold boundaries', () => {
|
|
1440
|
+
// Set heap just above warning threshold (70%)
|
|
1441
|
+
const memoryLimit = 128 * 1024 * 1024
|
|
1442
|
+
const warningThreshold = memoryLimit * 0.70
|
|
1443
|
+
|
|
1444
|
+
manager._setCurrentHeapUsage(warningThreshold + 1024)
|
|
1445
|
+
manager.recordMetricSample()
|
|
1446
|
+
|
|
1447
|
+
const level1 = manager.getPressureLevel()
|
|
1448
|
+
expect(level1).toBe('warning')
|
|
1449
|
+
|
|
1450
|
+
// Set heap just below warning threshold
|
|
1451
|
+
manager._setCurrentHeapUsage(warningThreshold - 1024)
|
|
1452
|
+
manager.recordMetricSample()
|
|
1453
|
+
|
|
1454
|
+
// With hysteresis, should stay at warning (within hysteresis band)
|
|
1455
|
+
// Only the raw level changes, the smoothed level should be more stable
|
|
1456
|
+
const smoothedLevel = manager.getSmoothedPressureLevel()
|
|
1457
|
+
expect(['normal', 'warning']).toContain(smoothedLevel)
|
|
1458
|
+
})
|
|
1459
|
+
})
|
|
1460
|
+
})
|