Add real DAOS-backed CI (build + test against a live DAOS instance)#71
Add real DAOS-backed CI (build + test against a live DAOS instance)#71brtnfld wants to merge 16 commits into
Conversation
… test suite) Add a daos-test job to CI that installs DAOS 2.6.5, builds HDF5 from source (matrixed over hdf5_1.14.6 and develop, the latter marked continue-on-error since it tracks a moving upstream target), builds the connector against it, and runs the full ctest suite (h5vl_test plus HDF5's own native/parallel test binaries ported to run against a VOL connector, plus the connector's own h5daos_test_* targets) against a live, ephemeral, single-node DAOS instance. Key pieces: - Rocky Linux 8 container running --privileged (required to disable transparent hugepages, which DAOS's SPDK housekeeping needs even with a pure-RAM storage tier). - test/scripts/daos_server.yml.in: RAM-emulated SCM storage tier sized and configured for small/CI hosts (system_ram_reserved lowered, scm_hugepages_disabled, nr_hugepages fixed). - test/scripts/daos_pool.sh.in: rewritten for the modern dmg CLI syntax, polling for engine join and pool queryability before signaling readiness to the test driver, to fix races where the harness would start the client before the pool was actually usable. - Excludes 3 known, tracked failures (h5_test_testhdf5, h5_partest_t_bigio, h5vl_ext_h5daos_test_metadata_parallel) so CI stays green on everything that's actually been verified so far - see the PR description for root-cause details on each. - .gitmodules: test/vol temporarily points at the brtnfld/vol-tests fork branch pending HDFGroup/vol-tests#67 merging; revert to HDFGroup/vol-tests once that lands.
1320795 to
99cfc1c
Compare
…ia CI testing Real, confirmed bugs found while exercising the connector against a live DAOS instance for the first time: - daos_vol_type.c / daos_vol_private.h / daos_vol_obj.c: H5_daos_dtype_t cached committed datatypes as a persistently-open hid_t, which looks identical to a user-visible open object to HDF5 core's native H5Fget_obj_count(H5F_OBJ_ALL, ...) accounting. Cache the datatype in its serialized (H5Tencode'd) form instead. - daos_vol.c: stop falsely advertising H5VL_CAP_FLAG_EXTERNAL_LINKS and H5VL_CAP_FLAG_UD_LINKS - H5_daos_link_create() hard-errors on H5VL_LINK_CREATE_UD (how H5Lcreate_external() is implemented internally by HDF5), so external/UD links were never actually supported despite the advertised flags. - daos_vol_link.c: reject H5Lcreate_hard() across two different files, matching the existing check already present in the H5Lmove/H5Lcopy path. - daos_vol_obj.c: handle H5I_ATTR in the H5VL_OBJECT_BY_SELF target-object resolution used by H5Oget_info and H5Ovisit, instead of type-punning the attribute's H5_daos_item_t header as a full H5_daos_obj_t. HDF5 2.0 (tracked by the develop branch) API compatibility: - daos_vol_private.h: add H5_VERSION_GE-gated macros for H5Tdecode (H5Tdecode1(buf) vs H5Tdecode2(buf, buf_size)) and for looking up this connector's own registered ID by class value (H5VLpeek_connector_id_by_value(), removed in 2.0, vs H5VLget_connector_id_by_value()). Update all 5 H5Tdecode call sites (daos_vol_attr.c, daos_vol_dset.c, daos_vol_map.c, daos_vol_obj.c) to use the new macro. Two fixes previously bundled here have been split out to their own branches/PRs: the H5Fget_obj_count/H5Fget_obj_ids container-label-vs- pointer comparison fix (obj-count-fix branch) and the H5_daos_link_ibco_task() creation-order-untracked fallback fix for H5Ovisit (best-effort-index-fix branch).
Points at the merged HDFGroup/vol-tests#67, which fixes test-driver robustness against benign DAOS log noise, gates known DAOS-specific test gaps on connector name rather than skipping unconditionally, and fixes HDF5 2.0 compatibility issues in the vendored test suite; and HDFGroup#68, which fixes an unrelated pre-existing CI workflow typo (ctest --build isn't a valid flag) discovered while investigating that suite's own CI status. .gitmodules is reverted to the upstream vol-tests URL now that both fixes have landed there.
17 is available in the same Ubuntu 24.04 (ubuntu-latest) universe repo
that already provides 14, and produces byte-identical output on every
file in src/*.c and src/*.h (verified against clang-format 14.0.6 and
17.0.6 directly) - only one trivial, cosmetic rule changed anywhere in
the repo (a space after "//" in a single commented-out line in
test/vol/hdf5_testpar/testpar.h). Drops the comment explaining the
13->14 bump, since that reasoning ("14 is the oldest still available")
no longer applies once jumping straight to the current version.
7edf419 to
c4360bd
Compare
h5vl_test now hits two known bugs: over-counting on repeated file opens, and H5Ovisit hard-erroring on a group without creation-order tracking. The first failure kills the shared DAOS server mid-run, cascading into most of the rest of the suite. Skip it here until those are resolved and reviewed.
| # CI runners have far fewer cores than "targets" below assumes; without | ||
| # this the engine refuses to start ("cannot start engine with 4 targets | ||
| # ... on 2 cores"). | ||
| - DAOS_TARGET_OVERSUBSCRIBE=1 |
There was a problem hiding this comment.
This is something that could easily be configured from CMake rather than using a hard-coded number of targets and oversubscribing
There was a problem hiding this comment.
Made this CMake-configurable: DAOS_SERVER_TARGETS cache var (defaults to 4), substituted into daos_server.yml.in. CI now passes -DDAOS_SERVER_TARGETS="$(nproc)" to match the runner's actual core count instead of hardcoding 4 targets + oversubscribing. Dropped DAOS_TARGET_OVERSUBSCRIBE entirely since it's no longer needed. ae17fad
| # Transport | ||
| set(DAOS_SERVER_TRANSPORT "ofi+sockets" CACHE STRING | ||
| "Transport used by DAOS server for testing (sm, ofi+sockets)." | ||
| # Note: libfabric removed the "sockets" provider (~1.16+); DAOS 2.6.x bundles |
There was a problem hiding this comment.
This comment seems useless as it talks about the old state that will no longer exist and will also basically become instantly out of date as DAOS versions move forward, but, having said that, this made me realize the top-level README.md needs updated to state which DAOS versions are supported and expected to be used with this VOL.
| assert(type_buf_len > 0); | ||
|
|
||
| /* Decode datatype */ | ||
| if ((dtype->type_id = H5Tdecode(p)) < 0) |
There was a problem hiding this comment.
There's an argument here as to whether it makes more sense to keep an ID for the datatype around and have to call H5Tencode() whenever you need the binary form, as opposed to keeping the binary form around and having to call H5Tdecode() whenever you need an ID. In the general case I think keeping the binary form around will be more efficient, but if switching to the binary form is just to avoid having an extra ID around for one of the API tests, I think it's a bit misguided and the test is making incorrect assumptions. There are any number of reasons for a VOL connector to keep an ID around and I believe they should be included in any ID counts made by an application as they aren't internal to HDF5 itself.
There was a problem hiding this comment.
Fair point - reverted to keeping the copied hid_t directly (as it was before this PR), rather than caching the encoded bytes. A VOL connector holding an ID for its own bookkeeping is legitimate and should be counted; not something worth working around here. b4dc0ad
| * for the lifetime of the process (see H5_DAOS_G_INIT below) - the extra | ||
| * held reference is intentional, not a leak, and if anything makes the | ||
| * cached ID safer against being invalidated by an unrelated unregister | ||
| * elsewhere. */ |
There was a problem hiding this comment.
The ID should probably still be closed in H5_daos_term() when H5VLget_connector_id_by_value() is used as it is still a leak and is not held for the life of the process, only for the lifetime of the DAOS VOL remaining initialized. Since H5VLget_connector_id_by_value() has existed since the beginning of the VOL, it can probably just be switched to and used unconditionally here.
There was a problem hiding this comment.
Switched to using H5VLget_connector_id_by_value() unconditionally (dropped the version-gated peek/get macro) and now release its reference in H5_daos_term() before forgetting H5_DAOS_g, so it's no longer held past the connector's own lifetime. 244ea63
There was a problem hiding this comment.
Update: the H5Idec_ref() call I added here caused a real crash - H5_daos_term() is invoked by the library while closing the last reference to this same ID, so decrementing it again from inside that callback recurses into still-being-torn-down state (surfaced as a tse_sched_progress: Assertion 0' failed` abort in DAOS's task scheduler on process shutdown, 100% reproducible in CI). Reverted the H5daos_term() close; kept the switch to H5VLget_connector_id_by_value() used unconditionally (that part was fine). 2596e9d
There was a problem hiding this comment.
Though it's very much an edge case, this is still a leak and needs to be closed in some cases to be clean. The termination function could be called outside of just the library terminating, which would leak the ID and also leave an incremented reference count on the associated connector object structure. The old comment about not needing to close the ID was only correct previously because the "peek" version of the function was used, which returns the ID directly without creating a new one. The "get" version of the function directly says that a new ID is returned and should be closed with H5VLclose() (not H5Idec_ref(), though they're functionally the same currently). H5is_library_terminating() might be usable here, though that does seem like hacking around design issues and it also still has to be known whether H5_DAOS_g was actually initialized by H5VLget_connector_id_by_value() or somewhere else. Probably not worth worrying about right now, but it is a design problem that could cause issues.
There was a problem hiding this comment.
Agreed it's a real gap, and appreciate you spelling out exactly what a correct fix would need - that's more precise than I'd worked out. Since a wrong attempt here already caused a confirmed, 100%-reproducible crash (the tse_sched_progress abort), and you've already flagged this as low-priority for now, I've documented the tradeoff in both places (why closing unconditionally isn't safe, and the two things a real fix needs: H5is_library_terminating() plus a way to know whether H5_DAOS_g came from H5_DAOS_G_INIT() specifically vs. H5Pset_fapl_daos()'s registration/name-lookup paths) rather than attempt a fix blind. Filed #74 to track it. dc61172
| # - h5vl_test: fails on two known bugs, tracked separately. | ||
| run: > | ||
| ctest --test-dir build --output-on-failure --timeout 300 | ||
| -E '^(h5_test_testhdf5|h5_partest_t_bigio|h5vl_ext_h5daos_test_metadata_parallel|h5vl_test)$' |
There was a problem hiding this comment.
I believe the last time testing was done the h5vl testing was separated by parts (file, group, dataset, etc.) so you might be able to skip just the parts that have failing tests and get at least some of the main serial testing working.
There was a problem hiding this comment.
Good call - enabled HDF5_VOL_TEST_ENABLE_PART, which registers h5vl_test as one ctest entry per area (attribute, dataset, file, group, link, misc, object, ...), each spawning its own DAOS server. CI now excludes only h5vl_test_file and h5vl_test_object (the two areas hitting the known bugs) instead of skipping the whole suite - the rest run normally. ae17fad
There was a problem hiding this comment.
Update: went with a more surgical approach in the end instead of PART-mode splitting - h5vl_test doesn't actually crash or cascade (a run showed 807/896 checks passing before it was excluded), it was just getting marked FAILED wholesale because the driver treats any "FAILED" substring as fatal with no way to mark individual checks as known-broken. Gated the two actual failing checks at the source in vol-tests instead (HDFGroup/vol-tests#70), so h5vl_test runs as a single ctest entry again and passes clean (100% tests passed, 0 failed, confirmed in CI). e87ffde
…area Expose DAOS_SERVER_TARGETS as a CMake cache variable instead of hard-coding the engine to 4 targets and papering over CI's smaller core count with DAOS_TARGET_OVERSUBSCRIBE; CI now passes -DDAOS_SERVER_TARGETS="$(nproc)" to match the runner it's actually on. Enable HDF5_VOL_TEST_ENABLE_PART so h5vl_test is registered as one ctest entry per functional area (attribute, dataset, file, group, ...) instead of a single binary, each against its own DAOS server instance. CI now excludes only the two known-broken areas (h5vl_test_file, h5vl_test_object) instead of skipping the whole suite, since a crash in one area no longer takes the rest down with it. Also drops two CMake comments that only described now-removed CLI flags and provider names with no remaining bearing on the current config.
The libdaos prerequisite only listed a years-old minimum version with no indication of what's actually exercised now that CI builds and runs the test suite against a live DAOS instance.
H5_DAOS_G_INIT() previously used H5VLpeek_connector_id_by_value() on HDF5 <2.0 (no owned reference) and H5VLget_connector_id_by_value() on >=2.0 (which does take one) via a version-gated macro, but H5_daos_term() unconditionally just discarded H5_DAOS_g without releasing that reference. H5VLget_connector_id_by_value() has been available since the VOL's introduction, so use it unconditionally and drop the peek/get macro, and release its reference in H5_daos_term() before forgetting the ID.
0b50093 switched H5_daos_dtype_t to cache committed datatypes in their H5Tencode'd form, to keep a live hid_t from inflating H5Fget_obj_count(H5F_OBJ_ALL, ...)'s count. Per review, a VOL connector holding an ID for its own object bookkeeping is legitimate and expected to be counted, so revert to keeping the copied hid_t directly (as before 0b50093), while keeping the H5_DAOS_TDECODE macro for HDF5 2.0's H5Tdecode1/H5Tdecode2 split.
…of skipping it h5vl_test doesn't crash or cascade - the prior run (before it was excluded) completed with 807/896 (90%) internal checks passing; the ctest entry was only marked FAILED because the driver treats any "FAILED" substring in output as fatal, with no way to mark individual checks as known-broken from outside the test binary. Gate the two specific failing checks (overlapping-file-opens object count, and H5Ovisit(_by_name) by creation order on an untracked root group) on the connector name in vol-tests itself (HDFGroup/vol-tests#70), matching the existing pattern already used in that file. .gitmodules points at the fork branch until the PR merges upstream. Revert the h5vl_test PART-mode split and CI exclusion from the last two commits - no longer needed since h5vl_test runs clean as a single test now.
… in CI Every single test in the last run failed identically: server starts, storage formats, but the engine never reports "Joined" within the pool script's 30s poll window - reproducible on the very first test, ruling out resource exhaustion from repeated cycles. The only infra-relevant change was replacing the hardcoded targets=4 + DAOS_TARGET_OVERSUBSCRIBE=1 with -DDAOS_SERVER_TARGETS="$(nproc)" and no oversubscribe: unlike a plain too-many-targets mismatch (which makes the engine refuse to start immediately with a clear error), nproc apparently doesn't reflect the actually-usable core count in this container, and without the oversubscribe fallback the engine hangs during startup instead. Restore DAOS_TARGET_OVERSUBSCRIBE=1 as an unconditional safety net and drop CI's nproc override, falling back to the proven-working default of 4 targets. DAOS_SERVER_TARGETS remains CMake-configurable for anyone who wants to tune it explicitly.
Every test in the last CI run crashed identically on process shutdown after otherwise completing cleanly: "h5vl_test: src/common/tse.c:775: tse_sched_progress: Assertion '0' failed" (SIGABRT). Root cause: H5_daos_term() is invoked by the library while closing the last reference to H5_DAOS_g itself, so calling H5Idec_ref() on that same ID from within the callback recurses into still-being-torn- down library state, corrupting the DAOS task scheduler on the way out. Keep H5_DAOS_G_INIT()'s switch to H5VLget_connector_id_by_value() (still correct - it works the same on both HDF5 <2.0 and >=2.0, so the version macro was unnecessary), but revert closing that reference in H5_daos_term(); the original code's "no need to close it here" was right.
jhendersonHDF flagged (PR HDFGroup#71) that H5_daos_term() not releasing the H5VLget_connector_id_by_value() reference is a real leak in the case where term() is reached outside of the ID's own refcount hitting zero - just not one worth chasing right now. Document why closing it unconditionally already caused a confirmed crash, and what a correct fix would actually require (H5is_library_terminating() plus a way to know H5_DAOS_g's provenance), rather than leaving the tradeoff implicit. Tracked in HDFGroup#74.
Fixes #69
Summary
Adds a
daos-testCI job that installs DAOS 2.6.5, builds HDF5 from source (matrixed overhdf5_1.14.6anddevelop), builds the connector against it, and runs the full test suite against a live, ephemeral, single-node DAOS instance. Previously this repo's CI only ran a clang-format check - there was no automated correctness signal against a real DAOS backend at all.Along the way, found and fixed several real connector bugs and HDF5 2.0 API compatibility issues (see the second commit for full details on each), and contributed two fixes upstream to HDFGroup/vol-tests (#67, #68, both merged) - one gating known DAOS-specific test gaps on connector name instead of skipping them unconditionally (so other VOL connectors sharing that suite aren't affected), one fixing an unrelated pre-existing CI script typo discovered along the way.
Current status
hdf5_1.14.6leg: 100% passing (9/9 tests that run; see "Known non-blocking issues" below for the 3 excluded).developleg:continue-on-error- HDF5'sdevelopbranch is a moving target tracking an upcoming 2.0 release; this leg surfaces real signal but isn't required to pass.Known non-blocking issues (excluded from
ctestvia-E, tracked separately)h5_test_testhdf5: a real, previously-undiscovered connector bug in paginated attribute name/index resolution (daos_vol_attr.c), only triggered once a group holds hundreds of attributes - no existing test in this suite exercised that scale before.h5_partest_t_bigioandh5vl_ext_h5daos_test_metadata_parallel(timeout): most likely DAOS RAM-backed storage exhaustion from running ~12 sequential DAOS server/pool instances in one CI container (aDER_NOSPACEerror appears in the DAOS client log right aroundt_bigio's failure window) rather than a connector bug, but not yet confirmed either way.None of these were reachable before this PR, since there was no DAOS-backed CI at all.