Repository navigation
Conversation
Codex now compresses every rollout idle for seven days to a sibling rollout-*.jsonl.zst and deletes the .jsonl. On a real machine that took 1,288 managed sessions out of the store, dropped the saved figure from 69% to 38%, and left 3,623 .zst files (24.2 GB) that CodexFold never touched. The service now folds each settled .zst in place. libzstd 1.5.7, the version Codex links (via github.com/DataDog/zstd), re-encodes the decoded content to the file's exact bytes; that is proven per file, the content is folded into the store, a marker attribute binds the file to its manifest, and its data blocks are released with a hole punch. Path, inode, size, mode and times are kept. The mount re-encodes on read, refuses writes, hides the marker and fails with EIO rather than serve empty blocks. All 3,623 real files reproduce byte for byte. Unreferenced manifests are released after two scans fifteen minutes apart; a file that lost its marker is found by inode and re-marked. `fs native-zst restore` writes the original bytes back before a downgrade. Folding no longer needs room for its pessimistic peak first: - .zst content is folded straight from the decoder, priced by a dry run when space is short, and a small-peak fold that frees four times as much may run down to 1 GiB free. - Pack builds rewrite only the old pack files worth it that fit the free space and hard-link the rest; dropped objects no longer force copying the whole pack, and dead pack bytes trigger a later build once there is room. - The enrollment planner asks for a cached dry-run price when the 3x raw estimate does not fit; `fold --apply` measures the same way, and pack estimates price loose objects by their compressed size. Also: deleted sessions now trigger a compacting build (maintenance only looked at top-level manifests newer than the pack), pack blocks use SpeedBetterCompression and stay raw only when compression does not help, and the storage figures count the native session tree.
A rollout that shares nothing with the store folds larger than Codex's own zstd: content-defined chunks compress independently, so a real 205 MB rollout needed 83.5 MB against its 68.6 MB .zst. Every file is now priced by a dry run first and folded only below 80% of its .zst; the savings come from content shared with other sessions, which per-file zstd cannot see. Loose objects use the pack builder's compression level through one shared encoder; SpeedDefault left entropy-only text nearly uncompressed, which also overpriced the dry run.
The FSKit extension prefetches a file through several handles at once, each taking whichever block is next. With an encoder per handle, every handle re-encoded the frame from its start and a read behind a handle's window restarted it, so a folded 1.4 GB rollout read through the mount at about 0.5 MB/s. All readers of a file now share one encoder whose output is spilled to an unlinked temporary file as it is produced, so each byte is encoded once in whatever order and through whatever handle it is read. The encoder only runs as far as reads ask plus 8 MiB, so listing threads still reads just their heads. A stream that produced little is dropped at close; a large one is kept two minutes for a reopen. Proofs and restores read sequentially and use a direct stream that spills nothing. Four handles reading a real 325 MiB folded file out of order now take 5.3 s.
The FSKit extension runs with launchd's 256-descriptor soft limit. A folded .zst has no native descriptor, so the daemon handed it a shared read window, and a window makes the extension prime up to nine prefetch channels on open, each with its own socket and window descriptor: about fourteen descriptors per open file. A few concurrent readers (Codex resuming a thread while another tool scanned rollouts) pushed the extension past the limit and every mount read failed with EMFILE. The daemon no longer offers a shared window for a folded handle, so opening one primes nothing. The extension raises its descriptor soft limit at start and bounds prefetch channels across all open files to 48; a file that gets none is still read through its own handle. Also stop re-proving the same .zst every pass: APFS can keep some extents of a hole-punched file allocated, so a fold that frees nothing more is remembered by size and mtime and left alone until the file changes, and only bytes actually released are counted as freed.
When a managed session is deleted, its native snapshot can stay at its route, and the mount deliberately hides it. The canonical readiness probe required every native file to be visible in the mount, so one such leftover failed it permanently: - automatic enrollment saw "mount warming" on every cycle and enrolled nothing new; - `fs service start` timed out on its health gate and rolled back. The probe now skips the routes of deletion tombstones, the same set the mount hides at startup. A failed native FSKit start also left the supervisor's mount attached after stopping both jobs, so every read in it failed with no backend. It now reclaims the mount the way an explicit stop does. Bump the FSKit App build to 117 for the descriptor-limit extension fix.
Linux accepts only namespaced extended attribute names, so the fixture's com.example.kept failed there with ENOTSUP; use user.example.kept. Move the xattr calls behind platform test helpers so the package's tests compile for Windows, where these folds are not supported and skip.
ext4 and XFS count a block of extended attributes in st_blocks, and the fold marker itself is one, so a fully punched file still reports one block there. Treating that as unreleased made every service start re-prove each folded file and kept a file that lost its marker from being re-marked. A file now counts as released when its allocation is within one filesystem block on Linux; APFS does not count attributes, so macOS still requires zero.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Codex now compresses every rollout that has been idle for seven days into a sibling
rollout-*.jsonl.zstand deletes the.jsonl. That pulled sessions out of the store one by one. On a real machine, the saved figure fell from 69% to 38%, and 3,623.zstfiles held 24.2 GB that CodexFold never touched. This branch has the service fold those files too, keeps folding working when the disk is nearly full, and fixes three production faults found while running it.Folding Codex
.zstfilesEach settled
.zstis folded in place:github.com/DataDog/zstd) must re-encode the decoded content to the file's exact bytes..zst.fs native-zst statusandfs native-zst restore --all --applyare added. Run the restore before installing a build without this support.Folding on a tight disk
.zstfolds. A.zstis folded straight from its decoder instead of staging its decoded content.fold --applymeasure the real cost instead of assuming three times the raw size. Prices are cached inenrollment/prices.json.Production fixes
.zstre-punched every 30 s. APFS kept a few extents of one punched file allocated, so it was proved and punched again on every pass. It is now left alone until it changes.mount-warmingfor 1,626 sessions and enrolled nothing.Validation
go vet, Go tests forcli,mountfs,nativezst,vfs,enroll,packandcodexzstd, and Windows and Linux cross-builds.ReadCacheTests, and a type check of the extension.Windows
.zstcode compiles for Windows, but Windows does not fold.zstfiles yet: in-place folding needs hole punching and marker attributes.