Skip to content

Commit

Permalink
Improve performance
Browse files Browse the repository at this point in the history
  • Loading branch information
Sergio Andres Virviescas Santana committed May 13, 2020
1 parent 5c28b43 commit 0298f52
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 136 deletions.
166 changes: 90 additions & 76 deletions radix/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -337,26 +337,23 @@ walk:
continue walk

} else if path == child.path {
methods := []string{method, MethodWild}

for i := range methods {
nHandler := child.handlers[methods[i]]

switch {
case nHandler == nil:
continue
case nHandler.tsr:
return nil, true
case nHandler.handler != nil:
return nHandler.handler, false
case nHandler.wildcard != nil:
if ctx != nil {
ctx.SetUserValue(nHandler.wildcard.paramKey, path)
}
nHandler := child.handlers[method]

return nHandler.wildcard.handler, false
switch {
case nHandler == nil:
case nHandler.tsr:
return nil, true
case nHandler.handler != nil:
return nHandler.handler, false
case nHandler.wildcard != nil:
if ctx != nil {
ctx.SetUserValue(nHandler.wildcard.paramKey, path)
}

return nHandler.wildcard.handler, false
}

return child.getFromMethodWild(ctx, path)
}

case param:
Expand Down Expand Up @@ -385,24 +382,23 @@ walk:
}

} else if len(path) == end {
methods := []string{method, MethodWild}

for i := range methods {
nHandler := child.handlers[methods[i]]
nHandler := child.handlers[method]
if nHandler == nil {
nHandler = child.handlers[MethodWild]
}

switch {
case nHandler == nil:
continue
case nHandler.tsr:
return nil, true
case ctx != nil:
for i, key := range child.paramKeys {
ctx.SetUserValue(key, values[i])
}
switch {
case nHandler == nil:
return nil, false
case nHandler.tsr:
return nil, true
case ctx != nil:
for i, key := range child.paramKeys {
ctx.SetUserValue(key, values[i])
}

return nHandler.handler, false
}

return nHandler.handler, false
}

default:
Expand All @@ -411,26 +407,45 @@ walk:
}

if n.handlers != nil {
methods := []string{method, MethodWild}

for i := range methods {
nHandler := n.handlers[methods[i]]

switch {
case nHandler == nil, nHandler.wildcard == nil:
continue
case ctx != nil:
ctx.SetUserValue(nHandler.wildcard.paramKey, path)
}
nHandler := n.handlers[method]
if nHandler == nil {
nHandler = n.handlers[MethodWild]
}

return nHandler.wildcard.handler, false
switch {
case nHandler == nil, nHandler.wildcard == nil:
return nil, false
case ctx != nil:
ctx.SetUserValue(nHandler.wildcard.paramKey, path)
}

return nHandler.wildcard.handler, false
}

return nil, false
}
}

func (n *node) getFromMethodWild(ctx *fasthttp.RequestCtx, wildPath string) (fasthttp.RequestHandler, bool) {
nHandler := n.handlers[MethodWild]

switch {
case nHandler == nil:
case nHandler.tsr:
return nil, true
case nHandler.handler != nil:
return nHandler.handler, false
case nHandler.wildcard != nil:
if ctx != nil {
ctx.SetUserValue(nHandler.wildcard.paramKey, wildPath)
}

return nHandler.wildcard.handler, false
}

return nil, false
}

