Repository navigation
Description
Why
An ESP32 build on a disk-constrained machine should either work or fail with something actionable. Today it does neither: fbuild can measure free space, never checks it, and when the disk fills the user gets a raw ENOSPC out of whichever subprocess happened to write next.
Follow-up from the ESP32 orchestrator work in #1730.
What happens today (evidence)
fbuild already knows how to measure free space, and no code uses it.
pub fn volume_facts(path: &Path) -> std::io::Result<VolumeFacts>—crates/fbuild-core/src/platform/fs.rs:180, withVolumeFacts.available_spaceat:24, implemented per-OS (linux/fs.rs:138,macos/fs.rs:157viastatvfs,windows/fs.rs:291viafs2).- A workspace-wide grep for
volume_facts/available_spaceoutsidecrates/fbuild-core/src/platform/returns only vendored third-party crates (zccache, kernal_api, sysinfo, fs2). There is no pre-flight space check anywhere in fbuild.
ESP32 is the most disk-hungry path, and its caches are only reclaimable by hand.
- Framework core objects are content-addressed global artifacts and are hydrated even on
--clean;--clean-allis the explicit cache-eviction path (crates/fbuild-build-esp/src/esp32/orchestrator/build.rs:585-588). - The blob/
.lnkdisk cache is authoritative — the code notes the GC can't reap a blob mid-build (build.rs:780-783) — and the embed stage hard-fails when the cache is unavailable (orchestrator/embed_stage.rs:39). - A warm esptool install can be evicted by the daemon's background GC mid-build, producing an
elf2imageENOENT (ci(esp32): daemon background GC evicts warm esptool install mid-build — elf2image ENOENT #1341). - Toolchain downloads have no resume: a failure at ~90 MB restarts from zero (Toolchain download restarts from zero at ~90MB and never completes (no resume) #1370).
So a full disk shows up as an ENOSPC from a downloader, linker or subprocess, with no statement of how much is needed, on which path, or what could be freed.
Proposal
- Measure the requirement. Record the peak disk delta of a cold ESP32 build (toolchain + framework libs + zccache + project build dir) and publish a documented minimum per platform. Keep the measured footprint per stage so the estimate tightens as data accumulates.
- Pre-flight check. Before resolving packages, call
volume_facts()on every root that will be written (cache root, workspace, temp) and fail fast with an actionable error: the path, free vs required, the shortfall, and the largest reclaimable caches. On a healthy machine emit a single info line. - Reclaim on demand — never silently, never mid-build. An explicit, budgeted path that evicts disposable caches in a fixed order (warm toolchain/esptool installs → framework libs cache → blob/
.lnkcache → zccache LRU per its existing budget), reusing the disk-cache budgets from Two-phase disk cache (archives + installed) with LRU GC, sized budgets, and crash-safe SQLite index #20 rather than inventing new policy, and reporting bytes freed. ci(esp32): daemon background GC evicts warm esptool install mid-build — elf2image ENOENT #1341 is the cautionary tale for when this may run. - Translate
ENOSPCwhen it still happens into that same actionable error, at the downloader, linker and subprocess boundaries. - Optional:
fbuild doctor/--check-disk— print per-root free space and reclaimable totals without building. - Worth copying: the sibling
running-processcrate already ships anENOSPCdelete-to-recover emergency reserve (track(platform): assess W600 FastLED build support #390). Pre-flight alone cannot cover a build that grows after the check.
Non-goals
- No automatic eviction of warm caches during a normal build.
- No silent degradation (dropping suites, lowering quality) to fit — if it does not fit, say so.
- No change to download or install semantics.
Acceptance criteria
- A cold ESP32 build with ample space logs one info line and behaves exactly as today.
- On a constrained host the build fails before package resolution, naming the path, the shortfall, and the reclaimable bytes.
- With reclaim enabled, the build completes after freeing at least the shortfall, and the log states what was evicted.
- An injected
ENOSPCfrom a downloader/linker surfaces as that same message, not a raw io error. - Tests: mocked-threshold unit tests; an integration test pointing the cache root at a small tmpfs asserting the fail-fast message; a test that the reclaim order is honoured and never runs mid-build; a test that a roomy build's log is unchanged apart from the info line.
Related
#20 (two-phase disk cache, LRU GC, sized budgets), #952 (framework libs core cache never hydrates), #1341 (GC evicts a warm esptool install mid-build), #1370 (toolchain download has no resume), #1539, #1730 (the ESP32 orchestrator guard this check would sit beside).
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsTriage
Activity
feat(disk): release a pre-committed reserve when a build hits ENOSPC (#…
zackees commentedon Oct 28, 2026
All six proposal items have landed; closing with the map.
4eee75f0—fbuild_build_engine::disk_footprint,FBUILD_DISK_FOOTPRINT[_JSON]; measured cold ESP32 peaks (Xtensa ~3.9 GiB, RISC-V ~4.9 GiB) setESP32_CACHE_BYTES= 5 GiB8b6e6d83—disk_preflight; fail-fast names path, free vs required, shortfall and the largest reclaimable caches; a roomy build logs one info line9bf53ed5—fbuild cache reclaim [--needed] [--dry-run] [--cache-dir], fixedRECLAIM_ORDER, refuses to run whiledaemon_status.jsonreportsoperation_in_progress3bf4c228—fbuild_core::disk_full, same message as pre-flightfbuild doctor --check-diskfa1e3c15— per-root free space and reclaimable totals, no build39a96f03—fbuild_core::disk_reserve, 32 MiB real bytes committed pre-flight, released only on an ENOSPC signature, re-armed next buildAcceptance-criteria status:
disk_preflight_tests.rs:short_root_fails_with_path_required_and_shortfall,failure_names_reclaimable_caches_largest_first).ample_space_is_sufficient_and_prints_one_line).a_tool_enospc_is_translated_and_lists_reclaimable_caches, plus the downloader tests).reclaim_tests.rsorder test,cache_reclaim_tests.rsbusy-daemon refusal).Non-goals were respected: no automatic eviction during a normal build, no silent degradation.
— fbuild steward (automated)