Skip to content

fix: match actor selection wildcards without backtracking (#3506) - #3519

Merged
pjfanning merged 1 commit into
apache:1.7.xfrom
pjfanning:match17
Sep 4, 2026
Merged

fix: match actor selection wildcards without backtracking (#3506)#3519
pjfanning merged 1 commit into
apache:1.7.xfrom
pjfanning:match17

Conversation

@pjfanning

Copy link
Copy Markdown
Member

Motivation

Backport of #3506 to 1.7.x: wildcard actor-selection matching went through a regular
expression that backtracks badly — a 26-character pattern in an ActorSelectionMessage
could pin the inbound stream thread for tens of seconds.

Modification

Cherry-pick of ec62931. The only conflict was the import line in ActorSelection.scala
(1.7.x also imports JavaDurationConverters, ccompat and FutureConverters there);
resolved by adding Glob to the existing import. Glob.scala and GlobSpec applied
clean — they are plain Scala 2 syntax and Java 8 APIs throughout.

Result

Same as #3506: the same selections match as before, in time linear in practice, and
deserializing a selection no longer compiles a regular expression.

Tests

  • sbt "++ 2.12.21 actor-tests/Test/compile" — clean, validating Scala 2.12
  • sbt "actor/scalafmtCheckAll" "actor-tests/scalafmtCheckAll" — clean
  • Test suites intentionally left to CI per the release-prep flow; the tests are the ones
    from fix: match actor selection wildcards without backtracking #3506, including the exhaustive agreement check against Helpers.makePattern

References

Backport of #3506.

* fix: match actor selection wildcards without backtracking

Motivation:
SelectChildPattern compiled its glob to a regular expression with
Helpers.makePattern, which turns every '*' into '.*'. A chain of those
backtracks: the 26 character pattern "*a*a*a*a*a*a*a*a*a*a*a*a*b" matched
against a 36 character actor name that cannot satisfy the trailing literal
takes about 42 seconds on one thread.

An ActorSelectionMessage carries its pattern elements in the message, so
that cost is reachable from one small message, and deliverSelection runs
on the caller's thread for a local selection and on the inbound stream
thread for a remote one. Bounding the pattern length would not help, since
26 characters is already enough.

Modification:
Add Glob (@internalapi), which matches the same grammar - '?' is one
character, '*' is any run, everything else is literal - by remembering only
the most recent '*' rather than by backtracking, so it runs in time
proportional to the product of the two lengths at worst. Match through it
in ActorSelection.deliverSelection.

SelectChildPattern.pattern is kept for compatibility but is now lazy, so
deserializing a selection no longer compiles a regular expression either.

Result:
The same selections match as before, in time linear in practice.

* scalafmt
@pjfanning pjfanning added this to the 1.7.1 milestone Sep 3, 2026
@pjfanning
pjfanning merged commit 3f0216a into apache:1.7.x Sep 4, 2026
10 checks passed
@pjfanning
pjfanning deleted the match17 branch September 4, 2026 10:26
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.

2 participants