Skip to content

Unify exist-core-jmh and exist-indexes-jmh maven wiring; fix broken Lucene/conf.xml benchmarks - #6646

Merged
line-o merged 6 commits into
eXist-db:developfrom
duncdrum:dp-jmh-conf-codegen
Aug 19, 2026
Merged

line-o merged 6 commits into
eXist-db:developfrom
duncdrum:dp-jmh-conf-codegen

Conversation

@duncdrum

@duncdrum duncdrum commented Aug 18, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Follow-up to my review comment on #6608: unifies the Maven wiring between exist-core-jmh (java -jar) and exist-indexes-jmh (mvn exec:exec), now that #6531's conf.xml codegen mechanism has merged and unblocks it.

Investigating why ci-benchmarks.yml's last run produced a 4.3 GB log and hit its timeout also turned up two real bugs:

(PR #6645, separate, fixes an unrelated log-bloat bug found in the same investigation.)

What changed

  • Both modules now generate conf.xml from canonical via the standard schema/generate-conf-fixture.xsl codegen, instead of reaching into another module's fixtures.
  • Removed the ensureExistHome() workarounds; fixed a LucenePhraseQueryBenchmark correctness bug the NPE had been masking (matchEvery=1 modulo formula).
  • exist-core-jmh now runs via mvn exec:exec, matching exist-indexes-jmh.
  • CI timeout bumped 90 → 180 min: benchmarks that previously failed instantly now run to full duration.
  • Removed a stale "shaded jar breaks log4j2" javadoc caveat from AxisBenchmark/ArrowOperatorBenchmark — verified stale by a real prior CI run plus local testing.
  • Both READMEs updated to match.

Test plan

  • Both modules build clean with -Pperf-tests
  • Generated conf.xml registers lucene/ngram/range indexes and ships in both shaded jars
  • All benchmark classes across both modules run clean via mvn exec:exec

🤖 Generated with Claude Code

@duncdrum
duncdrum requested a review from a team as a code owner August 18, 2026 08:32
duncdrum and others added 5 commits August 18, 2026 11:06
…chmarks

exist-core-jmh's conf.xml was a hand-maintained "verbatim copy of
exist-core/src/test/resources-filtered/conf.xml" with no Lucene
module/index registered. LucenePhraseQueryBenchmark and
UtilExpandHighlightingBenchmark worked around this at runtime with an
ensureExistHome() that tried to borrow
extensions/indexes/lucene/src/test/resources-filtered/conf.xml —
except that path is never a real file, it's the *input* to that
module's own Maven-time XSLT codegen (conf-fixture.xsl ->
target/generated-test-resources/conf.xml), only materialized when the
lucene extension module itself is built. Since ci-benchmarks.yml only
builds `-pl exist-core-jmh -am`, that directory never exists, so both
benchmarks silently fell back to exist-core-jmh's Lucene-less conf.xml
-> NullPointerException ("index" is null) in one, undefined `ft:`
prefix (XPST0081) in the other, on every single iteration.

Give exist-core-jmh its own generated conf.xml instead, using the same
schema/generate-conf-fixture.xsl mechanism the lucene extension (and
~35 other test fixtures) already use, with keep-indexes=lucene-index
and keep-modules including the lucene module (see the new
src/main/resources-filtered/conf-fixture.xsl). Since this module's
benchmarks are main-scope (packaged into the shaded benchmarks jar,
not test-scoped), the codegen runs via its own xml-maven-plugin
execution bound to generate-resources rather than the standard
auto-activating test-resources profile — same opt-out pattern
extensions/modules/expathrepo already uses for its own non-standard
output directory.

This also surfaced a pre-existing, previously-unreachable correctness
bug in LucenePhraseQueryBenchmark: `matches = (i % matchEvery) == 1`
is always false when matchEvery=1 (i % 1 is always 0), so the
"all docs match" parameterization never actually matched any document
by the intended construction - it happened to "pass" only because
doc #1's non-matching placeholder text ("datum" + 1) coincidentally
spelled the literal search phrase. Fixed to
`((i - 1) % matchEvery) == 0`.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
exist-core-jmh ran its benchmarks via a bare `java -jar`, while
exist-indexes-jmh wraps the same invocation in `mvn exec:exec`. The
module also carried a vestigial uberjar.name=benchmarks property that
nothing referenced (maven-shade-plugin's finalName duplicated the
same expression separately, hardcoded).

