From d8d52e6e6722bc2071cdcb6c6c21a75566c55ec5 Mon Sep 17 00:00:00 2001 From: Valentin Rothberg Date: Fri, 15 Mar 2019 14:01:48 +0100 Subject: [PATCH] ImageDestination: add blob locking Extend the ImageDestination interface with methods for locking and unlocking a blob: 1) LockBlob() for locking a given blob. 2) UnlockBlobk() for unlocking a blob. 3) SupportsBlobLocks() to indicate whether the image destination supports lock semantics or not. Signed-off-by: Valentin Rothberg --- directory/directory_dest.go | 21 +++++++++++++++++++++ docker/docker_image_dest.go | 21 +++++++++++++++++++++ docker/tarfile/dest.go | 21 +++++++++++++++++++++ image/docker_schema2_test.go | 9 +++++++++ oci/archive/oci_dest.go | 21 +++++++++++++++++++++ oci/layout/oci_dest.go | 21 +++++++++++++++++++++ openshift/openshift.go | 21 +++++++++++++++++++++ ostree/ostree_dest.go | 21 +++++++++++++++++++++ storage/storage_image.go | 21 +++++++++++++++++++++ types/types.go | 9 +++++++++ 10 files changed, 186 insertions(+) diff --git a/directory/directory_dest.go b/directory/directory_dest.go index 4b2ab022e2..955759d97a 100644 --- a/directory/directory_dest.go +++ b/directory/directory_dest.go @@ -129,6 +129,27 @@ func (d *dirImageDestination) HasThreadSafePutBlob() bool { return false } +// SupportsBlobLocks indicates whether the ImageDestination supports blob +// locking. +func (d *dirImageDestination) SupportsBlobLocks() bool { + return false +} + +// LockBlob can be used to synchronize operations on it (e.g., copying). +func (d *dirImageDestination) LockBlob(b types.BlobInfo) error { + // NOOP for this type. + return nil +} + +// UnlockBlob unlocks the blob. Note that it is safe to call UnlockBlob() +// multiple times. Only the first call is unlocking the blob. This is +// required to unlock a blob in the presence of errors or panics during copy +// operations. +func (d *dirImageDestination) UnlockBlob(b types.BlobInfo) error { + // NOOP for this type. + return nil +} + // PutBlob writes contents of stream and returns data representing the result (with all data filled in). // inputInfo.Digest can be optionally provided if known; it is not mandatory for the implementation to verify it. // inputInfo.Size is the expected length of stream, if known. diff --git a/docker/docker_image_dest.go b/docker/docker_image_dest.go index c116cbec32..b49c203f5f 100644 --- a/docker/docker_image_dest.go +++ b/docker/docker_image_dest.go @@ -117,6 +117,27 @@ func (d *dockerImageDestination) HasThreadSafePutBlob() bool { return true } +// SupportsBlobLocks indicates whether the ImageDestination supports blob +// locking. +func (d *dockerImageDestination) SupportsBlobLocks() bool { + return false +} + +// LockBlob can be used to synchronize operations on it (e.g., copying). +func (d *dockerImageDestination) LockBlob(b types.BlobInfo) error { + // NOOP for this type. + return nil +} + +// UnlockBlob unlocks the blob. Note that it is safe to call UnlockBlob() +// multiple times. Only the first call is unlocking the blob. This is +// required to unlock a blob in the presence of errors or panics during copy +// operations. +func (d *dockerImageDestination) UnlockBlob(b types.BlobInfo) error { + // NOOP for this type. + return nil +} + // PutBlob writes contents of stream and returns data representing the result (with all data filled in). // inputInfo.Digest can be optionally provided if known; it is not mandatory for the implementation to verify it. // inputInfo.Size is the expected length of stream, if known. diff --git a/docker/tarfile/dest.go b/docker/tarfile/dest.go index 5f30eddbc7..78368ed3e7 100644 --- a/docker/tarfile/dest.go +++ b/docker/tarfile/dest.go @@ -87,6 +87,27 @@ func (d *Destination) HasThreadSafePutBlob() bool { return false } +// SupportsBlobLocks indicates whether the ImageDestination supports blob +// locking. +func (d *Destination) SupportsBlobLocks() bool { + return false +} + +// LockBlob can be used to synchronize operations on it (e.g., copying). +func (d *Destination) LockBlob(b types.BlobInfo) error { + // NOOP for this type. + return nil +} + +// UnlockBlob unlocks the blob. Note that it is safe to call UnlockBlob() +// multiple times. Only the first call is unlocking the blob. This is +// required to unlock a blob in the presence of errors or panics during copy +// operations. +func (d *Destination) UnlockBlob(b types.BlobInfo) error { + // NOOP for this type. + return nil +} + // PutBlob writes contents of stream and returns data representing the result (with all data filled in). // inputInfo.Digest can be optionally provided if known; it is not mandatory for the implementation to verify it. // inputInfo.Size is the expected length of stream, if known. diff --git a/image/docker_schema2_test.go b/image/docker_schema2_test.go index 9d3f96fc6d..86ea5f31b0 100644 --- a/image/docker_schema2_test.go +++ b/image/docker_schema2_test.go @@ -401,6 +401,15 @@ func (d *memoryImageDest) IgnoresEmbeddedDockerReference() bool { func (d *memoryImageDest) HasThreadSafePutBlob() bool { panic("Unexpected call to a mock function") } +func (d *memoryImageDest) SupportsBlobLocks() bool { + panic("Unexpected call to a mock function") +} +func (d *memoryImageDest) LockBlob(b types.BlobInfo) error { + panic("Unexpected call to a mock function") +} +func (d *memoryImageDest) UnlockBlob(b types.BlobInfo) error { + panic("Unexpected call to a mock function") +} func (d *memoryImageDest) PutBlob(ctx context.Context, stream io.Reader, inputInfo types.BlobInfo, cache types.BlobInfoCache, isConfig bool) (types.BlobInfo, error) { if d.storedBlobs == nil { d.storedBlobs = make(map[digest.Digest][]byte) diff --git a/oci/archive/oci_dest.go b/oci/archive/oci_dest.go index 9571c37e2b..8435f91451 100644 --- a/oci/archive/oci_dest.go +++ b/oci/archive/oci_dest.go @@ -82,6 +82,27 @@ func (d *ociArchiveImageDestination) HasThreadSafePutBlob() bool { return false } +// SupportsBlobLocks indicates whether the ImageDestination supports blob +// locking. +func (d *ociArchiveImageDestination) SupportsBlobLocks() bool { + return false +} + +// LockBlob can be used to synchronize operations on it (e.g., copying). +func (d *ociArchiveImageDestination) LockBlob(b types.BlobInfo) error { + // NOOP for this type. + return nil +} + +// UnlockBlob unlocks the blob. Note that it is safe to call UnlockBlob() +// multiple times. Only the first call is unlocking the blob. This is +// required to unlock a blob in the presence of errors or panics during copy +// operations. +func (d *ociArchiveImageDestination) UnlockBlob(b types.BlobInfo) error { + // NOOP for this type. + return nil +} + // PutBlob writes contents of stream and returns data representing the result. // inputInfo.Digest can be optionally provided if known; it is not mandatory for the implementation to verify it. // inputInfo.Size is the expected length of stream, if known. diff --git a/oci/layout/oci_dest.go b/oci/layout/oci_dest.go index db102184db..99f7e2f703 100644 --- a/oci/layout/oci_dest.go +++ b/oci/layout/oci_dest.go @@ -112,6 +112,27 @@ func (d *ociImageDestination) HasThreadSafePutBlob() bool { return false } +// SupportsBlobLocks indicates whether the ImageDestination supports blob +// locking. +func (d *ociImageDestination) SupportsBlobLocks() bool { + return false +} + +// LockBlob can be used to synchronize operations on it (e.g., copying). +func (d *ociImageDestination) LockBlob(b types.BlobInfo) error { + // NOOP for this type. + return nil +} + +// UnlockBlob unlocks the blob. Note that it is safe to call UnlockBlob() +// multiple times. Only the first call is unlocking the blob. This is +// required to unlock a blob in the presence of errors or panics during copy +// operations. +func (d *ociImageDestination) UnlockBlob(b types.BlobInfo) error { + // NOOP for this type. + return nil +} + // PutBlob writes contents of stream and returns data representing the result. // inputInfo.Digest can be optionally provided if known; it is not mandatory for the implementation to verify it. // inputInfo.Size is the expected length of stream, if known. diff --git a/openshift/openshift.go b/openshift/openshift.go index 814c3eea1d..b775edfb9a 100644 --- a/openshift/openshift.go +++ b/openshift/openshift.go @@ -388,6 +388,27 @@ func (d *openshiftImageDestination) HasThreadSafePutBlob() bool { return false } +// SupportsBlobLocks indicates whether the ImageDestination supports blob +// locking. +func (d *openshiftImageDestination) SupportsBlobLocks() bool { + return false +} + +// LockBlob can be used to synchronize operations on it (e.g., copying). +func (d *openshiftImageDestination) LockBlob(b types.BlobInfo) error { + // NOOP for this type. + return nil +} + +// UnlockBlob unlocks the blob. Note that it is safe to call UnlockBlob() +// multiple times. Only the first call is unlocking the blob. This is +// required to unlock a blob in the presence of errors or panics during copy +// operations. +func (d *openshiftImageDestination) UnlockBlob(b types.BlobInfo) error { + // NOOP for this type. + return nil +} + // PutBlob writes contents of stream and returns data representing the result (with all data filled in). // inputInfo.Digest can be optionally provided if known; it is not mandatory for the implementation to verify it. // inputInfo.Size is the expected length of stream, if known. diff --git a/ostree/ostree_dest.go b/ostree/ostree_dest.go index d69f4fa331..deb770a660 100644 --- a/ostree/ostree_dest.go +++ b/ostree/ostree_dest.go @@ -137,6 +137,27 @@ func (d *ostreeImageDestination) HasThreadSafePutBlob() bool { return false } +// SupportsBlobLocks indicates whether the ImageDestination supports blob +// locking. +func (d *ostreeImageDestination) SupportsBlobLocks() bool { + return false +} + +// LockBlob can be used to synchronize operations on it (e.g., copying). +func (d *ostreeImageDestination) LockBlob(b types.BlobInfo) error { + // NOOP for this type. + return nil +} + +// UnlockBlob unlocks the blob. Note that it is safe to call UnlockBlob() +// multiple times. Only the first call is unlocking the blob. This is +// required to unlock a blob in the presence of errors or panics during copy +// operations. +func (d *ostreeImageDestination) UnlockBlob(b types.BlobInfo) error { + // NOOP for this type. + return nil +} + // PutBlob writes contents of stream and returns data representing the result. // inputInfo.Digest can be optionally provided if known; it is not mandatory for the implementation to verify it. // inputInfo.Size is the expected length of stream, if known. diff --git a/storage/storage_image.go b/storage/storage_image.go index b39d2bcc04..dfff28c800 100644 --- a/storage/storage_image.go +++ b/storage/storage_image.go @@ -360,6 +360,27 @@ func (s *storageImageDestination) HasThreadSafePutBlob() bool { return true } +// SupportsBlobLocks indicates whether the ImageDestination supports blob +// locking. +func (d *storageImageDestination) SupportsBlobLocks() bool { + return false +} + +// LockBlob can be used to synchronize operations on it (e.g., copying). +func (s *storageImageDestination) LockBlob(b types.BlobInfo) error { + // NOOP for this type. + return nil +} + +// UnlockBlob unlocks the blob. Note that it is safe to call UnlockBlob() +// multiple times. Only the first call is unlocking the blob. This is +// required to unlock a blob in the presence of errors or panics during copy +// operations. +func (s *storageImageDestination) UnlockBlob(b types.BlobInfo) error { + // NOOP for this type. + return nil +} + // PutBlob writes contents of stream and returns data representing the result. // inputInfo.Digest can be optionally provided if known; it is not mandatory for the implementation to verify it. // inputInfo.Size is the expected length of stream, if known. diff --git a/types/types.go b/types/types.go index 9fdab2314a..5a021536ba 100644 --- a/types/types.go +++ b/types/types.go @@ -287,6 +287,15 @@ type ImageDestination interface { // - Uploaded data MAY be visible to others before Commit() is called // - Uploaded data MAY be removed or MAY remain around if Close() is called without Commit() (i.e. rollback is allowed but not guaranteed) Commit(ctx context.Context) error + // SupportsBlobLocks indicates whether the ImageDestination supports blob locking. + SupportsBlobLocks() bool + // LockBlob can be used to synchronize operations on it (e.g., copying). + LockBlob(BlobInfo) error + // UnlockBlob unlocks the blob. Note that it is safe to call + // UnlockBlob() multiple times. Only the first call is unlocking the + // blob. This is required to unlock a blob in the presence of errors + // or panics during copy operations. + UnlockBlob(BlobInfo) error } // ManifestTypeRejectedError is returned by ImageDestination.PutManifest if the destination is in principle available,