mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Fix panic on network timeout during push
`Upload` already closes the reader returned by `compress` and the progressreader passed into it, before returning. But even so, the io.Copy inside compress' goroutine needs to attempt a read from the progressreader to notice that it's closed, and this read has a side effect of outputting a progress message. If this happens after `Upload` returns, it can result in a write to a closed channel. Change `compress` to return a channel that allows the caller to wait for its goroutine to finish before freeing any resources connected to the reader that was passed to it. Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
This commit is contained in:
parent
6c6729ef5b
commit
e273445dd4
2 changed files with 15 additions and 4 deletions
|
@ -170,7 +170,14 @@ func Push(ctx context.Context, ref reference.Named, imagePushConfig *ImagePushCo
|
||||||
// argument so that it can be used with httpBlobWriter's ReadFrom method.
|
// argument so that it can be used with httpBlobWriter's ReadFrom method.
|
||||||
// Using httpBlobWriter's Write method would send a PATCH request for every
|
// Using httpBlobWriter's Write method would send a PATCH request for every
|
||||||
// Write call.
|
// Write call.
|
||||||
func compress(in io.Reader) io.ReadCloser {
|
//
|
||||||
|
// The second return value is a channel that gets closed when the goroutine
|
||||||
|
// is finished. This allows the caller to make sure the goroutine finishes
|
||||||
|
// before it releases any resources connected with the reader that was
|
||||||
|
// passed in.
|
||||||
|
func compress(in io.Reader) (io.ReadCloser, chan struct{}) {
|
||||||
|
compressionDone := make(chan struct{})
|
||||||
|
|
||||||
pipeReader, pipeWriter := io.Pipe()
|
pipeReader, pipeWriter := io.Pipe()
|
||||||
// Use a bufio.Writer to avoid excessive chunking in HTTP request.
|
// Use a bufio.Writer to avoid excessive chunking in HTTP request.
|
||||||
bufWriter := bufio.NewWriterSize(pipeWriter, compressionBufSize)
|
bufWriter := bufio.NewWriterSize(pipeWriter, compressionBufSize)
|
||||||
|
@ -189,7 +196,8 @@ func compress(in io.Reader) io.ReadCloser {
|
||||||
} else {
|
} else {
|
||||||
pipeWriter.Close()
|
pipeWriter.Close()
|
||||||
}
|
}
|
||||||
|
close(compressionDone)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return pipeReader
|
return pipeReader, compressionDone
|
||||||
}
|
}
|
||||||
|
|
|
@ -345,8 +345,11 @@ func (pd *v2PushDescriptor) Upload(ctx context.Context, progressOutput progress.
|
||||||
size, _ := pd.layer.DiffSize()
|
size, _ := pd.layer.DiffSize()
|
||||||
|
|
||||||
reader := progress.NewProgressReader(ioutils.NewCancelReadCloser(ctx, arch), progressOutput, size, pd.ID(), "Pushing")
|
reader := progress.NewProgressReader(ioutils.NewCancelReadCloser(ctx, arch), progressOutput, size, pd.ID(), "Pushing")
|
||||||
defer reader.Close()
|
compressedReader, compressionDone := compress(reader)
|
||||||
compressedReader := compress(reader)
|
defer func() {
|
||||||
|
reader.Close()
|
||||||
|
<-compressionDone
|
||||||
|
}()
|
||||||
|
|
||||||
digester := digest.Canonical.New()
|
digester := digest.Canonical.New()
|
||||||
tee := io.TeeReader(compressedReader, digester.Hash())
|
tee := io.TeeReader(compressedReader, digester.Hash())
|
||||||
|
|
Loading…
Add table
Reference in a new issue