⚡ [performance improvement N+1 Query in database iteration] - #109

Closed
akutuva21 wants to merge 2 commits into
mainfrom
bolt-perf-naming-database-n-plus-1-1138012978852035096
Closed

⚡ [performance improvement N+1 Query in database iteration]#109
akutuva21 wants to merge 2 commits into
mainfrom
bolt-perf-naming-database-n-plus-1-1138012978852035096

Conversation

@akutuva21

Copy link
Copy Markdown
Owner

💡 What:
Replaced an N+1 looping query pattern inside NamingDatabase.findOverlappingNamespace with a batched query implementation. Instead of establishing a new connection and executing a SELECT statement for each file individually, it now chunks the fileList (size 500) and queries the DB using an IN (...) clause. The script builds a mapped dictionary mapping filenames to their rows and processes them locally.

🎯 Why:
The original implementation had a classic N+1 query issue. For N files, it initialized N separate database connections and ran N queries. This incurred heavy I/O overhead and was extremely inefficient, particularly for processing large databases.

📊 Measured Improvement:
On a dataset of 1000 simulated files:

  • Baseline (N+1 queries): ~0.417s
  • Optimized (Batched queries): ~0.010s
  • Speedup: ~40x

PR created automatically by Jules for task 1138012978852035096 started by @akutuva21

Replaces repeated N+1 DB calls inside a loop with a single chunked
batched SQL IN query fetching all required records once, speeding
up execution from O(N) queries to O(1) batched queries.
Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>
@google-labs-jules

Copy link
Copy Markdown

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@akutuva21

Copy link
Copy Markdown
OwnerAuthor

Superseded by #108 namingDatabase batching optimization.

@google-labs-jules

Copy link
Copy Markdown

Superseded by #108 namingDatabase batching optimization.

Understood. Acknowledging that this work is now obsolete and stopping work on this task.

akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
…ions
Under simulator='bngsim', the routing bridge silently fell back to the
legacy BNG2.pl subprocess engine whenever the Python parser
(modelapi.bngmodel) could not inspect a BNGL's actions — e.g. a typo'd or
unknown simulate argument (atoll, abstol, par_scan_vals) that bngmodel
rejects but BNG2.pl tolerates. This violated the simulator='bngsim'
contract ("use BNGsim, or error"): the caller got legacy output with no
exception and no warning. A parity sweep over 895 models hit this on 9
models.
_classify_bngl_actions_for_bngsim() returned ROUTE_SUBPROCESS for the
un-inspectable case unconditionally, with no reference to simulator.
Fix, at the classify_bngsim_route call site where simulator is in scope:
- simulator='bngsim' + un-inspectable actions -> ROUTE_ERROR, propagating
the underlying parse reason so the caller learns why it couldn't route
to BNGsim. Both consumers (main.py, runner.run) already raise
BNGSimError(route.reason) on ROUTE_ERROR.
- simulator='auto' keeps the subprocess fallback but emits a one-time
WARNING per file (deduped across the ~4 routing queries per run).
- simulator='subprocess' is unchanged (returns before action inspection).
To surface the reason, the routing parse now returns (actions, reason):
_parse_bngl_actions_for_routing and the memoized loader (renamed
_load_bngl_routing_actions; _load_bngl_actions_for_routing kept as a thin
list-only wrapper for its other callers) carry the parse message. The
unavailable-BNGsim case already returned ROUTE_ERROR and is untouched.
Adds tests covering the bngsim error, the auto one-time-warning fallback,
the subprocess no-inspect path, reason propagation through the cache, and
an end-to-end repro of the atoll-typo model from the issue.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
ActionList.define_parser's list-valued argument grammar was stricter than
BNG2.pl/Perl: arg_type_list matched elements with `pp.Word(pp.nums + ".")`
(digits and '.' only) inside a plain `pp.delimitedList`, so it rejected
- scientific notation, e.g. par_scan_vals=>[2.3e-10,5.1e-10]
- a trailing comma, e.g. par_scan_vals=>[1,2,3,]
Both are valid Perl that BNG2.pl parses and runs. When a model used either
(commonly par_scan_vals on parameter_scan), modelapi.bngmodel raised
BNGParseError, so under simulator='bngsim' the bridge couldn't inspect the
actions and silently fell back to the legacy subprocess (the #109 class) —
the model never ran on bngsim. Real models hit this: RuleHub's
Mitra2019/15-igf1r fits and Salazar-Cavazos2019 CHO_EGFR best-fit.
Broaden arg_type_list to use arg_type_expr (which already spans e/E and
+/-), allow an empty list, and tolerate one optional trailing comma:
arg_type_list = "[" + Optional(delimitedList(quote_word ^ arg_type_expr))
+ Optional(",") + "]"
Still rejects genuinely-malformed lists (double commas `[1,,2]`, unclosed
`[1,2,`). Adds parametrized accept/reject tests over the issue's matrix and
the affected real-model forms.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
…legacy
Follow-up to the #109 contract. classify_bngsim_route returned the
_classify_bngl_actions_for_bngsim result verbatim, so under an explicit
simulator='bngsim' request a BNGL with an action the router doesn't
recognize still silently ran on the legacy BNG2.pl stack (ROUTE_SUBPROCESS
was never promoted to ROUTE_ERROR). #109 only closed the parse-failure
(actions==None) hole; this closes the unrecognized-action hole.
BNGsim can run such a model via the BNG2.pl backend hook — the router just
can't confirm an unknown action is safe to delegate — so strict mode now
surfaces ROUTE_ERROR with the reason instead of degrading silently. PLA and
BNGsim-unsupported methods are genuine BNGsim incapabilities, so they stay
on the subprocess route in every mode (auto and bngsim alike); auto keeps
the legacy fallback for unrecognized actions too.
Threads `simulator` into _classify_bngl_actions_for_bngsim (default 'auto',
back-compatible) and promotes only the unrecognized-action branch. Adds
tests: bngsim unknown-action -> error, auto unknown-action -> subprocess,
and bngsim PLA / unsupported-method -> subprocess.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
method=>"rm" routes to BNGsim's RuleMonkey (via the rm->nf rewrite + backend
hook) only when RuleMonkey is installed. But the router marked rm supported
UNCONDITIONALLY — _method_supported_by_bngsim_for_routing never checked
RuleMonkey, unlike nf/NFsim — and classify_bngsim_route took no rulemonkey
arg. So an rm model on a BNGsim without RuleMonkey still classified as
ROUTE_BNGL_BNGSIM, then run_bngl_with_bngsim (which hardcodes
simulator="auto") silently fell back to legacy — invisibly even under
simulator='bngsim'. Same silent-downgrade class as #109.
Make the classifier RuleMonkey-aware (thread bngsim_has_rulemonkey through
classify_bngsim_route -> _classify_bngl_actions_for_bngsim ->
_method_supported_by_bngsim_for_routing) so the decision is made up front
where strict mode is enforced, not in the simulator-blind runner.
Treat nf-without-NFsim and rm-without-RuleMonkey uniformly as *build*
incapabilities (_BNGSIM_OPTIONAL_COMPONENT_METHODS): BNGsim could run them
with the component installed, so simulator='bngsim' errors (surfacing
"install NFsim/RuleMonkey") while auto falls back to legacy. This matches
the existing direct BNG-XML nf behavior (classify already errored there
under bngsim).
NOTE: this revises the BNGL nf-without-NFsim case shipped in the previous
commit (was subprocess in both modes) so nf and rm are consistent and the
strict-bngsim silent gap is closed for both. pla stays subprocess in both
modes (a categorical incapability, not a missing component); the cvode alias
keeps its legacy route. Updates tests accordingly and adds rm coverage.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
Fix BNGsim bridge silent fallbacks: strict routing error (#109) + Perl-faithful list-arg grammar (#110)
Sign up for freeto 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.

1 participant

@akutuva21
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

⚡ [performance improvement N+1 Query in database iteration] - #109

Closed
akutuva21 wants to merge 2 commits into
mainfrom
bolt-perf-naming-database-n-plus-1-1138012978852035096
Closed

⚡ [performance improvement N+1 Query in database iteration]#109
akutuva21 wants to merge 2 commits into
mainfrom
bolt-perf-naming-database-n-plus-1-1138012978852035096

Conversation

@akutuva21

Copy link
Copy Markdown
Owner

💡 What:
Replaced an N+1 looping query pattern inside NamingDatabase.findOverlappingNamespace with a batched query implementation. Instead of establishing a new connection and executing a SELECT statement for each file individually, it now chunks the fileList (size 500) and queries the DB using an IN (...) clause. The script builds a mapped dictionary mapping filenames to their rows and processes them locally.

🎯 Why:
The original implementation had a classic N+1 query issue. For N files, it initialized N separate database connections and ran N queries. This incurred heavy I/O overhead and was extremely inefficient, particularly for processing large databases.

📊 Measured Improvement:
On a dataset of 1000 simulated files:

  • Baseline (N+1 queries): ~0.417s
  • Optimized (Batched queries): ~0.010s
  • Speedup: ~40x

PR created automatically by Jules for task 1138012978852035096 started by @akutuva21

Replaces repeated N+1 DB calls inside a loop with a single chunked
batched SQL IN query fetching all required records once, speeding
up execution from O(N) queries to O(1) batched queries.
Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>
@google-labs-jules

Copy link
Copy Markdown

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@akutuva21

Copy link
Copy Markdown
OwnerAuthor

Superseded by #108 namingDatabase batching optimization.

@google-labs-jules

Copy link
Copy Markdown

Superseded by #108 namingDatabase batching optimization.

Understood. Acknowledging that this work is now obsolete and stopping work on this task.

akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
…ions
Under simulator='bngsim', the routing bridge silently fell back to the
legacy BNG2.pl subprocess engine whenever the Python parser
(modelapi.bngmodel) could not inspect a BNGL's actions — e.g. a typo'd or
unknown simulate argument (atoll, abstol, par_scan_vals) that bngmodel
rejects but BNG2.pl tolerates. This violated the simulator='bngsim'
contract ("use BNGsim, or error"): the caller got legacy output with no
exception and no warning. A parity sweep over 895 models hit this on 9
models.
_classify_bngl_actions_for_bngsim() returned ROUTE_SUBPROCESS for the
un-inspectable case unconditionally, with no reference to simulator.
Fix, at the classify_bngsim_route call site where simulator is in scope:
- simulator='bngsim' + un-inspectable actions -> ROUTE_ERROR, propagating
the underlying parse reason so the caller learns why it couldn't route
to BNGsim. Both consumers (main.py, runner.run) already raise
BNGSimError(route.reason) on ROUTE_ERROR.
- simulator='auto' keeps the subprocess fallback but emits a one-time
WARNING per file (deduped across the ~4 routing queries per run).
- simulator='subprocess' is unchanged (returns before action inspection).
To surface the reason, the routing parse now returns (actions, reason):
_parse_bngl_actions_for_routing and the memoized loader (renamed
_load_bngl_routing_actions; _load_bngl_actions_for_routing kept as a thin
list-only wrapper for its other callers) carry the parse message. The
unavailable-BNGsim case already returned ROUTE_ERROR and is untouched.
Adds tests covering the bngsim error, the auto one-time-warning fallback,
the subprocess no-inspect path, reason propagation through the cache, and
an end-to-end repro of the atoll-typo model from the issue.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
ActionList.define_parser's list-valued argument grammar was stricter than
BNG2.pl/Perl: arg_type_list matched elements with `pp.Word(pp.nums + ".")`
(digits and '.' only) inside a plain `pp.delimitedList`, so it rejected
- scientific notation, e.g. par_scan_vals=>[2.3e-10,5.1e-10]
- a trailing comma, e.g. par_scan_vals=>[1,2,3,]
Both are valid Perl that BNG2.pl parses and runs. When a model used either
(commonly par_scan_vals on parameter_scan), modelapi.bngmodel raised
BNGParseError, so under simulator='bngsim' the bridge couldn't inspect the
actions and silently fell back to the legacy subprocess (the #109 class) —
the model never ran on bngsim. Real models hit this: RuleHub's
Mitra2019/15-igf1r fits and Salazar-Cavazos2019 CHO_EGFR best-fit.
Broaden arg_type_list to use arg_type_expr (which already spans e/E and
+/-), allow an empty list, and tolerate one optional trailing comma:
arg_type_list = "[" + Optional(delimitedList(quote_word ^ arg_type_expr))
+ Optional(",") + "]"
Still rejects genuinely-malformed lists (double commas `[1,,2]`, unclosed
`[1,2,`). Adds parametrized accept/reject tests over the issue's matrix and
the affected real-model forms.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
…legacy
Follow-up to the #109 contract. classify_bngsim_route returned the
_classify_bngl_actions_for_bngsim result verbatim, so under an explicit
simulator='bngsim' request a BNGL with an action the router doesn't
recognize still silently ran on the legacy BNG2.pl stack (ROUTE_SUBPROCESS
was never promoted to ROUTE_ERROR). #109 only closed the parse-failure
(actions==None) hole; this closes the unrecognized-action hole.
BNGsim can run such a model via the BNG2.pl backend hook — the router just
can't confirm an unknown action is safe to delegate — so strict mode now
surfaces ROUTE_ERROR with the reason instead of degrading silently. PLA and
BNGsim-unsupported methods are genuine BNGsim incapabilities, so they stay
on the subprocess route in every mode (auto and bngsim alike); auto keeps
the legacy fallback for unrecognized actions too.
Threads `simulator` into _classify_bngl_actions_for_bngsim (default 'auto',
back-compatible) and promotes only the unrecognized-action branch. Adds
tests: bngsim unknown-action -> error, auto unknown-action -> subprocess,
and bngsim PLA / unsupported-method -> subprocess.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
method=>"rm" routes to BNGsim's RuleMonkey (via the rm->nf rewrite + backend
hook) only when RuleMonkey is installed. But the router marked rm supported
UNCONDITIONALLY — _method_supported_by_bngsim_for_routing never checked
RuleMonkey, unlike nf/NFsim — and classify_bngsim_route took no rulemonkey
arg. So an rm model on a BNGsim without RuleMonkey still classified as
ROUTE_BNGL_BNGSIM, then run_bngl_with_bngsim (which hardcodes
simulator="auto") silently fell back to legacy — invisibly even under
simulator='bngsim'. Same silent-downgrade class as #109.
Make the classifier RuleMonkey-aware (thread bngsim_has_rulemonkey through
classify_bngsim_route -> _classify_bngl_actions_for_bngsim ->
_method_supported_by_bngsim_for_routing) so the decision is made up front
where strict mode is enforced, not in the simulator-blind runner.
Treat nf-without-NFsim and rm-without-RuleMonkey uniformly as *build*
incapabilities (_BNGSIM_OPTIONAL_COMPONENT_METHODS): BNGsim could run them
with the component installed, so simulator='bngsim' errors (surfacing
"install NFsim/RuleMonkey") while auto falls back to legacy. This matches
the existing direct BNG-XML nf behavior (classify already errored there
under bngsim).
NOTE: this revises the BNGL nf-without-NFsim case shipped in the previous
commit (was subprocess in both modes) so nf and rm are consistent and the
strict-bngsim silent gap is closed for both. pla stays subprocess in both
modes (a categorical incapability, not a missing component); the cvode alias
keeps its legacy route. Updates tests accordingly and adds rm coverage.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
Fix BNGsim bridge silent fallbacks: strict routing error (#109) + Perl-faithful list-arg grammar (#110)
Sign up for freeto 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.

1 participant

@akutuva21
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

⚡ [performance improvement N+1 Query in database iteration] - #109

Closed
akutuva21 wants to merge 2 commits into
mainfrom
bolt-perf-naming-database-n-plus-1-1138012978852035096
Closed

⚡ [performance improvement N+1 Query in database iteration]#109
akutuva21 wants to merge 2 commits into
mainfrom
bolt-perf-naming-database-n-plus-1-1138012978852035096

Conversation

@akutuva21

Copy link
Copy Markdown
Owner

💡 What:
Replaced an N+1 looping query pattern inside NamingDatabase.findOverlappingNamespace with a batched query implementation. Instead of establishing a new connection and executing a SELECT statement for each file individually, it now chunks the fileList (size 500) and queries the DB using an IN (...) clause. The script builds a mapped dictionary mapping filenames to their rows and processes them locally.

🎯 Why:
The original implementation had a classic N+1 query issue. For N files, it initialized N separate database connections and ran N queries. This incurred heavy I/O overhead and was extremely inefficient, particularly for processing large databases.

📊 Measured Improvement:
On a dataset of 1000 simulated files:

  • Baseline (N+1 queries): ~0.417s
  • Optimized (Batched queries): ~0.010s
  • Speedup: ~40x

PR created automatically by Jules for task 1138012978852035096 started by @akutuva21

Replaces repeated N+1 DB calls inside a loop with a single chunked
batched SQL IN query fetching all required records once, speeding
up execution from O(N) queries to O(1) batched queries.
Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>
@google-labs-jules

Copy link
Copy Markdown

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@akutuva21

Copy link
Copy Markdown
OwnerAuthor

Superseded by #108 namingDatabase batching optimization.

@google-labs-jules

Copy link
Copy Markdown

Superseded by #108 namingDatabase batching optimization.

Understood. Acknowledging that this work is now obsolete and stopping work on this task.

akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
…ions
Under simulator='bngsim', the routing bridge silently fell back to the
legacy BNG2.pl subprocess engine whenever the Python parser
(modelapi.bngmodel) could not inspect a BNGL's actions — e.g. a typo'd or
unknown simulate argument (atoll, abstol, par_scan_vals) that bngmodel
rejects but BNG2.pl tolerates. This violated the simulator='bngsim'
contract ("use BNGsim, or error"): the caller got legacy output with no
exception and no warning. A parity sweep over 895 models hit this on 9
models.
_classify_bngl_actions_for_bngsim() returned ROUTE_SUBPROCESS for the
un-inspectable case unconditionally, with no reference to simulator.
Fix, at the classify_bngsim_route call site where simulator is in scope:
- simulator='bngsim' + un-inspectable actions -> ROUTE_ERROR, propagating
the underlying parse reason so the caller learns why it couldn't route
to BNGsim. Both consumers (main.py, runner.run) already raise
BNGSimError(route.reason) on ROUTE_ERROR.
- simulator='auto' keeps the subprocess fallback but emits a one-time
WARNING per file (deduped across the ~4 routing queries per run).
- simulator='subprocess' is unchanged (returns before action inspection).
To surface the reason, the routing parse now returns (actions, reason):
_parse_bngl_actions_for_routing and the memoized loader (renamed
_load_bngl_routing_actions; _load_bngl_actions_for_routing kept as a thin
list-only wrapper for its other callers) carry the parse message. The
unavailable-BNGsim case already returned ROUTE_ERROR and is untouched.
Adds tests covering the bngsim error, the auto one-time-warning fallback,
the subprocess no-inspect path, reason propagation through the cache, and
an end-to-end repro of the atoll-typo model from the issue.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
ActionList.define_parser's list-valued argument grammar was stricter than
BNG2.pl/Perl: arg_type_list matched elements with `pp.Word(pp.nums + ".")`
(digits and '.' only) inside a plain `pp.delimitedList`, so it rejected
- scientific notation, e.g. par_scan_vals=>[2.3e-10,5.1e-10]
- a trailing comma, e.g. par_scan_vals=>[1,2,3,]
Both are valid Perl that BNG2.pl parses and runs. When a model used either
(commonly par_scan_vals on parameter_scan), modelapi.bngmodel raised
BNGParseError, so under simulator='bngsim' the bridge couldn't inspect the
actions and silently fell back to the legacy subprocess (the #109 class) —
the model never ran on bngsim. Real models hit this: RuleHub's
Mitra2019/15-igf1r fits and Salazar-Cavazos2019 CHO_EGFR best-fit.
Broaden arg_type_list to use arg_type_expr (which already spans e/E and
+/-), allow an empty list, and tolerate one optional trailing comma:
arg_type_list = "[" + Optional(delimitedList(quote_word ^ arg_type_expr))
+ Optional(",") + "]"
Still rejects genuinely-malformed lists (double commas `[1,,2]`, unclosed
`[1,2,`). Adds parametrized accept/reject tests over the issue's matrix and
the affected real-model forms.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
…legacy
Follow-up to the #109 contract. classify_bngsim_route returned the
_classify_bngl_actions_for_bngsim result verbatim, so under an explicit
simulator='bngsim' request a BNGL with an action the router doesn't
recognize still silently ran on the legacy BNG2.pl stack (ROUTE_SUBPROCESS
was never promoted to ROUTE_ERROR). #109 only closed the parse-failure
(actions==None) hole; this closes the unrecognized-action hole.
BNGsim can run such a model via the BNG2.pl backend hook — the router just
can't confirm an unknown action is safe to delegate — so strict mode now
surfaces ROUTE_ERROR with the reason instead of degrading silently. PLA and
BNGsim-unsupported methods are genuine BNGsim incapabilities, so they stay
on the subprocess route in every mode (auto and bngsim alike); auto keeps
the legacy fallback for unrecognized actions too.
Threads `simulator` into _classify_bngl_actions_for_bngsim (default 'auto',
back-compatible) and promotes only the unrecognized-action branch. Adds
tests: bngsim unknown-action -> error, auto unknown-action -> subprocess,
and bngsim PLA / unsupported-method -> subprocess.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
method=>"rm" routes to BNGsim's RuleMonkey (via the rm->nf rewrite + backend
hook) only when RuleMonkey is installed. But the router marked rm supported
UNCONDITIONALLY — _method_supported_by_bngsim_for_routing never checked
RuleMonkey, unlike nf/NFsim — and classify_bngsim_route took no rulemonkey
arg. So an rm model on a BNGsim without RuleMonkey still classified as
ROUTE_BNGL_BNGSIM, then run_bngl_with_bngsim (which hardcodes
simulator="auto") silently fell back to legacy — invisibly even under
simulator='bngsim'. Same silent-downgrade class as #109.
Make the classifier RuleMonkey-aware (thread bngsim_has_rulemonkey through
classify_bngsim_route -> _classify_bngl_actions_for_bngsim ->
_method_supported_by_bngsim_for_routing) so the decision is made up front
where strict mode is enforced, not in the simulator-blind runner.
Treat nf-without-NFsim and rm-without-RuleMonkey uniformly as *build*
incapabilities (_BNGSIM_OPTIONAL_COMPONENT_METHODS): BNGsim could run them
with the component installed, so simulator='bngsim' errors (surfacing
"install NFsim/RuleMonkey") while auto falls back to legacy. This matches
the existing direct BNG-XML nf behavior (classify already errored there
under bngsim).
NOTE: this revises the BNGL nf-without-NFsim case shipped in the previous
commit (was subprocess in both modes) so nf and rm are consistent and the
strict-bngsim silent gap is closed for both. pla stays subprocess in both
modes (a categorical incapability, not a missing component); the cvode alias
keeps its legacy route. Updates tests accordingly and adds rm coverage.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
Fix BNGsim bridge silent fallbacks: strict routing error (#109) + Perl-faithful list-arg grammar (#110)
Sign up for freeto 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.

1 participant

@akutuva21
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

⚡ [performance improvement N+1 Query in database iteration] - #109

Closed
akutuva21 wants to merge 2 commits into
mainfrom
bolt-perf-naming-database-n-plus-1-1138012978852035096
Closed

⚡ [performance improvement N+1 Query in database iteration]#109
akutuva21 wants to merge 2 commits into
mainfrom
bolt-perf-naming-database-n-plus-1-1138012978852035096

Conversation

@akutuva21

Copy link
Copy Markdown
Owner

💡 What:
Replaced an N+1 looping query pattern inside NamingDatabase.findOverlappingNamespace with a batched query implementation. Instead of establishing a new connection and executing a SELECT statement for each file individually, it now chunks the fileList (size 500) and queries the DB using an IN (...) clause. The script builds a mapped dictionary mapping filenames to their rows and processes them locally.

🎯 Why:
The original implementation had a classic N+1 query issue. For N files, it initialized N separate database connections and ran N queries. This incurred heavy I/O overhead and was extremely inefficient, particularly for processing large databases.

📊 Measured Improvement:
On a dataset of 1000 simulated files:

  • Baseline (N+1 queries): ~0.417s
  • Optimized (Batched queries): ~0.010s
  • Speedup: ~40x

PR created automatically by Jules for task 1138012978852035096 started by @akutuva21

Replaces repeated N+1 DB calls inside a loop with a single chunked
batched SQL IN query fetching all required records once, speeding
up execution from O(N) queries to O(1) batched queries.
Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>
@google-labs-jules

Copy link
Copy Markdown

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@akutuva21

Copy link
Copy Markdown
OwnerAuthor

Superseded by #108 namingDatabase batching optimization.

@google-labs-jules

Copy link
Copy Markdown

Superseded by #108 namingDatabase batching optimization.

Understood. Acknowledging that this work is now obsolete and stopping work on this task.

akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
…ions
Under simulator='bngsim', the routing bridge silently fell back to the
legacy BNG2.pl subprocess engine whenever the Python parser
(modelapi.bngmodel) could not inspect a BNGL's actions — e.g. a typo'd or
unknown simulate argument (atoll, abstol, par_scan_vals) that bngmodel
rejects but BNG2.pl tolerates. This violated the simulator='bngsim'
contract ("use BNGsim, or error"): the caller got legacy output with no
exception and no warning. A parity sweep over 895 models hit this on 9
models.
_classify_bngl_actions_for_bngsim() returned ROUTE_SUBPROCESS for the
un-inspectable case unconditionally, with no reference to simulator.
Fix, at the classify_bngsim_route call site where simulator is in scope:
- simulator='bngsim' + un-inspectable actions -> ROUTE_ERROR, propagating
the underlying parse reason so the caller learns why it couldn't route
to BNGsim. Both consumers (main.py, runner.run) already raise
BNGSimError(route.reason) on ROUTE_ERROR.
- simulator='auto' keeps the subprocess fallback but emits a one-time
WARNING per file (deduped across the ~4 routing queries per run).
- simulator='subprocess' is unchanged (returns before action inspection).
To surface the reason, the routing parse now returns (actions, reason):
_parse_bngl_actions_for_routing and the memoized loader (renamed
_load_bngl_routing_actions; _load_bngl_actions_for_routing kept as a thin
list-only wrapper for its other callers) carry the parse message. The
unavailable-BNGsim case already returned ROUTE_ERROR and is untouched.
Adds tests covering the bngsim error, the auto one-time-warning fallback,
the subprocess no-inspect path, reason propagation through the cache, and
an end-to-end repro of the atoll-typo model from the issue.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
ActionList.define_parser's list-valued argument grammar was stricter than
BNG2.pl/Perl: arg_type_list matched elements with `pp.Word(pp.nums + ".")`
(digits and '.' only) inside a plain `pp.delimitedList`, so it rejected
- scientific notation, e.g. par_scan_vals=>[2.3e-10,5.1e-10]
- a trailing comma, e.g. par_scan_vals=>[1,2,3,]
Both are valid Perl that BNG2.pl parses and runs. When a model used either
(commonly par_scan_vals on parameter_scan), modelapi.bngmodel raised
BNGParseError, so under simulator='bngsim' the bridge couldn't inspect the
actions and silently fell back to the legacy subprocess (the #109 class) —
the model never ran on bngsim. Real models hit this: RuleHub's
Mitra2019/15-igf1r fits and Salazar-Cavazos2019 CHO_EGFR best-fit.
Broaden arg_type_list to use arg_type_expr (which already spans e/E and
+/-), allow an empty list, and tolerate one optional trailing comma:
arg_type_list = "[" + Optional(delimitedList(quote_word ^ arg_type_expr))
+ Optional(",") + "]"
Still rejects genuinely-malformed lists (double commas `[1,,2]`, unclosed
`[1,2,`). Adds parametrized accept/reject tests over the issue's matrix and
the affected real-model forms.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
…legacy
Follow-up to the #109 contract. classify_bngsim_route returned the
_classify_bngl_actions_for_bngsim result verbatim, so under an explicit
simulator='bngsim' request a BNGL with an action the router doesn't
recognize still silently ran on the legacy BNG2.pl stack (ROUTE_SUBPROCESS
was never promoted to ROUTE_ERROR). #109 only closed the parse-failure
(actions==None) hole; this closes the unrecognized-action hole.
BNGsim can run such a model via the BNG2.pl backend hook — the router just
can't confirm an unknown action is safe to delegate — so strict mode now
surfaces ROUTE_ERROR with the reason instead of degrading silently. PLA and
BNGsim-unsupported methods are genuine BNGsim incapabilities, so they stay
on the subprocess route in every mode (auto and bngsim alike); auto keeps
the legacy fallback for unrecognized actions too.
Threads `simulator` into _classify_bngl_actions_for_bngsim (default 'auto',
back-compatible) and promotes only the unrecognized-action branch. Adds
tests: bngsim unknown-action -> error, auto unknown-action -> subprocess,
and bngsim PLA / unsupported-method -> subprocess.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
method=>"rm" routes to BNGsim's RuleMonkey (via the rm->nf rewrite + backend
hook) only when RuleMonkey is installed. But the router marked rm supported
UNCONDITIONALLY — _method_supported_by_bngsim_for_routing never checked
RuleMonkey, unlike nf/NFsim — and classify_bngsim_route took no rulemonkey
arg. So an rm model on a BNGsim without RuleMonkey still classified as
ROUTE_BNGL_BNGSIM, then run_bngl_with_bngsim (which hardcodes
simulator="auto") silently fell back to legacy — invisibly even under
simulator='bngsim'. Same silent-downgrade class as #109.
Make the classifier RuleMonkey-aware (thread bngsim_has_rulemonkey through
classify_bngsim_route -> _classify_bngl_actions_for_bngsim ->
_method_supported_by_bngsim_for_routing) so the decision is made up front
where strict mode is enforced, not in the simulator-blind runner.
Treat nf-without-NFsim and rm-without-RuleMonkey uniformly as *build*
incapabilities (_BNGSIM_OPTIONAL_COMPONENT_METHODS): BNGsim could run them
with the component installed, so simulator='bngsim' errors (surfacing
"install NFsim/RuleMonkey") while auto falls back to legacy. This matches
the existing direct BNG-XML nf behavior (classify already errored there
under bngsim).
NOTE: this revises the BNGL nf-without-NFsim case shipped in the previous
commit (was subprocess in both modes) so nf and rm are consistent and the
strict-bngsim silent gap is closed for both. pla stays subprocess in both
modes (a categorical incapability, not a missing component); the cvode alias
keeps its legacy route. Updates tests accordingly and adds rm coverage.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
Fix BNGsim bridge silent fallbacks: strict routing error (#109) + Perl-faithful list-arg grammar (#110)
Sign up for freeto 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.

1 participant

@akutuva21
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

⚡ [performance improvement N+1 Query in database iteration] - #109

Closed
akutuva21 wants to merge 2 commits into
mainfrom
bolt-perf-naming-database-n-plus-1-1138012978852035096
Closed

⚡ [performance improvement N+1 Query in database iteration]#109
akutuva21 wants to merge 2 commits into
mainfrom
bolt-perf-naming-database-n-plus-1-1138012978852035096

Conversation

@akutuva21

Copy link
Copy Markdown
Owner

💡 What:
Replaced an N+1 looping query pattern inside NamingDatabase.findOverlappingNamespace with a batched query implementation. Instead of establishing a new connection and executing a SELECT statement for each file individually, it now chunks the fileList (size 500) and queries the DB using an IN (...) clause. The script builds a mapped dictionary mapping filenames to their rows and processes them locally.

🎯 Why:
The original implementation had a classic N+1 query issue. For N files, it initialized N separate database connections and ran N queries. This incurred heavy I/O overhead and was extremely inefficient, particularly for processing large databases.

📊 Measured Improvement:
On a dataset of 1000 simulated files:

  • Baseline (N+1 queries): ~0.417s
  • Optimized (Batched queries): ~0.010s
  • Speedup: ~40x

PR created automatically by Jules for task 1138012978852035096 started by @akutuva21

Replaces repeated N+1 DB calls inside a loop with a single chunked
batched SQL IN query fetching all required records once, speeding
up execution from O(N) queries to O(1) batched queries.
Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>
@google-labs-jules

Copy link
Copy Markdown

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@akutuva21

Copy link
Copy Markdown
OwnerAuthor

Superseded by #108 namingDatabase batching optimization.

@google-labs-jules

Copy link
Copy Markdown

Superseded by #108 namingDatabase batching optimization.

Understood. Acknowledging that this work is now obsolete and stopping work on this task.

akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
…ions
Under simulator='bngsim', the routing bridge silently fell back to the
legacy BNG2.pl subprocess engine whenever the Python parser
(modelapi.bngmodel) could not inspect a BNGL's actions — e.g. a typo'd or
unknown simulate argument (atoll, abstol, par_scan_vals) that bngmodel
rejects but BNG2.pl tolerates. This violated the simulator='bngsim'
contract ("use BNGsim, or error"): the caller got legacy output with no
exception and no warning. A parity sweep over 895 models hit this on 9
models.
_classify_bngl_actions_for_bngsim() returned ROUTE_SUBPROCESS for the
un-inspectable case unconditionally, with no reference to simulator.
Fix, at the classify_bngsim_route call site where simulator is in scope:
- simulator='bngsim' + un-inspectable actions -> ROUTE_ERROR, propagating
the underlying parse reason so the caller learns why it couldn't route
to BNGsim. Both consumers (main.py, runner.run) already raise
BNGSimError(route.reason) on ROUTE_ERROR.
- simulator='auto' keeps the subprocess fallback but emits a one-time
WARNING per file (deduped across the ~4 routing queries per run).
- simulator='subprocess' is unchanged (returns before action inspection).
To surface the reason, the routing parse now returns (actions, reason):
_parse_bngl_actions_for_routing and the memoized loader (renamed
_load_bngl_routing_actions; _load_bngl_actions_for_routing kept as a thin
list-only wrapper for its other callers) carry the parse message. The
unavailable-BNGsim case already returned ROUTE_ERROR and is untouched.
Adds tests covering the bngsim error, the auto one-time-warning fallback,
the subprocess no-inspect path, reason propagation through the cache, and
an end-to-end repro of the atoll-typo model from the issue.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
ActionList.define_parser's list-valued argument grammar was stricter than
BNG2.pl/Perl: arg_type_list matched elements with `pp.Word(pp.nums + ".")`
(digits and '.' only) inside a plain `pp.delimitedList`, so it rejected
- scientific notation, e.g. par_scan_vals=>[2.3e-10,5.1e-10]
- a trailing comma, e.g. par_scan_vals=>[1,2,3,]
Both are valid Perl that BNG2.pl parses and runs. When a model used either
(commonly par_scan_vals on parameter_scan), modelapi.bngmodel raised
BNGParseError, so under simulator='bngsim' the bridge couldn't inspect the
actions and silently fell back to the legacy subprocess (the #109 class) —
the model never ran on bngsim. Real models hit this: RuleHub's
Mitra2019/15-igf1r fits and Salazar-Cavazos2019 CHO_EGFR best-fit.
Broaden arg_type_list to use arg_type_expr (which already spans e/E and
+/-), allow an empty list, and tolerate one optional trailing comma:
arg_type_list = "[" + Optional(delimitedList(quote_word ^ arg_type_expr))
+ Optional(",") + "]"
Still rejects genuinely-malformed lists (double commas `[1,,2]`, unclosed
`[1,2,`). Adds parametrized accept/reject tests over the issue's matrix and
the affected real-model forms.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
…legacy
Follow-up to the #109 contract. classify_bngsim_route returned the
_classify_bngl_actions_for_bngsim result verbatim, so under an explicit
simulator='bngsim' request a BNGL with an action the router doesn't
recognize still silently ran on the legacy BNG2.pl stack (ROUTE_SUBPROCESS
was never promoted to ROUTE_ERROR). #109 only closed the parse-failure
(actions==None) hole; this closes the unrecognized-action hole.
BNGsim can run such a model via the BNG2.pl backend hook — the router just
can't confirm an unknown action is safe to delegate — so strict mode now
surfaces ROUTE_ERROR with the reason instead of degrading silently. PLA and
BNGsim-unsupported methods are genuine BNGsim incapabilities, so they stay
on the subprocess route in every mode (auto and bngsim alike); auto keeps
the legacy fallback for unrecognized actions too.
Threads `simulator` into _classify_bngl_actions_for_bngsim (default 'auto',
back-compatible) and promotes only the unrecognized-action branch. Adds
tests: bngsim unknown-action -> error, auto unknown-action -> subprocess,
and bngsim PLA / unsupported-method -> subprocess.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
method=>"rm" routes to BNGsim's RuleMonkey (via the rm->nf rewrite + backend
hook) only when RuleMonkey is installed. But the router marked rm supported
UNCONDITIONALLY — _method_supported_by_bngsim_for_routing never checked
RuleMonkey, unlike nf/NFsim — and classify_bngsim_route took no rulemonkey
arg. So an rm model on a BNGsim without RuleMonkey still classified as
ROUTE_BNGL_BNGSIM, then run_bngl_with_bngsim (which hardcodes
simulator="auto") silently fell back to legacy — invisibly even under
simulator='bngsim'. Same silent-downgrade class as #109.
Make the classifier RuleMonkey-aware (thread bngsim_has_rulemonkey through
classify_bngsim_route -> _classify_bngl_actions_for_bngsim ->
_method_supported_by_bngsim_for_routing) so the decision is made up front
where strict mode is enforced, not in the simulator-blind runner.
Treat nf-without-NFsim and rm-without-RuleMonkey uniformly as *build*
incapabilities (_BNGSIM_OPTIONAL_COMPONENT_METHODS): BNGsim could run them
with the component installed, so simulator='bngsim' errors (surfacing
"install NFsim/RuleMonkey") while auto falls back to legacy. This matches
the existing direct BNG-XML nf behavior (classify already errored there
under bngsim).
NOTE: this revises the BNGL nf-without-NFsim case shipped in the previous
commit (was subprocess in both modes) so nf and rm are consistent and the
strict-bngsim silent gap is closed for both. pla stays subprocess in both
modes (a categorical incapability, not a missing component); the cvode alias
keeps its legacy route. Updates tests accordingly and adds rm coverage.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
Fix BNGsim bridge silent fallbacks: strict routing error (#109) + Perl-faithful list-arg grammar (#110)
Sign up for freeto 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.

1 participant

@akutuva21
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

⚡ [performance improvement N+1 Query in database iteration] - #109

Closed
akutuva21 wants to merge 2 commits into
mainfrom
bolt-perf-naming-database-n-plus-1-1138012978852035096
Closed

⚡ [performance improvement N+1 Query in database iteration]#109
akutuva21 wants to merge 2 commits into
mainfrom
bolt-perf-naming-database-n-plus-1-1138012978852035096

Conversation

@akutuva21

Copy link
Copy Markdown
Owner

💡 What:
Replaced an N+1 looping query pattern inside NamingDatabase.findOverlappingNamespace with a batched query implementation. Instead of establishing a new connection and executing a SELECT statement for each file individually, it now chunks the fileList (size 500) and queries the DB using an IN (...) clause. The script builds a mapped dictionary mapping filenames to their rows and processes them locally.

🎯 Why:
The original implementation had a classic N+1 query issue. For N files, it initialized N separate database connections and ran N queries. This incurred heavy I/O overhead and was extremely inefficient, particularly for processing large databases.

📊 Measured Improvement:
On a dataset of 1000 simulated files:

  • Baseline (N+1 queries): ~0.417s
  • Optimized (Batched queries): ~0.010s
  • Speedup: ~40x

PR created automatically by Jules for task 1138012978852035096 started by @akutuva21

Replaces repeated N+1 DB calls inside a loop with a single chunked
batched SQL IN query fetching all required records once, speeding
up execution from O(N) queries to O(1) batched queries.
Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>
@google-labs-jules

Copy link
Copy Markdown

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@akutuva21

Copy link
Copy Markdown
OwnerAuthor

Superseded by #108 namingDatabase batching optimization.

@google-labs-jules

Copy link
Copy Markdown

Superseded by #108 namingDatabase batching optimization.

Understood. Acknowledging that this work is now obsolete and stopping work on this task.

akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
…ions
Under simulator='bngsim', the routing bridge silently fell back to the
legacy BNG2.pl subprocess engine whenever the Python parser
(modelapi.bngmodel) could not inspect a BNGL's actions — e.g. a typo'd or
unknown simulate argument (atoll, abstol, par_scan_vals) that bngmodel
rejects but BNG2.pl tolerates. This violated the simulator='bngsim'
contract ("use BNGsim, or error"): the caller got legacy output with no
exception and no warning. A parity sweep over 895 models hit this on 9
models.
_classify_bngl_actions_for_bngsim() returned ROUTE_SUBPROCESS for the
un-inspectable case unconditionally, with no reference to simulator.
Fix, at the classify_bngsim_route call site where simulator is in scope:
- simulator='bngsim' + un-inspectable actions -> ROUTE_ERROR, propagating
the underlying parse reason so the caller learns why it couldn't route
to BNGsim. Both consumers (main.py, runner.run) already raise
BNGSimError(route.reason) on ROUTE_ERROR.
- simulator='auto' keeps the subprocess fallback but emits a one-time
WARNING per file (deduped across the ~4 routing queries per run).
- simulator='subprocess' is unchanged (returns before action inspection).
To surface the reason, the routing parse now returns (actions, reason):
_parse_bngl_actions_for_routing and the memoized loader (renamed
_load_bngl_routing_actions; _load_bngl_actions_for_routing kept as a thin
list-only wrapper for its other callers) carry the parse message. The
unavailable-BNGsim case already returned ROUTE_ERROR and is untouched.
Adds tests covering the bngsim error, the auto one-time-warning fallback,
the subprocess no-inspect path, reason propagation through the cache, and
an end-to-end repro of the atoll-typo model from the issue.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
ActionList.define_parser's list-valued argument grammar was stricter than
BNG2.pl/Perl: arg_type_list matched elements with `pp.Word(pp.nums + ".")`
(digits and '.' only) inside a plain `pp.delimitedList`, so it rejected
- scientific notation, e.g. par_scan_vals=>[2.3e-10,5.1e-10]
- a trailing comma, e.g. par_scan_vals=>[1,2,3,]
Both are valid Perl that BNG2.pl parses and runs. When a model used either
(commonly par_scan_vals on parameter_scan), modelapi.bngmodel raised
BNGParseError, so under simulator='bngsim' the bridge couldn't inspect the
actions and silently fell back to the legacy subprocess (the #109 class) —
the model never ran on bngsim. Real models hit this: RuleHub's
Mitra2019/15-igf1r fits and Salazar-Cavazos2019 CHO_EGFR best-fit.
Broaden arg_type_list to use arg_type_expr (which already spans e/E and
+/-), allow an empty list, and tolerate one optional trailing comma:
arg_type_list = "[" + Optional(delimitedList(quote_word ^ arg_type_expr))
+ Optional(",") + "]"
Still rejects genuinely-malformed lists (double commas `[1,,2]`, unclosed
`[1,2,`). Adds parametrized accept/reject tests over the issue's matrix and
the affected real-model forms.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
…legacy
Follow-up to the #109 contract. classify_bngsim_route returned the
_classify_bngl_actions_for_bngsim result verbatim, so under an explicit
simulator='bngsim' request a BNGL with an action the router doesn't
recognize still silently ran on the legacy BNG2.pl stack (ROUTE_SUBPROCESS
was never promoted to ROUTE_ERROR). #109 only closed the parse-failure
(actions==None) hole; this closes the unrecognized-action hole.
BNGsim can run such a model via the BNG2.pl backend hook — the router just
can't confirm an unknown action is safe to delegate — so strict mode now
surfaces ROUTE_ERROR with the reason instead of degrading silently. PLA and
BNGsim-unsupported methods are genuine BNGsim incapabilities, so they stay
on the subprocess route in every mode (auto and bngsim alike); auto keeps
the legacy fallback for unrecognized actions too.
Threads `simulator` into _classify_bngl_actions_for_bngsim (default 'auto',
back-compatible) and promotes only the unrecognized-action branch. Adds
tests: bngsim unknown-action -> error, auto unknown-action -> subprocess,
and bngsim PLA / unsupported-method -> subprocess.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
method=>"rm" routes to BNGsim's RuleMonkey (via the rm->nf rewrite + backend
hook) only when RuleMonkey is installed. But the router marked rm supported
UNCONDITIONALLY — _method_supported_by_bngsim_for_routing never checked
RuleMonkey, unlike nf/NFsim — and classify_bngsim_route took no rulemonkey
arg. So an rm model on a BNGsim without RuleMonkey still classified as
ROUTE_BNGL_BNGSIM, then run_bngl_with_bngsim (which hardcodes
simulator="auto") silently fell back to legacy — invisibly even under
simulator='bngsim'. Same silent-downgrade class as #109.
Make the classifier RuleMonkey-aware (thread bngsim_has_rulemonkey through
classify_bngsim_route -> _classify_bngl_actions_for_bngsim ->
_method_supported_by_bngsim_for_routing) so the decision is made up front
where strict mode is enforced, not in the simulator-blind runner.
Treat nf-without-NFsim and rm-without-RuleMonkey uniformly as *build*
incapabilities (_BNGSIM_OPTIONAL_COMPONENT_METHODS): BNGsim could run them
with the component installed, so simulator='bngsim' errors (surfacing
"install NFsim/RuleMonkey") while auto falls back to legacy. This matches
the existing direct BNG-XML nf behavior (classify already errored there
under bngsim).
NOTE: this revises the BNGL nf-without-NFsim case shipped in the previous
commit (was subprocess in both modes) so nf and rm are consistent and the
strict-bngsim silent gap is closed for both. pla stays subprocess in both
modes (a categorical incapability, not a missing component); the cvode alias
keeps its legacy route. Updates tests accordingly and adds rm coverage.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
Fix BNGsim bridge silent fallbacks: strict routing error (#109) + Perl-faithful list-arg grammar (#110)
Sign up for freeto 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.

1 participant

@akutuva21
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

⚡ [performance improvement N+1 Query in database iteration] - #109

Closed
akutuva21 wants to merge 2 commits into
mainfrom
bolt-perf-naming-database-n-plus-1-1138012978852035096
Closed

⚡ [performance improvement N+1 Query in database iteration]#109
akutuva21 wants to merge 2 commits into
mainfrom
bolt-perf-naming-database-n-plus-1-1138012978852035096

Conversation

@akutuva21

Copy link
Copy Markdown
Owner

💡 What:
Replaced an N+1 looping query pattern inside NamingDatabase.findOverlappingNamespace with a batched query implementation. Instead of establishing a new connection and executing a SELECT statement for each file individually, it now chunks the fileList (size 500) and queries the DB using an IN (...) clause. The script builds a mapped dictionary mapping filenames to their rows and processes them locally.

🎯 Why:
The original implementation had a classic N+1 query issue. For N files, it initialized N separate database connections and ran N queries. This incurred heavy I/O overhead and was extremely inefficient, particularly for processing large databases.

📊 Measured Improvement:
On a dataset of 1000 simulated files:

  • Baseline (N+1 queries): ~0.417s
  • Optimized (Batched queries): ~0.010s
  • Speedup: ~40x

PR created automatically by Jules for task 1138012978852035096 started by @akutuva21

Replaces repeated N+1 DB calls inside a loop with a single chunked
batched SQL IN query fetching all required records once, speeding
up execution from O(N) queries to O(1) batched queries.
Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>
@google-labs-jules

Copy link
Copy Markdown

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@akutuva21

Copy link
Copy Markdown
OwnerAuthor

Superseded by #108 namingDatabase batching optimization.

@google-labs-jules

Copy link
Copy Markdown

Superseded by #108 namingDatabase batching optimization.

Understood. Acknowledging that this work is now obsolete and stopping work on this task.

akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
…ions
Under simulator='bngsim', the routing bridge silently fell back to the
legacy BNG2.pl subprocess engine whenever the Python parser
(modelapi.bngmodel) could not inspect a BNGL's actions — e.g. a typo'd or
unknown simulate argument (atoll, abstol, par_scan_vals) that bngmodel
rejects but BNG2.pl tolerates. This violated the simulator='bngsim'
contract ("use BNGsim, or error"): the caller got legacy output with no
exception and no warning. A parity sweep over 895 models hit this on 9
models.
_classify_bngl_actions_for_bngsim() returned ROUTE_SUBPROCESS for the
un-inspectable case unconditionally, with no reference to simulator.
Fix, at the classify_bngsim_route call site where simulator is in scope:
- simulator='bngsim' + un-inspectable actions -> ROUTE_ERROR, propagating
the underlying parse reason so the caller learns why it couldn't route
to BNGsim. Both consumers (main.py, runner.run) already raise
BNGSimError(route.reason) on ROUTE_ERROR.
- simulator='auto' keeps the subprocess fallback but emits a one-time
WARNING per file (deduped across the ~4 routing queries per run).
- simulator='subprocess' is unchanged (returns before action inspection).
To surface the reason, the routing parse now returns (actions, reason):
_parse_bngl_actions_for_routing and the memoized loader (renamed
_load_bngl_routing_actions; _load_bngl_actions_for_routing kept as a thin
list-only wrapper for its other callers) carry the parse message. The
unavailable-BNGsim case already returned ROUTE_ERROR and is untouched.
Adds tests covering the bngsim error, the auto one-time-warning fallback,
the subprocess no-inspect path, reason propagation through the cache, and
an end-to-end repro of the atoll-typo model from the issue.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
ActionList.define_parser's list-valued argument grammar was stricter than
BNG2.pl/Perl: arg_type_list matched elements with `pp.Word(pp.nums + ".")`
(digits and '.' only) inside a plain `pp.delimitedList`, so it rejected
- scientific notation, e.g. par_scan_vals=>[2.3e-10,5.1e-10]
- a trailing comma, e.g. par_scan_vals=>[1,2,3,]
Both are valid Perl that BNG2.pl parses and runs. When a model used either
(commonly par_scan_vals on parameter_scan), modelapi.bngmodel raised
BNGParseError, so under simulator='bngsim' the bridge couldn't inspect the
actions and silently fell back to the legacy subprocess (the #109 class) —
the model never ran on bngsim. Real models hit this: RuleHub's
Mitra2019/15-igf1r fits and Salazar-Cavazos2019 CHO_EGFR best-fit.
Broaden arg_type_list to use arg_type_expr (which already spans e/E and
+/-), allow an empty list, and tolerate one optional trailing comma:
arg_type_list = "[" + Optional(delimitedList(quote_word ^ arg_type_expr))
+ Optional(",") + "]"
Still rejects genuinely-malformed lists (double commas `[1,,2]`, unclosed
`[1,2,`). Adds parametrized accept/reject tests over the issue's matrix and
the affected real-model forms.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
…legacy
Follow-up to the #109 contract. classify_bngsim_route returned the
_classify_bngl_actions_for_bngsim result verbatim, so under an explicit
simulator='bngsim' request a BNGL with an action the router doesn't
recognize still silently ran on the legacy BNG2.pl stack (ROUTE_SUBPROCESS
was never promoted to ROUTE_ERROR). #109 only closed the parse-failure
(actions==None) hole; this closes the unrecognized-action hole.
BNGsim can run such a model via the BNG2.pl backend hook — the router just
can't confirm an unknown action is safe to delegate — so strict mode now
surfaces ROUTE_ERROR with the reason instead of degrading silently. PLA and
BNGsim-unsupported methods are genuine BNGsim incapabilities, so they stay
on the subprocess route in every mode (auto and bngsim alike); auto keeps
the legacy fallback for unrecognized actions too.
Threads `simulator` into _classify_bngl_actions_for_bngsim (default 'auto',
back-compatible) and promotes only the unrecognized-action branch. Adds
tests: bngsim unknown-action -> error, auto unknown-action -> subprocess,
and bngsim PLA / unsupported-method -> subprocess.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
method=>"rm" routes to BNGsim's RuleMonkey (via the rm->nf rewrite + backend
hook) only when RuleMonkey is installed. But the router marked rm supported
UNCONDITIONALLY — _method_supported_by_bngsim_for_routing never checked
RuleMonkey, unlike nf/NFsim — and classify_bngsim_route took no rulemonkey
arg. So an rm model on a BNGsim without RuleMonkey still classified as
ROUTE_BNGL_BNGSIM, then run_bngl_with_bngsim (which hardcodes
simulator="auto") silently fell back to legacy — invisibly even under
simulator='bngsim'. Same silent-downgrade class as #109.
Make the classifier RuleMonkey-aware (thread bngsim_has_rulemonkey through
classify_bngsim_route -> _classify_bngl_actions_for_bngsim ->
_method_supported_by_bngsim_for_routing) so the decision is made up front
where strict mode is enforced, not in the simulator-blind runner.
Treat nf-without-NFsim and rm-without-RuleMonkey uniformly as *build*
incapabilities (_BNGSIM_OPTIONAL_COMPONENT_METHODS): BNGsim could run them
with the component installed, so simulator='bngsim' errors (surfacing
"install NFsim/RuleMonkey") while auto falls back to legacy. This matches
the existing direct BNG-XML nf behavior (classify already errored there
under bngsim).
NOTE: this revises the BNGL nf-without-NFsim case shipped in the previous
commit (was subprocess in both modes) so nf and rm are consistent and the
strict-bngsim silent gap is closed for both. pla stays subprocess in both
modes (a categorical incapability, not a missing component); the cvode alias
keeps its legacy route. Updates tests accordingly and adds rm coverage.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
Fix BNGsim bridge silent fallbacks: strict routing error (#109) + Perl-faithful list-arg grammar (#110)
Sign up for freeto 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.

1 participant

@akutuva21
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

⚡ [performance improvement N+1 Query in database iteration] - #109

Closed
akutuva21 wants to merge 2 commits into
mainfrom
bolt-perf-naming-database-n-plus-1-1138012978852035096
Closed

⚡ [performance improvement N+1 Query in database iteration]#109
akutuva21 wants to merge 2 commits into
mainfrom
bolt-perf-naming-database-n-plus-1-1138012978852035096

Conversation

@akutuva21

Copy link
Copy Markdown
Owner

💡 What:
Replaced an N+1 looping query pattern inside NamingDatabase.findOverlappingNamespace with a batched query implementation. Instead of establishing a new connection and executing a SELECT statement for each file individually, it now chunks the fileList (size 500) and queries the DB using an IN (...) clause. The script builds a mapped dictionary mapping filenames to their rows and processes them locally.

🎯 Why:
The original implementation had a classic N+1 query issue. For N files, it initialized N separate database connections and ran N queries. This incurred heavy I/O overhead and was extremely inefficient, particularly for processing large databases.

📊 Measured Improvement:
On a dataset of 1000 simulated files:

  • Baseline (N+1 queries): ~0.417s
  • Optimized (Batched queries): ~0.010s
  • Speedup: ~40x

PR created automatically by Jules for task 1138012978852035096 started by @akutuva21

Replaces repeated N+1 DB calls inside a loop with a single chunked
batched SQL IN query fetching all required records once, speeding
up execution from O(N) queries to O(1) batched queries.
Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com>
@google-labs-jules

Copy link
Copy Markdown

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@akutuva21

Copy link
Copy Markdown
OwnerAuthor

Superseded by #108 namingDatabase batching optimization.

@google-labs-jules

Copy link
Copy Markdown

Superseded by #108 namingDatabase batching optimization.

Understood. Acknowledging that this work is now obsolete and stopping work on this task.

akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
…ions
Under simulator='bngsim', the routing bridge silently fell back to the
legacy BNG2.pl subprocess engine whenever the Python parser
(modelapi.bngmodel) could not inspect a BNGL's actions — e.g. a typo'd or
unknown simulate argument (atoll, abstol, par_scan_vals) that bngmodel
rejects but BNG2.pl tolerates. This violated the simulator='bngsim'
contract ("use BNGsim, or error"): the caller got legacy output with no
exception and no warning. A parity sweep over 895 models hit this on 9
models.
_classify_bngl_actions_for_bngsim() returned ROUTE_SUBPROCESS for the
un-inspectable case unconditionally, with no reference to simulator.
Fix, at the classify_bngsim_route call site where simulator is in scope:
- simulator='bngsim' + un-inspectable actions -> ROUTE_ERROR, propagating
the underlying parse reason so the caller learns why it couldn't route
to BNGsim. Both consumers (main.py, runner.run) already raise
BNGSimError(route.reason) on ROUTE_ERROR.
- simulator='auto' keeps the subprocess fallback but emits a one-time
WARNING per file (deduped across the ~4 routing queries per run).
- simulator='subprocess' is unchanged (returns before action inspection).
To surface the reason, the routing parse now returns (actions, reason):
_parse_bngl_actions_for_routing and the memoized loader (renamed
_load_bngl_routing_actions; _load_bngl_actions_for_routing kept as a thin
list-only wrapper for its other callers) carry the parse message. The
unavailable-BNGsim case already returned ROUTE_ERROR and is untouched.
Adds tests covering the bngsim error, the auto one-time-warning fallback,
the subprocess no-inspect path, reason propagation through the cache, and
an end-to-end repro of the atoll-typo model from the issue.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
ActionList.define_parser's list-valued argument grammar was stricter than
BNG2.pl/Perl: arg_type_list matched elements with `pp.Word(pp.nums + ".")`
(digits and '.' only) inside a plain `pp.delimitedList`, so it rejected
- scientific notation, e.g. par_scan_vals=>[2.3e-10,5.1e-10]
- a trailing comma, e.g. par_scan_vals=>[1,2,3,]
Both are valid Perl that BNG2.pl parses and runs. When a model used either
(commonly par_scan_vals on parameter_scan), modelapi.bngmodel raised
BNGParseError, so under simulator='bngsim' the bridge couldn't inspect the
actions and silently fell back to the legacy subprocess (the #109 class) —
the model never ran on bngsim. Real models hit this: RuleHub's
Mitra2019/15-igf1r fits and Salazar-Cavazos2019 CHO_EGFR best-fit.
Broaden arg_type_list to use arg_type_expr (which already spans e/E and
+/-), allow an empty list, and tolerate one optional trailing comma:
arg_type_list = "[" + Optional(delimitedList(quote_word ^ arg_type_expr))
+ Optional(",") + "]"
Still rejects genuinely-malformed lists (double commas `[1,,2]`, unclosed
`[1,2,`). Adds parametrized accept/reject tests over the issue's matrix and
the affected real-model forms.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
…legacy
Follow-up to the #109 contract. classify_bngsim_route returned the
_classify_bngl_actions_for_bngsim result verbatim, so under an explicit
simulator='bngsim' request a BNGL with an action the router doesn't
recognize still silently ran on the legacy BNG2.pl stack (ROUTE_SUBPROCESS
was never promoted to ROUTE_ERROR). #109 only closed the parse-failure
(actions==None) hole; this closes the unrecognized-action hole.
BNGsim can run such a model via the BNG2.pl backend hook — the router just
can't confirm an unknown action is safe to delegate — so strict mode now
surfaces ROUTE_ERROR with the reason instead of degrading silently. PLA and
BNGsim-unsupported methods are genuine BNGsim incapabilities, so they stay
on the subprocess route in every mode (auto and bngsim alike); auto keeps
the legacy fallback for unrecognized actions too.
Threads `simulator` into _classify_bngl_actions_for_bngsim (default 'auto',
back-compatible) and promotes only the unrecognized-action branch. Adds
tests: bngsim unknown-action -> error, auto unknown-action -> subprocess,
and bngsim PLA / unsupported-method -> subprocess.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
method=>"rm" routes to BNGsim's RuleMonkey (via the rm->nf rewrite + backend
hook) only when RuleMonkey is installed. But the router marked rm supported
UNCONDITIONALLY — _method_supported_by_bngsim_for_routing never checked
RuleMonkey, unlike nf/NFsim — and classify_bngsim_route took no rulemonkey
arg. So an rm model on a BNGsim without RuleMonkey still classified as
ROUTE_BNGL_BNGSIM, then run_bngl_with_bngsim (which hardcodes
simulator="auto") silently fell back to legacy — invisibly even under
simulator='bngsim'. Same silent-downgrade class as #109.
Make the classifier RuleMonkey-aware (thread bngsim_has_rulemonkey through
classify_bngsim_route -> _classify_bngl_actions_for_bngsim ->
_method_supported_by_bngsim_for_routing) so the decision is made up front
where strict mode is enforced, not in the simulator-blind runner.
Treat nf-without-NFsim and rm-without-RuleMonkey uniformly as *build*
incapabilities (_BNGSIM_OPTIONAL_COMPONENT_METHODS): BNGsim could run them
with the component installed, so simulator='bngsim' errors (surfacing
"install NFsim/RuleMonkey") while auto falls back to legacy. This matches
the existing direct BNG-XML nf behavior (classify already errored there
under bngsim).
NOTE: this revises the BNGL nf-without-NFsim case shipped in the previous
commit (was subprocess in both modes) so nf and rm are consistent and the
strict-bngsim silent gap is closed for both. pla stays subprocess in both
modes (a categorical incapability, not a missing component); the cvode alias
keeps its legacy route. Updates tests accordingly and adds rm coverage.
akutuva21 pushed a commit that referenced this pull request Jul 20, 2026
Fix BNGsim bridge silent fallbacks: strict routing error (#109) + Perl-faithful list-arg grammar (#110)
Sign up for freeto 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.

1 participant

@akutuva21