Skip to content

Lucene TermsEnum and PostingsEnum may only be used from acquiring thread - #149297

Merged
cimequinox merged 10 commits into
elastic:mainfrom
cimequinox:esql_lucene_bulk_keyword_thread_restriction
May 19, 2026
Merged

cimequinox merged 10 commits into
elastic:mainfrom
cimequinox:esql_lucene_bulk_keyword_thread_restriction

Conversation

@cimequinox

@cimequinox cimequinox commented May 18, 2026 •

Copy link
Copy Markdown
Contributor

Lucene TermsEnum may only consumed on the same thread that acquired it.
Discovered during CI test of #148937

2> java.lang.AssertionError:
   Terms enums are only supposed to be consumed in the thread in which they have been acquired.
   But was acquired in Thread[#134,elasticsearch[node_s1][search][T#2],5,TGRP-LookupJoinTypesIT]
       and consumed in Thread[#130,elasticsearch[node_s1][search][T#1],5,TGRP-LookupJoinTypesIT].
2>  at __randomizedtesting.SeedInfo.seed([36CFD9379C525E62]:0)
2>  at org.apache.lucene.tests.index.AssertingLeafReader.assertThread(AssertingLeafReader.java:75)
2>  at org.apache.lucene.tests.index.AssertingLeafReader$AssertingTermsEnum.seekExact(AssertingLeafReader.java:408)
2>  at org.apache.lucene.index.FilterLeafReader$FilterTermsEnum.seekExact(FilterLeafReader.java:194)
2>  at org.elasticsearch.compute.operator.lookup.BulkKeywordLookup.processQuery(BulkKeywordLookup.java:78)

This change corrects the issue by reseting the cache when we detect the current thread differs from the acquiring thread following the example of BlockDocValuesReader.

@cimequinox cimequinox self-assigned this May 18, 2026
@cimequinox cimequinox added >bug auto-backport Automatically create backport pull requests when merged :Analytics/ES|QL AKA ESQL v9.5.0 v9.4.2 labels May 18, 2026
@elasticsearchmachine

Copy link
Copy Markdown
Collaborator

Hi @cimequinox, I've created a changelog YAML for you.

@github-actions

github-actions Bot commented May 18, 2026 •

Copy link
Copy Markdown
Contributor

🔍 Preview links for changed docs

⏳ Building and deploying preview... View progress

This comment will be updated with preview links when the build is complete.

@github-actions

Copy link
Copy Markdown
Contributor

ℹ️ Important: Docs version tagging

👋 Thanks for updating the docs! Just a friendly reminder that our docs are now cumulative. This means all 9.x versions are documented on the same page and published off of the main branch, instead of creating separate pages for each minor version.

We use applies_to tags to mark version-specific features and changes.

Expand for a quick overview

When to use applies_to tags:

✅ At the page level to indicate which products/deployments the content applies to (mandatory)
✅ When features change state (e.g. preview, ga) in a specific version
✅ When availability differs across deployments and environments

What NOT to do:

❌ Don't remove or replace information that applies to an older version
❌ Don't add new information that applies to a specific version without an applies_to tag
❌ Don't forget that applies_to tags can be used at the page, section, and inline level

🤔 Need help?

@cimequinox cimequinox added the test-release Trigger CI checks against release build label May 18, 2026
@cimequinox

Copy link
Copy Markdown
Contributor Author

v9.3.5#bwcTestPart3 build failure appears unrelated. See #149308

@cimequinox
cimequinox marked this pull request as ready for review May 18, 2026 14:31
@elasticsearchmachine elasticsearchmachine added the Team:Analytics Meta label for analytical engine team (ESQL/Aggs/Geo) label May 18, 2026
@elasticsearchmachine

Copy link
Copy Markdown
Collaborator

Pinging @elastic/es-analytical-engine (Team:Analytics)

@cimequinox
cimequinox requested a review from dnhatn May 18, 2026 14:31

@dnhatn dnhatn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One comment, but the fix looks good. Thanks Cim!

final int numLeaves = indexReader.leaves().size();
final Thread current = Thread.currentThread();
final int numLeaves = indexReader.leaves().size();
if (termsEnumCache == null || creationThread != current || termsEnumCache.length != numLeaves) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per an offline discussion with Cim, he will remove the check termsEnumCache.length != numLeaves.

@cimequinox cimequinox removed the test-release Trigger CI checks against release build label May 18, 2026
@cimequinox

cimequinox commented May 18, 2026 •

Copy link
Copy Markdown
Contributor Author

Seeing many approximation not supported in checkPart3 / release-tests similar to those reported in #149321

There are a few hundred VerificationException: line X:XX: approximation not supported failures across many tests. In some failures a different warning appears than is expected e.g.

Expected: "line 1:87: approximation not supported: query with [FUSE] cannot be approximated"
 but: was "line 1:42: approximation not supported: query with [FORK (WHERE true) (WHERE true)] cannot be approximated"

Since CI passes for this without test-release, the approximation tests may need fixes similar to other tests which had a similar problem e.g. #144086

@cimequinox
cimequinox merged commit 30f138d into elastic:main May 19, 2026
36 checks passed
@elasticsearchmachine

Copy link
Copy Markdown
Collaborator

💚 Backport successful

Status Branch Result
✅ 9.4

elasticsearchmachine pushed a commit that referenced this pull request May 19, 2026
…ead (#149297) (#149349)

Lucene TermsEnum may only consumed on the same thread that acquired it. 
This change corrects the issue in BulkKeywordLookup by reseting the cache 
when we detect the current thread differs from the acquiring thread following 
the example of BlockDocValuesReader.
cimequinox added a commit to cimequinox/elasticsearch that referenced this pull request May 25, 2026
…ches

In the non-streaming EnrichQuerySourceOperator, queryPosition is incremented
in a slightly different way in the lucene query path and the bulk lookup path.

There the ordinary path increments queryPosition before comparing to positionCount
but the bulk path increments after the comparison.  That's not great but it's not
a bug because in that getOutput() the path do not share any logic inspecting it.
There each path tests for termination in its own way.

But in the LookupQueryOperator, getMatches() and getBulkMatches() share
the getOutput() termination condition so they must follow the same convention
and increment queryPosition before doing the comparison.  This way getOutput()
may always safely assume (queryPosition >= positionCount - 1) means we've
finished processing the page.

This change also removes the call to bulkKeywordLookup.initializeCaches(indexReader) which
is no longer necessary since elastic#149297
because we perform that check in each call to processQuery() for thread safety.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

:Analytics/ES|QL AKA ESQL auto-backport Automatically create backport pull requests when merged >bug Team:Analytics Meta label for analytical engine team (ESQL/Aggs/Geo) v9.4.2 v9.5.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants