Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 26 additions & 5 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,16 @@ jobs:
name: codecov-${{ matrix.os }}-${{ matrix.go }}
continue-on-error: true

race-check:
name: Race Detector
# `task test:race` split across runners (scripts/race-shard.sh): the heavy
# race packages starve each other on one 4-vCPU runner and cross the
# 120s per-package timeout. Same packages, flags and timeout as the task.
race-shard:
name: Race Detector (shard ${{ matrix.shard }}/4)
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
shard: [0, 1, 2, 3]
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0

Expand All @@ -88,10 +95,24 @@ jobs:
- name: Install Task
run: go install github.com/go-task/task/v3/cmd/task@v3.54.0

# Use Taskfile so CI matches local `task test:race` (pkg/cbinding excluded -
# it requires CGO and is exercised separately in the cbinding-race job).
# pkg/cbinding is excluded - it requires CGO and is exercised separately
# in the cbinding-race job.
- name: Run tests with race detector
run: task test:race
run: task test:race:shard SHARD=${{ matrix.shard }} SHARDS=4

# Required status check name; passes only if every shard passed.
race-check:
name: Race Detector
runs-on: ubuntu-latest
needs: race-shard
if: always()
steps:
- name: Check race shards
env:
RESULT: ${{ needs.race-shard.result }}
run: |
echo "race shards: $RESULT"
[ "$RESULT" = success ]

cbinding-race:
name: Race Detector (CGO / cbinding)
Expand Down
7 changes: 7 additions & 0 deletions Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ tasks:
- echo "Running tests with race detection..."
- CGO_ENABLED=1 go test -race -timeout 120s $(go list ./... | grep -v /cbinding)

test:race:shard:
desc: "Run one shard of test:race (CI). Usage: task test:race:shard SHARD=0 SHARDS=4"
requires:
vars: [SHARD, SHARDS]
cmds:
- bash scripts/race-shard.sh {{.SHARD}} {{.SHARDS}}

test:cbinding:
desc: Test C binding package (requires CGO)
env:
Expand Down
59 changes: 59 additions & 0 deletions scripts/race-shard.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/usr/bin/env bash
# Run one shard of the race-enabled test suite (`task test:race` split N ways).
#
# Usage: scripts/race-shard.sh SHARD SHARDS
#
# Packages are dealt round-robin with the heaviest race packages first, so no
# two of them share a shard. A single `go test -race ./...` on a 4-vCPU CI
# runner runs them side by side and starves each one; their wall time then
# swings with the runner (tokenizer 79-120s, security 65-104s on identical
# commits) and crosses the per-package -timeout. Sharding keeps the same
# packages, flags and timeout as `task test:race`; only the concurrency
# between heavy packages changes. pkg/cbinding stays excluded (CGO job).
set -euo pipefail

shard=${1:?shard index (0-based)}
shards=${2:?shard count}
if ! [[ $shard =~ ^[0-9]+$ && $shards =~ ^[1-9][0-9]*$ ]] || ((shard >= shards)); then
echo "race-shard: need 0 <= SHARD < SHARDS, got $shard/$shards" >&2
exit 2
fi

mod=$(go list -m)
# Heaviest first (CI race wall time, Nov 2026). Unknown packages follow in
# go list order; a heavy package missing from this list still runs.
heavy=(
pkg/sql/tokenizer
pkg/sql/security
pkg/sql/parser
pkg/transpiler
pkg/gosqlx
scripts/perf/gate
)

all=$(go list ./... | grep -v /cbinding)
ordered=()
for h in "${heavy[@]}"; do
if grep -qx "$mod/$h" <<<"$all"; then
ordered+=("$mod/$h")
fi
done
while IFS= read -r p; do
skip=
for h in "${heavy[@]}"; do
[[ $p == "$mod/$h" ]] && skip=1
done
[[ -z $skip ]] && ordered+=("$p")
done <<<"$all"

mine=()
for i in "${!ordered[@]}"; do
((i % shards == shard)) && mine+=("${ordered[$i]}")
done
if ((${#mine[@]} == 0)); then
echo "race-shard $shard/$shards: no packages"
exit 0
fi

echo "race-shard $shard/$shards: ${#mine[@]} of ${#ordered[@]} packages"
CGO_ENABLED=1 go test -race -timeout 120s "${mine[@]}"
Loading