pure-js-db 0.0.0-stage → 2.53.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/LICENSE +21 -0
- package/README.md +747 -3
- package/bindings/java/pom.xml +18 -0
- package/bindings/java/src/main/java/purejsdb/PureJsDBClient.java +146 -0
- package/bindings/java/src/main/java/purejsdb/TransactionClient.java +65 -0
- package/bindings/java/src/test/java/TestClient.java +68 -0
- package/bindings/orm/sequelize-adapter.js +1236 -0
- package/bindings/python/purejsdb/client.py +81 -0
- package/bindings/python/setup.py +9 -0
- package/bindings/python/test_client.py +63 -0
- package/config/datagrip-config.md +206 -0
- package/config/grafana-dashboard.json +1510 -0
- package/config/production.config.js +126 -0
- package/config/prometheus-scrape.yml +39 -0
- package/native/index.node +0 -0
- package/package.json +205 -6
- package/scripts/mcp-server.mjs +208 -0
- package/src/adapter/dialect-adapter.js +179 -0
- package/src/adapter/oracle-adapter.js +191 -0
- package/src/ai/ai-service.js +713 -0
- package/src/ai/rag-pipeline.js +160 -0
- package/src/alerting/alert-manager.js +622 -0
- package/src/alerting/index.js +10 -0
- package/src/arrow/arrow-ipc.js +973 -0
- package/src/arrow/flatbuffer.js +521 -0
- package/src/arrow/index.js +261 -0
- package/src/arrow/parquet.js +1525 -0
- package/src/audit/audit-log.js +1345 -0
- package/src/audit/audit-report.js +571 -0
- package/src/audit/index.js +6 -0
- package/src/backpressure/backpressure-controller.js +262 -0
- package/src/backpressure/index.js +6 -0
- package/src/backpressure/write-rate-limiter.js +243 -0
- package/src/backup/backup-manager.js +416 -0
- package/src/backup/index.js +8 -0
- package/src/backup/logical-backup.js +228 -0
- package/src/backup/snapshot.js +111 -0
- package/src/backup/toolkit.js +410 -0
- package/src/bindings/orm/prisma-adapter.js +571 -0
- package/src/bindings/orm/typeorm-adapter.js +477 -0
- package/src/cache/adaptive-cache-size.js +288 -0
- package/src/cache/adaptive-ttl.js +139 -0
- package/src/cache/cache-adapter.js +304 -0
- package/src/cache/circuit-breaker.js +294 -0
- package/src/cache/index.js +31 -0
- package/src/cache/lru-cache.js +353 -0
- package/src/cache/redis-adapter.js +391 -0
- package/src/cache/resilient-adapter.js +391 -0
- package/src/cache/result-cache.js +493 -0
- package/src/cache/semantic-cache.js +339 -0
- package/src/cdc/cdc-engine.js +1061 -0
- package/src/cdc/cdc-handlers.js +289 -0
- package/src/cdc/ddl-capture.js +330 -0
- package/src/cdc/debezium-adapter.js +366 -0
- package/src/cdc/schema-history.js +414 -0
- package/src/changelog/changelog-buffer.js +881 -0
- package/src/changelog/changelog-wal.js +299 -0
- package/src/changelog/linear-regression-predictor.js +186 -0
- package/src/changelog/predictive-growth.js +348 -0
- package/src/changelog/seasonal-predictor.js +450 -0
- package/src/changelog/write-rate-sampler.js +141 -0
- package/src/cli/dump-command.js +944 -0
- package/src/cli/interactive.js +188 -0
- package/src/cli/migrate-command.js +252 -0
- package/src/cli.js +533 -0
- package/src/cluster/failover.js +477 -0
- package/src/cluster/index.js +19 -0
- package/src/cluster/persistent-state.js +203 -0
- package/src/cluster/public-api.js +58 -0
- package/src/cluster/raft-http-transport.js +280 -0
- package/src/cluster/raft-log.js +313 -0
- package/src/cluster/raft.js +912 -0
- package/src/cluster/snapshot-persistence.js +131 -0
- package/src/concurrency/async-mutex.js +365 -0
- package/src/concurrency/circuit-breaker.js +326 -0
- package/src/concurrency/connection-pool.js +409 -0
- package/src/concurrency/connection-session.js +498 -0
- package/src/concurrency/index.js +29 -0
- package/src/concurrency/lock-manager.js +363 -0
- package/src/concurrency/lockfree-executor.js +322 -0
- package/src/concurrency/lockfree-manager.js +570 -0
- package/src/concurrency/mvcc.js +499 -0
- package/src/concurrency/occ-hot-row.js +726 -0
- package/src/concurrency/query-degradation.js +380 -0
- package/src/concurrency/query-isolation.js +374 -0
- package/src/concurrency/shared-memory-pool.js +459 -0
- package/src/concurrency/snapshot-buffer.js +461 -0
- package/src/concurrency/transaction-context.js +193 -0
- package/src/copy/copy-stream.js +643 -0
- package/src/copy/index.js +5 -0
- package/src/core/database.js +1947 -0
- package/src/core/index.js +13 -0
- package/src/daemon/compact-daemon.js +535 -0
- package/src/daemon/index.js +14 -0
- package/src/daemon/soa-daemon-integration.js +333 -0
- package/src/ddl/online-ddl.js +348 -0
- package/src/disruptor/disruptor.js +348 -0
- package/src/disruptor/event-bus.js +238 -0
- package/src/disruptor/event-pool.js +62 -0
- package/src/disruptor/index.js +31 -0
- package/src/disruptor/ring-buffer.js +150 -0
- package/src/disruptor/sequence.js +88 -0
- package/src/disruptor/wait-strategy.js +160 -0
- package/src/engine/public-api.js +210 -0
- package/src/executor/asof-join-executor.js +265 -0
- package/src/executor/bitmap-filter.js +1382 -0
- package/src/executor/compiled-expression.js +472 -0
- package/src/executor/compiled-predicate.js +458 -0
- package/src/executor/constraint-executor.js +577 -0
- package/src/executor/copy-executor.js +210 -0
- package/src/executor/cte/recursive-cte.js +89 -0
- package/src/executor/cte-executor.js +501 -0
- package/src/executor/cursor-executor.js +216 -0
- package/src/executor/database.js +41 -0
- package/src/executor/ddl-executor.js +3531 -0
- package/src/executor/dml-executor.js +3557 -0
- package/src/executor/executor-worker.js +331 -0
- package/src/executor/executor.js +10889 -0
- package/src/executor/explain-analyzer.js +422 -0
- package/src/executor/explain-executor.js +324 -0
- package/src/executor/expression.js +4972 -0
- package/src/executor/foreign-key-executor.js +691 -0
- package/src/executor/graph-table-executor.js +451 -0
- package/src/executor/grouping-executor.js +251 -0
- package/src/executor/hotpath.js +232 -0
- package/src/executor/hybrid-search-executor.js +326 -0
- package/src/executor/incremental-live-query.js +866 -0
- package/src/executor/index-maintenance-executor.js +731 -0
- package/src/executor/index.js +16 -0
- package/src/executor/info-schema-executor.js +123 -0
- package/src/executor/join/lateral-join.js +64 -0
- package/src/executor/join-executor.js +530 -0
- package/src/executor/lineage-executor.js +85 -0
- package/src/executor/live-query-manager.js +350 -0
- package/src/executor/loop-unroll.js +539 -0
- package/src/executor/match-recognize-executor.js +918 -0
- package/src/executor/multi-stream-wal.js +140 -0
- package/src/executor/nl2sql-executor.js +309 -0
- package/src/executor/parallel-dml.js +258 -0
- package/src/executor/pivot-executor.js +458 -0
- package/src/executor/pragma-executor.js +661 -0
- package/src/executor/select-executor.js +857 -0
- package/src/executor/sequence.js +139 -0
- package/src/executor/sql-reconstructor.js +296 -0
- package/src/executor/subquery-cache.js +186 -0
- package/src/executor/subquery-executor.js +1390 -0
- package/src/executor/system-catalog.js +731 -0
- package/src/executor/table-function-executor.js +656 -0
- package/src/executor/topn.js +103 -0
- package/src/executor/transaction-executor.js +926 -0
- package/src/executor/trigger-executor.js +441 -0
- package/src/executor/v8-turbofan-optimizer.js +363 -0
- package/src/executor/vector-acceleration.js +456 -0
- package/src/executor/vector-executor.js +847 -0
- package/src/executor/vectorized-columnar-engine.js +1130 -0
- package/src/executor/vectorized-executor-v2.js +993 -0
- package/src/executor/view-executor.js +149 -0
- package/src/executor/wal.js +1945 -0
- package/src/executor/wasm-simd-engine.js +929 -0
- package/src/executor/window-functions.js +894 -0
- package/src/fdw/fdw-manager.js +642 -0
- package/src/fdw/index.js +5 -0
- package/src/geo/geometry.js +447 -0
- package/src/geo/index.js +16 -0
- package/src/geo/spatial-functions.js +1241 -0
- package/src/graph/graph-helper.js +243 -0
- package/src/graph/pgq-matcher.js +2545 -0
- package/src/graph/property-graph.js +123 -0
- package/src/graphql-bridge.js +881 -0
- package/src/hotspot/access-tracker.js +188 -0
- package/src/hotspot/hotspot-detector.js +140 -0
- package/src/hotspot/hotspot-prefetcher.js +210 -0
- package/src/hotspot/index.js +7 -0
- package/src/http-api.js +1182 -0
- package/src/http-server/handlers/audit.js +224 -0
- package/src/http-server/handlers/changes-feed.js +261 -0
- package/src/http-server/handlers/management.js +464 -0
- package/src/http-server/handlers/query.js +573 -0
- package/src/http-server/handlers/transaction.js +251 -0
- package/src/http-server/index.js +89 -0
- package/src/http-server/openapi.js +656 -0
- package/src/http-server/router.js +120 -0
- package/src/http-server/server.js +1915 -0
- package/src/http-server/tls.js +126 -0
- package/src/http-server/ws-server.js +873 -0
- package/src/index/adaptive-hash-index.js +176 -0
- package/src/index/bitmap-index.js +429 -0
- package/src/index/brin-index.js +246 -0
- package/src/index/btree-index.js +428 -0
- package/src/index/btree.js +690 -0
- package/src/index/diskann-index.js +1903 -0
- package/src/index/fulltext/fulltext-index.js +66 -0
- package/src/index/fulltext/index.js +3 -0
- package/src/index/fulltext/inverted-index.js +197 -0
- package/src/index/fulltext/tokenizer.js +154 -0
- package/src/index/fulltext.js +287 -0
- package/src/index/gin-index.js +316 -0
- package/src/index/gist-index.js +463 -0
- package/src/index/gist-ops.js +325 -0
- package/src/index/graph-compressor.js +505 -0
- package/src/index/hash-index.js +180 -0
- package/src/index/hnsw-index.js +1232 -0
- package/src/index/hnsw-pq-index.js +1147 -0
- package/src/index/index-auto-tuner.js +1341 -0
- package/src/index/index-interface.js +364 -0
- package/src/index/index-selector.js +523 -0
- package/src/index/index.js +28 -0
- package/src/index/ivfpqsq-index.js +1163 -0
- package/src/index/offheap-btree-index.js +395 -0
- package/src/index/offheap-btree.js +748 -0
- package/src/index/product-quantizer.js +1447 -0
- package/src/index/robin-hood-hash-index.js +384 -0
- package/src/index/rtree-index.js +982 -0
- package/src/index/scalar-quantizer.js +411 -0
- package/src/index/semantic-index.js +283 -0
- package/src/index/string-interner.js +238 -0
- package/src/index/timestamp-index-advisor.js +491 -0
- package/src/index/timestamp-index-compressed.js +800 -0
- package/src/index/timestamp-index-compressor.js +547 -0
- package/src/index/timestamp-index.js +579 -0
- package/src/index/vector-index-serializer.js +499 -0
- package/src/index/vector-index-stats.js +450 -0
- package/src/index/vector-index.js +615 -0
- package/src/index-v3.js +27 -0
- package/src/index.js +33 -0
- package/src/internal/public-api.js +198 -0
- package/src/lineage/column-lineage.js +393 -0
- package/src/lineage/index.js +11 -0
- package/src/lineage/lineage-store.js +701 -0
- package/src/lineage/table-lineage.js +68 -0
- package/src/mcp/index.js +176 -0
- package/src/mcp/mcp-server.js +334 -0
- package/src/mcp/protocol.js +195 -0
- package/src/mcp/tools/backup-restore.js +131 -0
- package/src/mcp/tools/cdc-tools.js +201 -0
- package/src/mcp/tools/describe-table.js +100 -0
- package/src/mcp/tools/execute-sql.js +210 -0
- package/src/mcp/tools/explain-query.js +75 -0
- package/src/mcp/tools/index-management.js +191 -0
- package/src/mcp/tools/lineage.js +64 -0
- package/src/mcp/tools/list-tables.js +46 -0
- package/src/mcp/tools/monitoring.js +195 -0
- package/src/mcp/tools/schema-management.js +229 -0
- package/src/mcp/tools/text-to-sql.js +84 -0
- package/src/mcp/tools/transaction-management.js +191 -0
- package/src/mcp/tools/vector-search.js +101 -0
- package/src/mcp/transport/http.js +352 -0
- package/src/mcp/transport/stdio.js +117 -0
- package/src/memory/memory-manager.js +437 -0
- package/src/migration/migrator.js +389 -0
- package/src/monitor/index.js +36 -0
- package/src/monitor/metrics-exporter.js +517 -0
- package/src/monitor/monitor.js +385 -0
- package/src/monitor/performance-monitor.js +204 -0
- package/src/monitor/soa-monitor.js +628 -0
- package/src/multitenant/index.js +1 -0
- package/src/multitenant/tenant-manager.js +238 -0
- package/src/native/native-acceleration.js +3493 -0
- package/src/optimizer/adaptive-optimizer.js +666 -0
- package/src/optimizer/cse.js +383 -0
- package/src/optimizer/decorrelator.js +958 -0
- package/src/optimizer/derived-table-eliminator.js +367 -0
- package/src/optimizer/explain-visualizer.js +266 -0
- package/src/optimizer/histogram.js +290 -0
- package/src/optimizer/index.js +78 -0
- package/src/optimizer/jit-compiler.js +1200 -0
- package/src/optimizer/join-order-optimizer.js +717 -0
- package/src/optimizer/limit-pushdown.js +70 -0
- package/src/optimizer/optimized-plan.js +54 -0
- package/src/optimizer/optimizer-rule.js +295 -0
- package/src/optimizer/optimizer.js +1515 -0
- package/src/optimizer/pipeline.js +263 -0
- package/src/optimizer/predicate-pushdown.js +599 -0
- package/src/optimizer/query-plan-cache.js +275 -0
- package/src/optimizer/rule-adapters.js +343 -0
- package/src/optimizer/subquery-flattener.js +689 -0
- package/src/optimizer/timestamp-query-rewriter.js +498 -0
- package/src/orm/collection.js +160 -0
- package/src/orm/errors.js +76 -0
- package/src/orm/hooks.js +184 -0
- package/src/orm/index.js +93 -0
- package/src/orm/mixins/soft-delete.js +271 -0
- package/src/orm/model.js +951 -0
- package/src/orm/query-builder.js +681 -0
- package/src/orm/relations.js +303 -0
- package/src/orm/schema.js +443 -0
- package/src/orm/seeder.js +350 -0
- package/src/parallel/dml-pushdown-executor.js +430 -0
- package/src/parallel/dml-worker.js +151 -0
- package/src/parallel/morsel-queue.js +358 -0
- package/src/parallel/parallel-executor.js +277 -0
- package/src/parallel/pipeline-executor.js +423 -0
- package/src/parallel/shared-cache.js +206 -0
- package/src/parser/ast.js +3853 -0
- package/src/parser/parser.js +7909 -0
- package/src/parser/tokenizer.js +542 -0
- package/src/query/relation-preloader.js +327 -0
- package/src/replication/index.js +15 -0
- package/src/replication/lag-monitor.js +163 -0
- package/src/replication/master.js +117 -0
- package/src/replication/multi-master.js +495 -0
- package/src/replication/read-replica.js +490 -0
- package/src/replication/replica.js +395 -0
- package/src/replication/replication-http-transport.js +421 -0
- package/src/replication/wal-standby.js +334 -0
- package/src/runtime/index.js +4 -0
- package/src/runtime/plpgsql-interpreter.js +766 -0
- package/src/runtime/plpgsql-parser.js +852 -0
- package/src/runtime/stored-procedure.js +149 -0
- package/src/runtime/udf.js +194 -0
- package/src/schema/dsl-parser.js +896 -0
- package/src/schema/index.js +113 -0
- package/src/schema/introspector.js +246 -0
- package/src/schema/pg-migrator.js +599 -0
- package/src/schema/schema-differ.js +504 -0
- package/src/schema/schema-versioning.js +426 -0
- package/src/schema/type-generator.js +537 -0
- package/src/sdk/README.md +277 -0
- package/src/sdk/go/README.md +19 -0
- package/src/sdk/go/go.mod +3 -0
- package/src/sdk/go/pureclient/client.go +663 -0
- package/src/sdk/go/pureclient/client_test.go +413 -0
- package/src/sdk/java/README.md +19 -0
- package/src/sdk/java/pom.xml +87 -0
- package/src/sdk/java/pureclient/JsonUtil.java +366 -0
- package/src/sdk/java/pureclient/PureClient.java +835 -0
- package/src/sdk/java/pureclient/PureClientTest.java +570 -0
- package/src/sdk/java/pureclient/PureError.java +158 -0
- package/src/sdk/java/pureclient/Transaction.java +242 -0
- package/src/sdk/javascript/README.md +19 -0
- package/src/sdk/javascript/cdc.js +230 -0
- package/src/sdk/javascript/client.js +420 -0
- package/src/sdk/javascript/errors.js +66 -0
- package/src/sdk/javascript/index.js +35 -0
- package/src/sdk/javascript/pool.js +199 -0
- package/src/sdk/javascript/transaction.js +114 -0
- package/src/sdk/php/README.md +19 -0
- package/src/sdk/php/composer.json +30 -0
- package/src/sdk/php/src/PureClient.php +550 -0
- package/src/sdk/php/src/PureError.php +130 -0
- package/src/sdk/php/src/Transaction.php +172 -0
- package/src/sdk/public-api.js +16 -0
- package/src/sdk/python/README.md +19 -0
- package/src/sdk/python/pure_client.py +388 -0
- package/src/sdk/react-native/README.md +161 -0
- package/src/sdk/react-native/async-storage-adapter.js +147 -0
- package/src/sdk/react-native/embedded/embedded-client.js +266 -0
- package/src/sdk/react-native/embedded/hermes-jsi-bridge.js +207 -0
- package/src/sdk/react-native/embedded/sqlite-kv-adapter.js +345 -0
- package/src/sdk/react-native/expo-file-adapter.js +315 -0
- package/src/sdk/react-native/index.js +52 -0
- package/src/sdk/react-native/mobile-client.js +759 -0
- package/src/sdk/react-native/sync-manager.js +455 -0
- package/src/sdk/react-native/vector-search.js +322 -0
- package/src/sdk/rust/CHANGELOG.md +104 -0
- package/src/sdk/rust/Cargo.toml +35 -0
- package/src/sdk/rust/LICENSE +21 -0
- package/src/sdk/rust/PUBLISHING.md +202 -0
- package/src/sdk/rust/README.md +471 -0
- package/src/sdk/rust/RELEASE-CHECKLIST.md +340 -0
- package/src/sdk/rust/examples/basic_usage.rs +181 -0
- package/src/sdk/rust/scripts/publish.sh +233 -0
- package/src/sdk/rust/src/client.rs +481 -0
- package/src/sdk/rust/src/error.rs +95 -0
- package/src/sdk/rust/src/index/hnswpq.rs +626 -0
- package/src/sdk/rust/src/index/mod.rs +7 -0
- package/src/sdk/rust/src/lib.rs +66 -0
- package/src/sdk/rust/src/models.rs +198 -0
- package/src/sdk/rust/src/transaction.rs +123 -0
- package/src/sdk/rust/tests/concurrent_vector_search.rs +534 -0
- package/src/sdk/wechat/README.md +19 -0
- package/src/sdk/wechat/index.js +42 -0
- package/src/sdk/wechat/pure-js-db.js +105 -0
- package/src/sdk/wechat/stubs/empty.js +85 -0
- package/src/sdk/wechat/wx-database.js +225 -0
- package/src/sdk/wechat/wx-lite.js +191 -0
- package/src/sdk/wechat/wx-sqlite-adapter.js +655 -0
- package/src/sdk/wechat/wx-sqlite-database.js +146 -0
- package/src/sdk/wechat/wx-storage-adapter.js +609 -0
- package/src/security/api-key.js +215 -0
- package/src/security/auth.js +179 -0
- package/src/security/column-encryption-optimized.js +352 -0
- package/src/security/column-encryption.js +330 -0
- package/src/security/crypto-provider.js +345 -0
- package/src/security/data-masking.js +370 -0
- package/src/security/field-encryption.js +238 -0
- package/src/security/index.js +41 -0
- package/src/security/jwt.js +202 -0
- package/src/security/rbac.js +702 -0
- package/src/security/regex-guard.js +277 -0
- package/src/security/row-level-security.js +192 -0
- package/src/security/secure-erase.js +258 -0
- package/src/security/sql-firewall.js +185 -0
- package/src/security/sql-injection-detector.js +647 -0
- package/src/security/sql-rate-limiter.js +168 -0
- package/src/security/ssrf-guard.js +790 -0
- package/src/security/timing-safe.js +203 -0
- package/src/serializer/codecs.js +1155 -0
- package/src/serializer/index.js +13 -0
- package/src/serializer/serializer.js +468 -0
- package/src/server/public-api.js +14 -0
- package/src/server.js +31 -0
- package/src/service/log-service.js +593 -0
- package/src/sharding/cluster-manager.js +161 -0
- package/src/sharding/consistent-hash-ring-optimized.js +421 -0
- package/src/sharding/consistent-hash-ring.js +252 -0
- package/src/sharding/consistent-hash.js +175 -0
- package/src/sharding/distributed-executor.js +120 -0
- package/src/sharding/distributed-lock.js +256 -0
- package/src/sharding/distributed-transaction.js +262 -0
- package/src/sharding/failure-recovery.js +267 -0
- package/src/sharding/global-tx-coordinator.js +1299 -0
- package/src/sharding/index.js +16 -0
- package/src/sharding/parallel-write-coordinator.js +370 -0
- package/src/sharding/partition-manager.js +382 -0
- package/src/sharding/pushdown-executor.js +1101 -0
- package/src/sharding/scatter-gather-executor.js +460 -0
- package/src/sharding/shard-executor.js +624 -0
- package/src/sharding/shard-manager.js +717 -0
- package/src/sharding/three-phase-commit.js +699 -0
- package/src/sharding/two-phase-commit.js +1243 -0
- package/src/snapshot/historical-reader.js +257 -0
- package/src/snapshot/index.js +7 -0
- package/src/storage/batch-writer.js +110 -0
- package/src/storage/binary-storage-adapter.js +738 -0
- package/src/storage/blob-kv-adapter.js +253 -0
- package/src/storage/buffer-pool.js +458 -0
- package/src/storage/buffered-kv-adapter.js +325 -0
- package/src/storage/cold-data-migrator.js +519 -0
- package/src/storage/column-compression.js +878 -0
- package/src/storage/column-store-table.js +627 -0
- package/src/storage/column-store.js +1094 -0
- package/src/storage/columnar-file.js +489 -0
- package/src/storage/columnar-storage.js +485 -0
- package/src/storage/compact-recovery.js +394 -0
- package/src/storage/encrypted-kv-adapter.js +271 -0
- package/src/storage/file-kv-adapter.js +468 -0
- package/src/storage/hybrid-engine.js +1480 -0
- package/src/storage/importer.js +125 -0
- package/src/storage/in-memory-table-storage.js +291 -0
- package/src/storage/index.js +78 -0
- package/src/storage/io-thread-pool.js +240 -0
- package/src/storage/io-worker.js +42 -0
- package/src/storage/kv-adapter.js +322 -0
- package/src/storage/lsm/active-table.js +240 -0
- package/src/storage/lsm/block-cache.js +64 -0
- package/src/storage/lsm/bloom-filter.js +174 -0
- package/src/storage/lsm/compactor.js +460 -0
- package/src/storage/lsm/database-manager.js +177 -0
- package/src/storage/lsm/full-text-search.js +385 -0
- package/src/storage/lsm/index.js +14 -0
- package/src/storage/lsm/internal-key.js +140 -0
- package/src/storage/lsm/lsm-engine.js +798 -0
- package/src/storage/lsm/lsm-kv-adapter.js +137 -0
- package/src/storage/lsm/memtable.js +628 -0
- package/src/storage/lsm/mmap-region.js +289 -0
- package/src/storage/lsm/sstable-reader.js +403 -0
- package/src/storage/lsm/sstable-repair.js +437 -0
- package/src/storage/lsm/sstable-writer.js +202 -0
- package/src/storage/lsm/wal.js +800 -0
- package/src/storage/offheap-allocator.js +298 -0
- package/src/storage/page-checksum.js +221 -0
- package/src/storage/page-compression.js +95 -0
- package/src/storage/page-store.js +418 -0
- package/src/storage/page.js +261 -0
- package/src/storage/persisted-db.js +1885 -0
- package/src/storage/persisted-table-storage.js +280 -0
- package/src/storage/read-ahead.js +95 -0
- package/src/storage/shared-storage.js +688 -0
- package/src/storage/soa-table-storage.js +418 -0
- package/src/storage/storage-engine.js +187 -0
- package/src/storage/table-storage.js +215 -0
- package/src/storage/tiered-kv-adapter.js +381 -0
- package/src/storage/version-history-cleaner.js +888 -0
- package/src/studio/index.html +1503 -0
- package/src/studio/server.js +204 -0
- package/src/sync/change-log.js +144 -0
- package/src/sync/index.js +2 -0
- package/src/sync/sync-engine.js +428 -0
- package/src/sync/sync-handlers.js +196 -0
- package/src/test-utils.js +11 -0
- package/src/transaction/index.js +8 -0
- package/src/transaction/read-uncommitted.js +37 -0
- package/src/transaction/repeatable-read.js +380 -0
- package/src/transaction/rr-transaction-manager.js +262 -0
- package/src/transaction/ru-transaction-manager.js +76 -0
- package/src/transaction/serializable.js +205 -0
- package/src/transaction/transaction-manager.js +259 -0
- package/src/transaction/tx-manager.js +490 -0
- package/src/transaction/tx-state.js +43 -0
- package/src/tx/bfmark-snapshot.js +193 -0
- package/src/tx/row-lock.js +246 -0
- package/src/tx/ssi.js +229 -0
- package/src/types/datetime.js +621 -0
- package/src/types/decimal.js +220 -0
- package/src/types/enum-type.js +131 -0
- package/src/types/interval.js +565 -0
- package/src/types/json-type.js +376 -0
- package/src/types/jsonb.js +227 -0
- package/src/types/udt.js +180 -0
- package/src/utils/batch-processor.js +46 -0
- package/src/utils/debug-logger.js +116 -0
- package/src/utils/index-helper.js +74 -0
- package/src/utils/index.js +9 -0
- package/src/utils/join-engine.js +1713 -0
- package/src/utils/object-pool.js +610 -0
- package/src/utils/query-tracer.js +489 -0
- package/src/utils/timeout-util.js +92 -0
- package/src/utils/tx-log-persist.js +197 -0
- package/src/utils/undo-compress.js +93 -0
- package/src/utils/undo-log.js +196 -0
- package/src/utils/wal-common.js +138 -0
- package/src/vector/adaptive-ef.js +213 -0
- package/src/vector/distributed-vector-search.js +542 -0
- package/src/vector/federated-vector-search.js +707 -0
- package/src/vector/gpu-distance.js +647 -0
- package/src/vector/gpu-sq-distance.js +444 -0
- package/src/vector/hnsw-acceleration.js +298 -0
- package/src/vector/hnsw-profiler.js +341 -0
- package/src/vector/index.js +90 -0
- package/src/vector/public-api.js +29 -0
- package/src/vector/recall-benchmark.js +333 -0
- package/src/vector/simd-distance.js +511 -0
- package/src/vector/vector-scan.js +646 -0
- package/src/vector/wasm-hnsw.js +714 -0
- package/src/version/version-chain-manager.js +1277 -0
- package/src/version/version-delta-encoder.js +819 -0
- package/src/version.js +19 -0
- package/src/view/incremental-refresher.js +1015 -0
- package/src/view/index.js +12 -0
- package/src/view/materialized-view.js +204 -0
- package/src/view/view-manager.js +1368 -0
- package/src/wasm/bridge.js +79 -0
- package/src/worker/query-dispatcher.js +277 -0
- package/src/worker/session-worker-pool.js +355 -0
- package/src/worker/task-defs.js +330 -0
- package/src/worker/task-worker.js +406 -0
- package/src/worker/worker-pool.js +651 -0
- package/src/xml/xml-support.js +647 -0
- package/types/pure-js-db.d.ts +1988 -0
- package/types/schema.d.ts +65 -0
|
@@ -0,0 +1,651 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* worker-pool.js — Worker Thread 池化管理
|
|
3
|
+
*
|
|
4
|
+
* 管理一组 Worker Thread,支持任务分发、空闲复用、超时回收。
|
|
5
|
+
*
|
|
6
|
+
* 用法:
|
|
7
|
+
* import { WorkerPool } from './worker-pool.js';
|
|
8
|
+
* const pool = new WorkerPool({ size: 4 });
|
|
9
|
+
* await pool.init();
|
|
10
|
+
*
|
|
11
|
+
* // 并行排序: 数据分块 → 各 Worker 排序 → 主线程 K-way Merge
|
|
12
|
+
* const chunks = splitIntoChunks(data, pool.size);
|
|
13
|
+
* const tasks = chunks.map(c => createSortTask(c, 'id'));
|
|
14
|
+
* const sortedChunks = await pool.execAll(tasks);
|
|
15
|
+
* const result = kWayMerge(sortedChunks, (a,b) => a.id - b.id);
|
|
16
|
+
*
|
|
17
|
+
* // 并行过滤: 数据分块 → 各 Worker 过滤 → 结果拼接
|
|
18
|
+
* const filterTasks = chunks.map(c => createFilterTask(c, row => row.age > 18));
|
|
19
|
+
* const filtered = await pool.execAll(filterTasks);
|
|
20
|
+
* const all = filtered.flat();
|
|
21
|
+
*
|
|
22
|
+
* await pool.terminate();
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { Worker } from 'node:worker_threads';
|
|
26
|
+
import { fileURLToPath } from 'node:url';
|
|
27
|
+
import path from 'node:path';
|
|
28
|
+
import os from 'node:os';
|
|
29
|
+
import { performance } from 'node:perf_hooks';
|
|
30
|
+
import { WORKER_TIMEOUT } from './task-defs.js';
|
|
31
|
+
import { MorselQueue } from '../parallel/morsel-queue.js';
|
|
32
|
+
|
|
33
|
+
// Worker 脚本的绝对路径
|
|
34
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
35
|
+
const __dirname = path.dirname(__filename);
|
|
36
|
+
const WORKER_SCRIPT = path.join(__dirname, 'task-worker.js');
|
|
37
|
+
|
|
38
|
+
// ── 默认配置 ──
|
|
39
|
+
|
|
40
|
+
/** 默认池大小: CPU 核心数 - 1(保留一个给主线程) */
|
|
41
|
+
const DEFAULT_POOL_SIZE = Math.max(1, (os.cpus().length || 4) - 1);
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @typedef {object} WorkerPoolOptions
|
|
45
|
+
* @property {number} [size=DEFAULT_POOL_SIZE] - Worker 数量
|
|
46
|
+
* @property {number} [taskTimeout=WORKER_TIMEOUT] - 单个任务超时(ms)
|
|
47
|
+
* @property {boolean} [lazy=false] - 延迟初始化(首次任务时才创建 Worker)
|
|
48
|
+
* @property {SharedArrayBuffer} [sharedBuffer] - 共享内存(通过 workerData 传给所有 Worker)
|
|
49
|
+
*/
|
|
50
|
+
export class WorkerPool {
|
|
51
|
+
/**
|
|
52
|
+
* @param {WorkerPoolOptions} [options]
|
|
53
|
+
*/
|
|
54
|
+
constructor(options = {}) {
|
|
55
|
+
const opts = {
|
|
56
|
+
size: DEFAULT_POOL_SIZE,
|
|
57
|
+
taskTimeout: WORKER_TIMEOUT,
|
|
58
|
+
lazy: false,
|
|
59
|
+
log: null,
|
|
60
|
+
...options,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/** @type {number} Worker 数量 */
|
|
64
|
+
this.size = opts.size;
|
|
65
|
+
|
|
66
|
+
/** @type {number} 任务超时(ms) */
|
|
67
|
+
this.taskTimeout = opts.taskTimeout;
|
|
68
|
+
|
|
69
|
+
/** @type {boolean} 是否已初始化 */
|
|
70
|
+
this.initialized = false;
|
|
71
|
+
|
|
72
|
+
/** @type {object[]} Worker 状态列表 */
|
|
73
|
+
this._workers = [];
|
|
74
|
+
|
|
75
|
+
/** @type {number} 下一个任务 ID */
|
|
76
|
+
this._nextTaskId = 1;
|
|
77
|
+
|
|
78
|
+
/** @type {Map<number, { resolve, reject, timeout }>} 待处理的 Promise */
|
|
79
|
+
this._pending = new Map();
|
|
80
|
+
|
|
81
|
+
/** @type {Map<number, number>} 任务开始时间(用于计时) */
|
|
82
|
+
this._taskStartTimes = new Map();
|
|
83
|
+
|
|
84
|
+
// 延迟初始化时在首次 exec 前创建 Worker
|
|
85
|
+
this._lazy = opts.lazy;
|
|
86
|
+
|
|
87
|
+
/** @type {function(string):void} 日志函数 */
|
|
88
|
+
this._log = opts.log || null;
|
|
89
|
+
|
|
90
|
+
/** @type {SharedArrayBuffer|null} 共享内存(通过 workerData 传给 Worker) */
|
|
91
|
+
this._sharedBuffer = opts.sharedBuffer || null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* 内部日志(仅在有日志函数时输出)
|
|
96
|
+
*/
|
|
97
|
+
_debug(event, details = '') {
|
|
98
|
+
if (this._log) {
|
|
99
|
+
this._log(`[POOL] ${event}: ${details}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* 设置共享内存(必须在 init 之前或 terminate 之后调用)
|
|
105
|
+
* @param {SharedArrayBuffer|null} buffer
|
|
106
|
+
*/
|
|
107
|
+
setSharedBuffer(buffer) {
|
|
108
|
+
if (this.initialized) {
|
|
109
|
+
throw new Error('Worker Pool 已初始化,请先 terminate() 再设置 sharedBuffer');
|
|
110
|
+
}
|
|
111
|
+
this._sharedBuffer = buffer;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* 获取共享内存
|
|
116
|
+
* @returns {SharedArrayBuffer|null}
|
|
117
|
+
*/
|
|
118
|
+
getSharedBuffer() {
|
|
119
|
+
return this._sharedBuffer;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* 初始化 Worker Pool(创建所有 Worker)
|
|
124
|
+
*/
|
|
125
|
+
async init() {
|
|
126
|
+
if (this.initialized) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
this.initialized = true;
|
|
130
|
+
|
|
131
|
+
this._debug('INIT_START', `size=${this.size}, lazy=${this._lazy}`);
|
|
132
|
+
|
|
133
|
+
const promises = [];
|
|
134
|
+
for (let i = 0; i < this.size; i++) {
|
|
135
|
+
promises.push(this._createWorker());
|
|
136
|
+
}
|
|
137
|
+
await Promise.all(promises);
|
|
138
|
+
|
|
139
|
+
this._debug('INIT_DONE', `workers=${this._workers.length}`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* 创建一个 Worker
|
|
144
|
+
*/
|
|
145
|
+
async _createWorker() {
|
|
146
|
+
const workerOptions = this._sharedBuffer
|
|
147
|
+
? { workerData: { sab: this._sharedBuffer } }
|
|
148
|
+
: {};
|
|
149
|
+
const worker = new Worker(WORKER_SCRIPT, workerOptions);
|
|
150
|
+
const workerId = this._workers.length;
|
|
151
|
+
|
|
152
|
+
const entry = {
|
|
153
|
+
worker,
|
|
154
|
+
busy: false,
|
|
155
|
+
id: workerId,
|
|
156
|
+
taskCount: 0,
|
|
157
|
+
totalTime: 0,
|
|
158
|
+
};
|
|
159
|
+
this._workers.push(entry);
|
|
160
|
+
|
|
161
|
+
return new Promise((resolve) => {
|
|
162
|
+
// worker 就绪后 resolve
|
|
163
|
+
worker.on('online', () => {
|
|
164
|
+
this._debug('WORKER_ONLINE', `id=${workerId}`);
|
|
165
|
+
resolve();
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
worker.on('message', (msg) => {
|
|
169
|
+
this._handleResult(entry, msg);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
worker.on('error', (err) => {
|
|
173
|
+
this._debug('WORKER_ERROR', `id=${workerId} error="${err.message}"`);
|
|
174
|
+
this._handleError(entry, err);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
worker.on('exit', (code) => {
|
|
178
|
+
this._debug('WORKER_EXIT', `id=${workerId} code=${code}`);
|
|
179
|
+
if (code !== 0) {
|
|
180
|
+
this._handleError(entry, new Error(`Worker 异常退出, code=${code}`));
|
|
181
|
+
}
|
|
182
|
+
// 从 workers 列表中移除
|
|
183
|
+
const idx = this._workers.indexOf(entry);
|
|
184
|
+
if (idx !== -1) {
|
|
185
|
+
this._workers.splice(idx, 1);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* 处理 Worker 返回结果
|
|
193
|
+
*/
|
|
194
|
+
_handleResult(entry, msg) {
|
|
195
|
+
entry.busy = false;
|
|
196
|
+
const pending = this._pending.get(msg.taskId);
|
|
197
|
+
if (!pending) {
|
|
198
|
+
this._debug('RESULT_ORPHAN', `taskId=${msg.taskId} (already cancelled)`);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
this._pending.delete(msg.taskId);
|
|
203
|
+
clearTimeout(pending.timeout);
|
|
204
|
+
|
|
205
|
+
const taskTime = this._taskStartTimes.has(msg.taskId)
|
|
206
|
+
? (performance.now() - this._taskStartTimes.get(msg.taskId)).toFixed(1)
|
|
207
|
+
: '?';
|
|
208
|
+
this._taskStartTimes.delete(msg.taskId);
|
|
209
|
+
|
|
210
|
+
if (msg.error) {
|
|
211
|
+
this._debug('RESULT_ERROR', `taskId=${msg.taskId} worker=${entry.id} time=${taskTime}ms error="${msg.error}"`);
|
|
212
|
+
pending.reject(new Error(msg.error));
|
|
213
|
+
} else {
|
|
214
|
+
this._debug('RESULT_OK', `taskId=${msg.taskId} worker=${entry.id} time=${taskTime}ms`);
|
|
215
|
+
pending.resolve(msg.result);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* 处理 Worker 错误
|
|
221
|
+
*/
|
|
222
|
+
_handleError(entry, err) {
|
|
223
|
+
entry.busy = false;
|
|
224
|
+
let cancelledCount = 0;
|
|
225
|
+
// 将所有属于此 Worker 的待处理任务 reject
|
|
226
|
+
for (const [taskId, pending] of this._pending) {
|
|
227
|
+
if (pending.workerEntry === entry) {
|
|
228
|
+
this._pending.delete(taskId);
|
|
229
|
+
clearTimeout(pending.timeout);
|
|
230
|
+
this._taskStartTimes.delete(taskId);
|
|
231
|
+
pending.reject(err);
|
|
232
|
+
cancelledCount++;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (cancelledCount > 0) {
|
|
236
|
+
this._debug('HANDLE_ERROR', `worker=${entry.id} cancelled=${cancelledCount} error="${err.message}"`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* 选择一个空闲 Worker(Round-Robin 调度)
|
|
242
|
+
*/
|
|
243
|
+
_pickWorker() {
|
|
244
|
+
const idle = this._workers.filter(w => !w.busy);
|
|
245
|
+
if (idle.length === 0) {
|
|
246
|
+
this._debug('PICK_WORKER', 'none_idle');
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// 选择任务数最少的空闲 Worker(负载均衡)
|
|
251
|
+
idle.sort((a, b) => a.taskCount - b.taskCount);
|
|
252
|
+
this._debug('PICK_WORKER', `id=${idle[0].id} idle_count=${idle.length}`);
|
|
253
|
+
return idle[0];
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* 向指定 Worker 提交一个任务
|
|
258
|
+
* @param {object} entry - Worker 条目
|
|
259
|
+
* @param {object} task - 任务对象
|
|
260
|
+
* @returns {Promise<any>}
|
|
261
|
+
*/
|
|
262
|
+
_submitTask(entry, task) {
|
|
263
|
+
const taskId = this._nextTaskId++;
|
|
264
|
+
this._taskStartTimes.set(taskId, performance.now());
|
|
265
|
+
|
|
266
|
+
this._debug('SUBMIT_TASK', `taskId=${taskId} type=${task.type} worker=${entry.id}`);
|
|
267
|
+
|
|
268
|
+
return new Promise((resolve, reject) => {
|
|
269
|
+
const timeout = setTimeout(() => {
|
|
270
|
+
this._pending.delete(taskId);
|
|
271
|
+
this._taskStartTimes.delete(taskId);
|
|
272
|
+
this._debug('TASK_TIMEOUT', `taskId=${taskId} type=${task.type} worker=${entry.id} timeout=${this.taskTimeout}ms`);
|
|
273
|
+
reject(new Error(`任务超时 (${this.taskTimeout}ms): ${task.type}`));
|
|
274
|
+
}, this.taskTimeout);
|
|
275
|
+
|
|
276
|
+
this._pending.set(taskId, { resolve, reject, timeout, workerEntry: entry, startTime: performance.now() });
|
|
277
|
+
|
|
278
|
+
entry.busy = true;
|
|
279
|
+
entry.taskCount++;
|
|
280
|
+
entry.worker.postMessage({ taskId, task });
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* 在单个空闲 Worker 上执行任务
|
|
286
|
+
* @param {object} task
|
|
287
|
+
* @returns {Promise<any>}
|
|
288
|
+
*/
|
|
289
|
+
async exec(task) {
|
|
290
|
+
if (!this.initialized) {
|
|
291
|
+
await this.init();
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const entry = this._pickWorker();
|
|
295
|
+
if (!entry) {
|
|
296
|
+
// 没有空闲 Worker,等待 10ms 后重试
|
|
297
|
+
this._debug('EXEC_WAIT', `type=${task.type} (no idle worker, retry after 10ms)`);
|
|
298
|
+
await new Promise(r => setTimeout(r, 10));
|
|
299
|
+
return this.exec(task);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const start = performance.now();
|
|
303
|
+
try {
|
|
304
|
+
const result = await this._submitTask(entry, task);
|
|
305
|
+
entry.totalTime += performance.now() - start;
|
|
306
|
+
return result;
|
|
307
|
+
} catch (err) {
|
|
308
|
+
entry.totalTime += performance.now() - start;
|
|
309
|
+
throw err;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* 在所有 Worker 上执行一组任务(每个 Worker 一个任务)
|
|
315
|
+
* @param {object[]} tasks - 任务数组,长度应 <= pool.size
|
|
316
|
+
* @returns {Promise<any[]>} 结果数组(顺序与 tasks 一致)
|
|
317
|
+
*/
|
|
318
|
+
async execAll(tasks) {
|
|
319
|
+
if (!this.initialized) {
|
|
320
|
+
await this.init();
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (tasks.length === 0) {
|
|
324
|
+
return [];
|
|
325
|
+
}
|
|
326
|
+
if (tasks.length > this._workers.length) {
|
|
327
|
+
// 超出 Worker 数量,分批执行
|
|
328
|
+
this._debug('EXECALL_BATCHED', `tasks=${tasks.length} workers=${this._workers.length} batches=${Math.ceil(tasks.length / this._workers.length)}`);
|
|
329
|
+
const results = [];
|
|
330
|
+
for (let i = 0; i < tasks.length; i += this._workers.length) {
|
|
331
|
+
const batch = tasks.slice(i, i + this._workers.length);
|
|
332
|
+
const batchResults = await this._execBatch(batch);
|
|
333
|
+
results.push(...batchResults);
|
|
334
|
+
}
|
|
335
|
+
return results;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
this._debug('EXECALL', `tasks=${tasks.length} workers=${this._workers.length}`);
|
|
339
|
+
return this._execBatch(tasks);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* L2.3: Morsel-Driven 动态调度执行
|
|
344
|
+
*
|
|
345
|
+
* 与 execAll 的区别:
|
|
346
|
+
* - execAll: 静态分配(每个 Worker 一个任务),分批阻塞等待
|
|
347
|
+
* - execAllMorsels: 动态调度(Worker 空闲就分配下一个 morsel),无分批阻塞
|
|
348
|
+
*
|
|
349
|
+
* 优势:
|
|
350
|
+
* 1. 长尾 morsel 不拖慢整批(其他 Worker 继续拉取新 morsel)
|
|
351
|
+
* 2. 负载倾斜自动均衡(数据密集 morsel 慢,稀疏 morsel 快,Worker 自适应)
|
|
352
|
+
* 3. 支持 work stealing(僵死 morsel 可被重新分配)
|
|
353
|
+
*
|
|
354
|
+
* @param {Object} config
|
|
355
|
+
* @param {number} config.totalRows - 总行数(用于切分 morsel)
|
|
356
|
+
* @param {function(startRow: number, endRow: number): object} config.buildTask
|
|
357
|
+
* - 根据行范围构造 Worker 任务
|
|
358
|
+
* @param {number} [config.morselSize=65536] - 每个 morsel 的行数
|
|
359
|
+
* @param {number} [config.timeout=WORKER_TIMEOUT] - 单任务超时
|
|
360
|
+
* @param {boolean} [config.enableSteal=true] - 是否启用 work stealing
|
|
361
|
+
* @returns {Promise<Array<{morselId: number, result: any}>>}
|
|
362
|
+
* 结果数组(按 morselId 排序,调用方负责合并)
|
|
363
|
+
*/
|
|
364
|
+
async execAllMorsels(config) {
|
|
365
|
+
if (!this.initialized) {
|
|
366
|
+
await this.init();
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
const {
|
|
370
|
+
totalRows,
|
|
371
|
+
buildTask,
|
|
372
|
+
morselSize = 65536,
|
|
373
|
+
timeout = WORKER_TIMEOUT,
|
|
374
|
+
enableSteal = true,
|
|
375
|
+
} = config;
|
|
376
|
+
|
|
377
|
+
if (totalRows <= 0) {
|
|
378
|
+
return [];
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// 初始化 MorselQueue(无 SAB 时降级为内存模式,仍走动态调度)
|
|
382
|
+
const queue = new MorselQueue({ morselSize });
|
|
383
|
+
const morselCount = queue.isAvailable() ? queue.init(totalRows) : 0;
|
|
384
|
+
|
|
385
|
+
// 无 SAB 降级:用普通数组模拟 morsel 状态
|
|
386
|
+
const fallbackMorsels = queue.isAvailable() ? null : _buildFallbackMorsels(totalRows, morselSize);
|
|
387
|
+
const useFallback = !queue.isAvailable();
|
|
388
|
+
|
|
389
|
+
this._debug('EXECALL_MORSELS_START',
|
|
390
|
+
`rows=${totalRows} morsels=${useFallback ? fallbackMorsels.length : morselCount} ` +
|
|
391
|
+
`morselSize=${morselSize} sab=${!useFallback} steal=${enableSteal}`);
|
|
392
|
+
|
|
393
|
+
const results = new Array(useFallback ? fallbackMorsels.length : morselCount);
|
|
394
|
+
let completedCount = 0;
|
|
395
|
+
let nextFallbackIdx = 0;
|
|
396
|
+
const totalMorsels = useFallback ? fallbackMorsels.length : morselCount;
|
|
397
|
+
const startTime = performance.now();
|
|
398
|
+
|
|
399
|
+
// 提交下一个 morsel 给指定 Worker
|
|
400
|
+
const _submitNextMorsel = async (entry) => {
|
|
401
|
+
let morselIdx = -1;
|
|
402
|
+
let morsel = null;
|
|
403
|
+
|
|
404
|
+
if (useFallback) {
|
|
405
|
+
// 降级模式:从数组顺序取
|
|
406
|
+
morselIdx = nextFallbackIdx++;
|
|
407
|
+
if (morselIdx >= fallbackMorsels.length) {
|
|
408
|
+
return false;
|
|
409
|
+
}
|
|
410
|
+
morsel = fallbackMorsels[morselIdx];
|
|
411
|
+
} else {
|
|
412
|
+
// SAB 模式:原子抢占
|
|
413
|
+
morselIdx = queue.acquireNext(entry.id);
|
|
414
|
+
if (morselIdx < 0) {
|
|
415
|
+
// 无可用 morsel,尝试窃取
|
|
416
|
+
if (enableSteal) {
|
|
417
|
+
const stolen = queue.trySteal();
|
|
418
|
+
if (stolen >= 0) {
|
|
419
|
+
morselIdx = queue.acquireNext(entry.id);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
if (morselIdx < 0) {
|
|
423
|
+
return false;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
morsel = queue.getMorsel(morselIdx);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if (!morsel) {
|
|
430
|
+
return false;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
const task = buildTask(morsel.startRow, morsel.endRow);
|
|
434
|
+
const taskStart = performance.now();
|
|
435
|
+
|
|
436
|
+
try {
|
|
437
|
+
const result = await this._submitTaskWithTimeout(entry, task, timeout);
|
|
438
|
+
const elapsed = performance.now() - taskStart;
|
|
439
|
+
entry.totalTime += elapsed;
|
|
440
|
+
|
|
441
|
+
if (!useFallback) {
|
|
442
|
+
queue.markCompleted(morselIdx);
|
|
443
|
+
}
|
|
444
|
+
results[morsel.id] = { morselId: morsel.id, result };
|
|
445
|
+
completedCount++;
|
|
446
|
+
|
|
447
|
+
this._debug('MORSEL_DONE',
|
|
448
|
+
`worker=${entry.id} morselId=${morsel.id} rows=${morsel.endRow - morsel.startRow} ` +
|
|
449
|
+
`elapsed=${elapsed.toFixed(1)}ms completed=${completedCount}/${totalMorsels}`);
|
|
450
|
+
return true;
|
|
451
|
+
} catch (err) {
|
|
452
|
+
const elapsed = performance.now() - taskStart;
|
|
453
|
+
entry.totalTime += elapsed;
|
|
454
|
+
this._debug('MORSEL_ERROR',
|
|
455
|
+
`worker=${entry.id} morselId=${morsel.id} elapsed=${elapsed.toFixed(1)}ms error="${err.message}"`);
|
|
456
|
+
// 不标记 completed,让 steal 机制重试(或降级时直接标记失败)
|
|
457
|
+
if (useFallback) {
|
|
458
|
+
results[morsel.id] = { morselId: morsel.id, result: null, error: err.message };
|
|
459
|
+
completedCount++;
|
|
460
|
+
}
|
|
461
|
+
return false;
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
|
|
465
|
+
// 动态调度循环:所有 Worker 并发拉取 morsel
|
|
466
|
+
const workerPromises = this._workers.map(async (entry) => {
|
|
467
|
+
// 每个 Worker 持续拉取 morsel 直到无可用
|
|
468
|
+
while (completedCount + (totalMorsels - completedCount) > 0) {
|
|
469
|
+
// 检查是否还有未完成的 morsel
|
|
470
|
+
if (!useFallback && queue.isAllCompleted()) {
|
|
471
|
+
break;
|
|
472
|
+
}
|
|
473
|
+
if (useFallback && nextFallbackIdx >= fallbackMorsels.length) {
|
|
474
|
+
break;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
const got = await _submitNextMorsel(entry);
|
|
478
|
+
if (!got) {
|
|
479
|
+
// 无可用 morsel,短暂等待(可能有 morsel 即将完成或被窃取)
|
|
480
|
+
if (!useFallback && !queue.isAllCompleted()) {
|
|
481
|
+
await new Promise(r => setTimeout(r, 1));
|
|
482
|
+
// 重试一次,可能其他 Worker 完成后释放了 morsel
|
|
483
|
+
const got2 = await _submitNextMorsel(entry);
|
|
484
|
+
if (!got2) {
|
|
485
|
+
break;
|
|
486
|
+
}
|
|
487
|
+
} else {
|
|
488
|
+
break;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
await Promise.all(workerPromises);
|
|
495
|
+
|
|
496
|
+
// 过滤掉 null 结果(失败但未重试的 morsel)
|
|
497
|
+
const validResults = results.filter(r => r !== undefined && r !== null);
|
|
498
|
+
|
|
499
|
+
this._debug('EXECALL_MORSELS_DONE',
|
|
500
|
+
`morsels=${totalMorsels} completed=${completedCount} ` +
|
|
501
|
+
`valid=${validResults.length} duration=${(performance.now() - startTime).toFixed(1)}ms`);
|
|
502
|
+
|
|
503
|
+
return validResults;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* 向指定 Worker 提交任务(带超时)
|
|
508
|
+
* @param {object} entry - Worker 条目
|
|
509
|
+
* @param {object} task - 任务对象
|
|
510
|
+
* @param {number} timeout - 超时(ms)
|
|
511
|
+
* @returns {Promise<any>}
|
|
512
|
+
*/
|
|
513
|
+
async _submitTaskWithTimeout(entry, task, timeout) {
|
|
514
|
+
return new Promise((resolve, reject) => {
|
|
515
|
+
const taskId = this._nextTaskId++;
|
|
516
|
+
this._taskStartTimes.set(taskId, performance.now());
|
|
517
|
+
|
|
518
|
+
const timer = setTimeout(() => {
|
|
519
|
+
this._pending.delete(taskId);
|
|
520
|
+
this._taskStartTimes.delete(taskId);
|
|
521
|
+
entry.busy = false;
|
|
522
|
+
reject(new Error(`Morsel 任务超时 (${timeout}ms): ${task.type}`));
|
|
523
|
+
}, timeout);
|
|
524
|
+
timer.unref();
|
|
525
|
+
|
|
526
|
+
this._pending.set(taskId, {
|
|
527
|
+
resolve: (v) => {
|
|
528
|
+
clearTimeout(timer); entry.busy = false; resolve(v);
|
|
529
|
+
},
|
|
530
|
+
reject: (e) => {
|
|
531
|
+
clearTimeout(timer); entry.busy = false; reject(e);
|
|
532
|
+
},
|
|
533
|
+
timeout: timer,
|
|
534
|
+
workerEntry: entry,
|
|
535
|
+
startTime: performance.now(),
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
entry.busy = true;
|
|
539
|
+
entry.taskCount++;
|
|
540
|
+
entry.worker.postMessage({ taskId, task });
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* 执行一批任务(每个 Worker 一个任务)
|
|
546
|
+
*/
|
|
547
|
+
async _execBatch(tasks) {
|
|
548
|
+
this._debug('EXECBATCH_START', `tasks=${tasks.length}`);
|
|
549
|
+
const batchStart = performance.now();
|
|
550
|
+
const promises = [];
|
|
551
|
+
let taskIdx = 0;
|
|
552
|
+
|
|
553
|
+
// 分配任务到空闲 Worker
|
|
554
|
+
for (const entry of this._workers) {
|
|
555
|
+
if (taskIdx >= tasks.length) {
|
|
556
|
+
break;
|
|
557
|
+
}
|
|
558
|
+
const task = tasks[taskIdx++];
|
|
559
|
+
const start = performance.now();
|
|
560
|
+
// 使用 allSettled 模式:单个 Worker 崩溃不影响其他 Worker 结果
|
|
561
|
+
const promise = this._submitTask(entry, task).then(result => {
|
|
562
|
+
entry.totalTime += performance.now() - start;
|
|
563
|
+
return { status: 'fulfilled', value: result, taskIdx: taskIdx - 1 };
|
|
564
|
+
}).catch(err => {
|
|
565
|
+
entry.totalTime += performance.now() - start;
|
|
566
|
+
return { status: 'rejected', reason: err, taskIdx: taskIdx - 1 };
|
|
567
|
+
});
|
|
568
|
+
promises.push(promise);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
const settled = await Promise.all(promises);
|
|
572
|
+
const errors = settled.filter(r => r.status === 'rejected');
|
|
573
|
+
const results = settled.filter(r => r.status === 'fulfilled').map(r => r.value);
|
|
574
|
+
|
|
575
|
+
if (errors.length > 0) {
|
|
576
|
+
this._debug('EXECBATCH_PARTIAL_FAILURE',
|
|
577
|
+
`total=${tasks.length} succeeded=${results.length} failed=${errors.length} first_error="${errors[0].reason.message}"`);
|
|
578
|
+
// 如果全部失败才抛异常,部分成功则返回成功结果
|
|
579
|
+
if (results.length === 0) {
|
|
580
|
+
throw errors[0].reason;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
this._debug('EXECBATCH_DONE',
|
|
585
|
+
`tasks=${tasks.length} results=${results.length} errors=${errors.length} duration=${(performance.now() - batchStart).toFixed(1)}ms`);
|
|
586
|
+
return results;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* 获取 Pool 统计信息
|
|
591
|
+
*/
|
|
592
|
+
getStats() {
|
|
593
|
+
const stats = {
|
|
594
|
+
poolSize: this.size,
|
|
595
|
+
activeWorkers: this._workers.length,
|
|
596
|
+
busyCount: this._workers.filter(w => w.busy).length,
|
|
597
|
+
idleCount: this._workers.filter(w => !w.busy).length,
|
|
598
|
+
pendingTasks: this._pending.size,
|
|
599
|
+
workers: this._workers.map(w => ({
|
|
600
|
+
id: w.id,
|
|
601
|
+
busy: w.busy,
|
|
602
|
+
taskCount: w.taskCount,
|
|
603
|
+
totalTimeMs: +w.totalTime.toFixed(2),
|
|
604
|
+
})),
|
|
605
|
+
};
|
|
606
|
+
this._debug('GET_STATS', `busy=${stats.busyCount} idle=${stats.idleCount} pending=${stats.pendingTasks}`);
|
|
607
|
+
return stats;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
/**
|
|
611
|
+
* 终止所有 Worker
|
|
612
|
+
*/
|
|
613
|
+
async terminate() {
|
|
614
|
+
const pendingCount = this._pending.size;
|
|
615
|
+
this._debug('TERMINATE_START', `workers=${this._workers.length} pending=${pendingCount}`);
|
|
616
|
+
|
|
617
|
+
for (const [, pending] of this._pending) {
|
|
618
|
+
clearTimeout(pending.timeout);
|
|
619
|
+
pending.reject(new Error('Worker Pool 已关闭'));
|
|
620
|
+
}
|
|
621
|
+
this._pending.clear();
|
|
622
|
+
this._taskStartTimes.clear();
|
|
623
|
+
|
|
624
|
+
await Promise.all(this._workers.map(w => w.worker.terminate()));
|
|
625
|
+
this._workers = [];
|
|
626
|
+
this.initialized = false;
|
|
627
|
+
this._debug('TERMINATE_DONE', '');
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// ── 模块级辅助函数 ──
|
|
632
|
+
|
|
633
|
+
/**
|
|
634
|
+
* 无 SAB 环境下的降级 morsel 列表构建
|
|
635
|
+
* 用普通数组模拟 morsel 状态,仍支持动态调度(但不支持跨 Worker 共享状态)
|
|
636
|
+
*
|
|
637
|
+
* @param {number} totalRows - 总行数
|
|
638
|
+
* @param {number} morselSize - 每个 morsel 的行数
|
|
639
|
+
* @returns {Array<{id: number, startRow: number, endRow: number}>}
|
|
640
|
+
*/
|
|
641
|
+
function _buildFallbackMorsels(totalRows, morselSize) {
|
|
642
|
+
const morsels = [];
|
|
643
|
+
const size = Math.max(1, morselSize);
|
|
644
|
+
const count = Math.ceil(totalRows / size);
|
|
645
|
+
for (let i = 0; i < count; i++) {
|
|
646
|
+
const start = i * size;
|
|
647
|
+
const end = Math.min(start + size, totalRows);
|
|
648
|
+
morsels.push({ id: i, startRow: start, endRow: end });
|
|
649
|
+
}
|
|
650
|
+
return morsels;
|
|
651
|
+
}
|