Skip to content

Commit

Permalink
Use BlobInfoCache to share more layers if (TOC->Uncompressed) mapping…
Browse files Browse the repository at this point in the history
… is known

- Multiple TOC values might correspond to a single DiffID (e.g. if different
  compression levels are used); try to share them all, identified by DiffID
  (so that we also reuse with non-TOC pulls).
  - LayersByTOCDigest only uses a single TOC digest per layer; BlobInfoCache
    allows multiple matches, matches layers which have been since deleted,
    and potentially matches TOC digests which we have created by pushing
    but haven't pulled yet.
- On reuse, we can now use DiffID-based layer identities even if the reuse
  was TOC~driven.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
  • Loading branch information
mtrmac committed Mar 25, 2024
1 parent 01e8b23 commit 85ce7a7
Showing 1 changed file with 18 additions and 0 deletions.
18 changes: 18 additions & 0 deletions storage/storage_dest.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,8 +327,13 @@ func (s *storageImageDestination) PutBlobPartial(ctx context.Context, chunkAcces

s.lock.Lock()
if out.UncompressedDigest != "" {
s.lockProtected.indexToDiffID[options.LayerIndex] = out.UncompressedDigest
if out.TOCDigest != "" {
options.Cache.RecordTOCUncompressedPair(out.TOCDigest, out.UncompressedDigest)
}
// The computation of UncompressedDigest means the whole layer has been consumed; while doing that, chunked.GetDiffer is
// responsible for ensuring blobDigest has been validated.
// So, record also information about blobDigest, that might benefit reuse.
s.lockProtected.blobDiffIDs[blobDigest] = out.UncompressedDigest
} else {
// Don’t identify layers by TOC if UncompressedDigest is available.
Expand Down Expand Up @@ -460,6 +465,19 @@ func (s *storageImageDestination) tryReusingBlobAsPending(blobDigest digest.Dige
}

if options.TOCDigest != "" && options.LayerIndex != nil {
// Check if we know which which UncompressedDigest the TOC digest resolves to, and we have a match for that.
// Prefer this over LayersByTOCDigest because we can identify the layer using UncompressedDigest, maximizing reuse.
if uncompressedDigest := options.Cache.UncompressedDigestForTOC(options.TOCDigest); uncompressedDigest != "" {
layers, err = s.imageRef.transport.store.LayersByUncompressedDigest(uncompressedDigest)
if err != nil && !errors.Is(err, storage.ErrLayerUnknown) {
return false, private.ReusedBlob{}, fmt.Errorf(`looking for layers with digest %q: %w`, uncompressedDigest, err)
}
if found, reused := reusedBlobFromLayerLookupLocked(layers, blobDigest, size, options); found {
s.lockProtected.indexToDiffID[*options.LayerIndex] = uncompressedDigest
reused.MatchedByTOCDigest = true
return true, reused, nil
}
}
// Check if we have a chunked layer in storage with the same TOC digest.
layers, err := s.imageRef.transport.store.LayersByTOCDigest(options.TOCDigest)
if err != nil && !errors.Is(err, storage.ErrLayerUnknown) {
Expand Down

0 comments on commit 85ce7a7

Please sign in to comment.