From ab8aa1f6d8fae7c8863780f6b1b8cb37e11e1815 Mon Sep 17 00:00:00 2001 From: Carl Jackson Date: Sat, 23 Aug 2014 14:34:30 -0700 Subject: [PATCH] Use sync.Pool for go1.3 and up This has the additional benefit of removing the need for a go1.3 branch. --- web/chanpool.go | 31 +++++++++++++++++++++++++++++++ web/cpool.go | 24 ++++++++++++++++++++++++ web/middleware.go | 27 +++++++-------------------- web/middleware_test.go | 4 ++-- web/mux.go | 2 +- 5 files changed, 65 insertions(+), 23 deletions(-) create mode 100644 web/chanpool.go create mode 100644 web/cpool.go diff --git a/web/chanpool.go b/web/chanpool.go new file mode 100644 index 0000000..fbe2977 --- /dev/null +++ b/web/chanpool.go @@ -0,0 +1,31 @@ +// +build !go1.3 + +package web + +// This is an alternate implementation of Go 1.3's sync.Pool. + +// Maximum size of the pool of spare middleware stacks +const cPoolSize = 32 + +type cPool chan *cStack + +func makeCPool() *cPool { + var p cPool = make(chan *cStack, cPoolSize) + return &p +} + +func (c cPool) alloc() *cStack { + select { + case cs := <-c: + return cs + default: + return nil + } +} + +func (c cPool) release(cs *cStack) { + select { + case c <- cs: + default: + } +} diff --git a/web/cpool.go b/web/cpool.go new file mode 100644 index 0000000..98aa688 --- /dev/null +++ b/web/cpool.go @@ -0,0 +1,24 @@ +// +build go1.3 + +package web + +import "sync" + +type cPool sync.Pool + +func makeCPool() *cPool { + return &cPool{} +} + +func (c *cPool) alloc() *cStack { + cs := (*sync.Pool)(c).Get() + if cs == nil { + return nil + } else { + return cs.(*cStack) + } +} + +func (c *cPool) release(cs *cStack) { + (*sync.Pool)(c).Put(cs) +} diff --git a/web/middleware.go b/web/middleware.go index a91b9ad..882cdd4 100644 --- a/web/middleware.go +++ b/web/middleware.go @@ -7,9 +7,6 @@ import ( "sync" ) -// Maximum size of the pool of spare middleware stacks -const mPoolSize = 32 - type mLayer struct { fn func(*C, http.Handler) http.Handler orig interface{} @@ -18,7 +15,7 @@ type mLayer struct { type mStack struct { lock sync.Mutex stack []mLayer - pool chan *cStack + pool *cPool router internalRouter } @@ -46,7 +43,7 @@ cStack on the floor. type cStack struct { C m http.Handler - pool chan *cStack + pool *cPool } func (s *cStack) ServeHTTP(w http.ResponseWriter, r *http.Request) { @@ -86,7 +83,7 @@ func (m *mStack) findLayer(l interface{}) int { } func (m *mStack) invalidate() { - m.pool = make(chan *cStack, mPoolSize) + m.pool = makeCPool() } func (m *mStack) newStack() *cStack { @@ -112,16 +109,8 @@ func (m *mStack) alloc() *cStack { // sync/atomic, but for now I happen to know that on all the // architectures I care about it happens to be atomic. p := m.pool - var cs *cStack - select { - case cs = <-p: - // This can happen if we race against an invalidation. It's - // completely peaceful, so long as we assume we can grab a cStack before - // our stack blows out. - if cs == nil { - return m.alloc() - } - default: + cs := p.alloc() + if cs == nil { cs = m.newStack() } @@ -134,10 +123,8 @@ func (m *mStack) release(cs *cStack) { if cs.pool != m.pool { return } - select { - case cs.pool <- cs: - default: - } + cs.pool.release(cs) + cs.pool = nil } // Append the given middleware to the middleware stack. See the documentation diff --git a/web/middleware_test.go b/web/middleware_test.go index e52027d..ef36ac9 100644 --- a/web/middleware_test.go +++ b/web/middleware_test.go @@ -19,7 +19,7 @@ func makeStack(ch chan string) *mStack { } return &mStack{ stack: make([]mLayer, 0), - pool: make(chan *cStack, mPoolSize), + pool: makeCPool(), router: iRouter(router), } } @@ -215,7 +215,7 @@ func TestContext(t *testing.T) { } st := mStack{ stack: make([]mLayer, 0), - pool: make(chan *cStack, mPoolSize), + pool: makeCPool(), router: iRouter(router), } st.Use(func(c *C, h http.Handler) http.Handler { diff --git a/web/mux.go b/web/mux.go index a8e9bc6..de5a032 100644 --- a/web/mux.go +++ b/web/mux.go @@ -61,7 +61,7 @@ func New() *Mux { mux := Mux{ mStack: mStack{ stack: make([]mLayer, 0), - pool: make(chan *cStack, mPoolSize), + pool: makeCPool(), }, router: router{ routes: make([]route, 0),