diff --git a/tools/bazel-tools/.gitignore b/tools/bazel-tools/.gitignore new file mode 100644 index 0000000000000..ceddaa37f12a8 --- /dev/null +++ b/tools/bazel-tools/.gitignore @@ -0,0 +1 @@ +.cache/ diff --git a/tools/bazel-tools/support/bazel-tool-trampoline.sh b/tools/bazel-tools/support/bazel-tool-trampoline.sh index 7309f25420053..ae075d484a96c 100755 --- a/tools/bazel-tools/support/bazel-tool-trampoline.sh +++ b/tools/bazel-tools/support/bazel-tool-trampoline.sh @@ -52,9 +52,61 @@ debug "running $BAZEL_TOOL_TRAMPOLINE_TARGET" debug "bazel invoke cwd: $(pwd)" debug "target cwd : $BAZEL_TOOL_TRAMPOLINE_CWD" +# If BAZEL_TRAMPOLINE_PARALLEL=1 use a separate output_base so this tool can run +# in parallel with the main bazel server without contending for the same lock. +# Best for tools that need to run frequently and don't need a ton of files in +# their output base. disk_cache will in general obviate the need to actually +# rebuild anything. +# +# Determining the default output_base is tricky: `bazel info output_base` itself +# takes the main server's lock, so if the main server is busy the query would +# block (defeating the point). Strategy (keyed on cache existence): +# - No cache yet: no choice but to block — call `bazel info output_base` and +# seed the cache with the result. +# - Cache exists: try `bazel --noblock_for_lock info output_base` to +# opportunistically refresh the cache; on lock-held (exit 9) just use the +# cached value. +if [[ ${BAZEL_TRAMPOLINE_PARALLEL:-0} -gt 0 ]]; then + cache_dir="$support_script_dir/../.cache" + cache_file="$cache_dir/output_base" + mkdir -p "$cache_dir" + + if [[ ! -f $cache_file ]]; then + debug "output_base from: blocking bazel query (no cache yet)" + default_output_base="$(bazel info output_base)" + echo "$default_output_base" >"$cache_file" + else + # Bazel exits 9 (LOCK_HELD_NOBLOCK_FOR_LOCK) when --noblock_for_lock + # cannot acquire the server lock. Any other non-zero exit is a real + # error and should surface rather than silently falling back to cache. + rc=0 + fresh=$(bazel --noblock_for_lock info output_base 2>/dev/null) || rc=$? + if ((rc == 0)); then + debug "output_base from: live bazel query (cache refreshed)" + default_output_base=$fresh + echo "$default_output_base" >"$cache_file" + elif ((rc == 9)); then + default_output_base="$(cat "$cache_file")" + debug "output_base from: cache ($cache_file, lock held)" + else + echo "ERROR: bazel-tool-trampoline.sh: bazel info output_base failed (exit $rc)" >&2 + exit "$rc" + fi + fi + + tool_output_base="${default_output_base}_rptool" + output_base_flag=(--output_base="$tool_output_base") + + debug "tool output_base : $tool_output_base" +else + output_base_flag=() + debug "tool output_base : (default)" +fi + # These flags are to hide a bunch of Bazel's built-in output. -exec bazel run "$BAZEL_TOOL_TRAMPOLINE_TARGET" \ +exec bazel "${output_base_flag[@]}" \ + run "$BAZEL_TOOL_TRAMPOLINE_TARGET" \ --run_under=//tools/bazel-tools/support:run \ --noshow_progress \ --ui_event_filters=,+error,+fail \ diff --git a/tools/clang-format b/tools/clang-format index f07a5b5f55e2f..c445ccf01e899 120000 --- a/tools/clang-format +++ b/tools/clang-format @@ -1 +1 @@ -clang-tool.sh \ No newline at end of file +clang-tool-parallel.sh \ No newline at end of file diff --git a/tools/clang-tool-parallel.sh b/tools/clang-tool-parallel.sh new file mode 100755 index 0000000000000..27e183a20713c --- /dev/null +++ b/tools/clang-tool-parallel.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# Copyright 2026 Redpanda Data, Inc. +# +# Use of this software is governed by the Business Source License +# included in the file licenses/BSL.md +# +# As of the Change Date specified in that file, in accordance with +# the Business Source License, use of this software will be governed +# by the Apache License, Version 2.0 + +# Variant of clang-tool.sh that runs the tool against a separate bazel +# output_base so it can execute in parallel with the main bazel server. +# Only suitable for tools that don't depend on bazel-built artifacts +# (e.g. clang-tidy plugins) living in the default output_base. + +export BAZEL_TRAMPOLINE_PARALLEL="${BAZEL_TRAMPOLINE_PARALLEL:-1}" + +tools_dir="$(cd -- "$(dirname -- "$(realpath "${BASH_SOURCE[0]}")")" &>/dev/null && pwd)" + +# `exec -a` doesn't propagate through a shebang into bash's $0, so forward +# the invocation name via an env var that clang-tool.sh consults. +export CLANG_TOOL_NAME="$(basename "$0")" +exec "$tools_dir/clang-tool.sh" "$@" diff --git a/tools/clang-tool.sh b/tools/clang-tool.sh index 78fd607e79bce..ff6f12cd19da2 100755 --- a/tools/clang-tool.sh +++ b/tools/clang-tool.sh @@ -6,7 +6,8 @@ tools_dir="$(cd -- "$(dirname -- "$(realpath "${BASH_SOURCE[0]}")")" &>/dev/null && pwd)" -export BAZEL_TOOL_TRAMPOLINE_TARGET="@current_llvm_toolchain_llvm//:bin/$(basename "$0")" +tool_name="${CLANG_TOOL_NAME:-$(basename "$0")}" +export BAZEL_TOOL_TRAMPOLINE_TARGET="@current_llvm_toolchain_llvm//:bin/$tool_name" if [[ ${BAZEL_TRAMPOLINE_DEBUG:-0} -gt 0 ]]; then echo "DEBUG: clang-tool.sh: CWD : $(pwd)" >&2