♻️ Refactor: Improve performance analyseConstantPart#3753
♻️ Refactor: Improve performance analyseConstantPart#3753ReneWerner87 merged 4 commits intogofiber:mainfrom
Conversation
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughRefactors parameter parsing in Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Caller
participant Parser as parseRoute
participant Analyzer as analyseParameterPart
Caller->>Parser: parseRoute(pattern)
Parser->>Analyzer: examine next segment (byte slice)
Note over Analyzer: build 256-entry boolean table\nscan unescaped bytes for start\ntrack paramEnd/constraintStart/constraintEnd
Analyzer-->>Parser: segment info (start, end, name, constraint, flags)
Parser-->>Caller: compiled route segment
sequenceDiagram
rect rgba(230,245,255,0.6)
Note over Parser,Helpers: Old flow used multiple charset helper functions
participant Parser
participant Helpers as CharsetHelpers
Parser->>Helpers: findNextCharsetPosition(...)
Helpers-->>Parser: index
Parser->>Helpers: findNextNonEscapedCharsetPosition(...)
Helpers-->>Parser: index
Parser->>Analyzer: analyseParameterPart(with indices)
end
rect rgba(235,255,235,0.6)
Note over Parser,Analyzer: New flow inlines scanning and detection
participant Parser
participant Analyzer
Parser->>Analyzer: analyseParameterPart(slice)
Analyzer->>Analyzer: inline boolean-table + per-byte unescaped checks\ncompute paramEnd/constraint positions
Analyzer-->>Parser: result
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary of ChangesHello @ksw2000, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request delivers a crucial optimization to the route pattern matching mechanism within the Fiber framework. By streamlining the character search logic and integrating helper functions directly into the core parsing methods, the change dramatically improves the efficiency of route analysis. This enhancement translates to faster request processing and a more performant application overall, without introducing any additional memory overhead. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3753 +/- ##
==========================================
- Coverage 91.93% 91.50% -0.43%
==========================================
Files 113 113
Lines 11700 11778 +78
==========================================
+ Hits 10756 10778 +22
- Misses 684 735 +51
- Partials 260 265 +5
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Code Review
This pull request successfully refactors the path parsing logic for a significant performance improvement, primarily by replacing character set searches with lookup tables. The benchmarks clearly demonstrate the effectiveness of this optimization. The code is cleaner and more efficient. I've identified one edge-case bug in the new findNextParamPosition function concerning parameter clusters at the end of a string and have provided a suggested fix.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
path.go (2)
279-283: Fix formatting issue detected bygofumpt.The linter reports that the file is not properly formatted. The indentation on line 279 appears incorrect.
Apply this diff to fix the formatting:
- var search = [256]bool{ + search := [256]bool{ wildcardParam: true, plusParam: true, paramStarterChar: true, }
318-361: Consider extracting constraint parsing logic for better maintainability.The
analyseParameterPartfunction is complex with deeply nested logic for handling constraints and parameter endings. Consider extracting the constraint boundary detection (lines 339-354) into a separate helper function for improved readability and testability.Example refactor approach:
func findConstraintBoundaries(search string) (start, end int) { start, end = -1, -1 for i := range search { if start == -1 && search[i] == '<' && (i == 0 || search[i-1] != escapeChar) { start = i + 1 continue } if end == -1 && search[i] == '>' && (i == 0 || search[i-1] != escapeChar) { end = i + 1 break } } return start, end }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
path.go(2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Format Go code using gofumpt (enforced viamake format)
Ensure code passes golangci-lint checks (enforced viamake lint)
Optimize struct field alignment using betteralign (enforced viamake betteralign)
Modernize Go code using gopls modernize (enforced viamake modernize)
Files:
path.go
🪛 GitHub Check: lint
path.go
[failure] 279-279:
File is not properly formatted (gofumpt)
🪛 GitHub Actions: golangci-lint
path.go
[error] 279-279: golangci-lint: path.go:279:1 - File is not properly formatted (gofumpt)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: unit (1.25.x, macos-latest)
- GitHub Check: unit (1.25.x, windows-latest)
- GitHub Check: unit (1.25.x, macos-13)
- GitHub Check: repeated
- GitHub Check: Analyse
- GitHub Check: Compare
🔇 Additional comments (3)
path.go (3)
276-300: Well-optimized parameter detection using lookup table.The refactored implementation efficiently reduces time complexity from O(len(search) * len(charset)) to O(len(search)) by using a 256-entry boolean lookup table instead of charset scanning. This is a clean, performant approach that aligns well with the reported benchmark improvements.
327-361: Good performance improvement with inlined end detection.The refactored implementation successfully inlines the parameter end detection logic, eliminating the need for helper functions and reducing function call overhead. This contributes to the measured latency improvements while maintaining correct functionality.
343-345: Incorrect variable reference in constraint end detection.Line 343 references
paramConstraintEnd(a byte constant defined as'>') but should reference the local variable for comparison.Apply this diff to fix the variable reference:
- if parameterConstraintEnd == -1 && search[i] == paramConstraintEnd && (i == 0 || search[i-1] != escapeChar) { + if parameterConstraintEnd == -1 && search[i] == '>' && (i == 0 || search[i-1] != escapeChar) { parameterConstraintEnd = i + 1Likely an incorrect or invalid review comment.
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (2)
path.go (2)
284-300: Fix parameter cluster termination logic.The logic for handling parameter clusters has the same issue identified in the previous reviews. When a cluster of parameter start characters extends to the end of the pattern, the function returns
next(the start index) instead of the correct end index.Apply this fix to handle clusters that extend to the pattern end:
if next > 0 && pattern[next] != wildcardParam { // checking the found parameterStartChar is a cluster for i := next + 1; i < len(pattern); i++ { if !search[pattern[i]] { return i - 1 } } - next = len(pattern) - 1 + return len(pattern) - 1 } return next
340-341: Fix incorrect variable reference in constraint detection.The condition incorrectly references the byte constant
paramConstraintStartinstead of the local variableparameterConstraintStartfor comparison.Apply this diff to fix the variable reference:
- if parameterConstraintStart == -1 && search[i] == paramConstraintStart && (i == 0 || search[i-1] != escapeChar) { + if parameterConstraintStart == -1 && search[i] == '<' && (i == 0 || search[i-1] != escapeChar) { parameterConstraintStart = i + 1
🧹 Nitpick comments (1)
path.go (1)
351-351: Consider using explicit boolean logic for clarity.The XOR operation
parameterConstraintStart^parameterConstraintEnd >= 0is mathematically correct but could be more readable.Consider this more explicit approach for better readability:
- if parameterConstraintStart^parameterConstraintEnd >= 0 { + if (parameterConstraintStart == -1 && parameterConstraintEnd == -1) || + (parameterConstraintStart != -1 && parameterConstraintEnd != -1) {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
path.go(2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Format Go code using gofumpt (enforced viamake format)
Ensure code passes golangci-lint checks (enforced viamake lint)
Optimize struct field alignment using betteralign (enforced viamake betteralign)
Modernize Go code using gopls modernize (enforced viamake modernize)
Files:
path.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: unit (1.25.x, windows-latest)
- GitHub Check: repeated
- GitHub Check: Compare
🔇 Additional comments (4)
path.go (4)
279-283: LGTM: Effective optimization using boolean lookup table.The use of a 256-entry boolean array for character lookup is well-suited for Go, where booleans are represented as bytes, providing O(1) lookup performance while maintaining simplicity. This table-driven approach effectively replaces the previous charset-based string searches with direct array indexing.
329-336: LGTM: Efficient parameter end detection using boolean table.The implementation correctly uses a boolean table for quick character classification, properly identifying parameter end characters including delimiters and special characters. This approach maintains the same O(1) character lookup performance as the parameter start detection.
344-346: LGTM: Correct constraint end detection.The constraint end detection properly references the byte constant
paramConstraintEndand correctly updates the local variableparameterConstraintEnd.
357-362: LGTM: Proper parameter end position handling.The logic correctly handles different cases for parameter end position determination, including when no end is found and when additional character checking is needed. The boundary conditions are properly managed.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (8)
path.go (8)
279-284: Hoist the lookup table to avoid per-call init cost.Make the 256-entry
searchtable a package-level var and reuse it. It’s tiny but this function is hot.Apply:
- search := [256]bool{ - wildcardParam: true, - plusParam: true, - paramStarterChar: true, - } + search := paramStartLookupAdd outside the function:
var paramStartLookup = [256]bool{ wildcardParam: true, plusParam: true, paramStarterChar: true, }
285-290: Iterate by byte, not rune.Use a byte-indexed loop to avoid rune decoding overhead in this hot path.
- for i := range pattern { + for i := 0; i < len(pattern); i++ {
323-361: End-of-parameter scan: boundary conditions look good; small clarity tweak suggested.Logic is correct. For readability and to prevent future off-by-one regressions, consider storing
base := 1and commenting that indices in this block are relative topattern[1:].
365-367: Guard against impossible negatives (defensive only).
paramEndPositioncan’t be-1here due to the switch above, but a cheap assert helps future edits.- processedPart := pattern[0 : paramEndPosition+1] + // paramEndPosition >= 0 guaranteed by switch above + processedPart := pattern[0 : paramEndPosition+1]
372-373: Constraint slice indexes are correct; add a fast-path when empty.If
< >are adjacent (empty constraints), skip parsing to avoid allocating an empty slice.- constraintString := pattern[paramConstraintStartPosition+1 : paramConstraintEndPosition] + constraintString := pattern[paramConstraintStartPosition+1 : paramConstraintEndPosition] + if len(constraintString) == 0 { + // treat as no constraints: <> + goto build_segment + }
417-417: Correct name extraction with constraints; add trim for trailing spaces.If users accidentally put spaces before
<, trimming avoids surprising param names.- paramName = RemoveEscapeChar(GetTrimmedParam(pattern[0:paramConstraintStartPosition])) + paramName = RemoveEscapeChar(GetTrimmedParam(strings.TrimRight(pattern[0:paramConstraintStartPosition], " ")))
432-432: Optional flag detection is right; consider guarding wildcard early.Minor: short-circuit
IsOptionalfor wildcards to avoid indexing.- IsOptional: isWildCard || pattern[paramEndPosition] == optionalParam, + IsOptional: isWildCard || (!isWildCard && pattern[paramEndPosition] == optionalParam),
279-299: Add focused tests for escapes, clusters, and constraints.These fast paths are easy to regress. Please add unit tests covering:
- Escaped starters:
"\:a","\\:a"(escaped vs. double-escaped)- Cluster at EOF:
"a::","a++","a*:"- Constraints with/without data:
":id<min(3)>",":id<>", nested escaped"<regex(\>)>"- Optional marker inclusion:
":id?"and with trailing delimiter":id?/"I can draft them if helpful.
Also applies to: 323-361, 365-367, 372-373, 417-417, 432-432
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
path.go(4 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Format Go code using gofumpt (enforced viamake format)
Ensure code passes golangci-lint checks (enforced viamake lint)
Optimize struct field alignment using betteralign (enforced viamake betteralign)
Modernize Go code using gopls modernize (enforced viamake modernize)
Files:
path.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: unit (1.25.x, macos-latest)
- GitHub Check: unit (1.25.x, windows-latest)
- GitHub Check: unit (1.25.x, macos-13)
- GitHub Check: repeated
- GitHub Check: Compare
🔇 Additional comments (1)
path.go (1)
291-299: Approve — cluster termination fix is correct.
findNextParamPosition handles the fall‑through‑at‑EOF case and returning len(pattern)-1 for clusters that run to the string end is correct (verified in path.go); no changes required.
|
@ksw2000 thx |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
path.go (2)
123-138: Consider moving character maps to package level as suggested.Per the previous review comment, these boolean maps could be moved outside the functions to the package level for better organization and easier expansion. This change would have minimal performance impact while improving code maintainability.
Consider moving these maps outside the
varblock to package level:// Character lookup tables for parameter parsing var ( parameterStartChars = [256]bool{ wildcardParam: true, plusParam: true, paramStarterChar: true, } parameterEndChars = [256]bool{ optionalParam: true, paramStarterChar: true, escapeChar: true, slashDelimiter: true, '-': true, '.': true, } )
294-311: Fix handling of parameter clusters extending to pattern end.The current implementation correctly handles parameter clusters that extend to the end of the pattern by returning
len(pattern) - 1on line 308. However, there's a logical issue with the condition on line 301 - it should checknext != -1instead ofnext > 0to properly handle clusters starting at position 0.Apply this diff to fix the cluster detection logic:
- if next > 0 && pattern[next] != wildcardParam { + if next != -1 && pattern[next] != wildcardParam { // checking the found parameterStartChar is a cluster for i := next + 1; i < len(pattern); i++ { if !parameterStartChars[pattern[i]] { return i - 1 } } return len(pattern) - 1 }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
path.go(5 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Format Go code using gofumpt (enforced viamake format)
Ensure code passes golangci-lint checks (enforced viamake lint)
Optimize struct field alignment using betteralign (enforced viamake betteralign)
Modernize Go code using gopls modernize (enforced viamake modernize)
Files:
path.go
🔇 Additional comments (5)
path.go (5)
338-364: LGTM! Efficient inlined parameter end detection.The refactored logic successfully inlines the parameter end detection, replacing the previous helper functions with a single efficient scan. The boolean array lookup for
parameterEndCharsprovides O(1) character checking, and the constraint boundary detection is correctly integrated.
342-342: Fix incorrect variable reference in constraint detection.Line 342 incorrectly references
paramConstraintStart(the byte constant) instead ofparamConstraintStartPosition(the local variable). This causes the condition to always evaluate incorrectly.This issue was already identified in previous reviews and should be fixed as indicated.
367-368: LGTM! Consistent variable naming and usage.The parameter end position calculation and usage is now consistent throughout the function, properly using
paramEndPositionfor both the processed part extraction and length calculation.
374-420: LGTM! Proper constraint boundary handling.The constraint extraction logic correctly uses the new
paramConstraintStartPositionandparamConstraintEndPositionvariables, and the parameter name extraction properly accounts for the constraint boundaries when present.
434-434: LGTM! Correct optional parameter detection.The optional parameter detection correctly uses
paramEndPositionto check the character at the parameter's end position, maintaining the same logic as before but with the new variable naming.
Description
findNextCharsetPosition,findNextCharsetPositionConstraint, andfindNextNonEscapedCharsetPositionto reduce time complexity from O(len(search)len(charset)) to O(len(search)) and inline them into the functionanalyseParameterPart.findNextParamPosition.Changes introduced
List the new features or adjustments introduced in this pull request. Provide details on benchmarks, documentation updates, changelog entries, and if applicable, the migration guide.
Type of change
Please delete options that are not relevant.
Checklist
Before you submit your pull request, please make sure you meet these requirements:
/docs/directory for Fiber's documentation.