Skip to content

Commit fa34886

Browse files
Merge pull request #78 from LASTRADA-Software/feature/distributed-compilation
Add distributed compilation: dispatch cache misses to worker nodes
2 parents 27c04d6 + b4feccf commit fa34886

89 files changed

Lines changed: 12699 additions & 140 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/workflows/build.yml‎

Lines changed: 95 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -668,7 +668,7 @@ jobs:
668668
run: cmake --preset gcc-release -DFASTCACHED_BUILD_TESTS=OFF -DFASTCACHED_PACKAGE_ROOT_PREFIX=ON -DFASTCACHED_REQUIRE_EXACT_VERSION=${{ env.FASTCACHED_REQUIRE_EXACT_VERSION }}
669669

670670
- name: "Build"
671-
run: cmake --build --preset gcc-release --target fastcached fastcache-cc
671+
run: cmake --build --preset gcc-release --target fastcached fastcache-cc fastcache-compile-node
672672

673673
- name: "Package"
674674
working-directory: out/build/gcc-release
@@ -710,11 +710,15 @@ jobs:
710710
711711
# The binaries, the units and the config must each land in the one
712712
# location that works; /usr/etc or /lib would silently never be read.
713-
for path in ./usr/bin/fastcached ./usr/bin/fastcache-cc \
713+
for path in ./usr/bin/fastcached ./usr/bin/fastcache-cc ./usr/bin/fastcache-compile-node \
714714
./usr/lib/systemd/system/fastcached.service \
715715
./usr/lib/systemd/user/fastcached.service \
716716
./usr/lib/sysusers.d/fastcached.conf \
717717
./usr/lib/tmpfiles.d/fastcached.conf \
718+
./usr/lib/systemd/system/fastcache-compile-node.service \
719+
./usr/lib/systemd/system/fastcache-compile-node.socket \
720+
./usr/lib/sysusers.d/fastcache-node.conf \
721+
./etc/fastcached/compile-node.env \
718722
./etc/fastcached/fastcached.yaml; do
719723
grep -qx "$path" /tmp/deb-paths.txt || { echo "::error::missing $path"; exit 1; }
720724
done
@@ -739,17 +743,26 @@ jobs:
739743
rpm -qlp "$rpmfile" > /tmp/rpm-paths.txt
740744
rpm -qcp "$rpmfile" > /tmp/rpm-config.txt
741745
742-
for path in /usr/bin/fastcached /usr/bin/fastcache-cc \
746+
for path in /usr/bin/fastcached /usr/bin/fastcache-cc /usr/bin/fastcache-compile-node \
743747
/usr/lib/systemd/system/fastcached.service \
744748
/usr/lib/systemd/user/fastcached.service \
745749
/usr/lib/sysusers.d/fastcached.conf \
746750
/usr/lib/tmpfiles.d/fastcached.conf \
751+
/usr/lib/systemd/system/fastcache-compile-node.service \
752+
/usr/lib/systemd/system/fastcache-compile-node.socket \
753+
/usr/lib/sysusers.d/fastcache-node.conf \
754+
/etc/fastcached/compile-node.env \
747755
/etc/fastcached/fastcached.yaml; do
748756
grep -qx "$path" /tmp/rpm-paths.txt || { echo "::error::missing $path"; exit 1; }
749757
done
750758
751-
grep -qx '/etc/fastcached/fastcached.yaml' /tmp/rpm-config.txt \
752-
|| { echo "::error::config not marked %config"; exit 1; }
759+
# Both, and for the same reason: an upgrade that reset either one is a
760+
# silent regression. compile-node.env is what makes the worker work at
761+
# all, so resetting it un-registers the worker with no error anywhere.
762+
for path in /etc/fastcached/fastcached.yaml /etc/fastcached/compile-node.env; do
763+
grep -qx "$path" /tmp/rpm-config.txt \
764+
|| { echo "::error::$path not marked %config"; exit 1; }
765+
done
753766
754767
# Install for real and drive traffic through it. The GitHub runner has a
755768
# live systemd, so this exercises the actual unit — the service account,
@@ -803,6 +816,75 @@ jobs:
803816
sudo systemctl stop fastcached
804817
test "$(systemctl show -p Result --value fastcached)" = success
805818
819+
- name: "Socket-activate the compile worker on real systemd"
820+
run: |
821+
set -euo pipefail
822+
823+
# The account the sysusers.d entry must have created. Without it the
824+
# unit fails to start with "user does not exist", which says nothing
825+
# about which package forgot to create it.
826+
id fastcache-node >/dev/null \
827+
|| { echo "::error::the fastcache-node service account was not created"; exit 1; }
828+
829+
# A scheduler that is not there. The worker must still start, warn and
830+
# keep retrying -- a fleet where the scheduler restarts must not turn
831+
# into a fleet of dead workers.
832+
printf 'FASTCACHE_NODE_ARGS=--scheduler=127.0.0.1:6675 --advertise=127.0.0.1:6676 --toolchain=/usr/bin/g++\n' \
833+
| sudo tee /etc/fastcached/compile-node.env >/dev/null
834+
835+
# Enabling the SOCKET is what enables the worker; the service carries
836+
# no [Install] on purpose.
837+
sudo systemctl enable --now fastcache-compile-node.socket
838+
systemctl is-active --quiet fastcache-compile-node.socket \
839+
|| { echo "::error::the socket unit did not start"; exit 1; }
840+
841+
# Nothing should be running yet -- that is the whole point of
842+
# activation. An already-active service here means the socket was
843+
# bypassed and the unit is just an ordinary daemon.
844+
systemctl is-active --quiet fastcache-compile-node \
845+
&& { echo "::error::the service started without a connection"; exit 1; }
846+
847+
# One connection activates it.
848+
timeout 10 bash -c 'exec 3<>/dev/tcp/127.0.0.1/6676' || true
849+
850+
# Waited for by its OUTPUT, not by is-active. Type=simple is reported
851+
# active the moment systemd forks, while this worker still has to walk
852+
# its toolchain's include tree to compute a fingerprint -- seconds of
853+
# real work. Polling is-active therefore answers "has it started",
854+
# which is not the question; the first version of this step asked it
855+
# and read an empty journal.
856+
for _ in $(seq 1 90); do
857+
sudo journalctl -u fastcache-compile-node --no-pager > /tmp/node-log.txt 2>/dev/null || true
858+
grep -q 'compile node ready' /tmp/node-log.txt && break
859+
sleep 1
860+
done
861+
cat /tmp/node-log.txt
862+
grep -q 'compile node ready' /tmp/node-log.txt || {
863+
echo "::error::a connection did not bring the worker up"
864+
systemctl status fastcache-compile-node --no-pager || true; exit 1; }
865+
866+
# It must have ADOPTED the socket rather than bound its own. Binding
867+
# would have failed against the socket unit already holding the port,
868+
# so a running service that did not adopt is a service listening
869+
# somewhere nobody was told about.
870+
grep -q 'adopted a socket-activated listener' /tmp/node-log.txt \
871+
|| { echo "::error::the worker did not adopt the activated socket"; exit 1; }
872+
873+
test "$(systemctl show -p User --value fastcache-compile-node)" = fastcache-node
874+
875+
# The stop path, on real systemd and on an ADOPTED descriptor. This is
876+
# the assertion that matters most here: POSIX does not unblock a parked
877+
# accept() when the listener is closed, so a worker without a receive
878+
# timeout hangs until systemd escalates to SIGKILL -- and that bug has
879+
# already shipped once, on the ordinary bind path. `Result=success`
880+
# distinguishes a clean exit from a killed one; `is-system-running`
881+
# would not.
882+
sudo systemctl stop fastcache-compile-node
883+
test "$(systemctl show -p Result --value fastcache-compile-node)" = success \
884+
|| { echo "::error::the worker did not stop cleanly"
885+
sudo journalctl -u fastcache-compile-node --no-pager; exit 1; }
886+
sudo systemctl stop fastcache-compile-node.socket
887+
806888
- name: "Verify an upgrade keeps local config edits"
807889
working-directory: out/build/gcc-release
808890
run: |
@@ -818,8 +900,13 @@ jobs:
818900
set -euo pipefail
819901
sudo apt-get purge -y fastcached
820902
test ! -e /usr/lib/systemd/system/fastcached.service
903+
test ! -e /usr/lib/systemd/system/fastcache-compile-node.service
904+
test ! -e /usr/lib/systemd/system/fastcache-compile-node.socket
821905
# A leftover wants-symlink makes systemd log a failure on every boot.
822906
test ! -e /etc/systemd/system/multi-user.target.wants/fastcached.service
907+
# The socket is the unit that gets enabled, so it is the one that
908+
# leaves a symlink behind if the postrm forgets it.
909+
test ! -e /etc/systemd/system/sockets.target.wants/fastcache-compile-node.socket
823910
824911
- name: "Upload packages"
825912
uses: actions/upload-artifact@v4
@@ -1001,15 +1088,15 @@ jobs:
10011088
-DFASTCACHED_REQUIRE_EXACT_VERSION=${{ env.FASTCACHED_REQUIRE_EXACT_VERSION }}
10021089
10031090
- name: "Build"
1004-
run: cmake --build out/build/macos-package --target fastcached fastcache-cc
1091+
run: cmake --build out/build/macos-package --target fastcached fastcache-cc fastcache-compile-node
10051092

