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

🧹 chore: Improve Performance of Fiber Router #3261

Open
wants to merge 10 commits into
base: main
Choose a base branch
from

Conversation

gaby
Copy link
Member

@gaby gaby commented Dec 21, 2024

Description

  • Micro performance improvements for the Fiber Router.
  • Refactored requestHandler into two methods. One for CustomCtx and one for DefaultCtx.

Improvements to RemoveEscapeChar()

After:

ubuntu@ubuntu:~/Desktop/git/fiber$ go test -benchmem -run=^$ -bench ^Benchmark_Utils_RemoveEscapeChar$ github.com/gofiber/fiber/v3 -count=4
goos: linux
goarch: amd64
pkg: github.com/gofiber/fiber/v3
cpu: AMD Ryzen 7 7800X3D 8-Core Processor           
Benchmark_Utils_RemoveEscapeChar-4   	48737022	        21.87 ns/op	      16 B/op	       1 allocs/op
Benchmark_Utils_RemoveEscapeChar-4   	51360970	        21.88 ns/op	      16 B/op	       1 allocs/op
Benchmark_Utils_RemoveEscapeChar-4   	53682570	        21.97 ns/op	      16 B/op	       1 allocs/op
Benchmark_Utils_RemoveEscapeChar-4   	45811604	        21.91 ns/op	      16 B/op	       1 allocs/op
PASS
ok  	github.com/gofiber/fiber/v3	4.494s

Before:

ubuntu@ubuntu:~/Desktop/git/fiber$ go test -benchmem -run=^$ -bench ^Benchmark_Utils_RemoveEscapeChar$ github.com/gofiber/fiber/v3 -count=4
goos: linux
goarch: amd64
pkg: github.com/gofiber/fiber/v3
cpu: AMD Ryzen 7 7800X3D 8-Core Processor           
Benchmark_Utils_RemoveEscapeChar-4   	34108017	        33.72 ns/op	      16 B/op	       1 allocs/op
Benchmark_Utils_RemoveEscapeChar-4   	31172214	        33.48 ns/op	      16 B/op	       1 allocs/op
Benchmark_Utils_RemoveEscapeChar-4   	34733971	        33.61 ns/op	      16 B/op	       1 allocs/op
Benchmark_Utils_RemoveEscapeChar-4   	34788264	        33.87 ns/op	      16 B/op	       1 allocs/op
PASS
ok  	github.com/gofiber/fiber/v3	4.707s

Router Improvements

Benchmark between v2, main, and this PR

image

Type of change

  • Performance improvement (non-breaking change which improves efficiency)

Copy link
Contributor

coderabbitai bot commented Dec 21, 2024

Walkthrough

This pull request encompasses multiple changes across different files in the Fiber framework. The modifications include updating the golangci-lint version in the Makefile, enhancing routing and request handling logic in router.go, adding a Drop() method to the Ctx interface, optimizing the RemoveEscapeChar function in path.go, and introducing a new parallel benchmark in router_test.go. The changes focus on improving performance, flexibility, and maintainability of the framework's core components.

Changes

File Change Summary
Makefile Updated golangci-lint version from v1.62.0 to v1.62.2
app.go Modified NewCtxFunc and init methods to handle custom request handlers more flexibly
binder/mapping.go Moved a linter comment directive to the same line as the switch statement
ctx_interface_gen.go Added new Drop() method to Ctx interface for closing connections without sending response
path.go Optimized RemoveEscapeChar function with more efficient single-pass implementation
router.go Refactored routing logic, split request handler, improved path matching and context handling
router_test.go Added Benchmark_Router_Next_Default_Parallel for performance testing

Sequence Diagram

sequenceDiagram
    participant Client
    participant Router
    participant App
    participant Handler
    participant Context

    Client->>Router: Send Request
    Router->>App: Route Request
    App->>Handler: Select Request Handler
    Handler->>Context: Create Context
    Context-->>Handler: Return Processed Context
    Handler-->>Router: Return Response
    Router-->>Client: Send Response
Loading

Possibly Related PRs

Suggested Reviewers

  • sixcolors
  • ReneWerner87
  • efectn

Poem

🐰 Lint's version bumped with care,
Routing logic now more fair
Connections drop, performance soar
Fiber's magic opens a new door
Code evolves with rabbit's flair! 🚀

Tip

