Skip to content

Conversation

@ptoffy
Copy link
Member

@ptoffy ptoffy commented Nov 25, 2025

Fixes #145

This adds recursive backtracking to the trie algorithm. Unfortunately this will likely result in some performance loss when routing but we do want routes to be resolved correctly

@ptoffy ptoffy requested review from 0xTim and gwynne as code owners November 25, 2025 10:56
@codecov
Copy link

codecov bot commented Nov 25, 2025

Codecov Report

❌ Patch coverage is 60.25641% with 31 lines in your changes missing coverage. Please review.
✅ Project coverage is 84.92%. Comparing base (6629807) to head (dda4c9b).

Files with missing lines Patch % Lines
Sources/RoutingKit/TrieRouter/TrieRouter.swift 60.25% 31 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #149      +/-   ##
==========================================
- Coverage   90.43%   84.92%   -5.52%     
==========================================
  Files           5        5              
  Lines         251      325      +74     
==========================================
+ Hits          227      276      +49     
- Misses         24       49      +25     
Files with missing lines Coverage Δ
Sources/RoutingKit/TrieRouter/TrieRouter.swift 77.02% <60.25%> (-18.92%) ⬇️

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

gwynne
gwynne previously approved these changes Nov 25, 2025
Copy link
Member

@gwynne gwynne left a comment

Choose a reason for hiding this comment

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

My nits are not particularly critical, not using them will not make a huge difference. It'd be interesting to know if they benchmarked differently though.

Comment on lines +108 to +118
if let partials = currentNode.partials, !partials.isEmpty {
for partial in partials {
alternatives.append(
.init(
node: partial.node,
index: index,
kind: .partial(partial),
parameterSnapshot: parameters
))
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if let partials = currentNode.partials, !partials.isEmpty {
for partial in partials {
alternatives.append(
.init(
node: partial.node,
index: index,
kind: .partial(partial),
parameterSnapshot: parameters
))
}
}
alternatives.append(contentsOf: currentNode.partials?.map { .init(
node: partial.node, index: index, kind: .partial(partial), parameterSnapshot: parameters
) } ?? [])

Note

.append(contentsOf: []) and [].map(...) both compile to no-ops, so eliding the conditional does not degrade performance.

Comment on lines +91 to +101
if let partials = currentNode.partials, !partials.isEmpty {
for partial in partials {
alternatives.append(
.init(
node: partial.node,
index: index,
kind: .partial(partial),
parameterSnapshot: parameters
))
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if let partials = currentNode.partials, !partials.isEmpty {
for partial in partials {
alternatives.append(
.init(
node: partial.node,
index: index,
kind: .partial(partial),
parameterSnapshot: parameters
))
}
}
alternatives.append(contentsOf: currentNode.partials?.map { .init(
node: partial.node, index: index, kind: .partial(partial), parameterSnapshot: parameters
) } ?? [])

Note

.append(contentsOf: []) and [].map(...) both compile to no-ops, so eliding the conditional does not degrade performance.

@penny-for-vapor
Copy link

penny-for-vapor bot commented Nov 25, 2025

Benchmark Report for dda4c9b

❓ Pull request has significant performance differences 📊

Click to expand comparison result

Benchmark check running at 2025-11-25 11:29:11 UTC

Reading thresholds from "Benchmarks/Thresholds/"

Checking ["RouterPerformance:Case-sensitive", "RouterPerformance:Case-insensitive", "RouterPerformance:Case-insensitive_Match_First", "RouterPerformance:Case-insensitive_Match_Last", "RouterPerformance:Case-sensitive_Minimal", "RouterPerformance:Case-insensitive_Minimal", "RouterPerformance:Minimal_Early_Fail"]

========================================================================
Deviations worse than threshold for RouterPerformance:Minimal_Early_Fail
========================================================================
Throughput (# / s) (K, %) p90 threshold Add backtracki… Difference % Threshold %
p90 512 435 15 10

The baseline 'Add backtracking' is WORSE than the defined thresholds.

Click to expand benchmark result

Baseline 'Add backtracking'

Host 'b1e93067c10c' with 2 'aarch64' processors with 3 GB memory, running:
#16~24.04.1-Ubuntu SMP Tue Oct 14 01:56:45 UTC 2025

RouterPerformance

Case-insensitive

Metric p0 p25 p50 p75 p90 p99 p100 Samples
Malloc (total) * 22 22 22 22 22 22 22 9289
Memory (resident peak) (M) 24 24 24 24 24 24 24 9289
Throughput (# / s) (K) 237 196 191 185 177 163 49 9289

Case-insensitive_Match_First

Metric p0 p25 p50 p75 p90 p99 p100 Samples
Malloc (total) * 22 22 22 22 22 22 22 9271
Memory (resident peak) (M) 24 24 24 24 24 24 24 9271
Throughput (# / s) (K) 236 196 189 183 176 157 43 9271

Case-insensitive_Match_Last

Metric p0 p25 p50 p75 p90 p99 p100 Samples
Malloc (total) * 22 22 22 22 22 22 22 8936
Memory (resident peak) (M) 24 24 24 24 24 24 24 8936
Throughput (# / s) (K) 215 182 177 172 167 151 32 8936

Case-insensitive_Minimal

Metric p0 p25 p50 p75 p90 p99 p100 Samples
Malloc (total) * 18 18 18 18 18 18 18 10000
Memory (resident peak) (M) 23 24 24 24 24 24 24 10000
Throughput (# / s) (K) 528 479 473 466 458 398 64 10000

Case-sensitive

Metric p0 p25 p50 p75 p90 p99 p100 Samples
Malloc (total) * 22 22 22 22 22 22 22 9266
Memory (resident peak) (M) 24 24 24 24 24 24 24 9266
Throughput (# / s) (K) 240 200 195 190 185 164 23 9266

Case-sensitive_Minimal

Metric p0 p25 p50 p75 p90 p99 p100 Samples
Malloc (total) * 18 18 18 18 18 18 18 10000
Memory (resident peak) (M) 23 24 24 24 24 24 24 10000
Throughput (# / s) (K) 532 481 474 465 455 390 123 10000

Minimal_Early_Fail

Metric p0 p25 p50 p75 p90 p99 p100 Samples
Malloc (total) * 18 18 18 18 18 18 18 10000
Memory (resident peak) (M) 23 24 24 24 24 24 24 10000
Throughput (# / s) (K) 507 459 453 445 435 377 112 10000

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Route 404 with mixed path components of same absolute value

2 participants