fix(cache): re-add cacache.verify() to garbage collect orphaned content from put() overwrites - #44987
Open
bbodenmiller wants to merge 4 commits into
Open
fix(cache): re-add cacache.verify() to garbage collect orphaned content from put() overwrites#44987bbodenmiller wants to merge 4 commits into
bbodenmiller wants to merge 4 commits into
Conversation
…nt from put() overwrites
zharinov
approved these changes
Jul 31, 2026
zharinov
left a comment
Collaborator
There was a problem hiding this comment.
I approve but needs prettier fix
bbodenmiller
commented
Aug 2, 2026
bbodenmiller
commented
Aug 2, 2026
Contributor
Author
@zharinov thanks, fixed |
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.
Changes
Re-add
cacache.verify()to thedestroy()method to garbage collect content blobs orphaned bycacache.put()overwrites.When
cacache.put()is called with an existing key but different data (e.g., a version lookup result changes because a new release was published), cacache writes a new content blob and updates the index entry to point to it, but does not remove the previous content blob. Over many scheduled runs with many dependencies, these orphaned blobs accumulate indefinitely incontent-v2/.rm.content(added in #29860 whenverify()was removed) only removes content when an entryexpires. It does not handle orphans created by overwrites of still-live keys.
On a self-hosted instance running scheduled scans of ~100 repos over several months, the cache grew to multiple GB of orphaned content while the actual referenced data was only ~16 MB. Running
cacache.verify()reclaimed ~5 GB by removing ~565k unreferenced content blobs. After GC, Renovate's cache behavior was unchanged (verified: identical package cache hits, HTTP request counts, and lookup results before and after).Performance
The concern in #29795 was that
verify()is slow. However:verify()completes in under 1 second (~260ms for ~500 entries in testing)verify(), the cache grows until it causes CI cache upload failures (exceeding S3 size limits), pod evictions from ephemeral storage exhaustion, and minutes-long cache restore times — all worse than a sub-second GC passContext
Please select one of the following:
Related:
cacache.verify()to fix cacache cleanup doesn't return diskspace #28169verifystep #29795 / refactor(cache): userm.contentto remove expired content #29860 — removedverify()for performance, replaced withrm.contentper expired entry (does not cover put() orphans)filebackend #42543 — open PR with alternative GC approach (tracks digests during sweep, but does not handle pre-existing orphans)AI assistance disclosure
Did you use AI tools to create any part of this pull request?
Please select one option and, if yes, briefly describe how AI was used (e.g., code, tests, docs) and which tool(s) you used.
Investigation and drafting assisted by Claude. Root cause analysis, testing on real self-hosted instance, and code change were done collaboratively.
Documentation (please check one with an [x])
How I've tested my work (please select one)
I have verified these changes via:
Tested
cacache.verify()on a real self-hosted GitLab instance across three job types (local scan, 50-repo dry run, 100+ repo dry run). For each: ran cold (no cache), warm (with cache), GC, then warm again. Cache metrics (package cache gets/sets, HTTP requests) were identical between warm and warm-after-GC runs, confirming GC does not affect cache functionality.