Repository navigation
fix(oci): drop a moved tag from its previous manifest's tag set - #1469
Merged
Merged
Conversation
resolver.Memory.Tag overwrote the forward index entry for a reference but never removed the reference from the reverse index of the descriptor it previously pointed to. oci.Store.isTagged reads that reverse index, so Delete with AutoGC treated a manifest whose tag had moved away as still tagged and left it, and the blobs only it referenced, on disk until an explicit GC. Remove the reference from its previous descriptor's tag set before adding it to the new one, dropping the set once it is empty as Untag does. Fixes oras-project#1468 Signed-off-by: ctxloop <148732717+ctxloop@users.noreply.github.com>
ctxloop
requested review from
TerryHowe,
Wwwsylvia,
sabre1041 and
shizhMSFT
as code owners
September 27, 2026 19:35
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1469 +/- ##
==========================================
- Coverage 91.13% 91.12% -0.01%
==========================================
Files 98 98
Lines 7614 7619 +5
==========================================
+ Hits 6939 6943 +4
- Misses 664 665 +1
Partials 11 11 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This was referenced Sep 28, 2026
Merged
TerryHowe
pushed a commit
that referenced
this pull request
Sep 28, 2026
… (#1475) resolver.Memory.Tag overwrote the forward index entry for a reference but never removed the reference from the reverse index of the descriptor it previously pointed to. oci.Store.isTagged reads that reverse index, so Delete with AutoGC treated a manifest whose tag had moved away as still tagged and left it, and the blobs only it referenced, on disk until an explicit GC. Remove the reference from its previous descriptor's tag set before adding it to the new one, dropping the set once it is empty as Untag does. Fixes #1468 (cherry picked from commit c3de6f8) Signed-off-by: ctxloop <148732717+ctxloop@users.noreply.github.com>
Closed
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.
resolver.Memory.Tagoverwrites a reference's forward entry but leaves the reference in the reverse tag set of the descriptor it previously pointed to.oci.Store.isTaggedreads that tag set, soDeletewithAutoGCkeeps a manifest whose tag has moved to another manifest, along with the blobs only it references, until an explicitGC(). Details and reproduction are in #1468.The fix removes the reference from its previous descriptor's tag set before adding it to the new one, and drops that set once it is empty, as
Untagdoes. It runs under the same lock as the rest ofTag, so a concurrentResolvesees the reference pointing to either the old or the new descriptor, never to neither.Tests
Both tests fail on
main@ a0f6556 without the fix and pass with it.TestTagSetRetag(internal/resolver) moveslatestfrom one descriptor to another and checks both tag sets:TestStore_DeleteWithAutoGCAfterRetag(content/oci) pushes an index I referencing manifest A, moveslatestfrom A to manifest B, and deletes I. Before the fix, A and its layerfooremain:It also checks that B, its layer, the shared config and
latest→ B are left intact.Dropping the emptied set is exercised by
TestTagSetRetagbut not asserted, sinceTagSetreturns an empty set either way. It only keepsm.tagsfrom accumulating empty entries.make testpasses, including-race.v2
The reverse index dates from #680, so
v2has had the same bug since v2.4.0, and both tests fail the same way there. I can send a backport once this is merged.Fixes #1468