Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a global pool to share contexts between all routes #876

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"net/http"
"strings"
"sync"
)

// URLParam returns the url parameter from a http.Request object.
Expand Down Expand Up @@ -39,17 +40,29 @@ var (
RouteCtxKey = &contextKey{"RouteContext"}
)

var contextPool = sync.Pool{
New: func() interface{} {
return NewRouteContext()
},
}

func GetRouteContext(mx *Mux) *Context {
rctx := contextPool.Get().(*Context)
rctx.Routes = mx
return rctx
}

func PutRouteContext(rctx *Context) {
rctx.Reset()
contextPool.Put(rctx)
}

// Context is the default routing context set on the root node of a
// request context to track route patterns, URL parameters and
// an optional routing path.
type Context struct {
Routes Routes

// parentCtx is the parent of this one, for using Context as a
// context.Context directly. This is an optimization that saves
// 1 allocation.
parentCtx context.Context

// Routing path/method override used during the route search.
// See Mux#routeHTTP method.
RoutePath string
Expand Down Expand Up @@ -92,7 +105,6 @@ func (x *Context) Reset() {
x.routeParams.Values = x.routeParams.Values[:0]
x.methodNotAllowed = false
x.methodsAllowed = x.methodsAllowed[:0]
x.parentCtx = nil
}

// URLParam returns the corresponding URL parameter value from the request
Expand Down
18 changes: 4 additions & 14 deletions mux.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"fmt"
"net/http"
"strings"
"sync"
)

var _ Router = &Mux{}
Expand Down Expand Up @@ -33,9 +32,6 @@ type Mux struct {
// to a parent mux
parent *Mux

// Routing context pool
pool *sync.Pool

// Custom route not found handler
notFoundHandler http.HandlerFunc

Expand All @@ -50,10 +46,7 @@ type Mux struct {
// NewMux returns a newly initialized Mux object that implements the Router
// interface.
func NewMux() *Mux {
mux := &Mux{tree: &node{}, pool: &sync.Pool{}}
mux.pool.New = func() interface{} {
return NewRouteContext()
}
mux := &Mux{tree: &node{}}
return mux
}

Expand All @@ -78,17 +71,14 @@ func (mx *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// mx.handler that is comprised of mx.middlewares + mx.routeHTTP.
// Once the request is finished, reset the routing context and put it back
// into the pool for reuse from another request.
rctx = mx.pool.Get().(*Context)
rctx.Reset()
rctx.Routes = mx
rctx.parentCtx = r.Context()
rctx = GetRouteContext(mx)
defer PutRouteContext(rctx)

// NOTE: r.WithContext() causes 2 allocations and context.WithValue() causes 1 allocation
r = r.WithContext(context.WithValue(r.Context(), RouteCtxKey, rctx))

// Serve the request and once its done, put the request context back in the sync pool
mx.handler.ServeHTTP(w, r)
mx.pool.Put(rctx)
}

// Use appends a middleware handler to the Mux middleware stack.
Expand Down Expand Up @@ -255,7 +245,7 @@ func (mx *Mux) With(middlewares ...func(http.Handler) http.Handler) Router {
mws = append(mws, middlewares...)

im := &Mux{
pool: mx.pool, inline: true, parent: mx, tree: mx.tree, middlewares: mws,
inline: true, parent: mx, tree: mx.tree, middlewares: mws,
notFoundHandler: mx.notFoundHandler, methodNotAllowedHandler: mx.methodNotAllowedHandler,
}

Expand Down