Skip to content

Commit

Permalink
Optimizes tree lookup
Browse files Browse the repository at this point in the history
  • Loading branch information
manucorporat committed May 29, 2015
1 parent 9584e4e commit 66e9feb
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 20 deletions.
47 changes: 27 additions & 20 deletions gin.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ type (
Engine struct {
RouterGroup
HTMLRender render.HTMLRender
pool sync.Pool
allNoRoute HandlersChain
allNoMethod HandlersChain
noRoute HandlersChain
noMethod HandlersChain
trees map[string]*node
pool sync.Pool
trees methodTrees

// Enables automatic redirection if the current route can't be matched but a
// handler for the path with (without) the trailing slash exists.
Expand Down Expand Up @@ -75,7 +75,7 @@ func New() *Engine {
RedirectTrailingSlash: true,
RedirectFixedPath: true,
HandleMethodNotAllowed: true,
trees: make(map[string]*node),
trees: make(methodTrees, 0, 6),
}
engine.RouterGroup.engine = engine
engine.pool.New = func() interface{} {
Expand Down Expand Up @@ -155,10 +155,13 @@ func (engine *Engine) addRoute(method, path string, handlers HandlersChain) {
panic("there must be at least one handler")
}

root := engine.trees[method]
root := engine.trees.get("method")
if root == nil {
root = new(node)
engine.trees[method] = root
engine.trees = append(engine.trees, methodTree{
method: method,
root: root,
})
}
root.addRoute(path, handlers)
}
Expand Down Expand Up @@ -210,27 +213,31 @@ func (engine *Engine) handleHTTPRequest(context *Context) {
path := context.Request.URL.Path

// Find root of the tree for the given HTTP method
if root := engine.trees[httpMethod]; root != nil {
// Find route in tree
handlers, params, tsr := root.getValue(path, context.Params)
if handlers != nil {
context.handlers = handlers
context.Params = params
context.Next()
context.writermem.WriteHeaderNow()
return

} else if httpMethod != "CONNECT" && path != "/" {
if engine.serveAutoRedirect(context, root, tsr) {
t := engine.trees
for i, tl := 0, len(t); i < tl; i++ {
if t[i].method == httpMethod {
// Find route in tree
handlers, params, tsr := t[i].root.getValue(path, context.Params)
if handlers != nil {
context.handlers = handlers
context.Params = params
context.Next()
context.writermem.WriteHeaderNow()
return

} else if httpMethod != "CONNECT" && path != "/" {
if engine.serveAutoRedirect(context, t[i].root, tsr) {
return
}
}
}
}

// TODO: unit test
if engine.HandleMethodNotAllowed {
for method, root := range engine.trees {
if method != httpMethod {
if handlers, _, _ := root.getValue(path, nil); handlers != nil {
for _, tree := range engine.trees {
if tree.method != httpMethod {
if handlers, _, _ := tree.root.getValue(path, nil); handlers != nil {
context.handlers = engine.allNoMethod
serveError(context, 405, default405Body)
return
Expand Down
16 changes: 16 additions & 0 deletions tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,22 @@ func (ps Params) ByName(name string) (va string) {
return
}

type methodTree struct {
method string
root *node
}

type methodTrees []methodTree

func (trees methodTrees) get(method string) *node {
for _, tree := range trees {
if tree.method == method {
return tree.root
}
}
return nil
}

func min(a, b int) int {
if a <= b {
return a
Expand Down

0 comments on commit 66e9feb

Please sign in to comment.