sparkforensics-server 0.6.0 → 0.8.1
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/index.js +16 -7
- package/package.json +1 -1
- package/public/assets/AutoscalingChurn-DenWKTv-.js +1 -0
- package/public/assets/CacheUtilization-DLz7NdjV.js +1 -0
- package/public/assets/CachingOpportunity-zpQIqhzm.js +1 -0
- package/public/assets/ChartTheme-DAiARbLP.js +8 -0
- package/public/assets/ColdStart-C-9HjxWl.js +1 -0
- package/public/assets/ConfigAudit-D0V9tcrJ.js +1 -0
- package/public/assets/CoreUsageArea-yeerrljd.js +1 -0
- package/public/assets/Dashboard-DkUPrHKV.js +1 -0
- package/public/assets/DisclosureContext-DK1_iz6J.js +1 -0
- package/public/assets/DuplicatePlanSubtree-xDNDbCd3.js +1 -0
- package/public/assets/DurationHistogram-B6jsE0Ov.js +1 -0
- package/public/assets/EmptyState-C1uL40VU.js +1 -0
- package/public/assets/ExecutorUtilization-DXDZKmSc.js +1 -0
- package/public/assets/GcPressure-MRf7I4IG.js +1 -0
- package/public/assets/ImpactEstimate-Dm3xWbzV.js +1 -0
- package/public/assets/IncompleteRun-CaLOhMtf.js +1 -0
- package/public/assets/JobFailures-CzmzlvhO.js +1 -0
- package/public/assets/MemoryUtilization-AWUMUjCH.js +1 -0
- package/public/assets/NestedLoopJoin-C9sNr6Ss.js +1 -0
- package/public/assets/OverBroadcast-BOmRE6ca.js +1 -0
- package/public/assets/PartitionHint-BL2EmJfE.js +1 -0
- package/public/assets/PartitionSizing-BzBySvUq.js +1 -0
- package/public/assets/PlanExplorer-DdiQRcJU.js +1 -0
- package/public/assets/PlanGraphRoute-CIH9gBuR.js +1 -0
- package/public/assets/PlanView-B1hxzFRs.js +2 -0
- package/public/assets/PythonUdf-DvgCCueD.js +1 -0
- package/public/assets/RetryWaste-uXXu_CyM.js +1 -0
- package/public/assets/RowPagination-C-LzWkI5.js +1 -0
- package/public/assets/RowStatusCluster-Dbtmte7l.js +1 -0
- package/public/assets/ShuffleIO-nALwzC1_.js +1 -0
- package/public/assets/Skew-CHMEKgvk.js +1 -0
- package/public/assets/SlowHost-yyvjpHk6.js +1 -0
- package/public/assets/SmallFiles-y6odJ97n.js +1 -0
- package/public/assets/SpeculationWaste-C-SD2LOt.js +1 -0
- package/public/assets/Spill-DHTMmOup.js +1 -0
- package/public/assets/StageFailed-CQ3DxC9R.js +1 -0
- package/public/assets/StageFindingGroup-BgYLyj5q.js +1 -0
- package/public/assets/StageHeader-CIETkjVZ.js +1 -0
- package/public/assets/StagePill--P7PDd3s.js +1 -0
- package/public/assets/StageShape-BIv8vx_o.js +1 -0
- package/public/assets/StageSlowness-MMqzERxN.js +1 -0
- package/public/assets/Straggler-BgrY7AyW.js +1 -0
- package/public/assets/TaskFailures-BHHyKYTs.js +1 -0
- package/public/assets/TinyTask-DDScNhCl.js +1 -0
- package/public/assets/UnderBroadcast-CGIC04TI.js +1 -0
- package/public/assets/WidgetLeadSummary-CXFZP00C.js +1 -0
- package/public/assets/button-DbpTz2yk.js +1 -0
- package/public/assets/charts-vendor-CtTxwTeu.js +59 -0
- package/public/assets/composite-C9Nu2EI9.js +1 -0
- package/public/assets/d3-vendor-DNlD2-cz.js +1 -0
- package/public/assets/detector-registry-Bp8hrLua.js +2 -0
- package/public/assets/downsample-WmNM1qc9.js +1 -0
- package/public/assets/finding-anchor-Dr40LkS9.js +1 -0
- package/public/assets/findings-of-type-BL2u3RGZ.js +1 -0
- package/public/assets/impact-sort-mC5ISgX8.js +1 -0
- package/public/assets/inbox-KPU1Gppm.js +1 -0
- package/public/assets/index-CaRVPvAT.css +2 -0
- package/public/assets/index-fDiwfuoO.js +14 -0
- package/public/assets/inertValue-L9VxV0VE.js +1 -0
- package/public/assets/layout.worker-CLcBHxVp.js +3 -0
- package/public/assets/{parser-worker-CA5RxqKc.js → parser-worker-CRIOPMOW.js} +8 -8
- package/public/assets/plan-graph-vendor-Ce6d4HU6.js +7 -0
- package/public/assets/react-vendor-C6KcUD36.js +9 -0
- package/public/assets/select-BHqOqun5.js +1 -0
- package/public/assets/toggle-DPeN6aNa.js +1 -0
- package/public/assets/toggle-group-Kl3uyHSr.js +1 -0
- package/public/assets/usePagedRows-BafD6bEN.js +1 -0
- package/public/assets/useRecentFiles-DzJZAoOT.js +3 -0
- package/public/assets/useRegisterFieldControl-pQv-ZDoU.js +1 -0
- package/public/assets/useScrollLock-BCxn_dMp.js +1 -0
- package/public/assets/useSortMode-DjrAN-z4.js +1 -0
- package/public/docs/404.html +3 -3
- package/public/docs/assets/{app.CnWL6bKV.js → app.1gvzd5Zb.js} +1 -1
- package/public/docs/assets/chunks/@localSearchIndexroot.DS2TQP5_.js +1 -0
- package/public/docs/assets/chunks/{VPLocalSearchBox.C0IBKeRQ.js → VPLocalSearchBox.CNxT3s0I.js} +1 -1
- package/public/docs/assets/chunks/{theme.BH-2HuRf.js → theme.C5lLqUv7.js} +2 -2
- package/public/docs/assets/contributor-guide_architecture_board-widgets.md.CqKM_jEG.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_board-widgets.md.CqKM_jEG.lean.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_board-widgets_caching-and-memory.md.CQgn1t_M.js → contributor-guide_architecture_board-widgets_caching-and-memory.md.BYDo3ClR.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_board-widgets_plan-advisor.md.ajUAVdbc.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_board-widgets_visual-system-and-templating.md.wulOueeB.js → contributor-guide_architecture_board-widgets_visual-system-and-templating.md.WqY74T0T.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_board-widgets_visual-system-and-templating.md.WqY74T0T.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_detector-contract.md.CHHgywoP.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_detector-contract.md.N4hhenrA.lean.js → contributor-guide_architecture_detector-contract.md.CHHgywoP.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_detector-contract_plan-attribution.md.DIz3_oz9.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_detector-contract_plan-attribution.md.DIz3_oz9.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_detector-contract_threshold-tables.md.WH4tRHPL.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_detector-contract_threshold-tables.md.Dp3c40rx.lean.js → contributor-guide_architecture_detector-contract_threshold-tables.md.WH4tRHPL.lean.js} +1 -1
- package/public/docs/assets/{contributor-guide_architecture_drill-down.md.CqZPrdo9.js → contributor-guide_architecture_drill-down.md.yB-Hz2XT.js} +1 -1
- package/public/docs/assets/{contributor-guide_architecture_drill-down.md.CqZPrdo9.lean.js → contributor-guide_architecture_drill-down.md.yB-Hz2XT.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_drill-down_plan-graph.md.BQZE04sw.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_drill-down_plan-graph.md.DwOozIEs.lean.js → contributor-guide_architecture_drill-down_plan-graph.md.BQZE04sw.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_impact-estimation.md.K71YB-Rr.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_impact-estimation.md.DfvbqEUu.lean.js → contributor-guide_architecture_impact-estimation.md.K71YB-Rr.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_impact-estimation_caveats-tuning-and-coverage.md.DLCAffwn.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_impact-estimation_caveats-tuning-and-coverage.md.Cwm1jHmn.lean.js → contributor-guide_architecture_impact-estimation_caveats-tuning-and-coverage.md.DLCAffwn.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_impact-estimation_stage-union-rollup.md.JFrzDMwo.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_impact-estimation_stage-union-rollup.md.JFrzDMwo.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_overview.md.nxkpOhgf.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_state-and-history_run-comparison-internals.md.U-9KMDFK.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_state-and-history_run-comparison-internals.md.CZA0JLtV.lean.js → contributor-guide_architecture_state-and-history_run-comparison-internals.md.U-9KMDFK.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_widget-rendering.md.BrSz8Ezh.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_widget-rendering_findings-tab.md.B7rjSF_h.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_widget-rendering_findings-tab.md.B7rjSF_h.lean.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_widget-rendering_list-sort-mode.md.BuHKgH0C.js → contributor-guide_architecture_widget-rendering_list-sort-mode.md.37hcZJ7q.js} +1 -1
- package/public/docs/assets/{contributor-guide_architecture_widget-rendering_row-expand-contract.md.ZT89u9f1.js → contributor-guide_architecture_widget-rendering_row-expand-contract.md.mK_VmAWk.js} +1 -1
- package/public/docs/assets/{contributor-guide_architecture_worker-protocol.md.BAnhi2-d.js → contributor-guide_architecture_worker-protocol.md.Br6OE7RW.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_worker-protocol.md.Br6OE7RW.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_worker-protocol_cli-and-mcp.md.IVyaXrGe.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_worker-protocol_cli-and-mcp.md.BX1XnFbq.lean.js → contributor-guide_architecture_worker-protocol_cli-and-mcp.md.IVyaXrGe.lean.js} +1 -1
- package/public/docs/assets/{contributor-guide_architecture_worker-protocol_core-and-event-validation.md.DSVFPpWb.js → contributor-guide_architecture_worker-protocol_core-and-event-validation.md.DVSXn-bb.js} +1 -1
- package/public/docs/assets/{contributor-guide_architecture_worker-protocol_evidence-availability.md.CjimIDBY.js → contributor-guide_architecture_worker-protocol_evidence-availability.md.D3S5cyOW.js} +2 -2
- package/public/docs/assets/{contributor-guide_architecture_worker-protocol_evidence-availability.md.CjimIDBY.lean.js → contributor-guide_architecture_worker-protocol_evidence-availability.md.D3S5cyOW.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_worker-protocol_evidence-report.md.CtmCU57I.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_worker-protocol_evidence-report.md.CiQl1MLb.lean.js → contributor-guide_architecture_worker-protocol_evidence-report.md.CtmCU57I.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_contributing.md.DBW4drtZ.js +1 -0
- package/public/docs/assets/contributor-guide_development-setup.md.B21ZTDhn.js +15 -0
- package/public/docs/assets/contributor-guide_development-setup.md.B21ZTDhn.lean.js +1 -0
- package/public/docs/assets/contributor-guide_testing.md.DpkozNoG.js +4 -0
- package/public/docs/assets/{contributor-guide_testing.md.By6XGR9a.lean.js → contributor-guide_testing.md.DpkozNoG.lean.js} +1 -1
- package/public/docs/assets/{index.md.CHJVslga.js → index.md.lMm7SUMz.js} +1 -1
- package/public/docs/assets/{index.md.CHJVslga.lean.js → index.md.lMm7SUMz.lean.js} +1 -1
- package/public/docs/assets/{style.CyK9Ss73.css → style.Cfxqlj0y.css} +1 -1
- package/public/docs/assets/user-guide_getting-started_ci-and-automation.md.C0pcQoNc.js +29 -0
- package/public/docs/assets/{user-guide_getting-started_ci-and-automation.md.BEepbDDL.lean.js → user-guide_getting-started_ci-and-automation.md.C0pcQoNc.lean.js} +1 -1
- package/public/docs/assets/user-guide_getting-started_reading-the-dashboard.md.CGaxPX_1.js +1 -0
- package/public/docs/assets/{user-guide_getting-started_tuning-thresholds.md.B_MyjyZm.js → user-guide_getting-started_tuning-thresholds.md.BGVE-wrc.js} +2 -2
- package/public/docs/assets/{user-guide_getting-started_tuning-thresholds.md.B_MyjyZm.lean.js → user-guide_getting-started_tuning-thresholds.md.BGVE-wrc.lean.js} +1 -1
- package/public/docs/assets/{user-guide_mcp-tools.md.C65SjWUL.js → user-guide_mcp-tools.md.49r3L2YE.js} +1 -1
- package/public/docs/assets/{user-guide_mcp-tools_compare-runs.md.Cc_gLoix.js → user-guide_mcp-tools_compare-runs.md.BQ_kIptC.js} +11 -6
- package/public/docs/assets/user-guide_mcp-tools_compare-runs.md.BQ_kIptC.lean.js +1 -0
- package/public/docs/assets/user-guide_mcp-tools_diagnose-run.md.azCZXkH8.js +44 -0
- package/public/docs/assets/{user-guide_mcp-tools_diagnose-run.md.BP1vnHA5.lean.js → user-guide_mcp-tools_diagnose-run.md.azCZXkH8.lean.js} +1 -1
- package/public/docs/assets/{user-guide_mcp-tools_evaluate-budgets.md.BB0nDY3Z.js → user-guide_mcp-tools_evaluate-budgets.md.dpQpRQ7z.js} +2 -2
- package/public/docs/assets/{user-guide_mcp-tools_evaluate-budgets.md.BB0nDY3Z.lean.js → user-guide_mcp-tools_evaluate-budgets.md.dpQpRQ7z.lean.js} +1 -1
- package/public/docs/assets/{user-guide_mcp-tools_get-finding-evidence.md.rKyu4wts.js → user-guide_mcp-tools_get-finding-evidence.md.CH6FkNLX.js} +2 -1
- package/public/docs/assets/{user-guide_mcp-tools_get-finding-evidence.md.rKyu4wts.lean.js → user-guide_mcp-tools_get-finding-evidence.md.CH6FkNLX.lean.js} +1 -1
- package/public/docs/assets/user-guide_run-comparison.md.B_LOkdBf.js +1 -0
- package/public/docs/assets/user-guide_run-comparison.md.B_LOkdBf.lean.js +1 -0
- package/public/docs/assets/user-guide_understanding-findings.md.C4riKCKl.js +1 -0
- package/public/docs/assets/user-guide_understanding-findings.md.C4riKCKl.lean.js +1 -0
- package/public/docs/contributor-guide/architecture/board-widgets/caching-and-memory.html +6 -6
- package/public/docs/contributor-guide/architecture/board-widgets/plan-advisor.html +6 -6
- package/public/docs/contributor-guide/architecture/board-widgets/visual-system-and-templating.html +6 -6
- package/public/docs/contributor-guide/architecture/board-widgets.html +6 -6
- package/public/docs/contributor-guide/architecture/detector-contract/plan-attribution.html +6 -6
- package/public/docs/contributor-guide/architecture/detector-contract/threshold-tables.html +6 -6
- package/public/docs/contributor-guide/architecture/detector-contract.html +6 -6
- package/public/docs/contributor-guide/architecture/drill-down/plan-graph.html +6 -6
- package/public/docs/contributor-guide/architecture/drill-down.html +6 -6
- package/public/docs/contributor-guide/architecture/impact-estimation/caveats-tuning-and-coverage.html +6 -6
- package/public/docs/contributor-guide/architecture/impact-estimation/stage-union-rollup.html +6 -6
- package/public/docs/contributor-guide/architecture/impact-estimation.html +6 -6
- package/public/docs/contributor-guide/architecture/index.html +5 -5
- package/public/docs/contributor-guide/architecture/overview.html +6 -6
- package/public/docs/contributor-guide/architecture/state-and-history/history-server-intake.html +5 -5
- package/public/docs/contributor-guide/architecture/state-and-history/run-comparison-internals.html +6 -6
- package/public/docs/contributor-guide/architecture/state-and-history.html +5 -5
- package/public/docs/contributor-guide/architecture/widget-rendering/findings-tab.html +6 -6
- package/public/docs/contributor-guide/architecture/widget-rendering/investigation-routing.html +5 -5
- package/public/docs/contributor-guide/architecture/widget-rendering/list-sort-mode.html +6 -6
- package/public/docs/contributor-guide/architecture/widget-rendering/reference-section.html +5 -5
- package/public/docs/contributor-guide/architecture/widget-rendering/row-expand-contract.html +6 -6
- package/public/docs/contributor-guide/architecture/widget-rendering.html +6 -6
- package/public/docs/contributor-guide/architecture/worker-protocol/cli-and-mcp.html +6 -6
- package/public/docs/contributor-guide/architecture/worker-protocol/core-and-event-validation.html +6 -6
- package/public/docs/contributor-guide/architecture/worker-protocol/evidence-availability.html +7 -7
- package/public/docs/contributor-guide/architecture/worker-protocol/evidence-report.html +6 -6
- package/public/docs/contributor-guide/architecture/worker-protocol.html +6 -6
- package/public/docs/contributor-guide/contributing.html +6 -6
- package/public/docs/contributor-guide/development-setup.html +8 -8
- package/public/docs/contributor-guide/testing.html +9 -6
- package/public/docs/hashmap.json +1 -1
- package/public/docs/index.html +6 -6
- package/public/docs/logo-dark.svg +1 -0
- package/public/docs/logo-light.svg +1 -0
- package/public/docs/tuning-reference/anti-patterns.html +5 -5
- package/public/docs/tuning-reference/aqe.html +5 -5
- package/public/docs/tuning-reference/bottleneck-broadcast-sizing.html +5 -5
- package/public/docs/tuning-reference/bottleneck-cold-start.html +5 -5
- package/public/docs/tuning-reference/bottleneck-duplicate-plan-subtree.html +5 -5
- package/public/docs/tuning-reference/bottleneck-failures.html +5 -5
- package/public/docs/tuning-reference/bottleneck-gc.html +5 -5
- package/public/docs/tuning-reference/bottleneck-job-failure-rate.html +5 -5
- package/public/docs/tuning-reference/bottleneck-memory-utilization.html +5 -5
- package/public/docs/tuning-reference/bottleneck-retry-waste.html +5 -5
- package/public/docs/tuning-reference/bottleneck-shuffle.html +5 -5
- package/public/docs/tuning-reference/bottleneck-skew.html +5 -5
- package/public/docs/tuning-reference/bottleneck-slow-host.html +5 -5
- package/public/docs/tuning-reference/bottleneck-small-files.html +5 -5
- package/public/docs/tuning-reference/bottleneck-spill.html +5 -5
- package/public/docs/tuning-reference/bottleneck-straggler.html +5 -5
- package/public/docs/tuning-reference/bottleneck-tiny-tasks.html +5 -5
- package/public/docs/tuning-reference/bottleneck-utilization.html +5 -5
- package/public/docs/tuning-reference/caching.html +5 -5
- package/public/docs/tuning-reference/cluster-config.html +5 -5
- package/public/docs/tuning-reference/config.html +5 -5
- package/public/docs/tuning-reference/data-formats.html +5 -5
- package/public/docs/tuning-reference/index.html +5 -5
- package/public/docs/tuning-reference/intro.html +5 -5
- package/public/docs/tuning-reference/joins.html +5 -5
- package/public/docs/tuning-reference/memory-model.html +5 -5
- package/public/docs/tuning-reference/metrics.html +5 -5
- package/public/docs/tuning-reference/partitioning.html +5 -5
- package/public/docs/tuning-reference/pyspark.html +5 -5
- package/public/docs/tuning-reference/shuffle.html +5 -5
- package/public/docs/tuning-reference/spark-architecture.html +5 -5
- package/public/docs/tuning-reference/table-formats.html +5 -5
- package/public/docs/user-guide/alternative-log-retrieval/managed-platforms.html +5 -5
- package/public/docs/user-guide/alternative-log-retrieval/ssh-bastion.html +5 -5
- package/public/docs/user-guide/alternative-log-retrieval.html +5 -5
- package/public/docs/user-guide/getting-started/ci-and-automation.html +16 -11
- package/public/docs/user-guide/getting-started/reading-the-dashboard.html +6 -6
- package/public/docs/user-guide/getting-started/regression-metric-keys.html +5 -5
- package/public/docs/user-guide/getting-started/tuning-thresholds.html +7 -7
- package/public/docs/user-guide/getting-started.html +5 -5
- package/public/docs/user-guide/mcp-tools/compare-runs.html +16 -11
- package/public/docs/user-guide/mcp-tools/diagnose-run.html +28 -7
- package/public/docs/user-guide/mcp-tools/evaluate-budgets.html +6 -6
- package/public/docs/user-guide/mcp-tools/get-finding-documentation.html +5 -5
- package/public/docs/user-guide/mcp-tools/get-finding-evidence.html +7 -6
- package/public/docs/user-guide/mcp-tools/get-reference-doc.html +5 -5
- package/public/docs/user-guide/mcp-tools/get-run-summary.html +5 -5
- package/public/docs/user-guide/mcp-tools/list-runs.html +5 -5
- package/public/docs/user-guide/mcp-tools.html +6 -6
- package/public/docs/user-guide/run-comparison/how-stages-are-matched.html +5 -5
- package/public/docs/user-guide/run-comparison.html +6 -6
- package/public/docs/user-guide/understanding-findings.html +6 -6
- package/public/export-template.html +45 -45
- package/public/index.html +8 -7
- package/public/sample-runs/sample-run.ndjson.gz +0 -0
- package/vendor-core/allocation.js +25 -23
- package/vendor-core/analyzer.js +85 -58
- package/vendor-core/api-merge-writes.js +2 -0
- package/vendor-core/aqe-skew.js +347 -0
- package/vendor-core/cli/budgets.js +6 -4
- package/vendor-core/cli/collect-run-pair.js +89 -0
- package/vendor-core/cli/collect-run-worker.js +16 -0
- package/vendor-core/cli/collect-run.js +1 -2
- package/vendor-core/cli/native-zstd.js +12 -16
- package/vendor-core/comparability.js +234 -0
- package/vendor-core/comparison-output.js +15 -7
- package/vendor-core/comparison-verdict.js +105 -25
- package/vendor-core/core-source-hash.txt +1 -1
- package/vendor-core/core-time-series.js +0 -1
- package/vendor-core/core-usage-locality.js +1 -1
- package/vendor-core/detectors.js +1007 -380
- package/vendor-core/docs-config.js +0 -4
- package/vendor-core/docs-content/detection/cache.md +2 -1
- package/vendor-core/docs-content/detection/cfg.md +19 -11
- package/vendor-core/docs-content/detection/cold.md +2 -1
- package/vendor-core/docs-content/detection/gc.md +7 -3
- package/vendor-core/docs-content/detection/host.md +11 -1
- package/vendor-core/docs-content/detection/mem.md +17 -6
- package/vendor-core/docs-content/detection/part.md +3 -1
- package/vendor-core/docs-content/detection/plan.md +55 -13
- package/vendor-core/docs-content/detection/shfl.md +11 -5
- package/vendor-core/docs-content/detection/skew.md +47 -1
- package/vendor-core/docs-content/detection/slow.md +4 -2
- package/vendor-core/docs-content/detection/spec.md +6 -1
- package/vendor-core/docs-content/detection/spill.md +6 -3
- package/vendor-core/docs-content/detection/strag.md +19 -6
- package/vendor-core/docs-content/detection/tiny.md +9 -3
- package/vendor-core/effective-conf.js +7 -10
- package/vendor-core/efficiency-model.js +2 -2
- package/vendor-core/etl-phases.js +1 -2
- package/vendor-core/event-handlers.js +175 -57
- package/vendor-core/event-schemas.js +21 -16
- package/vendor-core/evidence-availability.js +9 -2
- package/vendor-core/evidence-report.js +118 -35
- package/vendor-core/executor-peaks.js +41 -0
- package/vendor-core/export-data.js +5 -5
- package/vendor-core/finding-identity.js +78 -0
- package/vendor-core/finding-presentation.js +116 -33
- package/vendor-core/finding-types.js +88 -21
- package/vendor-core/format-utils.js +14 -15
- package/vendor-core/html-export.js +1 -1
- package/vendor-core/impact-band.js +2 -2
- package/vendor-core/impact-format.js +47 -19
- package/vendor-core/impact-model.js +26 -15
- package/vendor-core/job-groups.js +4 -4
- package/vendor-core/mcp-server-factory.js +48 -12
- package/vendor-core/mcp-tools.js +179 -24
- package/vendor-core/median.js +2 -2
- package/vendor-core/nested-loop-join.js +73 -0
- package/vendor-core/occupancy.js +1 -2
- package/vendor-core/parser-worker.js +1 -1
- package/vendor-core/plan-graph-model.js +14 -22
- package/vendor-core/plan-node-detail.js +2 -3
- package/vendor-core/plan-summary.js +24 -19
- package/vendor-core/plan-tree-walk.js +6 -8
- package/vendor-core/python-stage.js +12 -1
- package/vendor-core/recommendation-rollup.js +13 -12
- package/vendor-core/redact.js +52 -46
- package/vendor-core/run-aggregates.js +6 -8
- package/vendor-core/run-comparison.js +226 -66
- package/vendor-core/run-identity.js +12 -0
- package/vendor-core/run-interpretation.js +21 -0
- package/vendor-core/run-metrics.js +2 -2
- package/vendor-core/run-output.js +32 -10
- package/vendor-core/run-totals.js +12 -0
- package/vendor-core/run-verdict.js +76 -3
- package/vendor-core/scaling-sim.js +3 -4
- package/vendor-core/snappy-block.js +2 -2
- package/vendor-core/spark-conf.js +168 -0
- package/vendor-core/sql-stages.js +2 -2
- package/vendor-core/stage-alignment.js +2 -12
- package/vendor-core/stage-identity.js +58 -3
- package/vendor-core/stage-label.js +14 -0
- package/vendor-core/stage-plan-nodes.js +17 -3
- package/vendor-core/stage-quantiles.js +141 -9
- package/vendor-core/stage-structure.js +17 -3
- package/vendor-core/threshold-overrides.js +9 -3
- package/vendor-core/types.js +58 -21
- package/vendor-core/wasted-core-hours.js +0 -1
- package/vendor-core/write-targets.js +114 -14
- package/vendor-core/zstd-worker-client.js +1 -1
- package/vendor-core/zstd-worker.js +1 -1
- package/public/assets/AutoscalingChurn-CRA2Mb7F.js +0 -1
- package/public/assets/CacheUtilization-Bh9OY_V9.js +0 -1
- package/public/assets/CachingOpportunity-oCiQwmTJ.js +0 -1
- package/public/assets/ColdStart-BJrtjfmn.js +0 -1
- package/public/assets/ConfigAudit-DMvKxySP.js +0 -1
- package/public/assets/CoreUsageArea-REC2zsKw.js +0 -1
- package/public/assets/Dashboard-BHZ76JCu.js +0 -2
- package/public/assets/DisclosureContext-OO7X1HAx.js +0 -1
- package/public/assets/DuplicatePlanSubtree-BgG-L-cK.js +0 -1
- package/public/assets/ExecutorUtilization-D2KhSVbY.js +0 -1
- package/public/assets/GcPressure-D1BTE8qh.js +0 -1
- package/public/assets/IncompleteRun-DD40xUpy.js +0 -1
- package/public/assets/JobFailures-YwNzCF19.js +0 -1
- package/public/assets/MemoryUtilization-9b8ee_3_.js +0 -1
- package/public/assets/OverBroadcast-CfctS8a8.js +0 -1
- package/public/assets/PartitionHint-CUvbnnxy.js +0 -1
- package/public/assets/PartitionSizing-VG8kBgG5.js +0 -1
- package/public/assets/PlanExplorer-DmubTAOP.js +0 -1
- package/public/assets/PlanGraphRoute-DctPZjS0.js +0 -1
- package/public/assets/RetryWaste-CnpM8bB7.js +0 -1
- package/public/assets/ShuffleIO-D13vGmas.js +0 -1
- package/public/assets/Skew-DlagstYP.js +0 -1
- package/public/assets/SlowHost-cSkLRZ_e.js +0 -1
- package/public/assets/SmallFiles-B-kERMcq.js +0 -1
- package/public/assets/SpeculationWaste-DaysAzXO.js +0 -1
- package/public/assets/Spill-H44Gz4US.js +0 -1
- package/public/assets/StageFailed-DCfii9h_.js +0 -1
- package/public/assets/StageFindingGroup-BXJ0Mj5n.js +0 -1
- package/public/assets/StageHeader--oN2J-oD.js +0 -1
- package/public/assets/StageShape-IZ80CZiJ.js +0 -1
- package/public/assets/StageSlowness--BRIaBc1.js +0 -1
- package/public/assets/Straggler-Ctq0Df_o.js +0 -1
- package/public/assets/TaskFailures-Bks_gqhL.js +0 -1
- package/public/assets/TinyTask-BssfzGFB.js +0 -1
- package/public/assets/UnderBroadcast-DsScrxc-.js +0 -1
- package/public/assets/charts-vendor-0VMaLVLN.js +0 -59
- package/public/assets/finding-anchor-BYW1oz5R.js +0 -1
- package/public/assets/impact-sort-xzy0g-Vh.js +0 -1
- package/public/assets/index-DhpRGMZc.css +0 -2
- package/public/assets/index-DwqkFUFk.js +0 -14
- package/public/assets/plan-graph-vendor-BYl-AzN5.js +0 -7
- package/public/assets/react-vendor-DfpuPQZf.js +0 -9
- package/public/assets/select-C8edjYTq.js +0 -1
- package/public/assets/usePagedRows-CsuUFeYx.js +0 -1
- package/public/assets/useRecentFiles-BvkKo3JN.js +0 -11
- package/public/assets/useSortMode-joX71BZN.js +0 -1
- package/public/docs/assets/chunks/@localSearchIndexroot.tE5pz54z.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_board-widgets.md.YQcj5EI4.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_board-widgets.md.YQcj5EI4.lean.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_board-widgets_plan-advisor.md.RlzvUmNm.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_board-widgets_visual-system-and-templating.md.wulOueeB.lean.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_detector-contract.md.N4hhenrA.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_detector-contract_plan-attribution.md.yNex4bys.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_detector-contract_plan-attribution.md.yNex4bys.lean.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_detector-contract_threshold-tables.md.Dp3c40rx.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_drill-down_plan-graph.md.DwOozIEs.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_impact-estimation.md.DfvbqEUu.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_impact-estimation_caveats-tuning-and-coverage.md.Cwm1jHmn.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_impact-estimation_stage-union-rollup.md.DdCGtAGu.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_impact-estimation_stage-union-rollup.md.DdCGtAGu.lean.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_overview.md.C1sSvm9i.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_state-and-history_run-comparison-internals.md.CZA0JLtV.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_widget-rendering.md.BOZ1azXG.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_widget-rendering_findings-tab.md.BQXycK6G.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_widget-rendering_findings-tab.md.BQXycK6G.lean.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_worker-protocol.md.BAnhi2-d.lean.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_worker-protocol_cli-and-mcp.md.BX1XnFbq.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_worker-protocol_evidence-report.md.CiQl1MLb.js +0 -1
- package/public/docs/assets/contributor-guide_contributing.md.CQMvGwFt.js +0 -1
- package/public/docs/assets/contributor-guide_development-setup.md.DQdzera7.js +0 -15
- package/public/docs/assets/contributor-guide_development-setup.md.DQdzera7.lean.js +0 -1
- package/public/docs/assets/contributor-guide_testing.md.By6XGR9a.js +0 -1
- package/public/docs/assets/user-guide_getting-started_ci-and-automation.md.BEepbDDL.js +0 -24
- package/public/docs/assets/user-guide_getting-started_reading-the-dashboard.md.Obf3W3__.js +0 -1
- package/public/docs/assets/user-guide_mcp-tools_compare-runs.md.Cc_gLoix.lean.js +0 -1
- package/public/docs/assets/user-guide_mcp-tools_diagnose-run.md.BP1vnHA5.js +0 -23
- package/public/docs/assets/user-guide_run-comparison.md.BUALkohi.js +0 -1
- package/public/docs/assets/user-guide_run-comparison.md.BUALkohi.lean.js +0 -1
- package/public/docs/assets/user-guide_understanding-findings.md.3C7KCEZO.js +0 -1
- package/public/docs/assets/user-guide_understanding-findings.md.3C7KCEZO.lean.js +0 -1
- /package/public/docs/assets/{contributor-guide_architecture_board-widgets_caching-and-memory.md.CQgn1t_M.lean.js → contributor-guide_architecture_board-widgets_caching-and-memory.md.BYDo3ClR.lean.js} +0 -0
- /package/public/docs/assets/{contributor-guide_architecture_board-widgets_plan-advisor.md.RlzvUmNm.lean.js → contributor-guide_architecture_board-widgets_plan-advisor.md.ajUAVdbc.lean.js} +0 -0
- /package/public/docs/assets/{contributor-guide_architecture_overview.md.C1sSvm9i.lean.js → contributor-guide_architecture_overview.md.nxkpOhgf.lean.js} +0 -0
- /package/public/docs/assets/{contributor-guide_architecture_widget-rendering.md.BOZ1azXG.lean.js → contributor-guide_architecture_widget-rendering.md.BrSz8Ezh.lean.js} +0 -0
- /package/public/docs/assets/{contributor-guide_architecture_widget-rendering_list-sort-mode.md.BuHKgH0C.lean.js → contributor-guide_architecture_widget-rendering_list-sort-mode.md.37hcZJ7q.lean.js} +0 -0
- /package/public/docs/assets/{contributor-guide_architecture_widget-rendering_row-expand-contract.md.ZT89u9f1.lean.js → contributor-guide_architecture_widget-rendering_row-expand-contract.md.mK_VmAWk.lean.js} +0 -0
- /package/public/docs/assets/{contributor-guide_architecture_worker-protocol_core-and-event-validation.md.DSVFPpWb.lean.js → contributor-guide_architecture_worker-protocol_core-and-event-validation.md.DVSXn-bb.lean.js} +0 -0
- /package/public/docs/assets/{contributor-guide_contributing.md.CQMvGwFt.lean.js → contributor-guide_contributing.md.DBW4drtZ.lean.js} +0 -0
- /package/public/docs/assets/{user-guide_getting-started_reading-the-dashboard.md.Obf3W3__.lean.js → user-guide_getting-started_reading-the-dashboard.md.CGaxPX_1.lean.js} +0 -0
- /package/public/docs/assets/{user-guide_mcp-tools.md.C65SjWUL.lean.js → user-guide_mcp-tools.md.49r3L2YE.lean.js} +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
import { medianOfSorted } from './median.js';
|
|
3
3
|
|
|
4
|
+
|
|
4
5
|
|
|
5
6
|
// Single source of truth for the packed per-task numeric array: FIELDS (offset
|
|
6
7
|
// constants), TASK_FIELD_NAMES (display labels), and the finalizeStage hot-loop
|
|
@@ -43,9 +44,8 @@ export const TASK_FIELD_NAMES = TASK_FIELD_DESCRIPTORS.map((d) => d.na
|
|
|
43
44
|
const TASK_FIELD_PROPS = TASK_FIELD_DESCRIPTORS.map((d) => d.prop);
|
|
44
45
|
|
|
45
46
|
// Numeric accumulator fields on `stage` that this function reads/increments.
|
|
46
|
-
// `stage`'s public parameter type stays the loose Record shape
|
|
47
|
-
//
|
|
48
|
-
// below, never a restatement of the object's real shape.
|
|
47
|
+
// `stage`'s public parameter type stays the loose Record shape; this narrow view is only for the
|
|
48
|
+
// arithmetic below, never a restatement of the object's real shape.
|
|
49
49
|
|
|
50
50
|
|
|
51
51
|
|
|
@@ -82,7 +82,8 @@ export function finalizeStage(
|
|
|
82
82
|
const localityStats = new Map();
|
|
83
83
|
let peakExecutionMemoryMax = 0;
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
const attempts = stage.taskAttempts;
|
|
86
|
+
for (const t of attempts.values()) {
|
|
86
87
|
taskCount++;
|
|
87
88
|
if (t.failed) {
|
|
88
89
|
failedTasks++;
|
|
@@ -105,7 +106,15 @@ export function finalizeStage(
|
|
|
105
106
|
}
|
|
106
107
|
if (t.executorId) {
|
|
107
108
|
let es = executorStats.get(t.executorId);
|
|
108
|
-
if (!es) { es = { taskCount: 0, totalDuration: 0, inputBytes: 0, shuffleReadBytes: 0, shuffleWriteBytes: 0 }; executorStats.set(t.executorId, es); }
|
|
109
|
+
if (!es) { es = { taskCount: 0, totalDuration: 0, logDurationSum: 0, logDurationM2: 0, inputBytes: 0, shuffleReadBytes: 0, shuffleWriteBytes: 0 }; executorStats.set(t.executorId, es); }
|
|
110
|
+
// Task durations scatter multiplicatively, so the spread slowHost tests an executor against is
|
|
111
|
+
// kept on the log scale: a running sum and Welford's M2 of ln(1 + duration). A non-finite
|
|
112
|
+
// duration makes both NaN, which the detector reads as "no spread known".
|
|
113
|
+
const logDuration = Math.log1p(t.duration);
|
|
114
|
+
const logMeanBefore = es.taskCount > 0 ? es.logDurationSum / es.taskCount : 0;
|
|
115
|
+
const logMeanAfter = (es.logDurationSum + logDuration) / (es.taskCount + 1);
|
|
116
|
+
es.logDurationM2 += (logDuration - logMeanBefore) * (logDuration - logMeanAfter);
|
|
117
|
+
es.logDurationSum += logDuration;
|
|
109
118
|
es.taskCount++;
|
|
110
119
|
es.totalDuration += t.duration;
|
|
111
120
|
es.inputBytes += t.inputBytes;
|
|
@@ -145,9 +154,9 @@ export function finalizeStage(
|
|
|
145
154
|
const { p50: spillMemP50, p95: spillMemP95, max: spillMemMax } = computeFieldQuantiles(arr, FIELDS.MEM_SPILLED);
|
|
146
155
|
const { p50: spillDiskP50, p95: spillDiskP95, max: spillDiskMax } = computeFieldQuantiles(arr, FIELDS.DISK_SPILLED);
|
|
147
156
|
|
|
148
|
-
// Straggler count: tasks with duration >
|
|
149
|
-
// task that isn't one.
|
|
150
|
-
const stragglerThreshold =
|
|
157
|
+
// Straggler count: tasks with duration > STRAGGLER_FACTOR * P50, their summed excess over P50, and
|
|
158
|
+
// the longest task that isn't one.
|
|
159
|
+
const stragglerThreshold = STRAGGLER_FACTOR * p50;
|
|
151
160
|
let stragglerCount = 0;
|
|
152
161
|
let stragglerExcessMs = 0;
|
|
153
162
|
let longestNonStragglerMs = 0;
|
|
@@ -160,6 +169,7 @@ export function finalizeStage(
|
|
|
160
169
|
}
|
|
161
170
|
}
|
|
162
171
|
|
|
172
|
+
const tailAttribution = p50 > 0 ? attributeTail(attempts.values() , p50) : null;
|
|
163
173
|
const peakConcurrentTasks = computePeakConcurrentTasks(arr);
|
|
164
174
|
const tailReplayRecoveryMs = stragglerCount > 0
|
|
165
175
|
? computeTailReplayRecoveryMs(arr, p50, peakConcurrentTasks)
|
|
@@ -169,7 +179,7 @@ export function finalizeStage(
|
|
|
169
179
|
([host, s]) => ({ host, taskCount: s.taskCount, totalDuration: s.totalDuration })
|
|
170
180
|
);
|
|
171
181
|
const executorStatsArr = [...executorStats.entries()].map(
|
|
172
|
-
([executorId, s]) => ({ executorId, taskCount: s.taskCount, totalDuration: s.totalDuration, inputBytes: s.inputBytes, shuffleReadBytes: s.shuffleReadBytes, shuffleWriteBytes: s.shuffleWriteBytes })
|
|
182
|
+
([executorId, s]) => ({ executorId, taskCount: s.taskCount, totalDuration: s.totalDuration, logDurationSum: s.logDurationSum, logDurationM2: s.logDurationM2, inputBytes: s.inputBytes, shuffleReadBytes: s.shuffleReadBytes, shuffleWriteBytes: s.shuffleWriteBytes })
|
|
173
183
|
);
|
|
174
184
|
const failureReasonsArr = [...failureReasons.entries()].map(
|
|
175
185
|
([reason, count]) => ({ reason, count })
|
|
@@ -191,6 +201,7 @@ export function finalizeStage(
|
|
|
191
201
|
peakExecutionMemoryMax,
|
|
192
202
|
taskActiveMs: computeTaskActiveMs(arr),
|
|
193
203
|
peakConcurrentTasks,
|
|
204
|
+
...(tailAttribution ? { tailAttribution } : {}),
|
|
194
205
|
taskDurationP50: p50,
|
|
195
206
|
taskDurationP95: p95,
|
|
196
207
|
taskDurationMax: max,
|
|
@@ -210,6 +221,127 @@ export function finalizeStage(
|
|
|
210
221
|
return { type: 'stage', data };
|
|
211
222
|
}
|
|
212
223
|
|
|
224
|
+
// A task is in the tail when it runs over this many times the stage's median task: skew's own
|
|
225
|
+
// P95/median ratio threshold, so every stage either detector flags on duration has a tail here.
|
|
226
|
+
export const TAIL_FACTOR = 3;
|
|
227
|
+
|
|
228
|
+
// A task is a straggler when it runs over this many times the stage's median task.
|
|
229
|
+
export const STRAGGLER_FACTOR = 4;
|
|
230
|
+
|
|
231
|
+
// The per-task fields attributeTail reads; a TaskRecord in event-handlers.ts has all of them.
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
// A hosts-concentration reading needs this many tail tasks on the host, at least this share of the
|
|
247
|
+
// tail, and at least this multiple of the host's share of all tasks, before the host explains the
|
|
248
|
+
// excess the other causes leave. One slow task on a host that ran a tenth of the stage is chance.
|
|
249
|
+
const TAIL_HOST_MIN_TASKS = 3;
|
|
250
|
+
const TAIL_HOST_MIN_TAIL_SHARE = 0.5;
|
|
251
|
+
const TAIL_HOST_MIN_OVERREPRESENTATION = 2;
|
|
252
|
+
|
|
253
|
+
// A median task that read next to nothing makes every ratio against it huge (a median of 4 bytes
|
|
254
|
+
// against a 1 MB task reads as 250000x). Below these floors the median task is read as having
|
|
255
|
+
// read almost nothing: there is no ratio to take, and a task counts as having read data only from
|
|
256
|
+
// the floors up.
|
|
257
|
+
const MIN_VOLUME_BYTES = 1024 * 1024;
|
|
258
|
+
const MIN_VOLUME_RECORDS = 1000;
|
|
259
|
+
|
|
260
|
+
// Why the stage's slow tasks (non-failed, over TAIL_FACTOR x P50) were slow, from what each task
|
|
261
|
+
// logged. A task's excess is its duration over P50. Four causes claim it, in this order so no
|
|
262
|
+
// millisecond counts twice:
|
|
263
|
+
// 1. Data: had run time scaled with data volume, the task would have taken P50 x (volume ratio)
|
|
264
|
+
// against the median task, with volume the task's input plus shuffle-read, in bytes or in
|
|
265
|
+
// records, whichever is further above the median. This is the definition Spark's UI and AQE
|
|
266
|
+
// use for skew (a partition far larger than the median one), applied to run time.
|
|
267
|
+
// 2. GC time over the median task's.
|
|
268
|
+
// 3. Shuffle fetch wait over the median task's.
|
|
269
|
+
// 4. Host: what is left of the tail tasks on the one host that holds most of the tail.
|
|
270
|
+
// With a median task that read almost nothing there is no ratio to take, so GC and fetch wait claim their
|
|
271
|
+
// excess first and a task that read data owns what they leave: the time was GC or waiting unless
|
|
272
|
+
// the data is all that is left to explain it.
|
|
273
|
+
// Null when the stage has no tail. `tasks` is consumed once.
|
|
274
|
+
export function attributeTail(tasks , p50 ) {
|
|
275
|
+
const all = [];
|
|
276
|
+
const tail = [];
|
|
277
|
+
for (const t of tasks) {
|
|
278
|
+
if (t.failed) continue; // a failed attempt's metrics stop where it died
|
|
279
|
+
all.push(t);
|
|
280
|
+
if (t.duration > TAIL_FACTOR * p50) tail.push(t);
|
|
281
|
+
}
|
|
282
|
+
if (tail.length === 0) return null;
|
|
283
|
+
|
|
284
|
+
const bytesOf = (t ) => t.inputBytes + t.shuffleRead;
|
|
285
|
+
const recordsOf = (t ) => t.inputRecords + t.shuffleReadRecords;
|
|
286
|
+
const medianBytes = medianOf(all, bytesOf);
|
|
287
|
+
const medianRecords = medianOf(all, recordsOf);
|
|
288
|
+
const medianGc = medianOf(all, (t) => t.gcTime);
|
|
289
|
+
const medianFetch = medianOf(all, (t) => t.fetchWaitTime);
|
|
290
|
+
const bytesComparable = medianBytes >= MIN_VOLUME_BYTES;
|
|
291
|
+
const recordsComparable = medianRecords >= MIN_VOLUME_RECORDS;
|
|
292
|
+
const hasVolume = bytesComparable || recordsComparable;
|
|
293
|
+
const volumeRatio = (t ) => Math.max(
|
|
294
|
+
bytesComparable ? bytesOf(t) / medianBytes : 0,
|
|
295
|
+
recordsComparable ? recordsOf(t) / medianRecords : 0,
|
|
296
|
+
);
|
|
297
|
+
const readsData = (t ) => bytesOf(t) >= MIN_VOLUME_BYTES || recordsOf(t) >= MIN_VOLUME_RECORDS;
|
|
298
|
+
|
|
299
|
+
const tailHosts = new Map ();
|
|
300
|
+
const allHosts = new Map ();
|
|
301
|
+
for (const t of all) if (t.host) allHosts.set(t.host, (allHosts.get(t.host) ?? 0) + 1);
|
|
302
|
+
for (const t of tail) if (t.host) tailHosts.set(t.host, (tailHosts.get(t.host) ?? 0) + 1);
|
|
303
|
+
let topHost = null;
|
|
304
|
+
for (const [host, n] of tailHosts) if (topHost === null || n > tailHosts.get(topHost) ) topHost = host;
|
|
305
|
+
const hostConcentrated = topHost !== null
|
|
306
|
+
&& tailHosts.get(topHost) >= TAIL_HOST_MIN_TASKS
|
|
307
|
+
&& tailHosts.get(topHost) / tail.length >= TAIL_HOST_MIN_TAIL_SHARE
|
|
308
|
+
&& (tailHosts.get(topHost) / tail.length) / (allHosts.get(topHost) / all.length) >= TAIL_HOST_MIN_OVERREPRESENTATION;
|
|
309
|
+
|
|
310
|
+
let excessMs = 0, dataMs = 0, gcMs = 0, fetchWaitMs = 0, hostMs = 0, cpuNs = 0, runMs = 0;
|
|
311
|
+
const ratios = [];
|
|
312
|
+
for (const t of tail) {
|
|
313
|
+
const excess = t.duration - p50;
|
|
314
|
+
excessMs += excess;
|
|
315
|
+
let left = excess;
|
|
316
|
+
if (hasVolume) {
|
|
317
|
+
const ratio = volumeRatio(t);
|
|
318
|
+
ratios.push(ratio);
|
|
319
|
+
const data = Math.min(left, Math.max(0, p50 * (ratio - 1)));
|
|
320
|
+
dataMs += data; left -= data;
|
|
321
|
+
}
|
|
322
|
+
const gc = Math.min(left, Math.max(0, t.gcTime - medianGc));
|
|
323
|
+
gcMs += gc; left -= gc;
|
|
324
|
+
const fetch = Math.min(left, Math.max(0, t.fetchWaitTime - medianFetch));
|
|
325
|
+
fetchWaitMs += fetch; left -= fetch;
|
|
326
|
+
if (!hasVolume && readsData(t)) { dataMs += left; left = 0; }
|
|
327
|
+
if (hostConcentrated && t.host === topHost) { hostMs += left; }
|
|
328
|
+
cpuNs += t.executorCpuTime;
|
|
329
|
+
runMs += t.executorRunTime;
|
|
330
|
+
}
|
|
331
|
+
ratios.sort((a, b) => a - b);
|
|
332
|
+
return {
|
|
333
|
+
tasks: tail.length, excessMs, dataMs, gcMs, fetchWaitMs, hostMs,
|
|
334
|
+
host: hostConcentrated ? topHost : null,
|
|
335
|
+
hostTasks: hostConcentrated ? tailHosts.get(topHost ) : 0,
|
|
336
|
+
dataRatio: hasVolume ? medianOfSorted(Float64Array.from(ratios)) : null,
|
|
337
|
+
cpuPct: cpuNs > 0 && runMs > 0 ? Math.min(100, (cpuNs / 1e6 / runMs) * 100) : null,
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function medianOf(tasks , valueOf ) {
|
|
342
|
+
return medianOfSorted(Float64Array.from(tasks, valueOf).sort());
|
|
343
|
+
}
|
|
344
|
+
|
|
213
345
|
// Wall-clock time during which at least one of the stage's tasks was running: the union of its
|
|
214
346
|
// [launch, finish) intervals. A stage's submittedAt..completedAt window also covers time it sat
|
|
215
347
|
// open with no task running (waiting for a free slot, or between retried tasks), which no
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// removed) and the token sets its similarity scores read. Pure.
|
|
4
4
|
|
|
5
5
|
import { cyrb53 } from './string-hash.js';
|
|
6
|
-
import { normalizeStageName, } from './stage-identity.js';
|
|
6
|
+
import { normalizeStageName, normalizedDetailOf, } from './stage-identity.js';
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
// Plumbing nodes: codegen boundaries and input adapters change with how Spark fuses a stage, not with
|
|
@@ -43,7 +43,7 @@ export function structuralKey(nodes ) {
|
|
|
43
43
|
const digestOf = (node ) => {
|
|
44
44
|
let d = digests.get(node);
|
|
45
45
|
if (d === undefined) {
|
|
46
|
-
d = cyrb53(JSON.stringify([normalizeStageName(node.name ?? ''),
|
|
46
|
+
d = cyrb53(JSON.stringify([normalizeStageName(node.name ?? ''), attributeNamesOf(node), below(node).sort()]));
|
|
47
47
|
digests.set(node, d);
|
|
48
48
|
}
|
|
49
49
|
return d;
|
|
@@ -53,6 +53,20 @@ export function structuralKey(nodes ) {
|
|
|
53
53
|
return cyrb53(JSON.stringify(roots));
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
// A node's attribute names are read by the structural key of every stage it ran in and by the
|
|
57
|
+
// execution's plan structure; a node is never mutated after the parser posts it.
|
|
58
|
+
const attributeNamesCache = new WeakMap ();
|
|
59
|
+
|
|
60
|
+
/** `attributeNames` of a plan node's detail, memoized per node. The array is shared: do not change it. */
|
|
61
|
+
export function attributeNamesOf(node ) {
|
|
62
|
+
let names = attributeNamesCache.get(node);
|
|
63
|
+
if (names === undefined) {
|
|
64
|
+
names = attributeNames(node.detail ?? '');
|
|
65
|
+
attributeNamesCache.set(node, names);
|
|
66
|
+
}
|
|
67
|
+
return names;
|
|
68
|
+
}
|
|
69
|
+
|
|
56
70
|
const TOKEN_SPLIT = /[^A-Za-z0-9_.$]+/;
|
|
57
71
|
|
|
58
72
|
/** Sorted distinct tokens of a stage's attributed nodes (name and normalized detail) and its name.
|
|
@@ -64,7 +78,7 @@ export function detailTokens(stageName , nodes
|
|
|
64
78
|
for (const node of nodes) {
|
|
65
79
|
if (isPlumbing(node)) continue;
|
|
66
80
|
add(normalizeStageName(node.name ?? ''));
|
|
67
|
-
add(
|
|
81
|
+
add(normalizedDetailOf(node, normalize));
|
|
68
82
|
}
|
|
69
83
|
return [...tokens].sort();
|
|
70
84
|
}
|
|
@@ -88,11 +88,17 @@ export function tunedThresholdsOf(entry , overrides
|
|
|
88
88
|
return Object.keys(tuned).length > 0 ? tuned : null;
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
// straggler judges a tail with skew's resolved thresholds (DetectorCtx.skewThresholds), so tuning skew
|
|
92
|
+
// changes which tails it reports without any `suppressedBy` link.
|
|
93
|
+
const THRESHOLD_DEPENDENCY = { straggler: 'skew' };
|
|
94
|
+
|
|
95
|
+
/** The tuned thresholds an entry's findings carry: its own, plus its `suppressedBy` entry's or the
|
|
96
|
+
* entry it reads thresholds from (named `<entry>.<threshold>`), since tuning either changes which
|
|
97
|
+
* of them survive. */
|
|
93
98
|
export function findingTunedThresholds(entry , overrides ) {
|
|
94
99
|
const own = tunedThresholdsOf(entry, overrides);
|
|
95
|
-
const
|
|
100
|
+
const suppressorType = entry.suppressedBy ?? THRESHOLD_DEPENDENCY[entry.type];
|
|
101
|
+
const suppressor = suppressorType ? entries.find((d) => d.type === suppressorType) : undefined;
|
|
96
102
|
const bySuppressor = suppressor ? tunedThresholdsOf(suppressor, overrides) : null;
|
|
97
103
|
if (!suppressor || !bySuppressor) return own;
|
|
98
104
|
const prefixed = Object.fromEntries(Object.entries(bySuppressor).map(([name, t]) => [`${suppressor.type}.${name}`, t]));
|
package/vendor-core/types.js
CHANGED
|
@@ -43,8 +43,7 @@
|
|
|
43
43
|
|
|
44
44
|
// Contract-pinned evidence `eventType`: the same fixed set as the parser's
|
|
45
45
|
// `evidenceInputs` counter keys, so provenance stays addressable against the
|
|
46
|
-
// documented `{ eventType, count }` shape
|
|
47
|
-
// from the counters they summarize).
|
|
46
|
+
// documented `{ eventType, count }` shape.
|
|
48
47
|
|
|
49
48
|
|
|
50
49
|
|
|
@@ -88,10 +87,10 @@
|
|
|
88
87
|
|
|
89
88
|
|
|
90
89
|
|
|
91
|
-
|
|
90
|
+
|
|
92
91
|
|
|
93
92
|
|
|
94
|
-
|
|
93
|
+
|
|
95
94
|
|
|
96
95
|
|
|
97
96
|
|
|
@@ -120,7 +119,7 @@
|
|
|
120
119
|
|
|
121
120
|
|
|
122
121
|
|
|
123
|
-
|
|
122
|
+
|
|
124
123
|
|
|
125
124
|
|
|
126
125
|
|
|
@@ -131,20 +130,51 @@
|
|
|
131
130
|
|
|
132
131
|
|
|
133
132
|
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
|
|
134
136
|
|
|
135
137
|
|
|
136
138
|
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
// The tail of a stage: its non-failed tasks over TAIL_FACTOR x P50. Each cause is the summed time
|
|
142
|
+
// (ms) of the tail's excess over P50 that the cause accounts for, taken in the order data, GC, fetch
|
|
143
|
+
// wait, host so that no millisecond counts twice; what none of them accounts for is
|
|
144
|
+
// excessMs - dataMs - gcMs - fetchWaitMs - hostMs.
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
|
|
137
165
|
|
|
138
166
|
|
|
139
167
|
|
|
140
168
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
169
|
+
|
|
170
|
+
|
|
144
171
|
|
|
145
172
|
|
|
146
173
|
|
|
147
|
-
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
|
|
148
178
|
|
|
149
179
|
|
|
150
180
|
|
|
@@ -161,6 +191,8 @@
|
|
|
161
191
|
|
|
162
192
|
|
|
163
193
|
|
|
194
|
+
|
|
195
|
+
|
|
164
196
|
|
|
165
197
|
|
|
166
198
|
|
|
@@ -179,19 +211,14 @@
|
|
|
179
211
|
|
|
180
212
|
|
|
181
213
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
|
|
192
219
|
|
|
193
220
|
|
|
194
|
-
|
|
221
|
+
|
|
195
222
|
|
|
196
223
|
|
|
197
224
|
|
|
@@ -289,6 +316,9 @@
|
|
|
289
316
|
|
|
290
317
|
|
|
291
318
|
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
|
|
292
322
|
|
|
293
323
|
|
|
294
324
|
|
|
@@ -316,6 +346,9 @@
|
|
|
316
346
|
|
|
317
347
|
|
|
318
348
|
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
|
|
319
352
|
|
|
320
353
|
|
|
321
354
|
|
|
@@ -332,6 +365,10 @@
|
|
|
332
365
|
|
|
333
366
|
|
|
334
367
|
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
|
|
335
372
|
|
|
336
373
|
|
|
337
374
|
|
|
@@ -363,7 +400,7 @@
|
|
|
363
400
|
|
|
364
401
|
|
|
365
402
|
|
|
366
|
-
|
|
403
|
+
|
|
367
404
|
|
|
368
405
|
|
|
369
406
|
|
|
@@ -40,7 +40,6 @@ export function computeWastedCoreHours(
|
|
|
40
40
|
runAggregates ,
|
|
41
41
|
executorsRemoved = [],
|
|
42
42
|
) {
|
|
43
|
-
// Nullish (not falsy) guard on times: a literal startTime:0 is valid.
|
|
44
43
|
if (!runAggregates || app?.startTime == null || app?.endTime == null) return EMPTY;
|
|
45
44
|
const appDurationMs = app.endTime - app.startTime;
|
|
46
45
|
if (appDurationMs <= 0) return EMPTY;
|
|
@@ -1,21 +1,14 @@
|
|
|
1
1
|
// Write targets: every SQL write command in a run's plans, with the path or table it writes to.
|
|
2
2
|
// Read by automation that halts a session when a target leaves its sandbox, so every rule here
|
|
3
|
-
// fails toward "target unknown" (null), never toward a guessed or partial target
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// - a write-like node outside the known list is reported as an unrecognized write;
|
|
8
|
-
// - an execution whose plan is not in the model (or whose start event could not be read) is
|
|
9
|
-
// listed, never skipped, and the count of unreadable log lines is reported;
|
|
10
|
-
// - a Delta target is set only when exactly one table or path is named (delta-targets.ts,
|
|
11
|
-
// api-merge-writes.ts).
|
|
12
|
-
// Targets are verbatim from the simpleString: nothing is resolved (relative paths, ${var}
|
|
13
|
-
// placeholders, catalog-relative table names all pass through as the log states them).
|
|
3
|
+
// fails toward "target unknown" (null), never toward a guessed or partial target, and targets are
|
|
4
|
+
// verbatim from the simpleString. Rules and fields: docs-site/user-guide/getting-started/ci-and-automation.md,
|
|
5
|
+
// "Write targets" (a node whose target cannot be parsed, a cut-short target, an unrecognized write,
|
|
6
|
+
// an unreadable execution, a Delta target named by exactly one table or path).
|
|
14
7
|
import { walkPlanTree } from './plan-tree-walk.js';
|
|
15
8
|
import { apiMergeWrites } from './api-merge-writes.js';
|
|
16
9
|
import { indexByRoot, isStagedDeltaWrite, parseDeltaTableV2, resolveDeltaCommandTarget, } from './delta-targets.js';
|
|
17
10
|
import { IDENT_PARTS, isCut, splitArgs, tableName, } from './write-target-args.js';
|
|
18
|
-
|
|
11
|
+
|
|
19
12
|
|
|
20
13
|
/** The row counts a MergeIntoCommand node reports in its SQL metrics. */
|
|
21
14
|
|
|
@@ -42,8 +35,25 @@ import { IDENT_PARTS, isCut, splitArgs, tableName, } from './write-targ
|
|
|
42
35
|
|
|
43
36
|
|
|
44
37
|
|
|
45
|
-
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
46
44
|
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
47
57
|
|
|
48
58
|
|
|
49
59
|
|
|
@@ -216,6 +226,14 @@ const DELTA_COMMANDS = new Set([
|
|
|
216
226
|
'CreateDeltaTableCommand', 'OptimizeTableCommand', 'RestoreTableCommand', 'DeltaReorgTableCommand',
|
|
217
227
|
]);
|
|
218
228
|
|
|
229
|
+
// Row-level and maintenance commands: a stage sum would misstate their output (their figures come
|
|
230
|
+
// from the command node's own counters, see commandOutputOf). A plain write is any other recognized
|
|
231
|
+
// write command.
|
|
232
|
+
const NOT_PLAIN_WRITES = new Set([
|
|
233
|
+
'MergeIntoCommand', 'UpdateCommand', 'DeleteCommand', 'DeltaMerge', 'ReplaceData', 'WriteDelta',
|
|
234
|
+
'CreateDeltaTableCommand', 'OptimizeTableCommand', 'RestoreTableCommand', 'DeltaReorgTableCommand',
|
|
235
|
+
]);
|
|
236
|
+
|
|
219
237
|
const ARG_PARSERS = {
|
|
220
238
|
InsertIntoHadoopFsRelationCommand: parseHadoopFsPath,
|
|
221
239
|
InsertIntoHiveTable: parseTableArg,
|
|
@@ -225,6 +243,11 @@ const ARG_PARSERS = {
|
|
|
225
243
|
SaveIntoDataSourceCommand: parseSaveIntoDataSource,
|
|
226
244
|
};
|
|
227
245
|
|
|
246
|
+
/** True for a recognized command that writes its output rows (not MERGE, UPDATE, DELETE or table maintenance). */
|
|
247
|
+
export function isPlainWrite(write ) {
|
|
248
|
+
return write.recognized && !NOT_PLAIN_WRITES.has(write.command);
|
|
249
|
+
}
|
|
250
|
+
|
|
228
251
|
function isKnownWrite(command ) {
|
|
229
252
|
return command in ARG_PARSERS || V2_WRITES.has(command) || V2_TABLE_AS_SELECT.has(command) || DELTA_COMMANDS.has(command);
|
|
230
253
|
}
|
|
@@ -254,6 +277,35 @@ function metricValue(node , ...names ) {
|
|
|
254
277
|
return metric !== undefined && Number.isFinite(metric.value) ? metric.value : null;
|
|
255
278
|
}
|
|
256
279
|
|
|
280
|
+
// Delta 4.x labels the DELETE copied-rows counter with a trailing period ("number of rows copied.");
|
|
281
|
+
// metricValue matches names exactly, so the counter lists both spellings.
|
|
282
|
+
const COPIED_ROWS_LABELS = ['number of rows copied.', 'number of rows copied'];
|
|
283
|
+
|
|
284
|
+
// Rows and bytes a MERGE, UPDATE or DELETE wrote to new files, from the command node's counters.
|
|
285
|
+
// A MERGE writes its inserted, updated and copied rows; an UPDATE writes the rows it touched
|
|
286
|
+
// (updated plus copied); a DELETE writes the target rows it copied. Rows removed by a DELETE or
|
|
287
|
+
// MERGE delete clause are not written, so they are not output rows.
|
|
288
|
+
function commandOutputOf(command , node ) {
|
|
289
|
+
if (command === 'MergeIntoCommand') {
|
|
290
|
+
const parts = [
|
|
291
|
+
metricValue(node, 'number of inserted rows'),
|
|
292
|
+
metricValue(node, 'number of updated rows'),
|
|
293
|
+
metricValue(node, 'number of target rows rewritten unmodified', 'number of rows copied'),
|
|
294
|
+
];
|
|
295
|
+
return {
|
|
296
|
+
rows: parts.some((v) => v === null) ? null : parts.reduce((sum, v) => sum + v , 0),
|
|
297
|
+
bytes: metricValue(node, 'number of target bytes added'),
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
if (command === 'UpdateCommand') {
|
|
301
|
+
return { rows: metricValue(node, 'number of rows touched (copied + updated)'), bytes: metricValue(node, 'number of bytes added') };
|
|
302
|
+
}
|
|
303
|
+
if (command === 'DeleteCommand') {
|
|
304
|
+
return { rows: metricValue(node, ...COPIED_ROWS_LABELS), bytes: metricValue(node, 'number of bytes added') };
|
|
305
|
+
}
|
|
306
|
+
return { rows: null, bytes: null };
|
|
307
|
+
}
|
|
308
|
+
|
|
257
309
|
function mergeRowsOf(command , node ) {
|
|
258
310
|
if (command !== 'MergeIntoCommand') return null;
|
|
259
311
|
const rows = {
|
|
@@ -273,6 +325,9 @@ function collectWrites(exec , root , byRoot
|
|
|
273
325
|
const [recognized, parsedFromDetail] = parseWrite(command, detail);
|
|
274
326
|
// A Delta command's simpleString is bare on real logs: its target is found elsewhere.
|
|
275
327
|
const parsed = parsedFromDetail ?? resolveDeltaCommandTarget(command, exec, node, byRoot);
|
|
328
|
+
const nodeRows = outputRowsOf(node);
|
|
329
|
+
const commandOutput = commandOutputOf(command, node);
|
|
330
|
+
const outputRows = nodeRows ?? commandOutput.rows;
|
|
276
331
|
out.push({
|
|
277
332
|
sqlExecutionId: exec.id,
|
|
278
333
|
nodeId: node.id ?? null,
|
|
@@ -280,7 +335,9 @@ function collectWrites(exec , root , byRoot
|
|
|
280
335
|
recognized,
|
|
281
336
|
kind: parsed?.kind ?? null,
|
|
282
337
|
target: parsed?.target ?? null,
|
|
283
|
-
outputRows
|
|
338
|
+
outputRows,
|
|
339
|
+
outputRowsSource: nodeRows !== null ? 'nodeMetric' : outputRows !== null ? 'commandMetric' : null,
|
|
340
|
+
outputBytes: commandOutput.bytes,
|
|
284
341
|
mergeRows: mergeRowsOf(command, node),
|
|
285
342
|
raw: detail !== '' ? detail : node.name,
|
|
286
343
|
});
|
|
@@ -301,7 +358,49 @@ function attributeStagedWrites(writes , sql
|
|
|
301
358
|
}
|
|
302
359
|
}
|
|
303
360
|
|
|
361
|
+
// The rows and bytes a plain write stored are reported by the stages of the executions under its
|
|
362
|
+
// root: a Delta DataFrame write's node sits in the root execution while its stages run in a child.
|
|
363
|
+
// Applied only when the root holds one logical write, so the stages cannot belong to another write.
|
|
364
|
+
function attachStageOutput(writes , sql , stages ) {
|
|
365
|
+
const byRoot = indexByRoot(sql);
|
|
366
|
+
const stagesByExecution = new Map ();
|
|
367
|
+
for (const stage of stages.values()) {
|
|
368
|
+
if (stage.sqlExecutionId == null) continue;
|
|
369
|
+
const list = stagesByExecution.get(stage.sqlExecutionId);
|
|
370
|
+
if (list) list.push(stage);
|
|
371
|
+
else stagesByExecution.set(stage.sqlExecutionId, [stage]);
|
|
372
|
+
}
|
|
373
|
+
const rootOf = (write ) => sql.get(write.sqlExecutionId)?.rootExecutionId ?? write.sqlExecutionId;
|
|
374
|
+
// One logical write per root: the plain writes that name the same table or path count once (a
|
|
375
|
+
// CTAS or RTAS node and the append it runs, Iceberg's replace and its overwrite). A write with no
|
|
376
|
+
// target, a MERGE, UPDATE or DELETE, or a second target in the root makes the stages ambiguous.
|
|
377
|
+
const identitiesPerRoot = new Map ();
|
|
378
|
+
writes.forEach((write, i) => {
|
|
379
|
+
const key = isPlainWrite(write) && write.target !== null ? `${write.kind}:${write.target}` : `#${i}`;
|
|
380
|
+
const root = rootOf(write);
|
|
381
|
+
const keys = identitiesPerRoot.get(root);
|
|
382
|
+
if (keys) keys.add(key);
|
|
383
|
+
else identitiesPerRoot.set(root, new Set([key]));
|
|
384
|
+
});
|
|
385
|
+
for (const write of writes) {
|
|
386
|
+
const root = rootOf(write);
|
|
387
|
+
if (!isPlainWrite(write) || identitiesPerRoot.get(root)?.size !== 1) continue;
|
|
388
|
+
const group = [root, ...(byRoot.get(root) ?? []).map((exec) => exec.id)];
|
|
389
|
+
const grouped = group.flatMap((id) => stagesByExecution.get(id) ?? []);
|
|
390
|
+
if (grouped.length === 0) continue;
|
|
391
|
+
const withBytes = grouped.filter((stage) => stage.outputBytes != null);
|
|
392
|
+
if (withBytes.length > 0) write.outputBytes = withBytes.reduce((sum, stage) => sum + stage.outputBytes , 0);
|
|
393
|
+
if (write.outputRows !== null) continue;
|
|
394
|
+
const reported = grouped.filter((stage) => stage.outputRecords != null);
|
|
395
|
+
if (reported.length === 0) continue;
|
|
396
|
+
write.outputRows = reported.reduce((sum, stage) => sum + stage.outputRecords , 0);
|
|
397
|
+
write.outputRowsSource = 'stageSum';
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
304
401
|
|
|
402
|
+
|
|
403
|
+
|
|
305
404
|
|
|
306
405
|
|
|
307
406
|
|
|
@@ -320,6 +419,7 @@ export function extractWriteTargets(sql , input
|
|
|
320
419
|
// DeltaTable API merges run no command node: they are found by their executions' descriptions.
|
|
321
420
|
attributeStagedWrites(writes, sql);
|
|
322
421
|
writes.push(...apiMergeWrites(sql));
|
|
422
|
+
if (input.stages) attachStageOutput(writes, sql, input.stages);
|
|
323
423
|
writes.sort((a, b) => a.sqlExecutionId - b.sqlExecutionId);
|
|
324
424
|
const executionsWithoutPlan = [...withoutPlan].sort((a, b) => a[0] - b[0])
|
|
325
425
|
.map(([sqlExecutionId, reason]) => ({ sqlExecutionId, reason }));
|
|
@@ -41,7 +41,7 @@ export const MAX_IN_FLIGHT_SLICES = 3;
|
|
|
41
41
|
// `spawn` starts the decompress worker; it runs at most once, on the first zstd stream, and the
|
|
42
42
|
// worker then serves every later stream (the files of a rolling log) one at a time. When it
|
|
43
43
|
// cannot start (no nested workers, a blocked script, a crash), each stream is decoded by
|
|
44
|
-
// `fallback` on the calling thread instead
|
|
44
|
+
// `fallback` on the calling thread instead.
|
|
45
45
|
export function createWorkerZstdDecoders(
|
|
46
46
|
spawn ,
|
|
47
47
|
fallback ,
|