1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

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
parent 49088b0b89
commit 21278efaee
11 changed files with 16 additions and 20 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -581,7 +581,7 @@ func (ls *layerStore) Changes(name string) ([]archive.Change, error) {
return ls.driver.Changes(m.mountID, pid) 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 { type diffPathDriver interface {
DiffPath(string) (string, func() error, error) DiffPath(string) (string, func() error, error)
} }

View file

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

View file

@ -22,12 +22,12 @@ func (ml *mountedLayer) cacheParent() string {
return "" 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()) archiver, err := ml.layerStore.driver.Diff(ml.mountID, ml.cacheParent())
if err != nil { if err != nil {
return nil, err return nil, err
} }
return autoClosingReader{archiver}, nil return archiver, nil
} }
func (ml *mountedLayer) Path() (string, error) { func (ml *mountedLayer) Path() (string, error) {
@ -50,15 +50,3 @@ func (ml *mountedLayer) Parent() Layer {
func (ml *mountedLayer) Size() (int64, error) { func (ml *mountedLayer) Size() (int64, error) {
return ml.layerStore.driver.DiffSize(ml.mountID, ml.cacheParent()) 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
}

View file

@ -14,7 +14,7 @@ type roLayer struct {
references map[Layer]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) r, err := rl.layerStore.store.TarSplitReader(rl.chainID)
if err != nil { if err != nil {
return nil, err return nil, err

View file

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