Skip to content

Feat: Introduce ScopedPatternFilterFactory for Managed, Thread-Safe Filtering#287

Open
YuyuZha0 wants to merge 9 commits into
gliwka:mainfrom
YuyuZha0:thread-safe-pattern-filter
Open

Feat: Introduce ScopedPatternFilterFactory for Managed, Thread-Safe Filtering#287
YuyuZha0 wants to merge 9 commits into
gliwka:mainfrom
YuyuZha0:thread-safe-pattern-filter

Conversation

@YuyuZha0

Copy link
Copy Markdown

Key Motivation

The existing PatternFilter class is effective for single-threaded use but has two critical limitations in concurrent environments:

  1. It is not thread-safe.
  2. It is expensive to instantiate, as each new PatternFilter() triggers a full Hyperscan database compilation.

This forces consumers to implement their own complex and error-prone pooling or ThreadLocal management to use Hyperscan filtering safely and efficiently in multi-threaded applications like web servers.

This PR introduces ScopedPatternFilterFactory as a high-level, managed solution that solves these problems out of the box.

Key Differences & Improvements

The new ScopedPatternFilterFactory supersedes the manual PatternFilter approach by providing:

  • Thread-Safety by Design: The factory manages a unique, isolated ScopedPatternFilter instance for each thread, eliminating the need for external synchronization.

  • High Performance via Caching: The expensive database compilation is performed only once per thread. Subsequent requests for a filter on the same thread reuse the already-compiled instance, drastically improving performance.

  • Simplified and Safer API: Users interact with a single factory instance and obtain a filter via try-with-resources (var filter = factory.get()). This returns a proxy that prevents accidental closure of the shared, thread-local resource.

  • Automatic Resource Cleanup: It introduces a robust, PhantomReference-based mechanism to automatically release native resources for threads that have terminated, preventing memory leaks in dynamic environments.

@YuyuZha0

Copy link
Copy Markdown
Author

@gliwka Could you please help me review this PR? Thank you!

@gliwka

gliwka commented Oct 31, 2025

Copy link
Copy Markdown
Owner

Thank you for your contribution. I'll take a look over the weekend.

- Reword ScopedPatternFilterFactory/Impl exception messages as descriptive
  sentences for consistency
- Add method-level Javadoc to the factory (create/ofPatterns/get/close) and
  class Javadoc to the package-private helpers (Impl, Proxy, PatternOnlyFilter,
  PatternFilterCleaner, ExpressionUtil)
- Redesign the util test suite against the shared-Database/ThreadLocal API:
  recreate factory/impl/proxy/cleaner tests and add PatternOnlyFilterTest

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@YuyuZha0
YuyuZha0 force-pushed the thread-safe-pattern-filter branch from 70e61bc to 97f1cc0 Compare June 2, 2026 11:30
yuyu.zhao and others added 2 commits June 2, 2026 19:41
…lter

A thread calling get() could pass the closed check, then have close() free
the shared database before its createFilter() ran allocScratch() over it —
a use-after-free of native memory. Guard filter creation (read lock, with a
re-check of closed) and teardown (write lock) with a ReentrantReadWriteLock so
allocScratch can never overlap database.close(). Add a concurrency stress test
racing get() against close().

Also document the ScopedPatternFilter feature in the README (key features,
usage option, thread-safe example, and a thread-safety note).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Make the periodic cleanUp() acquire the lifecycle read lock so its refKeeper
removals and scanner closes cannot overlap close()'s write-locked teardown.
With every refKeeper mutator now gated by the lock, close() can iterate the set
directly under the write lock and clear it, dropping the synchronized snapshot
and the redundant trailing cleanUp() call.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@YuyuZha0
YuyuZha0 force-pushed the thread-safe-pattern-filter branch from 69f7507 to fc3ec7a Compare June 2, 2026 11:51
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