10061093
- name: "Verify the binaries are redistributable"
10071094
# The regression that would otherwise ship silently: everything builds,
10081095
# every test passes, and the package refuses to launch on any machine
10091096
# without the build host's Homebrew prefix.
10101097
run: |
10111098
set -euo pipefail
1012-
for tool in fastcached fastcache-cc; do
1099+
for tool in fastcached fastcache-cc fastcache-compile-node; do
10131100
binary="out/build/macos-package/target/$tool"
10141101
echo "== $tool"; otool -L "$binary"
10151102
strays="$(otool -L "$binary" | tail -n +2 | awk '{print $1}' | grep -v '^/usr/lib/' || true)"
@@ -1157,7 +1244,7 @@ jobs:
11571244
run: cmake --preset cl-release -DFASTCACHED_BUILD_TESTS=OFF -DFASTCACHED_REQUIRE_EXACT_VERSION=${{ env.FASTCACHED_REQUIRE_EXACT_VERSION }}
11581245

11591246
- name: "Build"
1160-
run: cmake --build --preset cl-release --target fastcached fastcache-cc
1247+
run: cmake --build --preset cl-release --target fastcached fastcache-cc fastcache-compile-node
11611248

11621249
# On failure CPack only says "check wix.log", which lives in the build
11631250
# tree and is otherwise discarded with the runner — so the actual WiX

0 commit comments

Comments
 (0)