From d151b65999511044070be3df9d46c97a5e28a956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Milenkovi=C4=87?= Date: Sun, 24 May 2026 06:45:31 +0100 Subject: [PATCH 01/22] add command line helper --- dev/bin/plan_print.sh | 283 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 283 insertions(+) create mode 100755 dev/bin/plan_print.sh diff --git a/dev/bin/plan_print.sh b/dev/bin/plan_print.sh new file mode 100755 index 0000000000..e80a3df3b4 --- /dev/null +++ b/dev/bin/plan_print.sh @@ -0,0 +1,283 @@ +#!/bin/bash + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + + +# +# PLAN PRINT HELPER +# +# plan print is a helper command line utility for ballista. +# which prints command line utility +# +# ballista exposes rest API at the `http://localhost:50050/`` by default +# where address and port can be configurable. +# +# `curl http://localhost:50050/api/jobs | jq` +# returns list of running jobs in format +# +#```json +# [ +# { +# "job_id": "LOZNWx3", +# "job_name": "test job ", +# "job_status": "Completed. Produced 1 partition containing 1 row. Elapsed time: 20 ms.", +# "status": "Completed", +# "num_stages": 1, +# "completed_stages": 1, +# "percent_complete": 100, +# "start_time": 1779600307389, +# "end_time": 1779600307409 +# } +# ] +# ``` +# +# jobs are not sorted,. +# +# `curl http://localhost:50050/api/job/LOZNWx3 | jq` +# returns the specific job `LOZNWx3` information +# +# ```json +# { +# "job_id": "LOZNWx3", +# "job_name": "", +# "job_status": "Completed. Produced 1 partition containing 1 row. Elapsed time: 20 ms.", +# "status": "Completed", +# "num_stages": 1, +# "completed_stages": 1, +# "percent_complete": 100, +# "start_time": 1779600307389, +# "end_time": 1779600307409, +# "logical_plan": "Projection: Int64(1)\n EmptyRelation: rows=1", +# "physical_plan": "ProjectionExec: expr=[1 as Int64(1)]\n PlaceholderRowExec\n", +# "stage_plan": "AdaptiveExecutionGraph { TRUNCATED }" +# } +# ``` +# +# `curl http://localhost:50050/api/job/LOZNWx3/stages |jq` +# returns stage information for a given job +# ``` +# { +# "stages": [ +# { +# "stage_id": "0", +# "stage_status": "Successful", +# "input_rows": 1, +# "output_rows": 2, +# "elapsed_compute": "6.00ms", +# "stage_plan": "ShuffleWriterExec: partitioning: None\n ProjectionExec: expr=[1 as Int64(1)]\n PlaceholderRowExec\n", +# "task_duration_percentiles": { +# "min": 6, +# "p25": 6, +# "median": 6, +# "p75": 6, +# "max": 6 +# }, +# "task_input_percentiles": { +# "min": 1, +# "p25": 1, +# "median": 1, +# "p75": 1, +# "max": 1 +# }, +# "tasks": [ +# { +# "id": 0, +# "status": "Successful", +# "partition_id": 0, +# "scheduled_time": 1779600307391, +# "launch_time": 1779600307391, +# "start_exec_time": 1779600307400, +# "end_exec_time": 1779600307406, +# "exec_duration": 6, +# "finish_time": 1779600307407, +# "input_rows": 1, +# "output_rows": 2 +# } +# ] +# } +# ] +# } +# ``` +# +# Job and stages endpoint accept `render_tree=true` parameter which +# renders plans as tree. +# +# command actions and options +# +# plan_print.sh [options] +# +# is optional parameter specifying, if not provided +# uses the last job (filtered by max start time) +# +# -a specified executor API address in format `http://executor-host:12345/` +# it should contain host and port +# -p display `physical_plan` (default, if not specified) +# -l display `logical_plan` +# -e display `stage_plan` (from job info) +# -s [] display `physical_plan` for specified stage, or all stages if omitted (from stages info) +# -w pipe output through `less -S` (no word wrap, horizontal scroll) +# -t display plans as tree render (where applicable) + +set -euo pipefail + +# Defaults +API_BASE="http://localhost:50050/" +JOB_ID="" +DISPLAY_MODE="physical" +STAGE_ID="" +USE_PAGER=false +RENDER_TREE=false + +usage() { + echo "Usage: $(basename "$0") [job_id] [-a address] [-p] [-l] [-e] [-s stage_id]" + echo " job_id optional; defaults to the most recent job" + echo " -a ADDR API base URL (default: http://localhost:50050/)" + echo " -p display physical_plan (default)" + echo " -l display logical_plan" + echo " -e display stage_plan (from job info)" + echo " -s [STAGE_ID] display stage_plan for the given stage, or all stages if omitted (from stages info)" + echo " -w pipe output through 'less -S' (no line-wrap, horizontal scroll)" + echo " -t display plans as tree render (where applicable)" + exit 1 +} + +# First positional argument may be a job_id (does not start with -) +if [[ $# -gt 0 && "$1" != -* ]]; then + JOB_ID="$1" + shift +fi + +# Parse flags +while [[ $# -gt 0 ]]; do + case "$1" in + -a) + [[ $# -lt 2 ]] && { echo "Error: -a requires an address argument"; usage; } + API_BASE="$2" + shift 2 + ;; + -p) + DISPLAY_MODE="physical" + shift + ;; + -l) + DISPLAY_MODE="logical" + shift + ;; + -s) + DISPLAY_MODE="stage" + # stage_id is optional; consume next arg only if it is not a flag + if [[ $# -ge 2 && "$2" != -* ]]; then + STAGE_ID="$2" + shift 2 + else + STAGE_ID="" + shift + fi + ;; + -e) + DISPLAY_MODE="execution" + shift + ;; + -w) + USE_PAGER=true + shift + ;; + -t) + RENDER_TREE=true + shift + ;; + *) + echo "Unknown option: $1" + usage + ;; + esac +done + +# Normalize API base URL (ensure exactly one trailing slash) +API_BASE="${API_BASE%/}/" + +# Resolve job_id if not provided +if [[ -z "$JOB_ID" ]]; then + JOB_ID=$(curl -sf "${API_BASE}api/jobs" | jq -r 'max_by(.start_time) | .job_id') + if [[ -z "$JOB_ID" || "$JOB_ID" == "null" ]]; then + echo "Error: no jobs found at ${API_BASE}api/jobs" >&2 + exit 1 + fi +fi + +# Build job info and stages URLs (optionally with render_tree query param) +if [[ "$RENDER_TREE" == "true" ]]; then + JOB_URL="${API_BASE}api/job/${JOB_ID}?render_tree=true" + STAGES_URL="${API_BASE}api/job/${JOB_ID}/stages?render_tree=true" +else + JOB_URL="${API_BASE}api/job/${JOB_ID}" + STAGES_URL="${API_BASE}api/job/${JOB_ID}/stages" +fi + +COLS=$(tput cols 2>/dev/tty || echo 80) +SEP=$(printf '%.0s-' $(seq 1 $COLS)) + +print_plan() { + case "$DISPLAY_MODE" in + physical) + echo "${SEP}" + echo "Job ${JOB_ID} physical plan:" + echo "${SEP}" + curl -sf "${JOB_URL}" | jq -r '.physical_plan' + ;; + logical) + echo "${SEP}" + echo "Job ${JOB_ID} logical plan:" + echo "${SEP}" + curl -sf "${JOB_URL}" | jq -r '.logical_plan' + ;; + execution) + echo "${SEP}" + echo "Job ${JOB_ID} stage plan:" + echo "${SEP}" + curl -sf "${JOB_URL}" | jq -r '.stage_plan' + ;; + stage) + STAGES_JSON=$(curl -sf "${STAGES_URL}") + if [[ -n "$STAGE_ID" ]]; then + echo "${SEP}" + echo "Job ${JOB_ID}/${STAGE_ID} physical plan:" + echo "${SEP}" + echo "${STAGES_JSON}" \ + | jq -r --arg sid "$STAGE_ID" '.stages[] | select(.stage_id == $sid) | .stage_plan' + else + STAGE_COUNT=$(echo "${STAGES_JSON}" | jq '.stages | length') + for ((i = 0; i < STAGE_COUNT; i++)); do + SID=$(echo "${STAGES_JSON}" | jq -r ".stages[$i].stage_id") + echo "${SEP}" + echo "Job ${JOB_ID}/${SID} physical plan:" + echo "${SEP}" + echo "${STAGES_JSON}" | jq -r ".stages[$i].stage_plan" + done + fi + ;; + esac +} + +if [[ "$USE_PAGER" == "true" ]]; then + trap 'printf "\033[?7h"' EXIT # restore auto-wrap even on error/Ctrl-C + printf '\033[?7l' # disable auto-wrap + print_plan +else + print_plan +fi \ No newline at end of file From aa7fc5a0f96612e958db8103ec98c6d0de7ea077 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Milenkovi=C4=87?= Date: Sun, 24 May 2026 11:03:07 +0100 Subject: [PATCH 02/22] rename plan_print.sh to showplan.sh --- dev/bin/{plan_print.sh => showplan.sh} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename dev/bin/{plan_print.sh => showplan.sh} (100%) diff --git a/dev/bin/plan_print.sh b/dev/bin/showplan.sh similarity index 100% rename from dev/bin/plan_print.sh rename to dev/bin/showplan.sh From a8bdc21312c877470039e000516c6d0579e0770a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Milenkovi=C4=87?= Date: Mon, 25 May 2026 10:50:02 +0100 Subject: [PATCH 03/22] Update dev/bin/showplan.sh Co-authored-by: Martin Grigorov --- dev/bin/showplan.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/bin/showplan.sh b/dev/bin/showplan.sh index e80a3df3b4..b7d2c1c5bd 100755 --- a/dev/bin/showplan.sh +++ b/dev/bin/showplan.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file From 79c9777f66e480df8eadebbc6759db6e602bb608 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Milenkovi=C4=87?= Date: Mon, 25 May 2026 10:58:37 +0100 Subject: [PATCH 04/22] Update dev/bin/showplan.sh Co-authored-by: Martin Grigorov --- dev/bin/showplan.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/bin/showplan.sh b/dev/bin/showplan.sh index b7d2c1c5bd..98c1c3dc9e 100755 --- a/dev/bin/showplan.sh +++ b/dev/bin/showplan.sh @@ -24,7 +24,7 @@ # plan print is a helper command line utility for ballista. # which prints command line utility # -# ballista exposes rest API at the `http://localhost:50050/`` by default +# Ballista exposes REST API at `http://localhost:50050/` by default # where address and port can be configurable. # # `curl http://localhost:50050/api/jobs | jq` From e2d3dcf946af1dd7f048924f97b52fe8b7a24068 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Milenkovi=C4=87?= Date: Mon, 25 May 2026 10:58:45 +0100 Subject: [PATCH 05/22] Update dev/bin/showplan.sh Co-authored-by: Martin Grigorov --- dev/bin/showplan.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/bin/showplan.sh b/dev/bin/showplan.sh index 98c1c3dc9e..6a2e69d720 100755 --- a/dev/bin/showplan.sh +++ b/dev/bin/showplan.sh @@ -46,7 +46,7 @@ # ] # ``` # -# jobs are not sorted,. +# jobs are not sorted. # # `curl http://localhost:50050/api/job/LOZNWx3 | jq` # returns the specific job `LOZNWx3` information From 49c64012b0477fa7185250ab70d2936f005561bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Milenkovi=C4=87?= Date: Mon, 25 May 2026 10:59:23 +0100 Subject: [PATCH 06/22] Update dev/bin/showplan.sh Co-authored-by: Martin Grigorov --- dev/bin/showplan.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/bin/showplan.sh b/dev/bin/showplan.sh index 6a2e69d720..a723bef6fc 100755 --- a/dev/bin/showplan.sh +++ b/dev/bin/showplan.sh @@ -68,7 +68,7 @@ # } # ``` # -# `curl http://localhost:50050/api/job/LOZNWx3/stages |jq` +# `curl http://localhost:50050/api/job/LOZNWx3/stages | jq` # returns stage information for a given job # ``` # { From 7408325b73f450dc90ef5df2f52d7bb53b3af2e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Milenkovi=C4=87?= Date: Mon, 25 May 2026 11:00:34 +0100 Subject: [PATCH 07/22] Update dev/bin/showplan.sh Co-authored-by: Martin Grigorov --- dev/bin/showplan.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/bin/showplan.sh b/dev/bin/showplan.sh index a723bef6fc..ba32d52e96 100755 --- a/dev/bin/showplan.sh +++ b/dev/bin/showplan.sh @@ -21,7 +21,7 @@ # # PLAN PRINT HELPER # -# plan print is a helper command line utility for ballista. +# showplan.sh is a helper command line utility for Ballista. # which prints command line utility # # Ballista exposes REST API at `http://localhost:50050/` by default From 3b85cb10f11abd2a852f7d399419ae35eea8d4e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Milenkovi=C4=87?= Date: Mon, 25 May 2026 11:00:48 +0100 Subject: [PATCH 08/22] Update dev/bin/showplan.sh Co-authored-by: Martin Grigorov --- dev/bin/showplan.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/bin/showplan.sh b/dev/bin/showplan.sh index ba32d52e96..429dbbf832 100755 --- a/dev/bin/showplan.sh +++ b/dev/bin/showplan.sh @@ -19,7 +19,7 @@ # -# PLAN PRINT HELPER +# SHOW PLAN HELPER # # showplan.sh is a helper command line utility for Ballista. # which prints command line utility From ee6664084ee90dbc72cf8f22fe9f9e297d5758e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Milenkovi=C4=87?= Date: Mon, 25 May 2026 11:01:37 +0100 Subject: [PATCH 09/22] Update dev/bin/showplan.sh Co-authored-by: Martin Grigorov --- dev/bin/showplan.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/bin/showplan.sh b/dev/bin/showplan.sh index 429dbbf832..f6b3603605 100755 --- a/dev/bin/showplan.sh +++ b/dev/bin/showplan.sh @@ -117,7 +117,7 @@ # Job and stages endpoint accept `render_tree=true` parameter which # renders plans as tree. # -# command actions and options +# Command actions and options # # plan_print.sh [options] # From f29f30ba5748d994bc45301caffa9532b839a009 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Milenkovi=C4=87?= Date: Mon, 25 May 2026 11:01:58 +0100 Subject: [PATCH 10/22] Update dev/bin/showplan.sh Co-authored-by: Martin Grigorov --- dev/bin/showplan.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/bin/showplan.sh b/dev/bin/showplan.sh index f6b3603605..e975e1e93f 100755 --- a/dev/bin/showplan.sh +++ b/dev/bin/showplan.sh @@ -119,7 +119,7 @@ # # Command actions and options # -# plan_print.sh [options] +# showplan.sh [options] # # is optional parameter specifying, if not provided # uses the last job (filtered by max start time) From 5abd8f0fd719c101a3f2be3e072bf7a0199c14d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Milenkovi=C4=87?= Date: Mon, 25 May 2026 11:03:25 +0100 Subject: [PATCH 11/22] Update dev/bin/showplan.sh Co-authored-by: Martin Grigorov --- dev/bin/showplan.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dev/bin/showplan.sh b/dev/bin/showplan.sh index e975e1e93f..5aa6a10ecf 100755 --- a/dev/bin/showplan.sh +++ b/dev/bin/showplan.sh @@ -208,6 +208,14 @@ while [[ $# -gt 0 ]]; do esac done +# Check dependencies +for cmd in curl jq tput; do + if ! command -v "$cmd" &> /dev/null; then + echo "Error: $cmd is not installed." >&2 + exit 1 + fi +done + # Normalize API base URL (ensure exactly one trailing slash) API_BASE="${API_BASE%/}/" From 411b9a4343d3766532246ad18f910307787b7998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Milenkovi=C4=87?= Date: Mon, 25 May 2026 11:03:54 +0100 Subject: [PATCH 12/22] Update dev/bin/showplan.sh Co-authored-by: Martin Grigorov --- dev/bin/showplan.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/bin/showplan.sh b/dev/bin/showplan.sh index 5aa6a10ecf..b57307c0cf 100755 --- a/dev/bin/showplan.sh +++ b/dev/bin/showplan.sh @@ -238,7 +238,7 @@ else fi COLS=$(tput cols 2>/dev/tty || echo 80) -SEP=$(printf '%.0s-' $(seq 1 $COLS)) +SEP=$(printf '%*s' "$COLS" ' ' | tr ' ' '-') print_plan() { case "$DISPLAY_MODE" in From cd254c26fd27fda2c0639a5d3ec6f48cf19ae701 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Milenkovi=C4=87?= Date: Mon, 25 May 2026 11:04:35 +0100 Subject: [PATCH 13/22] Update dev/bin/showplan.sh Co-authored-by: Martin Grigorov --- dev/bin/showplan.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/bin/showplan.sh b/dev/bin/showplan.sh index b57307c0cf..c867d41d14 100755 --- a/dev/bin/showplan.sh +++ b/dev/bin/showplan.sh @@ -288,4 +288,4 @@ if [[ "$USE_PAGER" == "true" ]]; then print_plan else print_plan -fi \ No newline at end of file +fi From 62d5050bda55624a67e6c813117c7cb952338b07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Milenkovi=C4=87?= Date: Mon, 25 May 2026 11:08:11 +0100 Subject: [PATCH 14/22] Update dev/bin/showplan.sh Co-authored-by: Martin Grigorov --- dev/bin/showplan.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/bin/showplan.sh b/dev/bin/showplan.sh index c867d41d14..d0868cdd2c 100755 --- a/dev/bin/showplan.sh +++ b/dev/bin/showplan.sh @@ -124,7 +124,7 @@ # is optional parameter specifying, if not provided # uses the last job (filtered by max start time) # -# -a specified executor API address in format `http://executor-host:12345/` +# -a specify the Scheduler API address in format `http://executor-host:12345/` # it should contain host and port # -p display `physical_plan` (default, if not specified) # -l display `logical_plan` From 7b7d41718f3f1b509e6691525d1a4d05cd74ce63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Milenkovi=C4=87?= Date: Mon, 25 May 2026 11:11:01 +0100 Subject: [PATCH 15/22] Update dev/bin/showplan.sh Co-authored-by: Martin Grigorov --- dev/bin/showplan.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/bin/showplan.sh b/dev/bin/showplan.sh index d0868cdd2c..b7dda15e4a 100755 --- a/dev/bin/showplan.sh +++ b/dev/bin/showplan.sh @@ -221,7 +221,7 @@ API_BASE="${API_BASE%/}/" # Resolve job_id if not provided if [[ -z "$JOB_ID" ]]; then - JOB_ID=$(curl -sf "${API_BASE}api/jobs" | jq -r 'max_by(.start_time) | .job_id') + JOB_ID=$(curl -sSf "${API_BASE}api/jobs" | jq -r 'max_by(.start_time) | .job_id') if [[ -z "$JOB_ID" || "$JOB_ID" == "null" ]]; then echo "Error: no jobs found at ${API_BASE}api/jobs" >&2 exit 1 From 2ddfde2726b8828c2753670da35e5fb17eb48e34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Milenkovi=C4=87?= Date: Mon, 25 May 2026 11:13:43 +0100 Subject: [PATCH 16/22] Update dev/bin/showplan.sh Co-authored-by: Martin Grigorov --- dev/bin/showplan.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/bin/showplan.sh b/dev/bin/showplan.sh index b7dda15e4a..103e38cf5e 100755 --- a/dev/bin/showplan.sh +++ b/dev/bin/showplan.sh @@ -252,7 +252,7 @@ print_plan() { echo "${SEP}" echo "Job ${JOB_ID} logical plan:" echo "${SEP}" - curl -sf "${JOB_URL}" | jq -r '.logical_plan' + curl -sSf "${JOB_URL}" | jq -r '.logical_plan' ;; execution) echo "${SEP}" From 7df4edebfa9a6f3f06b27433dc7aa448d1a51ed0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Milenkovi=C4=87?= Date: Mon, 25 May 2026 11:14:15 +0100 Subject: [PATCH 17/22] Update dev/bin/showplan.sh Co-authored-by: Martin Grigorov --- dev/bin/showplan.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/bin/showplan.sh b/dev/bin/showplan.sh index 103e38cf5e..67f3493d87 100755 --- a/dev/bin/showplan.sh +++ b/dev/bin/showplan.sh @@ -246,7 +246,7 @@ print_plan() { echo "${SEP}" echo "Job ${JOB_ID} physical plan:" echo "${SEP}" - curl -sf "${JOB_URL}" | jq -r '.physical_plan' + curl -sSf "${JOB_URL}" | jq -r '.physical_plan' ;; logical) echo "${SEP}" From 27e9d16aa66170c4926c1c68d04977974b06e977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Milenkovi=C4=87?= Date: Mon, 25 May 2026 11:15:43 +0100 Subject: [PATCH 18/22] Update dev/bin/showplan.sh Co-authored-by: Martin Grigorov --- dev/bin/showplan.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/bin/showplan.sh b/dev/bin/showplan.sh index 67f3493d87..e0bb80e158 100755 --- a/dev/bin/showplan.sh +++ b/dev/bin/showplan.sh @@ -258,7 +258,7 @@ print_plan() { echo "${SEP}" echo "Job ${JOB_ID} stage plan:" echo "${SEP}" - curl -sf "${JOB_URL}" | jq -r '.stage_plan' + curl -sSf "${JOB_URL}" | jq -r '.stage_plan' ;; stage) STAGES_JSON=$(curl -sf "${STAGES_URL}") From cb0934b4f4e0820de02e9cdad4c60818908a0e1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Milenkovi=C4=87?= Date: Mon, 25 May 2026 11:16:10 +0100 Subject: [PATCH 19/22] Update dev/bin/showplan.sh Co-authored-by: Martin Grigorov --- dev/bin/showplan.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/bin/showplan.sh b/dev/bin/showplan.sh index e0bb80e158..f7a2252732 100755 --- a/dev/bin/showplan.sh +++ b/dev/bin/showplan.sh @@ -261,7 +261,7 @@ print_plan() { curl -sSf "${JOB_URL}" | jq -r '.stage_plan' ;; stage) - STAGES_JSON=$(curl -sf "${STAGES_URL}") + STAGES_JSON=$(curl -sSf "${STAGES_URL}") if [[ -n "$STAGE_ID" ]]; then echo "${SEP}" echo "Job ${JOB_ID}/${STAGE_ID} physical plan:" From 3d1cc6ab938e934a05c1e1ef443279ec4c980837 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Milenkovi=C4=87?= Date: Mon, 25 May 2026 11:37:52 +0100 Subject: [PATCH 20/22] minor doc update --- dev/bin/showplan.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/bin/showplan.sh b/dev/bin/showplan.sh index f7a2252732..257a4a4828 100755 --- a/dev/bin/showplan.sh +++ b/dev/bin/showplan.sh @@ -130,7 +130,7 @@ # -l display `logical_plan` # -e display `stage_plan` (from job info) # -s [] display `physical_plan` for specified stage, or all stages if omitted (from stages info) -# -w pipe output through `less -S` (no word wrap, horizontal scroll) +# -w displays result with no word wrap, horizontal scroll) # -t display plans as tree render (where applicable) set -euo pipefail @@ -151,7 +151,7 @@ usage() { echo " -l display logical_plan" echo " -e display stage_plan (from job info)" echo " -s [STAGE_ID] display stage_plan for the given stage, or all stages if omitted (from stages info)" - echo " -w pipe output through 'less -S' (no line-wrap, horizontal scroll)" + echo " -w displays result with no word wrap, horizontal scroll)" echo " -t display plans as tree render (where applicable)" exit 1 } From 8473a35615cf7e66ae929e4da78eedf3695a268a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Milenkovi=C4=87?= Date: Mon, 25 May 2026 13:41:23 +0100 Subject: [PATCH 21/22] add show multiple plans --- dev/bin/showplan.sh | 112 +++++++++++++++++++++++++------------------- 1 file changed, 63 insertions(+), 49 deletions(-) diff --git a/dev/bin/showplan.sh b/dev/bin/showplan.sh index 257a4a4828..51b76f6e3e 100755 --- a/dev/bin/showplan.sh +++ b/dev/bin/showplan.sh @@ -126,19 +126,23 @@ # # -a specify the Scheduler API address in format `http://executor-host:12345/` # it should contain host and port -# -p display `physical_plan` (default, if not specified) -# -l display `logical_plan` -# -e display `stage_plan` (from job info) -# -s [] display `physical_plan` for specified stage, or all stages if omitted (from stages info) +# -p display `physical_plan` (default, if not specified; combinable with other mode flags) +# -l display `logical_plan` (combinable with other mode flags) +# -e display `stage_plan` (from job info; combinable with other mode flags) +# -s [] display `physical_plan` for specified stage, or all stages if omitted +# (from stages info; combinable with other mode flags) # -w displays result with no word wrap, horizontal scroll) # -t display plans as tree render (where applicable) +# +# Multiple mode flags can be combined and each will be printed in order. +# Example: -p -l prints physical plan followed by logical plan. set -euo pipefail # Defaults API_BASE="http://localhost:50050/" JOB_ID="" -DISPLAY_MODE="physical" +DISPLAY_MODE=() # modes accumulate via flags; defaults to (physical) if none given STAGE_ID="" USE_PAGER=false RENDER_TREE=false @@ -147,12 +151,15 @@ usage() { echo "Usage: $(basename "$0") [job_id] [-a address] [-p] [-l] [-e] [-s stage_id]" echo " job_id optional; defaults to the most recent job" echo " -a ADDR API base URL (default: http://localhost:50050/)" - echo " -p display physical_plan (default)" - echo " -l display logical_plan" - echo " -e display stage_plan (from job info)" - echo " -s [STAGE_ID] display stage_plan for the given stage, or all stages if omitted (from stages info)" - echo " -w displays result with no word wrap, horizontal scroll)" + echo " -p display physical_plan (default; combinable with other mode flags)" + echo " -l display logical_plan (combinable with other mode flags)" + echo " -e display stage_plan from job info (combinable with other mode flags)" + echo " -s [STAGE_ID] display stage_plan for the given stage, or all stages if omitted (combinable)" + echo " -w displays result with no word wrap (horizontal scroll)" echo " -t display plans as tree render (where applicable)" + echo "" + echo " Mode flags are cumulative — each selected mode is printed in order." + echo " Example: $(basename "$0") -p -l prints physical plan then logical plan." exit 1 } @@ -171,15 +178,15 @@ while [[ $# -gt 0 ]]; do shift 2 ;; -p) - DISPLAY_MODE="physical" + DISPLAY_MODE+=("physical") shift ;; -l) - DISPLAY_MODE="logical" + DISPLAY_MODE+=("logical") shift ;; -s) - DISPLAY_MODE="stage" + DISPLAY_MODE+=("stage") # stage_id is optional; consume next arg only if it is not a flag if [[ $# -ge 2 && "$2" != -* ]]; then STAGE_ID="$2" @@ -190,7 +197,7 @@ while [[ $# -gt 0 ]]; do fi ;; -e) - DISPLAY_MODE="execution" + DISPLAY_MODE+=("execution") shift ;; -w) @@ -208,6 +215,11 @@ while [[ $# -gt 0 ]]; do esac done +# Default to physical if no mode flag was provided +if [[ ${#DISPLAY_MODE[@]} -eq 0 ]]; then + DISPLAY_MODE=("physical") +fi + # Check dependencies for cmd in curl jq tput; do if ! command -v "$cmd" &> /dev/null; then @@ -241,45 +253,47 @@ COLS=$(tput cols 2>/dev/tty || echo 80) SEP=$(printf '%*s' "$COLS" ' ' | tr ' ' '-') print_plan() { - case "$DISPLAY_MODE" in - physical) - echo "${SEP}" - echo "Job ${JOB_ID} physical plan:" - echo "${SEP}" - curl -sSf "${JOB_URL}" | jq -r '.physical_plan' - ;; - logical) - echo "${SEP}" - echo "Job ${JOB_ID} logical plan:" - echo "${SEP}" - curl -sSf "${JOB_URL}" | jq -r '.logical_plan' - ;; - execution) - echo "${SEP}" - echo "Job ${JOB_ID} stage plan:" - echo "${SEP}" - curl -sSf "${JOB_URL}" | jq -r '.stage_plan' - ;; - stage) - STAGES_JSON=$(curl -sSf "${STAGES_URL}") - if [[ -n "$STAGE_ID" ]]; then + for mode in "${DISPLAY_MODE[@]}"; do + case "$mode" in + physical) echo "${SEP}" - echo "Job ${JOB_ID}/${STAGE_ID} physical plan:" + echo "Job ${JOB_ID} physical plan:" echo "${SEP}" - echo "${STAGES_JSON}" \ - | jq -r --arg sid "$STAGE_ID" '.stages[] | select(.stage_id == $sid) | .stage_plan' - else - STAGE_COUNT=$(echo "${STAGES_JSON}" | jq '.stages | length') - for ((i = 0; i < STAGE_COUNT; i++)); do - SID=$(echo "${STAGES_JSON}" | jq -r ".stages[$i].stage_id") + curl -sSf "${JOB_URL}" | jq -r '.physical_plan' + ;; + logical) + echo "${SEP}" + echo "Job ${JOB_ID} logical plan:" + echo "${SEP}" + curl -sSf "${JOB_URL}" | jq -r '.logical_plan' + ;; + execution) + echo "${SEP}" + echo "Job ${JOB_ID} stage plan:" + echo "${SEP}" + curl -sSf "${JOB_URL}" | jq -r '.stage_plan' + ;; + stage) + STAGES_JSON=$(curl -sSf "${STAGES_URL}") + if [[ -n "$STAGE_ID" ]]; then echo "${SEP}" - echo "Job ${JOB_ID}/${SID} physical plan:" + echo "Job ${JOB_ID}/${STAGE_ID} physical plan:" echo "${SEP}" - echo "${STAGES_JSON}" | jq -r ".stages[$i].stage_plan" - done - fi - ;; - esac + echo "${STAGES_JSON}" \ + | jq -r --arg sid "$STAGE_ID" '.stages[] | select(.stage_id == $sid) | .stage_plan' + else + STAGE_COUNT=$(echo "${STAGES_JSON}" | jq '.stages | length') + for ((i = 0; i < STAGE_COUNT; i++)); do + SID=$(echo "${STAGES_JSON}" | jq -r ".stages[$i].stage_id") + echo "${SEP}" + echo "Job ${JOB_ID}/${SID} physical plan:" + echo "${SEP}" + echo "${STAGES_JSON}" | jq -r ".stages[$i].stage_plan" + done + fi + ;; + esac + done } if [[ "$USE_PAGER" == "true" ]]; then From 9173adbf63313e876be69d897743dd2b85a8abd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Milenkovi=C4=87?= Date: Mon, 25 May 2026 20:52:58 +0100 Subject: [PATCH 22/22] Update showplan.sh Co-authored-by: Martin Grigorov --- dev/bin/showplan.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/bin/showplan.sh b/dev/bin/showplan.sh index 51b76f6e3e..891c3c1997 100755 --- a/dev/bin/showplan.sh +++ b/dev/bin/showplan.sh @@ -124,7 +124,7 @@ # is optional parameter specifying, if not provided # uses the last job (filtered by max start time) # -# -a specify the Scheduler API address in format `http://executor-host:12345/` +# -a specify the Scheduler API address in format `http://scheduler-host:12345/` # it should contain host and port # -p display `physical_plan` (default, if not specified; combinable with other mode flags) # -l display `logical_plan` (combinable with other mode flags)