Skip to content

Commit

Permalink
Use internal/imagedestination/impl in dockerImageDestination
Browse files Browse the repository at this point in the history
For now, this does not change behavior; but it will allow
using BlobInfoCache2 next.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
  • Loading branch information
mtrmac committed Feb 15, 2022
1 parent bb6a899 commit 8c7520e
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 14 deletions.
46 changes: 32 additions & 14 deletions docker/docker_image_dest.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import (

"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/internal/blobinfocache"
"github.com/containers/image/v5/internal/imagedestination/impl"
"github.com/containers/image/v5/internal/private"
"github.com/containers/image/v5/internal/putblobdigest"
"github.com/containers/image/v5/internal/streamdigest"
"github.com/containers/image/v5/internal/uploadreader"
Expand All @@ -30,6 +32,8 @@ import (
)

type dockerImageDestination struct {
impl.Compat

ref dockerReference
c *dockerClient
// State
Expand All @@ -42,10 +46,12 @@ func newImageDestination(sys *types.SystemContext, ref dockerReference) (types.I
if err != nil {
return nil, err
}
return &dockerImageDestination{
dest := &dockerImageDestination{
ref: ref,
c: c,
}, nil
}
dest.Compat = impl.AddCompat(dest)
return dest, nil
}

// Reference returns the reference used to set up this destination. Note that this should directly correspond to user's intent,
Expand Down Expand Up @@ -123,14 +129,14 @@ func (d *dockerImageDestination) HasThreadSafePutBlob() bool {
return true
}

// PutBlob writes contents of stream and returns data representing the result (with all data filled in).
// PutBlobWithOptions writes contents of stream and returns data representing the result.
// inputInfo.Digest can be optionally provided if known; if provided, and stream is read to the end without error, the digest MUST match the stream contents.
// inputInfo.Size is the expected length of stream, if known.
// May update cache.
// inputInfo.MediaType describes the blob format, if known.
// WARNING: The contents of stream are being verified on the fly. Until stream.Read() returns io.EOF, the contents of the data SHOULD NOT be available
// to any other readers for download using the supplied digest.
// If stream.Read() at any time, ESPECIALLY at end of input, returns an error, PutBlob MUST 1) fail, and 2) delete any data stored so far.
func (d *dockerImageDestination) PutBlob(ctx context.Context, stream io.Reader, inputInfo types.BlobInfo, cache types.BlobInfoCache, isConfig bool) (types.BlobInfo, error) {
func (d *dockerImageDestination) PutBlobWithOptions(ctx context.Context, stream io.Reader, inputInfo types.BlobInfo, options private.PutBlobOptions) (types.BlobInfo, error) {
// If requested, precompute the blob digest to prevent uploading layers that already exist on the registry.
// This functionality is particularly useful when BlobInfoCache has not been populated with compressed digests,
// the source blob is uncompressed, and the destination blob is being compressed "on the fly".
Expand All @@ -147,7 +153,7 @@ func (d *dockerImageDestination) PutBlob(ctx context.Context, stream io.Reader,
if inputInfo.Digest != "" {
// This should not really be necessary, at least the copy code calls TryReusingBlob automatically.
// Still, we need to check, if only because the "initiate upload" endpoint does not have a documented "blob already exists" return value.
haveBlob, reusedInfo, err := d.tryReusingExactBlob(ctx, inputInfo, cache)
haveBlob, reusedInfo, err := d.tryReusingExactBlob(ctx, inputInfo, options.Cache)
if err != nil {
return types.BlobInfo{}, err
}
Expand Down Expand Up @@ -218,10 +224,24 @@ func (d *dockerImageDestination) PutBlob(ctx context.Context, stream io.Reader,
}

logrus.Debugf("Upload of layer %s complete", blobDigest)
cache.RecordKnownLocation(d.ref.Transport(), bicTransportScope(d.ref), blobDigest, newBICLocationReference(d.ref))
options.Cache.RecordKnownLocation(d.ref.Transport(), bicTransportScope(d.ref), blobDigest, newBICLocationReference(d.ref))
return types.BlobInfo{Digest: blobDigest, Size: sizeCounter.size}, nil
}

// SupportsPutBlobPartial returns true if PutBlobPartial is supported.
func (d *dockerImageDestination) SupportsPutBlobPartial() bool {
return false
}

// PutBlobPartial attempts to create a blob using the data that is already present
// at the destination. chunkAccessor is accessed in a non-sequential way to retrieve the missing chunks.
// It is available only if SupportsPutBlobPartial().
// Even if SupportsPutBlobPartial() returns true, the call can fail, in which case the caller
// should fall back to PutBlobWithOptions.
func (d *dockerImageDestination) PutBlobPartial(ctx context.Context, chunkAccessor private.BlobChunkAccessor, srcInfo types.BlobInfo, cache types.BlobInfoCache) (types.BlobInfo, error) {
return types.BlobInfo{}, fmt.Errorf("internal error: PutBlobPartial is not supported by the %q transport", d.Reference().Transport().Name())
}

// blobExists returns true iff repo contains a blob with digest, and if so, also its size.
// If the destination does not contain the blob, or it is unknown, blobExists ordinarily returns (false, -1, nil);
// it returns a non-nil error only on an unexpected failure.
Expand Down Expand Up @@ -309,22 +329,20 @@ func (d *dockerImageDestination) tryReusingExactBlob(ctx context.Context, info t
return false, types.BlobInfo{}, nil
}

// TryReusingBlob checks whether the transport already contains, or can efficiently reuse, a blob, and if so, applies it to the current destination
// TryReusingBlobWithOptions checks whether the transport already contains, or can efficiently reuse, a blob, and if so, applies it to the current destination
// (e.g. if the blob is a filesystem layer, this signifies that the changes it describes need to be applied again when composing a filesystem tree).
// info.Digest must not be empty.
// If canSubstitute, TryReusingBlob can use an equivalent equivalent of the desired blob; in that case the returned info may not match the input.
// If the blob has been successfully reused, returns (true, info, nil); info must contain at least a digest and size, and may
// include CompressionOperation and CompressionAlgorithm fields to indicate that a change to the compression type should be
// reflected in the manifest that will be written.
// If the transport can not reuse the requested blob, TryReusingBlob returns (false, {}, nil); it returns a non-nil error only on an unexpected failure.
// May use and/or update cache.
func (d *dockerImageDestination) TryReusingBlob(ctx context.Context, info types.BlobInfo, cache types.BlobInfoCache, canSubstitute bool) (bool, types.BlobInfo, error) {
func (d *dockerImageDestination) TryReusingBlobWithOptions(ctx context.Context, info types.BlobInfo, options private.TryReusingBlobOptions) (bool, types.BlobInfo, error) {
if info.Digest == "" {
return false, types.BlobInfo{}, errors.Errorf(`"Can not check for a blob with unknown digest`)
}

// First, check whether the blob happens to already exist at the destination.
haveBlob, reusedInfo, err := d.tryReusingExactBlob(ctx, info, cache)
haveBlob, reusedInfo, err := d.tryReusingExactBlob(ctx, info, options.Cache)
if err != nil {
return false, types.BlobInfo{}, err
}
Expand All @@ -333,8 +351,8 @@ func (d *dockerImageDestination) TryReusingBlob(ctx context.Context, info types.
}

// Then try reusing blobs from other locations.
bic := blobinfocache.FromBlobInfoCache(cache)
candidates := bic.CandidateLocations2(d.ref.Transport(), bicTransportScope(d.ref), info.Digest, canSubstitute)
bic := blobinfocache.FromBlobInfoCache(options.Cache)
candidates := bic.CandidateLocations2(d.ref.Transport(), bicTransportScope(d.ref), info.Digest, options.CanSubstitute)
for _, candidate := range candidates {
candidateRepo, err := parseBICLocationReference(candidate.Location)
if err != nil {
Expand Down
3 changes: 3 additions & 0 deletions docker/docker_image_dest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ import (
"net/http"
"testing"

"github.com/containers/image/v5/internal/private"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

var _ private.ImageDestination = (*dockerImageDestination)(nil)

func TestIsManifestInvalidError(t *testing.T) {
// Sadly only a smoke test; this really should record all known errors exactly as they happen.

Expand Down

0 comments on commit 8c7520e

Please sign in to comment.