Skip to content

Shared-layer lifecycle: accounting, eviction, recovery, materialization - #458

Open
chruffins wants to merge 6 commits into
hypeship/rootfs-compositionfrom
hypeship/storage-lifecycle
Open

chruffins wants to merge 6 commits into
hypeship/rootfs-compositionfrom
hypeship/storage-lifecycle

Conversation

@chruffins

@chruffins chruffins commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

summary

Adds the runtime consumer for shared image layers while preserving Hypeman's two-disk VM contract.

  • Shared base disks: images with multiple layers compose every layer except the final layer into a content-addressed read-only base disk under images/bases/.
  • Per-instance final layer: the final layer is materialized into the VM's writable overlay disk under upper/. The VM still receives one read-only rootfs disk and one writable overlay.
  • Build fallback: unsupported hosts, single-layer images, corrupt artifacts, and failed materialization use the existing flattened rootfs path.
  • Artifact lifecycle: final-layer artifacts and shared bases use in-flight leases, keyed singleflight, grace-period cleanup, reference scanning, startup recovery, and disk accounting.
  • Overlay capacity: image data is added to the physical overlay allocation while the caller-facing writable capacity remains unchanged. Admission reservations use the physical size.
  • Promotion and recovery: layered rootfs links are recreated relative to their destination during legacy-to-content promotion, and runtime manifest lookup follows the authoritative image layout.
  • Observability: image build phases distinguish shared-base export from flattened filesystem export.
  • CI reliability: EROFS artifacts are extracted with fsck.erofs instead of loop-mounted, layered overlay roots retain searchable 0755 permissions, and interrupted netlink dumps retry under parallel test load.

validation

  • Full CI is green: Linux tests, Darwin tests, and install E2E pass.
  • Targeted Linux end-to-end validation confirms nginx content is reachable through the layered rootfs and ingress path.
  • Image package tests pass on a root-capable Linux host with EROFS support.
  • Rootless local package tests cover manifest validation, shared-base hashing, lifecycle accounting, and legacy promotion; native mount tests require host privileges.
  • Storage and disk-I/O benchmarks show the composition prerequisite does not increase the flattened path's disk footprint or I/O. Representative shared-base runtime benchmarks remain required before production rollout.

rollout

Do not enable this path in production until storage and disk-I/O benchmarks are run against representative multi-layer images. The flattened path remains the fallback for hosts without native layer-artifact support.

  • Host-storage alert fix: runtime overlay preparation no longer creates transient read-only loop mounts for EROFS layer artifacts, avoiding false full-filesystem alerts on the host.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 33c8ca3. Configure here.

Comment thread lib/images/layer_gc.go
info, statErr := os.Stat(dirPath)
if statErr != nil || info.ModTime().After(cutoff) {
continue
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eviction can wipe in-flight layers

Medium Severity

Layer eviction decides freshness from the digest directory ModTime, and it runs concurrently with materialization. Unpack and mkfs.erofs write inside child temp dirs, so the parent mtime goes stale; DeleteImage can then RemoveAll that tree while a build is still using it, especially during the later unlocked ExportRootfs window before the manifest is written.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 33c8ca3. Configure here.

Comment thread lib/images/manager.go Outdated
if result.CacheHit {
cacheStatus = "hit"
}
m.recordImageBuildPhase(ctx, ref.Digest(), "layer_materialization", time.Since(materializeStart), "success", cacheStatus)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Layer bytes skipped after failed builds

Medium Severity

Materialized layer artifacts are written to the layer store before conversion, but refreshDiskUsageTotals only runs on successful finalize, delete, or startup. After a failed conversion the artifacts remain on disk while TotalImageBytes keeps the stale cached total, so capacity admission undercounts the real footprint.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 33c8ca3. Configure here.

@chruffins
chruffins force-pushed the hypeship/storage-lifecycle branch from 41f4080 to 35de95e Compare August 26, 2026 18:22
@chruffins
chruffins force-pushed the hypeship/storage-lifecycle branch from 35de95e to f9a5fcc Compare August 26, 2026 18:46
@chruffins
chruffins force-pushed the hypeship/storage-lifecycle branch from d9caa0e to b0a27b4 Compare August 26, 2026 18:51
@chruffins
chruffins force-pushed the hypeship/storage-lifecycle branch from b0a27b4 to 37b8128 Compare August 26, 2026 18:52
@chruffins
chruffins force-pushed the hypeship/storage-lifecycle branch from 37b8128 to 13adf76 Compare August 26, 2026 18:53
@chruffins
chruffins force-pushed the hypeship/storage-lifecycle branch from 13adf76 to c0e6c32 Compare August 26, 2026 18:54
@chruffins
chruffins force-pushed the hypeship/storage-lifecycle branch from c0e6c32 to aac8b57 Compare August 26, 2026 18:55
@chruffins
chruffins force-pushed the hypeship/storage-lifecycle branch from aac8b57 to 7464627 Compare August 26, 2026 18:56
@chruffins
chruffins force-pushed the hypeship/storage-lifecycle branch from 4467fe9 to 588fff8 Compare August 26, 2026 18:58
@chruffins
chruffins force-pushed the hypeship/storage-lifecycle branch from ac3de8e to 165e42f Compare August 26, 2026 19:30
@chruffins
chruffins force-pushed the hypeship/storage-lifecycle branch from 165e42f to 3cac19c Compare August 26, 2026 19:38
@chruffins
chruffins force-pushed the hypeship/storage-lifecycle branch from 8ca57c1 to 419c294 Compare August 26, 2026 19:41
@chruffins
chruffins force-pushed the hypeship/storage-lifecycle branch 2 times, most recently from c238f03 to 5051c46 Compare August 26, 2026 19:49
@chruffins
chruffins force-pushed the hypeship/storage-lifecycle branch from 466f089 to 0fa6aa6 Compare August 31, 2026 22:35
@chruffins
chruffins force-pushed the hypeship/storage-lifecycle branch 2 times, most recently from 78e404c to 0e1b801 Compare August 31, 2026 23:12
@chruffins
chruffins force-pushed the hypeship/storage-lifecycle branch from 0e1b801 to 888f303 Compare August 31, 2026 23:36
@chruffins
chruffins force-pushed the hypeship/storage-lifecycle branch from 888f303 to 197ed4c Compare September 1, 2026 16:06
@chruffins
chruffins force-pushed the hypeship/storage-lifecycle branch from 197ed4c to 72814fb Compare September 1, 2026 18:56
@chruffins
chruffins force-pushed the hypeship/storage-lifecycle branch from e6597bd to fe533bb Compare September 3, 2026 12:50
@chruffins
chruffins force-pushed the hypeship/storage-lifecycle branch from fe533bb to 962f4d2 Compare September 3, 2026 13:54
@chruffins
chruffins force-pushed the hypeship/storage-lifecycle branch from 962f4d2 to 2250812 Compare September 3, 2026 14:02
@chruffins
chruffins force-pushed the hypeship/storage-lifecycle branch from 2250812 to 3787792 Compare September 3, 2026 14:06
Materializes each manifest layer after a pull so sharing degrades instead
of failing the build. Artifacts unreferenced by any manifest model are
evicted, protected by a grace period and by in-flight references held
until the referencing model is durable. Startup sweeps stale staging
directories and orphans left by an unclean shutdown. Evictions are counted
as hypeman_images_layer_artifacts_evicted_total.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant