diff --git a/container/stream/attach.go b/container/stream/attach.go index 5f63f88f39e84..3dd53d3354e0e 100644 --- a/container/stream/attach.go +++ b/container/stream/attach.go @@ -7,6 +7,7 @@ import ( "golang.org/x/net/context" "github.com/Sirupsen/logrus" + "github.com/docker/docker/pkg/pools" "github.com/docker/docker/pkg/promise" "github.com/docker/docker/pkg/term" ) @@ -86,7 +87,7 @@ func (c *Config) CopyStreams(ctx context.Context, cfg *AttachConfig) chan error if cfg.TTY { _, err = copyEscapable(cfg.CStdin, cfg.Stdin, cfg.DetachKeys) } else { - _, err = io.Copy(cfg.CStdin, cfg.Stdin) + _, err = pools.Copy(cfg.CStdin, cfg.Stdin) } if err == io.ErrClosedPipe { err = nil @@ -116,7 +117,7 @@ func (c *Config) CopyStreams(ctx context.Context, cfg *AttachConfig) chan error } logrus.Debugf("attach: %s: begin", name) - _, err := io.Copy(stream, streamPipe) + _, err := pools.Copy(stream, streamPipe) if err == io.ErrClosedPipe { err = nil } @@ -174,5 +175,5 @@ func copyEscapable(dst io.Writer, src io.ReadCloser, keys []byte) (written int64 pr := term.NewEscapeProxy(src, keys) defer src.Close() - return io.Copy(dst, pr) + return pools.Copy(dst, pr) } diff --git a/pkg/pools/pools.go b/pkg/pools/pools.go index 5c5aead698af6..6a111a3ba7cd2 100644 --- a/pkg/pools/pools.go +++ b/pkg/pools/pools.go @@ -17,15 +17,16 @@ import ( "github.com/docker/docker/pkg/ioutils" ) +const buffer32K = 32 * 1024 + var ( // BufioReader32KPool is a pool which returns bufio.Reader with a 32K buffer. BufioReader32KPool = newBufioReaderPoolWithSize(buffer32K) // BufioWriter32KPool is a pool which returns bufio.Writer with a 32K buffer. BufioWriter32KPool = newBufioWriterPoolWithSize(buffer32K) + buffer32KPool = newBufferPoolWithSize(buffer32K) ) -const buffer32K = 32 * 1024 - // BufioReaderPool is a bufio reader that uses sync.Pool. type BufioReaderPool struct { pool sync.Pool @@ -54,11 +55,31 @@ func (bufPool *BufioReaderPool) Put(b *bufio.Reader) { bufPool.pool.Put(b) } +type bufferPool struct { + pool sync.Pool +} + +func newBufferPoolWithSize(size int) *bufferPool { + return &bufferPool{ + pool: sync.Pool{ + New: func() interface{} { return make([]byte, size) }, + }, + } +} + +func (bp *bufferPool) Get() []byte { + return bp.pool.Get().([]byte) +} + +func (bp *bufferPool) Put(b []byte) { + bp.pool.Put(b) +} + // Copy is a convenience wrapper which uses a buffer to avoid allocation in io.Copy. func Copy(dst io.Writer, src io.Reader) (written int64, err error) { - buf := BufioReader32KPool.Get(src) - written, err = io.Copy(dst, buf) - BufioReader32KPool.Put(buf) + buf := buffer32KPool.Get() + written, err = io.CopyBuffer(dst, src, buf) + buffer32KPool.Put(buf) return } diff --git a/pkg/pools/pools_test.go b/pkg/pools/pools_test.go index 1661b780c90c3..d71cb99ac77d8 100644 --- a/pkg/pools/pools_test.go +++ b/pkg/pools/pools_test.go @@ -159,3 +159,8 @@ func TestNewWriteCloserWrapperWithAWriteCloser(t *testing.T) { t.Fatalf("The ReaderCloser should have been closed, it is not.") } } + +func TestBufferPoolPutAndGet(t *testing.T) { + buf := buffer32KPool.Get() + buffer32KPool.Put(buf) +}