sparkforensics-server 0.5.0 → 0.5.2
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/package.json +3 -3
- package/public/assets/{AutoscalingChurn-9Zo6IMGS.js → AutoscalingChurn-8t3U3isq.js} +1 -1
- package/public/assets/{CacheUtilization-MBDfMsKC.js → CacheUtilization-CJs9tTum.js} +1 -1
- package/public/assets/CachingOpportunity-D1NcHs0V.js +1 -0
- package/public/assets/{ColdStart-BtS12b6_.js → ColdStart-CdRJ9gD8.js} +1 -1
- package/public/assets/{ConfigAudit-DNPV6EQg.js → ConfigAudit-B5Gbe5js.js} +1 -1
- package/public/assets/CoreUsageArea-a--NTRGY.js +1 -0
- package/public/assets/{Dashboard-CC_BXrNy.js → Dashboard-C1hNeX49.js} +2 -2
- package/public/assets/DisclosureContext-ZpE6CkHx.js +1 -0
- package/public/assets/{DuplicatePlanSubtree-vN3zqRsi.js → DuplicatePlanSubtree-dobXdz7E.js} +1 -1
- package/public/assets/{ExecutorUtilization-CZObSLIj.js → ExecutorUtilization-D9grwi7t.js} +1 -1
- package/public/assets/{GcPressure-ByJlLOua.js → GcPressure-8-G2ri10.js} +1 -1
- package/public/assets/{IncompleteRun-MzqV4W8y.js → IncompleteRun-B91lky7a.js} +1 -1
- package/public/assets/{JobFailures-LbMvAwAb.js → JobFailures-BsWvBMyJ.js} +1 -1
- package/public/assets/{MemoryUtilization-DH4jYvJK.js → MemoryUtilization-BM5schZI.js} +1 -1
- package/public/assets/{OverBroadcast-euk6HKg4.js → OverBroadcast-DdN8JIJH.js} +1 -1
- package/public/assets/{PartitionHint-DThaMMRT.js → PartitionHint-CUvbnnxy.js} +1 -1
- package/public/assets/{PartitionSizing-yIN-iZzx.js → PartitionSizing-CY5HDYtp.js} +1 -1
- package/public/assets/{PlanExplorer-Dd9WPK4S.js → PlanExplorer-DgHCDBD_.js} +1 -1
- package/public/assets/PlanGraphRoute-DH3KJb8j.js +1 -0
- package/public/assets/{RetryWaste-CXH4D-xH.js → RetryWaste-DOnE9vGF.js} +1 -1
- package/public/assets/{ShuffleIO-CW7U68ph.js → ShuffleIO-MMnDESkF.js} +1 -1
- package/public/assets/{Skew-PL79TppX.js → Skew-BmZZJ5ms.js} +1 -1
- package/public/assets/{SlowHost-GBO73hCi.js → SlowHost-CsJzfEqo.js} +1 -1
- package/public/assets/{SmallFiles-B5cUjEav.js → SmallFiles-BoK3R1Ex.js} +1 -1
- package/public/assets/{SpeculationWaste-mxi3jgb0.js → SpeculationWaste-CnVxB5AJ.js} +1 -1
- package/public/assets/Spill-BhNicyBy.js +1 -0
- package/public/assets/{StageFailed-YvxC11ii.js → StageFailed-mAhHU4l_.js} +1 -1
- package/public/assets/StageFindingGroup-BEtPWcT0.js +1 -0
- package/public/assets/{StageHeader-BMNmUy-s.js → StageHeader-DJkYkrsU.js} +1 -1
- package/public/assets/{StageShape-DO3mQ6NS.js → StageShape-BDxRknLp.js} +1 -1
- package/public/assets/{StageSlowness-SwRxfAEx.js → StageSlowness-BPRw-otN.js} +1 -1
- package/public/assets/{Straggler-DHLTiBY-.js → Straggler-CZCbnOWP.js} +1 -1
- package/public/assets/{TaskFailures-Bj0QxiOc.js → TaskFailures-C57YcLFQ.js} +1 -1
- package/public/assets/{TinyTask-COUQQ5bQ.js → TinyTask-Bi84qU7n.js} +1 -1
- package/public/assets/{UnderBroadcast-RAUbQ6vw.js → UnderBroadcast-DdQV7htE.js} +1 -1
- package/public/assets/{finding-anchor-Dl8mIHiU.js → finding-anchor-Cl6_5hfV.js} +1 -1
- package/public/assets/{impact-sort-Eihua9dY.js → impact-sort-CssZ6MT2.js} +1 -1
- package/public/assets/index-2h_TgUAb.css +2 -0
- package/public/assets/index-B-03mG7K.js +14 -0
- package/public/assets/parser-worker-CA5RxqKc.js +122 -0
- package/public/assets/{plan-graph-vendor-B0sEms9Z.js → plan-graph-vendor-BYl-AzN5.js} +1 -1
- package/public/assets/{react-vendor-BAKt3vny.js → react-vendor-DEdfrRTJ.js} +1 -1
- package/public/assets/{select-DkjFHlXR.js → select-CQjNhprm.js} +1 -1
- package/public/assets/{usePagedRows-Bo-aSztx.js → usePagedRows-Dyl6T8Ok.js} +1 -1
- package/public/assets/useRecentFiles-XZEnLlal.js +11 -0
- package/public/assets/{useSortMode-lDedD5a3.js → useSortMode-Dhvit8dt.js} +1 -1
- package/public/docs/404.html +2 -2
- package/public/docs/assets/{app.yjczoibf.js → app.eYTPqTeq.js} +1 -1
- package/public/docs/assets/chunks/@localSearchIndexroot.u_e5bQz4.js +1 -0
- package/public/docs/assets/chunks/{VPLocalSearchBox.DOBbPfix.js → VPLocalSearchBox.DsZrQKQR.js} +1 -1
- package/public/docs/assets/chunks/{theme.DFcAl8Ws.js → theme.DsTNE2pE.js} +2 -2
- package/public/docs/assets/contributor-guide_architecture_board-widgets.md.YQcj5EI4.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_board-widgets.md.D0Kkk_r5.lean.js → contributor-guide_architecture_board-widgets.md.YQcj5EI4.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_board-widgets_caching-and-memory.md.8bH1HnZp.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_board-widgets_caching-and-memory.md.8bH1HnZp.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_board-widgets_plan-advisor.md.RlzvUmNm.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_board-widgets_plan-advisor.md.RlzvUmNm.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_board-widgets_visual-system-and-templating.md.DYgUpIJB.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_board-widgets_visual-system-and-templating.md.DYgUpIJB.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_detector-contract.md.wj6Et6UD.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_detector-contract.md.wj6Et6UD.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_detector-contract_plan-attribution.md.yNex4bys.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_detector-contract_plan-attribution.md.yNex4bys.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_detector-contract_threshold-tables.md.CKjWG56Y.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_detector-contract_threshold-tables.md.CKjWG56Y.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_drill-down.md.CqZPrdo9.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_drill-down.md.CqZPrdo9.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_drill-down_plan-graph.md.DwOozIEs.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_drill-down_plan-graph.md.DwOozIEs.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_impact-estimation.md.CZv_ZGOp.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_impact-estimation.md.CZv_ZGOp.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_impact-estimation_caveats-tuning-and-coverage.md.BUucRc0A.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_impact-estimation_caveats-tuning-and-coverage.md.BUucRc0A.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_impact-estimation_stage-union-rollup.md.DdCGtAGu.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_impact-estimation_stage-union-rollup.md.DdCGtAGu.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_index.md.tymxf1Fh.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_index.md.B9yZieYL.lean.js → contributor-guide_architecture_index.md.tymxf1Fh.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_overview.md.C1sSvm9i.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_state-and-history.md.DyCBdjuM.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_state-and-history.md.w4lwybdh.lean.js → contributor-guide_architecture_state-and-history.md.DyCBdjuM.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_state-and-history_history-server-intake.md.C298hrHZ.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_state-and-history_history-server-intake.md.C298hrHZ.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_state-and-history_run-comparison-internals.md.CZA0JLtV.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_state-and-history_run-comparison-internals.md.CZA0JLtV.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_widget-rendering.md.BOZ1azXG.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_widget-rendering.md.BOZ1azXG.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_widget-rendering_findings-tab.md.BQXycK6G.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_widget-rendering_findings-tab.md.BQXycK6G.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_widget-rendering_investigation-routing.md.BGdiyElu.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_widget-rendering_investigation-routing.md.BGdiyElu.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_widget-rendering_list-sort-mode.md.BuHKgH0C.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_widget-rendering_list-sort-mode.md.BuHKgH0C.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_widget-rendering_reference-section.md.DWqC80bN.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_widget-rendering_reference-section.md.DWqC80bN.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_widget-rendering_row-expand-contract.md.ZT89u9f1.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_widget-rendering_row-expand-contract.md.ZT89u9f1.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_worker-protocol.md.BAnhi2-d.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_worker-protocol.md.BAnhi2-d.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_worker-protocol_cli-and-mcp.md.DC1YqXBp.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_worker-protocol_cli-and-mcp.md.DC1YqXBp.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_worker-protocol_core-and-event-validation.md.DSVFPpWb.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_worker-protocol_core-and-event-validation.md.DSVFPpWb.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_worker-protocol_evidence-availability.md.CjimIDBY.js +6 -0
- package/public/docs/assets/contributor-guide_architecture_worker-protocol_evidence-availability.md.CjimIDBY.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_worker-protocol_evidence-report.md.DVGZOWvW.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_worker-protocol_evidence-report.md.DVGZOWvW.lean.js +1 -0
- package/public/docs/assets/user-guide_alternative-log-retrieval.md.CJpYvHGo.js +4 -0
- package/public/docs/assets/user-guide_alternative-log-retrieval.md.CJpYvHGo.lean.js +1 -0
- package/public/docs/assets/user-guide_alternative-log-retrieval_managed-platforms.md.DvDwHNtC.js +4 -0
- package/public/docs/assets/user-guide_alternative-log-retrieval_managed-platforms.md.DvDwHNtC.lean.js +1 -0
- package/public/docs/assets/user-guide_alternative-log-retrieval_ssh-bastion.md.Gszzlplv.js +1 -0
- package/public/docs/assets/user-guide_alternative-log-retrieval_ssh-bastion.md.Gszzlplv.lean.js +1 -0
- package/public/docs/assets/user-guide_getting-started.md.DYHHHkQR.js +1 -0
- package/public/docs/assets/user-guide_getting-started.md.DYHHHkQR.lean.js +1 -0
- package/public/docs/assets/user-guide_getting-started_ci-and-automation.md.OUQqw3mI.js +23 -0
- package/public/docs/assets/user-guide_getting-started_ci-and-automation.md.OUQqw3mI.lean.js +1 -0
- package/public/docs/assets/user-guide_getting-started_reading-the-dashboard.md.Obf3W3__.js +1 -0
- package/public/docs/assets/user-guide_getting-started_reading-the-dashboard.md.Obf3W3__.lean.js +1 -0
- package/public/docs/assets/user-guide_getting-started_regression-metric-keys.md.B_gzr2Mw.js +1 -0
- package/public/docs/assets/user-guide_getting-started_regression-metric-keys.md.B_gzr2Mw.lean.js +1 -0
- package/public/docs/assets/user-guide_getting-started_tuning-thresholds.md.B_MyjyZm.js +4 -0
- package/public/docs/assets/user-guide_getting-started_tuning-thresholds.md.B_MyjyZm.lean.js +1 -0
- package/public/docs/assets/user-guide_mcp-tools.md.C65SjWUL.js +16 -0
- package/public/docs/assets/user-guide_mcp-tools.md.C65SjWUL.lean.js +1 -0
- package/public/docs/assets/user-guide_mcp-tools_compare-runs.md.Cc_gLoix.js +56 -0
- package/public/docs/assets/user-guide_mcp-tools_compare-runs.md.Cc_gLoix.lean.js +1 -0
- package/public/docs/assets/user-guide_mcp-tools_diagnose-run.md.BP1vnHA5.js +23 -0
- package/public/docs/assets/user-guide_mcp-tools_diagnose-run.md.BP1vnHA5.lean.js +1 -0
- package/public/docs/assets/user-guide_mcp-tools_evaluate-budgets.md.BB0nDY3Z.js +26 -0
- package/public/docs/assets/user-guide_mcp-tools_evaluate-budgets.md.BB0nDY3Z.lean.js +1 -0
- package/public/docs/assets/user-guide_mcp-tools_get-finding-documentation.md.BtTTHNV6.js +14 -0
- package/public/docs/assets/user-guide_mcp-tools_get-finding-documentation.md.BtTTHNV6.lean.js +1 -0
- package/public/docs/assets/user-guide_mcp-tools_get-finding-evidence.md.rKyu4wts.js +20 -0
- package/public/docs/assets/user-guide_mcp-tools_get-finding-evidence.md.rKyu4wts.lean.js +1 -0
- package/public/docs/assets/user-guide_mcp-tools_get-reference-doc.md.Yac4tH3u.js +5 -0
- package/public/docs/assets/user-guide_mcp-tools_get-reference-doc.md.Yac4tH3u.lean.js +1 -0
- package/public/docs/assets/user-guide_mcp-tools_get-run-summary.md.DpxZ4ZNp.js +15 -0
- package/public/docs/assets/user-guide_mcp-tools_get-run-summary.md.DpxZ4ZNp.lean.js +1 -0
- package/public/docs/assets/user-guide_mcp-tools_list-runs.md.DpQPeCM3.js +12 -0
- package/public/docs/assets/user-guide_mcp-tools_list-runs.md.DpQPeCM3.lean.js +1 -0
- package/public/docs/assets/user-guide_run-comparison.md.BUALkohi.js +1 -0
- package/public/docs/assets/user-guide_run-comparison.md.BUALkohi.lean.js +1 -0
- package/public/docs/assets/user-guide_run-comparison_how-stages-are-matched.md.DSXGu2tA.js +1 -0
- package/public/docs/assets/user-guide_run-comparison_how-stages-are-matched.md.DSXGu2tA.lean.js +1 -0
- package/public/docs/assets/user-guide_understanding-findings.md.C9YRruMT.js +1 -0
- package/public/docs/assets/user-guide_understanding-findings.md.C9YRruMT.lean.js +1 -0
- package/public/docs/contributor-guide/architecture/board-widgets/caching-and-memory.html +30 -0
- package/public/docs/contributor-guide/architecture/board-widgets/plan-advisor.html +30 -0
- package/public/docs/contributor-guide/architecture/board-widgets/visual-system-and-templating.html +30 -0
- package/public/docs/contributor-guide/architecture/board-widgets.html +5 -5
- package/public/docs/contributor-guide/architecture/detector-contract/plan-attribution.html +30 -0
- package/public/docs/contributor-guide/architecture/detector-contract/threshold-tables.html +30 -0
- package/public/docs/contributor-guide/architecture/detector-contract.html +5 -5
- package/public/docs/contributor-guide/architecture/drill-down/plan-graph.html +30 -0
- package/public/docs/contributor-guide/architecture/drill-down.html +5 -5
- package/public/docs/contributor-guide/architecture/impact-estimation/caveats-tuning-and-coverage.html +30 -0
- package/public/docs/contributor-guide/architecture/impact-estimation/stage-union-rollup.html +30 -0
- package/public/docs/contributor-guide/architecture/impact-estimation.html +5 -5
- package/public/docs/contributor-guide/architecture/index.html +5 -5
- package/public/docs/contributor-guide/architecture/overview.html +5 -5
- package/public/docs/contributor-guide/architecture/state-and-history/history-server-intake.html +30 -0
- package/public/docs/contributor-guide/architecture/state-and-history/run-comparison-internals.html +30 -0
- package/public/docs/contributor-guide/architecture/state-and-history.html +5 -5
- package/public/docs/contributor-guide/architecture/widget-rendering/findings-tab.html +30 -0
- package/public/docs/contributor-guide/architecture/widget-rendering/investigation-routing.html +30 -0
- package/public/docs/contributor-guide/architecture/widget-rendering/list-sort-mode.html +30 -0
- package/public/docs/contributor-guide/architecture/widget-rendering/reference-section.html +30 -0
- package/public/docs/contributor-guide/architecture/widget-rendering/row-expand-contract.html +30 -0
- package/public/docs/contributor-guide/architecture/widget-rendering.html +5 -5
- package/public/docs/contributor-guide/architecture/worker-protocol/cli-and-mcp.html +30 -0
- package/public/docs/contributor-guide/architecture/worker-protocol/core-and-event-validation.html +30 -0
- package/public/docs/contributor-guide/architecture/worker-protocol/evidence-availability.html +35 -0
- package/public/docs/contributor-guide/architecture/worker-protocol/evidence-report.html +30 -0
- package/public/docs/contributor-guide/architecture/worker-protocol.html +5 -10
- package/public/docs/contributor-guide/contributing.html +4 -4
- package/public/docs/contributor-guide/development-setup.html +4 -4
- package/public/docs/contributor-guide/testing.html +4 -4
- package/public/docs/hashmap.json +1 -1
- package/public/docs/index.html +3 -3
- package/public/docs/tuning-reference/anti-patterns.html +3 -3
- package/public/docs/tuning-reference/aqe.html +3 -3
- package/public/docs/tuning-reference/bottleneck-broadcast-sizing.html +3 -3
- package/public/docs/tuning-reference/bottleneck-cold-start.html +3 -3
- package/public/docs/tuning-reference/bottleneck-duplicate-plan-subtree.html +3 -3
- package/public/docs/tuning-reference/bottleneck-failures.html +3 -3
- package/public/docs/tuning-reference/bottleneck-gc.html +3 -3
- package/public/docs/tuning-reference/bottleneck-job-failure-rate.html +3 -3
- package/public/docs/tuning-reference/bottleneck-memory-utilization.html +3 -3
- package/public/docs/tuning-reference/bottleneck-retry-waste.html +3 -3
- package/public/docs/tuning-reference/bottleneck-shuffle.html +3 -3
- package/public/docs/tuning-reference/bottleneck-skew.html +3 -3
- package/public/docs/tuning-reference/bottleneck-slow-host.html +3 -3
- package/public/docs/tuning-reference/bottleneck-small-files.html +3 -3
- package/public/docs/tuning-reference/bottleneck-spill.html +3 -3
- package/public/docs/tuning-reference/bottleneck-straggler.html +3 -3
- package/public/docs/tuning-reference/bottleneck-tiny-tasks.html +3 -3
- package/public/docs/tuning-reference/bottleneck-utilization.html +3 -3
- package/public/docs/tuning-reference/caching.html +3 -3
- package/public/docs/tuning-reference/cluster-config.html +3 -3
- package/public/docs/tuning-reference/config.html +3 -3
- package/public/docs/tuning-reference/data-formats.html +3 -3
- package/public/docs/tuning-reference/index.html +3 -3
- package/public/docs/tuning-reference/intro.html +3 -3
- package/public/docs/tuning-reference/joins.html +3 -3
- package/public/docs/tuning-reference/memory-model.html +3 -3
- package/public/docs/tuning-reference/metrics.html +3 -3
- package/public/docs/tuning-reference/partitioning.html +3 -3
- package/public/docs/tuning-reference/pyspark.html +3 -3
- package/public/docs/tuning-reference/shuffle.html +3 -3
- package/public/docs/tuning-reference/spark-architecture.html +3 -3
- package/public/docs/tuning-reference/table-formats.html +3 -3
- package/public/docs/user-guide/alternative-log-retrieval/managed-platforms.html +33 -0
- package/public/docs/user-guide/alternative-log-retrieval/ssh-bastion.html +30 -0
- package/public/docs/user-guide/alternative-log-retrieval.html +6 -9
- package/public/docs/user-guide/getting-started/ci-and-automation.html +52 -0
- package/public/docs/user-guide/getting-started/reading-the-dashboard.html +30 -0
- package/public/docs/user-guide/getting-started/regression-metric-keys.html +30 -0
- package/public/docs/user-guide/getting-started/tuning-thresholds.html +33 -0
- package/public/docs/user-guide/getting-started.html +5 -28
- package/public/docs/user-guide/mcp-tools/compare-runs.html +85 -0
- package/public/docs/user-guide/mcp-tools/diagnose-run.html +52 -0
- package/public/docs/user-guide/mcp-tools/evaluate-budgets.html +55 -0
- package/public/docs/user-guide/mcp-tools/get-finding-documentation.html +43 -0
- package/public/docs/user-guide/mcp-tools/get-finding-evidence.html +49 -0
- package/public/docs/user-guide/mcp-tools/get-reference-doc.html +34 -0
- package/public/docs/user-guide/mcp-tools/get-run-summary.html +44 -0
- package/public/docs/user-guide/mcp-tools/list-runs.html +41 -0
- package/public/docs/user-guide/mcp-tools.html +8 -140
- package/public/docs/user-guide/run-comparison/how-stages-are-matched.html +30 -0
- package/public/docs/user-guide/run-comparison.html +5 -5
- package/public/docs/user-guide/understanding-findings.html +5 -5
- package/public/export-template.html +45 -45
- package/public/index.html +5 -5
- package/vendor-core/analyzer.js +1 -1
- package/vendor-core/api-merge-writes.js +80 -0
- package/vendor-core/cli/budgets.js +62 -2
- package/vendor-core/cli/regression-budgets.js +35 -0
- package/vendor-core/comparison-output.js +50 -0
- package/vendor-core/core-source-hash.txt +1 -1
- package/vendor-core/delta-commands.js +13 -0
- package/vendor-core/delta-log-paths.js +42 -0
- package/vendor-core/delta-targets.js +127 -0
- package/vendor-core/detectors.js +219 -56
- package/vendor-core/docs-content/detection/chrn.md +3 -1
- package/vendor-core/docs-content/detection/cold.md +2 -1
- package/vendor-core/docs-content/detection/plan.md +9 -2
- package/vendor-core/docs-content/detection/shfl.md +8 -2
- package/vendor-core/docs-content/detection/skew.md +11 -5
- package/vendor-core/docs-content/detection/slow.md +6 -2
- package/vendor-core/docs-content/detection/spill.md +4 -1
- package/vendor-core/docs-content/detection/strag.md +5 -3
- package/vendor-core/docs-content/detection/tiny.md +3 -2
- package/vendor-core/event-handlers.js +95 -9
- package/vendor-core/event-schemas.js +3 -1
- package/vendor-core/evidence-report.js +24 -15
- package/vendor-core/finding-presentation.js +39 -13
- package/vendor-core/finding-types.js +50 -6
- package/vendor-core/mcp-server-factory.js +17 -6
- package/vendor-core/mcp-tools.js +53 -35
- package/vendor-core/median.js +8 -0
- package/vendor-core/plan-graph-model.js +1 -1
- package/vendor-core/plan-summary.js +13 -10
- package/vendor-core/run-comparison.js +81 -120
- package/vendor-core/run-output.js +26 -0
- package/vendor-core/sequence-alignment.js +83 -0
- package/vendor-core/stage-alignment.js +586 -0
- package/vendor-core/stage-identity.js +112 -0
- package/vendor-core/stage-quantiles.js +3 -1
- package/vendor-core/stage-structure.js +83 -0
- package/vendor-core/types.js +5 -0
- package/vendor-core/write-target-args.js +48 -0
- package/vendor-core/write-targets.js +35 -52
- package/public/assets/CachingOpportunity-Cfw3wAFa.js +0 -1
- package/public/assets/CoreUsageArea-BObEeenE.js +0 -1
- package/public/assets/DisclosureContext-Ds0hcZFn.js +0 -1
- package/public/assets/PlanGraphRoute-NV5mCXRm.js +0 -1
- package/public/assets/Spill-CH1bNpxL.js +0 -1
- package/public/assets/StageFindingGroup-B1A0nf-e.js +0 -1
- package/public/assets/index-BcqTLKFp.css +0 -2
- package/public/assets/index-DaC8A2FS.js +0 -13
- package/public/assets/parser-worker-CfDvPkwF.js +0 -122
- package/public/assets/useRecentFiles-Bb4-ukVz.js +0 -11
- package/public/docs/assets/chunks/@localSearchIndexroot.r9imX8Aq.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_board-widgets.md.D0Kkk_r5.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_detector-contract.md.caA46z-u.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_detector-contract.md.caA46z-u.lean.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_drill-down.md.CdtlKHl-.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_drill-down.md.CdtlKHl-.lean.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_impact-estimation.md.BNp14LtL.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_impact-estimation.md.BNp14LtL.lean.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_index.md.B9yZieYL.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_overview.md.DBGo-bwn.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_state-and-history.md.w4lwybdh.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_widget-rendering.md.CcvqxnZI.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_widget-rendering.md.CcvqxnZI.lean.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_worker-protocol.md.CKeFttKj.js +0 -6
- package/public/docs/assets/contributor-guide_architecture_worker-protocol.md.CKeFttKj.lean.js +0 -1
- package/public/docs/assets/user-guide_alternative-log-retrieval.md.z-8npxNk.js +0 -7
- package/public/docs/assets/user-guide_alternative-log-retrieval.md.z-8npxNk.lean.js +0 -1
- package/public/docs/assets/user-guide_getting-started.md.BJW5oVhe.js +0 -24
- package/public/docs/assets/user-guide_getting-started.md.BJW5oVhe.lean.js +0 -1
- package/public/docs/assets/user-guide_mcp-tools.md.DcLiOa9t.js +0 -148
- package/public/docs/assets/user-guide_mcp-tools.md.DcLiOa9t.lean.js +0 -1
- package/public/docs/assets/user-guide_run-comparison.md.qin0a4IX.js +0 -1
- package/public/docs/assets/user-guide_run-comparison.md.qin0a4IX.lean.js +0 -1
- package/public/docs/assets/user-guide_understanding-findings.md.DzReyCXb.js +0 -1
- package/public/docs/assets/user-guide_understanding-findings.md.DzReyCXb.lean.js +0 -1
- /package/public/docs/assets/{contributor-guide_architecture_overview.md.DBGo-bwn.lean.js → contributor-guide_architecture_overview.md.C1sSvm9i.lean.js} +0 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { cyrb53 } from './string-hash.js';
|
|
2
|
+
import { planNodesOfStage } from './stage-plan-nodes.js';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
// The stage-identity recipe, parameterized by the detail normalizer. `stageIdentity` (the frozen
|
|
7
|
+
// exact key, run-comparison.ts) runs it with `normalizeDetail`; the aligner's `comparisonIdentity`
|
|
8
|
+
// runs it with the comparison normalizer. One recipe, so the two keys can differ only in how a
|
|
9
|
+
// detail string is normalized.
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
// Replace run-varying tokens (digit runs, long hex ids) with a stable marker so
|
|
14
|
+
// the same logical stage across two runs normalizes to one identity.
|
|
15
|
+
export function normalizeStageName(name ) {
|
|
16
|
+
return String(name)
|
|
17
|
+
.toLowerCase()
|
|
18
|
+
.replace(/\b[0-9a-f]{8,}\b/g, '#') // hex ids/uuids first (they contain digits)
|
|
19
|
+
.replace(/\d+/g, '#')
|
|
20
|
+
.replace(/\s+/g, ' ')
|
|
21
|
+
.trim();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Bottom-up, order-independent structural identity of a resolved plan tree:
|
|
25
|
+
// each node folds its normalized name/detail with its children's digests
|
|
26
|
+
// (children sorted, so AQE picking a different broadcast side still matches),
|
|
27
|
+
// so two plans collide only when their whole shape and every node's detail
|
|
28
|
+
// agree. `normalizeDetail` strips the run-to-run noise (expr ids, `plan_id=`,
|
|
29
|
+
// codegen numbers, AQE build-side choice, commutative-operand order). Each
|
|
30
|
+
// node folds to a fixed-length cyrb53 digest (JSON.stringify-encoded, so
|
|
31
|
+
// detail text containing `<`/`>`/`{`/`,` can't collide two different plans)
|
|
32
|
+
// instead of embedding full child identity strings, which would re-escape
|
|
33
|
+
// every level below and blow identity size up to ~2^depth on the 20-60+
|
|
34
|
+
// operator-deep plans real Spark produces.
|
|
35
|
+
function planTreeIdentity(root , normalizeDetail ) {
|
|
36
|
+
if (!root) return null;
|
|
37
|
+
function visit(node ) {
|
|
38
|
+
const childDigests = (node.children ?? []).map(visit).sort();
|
|
39
|
+
return cyrb53(JSON.stringify([normalizeStageName(node.name ?? ''), normalizeDetail(node.detail ?? ''), childDigests]));
|
|
40
|
+
}
|
|
41
|
+
return visit(root);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Plan identity for the stage's SQL execution, scoped to only the plan nodes
|
|
45
|
+
// this stage actually ran (`node.stageIds`), not the whole tree: two stages
|
|
46
|
+
// sharing one SQL execution (e.g. a self-join's two Exchange stages) otherwise
|
|
47
|
+
// collapse onto one identity regardless of which part of the plan each ran.
|
|
48
|
+
// Falls back to the coarser whole-tree identity when the stage has no
|
|
49
|
+
// attributed nodes (hand-built snapshots without `stageIds`, or unmatched
|
|
50
|
+
// accumulables).
|
|
51
|
+
function sqlNodeIdentity(
|
|
52
|
+
stage , snapshot , normalizeDetail , nodes ,
|
|
53
|
+
) {
|
|
54
|
+
const execId = stage.sqlExecutionId;
|
|
55
|
+
if (execId == null) return '';
|
|
56
|
+
const root = snapshot.sql.get(execId)?.planTree ?? null;
|
|
57
|
+
if (!root) return '';
|
|
58
|
+
const fingerprints = (nodes ?? planNodesOfStage(stage, snapshot.sql))
|
|
59
|
+
.map((node) => JSON.stringify([normalizeStageName(node.name ?? ''), normalizeDetail(node.detail ?? '')]));
|
|
60
|
+
if (fingerprints.length === 0) return planTreeIdentity(root, normalizeDetail) ?? '';
|
|
61
|
+
return cyrb53(JSON.stringify(fingerprints.sort()));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** `nodes`: the stage's attributed plan nodes when the caller already has them (`planNodesOfStage`),
|
|
65
|
+
* so one walk of the plan serves several readers. */
|
|
66
|
+
export function stageIdentityWith(
|
|
67
|
+
stage , snapshot , normalizeDetail , nodes ,
|
|
68
|
+
) {
|
|
69
|
+
return normalizeStageName(stage.name ?? '') + '§' + sqlNodeIdentity(stage, snapshot, normalizeDetail, nodes);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function identityIndexWith(
|
|
73
|
+
snapshot , identityOf , only = () => true,
|
|
74
|
+
) {
|
|
75
|
+
const byIdentity = new Map ();
|
|
76
|
+
for (const [id, stage] of snapshot.stages) {
|
|
77
|
+
if (!only(id)) continue;
|
|
78
|
+
const key = identityOf(stage, id);
|
|
79
|
+
const ids = byIdentity.get(key);
|
|
80
|
+
if (ids) ids.push(id);
|
|
81
|
+
else byIdentity.set(key, [id]);
|
|
82
|
+
}
|
|
83
|
+
return byIdentity;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Pairs the stages of two identity indexes. An identity colliding equally on both sides has no
|
|
87
|
+
* genuine ambiguity about *count*, so its stages pair off positionally by sorted id rather than
|
|
88
|
+
* being dropped. This is exact when the identity actually distinguishes stages (e.g.
|
|
89
|
+
* self-comparing a run: every stage matches itself). It's a best-effort guess when the identity is
|
|
90
|
+
* coarse (no SQL/attribution) and the two sides are genuinely different runs -- two unrelated
|
|
91
|
+
* same-named stages could get cross-paired. Accepted tradeoff: dropping them instead would also
|
|
92
|
+
* sacrifice the exact-self-comparison case, which matters more. An identity with different counts
|
|
93
|
+
* per side pairs nothing. Deterministic and symmetric: identities visit in sorted order. */
|
|
94
|
+
export function pairEqualCounts(
|
|
95
|
+
baseIdx , candIdx ,
|
|
96
|
+
) {
|
|
97
|
+
const pairs = [];
|
|
98
|
+
const matchedIdentities = new Set ();
|
|
99
|
+
for (const identity of [...baseIdx.keys()].sort()) {
|
|
100
|
+
const candIds = candIdx.get(identity);
|
|
101
|
+
if (!candIds) continue;
|
|
102
|
+
const baseIds = baseIdx.get(identity) ;
|
|
103
|
+
if (baseIds.length !== candIds.length) continue;
|
|
104
|
+
const sortedBaseIds = [...baseIds].sort((a, b) => a - b);
|
|
105
|
+
const sortedCandIds = [...candIds].sort((a, b) => a - b);
|
|
106
|
+
for (let i = 0; i < sortedBaseIds.length; i++) {
|
|
107
|
+
pairs.push({ identity, baseId: sortedBaseIds[i], candId: sortedCandIds[i] });
|
|
108
|
+
}
|
|
109
|
+
matchedIdentities.add(identity);
|
|
110
|
+
}
|
|
111
|
+
return { pairs, matchedIdentities };
|
|
112
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
|
|
2
|
+
import { medianOfSorted } from './median.js';
|
|
2
3
|
|
|
3
4
|
|
|
4
5
|
// Single source of truth for the packed per-task numeric array: FIELDS (offset
|
|
@@ -304,6 +305,7 @@ function listScheduleEndMs(
|
|
|
304
305
|
return endMs;
|
|
305
306
|
}
|
|
306
307
|
|
|
308
|
+
// p50 is the textbook median (the mean of the two middle values on an even count); p95 is nearest-rank.
|
|
307
309
|
export function computeFieldQuantiles(arr , fieldIndex ) {
|
|
308
310
|
const taskCount = arr.length / FIELDS.STRIDE;
|
|
309
311
|
if (taskCount === 0) return { p50: 0, p95: 0, max: 0 };
|
|
@@ -313,7 +315,7 @@ export function computeFieldQuantiles(arr , fieldIndex )
|
|
|
313
315
|
values.sort();
|
|
314
316
|
|
|
315
317
|
return {
|
|
316
|
-
p50: values
|
|
318
|
+
p50: medianOfSorted(values),
|
|
317
319
|
p95: values[Math.ceil(taskCount * 0.95) - 1],
|
|
318
320
|
max: values[taskCount - 1],
|
|
319
321
|
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// What the stage aligner compares beyond the exact comparison key: a stage's structural key (operator
|
|
2
|
+
// tree shape, node names and sorted attribute names, with literals, paths, file counts and ids
|
|
3
|
+
// removed) and the token sets its similarity scores read. Pure.
|
|
4
|
+
|
|
5
|
+
import { cyrb53 } from './string-hash.js';
|
|
6
|
+
import { normalizeStageName, } from './stage-identity.js';
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
// Plumbing nodes: codegen boundaries and input adapters change with how Spark fuses a stage, not with
|
|
10
|
+
// the query, so the structural key and the similarity tokens skip them.
|
|
11
|
+
const PLUMBING_NODE = /^(WholeStageCodegen|InputAdapter|ColumnarToRow|RowToColumnar)\b/;
|
|
12
|
+
|
|
13
|
+
const isPlumbing = (node ) => PLUMBING_NODE.test(node.name ?? '');
|
|
14
|
+
|
|
15
|
+
/** The attribute names a plan node's text mentions (`amount#12` gives `amount`), without ids, each
|
|
16
|
+
* once, sorted. Sorting makes the key insensitive to the nondeterministic order in which Spark lists
|
|
17
|
+
* grouping and projection columns; reading only `name#id` references leaves literals out. */
|
|
18
|
+
export function attributeNames(detail ) {
|
|
19
|
+
const names = new Set ();
|
|
20
|
+
for (const m of detail.matchAll(/([A-Za-z_][\w$.]*)#\d+L?/g)) names.add(m[1]);
|
|
21
|
+
return [...names].sort();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** The structural key of a stage from the plan nodes attributed to it, or null when nothing but
|
|
25
|
+
* plumbing is attributed. The nodes form a forest (a node's parent is its nearest attributed
|
|
26
|
+
* ancestor); the key folds each node's normalized name, its sorted attribute names and its
|
|
27
|
+
* children's digests (sorted, so a join's side order does not matter). Only structure goes in: no
|
|
28
|
+
* node detail, so a literal, a path or a file count never splits two stages. */
|
|
29
|
+
export function structuralKey(nodes ) {
|
|
30
|
+
const attributed = new Set(nodes.filter((n) => !isPlumbing(n)));
|
|
31
|
+
if (attributed.size === 0) return null;
|
|
32
|
+
const digests = new Map ();
|
|
33
|
+
const nested = new Set ();
|
|
34
|
+
// Digests of the nearest attributed descendants of `node`'s children.
|
|
35
|
+
const below = (node ) => {
|
|
36
|
+
const out = [];
|
|
37
|
+
for (const child of node.children ?? []) {
|
|
38
|
+
if (attributed.has(child)) { out.push(digestOf(child)); nested.add(child); }
|
|
39
|
+
else out.push(...below(child));
|
|
40
|
+
}
|
|
41
|
+
return out;
|
|
42
|
+
};
|
|
43
|
+
const digestOf = (node ) => {
|
|
44
|
+
let d = digests.get(node);
|
|
45
|
+
if (d === undefined) {
|
|
46
|
+
d = cyrb53(JSON.stringify([normalizeStageName(node.name ?? ''), attributeNames(node.detail ?? ''), below(node).sort()]));
|
|
47
|
+
digests.set(node, d);
|
|
48
|
+
}
|
|
49
|
+
return d;
|
|
50
|
+
};
|
|
51
|
+
for (const node of attributed) digestOf(node);
|
|
52
|
+
const roots = [...attributed].filter((n) => !nested.has(n)).map(digestOf).sort();
|
|
53
|
+
return cyrb53(JSON.stringify(roots));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const TOKEN_SPLIT = /[^A-Za-z0-9_.$]+/;
|
|
57
|
+
|
|
58
|
+
/** Sorted distinct tokens of a stage's attributed nodes (name and normalized detail) and its name.
|
|
59
|
+
* Two stages whose text differs in one literal share nearly every token. */
|
|
60
|
+
export function detailTokens(stageName , nodes , normalize ) {
|
|
61
|
+
const tokens = new Set ();
|
|
62
|
+
const add = (text ) => { for (const t of text.split(TOKEN_SPLIT)) if (t) tokens.add(t); };
|
|
63
|
+
add(normalizeStageName(stageName ?? ''));
|
|
64
|
+
for (const node of nodes) {
|
|
65
|
+
if (isPlumbing(node)) continue;
|
|
66
|
+
add(normalizeStageName(node.name ?? ''));
|
|
67
|
+
add(normalize(node.detail ?? ''));
|
|
68
|
+
}
|
|
69
|
+
return [...tokens].sort();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Jaccard similarity of two sorted arrays; 1 when both are empty. An element repeated in both counts
|
|
73
|
+
* as often as it repeats in the shorter side (multiset Jaccard), so distinct arrays give the plain one. */
|
|
74
|
+
export function jaccard(a , b ) {
|
|
75
|
+
if (a.length === 0 && b.length === 0) return 1;
|
|
76
|
+
let i = 0, j = 0, both = 0;
|
|
77
|
+
while (i < a.length && j < b.length) {
|
|
78
|
+
if (a[i] === b[j]) { both++; i++; j++; }
|
|
79
|
+
else if (a[i] < b[j]) i++;
|
|
80
|
+
else j++;
|
|
81
|
+
}
|
|
82
|
+
return both / (a.length + b.length - both);
|
|
83
|
+
}
|
package/vendor-core/types.js
CHANGED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// Argument and identifier helpers shared by the write-target parsers (write-targets.ts) and the
|
|
2
|
+
// Delta command resolver (delta-targets.ts).
|
|
3
|
+
const IDENT_PART = String.raw`(?:\`(?:[^\`]|\`\`)*\`|[A-Za-z0-9_$]+)`;
|
|
4
|
+
const IDENTIFIER = new RegExp(`^${IDENT_PART}(?:\\.${IDENT_PART})*$`);
|
|
5
|
+
export const IDENT_PARTS = new RegExp(IDENT_PART, 'g');
|
|
6
|
+
const TRUNCATION_MARKER = /\.\.\.(?:\s*\d+ more fields)?/;
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
// Splits at top-level commas, ignoring commas inside (), [], {} and backticks. `terminated` is
|
|
11
|
+
// true when a comma follows the arg: the last arg of a cut-off string is never terminated.
|
|
12
|
+
export function splitArgs(args ) {
|
|
13
|
+
const out = [];
|
|
14
|
+
let depth = 0;
|
|
15
|
+
let quoted = false;
|
|
16
|
+
let start = 0;
|
|
17
|
+
for (let i = 0; i < args.length; i++) {
|
|
18
|
+
const c = args[i];
|
|
19
|
+
if (c === '`') quoted = !quoted;
|
|
20
|
+
else if (quoted) continue;
|
|
21
|
+
else if (c === '(' || c === '[' || c === '{') depth++;
|
|
22
|
+
else if (c === ')' || c === ']' || c === '}') depth--;
|
|
23
|
+
else if (c === ',' && depth === 0) {
|
|
24
|
+
out.push({ text: args.slice(start, i).trim(), terminated: true });
|
|
25
|
+
start = i + 1;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
out.push({ text: args.slice(start).trim(), terminated: false });
|
|
29
|
+
return out;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function isCut(text ) {
|
|
33
|
+
return text === '' || TRUNCATION_MARKER.test(text);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// `db`.`t` or db.t -> db.t. A part that itself contains a dot or backtick keeps its quoting.
|
|
37
|
+
export function tableName(ident ) {
|
|
38
|
+
if (!IDENTIFIER.test(ident)) return null;
|
|
39
|
+
const parts = (ident.match(IDENT_PARTS) ?? []).map((p) => {
|
|
40
|
+
if (!p.startsWith('`')) return p;
|
|
41
|
+
const inner = p.slice(1, -1).replace(/``/g, '`');
|
|
42
|
+
return /[.`]/.test(inner) ? p : inner;
|
|
43
|
+
});
|
|
44
|
+
return parts.join('.');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** A write target found without parsing the node's simpleString. */
|
|
48
|
+
|
|
@@ -6,10 +6,15 @@
|
|
|
6
6
|
// - a target Spark cut short (no delimiter after it, or a "..." marker in it) is unparseable;
|
|
7
7
|
// - a write-like node outside the known list is reported as an unrecognized write;
|
|
8
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
|
|
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).
|
|
10
12
|
// Targets are verbatim from the simpleString: nothing is resolved (relative paths, ${var}
|
|
11
13
|
// placeholders, catalog-relative table names all pass through as the log states them).
|
|
12
14
|
import { walkPlanTree } from './plan-tree-walk.js';
|
|
15
|
+
import { apiMergeWrites } from './api-merge-writes.js';
|
|
16
|
+
import { indexByRoot, isStagedDeltaWrite, parseDeltaTableV2, resolveDeltaCommandTarget, } from './delta-targets.js';
|
|
17
|
+
import { IDENT_PARTS, isCut, splitArgs, tableName, } from './write-target-args.js';
|
|
13
18
|
|
|
14
19
|
|
|
15
20
|
|
|
@@ -67,11 +72,6 @@ const NOT_WRITES = new Set([
|
|
|
67
72
|
'UpdateEventTimeWatermarkColumn',
|
|
68
73
|
]);
|
|
69
74
|
|
|
70
|
-
const IDENT_PART = String.raw`(?:\`(?:[^\`]|\`\`)*\`|[A-Za-z0-9_$]+)`;
|
|
71
|
-
const IDENTIFIER = new RegExp(`^${IDENT_PART}(?:\\.${IDENT_PART})*$`);
|
|
72
|
-
const IDENT_PARTS = new RegExp(IDENT_PART, 'g');
|
|
73
|
-
const TRUNCATION_MARKER = /\.\.\.(?:\s*\d+ more fields)?/;
|
|
74
|
-
|
|
75
75
|
function commandOf(nodeName ) {
|
|
76
76
|
return nodeName.replace(/^Execute\s+/, '').trim().replace(/Exec$/, '');
|
|
77
77
|
}
|
|
@@ -86,30 +86,6 @@ function isWriteLike(command ) {
|
|
|
86
86
|
return (operator.match(/[A-Z][a-z0-9]*/g) ?? []).some((word) => WRITE_WORDS.has(word));
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
// Splits at top-level commas, ignoring commas inside (), [], {} and backticks. `terminated` is
|
|
92
|
-
// true when a comma follows the arg: the last arg of a cut-off string is never terminated.
|
|
93
|
-
function splitArgs(args ) {
|
|
94
|
-
const out = [];
|
|
95
|
-
let depth = 0;
|
|
96
|
-
let quoted = false;
|
|
97
|
-
let start = 0;
|
|
98
|
-
for (let i = 0; i < args.length; i++) {
|
|
99
|
-
const c = args[i];
|
|
100
|
-
if (c === '`') quoted = !quoted;
|
|
101
|
-
else if (quoted) continue;
|
|
102
|
-
else if (c === '(' || c === '[' || c === '{') depth++;
|
|
103
|
-
else if (c === ')' || c === ']' || c === '}') depth--;
|
|
104
|
-
else if (c === ',' && depth === 0) {
|
|
105
|
-
out.push({ text: args.slice(start, i).trim(), terminated: true });
|
|
106
|
-
start = i + 1;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
out.push({ text: args.slice(start).trim(), terminated: false });
|
|
110
|
-
return out;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
89
|
// Text after the command name in the simpleString. Empty when the simpleString does not start
|
|
114
90
|
// with the command (so nothing after it can be trusted).
|
|
115
91
|
function argsOf(detail , command ) {
|
|
@@ -118,21 +94,6 @@ function argsOf(detail , command ) {
|
|
|
118
94
|
return m[2];
|
|
119
95
|
}
|
|
120
96
|
|
|
121
|
-
function isCut(text ) {
|
|
122
|
-
return text === '' || TRUNCATION_MARKER.test(text);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// `db`.`t` or db.t -> db.t. A part that itself contains a dot or backtick keeps its quoting.
|
|
126
|
-
function tableName(ident ) {
|
|
127
|
-
if (!IDENTIFIER.test(ident)) return null;
|
|
128
|
-
const parts = (ident.match(IDENT_PARTS) ?? []).map((p) => {
|
|
129
|
-
if (!p.startsWith('`')) return p;
|
|
130
|
-
const inner = p.slice(1, -1).replace(/``/g, '`');
|
|
131
|
-
return /[.`]/.test(inner) ? p : inner;
|
|
132
|
-
});
|
|
133
|
-
return parts.join('.');
|
|
134
|
-
}
|
|
135
|
-
|
|
136
97
|
// First arg of a path-writing command. The next arg must be the boolean that follows it in
|
|
137
98
|
// InsertIntoHadoopFsRelationCommand, or the static-partition map (INSERT OVERWRITE ... PARTITION
|
|
138
99
|
// (dt='x')) that precedes that boolean, which Spark prints as `[dt=x]` (or `Map(dt -> x)`); this also rejects a path Spark printed with ", " inside.
|
|
@@ -259,9 +220,10 @@ function isKnownWrite(command ) {
|
|
|
259
220
|
function parseWrite(command , detail ) {
|
|
260
221
|
const argParser = ARG_PARSERS[command];
|
|
261
222
|
if (argParser) return [true, argParser(splitArgs(argsOf(detail, command)))];
|
|
262
|
-
if (V2_WRITES.has(command)) return [true, parseV2Write(detail)];
|
|
223
|
+
if (V2_WRITES.has(command)) return [true, parseDeltaTableV2(detail) ?? parseV2Write(detail)];
|
|
263
224
|
if (V2_TABLE_AS_SELECT.has(command)) return [true, parseV2TableAsSelect(splitArgs(argsOf(detail, command)))];
|
|
264
225
|
// A MERGE prints its source relation too, so a delta. path in it may be the source, not the target.
|
|
226
|
+
// Its target comes from resolveDeltaCommandTarget alone.
|
|
265
227
|
if (command === 'MergeIntoCommand') return [true, null];
|
|
266
228
|
if (DELTA_COMMANDS.has(command)) return [true, parseDeltaPath(splitArgs(argsOf(detail, command)))];
|
|
267
229
|
return [false, null];
|
|
@@ -272,14 +234,16 @@ function outputRowsOf(node ) {
|
|
|
272
234
|
return metric !== undefined && Number.isFinite(metric.value) ? metric.value : null;
|
|
273
235
|
}
|
|
274
236
|
|
|
275
|
-
function collectWrites(
|
|
237
|
+
function collectWrites(exec , root , byRoot , out ) {
|
|
276
238
|
walkPlanTree(root, (node) => {
|
|
277
239
|
const command = commandOf(node.name);
|
|
278
240
|
if (!isWriteLike(command)) return;
|
|
279
241
|
const detail = node.detail ?? '';
|
|
280
|
-
const [recognized,
|
|
242
|
+
const [recognized, parsedFromDetail] = parseWrite(command, detail);
|
|
243
|
+
// A Delta command's simpleString is bare on real logs: its target is found elsewhere.
|
|
244
|
+
const parsed = parsedFromDetail ?? resolveDeltaCommandTarget(command, exec, node, byRoot);
|
|
281
245
|
out.push({
|
|
282
|
-
sqlExecutionId:
|
|
246
|
+
sqlExecutionId: exec.id,
|
|
283
247
|
nodeId: node.id ?? null,
|
|
284
248
|
command,
|
|
285
249
|
recognized,
|
|
@@ -291,6 +255,20 @@ function collectWrites(executionId , root , out )
|
|
|
291
255
|
}, { dedupe: true });
|
|
292
256
|
}
|
|
293
257
|
|
|
258
|
+
// A staged Delta write writes the table its root's CTAS/RTAS node names, when it has exactly one.
|
|
259
|
+
function attributeStagedWrites(writes , sql ) {
|
|
260
|
+
for (const write of writes) {
|
|
261
|
+
if (write.target !== null || !isStagedDeltaWrite(write)) continue;
|
|
262
|
+
const root = sql.get(write.sqlExecutionId)?.rootExecutionId;
|
|
263
|
+
if (root === undefined || root === write.sqlExecutionId) continue;
|
|
264
|
+
const parents = writes.filter((w) => w.sqlExecutionId === root && V2_TABLE_AS_SELECT.has(w.command));
|
|
265
|
+
if (parents.length === 1 && parents[0].target !== null) {
|
|
266
|
+
write.kind = parents[0].kind;
|
|
267
|
+
write.target = parents[0].target;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
294
272
|
|
|
295
273
|
|
|
296
274
|
|
|
@@ -301,11 +279,16 @@ export function extractWriteTargets(sql , input
|
|
|
301
279
|
const writes = [];
|
|
302
280
|
const withoutPlan = new Map ();
|
|
303
281
|
for (const id of input.unreadableSqlExecutions ?? []) if (!sql.get(id)?.planTree) withoutPlan.set(id, 'unreadableStart');
|
|
282
|
+
const byRoot = indexByRoot(sql);
|
|
304
283
|
for (const id of [...sql.keys()].sort((a, b) => a - b)) {
|
|
305
|
-
const
|
|
306
|
-
if (!planTree) withoutPlan.set(id, withoutPlan.get(id) ?? 'noPlan');
|
|
307
|
-
else collectWrites(
|
|
284
|
+
const exec = sql.get(id) ;
|
|
285
|
+
if (!exec.planTree) withoutPlan.set(id, withoutPlan.get(id) ?? 'noPlan');
|
|
286
|
+
else collectWrites(exec, exec.planTree, byRoot, writes);
|
|
308
287
|
}
|
|
288
|
+
// DeltaTable API merges run no command node: they are found by their executions' descriptions.
|
|
289
|
+
attributeStagedWrites(writes, sql);
|
|
290
|
+
writes.push(...apiMergeWrites(sql));
|
|
291
|
+
writes.sort((a, b) => a.sqlExecutionId - b.sqlExecutionId);
|
|
309
292
|
const executionsWithoutPlan = [...withoutPlan].sort((a, b) => a[0] - b[0])
|
|
310
293
|
.map(([sqlExecutionId, reason]) => ({ sqlExecutionId, reason }));
|
|
311
294
|
return { writes, executionsWithoutPlan, skippedLines: input.skippedLines ?? null };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as e}from"./rolldown-runtime-hePW80VL.js";import{M as t}from"./charts-vendor-0VMaLVLN.js";import{E as n,Y as r,_t as i,d as a,p as o}from"./DisclosureContext-Ds0hcZFn.js";import{p as s}from"./plan-graph-vendor-B0sEms9Z.js";import{h as c,m as l}from"./useRecentFiles-Bb4-ukVz.js";import{C as u,F as d,I as f,L as p,M as m,N as h,O as g,R as _}from"./index-DaC8A2FS.js";import{o as v,r as y,t as b}from"./Dashboard-CC_BXrNy.js";import{n as x}from"./finding-anchor-Dl8mIHiU.js";import{t as S}from"./usePagedRows-Bo-aSztx.js";var C={name:`git-merge`,size:24,node:[[`circle`,{cx:`18`,cy:`18`,r:`3`,key:`1xkwt0`}],[`circle`,{cx:`6`,cy:`6`,r:`3`,key:`1lh9wr`}],[`path`,{d:`M6 21V9a9 9 0 0 0 9 9`,key:`7kw0sc`}]]};C.node;var w=i(C),T=e(t(),1),E=s();function D({relations:e,operator:t}){let n=t===`union`?`union`:`join`;return(0,E.jsx)(`span`,{className:`inline-flex flex-wrap items-baseline`,children:e.map((e,t)=>(0,E.jsxs)(`span`,{children:[t>0?(0,E.jsxs)(E.Fragment,{children:[` `,(0,E.jsx)(`span`,{className:`mx-1 font-semibold uppercase text-xs tracking-wide text-primary`,children:n}),` `]}):null,e.relation]},e.relation))})}function O({finding:e}){let t=x([e]),i=e.variant===`composite`;return(0,E.jsxs)(_,{ref:t.ref,tabIndex:t.tabIndex,"data-flashed":t.dataFlashed,className:`transition-colors ${t.flashClassName}`,children:[(0,E.jsx)(d,{children:(0,E.jsxs)(`span`,{className:`inline-flex items-center gap-2`,children:[i?(0,E.jsx)(w,{className:`size-3.5 text-muted-foreground`,"aria-hidden":`true`}):null,i&&e.relations&&e.relations.length>0?(0,E.jsx)(D,{relations:e.relations,operator:e.operator}):(0,E.jsx)(`span`,{children:e.relation}),i?(0,E.jsx)(n,{variant:`outline`,className:`text-xs uppercase border-dashed`,children:e.operator?.toUpperCase()}):(0,E.jsx)(n,{variant:`secondary`,className:`text-xs uppercase`,children:e.format})]})}),(0,E.jsxs)(d,{children:[e.value,` queries`]}),(0,E.jsx)(d,{className:`text-right`,children:r(e.totalReadBytes)}),(0,E.jsxs)(d,{children:[(0,E.jsx)(b,{finding:e}),(0,E.jsx)(o,{children:(0,E.jsx)(c,{confidence:e.confidence,validationRequired:e.validationRequired})})]})]})}var k=(0,T.memo)(function({catalog:e,defaultCollapsed:t=!0}){let[n,r]=(0,T.useState)(0),i=(0,T.useMemo)(()=>l(e,`cachingOpportunity`).sort((e,t)=>t.totalReadBytes-e.totalReadBytes||(t.value??0)-(e.value??0)),[e]),s=g(),c=s?i.findIndex(e=>e===s.finding):null,{totalPages:d,effectivePage:b,visible:x}=S(i,n,r,c);if(i.length===0)return null;let C=i[0];return(0,E.jsx)(u,{title:`Caching Opportunities`,fixFor:i,impactBand:`info`,badges:(0,E.jsx)(a,{type:`cachingOpportunity`,impactBand:`info`}),defaultCollapsed:t,summary:(0,E.jsx)(v,{value:`${C.value}×`,context:`read by ${C.value} queries: ${C.relation}`}),children:(0,E.jsxs)(`div`,{className:`space-y-3`,children:[(0,E.jsxs)(m,{children:[(0,E.jsx)(p,{children:(0,E.jsxs)(_,{children:[(0,E.jsx)(f,{children:`Relation`}),(0,E.jsx)(f,{children:`Read by`}),(0,E.jsx)(f,{className:`text-right`,children:`Data read`}),(0,E.jsx)(f,{children:`Estimate`})]})}),(0,E.jsx)(h,{children:x.map((e,t)=>(0,E.jsx)(O,{finding:e},`${e.format}:${e.relation}:${(e.executionIds??[]).join(`,`)}:${t}`))})]}),(0,E.jsx)(o,{children:(0,E.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`Reuse is inferred from plan structure, not confirmed by execution. Verify before caching.`})}),(0,E.jsx)(y,{page:b,totalPages:d,onPrev:()=>r(e=>e-1),onNext:()=>r(e=>e+1)})]})})});export{k as CachingOpportunity};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as e}from"./rolldown-runtime-hePW80VL.js";import{M as t,T as n,f as r,n as i,o as a,s as o,u as s,v as c}from"./charts-vendor-0VMaLVLN.js";import{B as l,S as u,X as d,b as f,d as p,p as m,u as h}from"./DisclosureContext-Ds0hcZFn.js";import{p as g}from"./plan-graph-vendor-B0sEms9Z.js";import{_,b as v,h as y,y as b}from"./useRecentFiles-Bb4-ukVz.js";import{C as x}from"./index-DaC8A2FS.js";import{c as S,f as C,o as w,p as T,r as E,t as D}from"./Dashboard-CC_BXrNy.js";import{t as O}from"./usePagedRows-Bo-aSztx.js";var k=e(t(),1),A=g(),j=240,M={PROCESS_LOCAL:`Process-local`,NODE_LOCAL:`Node-local`,RACK_LOCAL:`Rack-local`,NO_PREF:`No preference`,ANY:`Any`,OTHER:`Other`,idle:`Idle`},N={PROCESS_LOCAL:_.clean,NODE_LOCAL:_.accent,RACK_LOCAL:_.warning,NO_PREF:_.muted,ANY:_.critical,OTHER:_.muted,idle:_.muted},P=`Core Usage by Locality`,F=(0,k.memo)(function({catalog:e,defaultCollapsed:t=!0}){let[g,F]=(0,k.useState)(0),I=f()?.data.coreLocality,L=(0,k.useMemo)(()=>{let e=I?.chart??{hasActivity:!1};return e.hasActivity?{...e,sampled:S(e.points)}:e},[I]),R=I?.ratio.topStages??[],z=e.find(e=>e.type===`coreLocality`),B=e.some(e=>e.type===`memoryUtilization`&&e.variant===`idleCores`),V=R.filter(e=>e.nonLocalTasks>0),{totalPages:H,effectivePage:U,visible:W}=O(V,g,F);if(!L.hasActivity)return(0,A.jsx)(x,{title:P,summary:(0,A.jsx)(`span`,{className:`text-muted-foreground text-xs`,children:`No stage activity to plot.`}),children:(0,A.jsx)(C,{tone:`neutral`,icon:T,title:`No stage activity to plot.`})});let{order:G,points:K,sampled:q,peakCores:J}=L;return(0,A.jsx)(x,{title:P,impactBand:z?.impactBand,badges:z?(0,A.jsx)(p,{type:`coreLocality`,impactBand:z.impactBand}):null,defaultCollapsed:t,summary:(0,A.jsx)(w,{value:`${d(J)} cores`,context:`busy at the peak`}),children:(0,A.jsxs)(`div`,{className:`space-y-2`,children:[(0,A.jsx)(m,{children:(0,A.jsxs)(`p`,{className:`text-muted-foreground text-xs`,children:[`approximate: stage-level attribution`,z?null:(0,A.jsxs)(A.Fragment,{children:[`, see `,(0,A.jsx)(u,{anchor:`#bottleneck-utilization`,children:`how utilization is measured`})]})]})}),z?(0,A.jsxs)(`p`,{className:`flex flex-wrap items-start gap-2 text-sm`,children:[(0,A.jsx)(h,{impactBand:z.impactBand,className:`mt-1.5`}),(0,A.jsxs)(`span`,{children:[(0,A.jsxs)(`strong`,{children:[z.value,`% non-local`]}),`. `,l(z)]})]}):null,z?(0,A.jsx)(D,{finding:z}):null,(0,A.jsx)(m,{children:z?(0,A.jsx)(y,{confidence:z.confidence,validationRequired:z.validationRequired}):null}),(0,A.jsx)(v,{ariaLabel:`Approximate concurrent core usage over time, stacked by task locality tier, with idle capacity shown. See the legend for tier colors.`,height:j,table:{caption:`Concurrent core usage over time by locality tier`,columns:[`Time (s)`,...G.map(e=>M[e]??e)],rows:K.map(e=>[e.t,...G.map(t=>Math.round(e[t]))]),align:Array.from({length:G.length+1},()=>`right`)},children:(0,A.jsxs)(i,{data:q,children:[(0,A.jsx)(r,{vertical:!1,stroke:_.muted,strokeOpacity:.2}),(0,A.jsx)(o,{dataKey:`t`,tick:{fontSize:10},label:{value:`seconds from app start`,position:`insideBottom`,offset:-2,fontSize:10}}),(0,A.jsx)(a,{tick:{fontSize:10},width:36,label:{value:`avg concurrent cores`,angle:-90,position:`insideLeft`,fontSize:10}}),(0,A.jsx)(c,{...b}),(0,A.jsx)(n,{wrapperStyle:{fontSize:10}}),G.map(e=>(0,A.jsx)(s,{type:`monotone`,dataKey:e,name:M[e]??e,stackId:`cores`,stroke:N[e]??_.muted,fill:N[e]??_.muted,fillOpacity:e===`idle`?.15:.8,isAnimationActive:!1},e))]})}),(0,A.jsx)(m,{children:W.length>0?(0,A.jsxs)(A.Fragment,{children:[(0,A.jsx)(`ul`,{className:`space-y-1 text-xs text-muted-foreground`,children:W.map(e=>(0,A.jsxs)(`li`,{children:[`Stage `,e.stageId,`: `,Math.round(e.ratio*100),`% non-local (`,e.nonLocalTasks,`/`,e.taskCount,` tasks)`]},e.stageId))}),(0,A.jsx)(E,{page:U,totalPages:H,onPrev:()=>F(e=>e-1),onNext:()=>F(e=>e+1)})]}):null}),(0,A.jsx)(m,{children:B?(0,A.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`Idle cores also flagged → see Memory Utilization widget`}):null})]})})});export{F as CoreUsageArea};
|