#!/usr/bin/env bash set -euo pipefail ENDPOINT="" ACCESS_KEY="" SECRET_KEY="" BUCKET="" OBJECTS="" REGION="us-east-1" MODES="sequential,ranged_parallel" CONCURRENCIES="1,4,8" RANGE_WORKERS="4" ROUNDS=3 COOLDOWN_SECS=15 PRESIGN_EXPIRY="2h" OUT_DIR="" MC_BIN="${MC_BIN:-mc}" CURL_BIN="${CURL_BIN:-curl}" JQ_BIN="${JQ_BIN:-jq}" INSECURE=false DRY_RUN=false usage() { cat <<'USAGE' Usage: scripts/run_gt1g_get_http_matrix.sh \ --endpoint --access-key --secret-key \ --bucket --objects [options] Required: --endpoint --access-key --secret-key --bucket --objects Format: label=object-key,label=object-key Options: --region Default: us-east-1 --modes Default: sequential,ranged_parallel --concurrencies Default: 1,4,8 --range-workers Default: 4 Used only by ranged_parallel mode --rounds Default: 3 --cooldown-secs Default: 15 --presign-expiry Default: 2h --out-dir Default: target/bench/gt1g-get-http- --mc-bin Default: mc --curl-bin Default: curl --jq-bin Default: jq --insecure Allow insecure TLS --dry-run -h, --help Examples: scripts/run_gt1g_get_http_matrix.sh \ --endpoint http://127.0.0.1:9000 \ --access-key rustfsadmin \ --secret-key rustfsadmin \ --bucket rustfs-bench \ --objects '1GiB=bench/issue713/plain-1g.bin,2GiB=bench/issue713/plain-2g.bin' USAGE } arg_value() { local flag="$1" local value="${2:-}" if [[ -z "$value" || "$value" == --* ]]; then echo "ERROR: missing value for $flag" >&2 exit 1 fi printf '%s\n' "$value" } require_cmd() { if ! command -v "$1" >/dev/null 2>&1; then echo "ERROR: command not found: $1" >&2 exit 1 fi } run_rust_helper_fallback() { local helper_out_dir="$OUT_DIR" if [[ -n "$helper_out_dir" && "$helper_out_dir" != /* ]]; then helper_out_dir="$PWD/$helper_out_dir" fi echo "mc not found; falling back to rustfs/tests/gt1g_get_benchmark_tool.rs" GT1G_GET_ACTION=bench \ GT1G_GET_ENDPOINT="$ENDPOINT" \ GT1G_GET_ACCESS_KEY="$ACCESS_KEY" \ GT1G_GET_SECRET_KEY="$SECRET_KEY" \ GT1G_GET_BUCKET="$BUCKET" \ GT1G_GET_REGION="$REGION" \ GT1G_GET_OBJECTS="$OBJECTS" \ GT1G_GET_MODES="$MODES" \ GT1G_GET_CONCURRENCIES="$CONCURRENCIES" \ GT1G_GET_RANGE_WORKERS="$RANGE_WORKERS" \ GT1G_GET_ROUNDS="$ROUNDS" \ GT1G_GET_COOLDOWN_SECS="$COOLDOWN_SECS" \ GT1G_GET_OUT_DIR="$helper_out_dir" \ cargo test -p rustfs --test gt1g_get_benchmark_tool gt1g_get_benchmark_tool -- --ignored --nocapture } parse_args() { while [[ $# -gt 0 ]]; do case "$1" in --endpoint) ENDPOINT="$(arg_value "$1" "${2:-}")"; shift 2 ;; --access-key) ACCESS_KEY="$(arg_value "$1" "${2:-}")"; shift 2 ;; --secret-key) SECRET_KEY="$(arg_value "$1" "${2:-}")"; shift 2 ;; --bucket) BUCKET="$(arg_value "$1" "${2:-}")"; shift 2 ;; --objects) OBJECTS="$(arg_value "$1" "${2:-}")"; shift 2 ;; --region) REGION="$(arg_value "$1" "${2:-}")"; shift 2 ;; --modes) MODES="$(arg_value "$1" "${2:-}")"; shift 2 ;; --concurrencies) CONCURRENCIES="$(arg_value "$1" "${2:-}")"; shift 2 ;; --range-workers) RANGE_WORKERS="$(arg_value "$1" "${2:-}")"; shift 2 ;; --rounds) ROUNDS="$(arg_value "$1" "${2:-}")"; shift 2 ;; --cooldown-secs) COOLDOWN_SECS="$(arg_value "$1" "${2:-}")"; shift 2 ;; --presign-expiry) PRESIGN_EXPIRY="$(arg_value "$1" "${2:-}")"; shift 2 ;; --out-dir) OUT_DIR="$(arg_value "$1" "${2:-}")"; shift 2 ;; --mc-bin) MC_BIN="$(arg_value "$1" "${2:-}")"; shift 2 ;; --curl-bin) CURL_BIN="$(arg_value "$1" "${2:-}")"; shift 2 ;; --jq-bin) JQ_BIN="$(arg_value "$1" "${2:-}")"; shift 2 ;; --insecure) INSECURE=true; shift ;; --dry-run) DRY_RUN=true; shift ;; -h|--help) usage; exit 0 ;; *) echo "ERROR: unknown arg: $1" >&2 usage exit 1 ;; esac done } validate_positive_int() { local value="$1" local label="$2" if ! [[ "$value" =~ ^[0-9]+$ ]] || (( value <= 0 )); then echo "ERROR: $label must be a positive integer, got: $value" >&2 exit 1 fi } validate_nonnegative_int() { local value="$1" local label="$2" if ! [[ "$value" =~ ^[0-9]+$ ]]; then echo "ERROR: $label must be a nonnegative integer, got: $value" >&2 exit 1 fi } trim() { echo "$1" | awk '{$1=$1;print}' } setup_output() { if [[ -z "$OUT_DIR" ]]; then OUT_DIR="target/bench/gt1g-get-http-$(date -u +%Y%m%dT%H%M%SZ)" fi LOG_DIR="${OUT_DIR}/logs" mkdir -p "$LOG_DIR" ROUND_CSV="${OUT_DIR}/round_results.csv" MEDIAN_CSV="${OUT_DIR}/median_summary.csv" cat > "$ROUND_CSV" <<'EOF' object_label,object_key,mode,range_workers,concurrency,round,status,total_bytes,elapsed_ms,throughput_bps,avg_client_latency_ms,log_file EOF cat > "$MEDIAN_CSV" <<'EOF' object_label,object_key,mode,range_workers,concurrency,successful_rounds,failed_rounds,median_total_bytes,median_elapsed_ms,median_throughput_bps,median_avg_client_latency_ms EOF cat > "${OUT_DIR}/artifact_layout.txt" <<'EOF' round_results.csv median_summary.csv artifact_layout.txt logs/ -