diff --git a/content/content.go b/content/content.go index 6770b3464..05fd4aebe 100644 --- a/content/content.go +++ b/content/content.go @@ -90,6 +90,7 @@ type IngestManager interface { // Writer handles the write of content into a content store type Writer interface { // Close is expected to be called after Commit() when commission is needed. + // Closing a writer without commit allows resuming or aborting. io.WriteCloser // Digest may return empty digest or panics until committed. diff --git a/content/local/writer.go b/content/local/writer.go index 362c0e209..c4f1a94f3 100644 --- a/content/local/writer.go +++ b/content/local/writer.go @@ -130,10 +130,10 @@ func (w *writer) Commit(ctx context.Context, size int64, expected digest.Digest, // tact. // // If one needs to resume the transaction, a new writer can be obtained from -// `ContentStore.Resume` using the same key. The write can then be continued +// `Ingester.Writer` using the same key. The write can then be continued // from it was left off. // -// To abandon a transaction completely, first call close then `Store.Remove` to +// To abandon a transaction completely, first call close then `IngestManager.Abort` to // clean up the associated resources. func (w *writer) Close() (err error) { if w.fp != nil { diff --git a/diff/walking/differ.go b/diff/walking/differ.go index 0af45ba98..70ee06533 100644 --- a/diff/walking/differ.go +++ b/diff/walking/differ.go @@ -16,6 +16,7 @@ import ( "github.com/containerd/containerd/diff" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/images" + "github.com/containerd/containerd/log" "github.com/containerd/containerd/metadata" "github.com/containerd/containerd/mount" "github.com/containerd/containerd/platforms" @@ -127,7 +128,7 @@ func (s *walkingDiff) Apply(ctx context.Context, desc ocispec.Descriptor, mounts // DiffMounts creates a diff between the given mounts and uploads the result // to the content store. -func (s *walkingDiff) DiffMounts(ctx context.Context, lower, upper []mount.Mount, opts ...diff.Opt) (ocispec.Descriptor, error) { +func (s *walkingDiff) DiffMounts(ctx context.Context, lower, upper []mount.Mount, opts ...diff.Opt) (d ocispec.Descriptor, err error) { var config diff.Config for _, opt := range opts { if err := opt(&config); err != nil { @@ -169,7 +170,9 @@ func (s *walkingDiff) DiffMounts(ctx context.Context, lower, upper []mount.Mount } defer mount.Unmount(bDir, 0) + var newReference bool if config.Reference == "" { + newReference = true config.Reference = uniqueRef() } @@ -177,18 +180,31 @@ func (s *walkingDiff) DiffMounts(ctx context.Context, lower, upper []mount.Mount if err != nil { return emptyDesc, errors.Wrap(err, "failed to open writer") } + defer func() { + if err != nil { + cw.Close() + if newReference { + if err := s.store.Abort(ctx, config.Reference); err != nil { + log.G(ctx).WithField("ref", config.Reference).Warnf("failed to delete diff upload") + } + } + } + }() + if !newReference { + if err := cw.Truncate(0); err != nil { + return emptyDesc, err + } + } if isCompressed { dgstr := digest.SHA256.Digester() compressed, err := compression.CompressStream(cw, compression.Gzip) if err != nil { - cw.Close() return emptyDesc, errors.Wrap(err, "failed to get compressed stream") } err = archive.WriteDiff(ctx, io.MultiWriter(compressed, dgstr.Hash()), aDir, bDir) compressed.Close() if err != nil { - cw.Close() return emptyDesc, errors.Wrap(err, "failed to write compressed diff") } @@ -198,7 +214,6 @@ func (s *walkingDiff) DiffMounts(ctx context.Context, lower, upper []mount.Mount config.Labels["containerd.io/uncompressed"] = dgstr.Digest().String() } else { if err = archive.WriteDiff(ctx, cw, aDir, bDir); err != nil { - cw.Close() return emptyDesc, errors.Wrap(err, "failed to write diff") } }