Permalink
Browse files

Merge branch 'reuse_conn_buffer'

Reusing connection buffers

Conflicts:
	server.go
  • Loading branch information...
2 parents 5ddf90d + 14a91d4 commit bceb445508b4944d7d63297ebb99adc999010f5b @dgrijalva dgrijalva committed Apr 23, 2012
Showing with 131 additions and 2 deletions.
  1. +63 −0 buffer_pool.go
  2. +60 −0 buffer_pool_test.go
  3. +8 −2 server.go
View
@@ -0,0 +1,63 @@
+package falcore
+
+import (
+ "bufio"
+ "io"
+ "io/ioutil"
+)
+
+// uses a chan as a leaky bucket buffer pool
+type bufferPool struct {
+ // size of buffer when creating new ones
+ bufSize int
+ // the actual pool of buffers ready for reuse
+ pool chan *bufferPoolEntry
+}
+
+// This is what's stored in the buffer. It allows
+// for the underlying io.Reader to be changed out
+// inside a bufio.Reader. This is required for reuse.
+type bufferPoolEntry struct {
+ br *bufio.Reader
+ source io.Reader
+}
+
+// make bufferPoolEntry a passthrough io.Reader
+func (bpe *bufferPoolEntry) Read(p []byte) (n int, err error) {
+ return bpe.source.Read(p)
+}
+
+func newBufferPool(poolSize, bufferSize int) *bufferPool {
+ return &bufferPool{
+ bufSize: bufferSize,
+ pool: make(chan *bufferPoolEntry, poolSize),
+ }
+}
+
+// Take a buffer from the pool and set
+// it up to read from r
+func (p *bufferPool) take(r io.Reader) (bpe *bufferPoolEntry) {
+ select {
+ case bpe = <-p.pool:
+ // prepare for reuse
+ if a := bpe.br.Buffered(); a > 0 {
+ // drain the internal buffer
+ io.CopyN(ioutil.Discard, bpe.br, int64(a))
+ }
+ // swap out the underlying reader
+ bpe.source = r
+ default:
+ // none available. create a new one
+ bpe = &bufferPoolEntry{nil, r}
+ bpe.br = bufio.NewReaderSize(bpe, p.bufSize)
+ }
+ return
+}
+
+// Return a buffer to the pool
+func (p *bufferPool) give(bpe *bufferPoolEntry) {
+ select {
+ case p.pool <- bpe: // return to pool
+ default: // discard
+ }
+}
View
@@ -0,0 +1,60 @@
+package falcore
+
+import (
+ /* "io"*/
+ "bytes"
+ "testing"
+)
+
+func TestBufferPool(t *testing.T) {
+ pool := newBufferPool(10, 1024)
+
+ text := []byte("Hello World")
+
+ // get one
+ bpe := pool.take(bytes.NewBuffer(text))
+ // read all
+ out := make([]byte, 1024)
+ l, _ := bpe.br.Read(out)
+ if bytes.Compare(out[0:l], text) != 0 {
+ t.Errorf("Read invalid data: %v", out)
+ }
+ if l != len(text) {
+ t.Errorf("Expected length %v got %v", len(text), l)
+ }
+ pool.give(bpe)
+
+ // get one
+ bpe = pool.take(bytes.NewBuffer(text))
+ // read all
+ out = make([]byte, 1024)
+ l, _ = bpe.br.Read(out)
+ if bytes.Compare(out[0:l], text) != 0 {
+ t.Errorf("Read invalid data: %v", out)
+ }
+ if l != len(text) {
+ t.Errorf("Expected length %v got %v", len(text), l)
+ }
+ pool.give(bpe)
+
+ // get one
+ bpe = pool.take(bytes.NewBuffer(text))
+ // read 1 byte
+ out = make([]byte, 1)
+ bpe.br.Read(out)
+ pool.give(bpe)
+
+ // get one
+ bpe = pool.take(bytes.NewBuffer(text))
+ // read all
+ out = make([]byte, 1024)
+ l, _ = bpe.br.Read(out)
+ if bytes.Compare(out[0:l], text) != 0 {
+ t.Errorf("Read invalid data: %v", out)
+ }
+ if l != len(text) {
+ t.Errorf("Expected length %v got %v", len(text), l)
+ }
+ pool.give(bpe)
+
+}
View
@@ -29,6 +29,7 @@ type Server struct {
AcceptReady chan int
sendfile bool
sockOpt int
+ bufferPool *bufferPool
}
func NewServer(port int, pipeline *Pipeline) *Server {
@@ -53,6 +54,10 @@ func NewServer(port int, pipeline *Pipeline) *Server {
default:
s.sendfile = false
}
+
+ // buffer pool for reusing connection bufio.Readers
+ s.bufferPool = newBufferPool(100, 8192)
+
return s
}
@@ -213,14 +218,15 @@ func (srv *Server) serve() (e error) {
func (srv *Server) handler(c net.Conn) {
startTime := time.Now()
defer srv.connectionFinished(c)
- buf := bufio.NewReaderSize(c, 8192)
+ bpe := srv.bufferPool.take(c)
+ defer srv.bufferPool.give(bpe)
var err error
var req *http.Request
// no keepalive (for now)
reqCount := 0
keepAlive := true
for err == nil && keepAlive {
- if req, err = http.ReadRequest(buf); err == nil {
+ if req, err = http.ReadRequest(bpe.br); err == nil {
if req.Header.Get("Connection") != "Keep-Alive" {
keepAlive = false
}

0 comments on commit bceb445

Please sign in to comment.