Share regex_remap rule sets - #13537
Conversation
Reloading remap.config becomes slow when it contains many mappings that reference the same regex_remap rule files. Since the PCRE2 conversion, every plugin instance JIT-compiles an independent copy, making reload time scale with instances rather than unique rule sets. This patch caches immutable compiled rule sets by resolved filename and exact source content. It keeps match contexts and profiling counters per instance and uses weak ownership so obsolete reload generations are released, preserving JIT request performance without redundant reload work.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.
Suppressed comments (1)
plugins/regex_remap/regex_remap.cc:914
- Reading the rule file into a pre-sized string using the earlier path stat size can spuriously fail with a "short read" if the file is replaced between stat() and open() (e.g., atomic rewrite + rename), aborting remap.config reload even though reading to EOF would succeed. Prefer reading the whole stream and using the actual bytes read as the cache key.
std::streamsize const expected_size = st.st_size;
std::string source(static_cast<size_t>(expected_size), '\0');
f.read(source.data(), expected_size);
if (f.bad() || f.gcount() != expected_size) {
TSError("[%s] short read on %s: got %lld of %lld bytes", PLUGIN_NAME, ri->filename.c_str(), static_cast<long long>(f.gcount()),
static_cast<long long>(expected_size));
return TS_ERROR;
|
The design is right and the sharing boundary is drawn in the correct place. Since "what may be shared" is the whole question here, I verified that side rather than just reading it. The regression premise checks out, and it is in the shipped 10.2.0. #12685 ("Remove PCRE references, complete migration to PCRE2") is on both master and 10.2.x, and Sharing the compiled rules is safe, and the match-context change was not optional. Previously I also confirmed the concurrent read is safe rather than assuming it. The weak ownership does what the comment claims. The cache stores One thing I would change. if (ri->profile) {
ri->rule_hits.resize(ri->rule_set->rules().size());
}and indexed only when profiling is on: if (ri->profile) {
ink_atomic_increment(&(ri->rule_hits[rule_ix]), 1);That is correct today — Smaller notes, none blocking:
On the test. Asserting via Backport. This is already tracked for 10.2.x, and it should pick cleanly: the new test uses Nothing blocking from me. |
cmcfarlen
left a comment
There was a problem hiding this comment.
I also read this (not just Claude). I couldn't tell if the cache would ever actually be used concurrently, but it is global so a mutex makes sense. I always enjoy seeing std::weak_ptr in the wild. Cool!
Reloading remap.config becomes slow when it contains many mappings that reference the same regex_remap rule files. Since the PCRE2 conversion, every plugin instance JIT-compiles an independent copy, making reload time scale with instances rather than unique rule sets. This patch caches immutable compiled rule sets by resolved filename and exact source content. It keeps match contexts and profiling counters per instance and uses weak ownership so obsolete reload generations are released, preserving JIT request performance without redundant reload work. (cherry picked from commit f869b9c)
|
Cherry-picked to the 10.2.x branch as 3ac694d for the 10.2.0 release. |
Reloading remap.config becomes slow when it contains many mappings that
reference the same regex_remap rule files. Since the PCRE2 conversion,
every plugin instance JIT-compiles an independent copy, making reload
time scale with instances rather than unique rule sets.
This patch caches immutable compiled rule sets by resolved filename and
exact source content. It keeps match contexts and profiling counters per
instance and uses weak ownership so obsolete reload generations are
released, preserving JIT request performance without redundant reload
work.