Make TarStream return an io.ReadCloser

Currently, the resources associated with the io.Reader returned by
TarStream are only freed when it is read until EOF. This means that
partial uploads or exports (for example, in the case of a full disk or
severed connection) can leak a goroutine and open file. This commit
changes TarStream to return an io.ReadCloser. Resources are freed when
Close is called.

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
This commit is contained in:
Aaron Lehmann 2015-11-25 16:39:54 -08:00
Родитель 49088b0b89
Коммит 21278efaee
11 изменённых файлов: 16 добавлений и 20 удалений

Просмотреть файл

@ -155,6 +155,7 @@ func (daemon *Daemon) exportContainerRw(container *Container) (archive.Archive,
return nil, err
}
return ioutils.NewReadCloserWrapper(archive, func() error {
archive.Close()
return daemon.layerStore.Unmount(container.ID)
}),
nil

Просмотреть файл

@ -429,6 +429,7 @@ func (p *v1Pusher) pushImage(v1Image v1Image, ep string) (checksum string, err e
if err != nil {
return "", err
}
defer arch.Close()
// don't care if this fails; best effort
size, _ := l.Size()

Просмотреть файл

@ -365,6 +365,7 @@ func (p *v2Pusher) pushV2Layer(bs distribution.BlobService, l layer.Layer) (dige
if err != nil {
return "", err
}
defer arch.Close()
// Send the layer
layerUpload, err := bs.Create(context.Background())

Просмотреть файл

@ -287,6 +287,8 @@ func (s *saveSession) saveLayer(id layer.ChainID, legacyImg image.V1Image, creat
if err != nil {
return err
}
defer arch.Close()
if _, err := io.Copy(tarFile, arch); err != nil {
return err
}

Просмотреть файл

@ -4,6 +4,7 @@ import (
"archive/tar"
"bytes"
"io"
"io/ioutil"
)
// DigestSHA256EmptyTar is the canonical sha256 digest of empty tar file -
@ -15,11 +16,11 @@ type emptyLayer struct{}
// EmptyLayer is a layer that corresponds to empty tar.
var EmptyLayer = &emptyLayer{}
func (el *emptyLayer) TarStream() (io.Reader, error) {
func (el *emptyLayer) TarStream() (io.ReadCloser, error) {
buf := new(bytes.Buffer)
tarWriter := tar.NewWriter(buf)
tarWriter.Close()
return buf, nil
return ioutil.NopCloser(buf), nil
}
func (el *emptyLayer) ChainID() ChainID {

Просмотреть файл

@ -67,7 +67,7 @@ func (diffID DiffID) String() string {
type TarStreamer interface {
// TarStream returns a tar archive stream
// for the contents of a layer.
TarStream() (io.Reader, error)
TarStream() (io.ReadCloser, error)
}
// Layer represents a read only layer

Просмотреть файл

@ -581,7 +581,7 @@ func (ls *layerStore) Changes(name string) ([]archive.Change, error) {
return ls.driver.Changes(m.mountID, pid)
}
func (ls *layerStore) assembleTar(graphID string, metadata io.ReadCloser, size *int64) (io.Reader, error) {
func (ls *layerStore) assembleTar(graphID string, metadata io.ReadCloser, size *int64) (io.ReadCloser, error) {
type diffPathDriver interface {
DiffPath(string) (string, func() error, error)
}

Просмотреть файл

@ -100,6 +100,7 @@ func createLayer(ls Store, parent ChainID, layerFunc layerInit) (Layer, error) {
if err != nil {
return nil, err
}
defer ts.Close()
layer, err := ls.Register(ts, parent)
if err != nil {
@ -521,6 +522,7 @@ func assertLayerDiff(t *testing.T, expected []byte, layer Layer) {
if err != nil {
t.Fatal(err)
}
defer ts.Close()
actual, err := ioutil.ReadAll(ts)
if err != nil {

Просмотреть файл

@ -22,12 +22,12 @@ func (ml *mountedLayer) cacheParent() string {
return ""
}
func (ml *mountedLayer) TarStream() (io.Reader, error) {
func (ml *mountedLayer) TarStream() (io.ReadCloser, error) {
archiver, err := ml.layerStore.driver.Diff(ml.mountID, ml.cacheParent())
if err != nil {
return nil, err
}
return autoClosingReader{archiver}, nil
return archiver, nil
}
func (ml *mountedLayer) Path() (string, error) {
@ -50,15 +50,3 @@ func (ml *mountedLayer) Parent() Layer {
func (ml *mountedLayer) Size() (int64, error) {
return ml.layerStore.driver.DiffSize(ml.mountID, ml.cacheParent())
}
type autoClosingReader struct {
source io.ReadCloser
}
func (r autoClosingReader) Read(p []byte) (n int, err error) {
n, err = r.source.Read(p)
if err != nil {
r.source.Close()
}
return
}

Просмотреть файл

@ -14,7 +14,7 @@ type roLayer struct {
references map[Layer]struct{}
}
func (rl *roLayer) TarStream() (io.Reader, error) {
func (rl *roLayer) TarStream() (io.ReadCloser, error) {
r, err := rl.layerStore.store.TarSplitReader(rl.chainID)
if err != nil {
return nil, err

Просмотреть файл

@ -357,7 +357,7 @@ type mockLayer struct {
parent *mockLayer
}
func (l *mockLayer) TarStream() (io.Reader, error) {
func (l *mockLayer) TarStream() (io.ReadCloser, error) {
return nil, nil
}