CodeRabbit's docstrings feature is now available as part of our Early Access Program! Simply use the command @coderabbitai generate docstrings to have CodeRabbit automatically generate docstrings for your pull request. We would love to hear your feedback on Discord.


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

codecov bot commented Dec 21, 2024

Codecov Report

Attention: Patch coverage is 83.87097% with 15 lines in your changes missing coverage. Please review.

Project coverage is 84.30%. Comparing base (775e0a7) to head (6f48599).

Files with missing lines Patch % Lines
router.go 87.14% 5 Missing and 4 partials ⚠️
app.go 57.14% 3 Missing and 3 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3261      +/-   ##
==========================================
- Coverage   84.42%   84.30%   -0.12%     
==========================================
  Files         116      116              
  Lines       11497    11519      +22     
==========================================
+ Hits         9706     9711       +5     
- Misses       1374     1385      +11     
- Partials      417      423       +6     
Flag Coverage Δ
unittests 84.30% <83.87%> (-0.12%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@@ -620,10 +620,16 @@ func GetTrimmedParam(param string) string {

// RemoveEscapeChar remove escape characters
func RemoveEscapeChar(word string) string {
if strings.IndexByte(word, escapeChar) != -1 {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change alone saves 12ns/op

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.50.

Benchmark suite Current: 6f48599 Previous: 775e0a7 Ratio
`Benchmark_RoutePatternMatch//api/:param/fixedEnd_ not_match _/api/abc/def/fixedEnd - allocs/op` 14 allocs/op
BenchmarkUnmarshalitem-4_middleware_limiter 40.68 ns/op 639.11 MB/s 0 B/op 0 allocs/op 26.65 ns/op 975.75 MB/s 0 B/op 0 allocs/op 1.53
BenchmarkUnmarshalitem-4_middleware_limiter - ns/op 40.68 ns/op 26.65 ns/op 1.53

This comment was automatically generated by workflow using github-action-benchmark.

@gaby gaby marked this pull request as ready for review December 28, 2024 05:32
@gaby gaby requested a review from a team as a code owner December 28, 2024 05:32
@gaby gaby requested review from sixcolors, ReneWerner87 and efectn and removed request for a team December 28, 2024 05:32
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
app.go (2)

619-622: Tests recommended for dynamic NewCtxFunc changes
By setting app.server.Handler to app.customRequestHandler on non-nil newCtxFunc, the server’s behavior changes significantly. Consider adding tests that confirm correct fallback to defaultRequestHandler when newCtxFunc is nil.


875-879: Handler returns custom or default
This block selects between app.customRequestHandler and app.defaultRequestHandler. Looks functionally correct. Adding minimal test coverage ensures stable switching whenever newCtxFunc is set or unset.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 877-878: app.go#L877-L878
Added lines #L877 - L878 were not covered by tests

ctx_interface_gen.go (1)

353-355: New Drop() method
The Drop() method can be valuable for quietly terminating connections (like DDoS mitigation). Ensure calling it doesn’t break existing middlewares that assume a response is always sent.

Could you document how or when this should be invoked in high-load cases?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 57744eb and 8e213e0.

⛔ Files ignored due to path filters (1)
  • .github/workflows/linter.yml is excluded by !**/*.yml
📒 Files selected for processing (7)
  • Makefile (1 hunks)
  • app.go (3 hunks)
  • binder/mapping.go (1 hunks)
  • ctx_interface_gen.go (1 hunks)
  • path.go (1 hunks)
  • router.go (4 hunks)
  • router_test.go (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • binder/mapping.go
🧰 Additional context used
🪛 GitHub Check: codecov/patch
app.go

[warning] 877-878: app.go#L877-L878
Added lines #L877 - L878 were not covered by tests


[warning] 1069-1069: app.go#L1069
Added line #L1069 was not covered by tests

router.go

[warning] 218-218: router.go#L218
Added line #L218 was not covered by tests


[warning] 232-233: router.go#L232-L233
Added lines #L232 - L233 were not covered by tests


[warning] 249-249: router.go#L249
Added line #L249 was not covered by tests


[warning] 270-270: router.go#L270
Added line #L270 was not covered by tests

🔇 Additional comments (8)
router.go (4)

214-243: Add test coverage for edge conditions
Lines #218 (panic) and #232–233 (flash cookie handling) appear uncovered by tests. Consider adding unit or integration tests to validate the behavior when the context pool fails to provide a *DefaultCtx and when request headers include flash cookies.

Do you want help generating a test function for these lines?

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 218-218: router.go#L218
Added line #L218 was not covered by tests


[warning] 232-233: router.go#L232-L233
Added lines #L232 - L233 were not covered by tests


245-270: Extend coverage for custom request handling
Similar to the default handler, lines #249 (panic) and #270 (internal server error state) lack explicit test coverage. Ensure that custom context scenarios are tested to guarantee stability and maintain confidence in your customRequestHandler.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 249-249: router.go#L249
Added line #L249 was not covered by tests


[warning] 270-270: router.go#L270
Added line #L270 was not covered by tests


327-376: Registration logic looks good
The path normalization and route registration improvements appear consistent. The single-pass path cleaning and constraints for empty handlers (panics) make maintenance easier. Great work!


68-106: Consider verifying edge cases in route matching
This logic correctly checks for root (r.root) and r.star. However, please ensure that complex edge cases (e.g., detectionPath unexpectedly empty or partial prefix matches) are handled as intended, especially when r.use is true.

Run this script to search relevant tests covering Route.match logic:

✅ Verification successful

Let me check the test implementations to verify the edge cases.


Route matching logic is well-tested for edge cases
The test suite comprehensively covers all edge cases in the route matching logic:

  • Empty paths and root handling (Test_Route_Match_Root)
  • Wildcard/star patterns (Test_Route_Match_Star)
  • Middleware prefix matches (Test_Route_Match_Middleware_HasPrefix)
  • Parameter parsing (Test_Route_Match_Parser)
  • Special character handling (Test_Route_Match_UnescapedPath, Test_Route_Match_WithEscapeChar)
  • Root middleware behavior (Test_Route_Match_Middleware_Root)

The implementation correctly handles all these cases, including empty paths, partial matches, and special characters.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# This script looks for test methods covering `Route.match` usage
rg -A 8 "func Test_Route_Match" 

Length of output: 2847


Script:

#!/bin/bash
# Get the full test implementations
rg -B 2 -A 25 "^func Test_Route_Match" router_test.go

Length of output: 6582

app.go (1)

1068-1072: Initialize the correct request handler
This chunk replicates the logic above, bridging the custom or default handler based on newCtxFunc. Ensuring consistency between Handler() and init() is key. Good design.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 1069-1069: app.go#L1069
Added line #L1069 was not covered by tests

router_test.go (1)

594-615: Parallel benchmark is a great addition
The new function Benchmark_Router_Next_Default_Parallel significantly broadens performance testing under concurrency. Consider adding testcases for heavier routes or dynamic handlers to measure real-world usage.

path.go (1)

623-632: Impressive single-pass removal
Shifting to a manual byte-slice approach for escaping yields meaningful performance gains. The logic is straightforward, and skipping copy operations should reduce allocations.

Makefile (1)

38-38: LGTM! Verify the golangci-lint version adoption.

The minor version bump of golangci-lint is a good maintenance practice. Let's verify the version's stability and adoption rate.

✅ Verification successful

Golangci-lint version update is safe to proceed

The verification shows:

  • The version v1.62.2 is only referenced in the Makefile, indicating this is a new adoption
  • The GitHub workflow uses the golangci-lint GitHub action v6, which is version-agnostic and compatible with the CLI version being used
  • No specific version constraints or issues were found in the documentation

Since this is a patch version update (v1.62.0 → v1.62.2) and the tooling setup is properly maintained through both Makefile and GitHub Actions, this change is safe to proceed.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check the adoption rate and stability of golangci-lint v1.62.2

# Check if this version is referenced in go.mod files across the codebase
rg -l "golangci-lint.*v1.62.2" 

# Look for any version-specific comments or issues mentioned in docs
fd -t f -e md | xargs rg "golangci-lint.*1\.62\.2"

# Check if there are any version constraints in GitHub workflows
fd -t f -g "*.yml" -g "*.yaml" .github/workflows/ | xargs rg "golangci-lint.*@v"

Length of output: 306

@gaby gaby added this to the v3 milestone Dec 28, 2024
defer app.ReleaseCtx(ctx)

// Check if the HTTP method is valid
if ctx.methodINT == -1 {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may have introduced a bug here, I need to add a check to replace app.methodInt()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: No status
Development

Successfully merging this pull request may close these issues.

1 participant