فهرست منبع

Merge pull request #3477 from creack/fix_tar_leaks

Make CopyFileWithTar use a pipe instead of a buffer. Save more than 1Gb of ram for a 500Mb file.
Michael Crosby 11 سال پیش
والد
کامیت
fca83b4cfb
1فایلهای تغییر یافته به همراه34 افزوده شده و 21 حذف شده
  1. 34 21
      archive/archive.go

+ 34 - 21
archive/archive.go

@@ -3,8 +3,8 @@ package archive
 import (
 	"archive/tar"
 	"bytes"
-	"compress/gzip"
 	"compress/bzip2"
+	"compress/gzip"
 	"fmt"
 	"github.com/dotcloud/docker/utils"
 	"io"
@@ -299,7 +299,7 @@ func CopyWithTar(src, dst string) error {
 //
 // If `dst` ends with a trailing slash '/', the final destination path
 // will be `dst/base(src)`.
-func CopyFileWithTar(src, dst string) error {
+func CopyFileWithTar(src, dst string) (err error) {
 	utils.Debugf("CopyFileWithTar(%s, %s)", src, dst)
 	srcSt, err := os.Stat(src)
 	if err != nil {
@@ -316,25 +316,38 @@ func CopyFileWithTar(src, dst string) error {
 	if err := os.MkdirAll(filepath.Dir(dst), 0700); err != nil && !os.IsExist(err) {
 		return err
 	}
-	buf := new(bytes.Buffer)
-	tw := tar.NewWriter(buf)
-	hdr, err := tar.FileInfoHeader(srcSt, "")
-	if err != nil {
-		return err
-	}
-	hdr.Name = filepath.Base(dst)
-	if err := tw.WriteHeader(hdr); err != nil {
-		return err
-	}
-	srcF, err := os.Open(src)
-	if err != nil {
-		return err
-	}
-	if _, err := io.Copy(tw, srcF); err != nil {
-		return err
-	}
-	tw.Close()
-	return Untar(buf, filepath.Dir(dst), nil)
+
+	r, w := io.Pipe()
+	errC := utils.Go(func() error {
+		defer w.Close()
+
+		srcF, err := os.Open(src)
+		if err != nil {
+			return err
+		}
+		defer srcF.Close()
+
+		tw := tar.NewWriter(w)
+		hdr, err := tar.FileInfoHeader(srcSt, "")
+		if err != nil {
+			return err
+		}
+		hdr.Name = filepath.Base(dst)
+		if err := tw.WriteHeader(hdr); err != nil {
+			return err
+		}
+		if _, err := io.Copy(tw, srcF); err != nil {
+			return err
+		}
+		tw.Close()
+		return nil
+	})
+	defer func() {
+		if er := <-errC; err != nil {
+			err = er
+		}
+	}()
+	return Untar(r, filepath.Dir(dst), nil)
 }
 
 // CmdStream executes a command, and returns its stdout as a stream.