Skip to content

Commit

Permalink
copy: use blobinfocache2 compression info for reused blobs
Browse files Browse the repository at this point in the history
Teach BlobInfoCache2 implementations to retrieve the type of compression
that was applied to a blob with a given digest, if we know it.

If we successfully reuse a blob while writing an image, and we know how
a blob with that reused blob's digest was compressed, use it to update
the MIME type of that blob.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
  • Loading branch information
nalind committed Feb 3, 2021
1 parent 1da72bf commit bfd0f33
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 0 deletions.
12 changes: 12 additions & 0 deletions copy/copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -1098,6 +1098,18 @@ func (ic *imageCopier) copyLayer(ctx context.Context, srcInfo types.BlobInfo, to
Artifact: srcInfo,
}
}

// If we know the blob that we just reused is compressed (or not), note how it's compressed (or not).
if compressorName := ic.c.blobInfoCache.DigestCompressorName(blobInfo.Digest); compressorName != internalblobinfocache.UnknownCompression {
if compressorName == internalblobinfocache.Uncompressed {
blobInfo.CompressionAlgorithm = nil
} else {
if algorithm, err := compression.AlgorithmByName(compressorName); err == nil {
blobInfo.CompressionAlgorithm = &algorithm
}
}
}

return blobInfo, cachedDiffID, nil
}
}
Expand Down
4 changes: 4 additions & 0 deletions internal/blobinfocache/blobinfocache.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ type v1OnlyBlobInfoCache struct {
func (bic *v1OnlyBlobInfoCache) RecordDigestCompressorName(anyDigest digest.Digest, compressorName string) {
}

func (bic *v1OnlyBlobInfoCache) DigestCompressorName(anyDigest digest.Digest) string {
return UnknownCompression
}

func (bic *v1OnlyBlobInfoCache) CandidateLocations2(transport types.ImageTransport, scope types.BICTransportScope, digest digest.Digest, canSubstitute bool) []BICReplacementCandidate2 {
return nil
}
Expand Down
3 changes: 3 additions & 0 deletions internal/blobinfocache/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ type BlobInfoCache2 interface {
// otherwise the cache could be poisoned and cause us to make incorrect edits to type
// information in a manifest.
RecordDigestCompressorName(anyDigest digest.Digest, compressorName string)
// DigestCompressorName returns the type of compression that we know is applied to the
// blob with the specified digest, or Uncompressed or UnknownCompression.
DigestCompressorName(anyDigest digest.Digest) string
// CandidateLocations2 returns a prioritized, limited, number of blobs and their locations
// that could possibly be reused within the specified (transport scope) (if they still
// exist, which is not guaranteed).
Expand Down
20 changes: 20 additions & 0 deletions pkg/blobinfocache/boltdb/boltdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,26 @@ func (bdc *cache) RecordDigestCompressorName(anyDigest digest.Digest, compressor
}) // FIXME? Log error (but throttle the log volume on repeated accesses)?
}

// DigestCompressorName returns the type of compression that we know is applied to the
// blob with the specified digest, or Uncompressed or UnknownCompression.
func (bdc *cache) DigestCompressorName(anyDigest digest.Digest) string {
compressorName := blobinfocache.UnknownCompression
if err := bdc.view(func(tx *bolt.Tx) error {
compressionBucket := tx.Bucket(digestCompressorBucket)
if compressionBucket == nil {
return nil
}
digestKey := []byte(anyDigest.String())
if compressorNameValue := compressionBucket.Get(digestKey); len(compressorNameValue) > 0 {
compressorName = string(compressorNameValue)
}
return nil
}); err != nil { // Including os.IsNotExist(err)
return blobinfocache.UnknownCompression // FIXME? Log err (but throttle the log volume on repeated accesses)?
}
return compressorName
}

// RecordKnownLocation records that a blob with the specified digest exists within the specified (transport, scope) scope,
// and can be reused given the opaque location data.
func (bdc *cache) RecordKnownLocation(transport types.ImageTransport, scope types.BICTransportScope, blobDigest digest.Digest, location types.BICLocationReference) {
Expand Down
8 changes: 8 additions & 0 deletions pkg/blobinfocache/internal/test/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,9 @@ func testGenericCandidateLocations2(t *testing.T, cache blobinfocache.BlobInfoCa
for _, e := range digestNameSet {
cache.RecordDigestCompressorName(e.d, blobinfocache.UnknownCompression)
}
for _, e := range digestNameSet {
assert.Equal(t, blobinfocache.UnknownCompression, cache.DigestCompressorName(e.d))
}
}

// No substitutions allowed:
Expand Down Expand Up @@ -276,6 +279,11 @@ func testGenericCandidateLocations2(t *testing.T, cache blobinfocache.BlobInfoCa
cache.RecordDigestCompressorName(e.d, e.m)
}

// Check that we can retrieve compression values
for _, e := range digestNameSet {
assert.Equal(t, e.m, cache.DigestCompressorName(e.d))
}

// No substitutions allowed:
for _, e := range digestNameSet {
assertCandidatesMatch(t, scopeName, []candidate{
Expand Down
11 changes: 11 additions & 0 deletions pkg/blobinfocache/memory/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,17 @@ func (mem *cache) RecordDigestCompressorName(blobDigest digest.Digest, compresso
mem.compressors[blobDigest] = compressorName
}

// DigestCompressorName returns the type of compression that we know is applied to the
// blob with the specified digest, or Uncompressed or UnknownCompression.
func (mem *cache) DigestCompressorName(blobDigest digest.Digest) string {
mem.mutex.Lock()
defer mem.mutex.Unlock()
if compressorName, ok := mem.compressors[blobDigest]; ok {
return compressorName
}
return blobinfocache.UnknownCompression
}

// appendReplacementCandiates creates prioritize.CandidateWithTime values for (transport, scope, digest), and returns the result of appending them to candidates.
func (mem *cache) appendReplacementCandidates(candidates []prioritize.CandidateWithTime, transport types.ImageTransport, scope types.BICTransportScope, digest digest.Digest, requireCompressionInfo bool) []prioritize.CandidateWithTime {
locations := mem.knownLocations[locationKey{transport: transport.Name(), scope: scope, blobDigest: digest}] // nil if not present
Expand Down

0 comments on commit bfd0f33

Please sign in to comment.