Index the offline mirror with one repo-add per CPU

repo-add takes one package at a time: it hashes the archive and lists its
files, which means decompressing all of it, for about a thousand
packages one after another.

A database is a tar of one directory per package. The packages are dealt
out to one repo-add per CPU, each writing its own database, and the
pieces are joined. On 160 packages on a 16-core machine the result is
identical to one repo-add's, db and files, in 1.0 s against 6.3 s. Two
versions of one package name are an error: one repo-add would keep the
last, the pieces apart would keep both.
This commit is contained in:
Emir Beganovic committed 2026-10-09 19:18:06 +02:00
1 parent 0bc00ff572
commit ebfbf43aa0
3 files changed
+134 -2

No files matched your search

+64
View File
@@ -0,0 +1,64 @@
#!/bin/bash
#
# The offline mirror is indexed by several repo-add processes whose databases
# are then joined (builder/index-offline-mirror.sh). The result has to be the
# database one repo-add writes over the same packages, and two versions of one
# package have to be an error, since apart they would both be kept.
set -euo pipefail
ROOT=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)
index="$ROOT/builder/index-offline-mirror.sh"
bash -n "$index"
if ! command -v repo-add >/dev/null; then
echo "offline mirror index tests skipped: no repo-add here"
exit 0
fi
fixture=$(mktemp -d)
trap 'rm -rf "$fixture"' EXIT
fail() { echo "FAIL: $*" >&2; exit 1; }
package() { # directory name version: the least repo-add accepts as a package
local stage="$fixture/stage"
rm -rf "$stage"; mkdir -p "$stage/usr/share/$2"
echo "$2 $3" >"$stage/usr/share/$2/version"
printf 'pkgname = %s\npkgver = %s\npkgdesc = fixture\narch = any\nsize = 1\n' "$2" "$3" >"$stage/.PKGINFO"
bsdtar -czf "$1/$2-$3-any.pkg.tar.gz" -C "$stage" .PKGINFO usr
}
contents() { # database file -> directory holding its entries
mkdir -p "$2"; bsdtar -xf "$1" -C "$2"
}
mkdir "$fixture/one" "$fixture/many"
for name in alpha bravo charlie delta echo foxtrot golf; do
package "$fixture/one" "$name" 1.0-1
cp "$fixture/one/$name-1.0-1-any.pkg.tar.gz" "$fixture/many/"
done
: >"$fixture/many/alpha-1.0-1-any.pkg.tar.gz.sig" # a signature is not a package
repo-add -q "$fixture/one/offline.db.tar.gz" "$fixture"/one/*.pkg.tar.gz >/dev/null 2>&1
bash "$index" "$fixture/many" 3 >/dev/null || fail "indexing seven packages with three processes failed"
for kind in db files; do
[[ -L $fixture/many/offline.$kind ]] || fail "offline.$kind, the name pacman fetches, is missing"
contents "$fixture/one/offline.$kind.tar.gz" "$fixture/x-one-$kind"
contents "$fixture/many/offline.$kind" "$fixture/x-many-$kind"
diff -r "$fixture/x-one-$kind" "$fixture/x-many-$kind" >/dev/null \
|| fail "the joined $kind database differs from one repo-add's"
done
# More processes than packages, and a second run over an indexed mirror.
bash "$index" "$fixture/many" 64 >/dev/null || fail "more processes than packages failed"
contents "$fixture/many/offline.db" "$fixture/x-again"
diff -r "$fixture/x-one-db" "$fixture/x-again" >/dev/null || fail "indexing an already indexed mirror changed it"
package "$fixture/many" alpha 2.0-1
bash "$index" "$fixture/many" 3 >/dev/null 2>&1 && fail "two versions of one package were indexed"
mkdir "$fixture/empty"
bash "$index" "$fixture/empty" >/dev/null 2>&1 && fail "an empty mirror was indexed"
grep -Fq 'bash /builder/index-offline-mirror.sh "$offline_mirror_dir"' "$ROOT/builder/build-iso.sh" \
|| fail "the build does not use the parallel index"
echo "offline mirror index tests passed"