diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fe1f57b83..09518b74b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -87,6 +87,22 @@ jobs: make ex_access 2>/dev/null || true ls -l libdb-*.a 2>/dev/null || ls -l .libs/libdb-*.* 2>/dev/null || true + # The test/db/ regression runners guard specific fixed bugs (the #139 hash + # comparator, recd compact/handler recovery, and the on-disk upgrade path). + # They were previously orphaned: no CI job and no make target invoked them, + # so a regression would have gone unnoticed. They all follow the same + # BUILD=${BUILD:-.} convention and expect to run from the build directory. + - name: Regression runners (test/db) + if: matrix.config == 'default' + working-directory: build_unix + run: | + set -e + for r in run_hash_unsorted_cmp run_recd_compact run_recd_handlers run_upgrade; do + echo "::group::$r" + bash "../test/db/$r.sh" + echo "::endgroup::" + done + # ---------------------------------------------------------------------------- # 32-bit build on Linux (pointer-size / portability coverage). # ---------------------------------------------------------------------------- diff --git a/test/db/run_hash_unsorted_cmp.sh b/test/db/run_hash_unsorted_cmp.sh index 2103b988a..3ebbf8403 100644 --- a/test/db/run_hash_unsorted_cmp.sh +++ b/test/db/run_hash_unsorted_cmp.sh @@ -32,22 +32,58 @@ SRC=${SRC:-../test/db/hash_unsorted_cmp.c} HOME_DIR=${HOME_DIR:-HASH_UNSORTED_TESTDIR} TIMEOUT=${TIMEOUT:-180} -LIB="$BUILD/.libs/libdb-5.3.so" -if [ ! -f "$LIB" ]; then - LIB=$(ls "$BUILD"/.libs/libdb-*.so 2>/dev/null | head -1) +# Prefer the STATIC library: on macOS the .dylib carries a baked-in install name +# (/usr/local/BerkeleyDB.5.3/lib/...) which takes precedence over -rpath, so a +# shared link runs against an uninstalled path and dyld aborts. Static linking +# avoids the dynamic loader entirely, which is what the other CI-wired suites +# (e.g. test/fuzz) already do. Fall back to the shared library if no static one +# was built. +LIB="" +LIBRPATH="" +for cand in "$BUILD"/libdb.a "$BUILD"/.libs/libdb-5.3.a "$BUILD"/.libs/libdb-*.a; do + if [ -f "$cand" ]; then LIB="$cand"; break; fi +done +if [ -z "$LIB" ]; then + for cand in "$BUILD"/.libs/libdb-5.3.so "$BUILD"/.libs/libdb-5.3.dylib \ + "$BUILD"/.libs/libdb-*.so "$BUILD"/.libs/libdb-*.dylib; do + if [ -f "$cand" ]; then LIB="$cand"; break; fi + done + [ -n "$LIB" ] && LIBRPATH="-Wl,-rpath,$(cd "$BUILD/.libs" && pwd)" fi -[ -n "$LIB" ] || { echo "FAIL: libdb .so not found in $BUILD/.libs"; exit 1; } +[ -n "$LIB" ] || { echo "FAIL: no libdb library (static or shared) found under $BUILD"; exit 1; } + +# A static libdb needs its transitive deps named explicitly. +EXTRALIBS="" +for l in $(pkg-config --libs liburing 2>/dev/null); do EXTRALIBS="$EXTRALIBS $l"; done echo "Compiling hash_unsorted_cmp against $LIB" -gcc -g -O1 ${CFLAGS:-} -I"$BUILD" "$SRC" "$LIB" \ - -lpthread -Wl,-rpath,"$(cd "$BUILD/.libs" && pwd)" \ +"${CC:-cc}" -g -O1 ${CFLAGS:-} -I"$BUILD" "$SRC" "$LIB" \ + -lpthread $LIBRPATH $EXTRALIBS \ -o "$BUILD/hash_unsorted_cmp" rm -f "$HOME_DIR"/*.db 2>/dev/null || true mkdir -p "$HOME_DIR" +# `timeout` is GNU coreutils: present on Linux, absent on stock macOS (where it +# is `gtimeout` if coreutils is installed). Resolve it once; if neither exists, +# run without a timeout rather than failing with rc=127. +if command -v timeout >/dev/null 2>&1; then + TIMEOUT_CMD="timeout" +elif command -v gtimeout >/dev/null 2>&1; then + TIMEOUT_CMD="gtimeout" +else + TIMEOUT_CMD="" +fi +run_with_timeout() { + if [ -n "$TIMEOUT_CMD" ]; then + "$TIMEOUT_CMD" "$@" + else + shift # drop the seconds argument + "$@" + fi +} echo "Running hash_unsorted_cmp (timeout ${TIMEOUT}s)" -if timeout "$TIMEOUT" "$BUILD/hash_unsorted_cmp"; then +if run_with_timeout "$TIMEOUT" "$BUILD/hash_unsorted_cmp"; then echo "run_hash_unsorted_cmp.sh: PASS" exit 0 else diff --git a/test/db/run_recd_compact.sh b/test/db/run_recd_compact.sh index 8a930ff7e..26ed92888 100644 --- a/test/db/run_recd_compact.sh +++ b/test/db/run_recd_compact.sh @@ -23,23 +23,59 @@ SRC=${SRC:-../test/db/recd_compact.c} HOME_DIR=${HOME_DIR:-RECD_COMPACT_TESTDIR} TIMEOUT=${TIMEOUT:-180} -LIB="$BUILD/.libs/libdb-5.3.so" -if [ ! -f "$LIB" ]; then - LIB=$(ls "$BUILD"/.libs/libdb-*.so 2>/dev/null | head -1) +# Prefer the STATIC library: on macOS the .dylib carries a baked-in install name +# (/usr/local/BerkeleyDB.5.3/lib/...) which takes precedence over -rpath, so a +# shared link runs against an uninstalled path and dyld aborts. Static linking +# avoids the dynamic loader entirely, which is what the other CI-wired suites +# (e.g. test/fuzz) already do. Fall back to the shared library if no static one +# was built. +LIB="" +LIBRPATH="" +for cand in "$BUILD"/libdb.a "$BUILD"/.libs/libdb-5.3.a "$BUILD"/.libs/libdb-*.a; do + if [ -f "$cand" ]; then LIB="$cand"; break; fi +done +if [ -z "$LIB" ]; then + for cand in "$BUILD"/.libs/libdb-5.3.so "$BUILD"/.libs/libdb-5.3.dylib \ + "$BUILD"/.libs/libdb-*.so "$BUILD"/.libs/libdb-*.dylib; do + if [ -f "$cand" ]; then LIB="$cand"; break; fi + done + [ -n "$LIB" ] && LIBRPATH="-Wl,-rpath,$(cd "$BUILD/.libs" && pwd)" fi -[ -n "$LIB" ] || { echo "FAIL: libdb .so not found in $BUILD/.libs"; exit 1; } +[ -n "$LIB" ] || { echo "FAIL: no libdb library (static or shared) found under $BUILD"; exit 1; } + +# A static libdb needs its transitive deps named explicitly. +EXTRALIBS="" +for l in $(pkg-config --libs liburing 2>/dev/null); do EXTRALIBS="$EXTRALIBS $l"; done echo "Compiling recd_compact against $LIB" -gcc -g -O1 ${CFLAGS:-} -I"$BUILD" "$SRC" "$LIB" \ - -lpthread -Wl,-rpath,"$(cd "$BUILD/.libs" && pwd)" \ +"${CC:-cc}" -g -O1 ${CFLAGS:-} -I"$BUILD" "$SRC" "$LIB" \ + -lpthread $LIBRPATH $EXTRALIBS \ -o "$BUILD/recd_compact" rm -f "$HOME_DIR"/__db.* "$HOME_DIR"/log.* "$HOME_DIR"/*.db \ "$HOME_DIR"/DB_CONFIG 2>/dev/null || true mkdir -p "$HOME_DIR" +# `timeout` is GNU coreutils: present on Linux, absent on stock macOS (where it +# is `gtimeout` if coreutils is installed). Resolve it once; if neither exists, +# run without a timeout rather than failing with rc=127. +if command -v timeout >/dev/null 2>&1; then + TIMEOUT_CMD="timeout" +elif command -v gtimeout >/dev/null 2>&1; then + TIMEOUT_CMD="gtimeout" +else + TIMEOUT_CMD="" +fi +run_with_timeout() { + if [ -n "$TIMEOUT_CMD" ]; then + "$TIMEOUT_CMD" "$@" + else + shift # drop the seconds argument + "$@" + fi +} echo "Running recd_compact (timeout ${TIMEOUT}s)" -if timeout "$TIMEOUT" "$BUILD/recd_compact"; then +if run_with_timeout "$TIMEOUT" "$BUILD/recd_compact"; then echo "run_recd_compact.sh: PASS" exit 0 else diff --git a/test/db/run_recd_handlers.sh b/test/db/run_recd_handlers.sh index e305ab8e6..7dfa5d26e 100644 --- a/test/db/run_recd_handlers.sh +++ b/test/db/run_recd_handlers.sh @@ -26,23 +26,59 @@ SRC=${SRC:-../test/db/recd_handlers.c} HOME_DIR=${HOME_DIR:-RECD_HANDLERS_TESTDIR} TIMEOUT=${TIMEOUT:-300} -LIB="$BUILD/.libs/libdb-5.3.so" -if [ ! -f "$LIB" ]; then - LIB=$(ls "$BUILD"/.libs/libdb-*.so 2>/dev/null | head -1) +# Prefer the STATIC library: on macOS the .dylib carries a baked-in install name +# (/usr/local/BerkeleyDB.5.3/lib/...) which takes precedence over -rpath, so a +# shared link runs against an uninstalled path and dyld aborts. Static linking +# avoids the dynamic loader entirely, which is what the other CI-wired suites +# (e.g. test/fuzz) already do. Fall back to the shared library if no static one +# was built. +LIB="" +LIBRPATH="" +for cand in "$BUILD"/libdb.a "$BUILD"/.libs/libdb-5.3.a "$BUILD"/.libs/libdb-*.a; do + if [ -f "$cand" ]; then LIB="$cand"; break; fi +done +if [ -z "$LIB" ]; then + for cand in "$BUILD"/.libs/libdb-5.3.so "$BUILD"/.libs/libdb-5.3.dylib \ + "$BUILD"/.libs/libdb-*.so "$BUILD"/.libs/libdb-*.dylib; do + if [ -f "$cand" ]; then LIB="$cand"; break; fi + done + [ -n "$LIB" ] && LIBRPATH="-Wl,-rpath,$(cd "$BUILD/.libs" && pwd)" fi -[ -n "$LIB" ] || { echo "FAIL: libdb .so not found in $BUILD/.libs"; exit 1; } +[ -n "$LIB" ] || { echo "FAIL: no libdb library (static or shared) found under $BUILD"; exit 1; } + +# A static libdb needs its transitive deps named explicitly. +EXTRALIBS="" +for l in $(pkg-config --libs liburing 2>/dev/null); do EXTRALIBS="$EXTRALIBS $l"; done echo "Compiling recd_handlers against $LIB" -gcc -g -O1 ${CFLAGS:-} -I"$BUILD" "$SRC" "$LIB" \ - -lpthread -Wl,-rpath,"$(cd "$BUILD/.libs" && pwd)" \ +"${CC:-cc}" -g -O1 ${CFLAGS:-} -I"$BUILD" "$SRC" "$LIB" \ + -lpthread $LIBRPATH $EXTRALIBS \ -o "$BUILD/recd_handlers" rm -f "$HOME_DIR"/__db.* "$HOME_DIR"/log.* "$HOME_DIR"/*.db \ "$HOME_DIR"/DB_CONFIG 2>/dev/null || true mkdir -p "$HOME_DIR" +# `timeout` is GNU coreutils: present on Linux, absent on stock macOS (where it +# is `gtimeout` if coreutils is installed). Resolve it once; if neither exists, +# run without a timeout rather than failing with rc=127. +if command -v timeout >/dev/null 2>&1; then + TIMEOUT_CMD="timeout" +elif command -v gtimeout >/dev/null 2>&1; then + TIMEOUT_CMD="gtimeout" +else + TIMEOUT_CMD="" +fi +run_with_timeout() { + if [ -n "$TIMEOUT_CMD" ]; then + "$TIMEOUT_CMD" "$@" + else + shift # drop the seconds argument + "$@" + fi +} echo "Running recd_handlers (timeout ${TIMEOUT}s)" -if timeout "$TIMEOUT" "$BUILD/recd_handlers"; then +if run_with_timeout "$TIMEOUT" "$BUILD/recd_handlers"; then echo "run_recd_handlers.sh: PASS" rm -f "$HOME_DIR"/__db.* "$HOME_DIR"/log.* "$HOME_DIR"/*.db \ "$HOME_DIR"/DB_CONFIG 2>/dev/null || true diff --git a/test/db/run_upgrade.sh b/test/db/run_upgrade.sh index ec82b04d6..8b9616a2e 100644 --- a/test/db/run_upgrade.sh +++ b/test/db/run_upgrade.sh @@ -85,13 +85,31 @@ ABS_VERIFY=$(cd "$BUILD" && pwd)/db_verify rm -f "$WORK"/__db.* "$WORK"/log.* "$WORK"/*.db 2>/dev/null || true mkdir -p "$WORK" +# `timeout` is GNU coreutils: present on Linux, absent on stock macOS (where it +# is `gtimeout` if coreutils is installed). Resolve it once; if neither exists, +# run without a timeout rather than failing with rc=127. +if command -v timeout >/dev/null 2>&1; then + TIMEOUT_CMD="timeout" +elif command -v gtimeout >/dev/null 2>&1; then + TIMEOUT_CMD="gtimeout" +else + TIMEOUT_CMD="" +fi +run_with_timeout() { + if [ -n "$TIMEOUT_CMD" ]; then + "$TIMEOUT_CMD" "$@" + else + shift # drop the seconds argument + "$@" + fi +} # upgrade_verify FILE [extra db_upgrade flags...] -- run db_upgrade then # db_verify (both under a timeout). Used for paths that must verify clean. upgrade_verify() { f=$1; shift echo "db_upgrade $* + verify: $f" - ( cd "$WORK" && timeout "$TIMEOUT" "$ABS_UPGRADE" -h . "$@" "$f" ) - ( cd "$WORK" && timeout "$TIMEOUT" "$ABS_VERIFY" "$f" >/dev/null ) + ( cd "$WORK" && run_with_timeout "$TIMEOUT" "$ABS_UPGRADE" -h . "$@" "$f" ) + ( cd "$WORK" && run_with_timeout "$TIMEOUT" "$ABS_VERIFY" "$f" >/dev/null ) echo " CLEAN $f" } @@ -102,7 +120,7 @@ upgrade_verify() { upgrade_only() { f=$1; exp=$2 echo "db_upgrade (no verify): $f" - ( cd "$WORK" && timeout "$TIMEOUT" "$ABS_UPGRADE" -h . "$f" ) + ( cd "$WORK" && run_with_timeout "$TIMEOUT" "$ABS_UPGRADE" -h . "$f" ) got=$( cd "$WORK" && "$PYTHON" -c "import struct,sys;print(struct.unpack_from('$got; verify skipped: __db_set_lastpgno off-by-one)" @@ -173,7 +191,7 @@ done # btree-with-dups: also drive the -s (DB_DUPSORT) flag path + salvage. upgrade_verify cur_btdup.db -s echo "salvage-verify cur_btdup.db" -( cd "$WORK" && timeout "$TIMEOUT" "$ABS_VERIFY" -o cur_btdup.db >/dev/null ) +( cd "$WORK" && run_with_timeout "$TIMEOUT" "$ABS_VERIFY" -o cur_btdup.db >/dev/null ) echo " CLEAN cur_btdup.db (salvage)" # 2b. rewrite metadata pages into old on-disk layouts (see header).