Bound compiled dynamic route regex chunks - #680
Open
samuelpatro wants to merge 1 commit into
Open
samuelpatro wants to merge 1 commit into
samuelpatro wants to merge 1 commit into
Conversation
samuelpatro
marked this pull request as ready for review
September 18, 2026 07:42
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A dynamic bucket with 2,000 routes sharing a prefix exceeds PCRE's compiled-regex limit. Both hits and misses then scan routes sequentially on every match.
Compile each bucket into ordered chunks bounded by 100 routes and approximately 8 KB of pattern source. Matching still chooses the earliest sorted candidate across the specific and catch-all buckets; wildcard precedence, expression/condition rejection, and regex-error fallback retain their existing behavior. Compiled cache format version 2 rebuilds old payloads, and malformed chunk shapes are rejected.
Regression tests cover 2,000/5,000-route hit and miss fallback counts, long Unicode patterns, optional parameters, priority/rejection, serialization, and old/malformed cache payloads. The large-bucket test fails on develop (two sequential fallbacks) and passes with the change (zero). Added two 5,000-route benchmark subjects. PHP 8.4 full suite: 234 tests, 1,487 assertions, no failures; one pre-existing risky test has no assertions. PHP syntax and diff checks pass. A single oversized route can still use the existing safe sequential fallback.
Rechecked on 2026-09-18: seven samples of 100 warm matches per sample, PHP 8.4, 5000 same-prefix dynamic routes. Median late hit: develop 2.110 ms, PR 0.096 ms (~22x faster); miss: 2.048 ms to 0.073 ms (~28x faster). Sequential fallback count drops from one per match to zero. At 100 routes, late-hit timing is effectively unchanged (2.96 vs 3.01 microseconds). Compilation is excluded. Timings are local illustrations; behavior and fallback counts are the regression gates. Full suite remains 234 tests / 1487 assertions.