Stage ABI-scoped unit generations
This commit is contained in:
+28
-17
@@ -1,4 +1,5 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")"
|
||||
cd ..
|
||||
|
||||
@@ -6,11 +7,14 @@ BUILDMODE=${2:-"debug"}
|
||||
OPT_FLAG="O0"
|
||||
GF="uce_fastcgi"
|
||||
|
||||
mkdir bin > /dev/null 2>&1
|
||||
mkdir bin/tmp > /dev/null 2>&1
|
||||
mkdir bin/assets > /dev/null 2>&1
|
||||
mkdir bin/wasm > /dev/null 2>&1
|
||||
mkdir work > /dev/null 2>&1
|
||||
mkdir -p bin/tmp bin/assets bin/wasm work
|
||||
exec 9>bin/.build.lock
|
||||
flock 9
|
||||
build_tmp_files=()
|
||||
cleanup_build_tmp() {
|
||||
((${#build_tmp_files[@]} == 0)) || rm -f "${build_tmp_files[@]}"
|
||||
}
|
||||
trap cleanup_build_tmp EXIT
|
||||
|
||||
COMPILER="clang++"
|
||||
# -rdynamic is a link-time flag; the -c compiles below do not need it.
|
||||
@@ -52,13 +56,16 @@ fi
|
||||
# SQLite: vendored C, depends only on its own source (not our headers).
|
||||
if needs_rebuild bin/sqlite3.o src/3rdparty/sqlite/sqlite3.c src/3rdparty/sqlite/sqlite3.h; then
|
||||
echo "Compiling SQLite..."
|
||||
tmp="bin/sqlite3.o.tmp.$$"
|
||||
build_tmp_files+=("$tmp")
|
||||
clang -g -O2 -fPIC \
|
||||
-DSQLITE_THREADSAFE=1 \
|
||||
-DSQLITE_OMIT_LOAD_EXTENSION=1 \
|
||||
-DSQLITE_DQS=0 \
|
||||
-DSQLITE_DEFAULT_FOREIGN_KEYS=1 \
|
||||
-DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \
|
||||
-c src/3rdparty/sqlite/sqlite3.c -o bin/sqlite3.o 2>&1 || exit 1
|
||||
-c src/3rdparty/sqlite/sqlite3.c -o "$tmp" 2>&1
|
||||
mv "$tmp" bin/sqlite3.o
|
||||
else
|
||||
echo "Reusing bin/sqlite3.o"
|
||||
fi
|
||||
@@ -67,7 +74,10 @@ fi
|
||||
# declarations (not the lib .cpp — those are compiled into main.o).
|
||||
if needs_rebuild bin/wasm.o src/wasm src/lib/*.h; then
|
||||
echo "Compiling wasm backend..."
|
||||
time -p $COMPILER -c src/wasm/wasm_module.cpp $SRCFLAGS $FLAGS $WASM_FLAGS -o bin/wasm.o 2>&1 || exit 1
|
||||
tmp="bin/wasm.o.tmp.$$"
|
||||
build_tmp_files+=("$tmp")
|
||||
time -p $COMPILER -c src/wasm/wasm_module.cpp $SRCFLAGS $FLAGS $WASM_FLAGS -o "$tmp" 2>&1
|
||||
mv "$tmp" bin/wasm.o
|
||||
else
|
||||
echo "Reusing bin/wasm.o"
|
||||
fi
|
||||
@@ -77,18 +87,19 @@ fi
|
||||
# (its only view of the wasm object) — but not the wasm .cpp sources.
|
||||
if needs_rebuild bin/main.o src/linux_fastcgi.cpp src/lib src/fastcgi src/wasm/backend.h; then
|
||||
echo "Compiling main..."
|
||||
time -p $COMPILER -c src/linux_fastcgi.cpp $SRCFLAGS $FLAGS -o bin/main.o 2>&1 || exit 1
|
||||
tmp="bin/main.o.tmp.$$"
|
||||
build_tmp_files+=("$tmp")
|
||||
time -p $COMPILER -c src/linux_fastcgi.cpp $SRCFLAGS $FLAGS -o "$tmp" 2>&1
|
||||
mv "$tmp" bin/main.o
|
||||
else
|
||||
echo "Reusing bin/main.o"
|
||||
fi
|
||||
|
||||
echo "Linking..."
|
||||
$COMPILER -rdynamic bin/main.o bin/wasm.o bin/sqlite3.o $FLAGS $LIBS -o bin/$GF.linux.bin 2>&1
|
||||
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
ls -lh bin/ | grep $GF
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
binary_tmp="bin/$GF.linux.bin.tmp.$$"
|
||||
build_tmp_files+=("$binary_tmp")
|
||||
$COMPILER -rdynamic bin/main.o bin/wasm.o bin/sqlite3.o $FLAGS $LIBS -o "$binary_tmp" 2>&1
|
||||
test -s "$binary_tmp"
|
||||
chmod 0755 "$binary_tmp"
|
||||
mv "$binary_tmp" "bin/$GF.linux.bin"
|
||||
ls -lh "bin/$GF.linux.bin"
|
||||
|
||||
@@ -160,7 +160,13 @@ def defined_symbols(path: Path, llvm_nm: str) -> list[str]:
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("wasm", type=Path)
|
||||
ap.add_argument("--abi-version", default="7")
|
||||
default_abi = "7"
|
||||
abi_header = Path(__file__).resolve().parents[1] / "src" / "wasm" / "abi.h"
|
||||
for line in abi_header.read_text().splitlines():
|
||||
if line.startswith("#define UCE_WASM_CORE_ABI_VERSION "):
|
||||
default_abi = line.rsplit(" ", 1)[1]
|
||||
break
|
||||
ap.add_argument("--abi-version", default=default_abi)
|
||||
ap.add_argument("--llvm-nm", default=None)
|
||||
ap.add_argument("--verbose", action="store_true")
|
||||
args = ap.parse_args()
|
||||
|
||||
@@ -11,7 +11,7 @@ PP_FN="$4"
|
||||
WASM_FN="$5"
|
||||
|
||||
SDK=${WASI_SDK:-/opt/wasi-sdk}
|
||||
ABI_VERSION=${UCE_UNIT_ABI_VERSION:-7}
|
||||
ABI_VERSION=${UCE_UNIT_ABI_VERSION:-$(awk '/^#define UCE_WASM_CORE_ABI_VERSION / {print $3; exit}' src/wasm/abi.h)}
|
||||
ROOT=$(pwd)
|
||||
OBJ_FN="$DEST_DIR/$PP_FN.wasm.o"
|
||||
ABI_TMP="$DEST_DIR/$PP_FN.uce-abi.txt"
|
||||
|
||||
@@ -67,6 +67,7 @@ if [[ "$action" == "run" ]]; then
|
||||
curl -sS --max-time "$curl_timeout" --fail-with-body --unix-socket "$socket_path" "${base_url}&group=${group}"
|
||||
done
|
||||
scripts/test_dependency_invalidation.sh
|
||||
scripts/test_abi_generation_rollout.sh
|
||||
scripts/test_cold_component_deadline.sh
|
||||
scripts/test_nested_component_props.sh
|
||||
scripts/test_component_once_prefetch.sh
|
||||
|
||||
@@ -56,6 +56,15 @@ case "$action" in
|
||||
if [[ "$REPO_ROOT" != "/usr/lib/uce" && "$REPO_ROOT" != "/opt/uce" ]]; then
|
||||
"$REPO_ROOT/scripts/build_linux.sh"
|
||||
fi
|
||||
(
|
||||
cd "$REPO_ROOT"
|
||||
service_user=$(systemctl show "$UNIT_NAME" -p User --value)
|
||||
if [[ -n "$service_user" && "$(id -u)" == "0" ]]; then
|
||||
runuser -u "$service_user" -- "$REPO_ROOT/bin/uce_fastcgi.linux.bin" --precompile
|
||||
else
|
||||
"$REPO_ROOT/bin/uce_fastcgi.linux.bin" --precompile
|
||||
fi
|
||||
)
|
||||
systemctl restart "$UNIT_NAME"
|
||||
;;
|
||||
start|stop|status)
|
||||
|
||||
@@ -10,7 +10,7 @@ if [[ -r /etc/uce/settings.cfg ]]; then
|
||||
fi
|
||||
|
||||
for ((attempt = 0; attempt < 200; attempt++)); do
|
||||
if [[ -S "$socket_path" ]]; then
|
||||
if [[ -S "$socket_path" ]] && [[ "$(curl -sS --max-time 0.2 --unix-socket "$socket_path" http://localhost/ping 2>/dev/null || true)" == "uce-cli: ok" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
sleep 0.05
|
||||
|
||||
Executable
+101
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
test_name="abi-generation-test-$$"
|
||||
site_directory="${UCE_TEST_SITE_DIRECTORY:-site}"
|
||||
if [[ -z "${UCE_TEST_SITE_DIRECTORY:-}" && -r /etc/uce/settings.cfg ]]; then
|
||||
configured_site_directory=$(awk -F= '/^[[:space:]]*SITE_DIRECTORY[[:space:]]*=/ {gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); print $2; exit}' /etc/uce/settings.cfg)
|
||||
[[ -z "${configured_site_directory:-}" ]] || site_directory="$configured_site_directory"
|
||||
fi
|
||||
source_dir="$site_directory/$test_name"
|
||||
http_host="${UCE_TEST_HTTP_HOST:-uce.openfu.com}"
|
||||
body_file="/tmp/uce-abi-generation-body-$$"
|
||||
ready_file="/tmp/uce-abi-generation-ready-$$"
|
||||
|
||||
cleanup() {
|
||||
rm -rf "$source_dir"
|
||||
rm -f "$body_file" "$ready_file"
|
||||
[[ -z "${artifact_dir:-}" ]] || rm -rf "$artifact_dir"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
mkdir -p "$source_dir"
|
||||
|
||||
printf '%s\n' \
|
||||
'RENDER(Request& context) { print("entry-current"); }' \
|
||||
'CLI(Request& context) {' \
|
||||
' if(context.get["artifact"] == "entry") print(unit_info(context.params["SCRIPT_FILENAME"])["wasm_name"].to_string());' \
|
||||
' else print("entry-current");' \
|
||||
'}' >"$source_dir/entry.uce"
|
||||
printf '%s\n' \
|
||||
'COMPONENT(Request& context) { print("component-current"); }' >"$source_dir/child.uce"
|
||||
printf '%s\n' \
|
||||
'RENDER(Request& context) { DValue props; print(component("child", props, context)); }' \
|
||||
'CLI(Request& context) {' \
|
||||
' DValue props; component("child", props, context);' \
|
||||
' print(unit_info("child.uce")["wasm_name"].to_string());' \
|
||||
'}' >"$source_dir/component-parent.uce"
|
||||
|
||||
entry_url="http://127.0.0.1/$test_name/entry.uce"
|
||||
component_url="http://127.0.0.1/$test_name/component-parent.uce"
|
||||
[[ "$(curl -fsS -H "Host: $http_host" "$entry_url")" == "entry-current" ]]
|
||||
entry_wasm=$(scripts/uce-cli --get "/$test_name/entry.uce" artifact=entry)
|
||||
component_wasm=$(scripts/uce-cli "/$test_name/component-parent.uce")
|
||||
artifact_dir=$(dirname "$entry_wasm")
|
||||
generation_name=$(basename "$(scripts/unit_cache_directory /tmp/uce-generation-probe)")
|
||||
if [[ "$entry_wasm" != *"/$generation_name/"* || "$component_wasm" != *"/$generation_name/"* ]]; then
|
||||
echo "unit artifacts are not isolated by compiler/core ABI generation: $entry_wasm $component_wasm" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
publish_incompatible_artifact_while_locked() {
|
||||
local source_file="$1"
|
||||
local wasm_file="$2"
|
||||
local marker="$3"
|
||||
local destination
|
||||
destination=$(dirname "$wasm_file")
|
||||
(
|
||||
exec 8>"$wasm_file.lock"
|
||||
flock 8
|
||||
UCE_UNIT_ABI_VERSION=6 scripts/compile_wasm_unit \
|
||||
"$(dirname "$source_file")" "$destination" "$source_file" \
|
||||
"$(basename "$source_file").cpp" "$(basename "$wasm_file")"
|
||||
sed -i \
|
||||
-e 's/^unit_abi_version=.*/unit_abi_version=0/' \
|
||||
-e 's/^wasm_core_abi_version=.*/wasm_core_abi_version=0/' \
|
||||
"${wasm_file%.wasm}.meta.txt"
|
||||
rm -f "${wasm_file%.wasm}.cwasm"
|
||||
printf '%s\n' "$marker" >"$ready_file"
|
||||
sleep 2
|
||||
) &
|
||||
lock_pid=$!
|
||||
deadline=$((SECONDS + 20))
|
||||
while [[ ! -e "$ready_file" && $SECONDS -lt $deadline ]]; do sleep 0.05; done
|
||||
if [[ ! -e "$ready_file" || "$(cat "$ready_file")" != "$marker" ]]; then
|
||||
echo "incompatible artifact was not published under lock: $marker" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
publish_incompatible_artifact_while_locked "$source_dir/entry.uce" "$entry_wasm" entry
|
||||
started_at=$(date +%s%N)
|
||||
entry_status=$(curl -sS --max-time 30 -o "$body_file" -w '%{http_code}' -H "Host: $http_host" "$entry_url")
|
||||
entry_elapsed_ms=$(( ($(date +%s%N) - started_at) / 1000000 ))
|
||||
wait "$lock_pid"
|
||||
if [[ "$entry_status" != "200" || "$(cat "$body_file")" != "entry-current" || $entry_elapsed_ms -lt 1500 ]]; then
|
||||
echo "ABI-incompatible entry artifact was served instead of joining its rebuild: status=$entry_status elapsed=${entry_elapsed_ms}ms body=$(cat "$body_file")" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -f "$ready_file"
|
||||
publish_incompatible_artifact_while_locked "$source_dir/child.uce" "$component_wasm" component
|
||||
started_at=$(date +%s%N)
|
||||
component_status=$(curl -sS --max-time 30 -o "$body_file" -w '%{http_code}' -H "Host: $http_host" "$component_url")
|
||||
component_elapsed_ms=$(( ($(date +%s%N) - started_at) / 1000000 ))
|
||||
wait "$lock_pid"
|
||||
if [[ "$component_status" != "200" || "$(cat "$body_file")" != "component-current" || $component_elapsed_ms -lt 1500 ]]; then
|
||||
echo "ABI-incompatible component artifact was served instead of joining its rebuild: status=$component_status elapsed=${component_elapsed_ms}ms body=$(cat "$body_file")" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "ABI generation rollout passed"
|
||||
@@ -26,7 +26,7 @@ cleanup() {
|
||||
}
|
||||
trap cleanup EXIT
|
||||
mkdir -p "$source_dir"
|
||||
cache_dir="$bin_directory$(realpath "$source_dir")"
|
||||
cache_dir="$(scripts/unit_cache_directory "$bin_directory")$(realpath "$source_dir")"
|
||||
|
||||
printf '%s\n' \
|
||||
'CLI(Request& context) { DValue props; print(component("child", props, context)); }' >"$source_dir/parent.uce"
|
||||
|
||||
@@ -40,7 +40,7 @@ cleanup() {
|
||||
}
|
||||
trap cleanup EXIT
|
||||
mkdir -p "$source_dir"
|
||||
cache_dir="$bin_directory$(realpath "$source_dir")"
|
||||
cache_dir="$(scripts/unit_cache_directory "$bin_directory")$(realpath "$source_dir")"
|
||||
|
||||
printf '%s\n' \
|
||||
'#ifndef UCE_DEPENDENCY_CACHE_CHILD' \
|
||||
|
||||
@@ -26,7 +26,7 @@ cleanup() {
|
||||
}
|
||||
trap cleanup EXIT
|
||||
mkdir -p "$source_dir"
|
||||
cache_dir="$bin_directory$(realpath "$source_dir")"
|
||||
cache_dir="$(scripts/unit_cache_directory "$bin_directory")$(realpath "$source_dir")"
|
||||
|
||||
printf '%s\n' 'CLI(Request& context) { deliberate_log_timeliness_compile_failure }' >"$source_dir/probe.uce"
|
||||
rm -rf "$cache_dir"
|
||||
|
||||
@@ -38,7 +38,7 @@ cleanup() {
|
||||
}
|
||||
trap cleanup EXIT
|
||||
mkdir -p "$source_dir"
|
||||
cache_dir="$bin_directory$(realpath "$source_dir")"
|
||||
cache_dir="$(scripts/unit_cache_directory "$bin_directory")$(realpath "$source_dir")"
|
||||
mariadb -e "DROP USER IF EXISTS '$test_user'@'127.0.0.1'; CREATE USER '$test_user'@'127.0.0.1' IDENTIFIED BY '$test_password'"
|
||||
test_user_created=true
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ cleanup() {
|
||||
}
|
||||
trap cleanup EXIT
|
||||
mkdir -p "$source_dir"
|
||||
cache_dir="$bin_directory$(realpath "$source_dir")"
|
||||
cache_dir="$(scripts/unit_cache_directory "$bin_directory")$(realpath "$source_dir")"
|
||||
mariadb -e "DROP DATABASE IF EXISTS \`$test_database\`; DROP DATABASE IF EXISTS \`$test_database_other\`; DROP USER IF EXISTS '$test_user'@'127.0.0.1'; CREATE DATABASE \`$test_database\`; CREATE DATABASE \`$test_database_other\`; CREATE USER '$test_user'@'127.0.0.1' IDENTIFIED BY '$test_password'; GRANT ALL ON \`$test_database\`.* TO '$test_user'@'127.0.0.1'; GRANT ALL ON \`$test_database_other\`.* TO '$test_user'@'127.0.0.1'; CREATE TABLE \`$test_database\`.pool_identity (label VARCHAR(16) NOT NULL); INSERT INTO \`$test_database\`.pool_identity VALUES ('primary'); CREATE TABLE \`$test_database_other\`.pool_identity (label VARCHAR(16) NOT NULL); INSERT INTO \`$test_database_other\`.pool_identity VALUES ('other')"
|
||||
|
||||
printf '%s\n' \
|
||||
|
||||
@@ -26,7 +26,7 @@ cleanup() {
|
||||
}
|
||||
trap cleanup EXIT
|
||||
mkdir -p "$source_dir"
|
||||
cache_dir="$bin_directory$(realpath "$source_dir")"
|
||||
cache_dir="$(scripts/unit_cache_directory "$bin_directory")$(realpath "$source_dir")"
|
||||
|
||||
printf '%s\n' \
|
||||
'CLI(Request& context) {' \
|
||||
|
||||
@@ -27,7 +27,7 @@ cleanup() {
|
||||
trap cleanup EXIT
|
||||
mkdir -p "$source_dir"
|
||||
absolute_source_dir=$(realpath "$source_dir")
|
||||
artifact_dir="$bin_directory$absolute_source_dir"
|
||||
artifact_dir="$(scripts/unit_cache_directory "$bin_directory")$absolute_source_dir"
|
||||
|
||||
printf '%s\n' \
|
||||
'String visibility_used() { return("private-used"); }' \
|
||||
|
||||
@@ -22,7 +22,7 @@ cleanup() {
|
||||
trap cleanup EXIT
|
||||
mkdir -p "$source_dir"
|
||||
absolute_source_dir=$(realpath "$source_dir")
|
||||
artifact_dir="$bin_directory$absolute_source_dir"
|
||||
artifact_dir="$(scripts/unit_cache_directory "$bin_directory")$absolute_source_dir"
|
||||
printf '%s\n' 'CLI(Request& context) { __builtin_trap(); }' >"$source_dir/entry.uce"
|
||||
|
||||
set +e
|
||||
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
base="${1:-/tmp/uce/work}"
|
||||
compiler_abi=$(awk '/^#define UCE_COMPILER_UNIT_ABI_VERSION / {print $3; exit}' src/wasm/abi.h)
|
||||
core_abi=$(awk '/^#define UCE_WASM_CORE_ABI_VERSION / {print $3; exit}' src/wasm/abi.h)
|
||||
printf '%s/units-c%s-w%s\n' "${base%/}" "$compiler_abi" "$core_abi"
|
||||
Reference in New Issue
Block a user