Selaa lähdekoodia

Merge pull request #8084 from unclejack/improve_stdcopy

stdwriter: improve perf by avoiding buffer growth
Tibor Vass 10 vuotta sitten
vanhempi
commit
8b97e2c287

+ 2 - 1
api/client/hijack.go

@@ -14,6 +14,7 @@ import (
 	"github.com/docker/docker/api"
 	"github.com/docker/docker/dockerversion"
 	"github.com/docker/docker/pkg/log"
+	"github.com/docker/docker/pkg/stdcopy"
 	"github.com/docker/docker/pkg/term"
 	"github.com/docker/docker/utils"
 )
@@ -96,7 +97,7 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.Rea
 			if setRawTerminal && stdout != nil {
 				_, err = io.Copy(stdout, br)
 			} else {
-				_, err = utils.StdCopy(stdout, stderr, br)
+				_, err = stdcopy.StdCopy(stdout, stderr, br)
 			}
 			log.Debugf("[hijack] End of stdout")
 			return err

+ 2 - 1
api/client/utils.go

@@ -22,6 +22,7 @@ import (
 	"github.com/docker/docker/dockerversion"
 	"github.com/docker/docker/engine"
 	"github.com/docker/docker/pkg/log"
+	"github.com/docker/docker/pkg/stdcopy"
 	"github.com/docker/docker/pkg/term"
 	"github.com/docker/docker/registry"
 	"github.com/docker/docker/utils"
@@ -174,7 +175,7 @@ func (cli *DockerCli) streamHelper(method, path string, setRawTerminal bool, in
 		if setRawTerminal {
 			_, err = io.Copy(stdout, resp.Body)
 		} else {
-			_, err = utils.StdCopy(stdout, stderr, resp.Body)
+			_, err = stdcopy.StdCopy(stdout, stderr, resp.Body)
 		}
 		log.Debugf("[stream] End of stdout")
 		return err

+ 7 - 6
api/server/server.go

@@ -28,6 +28,7 @@ import (
 	"github.com/docker/docker/pkg/listenbuffer"
 	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/pkg/parsers"
+	"github.com/docker/docker/pkg/stdcopy"
 	"github.com/docker/docker/pkg/systemd"
 	"github.com/docker/docker/pkg/version"
 	"github.com/docker/docker/registry"
@@ -399,8 +400,8 @@ func getContainersLogs(eng *engine.Engine, version version.Version, w http.Respo
 	outStream = utils.NewWriteFlusher(w)
 
 	if c.GetSubEnv("Config") != nil && !c.GetSubEnv("Config").GetBool("Tty") && version.GreaterThanOrEqualTo("1.6") {
-		errStream = utils.NewStdWriter(outStream, utils.Stderr)
-		outStream = utils.NewStdWriter(outStream, utils.Stdout)
+		errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr)
+		outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout)
 	} else {
 		errStream = outStream
 	}
@@ -843,8 +844,8 @@ func postContainersAttach(eng *engine.Engine, version version.Version, w http.Re
 	fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
 
 	if c.GetSubEnv("Config") != nil && !c.GetSubEnv("Config").GetBool("Tty") && version.GreaterThanOrEqualTo("1.6") {
-		errStream = utils.NewStdWriter(outStream, utils.Stderr)
-		outStream = utils.NewStdWriter(outStream, utils.Stdout)
+		errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr)
+		outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout)
 	} else {
 		errStream = outStream
 	}
@@ -1091,8 +1092,8 @@ func postContainerExecStart(eng *engine.Engine, version version.Version, w http.
 
 		fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
 		if !job.GetenvBool("Tty") && version.GreaterThanOrEqualTo("1.6") {
-			errStream = utils.NewStdWriter(outStream, utils.Stderr)
-			outStream = utils.NewStdWriter(outStream, utils.Stdout)
+			errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr)
+			outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout)
 		} else {
 			errStream = outStream
 		}

+ 1 - 0
pkg/stdcopy/MAINTAINERS

@@ -0,0 +1 @@
+Cristian Staretu <cristian.staretu@gmail.com> (@unclejack)

+ 13 - 5
utils/stdcopy.go → pkg/stdcopy/stdcopy.go

@@ -1,4 +1,4 @@
-package utils
+package stdcopy
 
 import (
 	"encoding/binary"
@@ -29,14 +29,22 @@ type StdWriter struct {
 }
 
 func (w *StdWriter) Write(buf []byte) (n int, err error) {
+	var n1, n2 int
 	if w == nil || w.Writer == nil {
 		return 0, errors.New("Writer not instanciated")
 	}
 	binary.BigEndian.PutUint32(w.prefix[4:], uint32(len(buf)))
-	buf = append(w.prefix[:], buf...)
-
-	n, err = w.Writer.Write(buf)
-	return n - StdWriterPrefixLen, err
+	n1, err = w.Writer.Write(w.prefix[:])
+	if err != nil {
+		n = n1 - StdWriterPrefixLen
+	} else {
+		n2, err = w.Writer.Write(buf)
+		n = n1 + n2 - StdWriterPrefixLen
+	}
+	if n < 0 {
+		n = 0
+	}
+	return
 }
 
 // NewStdWriter instanciates a new Writer.

+ 20 - 0
pkg/stdcopy/stdcopy_test.go

@@ -0,0 +1,20 @@
+package stdcopy
+
+import (
+	"bytes"
+	"io/ioutil"
+	"testing"
+)
+
+func BenchmarkWrite(b *testing.B) {
+	w := NewStdWriter(ioutil.Discard, Stdout)
+	data := []byte("Test line for testing stdwriter performance\n")
+	data = bytes.Repeat(data, 100)
+	b.SetBytes(int64(len(data)))
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		if _, err := w.Write(data); err != nil {
+			b.Fatal(err)
+		}
+	}
+}