ci: compact older builds on the storage server #697

Merged
Burer merged 5 commits from builds-cleanup into main 2026-09-28 07:32:38 +00:00
2 changed files with 98 additions and 0 deletions

No files matched your search

+24
View File
@@ -54,3 +54,27 @@
src: "{{ stable_artifact_path }}/"
dest: "{{ storage_path }}/../"
mode: preserve
# older builds shrink to compressed images and lose their unpacked tree; the newest few keep both
- name: Looking for zstd on the storage server
ansible.builtin.shell: command -v zstd
Sweetbread marked this conversation as resolved Outdated
Outdated
Review

Are you sure zip is better for compressing? Why not 7z?

Are you sure zip is better for compressing? Why not 7z?
Outdated
Review

Feels like zip is more common and supported out of box in different OS.
Also runs much faster on our server, without much bigger size.
Example for kolibri.raw:

method size from original time
zip -9 56 270 041 41.9% 17 с
7z -tzip -mx9 (deflate) 54 260 068 40.4% 112 с
zstd -12 50 916 883 37.9% 7 с
zstd -19 46 533 976 34.7% 38 с
xz -6 44 025 416 32.8% 35 с
xz -9 43 146 400 32.1% 95 с
7z LZMA2 -mx9 43 116 123 32.1% 40 с
Feels like zip is more common and supported out of box in different OS. Also runs much faster on our server, without much bigger size. Example for `kolibri.raw`: method | size | from original | time -- | -- | -- | -- zip -9 | 56 270 041 | 41.9% | 17 с 7z -tzip -mx9 (deflate) | 54 260 068 | 40.4% | 112 с zstd -12 | 50 916 883 | 37.9% | 7 с zstd -19 | 46 533 976 | 34.7% | 38 с xz -6 | 44 025 416 | 32.8% | 35 с xz -9 | 43 146 400 | 32.1% | 95 с 7z LZMA2 -mx9 | 43 116 123 | 32.1% | 40 с
Outdated
Review

Well, we have and had a lot of versions and I don't think it would be difficult to install some rare archiver to extract an old version for some reason

Well, we have and had a *lot* of versions and I don't think it would be difficult to install some rare archiver to extract an old version for some reason
Outdated
Review

Switched to zstd -12. Measured on the storage server, per build (680 MB of images, three languages):

zip -9 zstd -12
size after 314 MB 290 MB
time 54 s 42 s
Switched to zstd -12. Measured on the storage server, per build (680 MB of images, three languages): | | zip -9 | zstd -12 | |---|---|---| | size after | 314 MB | 290 MB | | time | 54 s | 42 s |
register: zstd_present
changed_when: false
failed_when: false
- name: Requiring zstd for compaction
ansible.builtin.assert:
that: zstd_present.rc == 0
fail_msg: >-
zstd is not installed on the storage server, so older builds cannot
be compacted. Install it and re-run this build.
- name: Compacting older builds
ansible.builtin.script:
cmd: >-
../../utils/compact-builds.sh
{{ storage_path | quote }}
{{ compact_keep | default(5) | int }}
{{ compact_max | default(10) | int }}
register: compaction
changed_when: "'compacted 0 of' not in compaction.stdout"
+74
View File
@@ -0,0 +1,74 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0-only
# SPDX-FileCopyrightText: 2026 KolibriOS team
# Shrink older builds on the storage server: compress their images and drop
# their unpacked tree, which is rebuildable from the commit. sha256sums.txt
# keeps naming the bare images, so a compacted build has to be decompressed
# before it can be verified.
#
# Layout: <root>/<version>/<lang>/kolibrios-<descr>-<lang>.{img,iso,raw} -> .zst
# <root>/<version>/<lang>/data/ -> removed
#
# Usage: compact-builds.sh <storage-root> [keep] [max-per-run]
# DRY_RUN=1 walks the same selection and changes nothing
set -euo pipefail
root=${1:?storage root required}
# the build just published is always among these, so an upload in flight is safe
keep=${2:-5}
# a build is hundreds of MiB to re-compress: cap the first pass over the backlog
max=${3:-10}
dry=${DRY_RUN:-0}
verb=compacted
[ "$dry" = 1 ] && verb="would compact"
# --rm drops the source only once the archive is written; the box serves the
Sweetbread marked this conversation as resolved Outdated
Outdated
Review

You defined root var, but still use positional argument

You defined `root` var, but still use positional argument
Outdated
Review

Fixed.

Fixed.
Outdated
Review

No

No
Outdated
Review

leftovers is not called with the storage root - it takes one build directory (leftovers "$dir", where dir="$root/$version"), so $root would be the wrong path to search. The argument is now named:

    leftovers() {
        local build=$1
        find "$build" -mindepth 2 -maxdepth 2 ...

If you meant something else by "still use positional argument", say which line and I will change it.

`leftovers` is not called with the storage root - it takes one build directory (`leftovers "$dir"`, where `dir="$root/$version"`), so `$root` would be the wrong path to search. The argument is now named: ```sh leftovers() { local build=$1 find "$build" -mindepth 2 -maxdepth 2 ... ``` If you meant something else by "still use positional argument", say which line and I will change it.
# site over NFS, so compaction yields to it
compress_image() {
nice -n 10 ionice -c3 zstd -12 -T1 -q --rm "$1"
}
export -f compress_image
leftovers() {
local build=$1
find "$build" -mindepth 2 -maxdepth 2 \
\( -type d -name data \
-o -type f \( -name '*.img' -o -name '*.iso' -o -name '*.raw' \) \) \
-print -quit
}
compacted=0
pending=0
while IFS= read -r version; do
dir="$root/$version"
[ -n "$(leftovers "$dir")" ] || continue
pending=$((pending + 1))
[ "$compacted" -lt "$max" ] || continue
if [ "$dry" = 1 ]; then
compacted=$((compacted + 1))
echo "$verb $version"
continue
Sweetbread marked this conversation as resolved Outdated
Outdated
Review

It's a bad idea to use mtime. Better keep last N builds

It's a bad idea to use `mtime`. Better keep last N builds
Outdated
Review

Fixed.

Fixed.
fi
# a build holds nine images: one per core, each zstd kept to one thread so
# the two levels of parallelism do not fight. Archive before dropping the
# tree, so a failure here leaves the build merely uncompacted and the next
# run picks it up again
find "$dir" -mindepth 2 -maxdepth 2 -type f \
\( -name '*.img' -o -name '*.iso' -o -name '*.raw' \) -print0 \
| xargs -0 -r -P "$(nproc)" -I{} bash -c 'compress_image "$@"' _ {}
find "$dir" -mindepth 2 -maxdepth 2 -type d -name data -exec rm -rf {} +
compacted=$((compacted + 1))
echo "$verb $version"
# <tag>-<commit count>-g<sha>: order by the count, never by mtime
done < <(find "$root" -mindepth 1 -maxdepth 1 -type d -name '*-*-g*' -printf '%f\n' \
| sort -t- -k2,2n | head -n "-$keep")
echo "$verb $compacted of $pending older build(s), $((pending - compacted)) left for the next run"