uberjar.name is now a real property, shared between the shade
plugin's finalName and the new exec-maven-plugin execution - same
pattern exist-indexes-jmh already uses. Adds a benchmark.args property
(default: ArrowOperatorBenchmark -prof gc) overridable via
-Dbenchmark.args, matching exist-indexes-jmh's convention.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
exist-indexes-jmh generated its conf.xml by transforming
extensions/indexes/indexes-integration-tests/src/test/resources-filtered/conf.xml
via its own src/main/xslt/conf-jmh.xslt. That source file was never a
real static file, only the *input* to indexes-integration-tests' own
Maven-time fixture codegen - and once that module switched to the
canonical-fixture mechanism (PR eXist-db#6531), its resources-filtered
directory holds only a conf-fixture.xsl, no static conf.xml.

Result: xml-maven-plugin's transform matched zero input files
("[WARNING] No files found for transformation"), succeeded anyway
(empty transformation sets aren't a build failure), and produced no
conf.xml at all - the shaded benchmarks jar shipped with none.  Every
benchmark method across all 5 classes failed instantly on setUp():
`DatabaseConfigurationException: Unable to read configuration file at
.../exist-indexes-jmh/etc/conf.xml`. No CI run had exercised this
module's benchmarks since eXist-db#6531 merged (the ci-benchmarks.yml run
that would have hit it was independently cancelled by the 90-minute
job timeout during exist-core-jmh's step first).

Fixed by sourcing directly from canonical
(exist-distribution/src/main/config/conf.xml) via a new
src/main/resources-filtered/conf-fixture.xsl, using the same
schema/generate-conf-fixture.xsl mechanism as ~35 other fixtures in
the repo (and the one exist-core-jmh now also uses), instead of
depending on another module's private fixture input a second time.
Removes the now-obsolete conf-jmh.xslt.

Verified all 5 benchmark classes (Ngram/RangeEq/RangeFieldEq/Lucene/
GeneralComparisonWhereClauseBenchmark) run clean via `mvn exec:exec`.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ification

- exist-core-jmh/README.md now documents `mvn exec:exec` as the
  primary invocation (matching exist-indexes-jmh), with `java -jar`
  kept as a secondary option; notes conf.xml is now generated from
  canonical.
- exist-indexes-jmh/README.md's layout section and conf.xml paragraph
  updated for the new canonical-sourced fixture (replacing the removed
  conf-jmh.xslt / indexes-integration-tests dependency).
- ci-benchmarks.yml: exist-core-jmh's run step switches to exec:exec
  (matching exist-indexes-jmh); job timeout bumped 90 -> 180 minutes,
  since benchmarks that previously failed instantly (the bugs fixed in
  prior commits) now run to their full configured duration - this is
  a report-only weekly/manual job that blocks no PR, so a longer
  timeout only costs CI minutes on a schedule.
- Removed a stale "shaded benchmark jar trips a log4j2 caller-class
  assertion when booting a BrokerPool" javadoc caveat from
  AxisBenchmark and ArrowOperatorBenchmark, along with the unshaded
  classpath workaround recipe it prescribed. Verified stale two ways:
  a real prior CI run completed AxisBenchmark successfully via the
  shaded `java -jar` invocation, and all 4 ArrowOperatorBenchmark
  methods ran clean locally via the shaded jar with no errors.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…es not need conf.xml

It uses raw Lucene IndexWriter/IndexSearcher APIs directly, never
boots a BrokerPool or reads conf.xml, so it doesn't benefit from
lucene-index registration the way LucenePhraseQueryBenchmark and
UtilExpandHighlightingBenchmark do.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@duncdrum
duncdrum force-pushed the dp-jmh-conf-codegen branch from 0d4072f to a68d4d6 Compare August 18, 2026 09:07
…est allowlist

Its hand-maintained conf.xml (missing schemaVersion) was deleted and
replaced by one generated from canonical, which carries schemaVersion
like every other canonical-derived fixture. The audit test's
hardcoded REMAINING_WITHOUT_VERSION set needs to track that.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@dizzzz
dizzzz requested review from a team, joewiz, line-o and reinhapa August 18, 2026 18:22
@line-o
line-o merged commit 8523b12 into eXist-db:develop Aug 19, 2026
9 checks passed
@duncdrum
duncdrum deleted the dp-jmh-conf-codegen branch August 19, 2026 10:25
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.

4 participants