Stage ABI-scoped unit generations
This commit is contained in:
+11
-2
@@ -215,7 +215,9 @@ Important settings:
|
|||||||
- `FCGI_SOCKET_MODE` and `CLI_SOCKET_MODE` are octal permission modes applied after socket bind. Prefer tightening `FCGI_SOCKET_MODE` to `0660` when nginx/Apache can share a trusted group with the UCE worker.
|
- `FCGI_SOCKET_MODE` and `CLI_SOCKET_MODE` are octal permission modes applied after socket bind. Prefer tightening `FCGI_SOCKET_MODE` to `0660` when nginx/Apache can share a trusted group with the UCE worker.
|
||||||
- `SITE_DIRECTORY` is the public site tree to scan for `.uce` files. Use `/var/www/html` when the web root is outside the runtime tree; relative paths are resolved from the runtime working directory. Installed regression gate scripts derive their temporary test root from this setting unless `UCE_TEST_SITE_DIRECTORY` is explicitly provided.
|
- `SITE_DIRECTORY` is the public site tree to scan for `.uce` files. Use `/var/www/html` when the web root is outside the runtime tree; relative paths are resolved from the runtime working directory. Installed regression gate scripts derive their temporary test root from this setting unless `UCE_TEST_SITE_DIRECTORY` is explicitly provided.
|
||||||
- `HTTP_DOCUMENT_ROOT` is the root used by the built-in HTTP/WebSocket listener when it resolves upgrade requests. Set it to the same web root as nginx/Apache.
|
- `HTTP_DOCUMENT_ROOT` is the root used by the built-in HTTP/WebSocket listener when it resolves upgrade requests. Set it to the same web root as nginx/Apache.
|
||||||
- `BIN_DIRECTORY` stores generated C++, wasm artifacts, compile output, and runtime caches.
|
- `BIN_DIRECTORY` stores runtime state plus ABI-scoped unit generations. Unit
|
||||||
|
C++, wasm, serialized modules, source maps, and compile diagnostics live in
|
||||||
|
`units-c<compiler ABI>-w<core ABI>` so an upgrade cannot mix generations.
|
||||||
- `TMP_UPLOAD_PATH` and `SESSION_PATH` must be writable by the runtime.
|
- `TMP_UPLOAD_PATH` and `SESSION_PATH` must be writable by the runtime.
|
||||||
- `SESSION_COOKIE_SECURE=1` adds the `Secure` attribute to UCE-managed session cookies and should be used for HTTPS-only deployments. Leave it `0` only for local/plain-HTTP development.
|
- `SESSION_COOKIE_SECURE=1` adds the `Secure` attribute to UCE-managed session cookies and should be used for HTTPS-only deployments. Leave it `0` only for local/plain-HTTP development.
|
||||||
- `MYSQL_PERSISTENT_POOL_SIZE` caps credential-keyed connections retained by each Wasm worker. The default `8` is clamped to `64`; set it to `0` to restore request-lifetime connections. Cached sessions are reset before reuse.
|
- `MYSQL_PERSISTENT_POOL_SIZE` caps credential-keyed connections retained by each Wasm worker. The default `8` is clamped to `64`; set it to `0` to restore request-lifetime connections. Cached sessions are reset before reuse.
|
||||||
@@ -697,7 +699,14 @@ Common compile footguns:
|
|||||||
- `WASMTIME_HOME` does not point at a tree with Wasmtime headers and `libwasmtime.so`.
|
- `WASMTIME_HOME` does not point at a tree with Wasmtime headers and `libwasmtime.so`.
|
||||||
- A previous failed compile left stale `.compile.txt`, `.wasm-check.txt`, or partial `.wasm` files under `BIN_DIRECTORY`.
|
- A previous failed compile left stale `.compile.txt`, `.wasm-check.txt`, or partial `.wasm` files under `BIN_DIRECTORY`.
|
||||||
|
|
||||||
Failed compile output is persisted under the unit's generated path in `BIN_DIRECTORY` and may be reused until the source or compiler inputs change. First fix the source/toolchain issue and reload the page. If the cache itself is suspect, stop UCE, move only the affected unit artifact files or directory aside, and restart so the runtime recompiles from source. Avoid deleting the whole `BIN_DIRECTORY` unless you intentionally want a full rebuild.
|
Failed compile output is persisted under the unit's ABI-generation path in
|
||||||
|
`BIN_DIRECTORY` and may be reused until the source or compiler inputs change.
|
||||||
|
The managed `restart` command first runs the new binary's `--precompile` mode as
|
||||||
|
the configured service user while the old service remains live. It restarts
|
||||||
|
systemd only after every scanned unit compiles and serializes successfully.
|
||||||
|
First fix source/toolchain failures and retry; do not remove the prior generation,
|
||||||
|
which remains the rollback path. Avoid deleting the whole `BIN_DIRECTORY` unless
|
||||||
|
you intentionally want a full rebuild and have accepted losing rollback artifacts.
|
||||||
|
|
||||||
### CLI commands fail
|
### CLI commands fail
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,9 @@ Treat WASI SDK upgrades like runtime dependency upgrades:
|
|||||||
2. Record the new release and checksum here.
|
2. Record the new release and checksum here.
|
||||||
3. Rebuild `bin/wasm/core.wasm` with `scripts/build_core_wasm.sh`.
|
3. Rebuild `bin/wasm/core.wasm` with `scripts/build_core_wasm.sh`.
|
||||||
4. Rebuild the native runtime with `scripts/build_linux.sh`.
|
4. Rebuild the native runtime with `scripts/build_linux.sh`.
|
||||||
5. Clear or invalidate stale unit wasm artifacts by bumping `UCE_UNIT_ABI_VERSION` when required, or by removing affected generated artifacts under `BIN_DIRECTORY`.
|
5. Bump the compiler or core ABI constant in `src/wasm/abi.h` when required.
|
||||||
|
The managed restart precompiles the resulting isolated unit generation before
|
||||||
|
switching workers; do not overwrite or delete the previous generation.
|
||||||
6. Run the full CLI suite including wasm kill tests:
|
6. Run the full CLI suite including wasm kill tests:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -232,6 +232,14 @@ refreshes the epoch deadline before its first guest call. Otherwise a component
|
|||||||
whose compilation outlasted the guest CPU budget would immediately trap in the
|
whose compilation outlasted the guest CPU budget would immediately trap in the
|
||||||
following allocator/relocation call even though no guest loop consumed it.
|
following allocator/relocation call even though no guest loop consumed it.
|
||||||
|
|
||||||
|
Unit artifacts live beneath an ABI-generation directory such as
|
||||||
|
`BIN_DIRECTORY/units-c12-w7`: `c12` is the compiler/unit-metadata ABI and `w7`
|
||||||
|
is the runtime core ABI. Old and new service binaries therefore never publish
|
||||||
|
or read the same unit path during an ABI transition. The managed restart builds
|
||||||
|
and serializes the complete next generation before stopping the old service;
|
||||||
|
failure aborts the switch and leaves the running generation intact. Old
|
||||||
|
generation directories are retained as an explicit rollback path.
|
||||||
|
|
||||||
The proactive compiler and request workers coordinate through per-unit file
|
The proactive compiler and request workers coordinate through per-unit file
|
||||||
locks and a lock-protected demand-priority queue under `BIN_DIRECTORY`. A small
|
locks and a lock-protected demand-priority queue under `BIN_DIRECTORY`. A small
|
||||||
priority-only compiler process drains that queue independently of the full-site
|
priority-only compiler process drains that queue independently of the full-site
|
||||||
|
|||||||
+28
-17
@@ -1,4 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
cd "$(dirname "$0")"
|
cd "$(dirname "$0")"
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
@@ -6,11 +7,14 @@ BUILDMODE=${2:-"debug"}
|
|||||||
OPT_FLAG="O0"
|
OPT_FLAG="O0"
|
||||||
GF="uce_fastcgi"
|
GF="uce_fastcgi"
|
||||||
|
|
||||||
mkdir bin > /dev/null 2>&1
|
mkdir -p bin/tmp bin/assets bin/wasm work
|
||||||
mkdir bin/tmp > /dev/null 2>&1
|
exec 9>bin/.build.lock
|
||||||
mkdir bin/assets > /dev/null 2>&1
|
flock 9
|
||||||
mkdir bin/wasm > /dev/null 2>&1
|
build_tmp_files=()
|
||||||
mkdir work > /dev/null 2>&1
|
cleanup_build_tmp() {
|
||||||
|
((${#build_tmp_files[@]} == 0)) || rm -f "${build_tmp_files[@]}"
|
||||||
|
}
|
||||||
|
trap cleanup_build_tmp EXIT
|
||||||
|
|
||||||
COMPILER="clang++"
|
COMPILER="clang++"
|
||||||
# -rdynamic is a link-time flag; the -c compiles below do not need it.
|
# -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).
|
# 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
|
if needs_rebuild bin/sqlite3.o src/3rdparty/sqlite/sqlite3.c src/3rdparty/sqlite/sqlite3.h; then
|
||||||
echo "Compiling SQLite..."
|
echo "Compiling SQLite..."
|
||||||
|
tmp="bin/sqlite3.o.tmp.$$"
|
||||||
|
build_tmp_files+=("$tmp")
|
||||||
clang -g -O2 -fPIC \
|
clang -g -O2 -fPIC \
|
||||||
-DSQLITE_THREADSAFE=1 \
|
-DSQLITE_THREADSAFE=1 \
|
||||||
-DSQLITE_OMIT_LOAD_EXTENSION=1 \
|
-DSQLITE_OMIT_LOAD_EXTENSION=1 \
|
||||||
-DSQLITE_DQS=0 \
|
-DSQLITE_DQS=0 \
|
||||||
-DSQLITE_DEFAULT_FOREIGN_KEYS=1 \
|
-DSQLITE_DEFAULT_FOREIGN_KEYS=1 \
|
||||||
-DSQLITE_DEFAULT_WAL_SYNCHRONOUS=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
|
else
|
||||||
echo "Reusing bin/sqlite3.o"
|
echo "Reusing bin/sqlite3.o"
|
||||||
fi
|
fi
|
||||||
@@ -67,7 +74,10 @@ fi
|
|||||||
# declarations (not the lib .cpp — those are compiled into main.o).
|
# declarations (not the lib .cpp — those are compiled into main.o).
|
||||||
if needs_rebuild bin/wasm.o src/wasm src/lib/*.h; then
|
if needs_rebuild bin/wasm.o src/wasm src/lib/*.h; then
|
||||||
echo "Compiling wasm backend..."
|
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
|
else
|
||||||
echo "Reusing bin/wasm.o"
|
echo "Reusing bin/wasm.o"
|
||||||
fi
|
fi
|
||||||
@@ -77,18 +87,19 @@ fi
|
|||||||
# (its only view of the wasm object) — but not the wasm .cpp sources.
|
# (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
|
if needs_rebuild bin/main.o src/linux_fastcgi.cpp src/lib src/fastcgi src/wasm/backend.h; then
|
||||||
echo "Compiling main..."
|
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
|
else
|
||||||
echo "Reusing bin/main.o"
|
echo "Reusing bin/main.o"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Linking..."
|
echo "Linking..."
|
||||||
$COMPILER -rdynamic bin/main.o bin/wasm.o bin/sqlite3.o $FLAGS $LIBS -o bin/$GF.linux.bin 2>&1
|
binary_tmp="bin/$GF.linux.bin.tmp.$$"
|
||||||
|
build_tmp_files+=("$binary_tmp")
|
||||||
if [ $? -eq 0 ]
|
$COMPILER -rdynamic bin/main.o bin/wasm.o bin/sqlite3.o $FLAGS $LIBS -o "$binary_tmp" 2>&1
|
||||||
then
|
test -s "$binary_tmp"
|
||||||
ls -lh bin/ | grep $GF
|
chmod 0755 "$binary_tmp"
|
||||||
exit 0
|
mv "$binary_tmp" "bin/$GF.linux.bin"
|
||||||
else
|
ls -lh "bin/$GF.linux.bin"
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|||||||
@@ -160,7 +160,13 @@ def defined_symbols(path: Path, llvm_nm: str) -> list[str]:
|
|||||||
def main() -> int:
|
def main() -> int:
|
||||||
ap = argparse.ArgumentParser()
|
ap = argparse.ArgumentParser()
|
||||||
ap.add_argument("wasm", type=Path)
|
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("--llvm-nm", default=None)
|
||||||
ap.add_argument("--verbose", action="store_true")
|
ap.add_argument("--verbose", action="store_true")
|
||||||
args = ap.parse_args()
|
args = ap.parse_args()
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ PP_FN="$4"
|
|||||||
WASM_FN="$5"
|
WASM_FN="$5"
|
||||||
|
|
||||||
SDK=${WASI_SDK:-/opt/wasi-sdk}
|
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)
|
ROOT=$(pwd)
|
||||||
OBJ_FN="$DEST_DIR/$PP_FN.wasm.o"
|
OBJ_FN="$DEST_DIR/$PP_FN.wasm.o"
|
||||||
ABI_TMP="$DEST_DIR/$PP_FN.uce-abi.txt"
|
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}"
|
curl -sS --max-time "$curl_timeout" --fail-with-body --unix-socket "$socket_path" "${base_url}&group=${group}"
|
||||||
done
|
done
|
||||||
scripts/test_dependency_invalidation.sh
|
scripts/test_dependency_invalidation.sh
|
||||||
|
scripts/test_abi_generation_rollout.sh
|
||||||
scripts/test_cold_component_deadline.sh
|
scripts/test_cold_component_deadline.sh
|
||||||
scripts/test_nested_component_props.sh
|
scripts/test_nested_component_props.sh
|
||||||
scripts/test_component_once_prefetch.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
|
if [[ "$REPO_ROOT" != "/usr/lib/uce" && "$REPO_ROOT" != "/opt/uce" ]]; then
|
||||||
"$REPO_ROOT/scripts/build_linux.sh"
|
"$REPO_ROOT/scripts/build_linux.sh"
|
||||||
fi
|
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"
|
systemctl restart "$UNIT_NAME"
|
||||||
;;
|
;;
|
||||||
start|stop|status)
|
start|stop|status)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ if [[ -r /etc/uce/settings.cfg ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
for ((attempt = 0; attempt < 200; attempt++)); do
|
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
|
exit 0
|
||||||
fi
|
fi
|
||||||
sleep 0.05
|
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
|
trap cleanup EXIT
|
||||||
mkdir -p "$source_dir"
|
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' \
|
printf '%s\n' \
|
||||||
'CLI(Request& context) { DValue props; print(component("child", props, context)); }' >"$source_dir/parent.uce"
|
'CLI(Request& context) { DValue props; print(component("child", props, context)); }' >"$source_dir/parent.uce"
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ cleanup() {
|
|||||||
}
|
}
|
||||||
trap cleanup EXIT
|
trap cleanup EXIT
|
||||||
mkdir -p "$source_dir"
|
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' \
|
printf '%s\n' \
|
||||||
'#ifndef UCE_DEPENDENCY_CACHE_CHILD' \
|
'#ifndef UCE_DEPENDENCY_CACHE_CHILD' \
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ cleanup() {
|
|||||||
}
|
}
|
||||||
trap cleanup EXIT
|
trap cleanup EXIT
|
||||||
mkdir -p "$source_dir"
|
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"
|
printf '%s\n' 'CLI(Request& context) { deliberate_log_timeliness_compile_failure }' >"$source_dir/probe.uce"
|
||||||
rm -rf "$cache_dir"
|
rm -rf "$cache_dir"
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ cleanup() {
|
|||||||
}
|
}
|
||||||
trap cleanup EXIT
|
trap cleanup EXIT
|
||||||
mkdir -p "$source_dir"
|
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'"
|
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
|
test_user_created=true
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ cleanup() {
|
|||||||
}
|
}
|
||||||
trap cleanup EXIT
|
trap cleanup EXIT
|
||||||
mkdir -p "$source_dir"
|
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')"
|
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' \
|
printf '%s\n' \
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ cleanup() {
|
|||||||
}
|
}
|
||||||
trap cleanup EXIT
|
trap cleanup EXIT
|
||||||
mkdir -p "$source_dir"
|
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' \
|
printf '%s\n' \
|
||||||
'CLI(Request& context) {' \
|
'CLI(Request& context) {' \
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ cleanup() {
|
|||||||
trap cleanup EXIT
|
trap cleanup EXIT
|
||||||
mkdir -p "$source_dir"
|
mkdir -p "$source_dir"
|
||||||
absolute_source_dir=$(realpath "$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' \
|
printf '%s\n' \
|
||||||
'String visibility_used() { return("private-used"); }' \
|
'String visibility_used() { return("private-used"); }' \
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ cleanup() {
|
|||||||
trap cleanup EXIT
|
trap cleanup EXIT
|
||||||
mkdir -p "$source_dir"
|
mkdir -p "$source_dir"
|
||||||
absolute_source_dir=$(realpath "$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"
|
printf '%s\n' 'CLI(Request& context) { __builtin_trap(); }' >"$source_dir/entry.uce"
|
||||||
|
|
||||||
set +e
|
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"
|
||||||
+60
-10
@@ -1,6 +1,7 @@
|
|||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
#include "compiler-parser.h"
|
#include "compiler-parser.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
|
#include "../wasm/abi.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
@@ -16,7 +17,7 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const u64 UCE_UNIT_ABI_VERSION = 11;
|
const u64 UCE_UNIT_ABI_VERSION = UCE_COMPILER_UNIT_ABI_VERSION;
|
||||||
|
|
||||||
struct SharedUnitFilesystemState
|
struct SharedUnitFilesystemState
|
||||||
{
|
{
|
||||||
@@ -35,6 +36,8 @@ struct SharedUnitFilesystemState
|
|||||||
time_t required_time = 0;
|
time_t required_time = 0;
|
||||||
u64 metadata_abi_version = 0;
|
u64 metadata_abi_version = 0;
|
||||||
u64 runtime_abi_version = UCE_UNIT_ABI_VERSION;
|
u64 runtime_abi_version = UCE_UNIT_ABI_VERSION;
|
||||||
|
u64 metadata_wasm_core_abi_version = 0;
|
||||||
|
u64 runtime_wasm_core_abi_version = UCE_WASM_CORE_ABI_VERSION;
|
||||||
String metadata_content;
|
String metadata_content;
|
||||||
String compile_output_content;
|
String compile_output_content;
|
||||||
String metadata_build_token;
|
String metadata_build_token;
|
||||||
@@ -262,7 +265,8 @@ String compiler_unit_input_signature(Request* context, SharedUnit* su, bool allo
|
|||||||
return(
|
return(
|
||||||
compiler_unit_source_signature(su->file_name, allow_recent_source_stat) + ":" +
|
compiler_unit_source_signature(su->file_name, allow_recent_source_stat) + ":" +
|
||||||
gen_sha1(file_get_contents(setup_template)) + ":" +
|
gen_sha1(file_get_contents(setup_template)) + ":" +
|
||||||
std::to_string(UCE_UNIT_ABI_VERSION)
|
std::to_string(UCE_UNIT_ABI_VERSION) + ":" +
|
||||||
|
std::to_string(UCE_WASM_CORE_ABI_VERSION)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,6 +285,7 @@ String compiler_unit_metadata_text(Request* context, SharedUnit* su, String inpu
|
|||||||
return(
|
return(
|
||||||
"format=uce-unit-metadata-v1\n"
|
"format=uce-unit-metadata-v1\n"
|
||||||
"unit_abi_version=" + std::to_string(UCE_UNIT_ABI_VERSION) + "\n"
|
"unit_abi_version=" + std::to_string(UCE_UNIT_ABI_VERSION) + "\n"
|
||||||
|
"wasm_core_abi_version=" + std::to_string(UCE_WASM_CORE_ABI_VERSION) + "\n"
|
||||||
"source_path=" + su->file_name + "\n"
|
"source_path=" + su->file_name + "\n"
|
||||||
"input_signature=" + input_signature + "\n"
|
"input_signature=" + input_signature + "\n"
|
||||||
"build_token=" + compiler_unit_build_token() + "\n"
|
"build_token=" + compiler_unit_build_token() + "\n"
|
||||||
@@ -387,7 +392,7 @@ time_t compiler_runtime_abi_time(Request* context)
|
|||||||
|
|
||||||
String compiler_registry_file_name(Request* context)
|
String compiler_registry_file_name(Request* context)
|
||||||
{
|
{
|
||||||
return(context->server->config["BIN_DIRECTORY"] + "/known-uce-files.txt");
|
return(compiler_unit_bin_directory(context) + "/known-uce-files.txt");
|
||||||
}
|
}
|
||||||
|
|
||||||
String compiler_registry_lock_file_name(Request* context)
|
String compiler_registry_lock_file_name(Request* context)
|
||||||
@@ -397,12 +402,12 @@ String compiler_registry_lock_file_name(Request* context)
|
|||||||
|
|
||||||
String compiler_priority_file_name(Request* context)
|
String compiler_priority_file_name(Request* context)
|
||||||
{
|
{
|
||||||
return(context->server->config["BIN_DIRECTORY"] + "/proactive-priority.txt");
|
return(compiler_unit_bin_directory(context) + "/proactive-priority.txt");
|
||||||
}
|
}
|
||||||
|
|
||||||
String compiler_source_generation_file_name(Request* context)
|
String compiler_source_generation_file_name(Request* context)
|
||||||
{
|
{
|
||||||
return(context->server->config["BIN_DIRECTORY"] + "/source-generation.txt");
|
return(compiler_unit_bin_directory(context) + "/source-generation.txt");
|
||||||
}
|
}
|
||||||
|
|
||||||
int compiler_open_lock_file(String file_name, String purpose, bool nonblocking = false)
|
int compiler_open_lock_file(String file_name, String purpose, bool nonblocking = false)
|
||||||
@@ -553,6 +558,9 @@ SharedUnitFilesystemState inspect_shared_unit_filesystem(Request* context, Share
|
|||||||
auto input_it = metadata.find("input_signature");
|
auto input_it = metadata.find("input_signature");
|
||||||
if(input_it != metadata.end())
|
if(input_it != metadata.end())
|
||||||
state.metadata_input_signature = input_it->second;
|
state.metadata_input_signature = input_it->second;
|
||||||
|
auto core_abi_it = metadata.find("wasm_core_abi_version");
|
||||||
|
if(core_abi_it != metadata.end() && compiler_is_u64_string(core_abi_it->second))
|
||||||
|
state.metadata_wasm_core_abi_version = (u64)atoll(core_abi_it->second.c_str());
|
||||||
auto source_it = metadata.find("source_path");
|
auto source_it = metadata.find("source_path");
|
||||||
if(source_it != metadata.end())
|
if(source_it != metadata.end())
|
||||||
state.metadata_source_path = source_it->second;
|
state.metadata_source_path = source_it->second;
|
||||||
@@ -562,7 +570,11 @@ SharedUnitFilesystemState inspect_shared_unit_filesystem(Request* context, Share
|
|||||||
}
|
}
|
||||||
if(state.compile_output_exists)
|
if(state.compile_output_exists)
|
||||||
state.compile_output_content = file_get_contents(su->compile_output_file_name);
|
state.compile_output_content = file_get_contents(su->compile_output_file_name);
|
||||||
state.abi_compatible = (state.metadata_parsed && state.metadata_abi_version == state.runtime_abi_version);
|
state.abi_compatible = (
|
||||||
|
state.metadata_parsed &&
|
||||||
|
state.metadata_abi_version == state.runtime_abi_version &&
|
||||||
|
state.metadata_wasm_core_abi_version == state.runtime_wasm_core_abi_version
|
||||||
|
);
|
||||||
state.input_signature_matches = (
|
state.input_signature_matches = (
|
||||||
state.metadata_parsed &&
|
state.metadata_parsed &&
|
||||||
state.metadata_input_signature != "" &&
|
state.metadata_input_signature != "" &&
|
||||||
@@ -791,7 +803,23 @@ String compiler_generated_cpp_path(Request* context, String source_file)
|
|||||||
{
|
{
|
||||||
if(!context || !context->server || source_file == "")
|
if(!context || !context->server || source_file == "")
|
||||||
return("");
|
return("");
|
||||||
return(context->server->config["BIN_DIRECTORY"] + dirname(source_file) + "/" + basename(source_file) + ".cpp");
|
return(compiler_unit_bin_directory(context) + dirname(source_file) + "/" + basename(source_file) + ".cpp");
|
||||||
|
}
|
||||||
|
|
||||||
|
String compiler_unit_bin_directory(Request* context)
|
||||||
|
{
|
||||||
|
if(!context || !context->server)
|
||||||
|
return("");
|
||||||
|
return(path_join(
|
||||||
|
context->server->config["BIN_DIRECTORY"],
|
||||||
|
"units-c" + std::to_string(UCE_UNIT_ABI_VERSION) +
|
||||||
|
"-w" + std::to_string(UCE_WASM_CORE_ABI_VERSION)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
String compiler_unit_wasm_path(Request* context, String source_file)
|
||||||
|
{
|
||||||
|
return(compiler_unit_bin_directory(context) + source_file + ".wasm");
|
||||||
}
|
}
|
||||||
|
|
||||||
String compiler_generated_cpp_path(SharedUnit* su)
|
String compiler_generated_cpp_path(SharedUnit* su)
|
||||||
@@ -809,8 +837,8 @@ void setup_unit_paths(Request* context, SharedUnit* su, String file_name)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
su->src_path = dirname(file_name);
|
su->src_path = dirname(file_name);
|
||||||
su->bin_path = context->server->config["BIN_DIRECTORY"] + su->src_path;
|
su->bin_path = compiler_unit_bin_directory(context) + su->src_path;
|
||||||
su->pre_path = context->server->config["BIN_DIRECTORY"] + su->src_path;
|
su->pre_path = compiler_unit_bin_directory(context) + su->src_path;
|
||||||
|
|
||||||
su->src_file_name = basename(file_name);
|
su->src_file_name = basename(file_name);
|
||||||
su->wasm_file_name = su->src_file_name + ".wasm";
|
su->wasm_file_name = su->src_file_name + ".wasm";
|
||||||
@@ -1023,7 +1051,7 @@ SharedUnit* compiler_get_shared_unit_internal(Request* context, String file_name
|
|||||||
SharedUnit* su = new SharedUnit();
|
SharedUnit* su = new SharedUnit();
|
||||||
setup_unit_paths(context, su, file_name);
|
setup_unit_paths(context, su, file_name);
|
||||||
|
|
||||||
bool can_serve_stale = !force_recompile && compiler_request_can_serve_stale_artifact(context);
|
bool can_serve_stale = !force_recompile && compiler_unit_can_serve_stale_artifact(context, file_name);
|
||||||
int fdlock = compiler_open_lock_file(su->wasm_name + ".lock", "shared-unit:" + file_name, can_serve_stale);
|
int fdlock = compiler_open_lock_file(su->wasm_name + ".lock", "shared-unit:" + file_name, can_serve_stale);
|
||||||
if(fdlock == -2 && file_exists(su->wasm_name))
|
if(fdlock == -2 && file_exists(su->wasm_name))
|
||||||
{
|
{
|
||||||
@@ -1178,6 +1206,26 @@ bool compiler_request_can_serve_stale_artifact(Request* context)
|
|||||||
float_val(context->server->config["PROACTIVE_COMPILE_CHECK_INTERVAL"]) > 0);
|
float_val(context->server->config["PROACTIVE_COMPILE_CHECK_INTERVAL"]) > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool compiler_unit_can_serve_stale_artifact(Request* context, String file_name)
|
||||||
|
{
|
||||||
|
if(!compiler_request_can_serve_stale_artifact(context))
|
||||||
|
return(false);
|
||||||
|
file_name = compiler_normalize_unit_path(context, file_name);
|
||||||
|
if(file_name == "")
|
||||||
|
return(false);
|
||||||
|
SharedUnit su;
|
||||||
|
setup_unit_paths(context, &su, file_name);
|
||||||
|
auto state = inspect_shared_unit_filesystem(context, &su, true);
|
||||||
|
return(
|
||||||
|
state.source_exists &&
|
||||||
|
state.compiled_time != 0 &&
|
||||||
|
state.metadata_exists &&
|
||||||
|
state.metadata_parsed &&
|
||||||
|
state.abi_compatible &&
|
||||||
|
state.metadata_source_path == file_name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void compiler_prioritize_unit(Request* context, String file_name)
|
void compiler_prioritize_unit(Request* context, String file_name)
|
||||||
{
|
{
|
||||||
if(!compiler_request_can_serve_stale_artifact(context))
|
if(!compiler_request_can_serve_stale_artifact(context))
|
||||||
@@ -1493,6 +1541,8 @@ DValue unit_info(String path)
|
|||||||
info["required_mtime"] = (f64)fs_state.required_time;
|
info["required_mtime"] = (f64)fs_state.required_time;
|
||||||
info["runtime_abi_version"] = (f64)fs_state.runtime_abi_version;
|
info["runtime_abi_version"] = (f64)fs_state.runtime_abi_version;
|
||||||
info["metadata_abi_version"] = (f64)fs_state.metadata_abi_version;
|
info["metadata_abi_version"] = (f64)fs_state.metadata_abi_version;
|
||||||
|
info["runtime_wasm_core_abi_version"] = (f64)fs_state.runtime_wasm_core_abi_version;
|
||||||
|
info["metadata_wasm_core_abi_version"] = (f64)fs_state.metadata_wasm_core_abi_version;
|
||||||
info["current_input_signature"] = fs_state.current_input_signature;
|
info["current_input_signature"] = fs_state.current_input_signature;
|
||||||
info["metadata_input_signature"] = fs_state.metadata_input_signature;
|
info["metadata_input_signature"] = fs_state.metadata_input_signature;
|
||||||
info["metadata_build_token"] = fs_state.metadata_build_token;
|
info["metadata_build_token"] = fs_state.metadata_build_token;
|
||||||
|
|||||||
@@ -18,6 +18,10 @@
|
|||||||
String preprocess_shared_unit(Request* context, SharedUnit* su);
|
String preprocess_shared_unit(Request* context, SharedUnit* su);
|
||||||
String compiler_generated_cpp_path(Request* context, String source_file);
|
String compiler_generated_cpp_path(Request* context, String source_file);
|
||||||
String compiler_generated_cpp_path(SharedUnit* su);
|
String compiler_generated_cpp_path(SharedUnit* su);
|
||||||
|
#ifndef __UCE_WASM_UNIT__
|
||||||
|
String compiler_unit_bin_directory(Request* context);
|
||||||
|
String compiler_unit_wasm_path(Request* context, String source_file);
|
||||||
|
#endif
|
||||||
void setup_unit_paths(Request* context, SharedUnit* su, String file_name);
|
void setup_unit_paths(Request* context, SharedUnit* su, String file_name);
|
||||||
void compile_shared_unit(Request* context, SharedUnit* su);
|
void compile_shared_unit(Request* context, SharedUnit* su);
|
||||||
SharedUnit* get_shared_unit(Request* context, String file_name);
|
SharedUnit* get_shared_unit(Request* context, String file_name);
|
||||||
@@ -25,6 +29,7 @@ String compiler_error_page_unit(Request* context, String config_key);
|
|||||||
bool compiler_unit_compile_pending(Request* context, String file_name);
|
bool compiler_unit_compile_pending(Request* context, String file_name);
|
||||||
bool compiler_unit_compile_in_progress(Request* context, String file_name);
|
bool compiler_unit_compile_in_progress(Request* context, String file_name);
|
||||||
bool compiler_request_can_serve_stale_artifact(Request* context);
|
bool compiler_request_can_serve_stale_artifact(Request* context);
|
||||||
|
bool compiler_unit_can_serve_stale_artifact(Request* context, String file_name);
|
||||||
void compiler_prioritize_unit(Request* context, String file_name);
|
void compiler_prioritize_unit(Request* context, String file_name);
|
||||||
StringList compiler_take_priority_units(Request* context);
|
StringList compiler_take_priority_units(Request* context);
|
||||||
String compiler_source_generation(Request* context);
|
String compiler_source_generation(Request* context);
|
||||||
|
|||||||
+33
-1
@@ -1221,7 +1221,7 @@ void proactive_compile_queue_push(StringList& queue, String file_name)
|
|||||||
bool proactive_compile_unit(Request& context, String file_name, bool& source_missing)
|
bool proactive_compile_unit(Request& context, String file_name, bool& source_missing)
|
||||||
{
|
{
|
||||||
bool failed = false;
|
bool failed = false;
|
||||||
String wasm_path = server_state.config["BIN_DIRECTORY"] + file_name + ".wasm";
|
String wasm_path = compiler_unit_wasm_path(&context, file_name);
|
||||||
if(compiler_unit_needs_recompile(&context, file_name, &source_missing))
|
if(compiler_unit_needs_recompile(&context, file_name, &source_missing))
|
||||||
{
|
{
|
||||||
printf("(i) proactive compile %s\n", file_name.c_str());
|
printf("(i) proactive compile %s\n", file_name.c_str());
|
||||||
@@ -1582,6 +1582,36 @@ void init_base_process()
|
|||||||
srand(time());
|
srand(time());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int precompile_unit_generation()
|
||||||
|
{
|
||||||
|
f64 started_at = time_precise();
|
||||||
|
server_state.config = make_server_settings();
|
||||||
|
server_state.config["COMPILER_SYS_PATH"] = cwd_get();
|
||||||
|
Request background_context;
|
||||||
|
background_context.server = &server_state;
|
||||||
|
mkdir(server_state.config["BIN_DIRECTORY"]);
|
||||||
|
mkdir(compiler_unit_bin_directory(&background_context));
|
||||||
|
|
||||||
|
set_active_request(background_context);
|
||||||
|
auto files = compiler_scan_site_units(&background_context);
|
||||||
|
compiler_set_known_units(&background_context, files);
|
||||||
|
u64 failed = 0;
|
||||||
|
u64 compiled = 0;
|
||||||
|
for(auto& file_name : files)
|
||||||
|
{
|
||||||
|
bool source_missing = false;
|
||||||
|
if(compiler_unit_needs_recompile(&background_context, file_name, &source_missing))
|
||||||
|
compiled++;
|
||||||
|
if(proactive_compile_unit(background_context, file_name, source_missing))
|
||||||
|
failed++;
|
||||||
|
}
|
||||||
|
printf("Precompiled unit generation %s: %zu units, %llu compiled, %llu failed in %.3f s\n",
|
||||||
|
compiler_unit_bin_directory(&background_context).c_str(), files.size(),
|
||||||
|
(unsigned long long)compiled, (unsigned long long)failed,
|
||||||
|
time_precise() - started_at);
|
||||||
|
return(failed == 0 ? 0 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
// systemd connects stdout to a pipe, which otherwise block-buffers child
|
// systemd connects stdout to a pipe, which otherwise block-buffers child
|
||||||
@@ -1592,6 +1622,8 @@ int main(int argc, char** argv)
|
|||||||
// after a fault does not allocate.
|
// after a fault does not allocate.
|
||||||
backtrace(request_fault_frames, 4);
|
backtrace(request_fault_frames, 4);
|
||||||
process_start_directory();
|
process_start_directory();
|
||||||
|
if(argc == 2 && String(argv[1]) == "--precompile")
|
||||||
|
return(precompile_unit_generation());
|
||||||
|
|
||||||
init_base_process();
|
init_base_process();
|
||||||
ensure_proactive_compiler();
|
ensure_proactive_compiler();
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define UCE_WASM_CORE_ABI_VERSION 7
|
||||||
|
#define UCE_COMPILER_UNIT_ABI_VERSION 12
|
||||||
@@ -42,7 +42,7 @@ static String wasm_backend_ensure_started(Request* context)
|
|||||||
wc.core_wasm_path = first(cfg["WASM_CORE_PATH"],
|
wc.core_wasm_path = first(cfg["WASM_CORE_PATH"],
|
||||||
path_join(cfg["COMPILER_SYS_PATH"], "bin/wasm/core.wasm"));
|
path_join(cfg["COMPILER_SYS_PATH"], "bin/wasm/core.wasm"));
|
||||||
wc.site_root = path_join(cfg["COMPILER_SYS_PATH"], cfg["SITE_DIRECTORY"]);
|
wc.site_root = path_join(cfg["COMPILER_SYS_PATH"], cfg["SITE_DIRECTORY"]);
|
||||||
wc.cache_root = cfg["BIN_DIRECTORY"];
|
wc.cache_root = compiler_unit_bin_directory(context);
|
||||||
// write membrane allowlist: the site tree plus the runtime scratch dirs
|
// write membrane allowlist: the site tree plus the runtime scratch dirs
|
||||||
// pages legitimately write to (matches native reachable write targets).
|
// pages legitimately write to (matches native reachable write targets).
|
||||||
wc.write_roots = { wc.site_root, "/tmp" };
|
wc.write_roots = { wc.site_root, "/tmp" };
|
||||||
@@ -114,7 +114,7 @@ static bool wasm_artifact_exists(Request* context, const String& entry_unit)
|
|||||||
{
|
{
|
||||||
if(entry_unit == "")
|
if(entry_unit == "")
|
||||||
return(false);
|
return(false);
|
||||||
String wasm_path = context->server->config["BIN_DIRECTORY"] + entry_unit + ".wasm";
|
String wasm_path = compiler_unit_wasm_path(context, entry_unit);
|
||||||
struct stat wasm_st;
|
struct stat wasm_st;
|
||||||
f64 phase_started = time_precise();
|
f64 phase_started = time_precise();
|
||||||
context->stats.wasm_ready_check_count++;
|
context->stats.wasm_ready_check_count++;
|
||||||
@@ -133,7 +133,7 @@ static bool wasm_artifact_exists(Request* context, const String& entry_unit)
|
|||||||
{
|
{
|
||||||
context->stats.wasm_ready_freshness_us += (u64)((time_precise() - phase_started) * 1000000.0);
|
context->stats.wasm_ready_freshness_us += (u64)((time_precise() - phase_started) * 1000000.0);
|
||||||
compiler_prioritize_unit(context, entry_unit);
|
compiler_prioritize_unit(context, entry_unit);
|
||||||
return(compiler_request_can_serve_stale_artifact(context));
|
return(compiler_unit_can_serve_stale_artifact(context, entry_unit));
|
||||||
}
|
}
|
||||||
context->stats.wasm_ready_freshness_us += (u64)((time_precise() - phase_started) * 1000000.0);
|
context->stats.wasm_ready_freshness_us += (u64)((time_precise() - phase_started) * 1000000.0);
|
||||||
if(source_missing)
|
if(source_missing)
|
||||||
|
|||||||
+2
-1
@@ -6,6 +6,7 @@
|
|||||||
// into core.wasm.
|
// into core.wasm.
|
||||||
|
|
||||||
#define __UCE_WASM_CORE__ 1
|
#define __UCE_WASM_CORE__ 1
|
||||||
|
#include "abi.h"
|
||||||
#include "../lib/uce_lib.cpp"
|
#include "../lib/uce_lib.cpp"
|
||||||
|
|
||||||
#include "../lib/mysql-connector.h"
|
#include "../lib/mysql-connector.h"
|
||||||
@@ -809,7 +810,7 @@ void uce_free(void* ptr)
|
|||||||
|
|
||||||
u32 uce_wasm_core_abi_version()
|
u32 uce_wasm_core_abi_version()
|
||||||
{
|
{
|
||||||
return(7);
|
return(UCE_WASM_CORE_ABI_VERSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
int uce_wasm_core_init()
|
int uce_wasm_core_init()
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// W1 smoke driver for the production UCE core.wasm.
|
// W1 smoke driver for the production UCE core.wasm.
|
||||||
|
|
||||||
#include <wasm.h>
|
#include <wasm.h>
|
||||||
|
#include "abi.h"
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
@@ -254,7 +255,7 @@ int main(int argc, char** argv)
|
|||||||
|
|
||||||
CHECK(call_i32(core, "uce_wasm_core_init") == 0, "core init failed");
|
CHECK(call_i32(core, "uce_wasm_core_init") == 0, "core init failed");
|
||||||
call_i32(core, "uce_wasm_core_reset_request");
|
call_i32(core, "uce_wasm_core_reset_request");
|
||||||
CHECK(call_i32(core, "uce_wasm_core_abi_version") == 7, "unexpected ABI version");
|
CHECK(call_i32(core, "uce_wasm_core_abi_version") == UCE_WASM_CORE_ABI_VERSION, "unexpected ABI version");
|
||||||
|
|
||||||
wasm_memory_t* memory = core.memory();
|
wasm_memory_t* memory = core.memory();
|
||||||
int32_t root = call_i32(core, "uce_dv_root");
|
int32_t root = call_i32(core, "uce_dv_root");
|
||||||
@@ -302,7 +303,7 @@ int main(int argc, char** argv)
|
|||||||
int32_t output_ptr = call_i32(core, "uce_wasm_output_data");
|
int32_t output_ptr = call_i32(core, "uce_wasm_output_data");
|
||||||
CHECK(read_bytes(memory, output_ptr, output_len) == out, "output plumbing mismatch");
|
CHECK(read_bytes(memory, output_ptr, output_len) == out, "output plumbing mismatch");
|
||||||
|
|
||||||
printf("W1 core.wasm smoke: abi=7 encoded=%d output=%d\n", encoded_len, output_len);
|
printf("W1 core.wasm smoke: abi=%d encoded=%d output=%d\n", UCE_WASM_CORE_ABI_VERSION, encoded_len, output_len);
|
||||||
printf("W1 EXIT CRITERION: PASS\n");
|
printf("W1 EXIT CRITERION: PASS\n");
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-5
@@ -2615,8 +2615,8 @@ private:
|
|||||||
{
|
{
|
||||||
auto artifact_start = std::chrono::steady_clock::now();
|
auto artifact_start = std::chrono::steady_clock::now();
|
||||||
bool artifact_exists = file_exists_host(worker.unit_wasm_path(resolved));
|
bool artifact_exists = file_exists_host(worker.unit_wasm_path(resolved));
|
||||||
bool can_serve_stale = compiler_request_can_serve_stale_artifact(context);
|
bool stale_policy = compiler_request_can_serve_stale_artifact(context);
|
||||||
if(can_serve_stale && read_request && !component_source_generation_checked)
|
if(stale_policy && read_request && !component_source_generation_checked)
|
||||||
{
|
{
|
||||||
component_source_generation = compiler_source_generation(context);
|
component_source_generation = compiler_source_generation(context);
|
||||||
component_source_generation_checked = true;
|
component_source_generation_checked = true;
|
||||||
@@ -2629,7 +2629,7 @@ private:
|
|||||||
// HTTP reads may serve a complete stale artifact, so bound their graph
|
// HTTP reads may serve a complete stale artifact, so bound their graph
|
||||||
// stat work; CLI and mutations always check the current graph.
|
// stat work; CLI and mutations always check the current graph.
|
||||||
bool generation_available = component_source_generation != "";
|
bool generation_available = component_source_generation != "";
|
||||||
bool check_freshness = !can_serve_stale || !read_request ||
|
bool check_freshness = !stale_policy || !read_request ||
|
||||||
cached_freshness == worker.component_freshness.end() ||
|
cached_freshness == worker.component_freshness.end() ||
|
||||||
(generation_available ?
|
(generation_available ?
|
||||||
cached_freshness->second.source_generation != component_source_generation :
|
cached_freshness->second.source_generation != component_source_generation :
|
||||||
@@ -2637,13 +2637,14 @@ private:
|
|||||||
now - cached_freshness->second.checked_at).count() >= 1000);
|
now - cached_freshness->second.checked_at).count() >= 1000);
|
||||||
if(check_freshness)
|
if(check_freshness)
|
||||||
{
|
{
|
||||||
stale = compiler_unit_needs_recompile(context, resolved, 0, can_serve_stale && read_request, true);
|
stale = compiler_unit_needs_recompile(context, resolved, 0, stale_policy && read_request, true);
|
||||||
worker.component_freshness[resolved] = { now, stale, component_source_generation };
|
worker.component_freshness[resolved] = { now, stale, component_source_generation };
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
stale = cached_freshness->second.stale;
|
stale = cached_freshness->second.stale;
|
||||||
}
|
}
|
||||||
if(stale && can_serve_stale)
|
bool can_serve_stale = stale && compiler_unit_can_serve_stale_artifact(context, resolved);
|
||||||
|
if(stale && stale_policy)
|
||||||
{
|
{
|
||||||
compiler_prioritize_unit(context, resolved);
|
compiler_prioritize_unit(context, resolved);
|
||||||
if(!read_request)
|
if(!read_request)
|
||||||
|
|||||||
Reference in New Issue
Block a user