func (n *node) find(method, path string, buf *bytebufferpool.ByteBuffer) (bool, bool) {
if len(path) > len(n.path) {
if !strings.EqualFold(path[:len(n.path)], n.path) {
Expand All @@ -448,28 +463,28 @@ func (n *node) find(method, path string, buf *bytebufferpool.ByteBuffer) (bool,
bufferRemoveString(buf, n.path)

} else if strings.EqualFold(path, n.path) {
methods := []string{method, MethodWild}
nHandler := n.handlers[method]
if nHandler == nil {
nHandler = n.handlers[MethodWild]

for i := range methods {
nHandler := n.handlers[methods[i]]
if nHandler == nil {
continue
return false, false
}
}

buf.WriteString(n.path)

if nHandler.tsr {
if n.path == "/" {
bufferRemoveString(buf, n.path)
} else {
buf.WriteByte('/')
}
buf.WriteString(n.path)

return true, true
if nHandler.tsr {
if n.path == "/" {
bufferRemoveString(buf, n.path)
} else {
buf.WriteByte('/')
}

return true, false
return true, true
}

return true, false
}

return false, false
Expand Down Expand Up @@ -503,22 +518,22 @@ func (n *node) findFromChild(method, path string, buf *bytebufferpool.ByteBuffer
}

} else if len(path) == end {
methods := []string{method, MethodWild}
nHandler := child.handlers[method]
if nHandler == nil {
nHandler = child.handlers[MethodWild]

for i := range methods {
nHandler := child.handlers[methods[i]]
if nHandler == nil {
continue
return false, false
}
}

if nHandler.tsr {
buf.WriteByte('/')

return true, true
}
if nHandler.tsr {
buf.WriteByte('/')

return true, false
return true, true
}

return true, false
}

bufferRemoveString(buf, path[:end])
Expand All @@ -529,16 +544,15 @@ func (n *node) findFromChild(method, path string, buf *bytebufferpool.ByteBuffer
}

if n.handlers != nil {
methods := []string{method, MethodWild}

for i := range methods {
nHandler := n.handlers[methods[i]]
nHandler := n.handlers[method]
if nHandler == nil {
nHandler = n.handlers[MethodWild]
}

if nHandler != nil && nHandler.wildcard != nil {
buf.WriteString(path)
if nHandler != nil && nHandler.wildcard != nil {
buf.WriteString(path)

return true, false
}
return true, false
}
}

Expand Down
33 changes: 26 additions & 7 deletions radix/node_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,9 @@ func TestTreeAddAndGet(t *testing.T) {
})
}

func TestTreeWildcard(t *testing.T) {
func testTreeWildcardByMethod(t *testing.T, method string) {
tree := New()

method := randomHTTPMethod()
routes := [...]string{
"/",
"/cmd/{tool}/{sub}",
Expand All @@ -171,6 +170,10 @@ func TestTreeWildcard(t *testing.T) {
tree.Add(method, route, fakeHandler(route))
}

if method == MethodWild {
method = randomHTTPMethod()
}

checkRequests(t, tree, testRequests{
{method, "/", false, "/", nil},
{method, "/cmd/test/", false, "/cmd/{tool}/", map[string]interface{}{"tool": "test"}},
Expand All @@ -190,6 +193,12 @@ func TestTreeWildcard(t *testing.T) {
})
}

func TestTreeWildcard(t *testing.T) {
for _, method := range httpMethods {
testTreeWildcardByMethod(t, method)
}
}

func TestTreeWildcardConflict(t *testing.T) {
method := randomHTTPMethod()
routes := []testRoute{
Expand Down Expand Up @@ -442,12 +451,17 @@ func TestTreeRootTrailingSlashRedirect(t *testing.T) {
}

func TestTreeFindCaseInsensitivePath(t *testing.T) {
for _, method := range httpMethods {
testTreeFindCaseInsensitivePathByMethod(t, method)
}
}

func testTreeFindCaseInsensitivePathByMethod(t *testing.T, method string) {
tree := New()

longPath := "/l" + strings.Repeat("o", 128) + "ng"
lOngPath := "/l" + strings.Repeat("O", 128) + "ng/"

method := randomHTTPMethod()
routes := [...]string{
"/hi",
"/b/",
Expand Down Expand Up @@ -487,6 +501,11 @@ func TestTreeFindCaseInsensitivePath(t *testing.T) {
longPath,
}

reqMethod := method
if reqMethod == MethodWild {
reqMethod = randomHTTPMethod()
}

for _, route := range routes {
recv := catchPanic(func() {
tree.Add(method, route, fakeHandler(route))
Expand All @@ -501,7 +520,7 @@ func TestTreeFindCaseInsensitivePath(t *testing.T) {
// Check out == in for all registered routes
// With fixTrailingSlash = true
for _, route := range routes {
found := tree.FindCaseInsensitivePath(method, route, true, buf)
found := tree.FindCaseInsensitivePath(reqMethod, route, true, buf)
if !found {
t.Errorf("Route '%s' not found!", route)
} else if out := buf.String(); out != route {
Expand All @@ -512,7 +531,7 @@ func TestTreeFindCaseInsensitivePath(t *testing.T) {
}
// With fixTrailingSlash = false
for _, route := range routes {
found := tree.FindCaseInsensitivePath(method, route, false, buf)
found := tree.FindCaseInsensitivePath(reqMethod, route, false, buf)
if !found {
t.Errorf("Route '%s' not found!", route)
} else if out := buf.String(); out != route {
Expand Down Expand Up @@ -593,7 +612,7 @@ func TestTreeFindCaseInsensitivePath(t *testing.T) {
}
// With fixTrailingSlash = true
for _, test := range tests {
found := tree.FindCaseInsensitivePath(method, test.in, true, buf)
found := tree.FindCaseInsensitivePath(reqMethod, test.in, true, buf)
if out := buf.String(); found != test.found || (found && (out != test.out)) {
t.Errorf("Wrong result for '%s': got %s, %t; want %s, %t",
test.in, string(out), found, test.out, test.found)
Expand All @@ -603,7 +622,7 @@ func TestTreeFindCaseInsensitivePath(t *testing.T) {
}
// With fixTrailingSlash = false
for _, test := range tests {
found := tree.FindCaseInsensitivePath(method, test.in, false, buf)
found := tree.FindCaseInsensitivePath(reqMethod, test.in, false, buf)
if test.slash {
if found { // test needs a trailingSlash fix. It must not be found!
t.Errorf("Found without fixTrailingSlash: %s; got %s", test.in, buf.String())
Expand Down
34 changes: 16 additions & 18 deletions radix/tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,26 +69,24 @@ func (t *Tree) Get(method, path string, ctx *fasthttp.RequestCtx) (fasthttp.Requ
return t.root.getFromChild(method, path, ctx)

} else if path == t.root.path {
methods := []string{method, MethodWild}

for i := range methods {
nHandler := t.root.handlers[methods[i]]

switch {
case nHandler == nil:
continue
case nHandler.tsr:
return nil, true
case nHandler.handler != nil:
return nHandler.handler, false
case nHandler.wildcard != nil:
if ctx != nil {
ctx.SetUserValue(nHandler.wildcard.paramKey, "/")
}

return nHandler.wildcard.handler, false
nHandler := t.root.handlers[method]

switch {
case nHandler == nil:
case nHandler.tsr:
return nil, true
case nHandler.handler != nil:
return nHandler.handler, false
case nHandler.wildcard != nil:
if ctx != nil {
ctx.SetUserValue(nHandler.wildcard.paramKey, "/")
}

return nHandler.wildcard.handler, false
}

return t.root.getFromMethodWild(ctx, "/")

}

return nil, false
Expand Down
Loading

0 comments on commit 0298f52

Please sign in to comment.