mirror of
https://github.com/gin-gonic/gin.git
synced 2025-10-16 13:22:09 +08:00
allocate skippedNodes from sync pool
This commit is contained in:
parent
2eb3ba8b52
commit
54f3b457c7
@ -55,8 +55,9 @@ type Context struct {
|
|||||||
index int8
|
index int8
|
||||||
fullPath string
|
fullPath string
|
||||||
|
|
||||||
engine *Engine
|
engine *Engine
|
||||||
params *Params
|
params *Params
|
||||||
|
skippedNodes *[]skippedNode
|
||||||
|
|
||||||
// This mutex protect Keys map
|
// This mutex protect Keys map
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
@ -99,6 +100,7 @@ func (c *Context) reset() {
|
|||||||
c.queryCache = nil
|
c.queryCache = nil
|
||||||
c.formCache = nil
|
c.formCache = nil
|
||||||
*c.params = (*c.params)[:0]
|
*c.params = (*c.params)[:0]
|
||||||
|
*c.skippedNodes = (*c.skippedNodes)[:0]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy returns a copy of the current context that can be safely used outside the request's scope.
|
// Copy returns a copy of the current context that can be safely used outside the request's scope.
|
||||||
|
12
gin.go
12
gin.go
@ -147,6 +147,7 @@ type Engine struct {
|
|||||||
pool sync.Pool
|
pool sync.Pool
|
||||||
trees methodTrees
|
trees methodTrees
|
||||||
maxParams uint16
|
maxParams uint16
|
||||||
|
maxSections uint16
|
||||||
trustedCIDRs []*net.IPNet
|
trustedCIDRs []*net.IPNet
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,7 +203,8 @@ func Default() *Engine {
|
|||||||
|
|
||||||
func (engine *Engine) allocateContext() *Context {
|
func (engine *Engine) allocateContext() *Context {
|
||||||
v := make(Params, 0, engine.maxParams)
|
v := make(Params, 0, engine.maxParams)
|
||||||
return &Context{engine: engine, params: &v}
|
skippedNodes := make([]skippedNode, 0, engine.maxSections)
|
||||||
|
return &Context{engine: engine, params: &v, skippedNodes: &skippedNodes}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delims sets template left and right delims and returns a Engine instance.
|
// Delims sets template left and right delims and returns a Engine instance.
|
||||||
@ -308,6 +310,10 @@ func (engine *Engine) addRoute(method, path string, handlers HandlersChain) {
|
|||||||
if paramsCount := countParams(path); paramsCount > engine.maxParams {
|
if paramsCount := countParams(path); paramsCount > engine.maxParams {
|
||||||
engine.maxParams = paramsCount
|
engine.maxParams = paramsCount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if sectionsCount := countSections(path); sectionsCount > engine.maxSections {
|
||||||
|
engine.maxSections = sectionsCount
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Routes returns a slice of registered routes, including some useful information, such as:
|
// Routes returns a slice of registered routes, including some useful information, such as:
|
||||||
@ -529,7 +535,7 @@ func (engine *Engine) handleHTTPRequest(c *Context) {
|
|||||||
}
|
}
|
||||||
root := t[i].root
|
root := t[i].root
|
||||||
// Find route in tree
|
// Find route in tree
|
||||||
value := root.getValue(rPath, c.params, unescape)
|
value := root.getValue(rPath, c.params, c.skippedNodes, unescape)
|
||||||
if value.params != nil {
|
if value.params != nil {
|
||||||
c.Params = *value.params
|
c.Params = *value.params
|
||||||
}
|
}
|
||||||
@ -557,7 +563,7 @@ func (engine *Engine) handleHTTPRequest(c *Context) {
|
|||||||
if tree.method == httpMethod {
|
if tree.method == httpMethod {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if value := tree.root.getValue(rPath, nil, unescape); value.handlers != nil {
|
if value := tree.root.getValue(rPath, nil, c.skippedNodes, unescape); value.handlers != nil {
|
||||||
c.handlers = engine.allNoMethod
|
c.handlers = engine.allNoMethod
|
||||||
serveError(c, http.StatusMethodNotAllowed, default405Body)
|
serveError(c, http.StatusMethodNotAllowed, default405Body)
|
||||||
return
|
return
|
||||||
|
31
tree.go
31
tree.go
@ -410,8 +410,8 @@ type skippedNode struct {
|
|||||||
// If no handle can be found, a TSR (trailing slash redirect) recommendation is
|
// If no handle can be found, a TSR (trailing slash redirect) recommendation is
|
||||||
// made if a handle exists with an extra (without the) trailing slash for the
|
// made if a handle exists with an extra (without the) trailing slash for the
|
||||||
// given path.
|
// given path.
|
||||||
func (n *node) getValue(path string, params *Params, unescape bool) (value nodeValue) {
|
func (n *node) getValue(path string, params *Params, skippedNodes *[]skippedNode, unescape bool) (value nodeValue) {
|
||||||
skippedNodes := make([]skippedNode, 0, countSections(path)) // Caching the latest nodes
|
//skippedNodes := make([]skippedNode, 0, countSections(path)) // Caching the latest nodes
|
||||||
var globalParamsCount int16
|
var globalParamsCount int16
|
||||||
|
|
||||||
walk: // Outer loop for walking the tree
|
walk: // Outer loop for walking the tree
|
||||||
@ -427,9 +427,9 @@ walk: // Outer loop for walking the tree
|
|||||||
if c == idxc {
|
if c == idxc {
|
||||||
// strings.HasPrefix(n.children[len(n.children)-1].path, ":") == n.wildChild
|
// strings.HasPrefix(n.children[len(n.children)-1].path, ":") == n.wildChild
|
||||||
if n.wildChild {
|
if n.wildChild {
|
||||||
index := len(skippedNodes)
|
index := len(*skippedNodes)
|
||||||
skippedNodes = skippedNodes[:index+1]
|
*skippedNodes = (*skippedNodes)[:index+1]
|
||||||
skippedNodes[index] = skippedNode{
|
(*skippedNodes)[index] = skippedNode{
|
||||||
path: prefix + path,
|
path: prefix + path,
|
||||||
node: &node{
|
node: &node{
|
||||||
path: n.path,
|
path: n.path,
|
||||||
@ -464,10 +464,9 @@ walk: // Outer loop for walking the tree
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
if path != "/" && !n.wildChild {
|
if path != "/" && !n.wildChild {
|
||||||
for len(skippedNodes) > 0 {
|
for l := len(*skippedNodes); l > 0; {
|
||||||
l := len(skippedNodes)
|
skippedNode := (*skippedNodes)[l-1]
|
||||||
skippedNode := skippedNodes[l-1]
|
*skippedNodes = (*skippedNodes)[:l-1]
|
||||||
skippedNodes = skippedNodes[:l-1]
|
|
||||||
if strings.HasSuffix(skippedNode.path, path) {
|
if strings.HasSuffix(skippedNode.path, path) {
|
||||||
path = skippedNode.path
|
path = skippedNode.path
|
||||||
n = skippedNode.node
|
n = skippedNode.node
|
||||||
@ -593,10 +592,9 @@ walk: // Outer loop for walking the tree
|
|||||||
// If the current path does not equal '/' and the node does not have a registered handle and the most recently matched node has a child node
|
// If the current path does not equal '/' and the node does not have a registered handle and the most recently matched node has a child node
|
||||||
// the current node needs to be equal to the latest matching node
|
// the current node needs to be equal to the latest matching node
|
||||||
if n.handlers == nil && path != "/" {
|
if n.handlers == nil && path != "/" {
|
||||||
for len(skippedNodes) > 0 {
|
for l := len(*skippedNodes); l > 0; {
|
||||||
l := len(skippedNodes)
|
skippedNode := (*skippedNodes)[l-1]
|
||||||
skippedNode := skippedNodes[l-1]
|
*skippedNodes = (*skippedNodes)[:l-1]
|
||||||
skippedNodes = skippedNodes[:l-1]
|
|
||||||
if strings.HasSuffix(skippedNode.path, path) {
|
if strings.HasSuffix(skippedNode.path, path) {
|
||||||
path = skippedNode.path
|
path = skippedNode.path
|
||||||
n = skippedNode.node
|
n = skippedNode.node
|
||||||
@ -639,10 +637,9 @@ walk: // Outer loop for walking the tree
|
|||||||
}
|
}
|
||||||
|
|
||||||
if path != "/" {
|
if path != "/" {
|
||||||
for len(skippedNodes) > 0 {
|
for l := len(*skippedNodes); l > 0; {
|
||||||
l := len(skippedNodes)
|
skippedNode := (*skippedNodes)[l-1]
|
||||||
skippedNode := skippedNodes[l-1]
|
*skippedNodes = (*skippedNodes)[:l-1]
|
||||||
skippedNodes = skippedNodes[:l-1]
|
|
||||||
if strings.HasSuffix(skippedNode.path, path) {
|
if strings.HasSuffix(skippedNode.path, path) {
|
||||||
path = skippedNode.path
|
path = skippedNode.path
|
||||||
n = skippedNode.node
|
n = skippedNode.node
|
||||||
|
17
tree_test.go
17
tree_test.go
@ -33,6 +33,11 @@ func getParams() *Params {
|
|||||||
return &ps
|
return &ps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getSkippedNodes() *[]skippedNode {
|
||||||
|
ps := make([]skippedNode, 0, 20)
|
||||||
|
return &ps
|
||||||
|
}
|
||||||
|
|
||||||
func checkRequests(t *testing.T, tree *node, requests testRequests, unescapes ...bool) {
|
func checkRequests(t *testing.T, tree *node, requests testRequests, unescapes ...bool) {
|
||||||
unescape := false
|
unescape := false
|
||||||
if len(unescapes) >= 1 {
|
if len(unescapes) >= 1 {
|
||||||
@ -40,7 +45,7 @@ func checkRequests(t *testing.T, tree *node, requests testRequests, unescapes ..
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, request := range requests {
|
for _, request := range requests {
|
||||||
value := tree.getValue(request.path, getParams(), unescape)
|
value := tree.getValue(request.path, getParams(), getSkippedNodes(), unescape)
|
||||||
|
|
||||||
if value.handlers == nil {
|
if value.handlers == nil {
|
||||||
if !request.nilHandler {
|
if !request.nilHandler {
|
||||||
@ -605,7 +610,7 @@ func TestTreeTrailingSlashRedirect(t *testing.T) {
|
|||||||
"/doc/",
|
"/doc/",
|
||||||
}
|
}
|
||||||
for _, route := range tsrRoutes {
|
for _, route := range tsrRoutes {
|
||||||
value := tree.getValue(route, nil, false)
|
value := tree.getValue(route, nil, getSkippedNodes(), false)
|
||||||
if value.handlers != nil {
|
if value.handlers != nil {
|
||||||
t.Fatalf("non-nil handler for TSR route '%s", route)
|
t.Fatalf("non-nil handler for TSR route '%s", route)
|
||||||
} else if !value.tsr {
|
} else if !value.tsr {
|
||||||
@ -622,7 +627,7 @@ func TestTreeTrailingSlashRedirect(t *testing.T) {
|
|||||||
"/api/world/abc",
|
"/api/world/abc",
|
||||||
}
|
}
|
||||||
for _, route := range noTsrRoutes {
|
for _, route := range noTsrRoutes {
|
||||||
value := tree.getValue(route, nil, false)
|
value := tree.getValue(route, nil, getSkippedNodes(), false)
|
||||||
if value.handlers != nil {
|
if value.handlers != nil {
|
||||||
t.Fatalf("non-nil handler for No-TSR route '%s", route)
|
t.Fatalf("non-nil handler for No-TSR route '%s", route)
|
||||||
} else if value.tsr {
|
} else if value.tsr {
|
||||||
@ -641,7 +646,7 @@ func TestTreeRootTrailingSlashRedirect(t *testing.T) {
|
|||||||
t.Fatalf("panic inserting test route: %v", recv)
|
t.Fatalf("panic inserting test route: %v", recv)
|
||||||
}
|
}
|
||||||
|
|
||||||
value := tree.getValue("/", nil, false)
|
value := tree.getValue("/", nil, getSkippedNodes(), false)
|
||||||
if value.handlers != nil {
|
if value.handlers != nil {
|
||||||
t.Fatalf("non-nil handler")
|
t.Fatalf("non-nil handler")
|
||||||
} else if value.tsr {
|
} else if value.tsr {
|
||||||
@ -821,7 +826,7 @@ func TestTreeInvalidNodeType(t *testing.T) {
|
|||||||
|
|
||||||
// normal lookup
|
// normal lookup
|
||||||
recv := catchPanic(func() {
|
recv := catchPanic(func() {
|
||||||
tree.getValue("/test", nil, false)
|
tree.getValue("/test", nil, getSkippedNodes(), false)
|
||||||
})
|
})
|
||||||
if rs, ok := recv.(string); !ok || rs != panicMsg {
|
if rs, ok := recv.(string); !ok || rs != panicMsg {
|
||||||
t.Fatalf("Expected panic '"+panicMsg+"', got '%v'", recv)
|
t.Fatalf("Expected panic '"+panicMsg+"', got '%v'", recv)
|
||||||
@ -846,7 +851,7 @@ func TestTreeInvalidParamsType(t *testing.T) {
|
|||||||
params := make(Params, 0)
|
params := make(Params, 0)
|
||||||
|
|
||||||
// try to trigger slice bounds out of range with capacity 0
|
// try to trigger slice bounds out of range with capacity 0
|
||||||
tree.getValue("/test", ¶ms, false)
|
tree.getValue("/test", ¶ms, getSkippedNodes(), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTreeWildcardConflictEx(t *testing.T) {
|
func TestTreeWildcardConflictEx(t *testing.T) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user