Optimizes tree lookup
This commit is contained in:
		
							
								
								
									
										29
									
								
								gin.go
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								gin.go
									
									
									
									
									
								
							@ -28,12 +28,12 @@ type (
 | 
				
			|||||||
	Engine struct {
 | 
						Engine struct {
 | 
				
			||||||
		RouterGroup
 | 
							RouterGroup
 | 
				
			||||||
		HTMLRender  render.HTMLRender
 | 
							HTMLRender  render.HTMLRender
 | 
				
			||||||
		pool        sync.Pool
 | 
					 | 
				
			||||||
		allNoRoute  HandlersChain
 | 
							allNoRoute  HandlersChain
 | 
				
			||||||
		allNoMethod HandlersChain
 | 
							allNoMethod HandlersChain
 | 
				
			||||||
		noRoute     HandlersChain
 | 
							noRoute     HandlersChain
 | 
				
			||||||
		noMethod    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
 | 
							// Enables automatic redirection if the current route can't be matched but a
 | 
				
			||||||
		// handler for the path with (without) the trailing slash exists.
 | 
							// handler for the path with (without) the trailing slash exists.
 | 
				
			||||||
@ -75,7 +75,7 @@ func New() *Engine {
 | 
				
			|||||||
		RedirectTrailingSlash:  true,
 | 
							RedirectTrailingSlash:  true,
 | 
				
			||||||
		RedirectFixedPath:      true,
 | 
							RedirectFixedPath:      true,
 | 
				
			||||||
		HandleMethodNotAllowed: true,
 | 
							HandleMethodNotAllowed: true,
 | 
				
			||||||
		trees: make(map[string]*node),
 | 
							trees: make(methodTrees, 0, 6),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	engine.RouterGroup.engine = engine
 | 
						engine.RouterGroup.engine = engine
 | 
				
			||||||
	engine.pool.New = func() interface{} {
 | 
						engine.pool.New = func() interface{} {
 | 
				
			||||||
@ -155,10 +155,13 @@ func (engine *Engine) addRoute(method, path string, handlers HandlersChain) {
 | 
				
			|||||||
		panic("there must be at least one handler")
 | 
							panic("there must be at least one handler")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	root := engine.trees[method]
 | 
						root := engine.trees.get("method")
 | 
				
			||||||
	if root == nil {
 | 
						if root == nil {
 | 
				
			||||||
		root = new(node)
 | 
							root = new(node)
 | 
				
			||||||
		engine.trees[method] = root
 | 
							engine.trees = append(engine.trees, methodTree{
 | 
				
			||||||
 | 
								method: method,
 | 
				
			||||||
 | 
								root:   root,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	root.addRoute(path, handlers)
 | 
						root.addRoute(path, handlers)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -210,9 +213,11 @@ func (engine *Engine) handleHTTPRequest(context *Context) {
 | 
				
			|||||||
	path := context.Request.URL.Path
 | 
						path := context.Request.URL.Path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Find root of the tree for the given HTTP method
 | 
						// Find root of the tree for the given HTTP method
 | 
				
			||||||
	if root := engine.trees[httpMethod]; root != nil {
 | 
						t := engine.trees
 | 
				
			||||||
 | 
						for i, tl := 0, len(t); i < tl; i++ {
 | 
				
			||||||
 | 
							if t[i].method == httpMethod {
 | 
				
			||||||
			// Find route in tree
 | 
								// Find route in tree
 | 
				
			||||||
		handlers, params, tsr := root.getValue(path, context.Params)
 | 
								handlers, params, tsr := t[i].root.getValue(path, context.Params)
 | 
				
			||||||
			if handlers != nil {
 | 
								if handlers != nil {
 | 
				
			||||||
				context.handlers = handlers
 | 
									context.handlers = handlers
 | 
				
			||||||
				context.Params = params
 | 
									context.Params = params
 | 
				
			||||||
@ -221,16 +226,18 @@ func (engine *Engine) handleHTTPRequest(context *Context) {
 | 
				
			|||||||
				return
 | 
									return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			} else if httpMethod != "CONNECT" && path != "/" {
 | 
								} else if httpMethod != "CONNECT" && path != "/" {
 | 
				
			||||||
			if engine.serveAutoRedirect(context, root, tsr) {
 | 
									if engine.serveAutoRedirect(context, t[i].root, tsr) {
 | 
				
			||||||
					return
 | 
										return
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: unit test
 | 
				
			||||||
	if engine.HandleMethodNotAllowed {
 | 
						if engine.HandleMethodNotAllowed {
 | 
				
			||||||
		for method, root := range engine.trees {
 | 
							for _, tree := range engine.trees {
 | 
				
			||||||
			if method != httpMethod {
 | 
								if tree.method != httpMethod {
 | 
				
			||||||
				if handlers, _, _ := root.getValue(path, nil); handlers != nil {
 | 
									if handlers, _, _ := tree.root.getValue(path, nil); handlers != nil {
 | 
				
			||||||
					context.handlers = engine.allNoMethod
 | 
										context.handlers = engine.allNoMethod
 | 
				
			||||||
					serveError(context, 405, default405Body)
 | 
										serveError(context, 405, default405Body)
 | 
				
			||||||
					return
 | 
										return
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										16
									
								
								tree.go
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								tree.go
									
									
									
									
									
								
							@ -36,6 +36,22 @@ func (ps Params) ByName(name string) (va string) {
 | 
				
			|||||||
	return
 | 
						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 {
 | 
					func min(a, b int) int {
 | 
				
			||||||
	if a <= b {
 | 
						if a <= b {
 | 
				
			||||||
		return a
 | 
							return a
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user