From ab76cc8d705a13962dddc9d889860aa32bb4e827 Mon Sep 17 00:00:00 2001 From: Joe Isaacs Date: Wed, 19 Aug 2026 16:50:49 +0000 Subject: [PATCH 1/6] ci: run the multi-GiB slow tests in one job, not four The three multi-GiB regression tests (`build_views_offsets_overflow_i32`, `compress_large_int`, `fsst_compress_offsets_overflow_i32`) were gated on the ambient `CI` env var, so they ran in every workspace test job: the instrumented coverage run, Windows, linux-arm64 and musl. The coverage job is the worst place for them, since `-Cinstrument-coverage` on an unoptimized build makes the multi-GiB allocation and fill loops far slower, and the coverage they add is negligible. Gate them with plain `#[ignore]` instead, so every test job skips them, and pass `--run-ignored all` in "Rust tests (linux-arm64)" so that one job still runs the whole suite. A `slow-multi-gib` nextest test group holds them to one at a time, since each keeps several GiB live. The `test-with` gate was evaluated at compile time, so whether a job ran the slow tests depended on the environment at build time rather than at run time; `#[ignore]` plus `--run-ignored` is decided at run time. `test-with` is now unused and is dropped, along with the 19 transitive crates it pulled in. Also fix the nextest override for these tests: the old filterset `test(a | b)` matched nothing (`|` is not regex syntax inside `test()`) and the override carried no settings, leaving the tests on the default 150s kill budget that `fsst_compress_offsets_overflow_i32` (~110s locally) was close to. Signed-off-by: Joe Isaacs --- .config/nextest.toml | 10 +- .github/workflows/ci.yml | 7 +- .github/workflows/rust-instrumented.yml | 2 - Cargo.lock | 245 +----------------- Cargo.toml | 1 - encodings/fsst/Cargo.toml | 1 - encodings/fsst/src/tests.rs | 15 +- vortex-array/Cargo.toml | 1 - .../src/arrays/varbinview/build_views.rs | 12 +- vortex-btrblocks/Cargo.toml | 1 - vortex-btrblocks/src/schemes/integer/tests.rs | 10 +- 11 files changed, 43 insertions(+), 262 deletions(-) diff --git a/.config/nextest.toml b/.config/nextest.toml index 63a141f3773..1697741c18d 100644 --- a/.config/nextest.toml +++ b/.config/nextest.toml @@ -1,6 +1,14 @@ [profile.default] slow-timeout = { period = "30s", terminate-after = 5 } +# The multi-GiB regression tests are `#[ignore]`d, so only the "Rust tests (linux-arm64)" job +# (which passes `--run-ignored all`) runs them. Each holds several GiB live, so they are held to +# one at a time and given far more than the default time budget. +[test-groups.slow-multi-gib] +max-threads = 1 + [[profile.default.overrides]] -filter = 'test(compress_large_int | fsst_compress_offsets_overflow_i32)' +filter = 'test(build_views_offsets_overflow_i32) + test(compress_large_int) + test(fsst_compress_offsets_overflow_i32)' +test-group = 'slow-multi-gib' +slow-timeout = { period = "60s", terminate-after = 20 } priority = 100 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 889eb6d2f7c..81dd98b915b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -461,7 +461,7 @@ jobs: name: "Rust tests (linux-arm64)" needs: duckdb-ready if: github.repository == 'vortex-data/vortex' - timeout-minutes: 30 + timeout-minutes: 45 runs-on: runs-on=${{ github.run_id }}/runner=arm64-medium/image=ubuntu24-full-arm64-pre-v2/extras=s3-cache/tag=rust-test-linux-arm64 steps: - uses: runs-on/action@v2 @@ -471,9 +471,12 @@ jobs: - uses: ./.github/actions/setup-prebuild with: enable-sccache: "true" + # This is the only test job that runs the `#[ignore]`d multi-GiB regression tests; + # every other job skips them. The `slow-multi-gib` nextest test group keeps them from + # running concurrently with each other, since each holds several GiB live. - name: Rust Tests run: | - cargo nextest run --cargo-profile ci --locked --workspace --all-features --no-fail-fast --exclude vortex-bench --exclude xtask --exclude vortex-sqllogictest + cargo nextest run --cargo-profile ci --locked --workspace --all-features --no-fail-fast --run-ignored all --exclude vortex-bench --exclude xtask --exclude vortex-sqllogictest - uses: ./.github/actions/check-rebuild with: command: "cargo test --profile ci --locked --workspace --all-features --no-run --exclude vortex-bench --exclude xtask --exclude vortex-sqllogictest" diff --git a/.github/workflows/rust-instrumented.yml b/.github/workflows/rust-instrumented.yml index de135445176..a602429a0a1 100644 --- a/.github/workflows/rust-instrumented.yml +++ b/.github/workflows/rust-instrumented.yml @@ -177,7 +177,6 @@ jobs: MSAN_SYMBOLIZER_PATH: "/usr/bin/llvm-symbolizer" TSAN_OPTIONS: "symbolize=1:suppressions=${{ github.workspace }}/vortex-ffi/tsan_suppressions.txt" TSAN_SYMBOLIZER_PATH: "/usr/bin/llvm-symbolizer" - VORTEX_SKIP_SLOW_TESTS: "1" # -Cunsafe-allow-abi-mismatch=sanitizer: libraries like compiler_builtins # unset -Zsanitizer flag and we should allow that. RUSTFLAGS: "-A warnings -Cunsafe-allow-abi-mismatch=sanitizer -C debuginfo=2 -C opt-level=0 -C strip=none" @@ -243,7 +242,6 @@ jobs: MSAN_SYMBOLIZER_PATH: "/usr/bin/llvm-symbolizer" TSAN_OPTIONS: "symbolize=1:suppressions=${{ github.workspace }}/vortex-ffi/tsan_suppressions.txt" TSAN_SYMBOLIZER_PATH: "/usr/bin/llvm-symbolizer" - VORTEX_SKIP_SLOW_TESTS: "1" # -Cunsafe-allow-abi-mismatch=sanitizer: libraries like compiler_builtins # unset -Zsanitizer flag and we should allow that. runs-on: >- diff --git a/Cargo.lock b/Cargo.lock index b6d17407dec..fa8e9c249f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,17 +19,6 @@ dependencies = [ "cpufeatures", ] -[[package]] -name = "ahash" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" -dependencies = [ - "getrandom 0.2.17", - "once_cell", - "version_check", -] - [[package]] name = "ahash" version = "0.8.12" @@ -280,7 +269,7 @@ version = "56.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b02ccba2e977a3aabb4384036109ca32f552399a2bc0588f925f91ed073ce70c" dependencies = [ - "ahash 0.8.12", + "ahash", "arrow-buffer 56.2.1", "arrow-data 56.2.1", "arrow-schema 56.2.1", @@ -296,7 +285,7 @@ version = "58.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae33dad492b7df00a217563a7b0ef2874df68a0deea1b1a3acf628152f7f7a69" dependencies = [ - "ahash 0.8.12", + "ahash", "arrow-buffer 58.4.0", "arrow-data 58.4.0", "arrow-schema 58.4.0", @@ -569,7 +558,7 @@ version = "56.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2368a78bd32902dba39d52519d70f63799c8b5dc8a9477129a30c2fd3dc70c19" dependencies = [ - "ahash 0.8.12", + "ahash", "arrow-array 56.2.1", "arrow-buffer 56.2.1", "arrow-data 56.2.1", @@ -583,7 +572,7 @@ version = "58.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c58da39eb3d8350ad4a549e5c2bc49284dac554016c69829310350f1731b0aad" dependencies = [ - "ahash 0.8.12", + "ahash", "arrow-array 58.4.0", "arrow-buffer 58.4.0", "arrow-data 58.4.0", @@ -1055,30 +1044,6 @@ dependencies = [ "piper", ] -[[package]] -name = "borsh" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a88b7ea17d208c4193f2c1e6de3c35fe71f98c96982d5ced308bdcc749ff6e1f" -dependencies = [ - "borsh-derive", - "bytes", - "cfg_aliases", -] - -[[package]] -name = "borsh-derive" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8f347189c62a579b8cd5f80714efa178f52e461dc2e6d701d264f5ff22e566c" -dependencies = [ - "once_cell", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "brotli" version = "8.0.4" @@ -1138,40 +1103,6 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" -[[package]] -name = "byte-unit" -version = "5.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a813de7f2bbedb7dce265b64f1cf5908ebe4d56281ece8d847e98113788b9b0" -dependencies = [ - "rust_decimal", - "schemars 1.2.2", - "serde", - "utf8-width", -] - -[[package]] -name = "bytecheck" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" -dependencies = [ - "bytecheck_derive", - "ptr_meta", - "simdutf8", -] - -[[package]] -name = "bytecheck_derive" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "bytecount" version = "0.6.9" @@ -3787,9 +3718,6 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash 0.7.8", -] [[package]] name = "hashbrown" @@ -3797,7 +3725,7 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ - "ahash 0.8.12", + "ahash", "allocator-api2", ] @@ -6434,7 +6362,7 @@ version = "56.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3abbfef8a25900f4925c86e4cb881ea24672ca3c31ee4fb50a8083c4c56d313" dependencies = [ - "ahash 0.8.12", + "ahash", "arrow-array 56.2.1", "arrow-buffer 56.2.1", "arrow-cast 56.2.1", @@ -6469,7 +6397,7 @@ version = "58.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d298093b2dec60289dce0684c986d0f7679e9dd15771c2c65406e1aaf604a704" dependencies = [ - "ahash 0.8.12", + "ahash", "arrow-array 58.4.0", "arrow-buffer 58.4.0", "arrow-data 58.4.0", @@ -6660,17 +6588,6 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" -[[package]] -name = "ping" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "044b1fa4f259f4df9ad5078e587b208f5d288a25407575fcddb9face30c7c692" -dependencies = [ - "rand 0.9.5", - "socket2", - "thiserror 2.0.19", -] - [[package]] name = "piper" version = "0.2.5" @@ -6906,26 +6823,6 @@ dependencies = [ "cc", ] -[[package]] -name = "ptr_meta" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" -dependencies = [ - "ptr_meta_derive", -] - -[[package]] -name = "ptr_meta_derive" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "pyo3" version = "0.29.1" @@ -7069,7 +6966,7 @@ version = "0.6.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9c6658afe513a3b484e3abfdaa0d03ef3c0bbf017542c178dd55f94eb3051f9" dependencies = [ - "ahash 0.8.12", + "ahash", "equivalent", "hashbrown 0.16.1", "parking_lot", @@ -7513,15 +7410,6 @@ version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" -[[package]] -name = "rend" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" -dependencies = [ - "bytecheck", -] - [[package]] name = "reqsign-aliyun-oss" version = "3.1.2" @@ -7688,35 +7576,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rkyv" -version = "0.7.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2297bf9c81a3f0dc96bc9521370b88f054168c29826a75e89c55ff196e7ed6a1" -dependencies = [ - "bitvec", - "bytecheck", - "bytes", - "hashbrown 0.12.3", - "ptr_meta", - "rend", - "rkyv_derive", - "seahash", - "tinyvec", - "uuid", -] - -[[package]] -name = "rkyv_derive" -version = "0.7.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84d7b42d4b8d06048d3ac8db0eb31bcb942cbeb709f0b5f2b2ebde398d3038f5" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "roaring" version = "0.11.4" @@ -7804,23 +7663,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "rust_decimal" -version = "1.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be2a24f50780bc85f09cc6ac299bdf1424302742d77221106859c9d8b102126a" -dependencies = [ - "arrayvec", - "borsh", - "bytes", - "num-traits", - "rand 0.8.7", - "rkyv", - "serde", - "serde_json", - "wasm-bindgen", -] - [[package]] name = "rustc-hash" version = "2.1.3" @@ -8009,12 +7851,6 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" -[[package]] -name = "seahash" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" - [[package]] name = "security-framework" version = "3.7.0" @@ -8806,43 +8642,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4d1330fe7f7f872cd05165130b10602d667b205fd85be09be2814b115d4ced9" -[[package]] -name = "test-with" -version = "0.16.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "964c2c219d0e7658fc3cd7354826e9e8d997c1e7d592cc32f349fc1125b64a84" -dependencies = [ - "byte-unit", - "chrono", - "num_cpus", - "ping", - "reqwest 0.13.4", - "sysinfo", - "test-with-derive", - "uzers", - "which", -] - -[[package]] -name = "test-with-derive" -version = "0.16.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52884ff2163f79cd0a7af841fd2e9aca103f2ff1207092d317bf00565abdc59c" -dependencies = [ - "byte-unit", - "chrono", - "num_cpus", - "ping", - "proc-macro2", - "quote", - "regex", - "reqwest 0.13.4", - "syn 2.0.119", - "sysinfo", - "uzers", - "which", -] - [[package]] name = "testing_table" version = "0.3.0" @@ -9460,12 +9259,6 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcfc827f90e53a02eaef5e535ee14266c1d569214c6aa70133a624d8a3164ba" -[[package]] -name = "utf8-width" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "159a7cadce548703edd50d24069bc294c5415ecab0a480e0cd1ca06d112dc94a" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -9490,16 +9283,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "uzers" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b8275fb1afee25b4111d2dc8b5c505dbbc4afd0b990cb96deb2d88bff8be18d" -dependencies = [ - "libc", - "log", -] - [[package]] name = "valuable" version = "0.1.1" @@ -9626,7 +9409,6 @@ dependencies = [ "smallvec", "static_assertions", "tabled", - "test-with", "tracing", "uuid", "vortex-array", @@ -9754,7 +9536,6 @@ dependencies = [ "pco", "rand 0.10.2", "rstest", - "test-with", "tpchgen", "tpchgen-arrow", "vortex-alp", @@ -10194,7 +9975,6 @@ dependencies = [ "prost 0.14.4", "rand 0.10.2", "rstest", - "test-with", "vortex-array", "vortex-buffer", "vortex-error", @@ -10929,15 +10709,6 @@ dependencies = [ "rustls-pki-types", ] -[[package]] -name = "which" -version = "8.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3ef584124b911bcc3875c2f1472e80f24361ceb789bd1c62b3e9a3df9ff43c" -dependencies = [ - "libc", -] - [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 389d624c98f..6a295da1477 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -268,7 +268,6 @@ target-lexicon = "0.13" temp-env = "0.3" tempfile = "3" termtree = { version = "1.0" } -test-with = "=0.16.3" thiserror = "2.0.3" tokio = { version = "1.52" } tokio-stream = "0.1.17" diff --git a/encodings/fsst/Cargo.toml b/encodings/fsst/Cargo.toml index f749f121efa..9ae4b526e7a 100644 --- a/encodings/fsst/Cargo.toml +++ b/encodings/fsst/Cargo.toml @@ -34,7 +34,6 @@ _test-harness = ["dep:rand", "vortex-array/_test-harness"] divan = { workspace = true } rand = { workspace = true } rstest = { workspace = true } -test-with = { workspace = true } vortex-array = { workspace = true, features = ["_test-harness"] } [[bench]] diff --git a/encodings/fsst/src/tests.rs b/encodings/fsst/src/tests.rs index 2b908a8997f..daee85f5c51 100644 --- a/encodings/fsst/src/tests.rs +++ b/encodings/fsst/src/tests.rs @@ -126,8 +126,6 @@ fn test_fsst_array_ops() { assert_arrays_eq!(fsst_array, canonical_array, &mut ctx); } -// TODO(someone): ideally CI would run this in release mode as well since debug builds make the -// allocation and compression loop substantially slower. /// Regression for #7833: [`fsst_compress`] must accept inputs whose cumulative compressed /// bytes exceed [`i32::MAX`]. Before the fix, the compress path hardcoded /// [`VarBinBuilder`] for the FSST output and panicked in @@ -141,17 +139,18 @@ fn test_fsst_array_ops() { /// is on the FSST output side. After the fix the test must succeed with the row count /// preserved. /// -/// Allocates ~1.1 GiB for the input and ~2.1 GiB for the FSST output (~3.2 GiB total), so -/// it is gated to CI runs and skipped when `VORTEX_SKIP_SLOW_TESTS` is set. To run it -/// locally: +/// Allocates ~1.1 GiB for the input and ~2.1 GiB for the FSST output (~3.2 GiB total), so it is +/// ignored by default and run only by the "Rust tests (linux-arm64)" CI job. To run it locally +/// (release mode, since debug builds make the allocation and compression loop substantially +/// slower): /// /// ```text -/// CI=1 cargo test --release -p vortex-fsst fsst_compress_offsets +/// cargo test --release -p vortex-fsst fsst_compress_offsets -- --ignored /// ``` /// /// [`fsst_compress`]: crate::compress::fsst_compress -#[test_with::env(CI)] -#[test_with::no_env(VORTEX_SKIP_SLOW_TESTS)] +#[test] +#[ignore = "slow: allocates ~3.2 GiB, run by the \"Rust tests (linux-arm64)\" CI job"] fn fsst_compress_offsets_overflow_i32() { const STRING_LEN: usize = 64 * 1024; // Escape coding doubles every byte, so ~1.06 GiB of input compresses to ~2.13 GiB, diff --git a/vortex-array/Cargo.toml b/vortex-array/Cargo.toml index 7c5936627e5..8ce0e3b8095 100644 --- a/vortex-array/Cargo.toml +++ b/vortex-array/Cargo.toml @@ -91,7 +91,6 @@ rand_distr = { workspace = true } rstest = { workspace = true } serde_json = { workspace = true } serde_test = { workspace = true } -test-with = { workspace = true } vortex-array = { path = ".", features = [ "_test-harness", "table-display", diff --git a/vortex-array/src/arrays/varbinview/build_views.rs b/vortex-array/src/arrays/varbinview/build_views.rs index 8a6a5a0530d..bcb98427a1a 100644 --- a/vortex-array/src/arrays/varbinview/build_views.rs +++ b/vortex-array/src/arrays/varbinview/build_views.rs @@ -492,8 +492,6 @@ mod tests { build_views(0, MAX_BUFFER_LEN, bytes, &[31u32]); } - // TODO(someone): ideally CI would run this in release mode as well, since debug builds make the - // ~2.25 GiB allocation and fill loop substantially slower. /// Slow regression for the single-buffer fast-path guard. The fast path is only valid when the /// whole heap fits in one buffer (`bytes.len() <= max_buffer_len`); once the heap exceeds /// [`MAX_BUFFER_LEN`] (`i32::MAX`, ~2.0 GiB) `build_views` must roll the heap into multiple @@ -506,15 +504,17 @@ mod tests { /// the fast path swallowed the whole heap, it would emit a single >2 GiB buffer with offsets past /// `i32::MAX`, which the buffer-count and buffer-size assertions catch. /// - /// Allocates ~2.25 GiB, so it is gated to CI and skipped when `VORTEX_SKIP_SLOW_TESTS` is set: + /// Allocates ~2.25 GiB, so it is ignored by default and run only by the "Rust tests + /// (linux-arm64)" CI job. To run it locally (release mode, since debug builds make the + /// allocation and fill loop substantially slower): /// /// ```text - /// CI=1 cargo test --release -p vortex-array build_views_offsets_overflow + /// cargo test --release -p vortex-array build_views_offsets_overflow -- --ignored /// ``` /// /// [`MAX_BUFFER_LEN`]: super::MAX_BUFFER_LEN - #[test_with::env(CI)] - #[test_with::no_env(VORTEX_SKIP_SLOW_TESTS)] + #[test] + #[ignore = "slow: allocates ~2.25 GiB, run by the \"Rust tests (linux-arm64)\" CI job"] fn build_views_offsets_overflow_i32() { const STRING_LEN: usize = 64 * 1024; // Comfortably past MAX_BUFFER_LEN (`i32::MAX` ~= 2.0 GiB) so the heap must roll over. diff --git a/vortex-btrblocks/Cargo.toml b/vortex-btrblocks/Cargo.toml index 4e22f042adf..6433ef2aa41 100644 --- a/vortex-btrblocks/Cargo.toml +++ b/vortex-btrblocks/Cargo.toml @@ -43,7 +43,6 @@ arrow-array = { workspace = true } divan = { workspace = true } insta = { workspace = true } rstest = { workspace = true } -test-with = { workspace = true } tpchgen = { workspace = true } tpchgen-arrow = { workspace = true } vortex-array = { workspace = true, features = ["_test-harness"] } diff --git a/vortex-btrblocks/src/schemes/integer/tests.rs b/vortex-btrblocks/src/schemes/integer/tests.rs index a9ef24dc0e0..85fb2c65d44 100644 --- a/vortex-btrblocks/src/schemes/integer/tests.rs +++ b/vortex-btrblocks/src/schemes/integer/tests.rs @@ -128,8 +128,14 @@ fn test_rle_compression() -> VortexResult<()> { Ok(()) } -#[test_with::env(CI)] -#[test_with::no_env(VORTEX_SKIP_SLOW_TESTS)] +/// Compresses 50M values, so it is ignored by default and run only by the "Rust tests +/// (linux-arm64)" CI job. To run it locally: +/// +/// ```text +/// cargo test --release -p vortex-btrblocks compress_large_int -- --ignored +/// ``` +#[test] +#[ignore = "slow: compresses 50M values, run by the \"Rust tests (linux-arm64)\" CI job"] fn compress_large_int() -> VortexResult<()> { const NUM_LISTS: usize = 10_000; const ELEMENTS_PER_LIST: usize = 5_000; From 7d0f08407440c30382a9d0beb373488520f6fc71 Mon Sep 17 00:00:00 2001 From: Joe Isaacs Date: Wed, 19 Aug 2026 17:42:46 +0000 Subject: [PATCH 2/6] ci: name the slow tests instead of running every ignored test `--run-ignored all` on the workspace run also un-ignored the CUDA tests, which `vortex-cuda`'s test macro marks `#[ignore]` when the runner has no GPU: 568 of them ran and failed on linux-arm64. Run the slow tests from their own step instead, selected by name, with the same cargo arguments as the step above so nothing is rebuilt. Signed-off-by: Joe Isaacs --- .github/workflows/ci.yml | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 81dd98b915b..60c0a4910c1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -461,7 +461,7 @@ jobs: name: "Rust tests (linux-arm64)" needs: duckdb-ready if: github.repository == 'vortex-data/vortex' - timeout-minutes: 45 + timeout-minutes: 30 runs-on: runs-on=${{ github.run_id }}/runner=arm64-medium/image=ubuntu24-full-arm64-pre-v2/extras=s3-cache/tag=rust-test-linux-arm64 steps: - uses: runs-on/action@v2 @@ -471,12 +471,20 @@ jobs: - uses: ./.github/actions/setup-prebuild with: enable-sccache: "true" - # This is the only test job that runs the `#[ignore]`d multi-GiB regression tests; - # every other job skips them. The `slow-multi-gib` nextest test group keeps them from - # running concurrently with each other, since each holds several GiB live. - name: Rust Tests run: | - cargo nextest run --cargo-profile ci --locked --workspace --all-features --no-fail-fast --run-ignored all --exclude vortex-bench --exclude xtask --exclude vortex-sqllogictest + cargo nextest run --cargo-profile ci --locked --workspace --all-features --no-fail-fast --exclude vortex-bench --exclude xtask --exclude vortex-sqllogictest + # The multi-GiB regression tests are `#[ignore]`d so that every other test job skips + # them; this is the only job that runs them. They are named explicitly rather than run + # with a bare `--run-ignored`, which would also pick up the CUDA tests that are ignored + # when the runner has no GPU. The cargo arguments match the step above so that nothing + # is rebuilt. The `slow-multi-gib` nextest test group keeps them from running + # concurrently with each other, since each holds several GiB live. + - name: Rust Tests (slow) + run: | + cargo nextest run --cargo-profile ci --locked --workspace --all-features --no-fail-fast --run-ignored only \ + --exclude vortex-bench --exclude xtask --exclude vortex-sqllogictest \ + -E 'test(build_views_offsets_overflow_i32) + test(compress_large_int) + test(fsst_compress_offsets_overflow_i32)' - uses: ./.github/actions/check-rebuild with: command: "cargo test --profile ci --locked --workspace --all-features --no-run --exclude vortex-bench --exclude xtask --exclude vortex-sqllogictest" From 7b0a6f1759ea3942ab693421ce7b0391aa5ac878 Mon Sep 17 00:00:00 2001 From: Joe Isaacs Date: Thu, 20 Aug 2026 11:49:47 +0000 Subject: [PATCH 3/6] test(fsst): cover the i64 codes-offsets path without multi-GiB input The i32-vs-i64 decision already has a cheap unit test on `fsst_output_fits_in_i32_offsets`, but the i64 branch itself was only reachable through `fsst_compress_offsets_overflow_i32`, which must build ~3.2 GiB to push FSST output past `i32::MAX`. That size is not padding: escape coding is exactly 2x, so crossing the boundary needs ~1.07 GiB of input and the test already sits within 1% of that minimum. `compress_views` is generic over the offset type, so drive it as `i64` directly on three short strings: the branch is covered in 10ms, and the multi-GiB test is left as an end-to-end check of the real boundary rather than the only coverage of the code path. Also build `fsst-rs` optimized under the `ci` profile. Its compression kernel dominates that test's runtime unoptimized: 106s -> 64s locally. Signed-off-by: Joe Isaacs --- Cargo.toml | 5 +++++ encodings/fsst/src/compress.rs | 16 +++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 6a295da1477..4c9599675f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -440,3 +440,8 @@ incremental = false # This improved build times significantly for default common cases that we use locally [profile.dev.package.vortex-fastlanes] debug = false + +# FSST's compression kernel is hot enough that an unoptimized build dominates the runtime of the +# multi-GiB `fsst_compress_offsets_overflow_i32` regression (106s -> 64s locally when optimized). +[profile.ci.package.fsst-rs] +opt-level = 3 diff --git a/encodings/fsst/src/compress.rs b/encodings/fsst/src/compress.rs index 9df8f6989dd..a02e97dffb6 100644 --- a/encodings/fsst/src/compress.rs +++ b/encodings/fsst/src/compress.rs @@ -368,8 +368,22 @@ mod tests { assert!(!fsst_output_fits_in_i32_offsets(usize::MAX)); } + /// The i64 codes-offsets path must build a valid array. Driving `compress_views::` + /// directly covers the branch on a three-string input, so day-to-day coverage of it does not + /// depend on the multi-GiB `tests::fsst_compress_offsets_overflow_i32`. + #[test] + fn codes_offsets_i64_path_roundtrips() -> VortexResult<()> { + let array = VarBinViewArray::from_iter_str(["hello", "world", "fsst encoded"]); + let mut ctx = array_session().create_execution_ctx(); + let compressor = fsst_train_compressor(array.as_array(), &mut ctx)?; + let mask = array.validity()?.execute_mask(array.len(), &mut ctx)?; + let fsst = super::compress_views::(array.as_view(), &mask, &compressor, &mut ctx)?; + assert_eq!(fsst.codes().offsets().dtype().as_ptype(), PType::I64); + assert_eq!(fsst.len(), array.len()); + Ok(()) + } + /// Small inputs fit the i32 bound, so `fsst_compress` must pick i32 offsets. - /// The i64 branch is covered by `tests::fsst_compress_offsets_overflow_i32`. #[test] fn codes_offsets_dtype_small_input_is_i32() -> VortexResult<()> { let array = VarBinViewArray::from_iter_str(["hello", "world", "fsst encoded"]); From 33d6a01f48d3d5c81b41afd1b6ddd0a971ce8d8b Mon Sep 17 00:00:00 2001 From: Joe Isaacs Date: Thu, 20 Aug 2026 13:20:21 +0000 Subject: [PATCH 4/6] test(btrblocks): pin the ALP patch structure without 50M values `compress_large_int` asserts nothing beyond "does not error", so what it guards was not recorded anywhere. Printing the encoding tree at several sizes shows it: at 50M rows the sampled ALP exponents no longer fit every value, and the result carries `patch_indices` / `patch_values` / `patch_chunk_offsets`. Below ~5M rows the sample fits the whole array and no patches are produced at all, so the structure appears only by scale. Reach it deliberately instead: keep whole numbers as the bulk and sprinkle values needing more decimal digits than the sampled exponents can represent. 200K rows reproduce the same patched-ALP tree, and varying the patch density pins the `patch_chunk_offsets` width across u8, u16 and u32. The three cases run in 1.3s against 40s for `compress_large_int`, and unlike it they assert the shape and round-trip the values. Signed-off-by: Joe Isaacs --- vortex-btrblocks/src/schemes/integer/tests.rs | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/vortex-btrblocks/src/schemes/integer/tests.rs b/vortex-btrblocks/src/schemes/integer/tests.rs index 85fb2c65d44..0dd0c9389f3 100644 --- a/vortex-btrblocks/src/schemes/integer/tests.rs +++ b/vortex-btrblocks/src/schemes/integer/tests.rs @@ -15,11 +15,13 @@ use vortex_array::arrays::Dict; use vortex_array::arrays::Masked; use vortex_array::arrays::PrimitiveArray; use vortex_array::assert_arrays_eq; +use vortex_array::dtype::PType; use vortex_array::validity::Validity; use vortex_buffer::Buffer; use vortex_buffer::BufferMut; use vortex_buffer::buffer; use vortex_compressor::CascadingCompressor; +use vortex_error::VortexExpect; use vortex_error::VortexResult; use vortex_fastlanes::RLE; use vortex_sequence::Sequence; @@ -152,3 +154,45 @@ fn compress_large_int() -> VortexResult<()> { Ok(()) } + +/// The compressor picks ALP exponents from a sample, so values the sample did not represent must +/// be stored as patches, indexed per chunk. This is the structure `compress_large_int` reaches +/// only by scale; here the misfit values are placed deliberately, which also pins the +/// `patch_chunk_offsets` width across the three magnitudes it is chosen from. +#[rstest::rstest] +#[case::sparse_patches(200_000, 1_000, PType::U8)] +#[case::dense_patches(200_000, 100, PType::U16)] +#[case::many_patches(1_000_000, 10, PType::U32)] +fn alp_patches_are_chunk_indexed( + #[case] len: usize, + #[case] patch_every: usize, + #[case] chunk_offsets_ptype: PType, +) -> VortexResult<()> { + let mut ctx = SESSION.create_execution_ctx(); + + // Whole numbers dominate, so the sampled exponents encode them exactly; the sprinkled values + // need more decimal digits than those exponents can represent and must be patched. + let values = (0..len) + .map(|i| { + if i % patch_every == patch_every - 1 { + i as f64 + 0.123_456_789_012_345 + } else { + i as f64 + } + }) + .collect::() + .into_array(); + + let compressed = BtrBlocksCompressor::default().compress(&values, &mut ctx)?; + + let offsets = compressed + .children_names() + .iter() + .position(|name| name == "patch_chunk_offsets") + .map(|idx| compressed.children()[idx].clone()) + .vortex_expect("compressed array must carry chunk-indexed ALP patches"); + assert_eq!(offsets.dtype().as_ptype(), chunk_offsets_ptype); + + assert_arrays_eq!(compressed, values, &mut ctx); + Ok(()) +} From d8157d1fab0766d51dab4af23427cee09869d4f6 Mon Sep 17 00:00:00 2001 From: Joe Isaacs Date: Thu, 20 Aug 2026 14:05:14 +0000 Subject: [PATCH 5/6] Restore the VORTEX_SKIP_SLOW_TESTS opt-out on the slow tests Keeps `#[test_with::no_env(VORTEX_SKIP_SLOW_TESTS)]` alongside the `#[ignore]` gate, so setting the variable at build time still drops the multi-GiB tests from the binary, and restores it in the two sanitizer jobs so they never compile those test bodies under asan/tsan. `test-with` comes back as a dev-dependency of the three crates. The two gates do not overlap: `#[ignore]` decides at run time and is what keeps the tests out of every job's default run, while `no_env` decides at compile time and removes them from the binary entirely. Signed-off-by: Joe Isaacs --- .github/workflows/rust-instrumented.yml | 4 + Cargo.lock | 245 +++++++++++++++++- Cargo.toml | 1 + encodings/fsst/Cargo.toml | 1 + encodings/fsst/src/tests.rs | 8 +- vortex-array/Cargo.toml | 1 + .../src/arrays/varbinview/build_views.rs | 6 +- vortex-btrblocks/Cargo.toml | 1 + vortex-btrblocks/src/schemes/integer/tests.rs | 4 +- 9 files changed, 257 insertions(+), 14 deletions(-) diff --git a/.github/workflows/rust-instrumented.yml b/.github/workflows/rust-instrumented.yml index a602429a0a1..26055db907b 100644 --- a/.github/workflows/rust-instrumented.yml +++ b/.github/workflows/rust-instrumented.yml @@ -177,6 +177,8 @@ jobs: MSAN_SYMBOLIZER_PATH: "/usr/bin/llvm-symbolizer" TSAN_OPTIONS: "symbolize=1:suppressions=${{ github.workspace }}/vortex-ffi/tsan_suppressions.txt" TSAN_SYMBOLIZER_PATH: "/usr/bin/llvm-symbolizer" + # Compiles the multi-GiB tests out of the sanitizer build entirely. + VORTEX_SKIP_SLOW_TESTS: "1" # -Cunsafe-allow-abi-mismatch=sanitizer: libraries like compiler_builtins # unset -Zsanitizer flag and we should allow that. RUSTFLAGS: "-A warnings -Cunsafe-allow-abi-mismatch=sanitizer -C debuginfo=2 -C opt-level=0 -C strip=none" @@ -242,6 +244,8 @@ jobs: MSAN_SYMBOLIZER_PATH: "/usr/bin/llvm-symbolizer" TSAN_OPTIONS: "symbolize=1:suppressions=${{ github.workspace }}/vortex-ffi/tsan_suppressions.txt" TSAN_SYMBOLIZER_PATH: "/usr/bin/llvm-symbolizer" + # Compiles the multi-GiB tests out of the sanitizer build entirely. + VORTEX_SKIP_SLOW_TESTS: "1" # -Cunsafe-allow-abi-mismatch=sanitizer: libraries like compiler_builtins # unset -Zsanitizer flag and we should allow that. runs-on: >- diff --git a/Cargo.lock b/Cargo.lock index fa8e9c249f4..b6d17407dec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,6 +19,17 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom 0.2.17", + "once_cell", + "version_check", +] + [[package]] name = "ahash" version = "0.8.12" @@ -269,7 +280,7 @@ version = "56.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b02ccba2e977a3aabb4384036109ca32f552399a2bc0588f925f91ed073ce70c" dependencies = [ - "ahash", + "ahash 0.8.12", "arrow-buffer 56.2.1", "arrow-data 56.2.1", "arrow-schema 56.2.1", @@ -285,7 +296,7 @@ version = "58.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae33dad492b7df00a217563a7b0ef2874df68a0deea1b1a3acf628152f7f7a69" dependencies = [ - "ahash", + "ahash 0.8.12", "arrow-buffer 58.4.0", "arrow-data 58.4.0", "arrow-schema 58.4.0", @@ -558,7 +569,7 @@ version = "56.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2368a78bd32902dba39d52519d70f63799c8b5dc8a9477129a30c2fd3dc70c19" dependencies = [ - "ahash", + "ahash 0.8.12", "arrow-array 56.2.1", "arrow-buffer 56.2.1", "arrow-data 56.2.1", @@ -572,7 +583,7 @@ version = "58.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c58da39eb3d8350ad4a549e5c2bc49284dac554016c69829310350f1731b0aad" dependencies = [ - "ahash", + "ahash 0.8.12", "arrow-array 58.4.0", "arrow-buffer 58.4.0", "arrow-data 58.4.0", @@ -1044,6 +1055,30 @@ dependencies = [ "piper", ] +[[package]] +name = "borsh" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a88b7ea17d208c4193f2c1e6de3c35fe71f98c96982d5ced308bdcc749ff6e1f" +dependencies = [ + "borsh-derive", + "bytes", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8f347189c62a579b8cd5f80714efa178f52e461dc2e6d701d264f5ff22e566c" +dependencies = [ + "once_cell", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "brotli" version = "8.0.4" @@ -1103,6 +1138,40 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" +[[package]] +name = "byte-unit" +version = "5.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a813de7f2bbedb7dce265b64f1cf5908ebe4d56281ece8d847e98113788b9b0" +dependencies = [ + "rust_decimal", + "schemars 1.2.2", + "serde", + "utf8-width", +] + +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "bytecount" version = "0.6.9" @@ -3718,6 +3787,9 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.8", +] [[package]] name = "hashbrown" @@ -3725,7 +3797,7 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ - "ahash", + "ahash 0.8.12", "allocator-api2", ] @@ -6362,7 +6434,7 @@ version = "56.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3abbfef8a25900f4925c86e4cb881ea24672ca3c31ee4fb50a8083c4c56d313" dependencies = [ - "ahash", + "ahash 0.8.12", "arrow-array 56.2.1", "arrow-buffer 56.2.1", "arrow-cast 56.2.1", @@ -6397,7 +6469,7 @@ version = "58.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d298093b2dec60289dce0684c986d0f7679e9dd15771c2c65406e1aaf604a704" dependencies = [ - "ahash", + "ahash 0.8.12", "arrow-array 58.4.0", "arrow-buffer 58.4.0", "arrow-data 58.4.0", @@ -6588,6 +6660,17 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" +[[package]] +name = "ping" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "044b1fa4f259f4df9ad5078e587b208f5d288a25407575fcddb9face30c7c692" +dependencies = [ + "rand 0.9.5", + "socket2", + "thiserror 2.0.19", +] + [[package]] name = "piper" version = "0.2.5" @@ -6823,6 +6906,26 @@ dependencies = [ "cc", ] +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "pyo3" version = "0.29.1" @@ -6966,7 +7069,7 @@ version = "0.6.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9c6658afe513a3b484e3abfdaa0d03ef3c0bbf017542c178dd55f94eb3051f9" dependencies = [ - "ahash", + "ahash 0.8.12", "equivalent", "hashbrown 0.16.1", "parking_lot", @@ -7410,6 +7513,15 @@ version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" +[[package]] +name = "rend" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +dependencies = [ + "bytecheck", +] + [[package]] name = "reqsign-aliyun-oss" version = "3.1.2" @@ -7576,6 +7688,35 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rkyv" +version = "0.7.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2297bf9c81a3f0dc96bc9521370b88f054168c29826a75e89c55ff196e7ed6a1" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84d7b42d4b8d06048d3ac8db0eb31bcb942cbeb709f0b5f2b2ebde398d3038f5" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "roaring" version = "0.11.4" @@ -7663,6 +7804,23 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "rust_decimal" +version = "1.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be2a24f50780bc85f09cc6ac299bdf1424302742d77221106859c9d8b102126a" +dependencies = [ + "arrayvec", + "borsh", + "bytes", + "num-traits", + "rand 0.8.7", + "rkyv", + "serde", + "serde_json", + "wasm-bindgen", +] + [[package]] name = "rustc-hash" version = "2.1.3" @@ -7851,6 +8009,12 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + [[package]] name = "security-framework" version = "3.7.0" @@ -8642,6 +8806,43 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4d1330fe7f7f872cd05165130b10602d667b205fd85be09be2814b115d4ced9" +[[package]] +name = "test-with" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "964c2c219d0e7658fc3cd7354826e9e8d997c1e7d592cc32f349fc1125b64a84" +dependencies = [ + "byte-unit", + "chrono", + "num_cpus", + "ping", + "reqwest 0.13.4", + "sysinfo", + "test-with-derive", + "uzers", + "which", +] + +[[package]] +name = "test-with-derive" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52884ff2163f79cd0a7af841fd2e9aca103f2ff1207092d317bf00565abdc59c" +dependencies = [ + "byte-unit", + "chrono", + "num_cpus", + "ping", + "proc-macro2", + "quote", + "regex", + "reqwest 0.13.4", + "syn 2.0.119", + "sysinfo", + "uzers", + "which", +] + [[package]] name = "testing_table" version = "0.3.0" @@ -9259,6 +9460,12 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcfc827f90e53a02eaef5e535ee14266c1d569214c6aa70133a624d8a3164ba" +[[package]] +name = "utf8-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "159a7cadce548703edd50d24069bc294c5415ecab0a480e0cd1ca06d112dc94a" + [[package]] name = "utf8_iter" version = "1.0.4" @@ -9283,6 +9490,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "uzers" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b8275fb1afee25b4111d2dc8b5c505dbbc4afd0b990cb96deb2d88bff8be18d" +dependencies = [ + "libc", + "log", +] + [[package]] name = "valuable" version = "0.1.1" @@ -9409,6 +9626,7 @@ dependencies = [ "smallvec", "static_assertions", "tabled", + "test-with", "tracing", "uuid", "vortex-array", @@ -9536,6 +9754,7 @@ dependencies = [ "pco", "rand 0.10.2", "rstest", + "test-with", "tpchgen", "tpchgen-arrow", "vortex-alp", @@ -9975,6 +10194,7 @@ dependencies = [ "prost 0.14.4", "rand 0.10.2", "rstest", + "test-with", "vortex-array", "vortex-buffer", "vortex-error", @@ -10709,6 +10929,15 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "which" +version = "8.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3ef584124b911bcc3875c2f1472e80f24361ceb789bd1c62b3e9a3df9ff43c" +dependencies = [ + "libc", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 4c9599675f4..59c529e2cc4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -268,6 +268,7 @@ target-lexicon = "0.13" temp-env = "0.3" tempfile = "3" termtree = { version = "1.0" } +test-with = "=0.16.3" thiserror = "2.0.3" tokio = { version = "1.52" } tokio-stream = "0.1.17" diff --git a/encodings/fsst/Cargo.toml b/encodings/fsst/Cargo.toml index 9ae4b526e7a..f749f121efa 100644 --- a/encodings/fsst/Cargo.toml +++ b/encodings/fsst/Cargo.toml @@ -34,6 +34,7 @@ _test-harness = ["dep:rand", "vortex-array/_test-harness"] divan = { workspace = true } rand = { workspace = true } rstest = { workspace = true } +test-with = { workspace = true } vortex-array = { workspace = true, features = ["_test-harness"] } [[bench]] diff --git a/encodings/fsst/src/tests.rs b/encodings/fsst/src/tests.rs index daee85f5c51..ad915e47158 100644 --- a/encodings/fsst/src/tests.rs +++ b/encodings/fsst/src/tests.rs @@ -140,15 +140,17 @@ fn test_fsst_array_ops() { /// preserved. /// /// Allocates ~1.1 GiB for the input and ~2.1 GiB for the FSST output (~3.2 GiB total), so it is -/// ignored by default and run only by the "Rust tests (linux-arm64)" CI job. To run it locally -/// (release mode, since debug builds make the allocation and compression loop substantially -/// slower): +/// ignored by default and run only by the "Rust tests (linux-arm64)" CI job. Setting +/// `VORTEX_SKIP_SLOW_TESTS` at build time drops it from the binary, which is how the sanitizer +/// jobs avoid compiling it at all. To run it locally (release mode, since debug builds make the +/// allocation and compression loop substantially slower): /// /// ```text /// cargo test --release -p vortex-fsst fsst_compress_offsets -- --ignored /// ``` /// /// [`fsst_compress`]: crate::compress::fsst_compress +#[test_with::no_env(VORTEX_SKIP_SLOW_TESTS)] #[test] #[ignore = "slow: allocates ~3.2 GiB, run by the \"Rust tests (linux-arm64)\" CI job"] fn fsst_compress_offsets_overflow_i32() { diff --git a/vortex-array/Cargo.toml b/vortex-array/Cargo.toml index 8ce0e3b8095..7c5936627e5 100644 --- a/vortex-array/Cargo.toml +++ b/vortex-array/Cargo.toml @@ -91,6 +91,7 @@ rand_distr = { workspace = true } rstest = { workspace = true } serde_json = { workspace = true } serde_test = { workspace = true } +test-with = { workspace = true } vortex-array = { path = ".", features = [ "_test-harness", "table-display", diff --git a/vortex-array/src/arrays/varbinview/build_views.rs b/vortex-array/src/arrays/varbinview/build_views.rs index bcb98427a1a..ee81970fea6 100644 --- a/vortex-array/src/arrays/varbinview/build_views.rs +++ b/vortex-array/src/arrays/varbinview/build_views.rs @@ -505,14 +505,16 @@ mod tests { /// `i32::MAX`, which the buffer-count and buffer-size assertions catch. /// /// Allocates ~2.25 GiB, so it is ignored by default and run only by the "Rust tests - /// (linux-arm64)" CI job. To run it locally (release mode, since debug builds make the - /// allocation and fill loop substantially slower): + /// (linux-arm64)" CI job. Setting `VORTEX_SKIP_SLOW_TESTS` at build time drops it from the + /// binary, which is how the sanitizer jobs avoid compiling it at all. To run it locally + /// (release mode, since debug builds make the allocation and fill loop substantially slower): /// /// ```text /// cargo test --release -p vortex-array build_views_offsets_overflow -- --ignored /// ``` /// /// [`MAX_BUFFER_LEN`]: super::MAX_BUFFER_LEN + #[test_with::no_env(VORTEX_SKIP_SLOW_TESTS)] #[test] #[ignore = "slow: allocates ~2.25 GiB, run by the \"Rust tests (linux-arm64)\" CI job"] fn build_views_offsets_overflow_i32() { diff --git a/vortex-btrblocks/Cargo.toml b/vortex-btrblocks/Cargo.toml index 6433ef2aa41..4e22f042adf 100644 --- a/vortex-btrblocks/Cargo.toml +++ b/vortex-btrblocks/Cargo.toml @@ -43,6 +43,7 @@ arrow-array = { workspace = true } divan = { workspace = true } insta = { workspace = true } rstest = { workspace = true } +test-with = { workspace = true } tpchgen = { workspace = true } tpchgen-arrow = { workspace = true } vortex-array = { workspace = true, features = ["_test-harness"] } diff --git a/vortex-btrblocks/src/schemes/integer/tests.rs b/vortex-btrblocks/src/schemes/integer/tests.rs index 0dd0c9389f3..3645e3a05bc 100644 --- a/vortex-btrblocks/src/schemes/integer/tests.rs +++ b/vortex-btrblocks/src/schemes/integer/tests.rs @@ -131,11 +131,13 @@ fn test_rle_compression() -> VortexResult<()> { } /// Compresses 50M values, so it is ignored by default and run only by the "Rust tests -/// (linux-arm64)" CI job. To run it locally: +/// (linux-arm64)" CI job. Setting `VORTEX_SKIP_SLOW_TESTS` at build time drops it from the +/// binary, which is how the sanitizer jobs avoid compiling it at all. To run it locally: /// /// ```text /// cargo test --release -p vortex-btrblocks compress_large_int -- --ignored /// ``` +#[test_with::no_env(VORTEX_SKIP_SLOW_TESTS)] #[test] #[ignore = "slow: compresses 50M values, run by the \"Rust tests (linux-arm64)\" CI job"] fn compress_large_int() -> VortexResult<()> { From 5fa8c2a309cb88c2fc1bf3a56e203469f8ed92ca Mon Sep 17 00:00:00 2001 From: Joe Isaacs Date: Thu, 20 Aug 2026 15:44:29 +0000 Subject: [PATCH 6/6] ci: run the slow tests from the musl job, which runs on every event MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `Rust tests (linux-arm64)` does not run everywhere: it is gated on `github.repository == 'vortex-data/vortex'`, so fork pull requests skip it, and it is skipped on pushes to develop along with the windows and coverage jobs. Hanging the multi-GiB regression tests off that job therefore left them running on upstream pull requests only — before this branch they still ran on develop pushes and on forks through the musl job. `Rust tests (linux-musl)` runs in all three cases: it has no repository gate, falls back to `ubuntu-latest` off the upstream org, and runs on pushes to develop. Move the step there, keeping the explicit test names and the cargo arguments that match the step above it so nothing is rebuilt. Signed-off-by: Joe Isaacs --- .config/nextest.toml | 6 +++--- .github/workflows/ci.yml | 11 ---------- .github/workflows/musl.yml | 20 +++++++++++++++++++ encodings/fsst/src/tests.rs | 4 ++-- .../src/arrays/varbinview/build_views.rs | 4 ++-- vortex-btrblocks/src/schemes/integer/tests.rs | 4 ++-- 6 files changed, 29 insertions(+), 20 deletions(-) diff --git a/.config/nextest.toml b/.config/nextest.toml index 1697741c18d..eb99cf61619 100644 --- a/.config/nextest.toml +++ b/.config/nextest.toml @@ -1,9 +1,9 @@ [profile.default] slow-timeout = { period = "30s", terminate-after = 5 } -# The multi-GiB regression tests are `#[ignore]`d, so only the "Rust tests (linux-arm64)" job -# (which passes `--run-ignored all`) runs them. Each holds several GiB live, so they are held to -# one at a time and given far more than the default time budget. +# The multi-GiB regression tests are `#[ignore]`d, so only the "Rust tests (linux-musl)" job +# runs them. Each holds several GiB live, so they are held to one at a time and given far more +# than the default time budget. [test-groups.slow-multi-gib] max-threads = 1 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 60c0a4910c1..889eb6d2f7c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -474,17 +474,6 @@ jobs: - name: Rust Tests run: | cargo nextest run --cargo-profile ci --locked --workspace --all-features --no-fail-fast --exclude vortex-bench --exclude xtask --exclude vortex-sqllogictest - # The multi-GiB regression tests are `#[ignore]`d so that every other test job skips - # them; this is the only job that runs them. They are named explicitly rather than run - # with a bare `--run-ignored`, which would also pick up the CUDA tests that are ignored - # when the runner has no GPU. The cargo arguments match the step above so that nothing - # is rebuilt. The `slow-multi-gib` nextest test group keeps them from running - # concurrently with each other, since each holds several GiB live. - - name: Rust Tests (slow) - run: | - cargo nextest run --cargo-profile ci --locked --workspace --all-features --no-fail-fast --run-ignored only \ - --exclude vortex-bench --exclude xtask --exclude vortex-sqllogictest \ - -E 'test(build_views_offsets_overflow_i32) + test(compress_large_int) + test(fsst_compress_offsets_overflow_i32)' - uses: ./.github/actions/check-rebuild with: command: "cargo test --profile ci --locked --workspace --all-features --no-run --exclude vortex-bench --exclude xtask --exclude vortex-sqllogictest" diff --git a/.github/workflows/musl.yml b/.github/workflows/musl.yml index c331dbc2859..43a181c9891 100644 --- a/.github/workflows/musl.yml +++ b/.github/workflows/musl.yml @@ -71,6 +71,26 @@ jobs: --exclude vortex-bench --exclude lance-bench --exclude datafusion-bench --exclude vortex-datafusion \ --exclude compress-bench --exclude random-access-bench --exclude vortex-bench-server + # The multi-GiB regression tests are `#[ignore]`d, so every test job skips them by + # default and this step is the only place they run. This job is the one that covers + # every event: `Rust tests (linux-arm64)` is gated to the upstream repository and is + # skipped on pushes to develop, so gating them there would leave forks and develop + # untested. They are named explicitly rather than run with a bare `--run-ignored`, + # which would also un-ignore the CUDA tests that have no GPU here, and the cargo + # arguments match the step above so that nothing is rebuilt. The `slow-multi-gib` + # nextest test group keeps them from running concurrently, since each holds several + # GiB live. + - name: Run multi-GiB regression tests + shell: bash + run: | + cargo nextest run --cargo-profile ci --locked --workspace --no-fail-fast --run-ignored only \ + --exclude vortex-cuda --exclude vortex-cub --exclude vortex-nvcomp \ + --exclude gpu-scan-cli --exclude vortex-test-e2e-cuda --exclude vortex-python-cuda \ + --exclude vortex-duckdb --exclude duckdb-bench --exclude vortex-sqllogictest \ + --exclude vortex-bench --exclude lance-bench --exclude datafusion-bench --exclude vortex-datafusion \ + --exclude compress-bench --exclude random-access-bench --exclude vortex-bench-server \ + -E 'test(build_views_offsets_overflow_i32) + test(compress_large_int) + test(fsst_compress_offsets_overflow_i32)' + - name: Alert incident.io if: failure() && github.event_name == 'push' && github.ref == 'refs/heads/develop' uses: ./.github/actions/alert-incident-io diff --git a/encodings/fsst/src/tests.rs b/encodings/fsst/src/tests.rs index ad915e47158..00019927370 100644 --- a/encodings/fsst/src/tests.rs +++ b/encodings/fsst/src/tests.rs @@ -140,7 +140,7 @@ fn test_fsst_array_ops() { /// preserved. /// /// Allocates ~1.1 GiB for the input and ~2.1 GiB for the FSST output (~3.2 GiB total), so it is -/// ignored by default and run only by the "Rust tests (linux-arm64)" CI job. Setting +/// ignored by default and run only by the "Rust tests (linux-musl)" CI job. Setting /// `VORTEX_SKIP_SLOW_TESTS` at build time drops it from the binary, which is how the sanitizer /// jobs avoid compiling it at all. To run it locally (release mode, since debug builds make the /// allocation and compression loop substantially slower): @@ -152,7 +152,7 @@ fn test_fsst_array_ops() { /// [`fsst_compress`]: crate::compress::fsst_compress #[test_with::no_env(VORTEX_SKIP_SLOW_TESTS)] #[test] -#[ignore = "slow: allocates ~3.2 GiB, run by the \"Rust tests (linux-arm64)\" CI job"] +#[ignore = "slow: allocates ~3.2 GiB, run by the \"Rust tests (linux-musl)\" CI job"] fn fsst_compress_offsets_overflow_i32() { const STRING_LEN: usize = 64 * 1024; // Escape coding doubles every byte, so ~1.06 GiB of input compresses to ~2.13 GiB, diff --git a/vortex-array/src/arrays/varbinview/build_views.rs b/vortex-array/src/arrays/varbinview/build_views.rs index ee81970fea6..bf4a0179858 100644 --- a/vortex-array/src/arrays/varbinview/build_views.rs +++ b/vortex-array/src/arrays/varbinview/build_views.rs @@ -505,7 +505,7 @@ mod tests { /// `i32::MAX`, which the buffer-count and buffer-size assertions catch. /// /// Allocates ~2.25 GiB, so it is ignored by default and run only by the "Rust tests - /// (linux-arm64)" CI job. Setting `VORTEX_SKIP_SLOW_TESTS` at build time drops it from the + /// (linux-musl)" CI job. Setting `VORTEX_SKIP_SLOW_TESTS` at build time drops it from the /// binary, which is how the sanitizer jobs avoid compiling it at all. To run it locally /// (release mode, since debug builds make the allocation and fill loop substantially slower): /// @@ -516,7 +516,7 @@ mod tests { /// [`MAX_BUFFER_LEN`]: super::MAX_BUFFER_LEN #[test_with::no_env(VORTEX_SKIP_SLOW_TESTS)] #[test] - #[ignore = "slow: allocates ~2.25 GiB, run by the \"Rust tests (linux-arm64)\" CI job"] + #[ignore = "slow: allocates ~2.25 GiB, run by the \"Rust tests (linux-musl)\" CI job"] fn build_views_offsets_overflow_i32() { const STRING_LEN: usize = 64 * 1024; // Comfortably past MAX_BUFFER_LEN (`i32::MAX` ~= 2.0 GiB) so the heap must roll over. diff --git a/vortex-btrblocks/src/schemes/integer/tests.rs b/vortex-btrblocks/src/schemes/integer/tests.rs index 3645e3a05bc..047a6582ca5 100644 --- a/vortex-btrblocks/src/schemes/integer/tests.rs +++ b/vortex-btrblocks/src/schemes/integer/tests.rs @@ -131,7 +131,7 @@ fn test_rle_compression() -> VortexResult<()> { } /// Compresses 50M values, so it is ignored by default and run only by the "Rust tests -/// (linux-arm64)" CI job. Setting `VORTEX_SKIP_SLOW_TESTS` at build time drops it from the +/// (linux-musl)" CI job. Setting `VORTEX_SKIP_SLOW_TESTS` at build time drops it from the /// binary, which is how the sanitizer jobs avoid compiling it at all. To run it locally: /// /// ```text @@ -139,7 +139,7 @@ fn test_rle_compression() -> VortexResult<()> { /// ``` #[test_with::no_env(VORTEX_SKIP_SLOW_TESTS)] #[test] -#[ignore = "slow: compresses 50M values, run by the \"Rust tests (linux-arm64)\" CI job"] +#[ignore = "slow: compresses 50M values, run by the \"Rust tests (linux-musl)\" CI job"] fn compress_large_int() -> VortexResult<()> { const NUM_LISTS: usize = 10_000; const ELEMENTS_PER_LIST: usize = 5_000;