shashank created CAMEL-25506:
--------------------------------

             Summary: camel-lucene - concurrent queries can get another query's 
hits, and queries fail after the route is restarted
                 Key: CAMEL-25506
                 URL: https://issues.apache.org/jira/browse/CAMEL-25506
             Project: Camel
          Issue Type: Bug
          Components: camel-lucene
            Reporter: shashank


{{LuceneQueryProducer}} creates one {{LuceneSearcher}} in {{doStart()}} and 
uses it for every exchange (Camel producers are shared by concurrent 
exchanges). {{LuceneSearcher}} keeps the state of a query in fields (main 
c578a42a776d): {{open()}} assigns {{indexReader}} and {{indexSearcher}} (lines 
47-51) and {{doSearch()}} assigns {{hits}} (line 94), which {{search()}} then 
iterates (line 71). So:

* two exchanges querying at the same time can get each other's results: one 
exchange assigns {{hits}} between the other's search and its loop over 
{{hits}}. In the test below, 27 to 48 of 20000 queries (8 threads, two terms) 
returned the hits of the other term on main;
* every query opens a new {{DirectoryReader}} and only the one in the field 
when the producer stops is closed; the others are left to the garbage collector;
* {{LuceneQueryProducer.doStop()}} calls {{LuceneSearcher.close()}}, which 
closes the endpoint's {{Analyzer}} (the configured bean or the endpoint's 
default). After the route is stopped and started again, every query fails with 
{{org.apache.lucene.store.AlreadyClosedException: this Analyzer is closed}} 
until the CamelContext is restarted; when the route had not run a query yet, 
the stop fails with a {{NullPointerException}} ({{indexReader}} is null), 
logged as a WARN by the shutdown strategy.

{{LuceneQueryProcessor}} has the same reader handling (a new searcher in a 
shared field per exchange, never closed).

h3. Reproduction

New {{LuceneQueryProducerLifecycleTest}} (an index of 20 "alpha" and 20 "beta" 
documents built in {{@BeforeEach}}, a route {{direct:query}} to 
{{lucene:queryIndex:query}}):
* {{queryWorksAfterRouteRestart}} (deterministic): on main {{a query after the 
route was restarted must succeed ==> expected: <null> but was: 
<org.apache.lucene.store.AlreadyClosedException: this Analyzer is closed>}}.
* {{concurrentQueriesGetTheirOwnHits}} (20000 queries on 8 threads, about 2 s; 
it cannot force the interleaving, it makes it very likely): on main {{each 
query must get the hits of its own query, but 39 of 20000 did not, e.g. [alpha: 
got hit 'beta document 0', ...]}}; it failed in all six runs on main (27 to 48 
wrong answers) and passed in every run with the fix.

h3. Proposed fix

Each exchange uses its own {{LuceneSearcher}} ({{open}}, {{search}}, {{close}} 
in a {{finally}}); the producer no longer keeps one, so {{doStart}}/{{doStop}} 
are gone. {{LuceneSearcher.close()}} closes only its reader (null-safe), not 
the analyzer, which belongs to the endpoint or the registry. 
{{LuceneQueryProcessor}} does the same (no dedicated test; 
{{LuceneQueryProcessorIT}} passes). Code that calls {{LuceneSearcher}} directly 
now has to close its analyzer itself. The {{Hits}} hold the stored values (and 
the {{Document}} when requested), so closing the reader after building them is 
safe; the existing ITs still pass. camel-lucene tests with the fix: 
{{LuceneQueryProducerLifecycleTest}} 2, {{LuceneIndexAndQueryProducerIT}} 4, 
{{LuceneQueryProcessorIT}} 2, 0 failures.

Found with a TLA+ model of the producer and searcher (one action per field 
read/write: open reader, create searcher, collect hits, iterate hits; route 
stop/start): "every answer holds the hits of its own query" is violated in 7 
steps with two threads, "no reader is left open after the stop" in 12 steps 
with one thread and two queries, and "no query runs on a closed analyzer" in 9 
steps (query, stop, start, query). With the fix all properties hold for 2 and 3 
threads and a restart. Then confirmed with the real component as above.

Affected: main, camel-4.22.x, camel-4.18.x, camel-4.14.x (same code, GitHub 
contents API; unchanged since 2.x).

Duplicate check (2026-10-09): JIRA component camel-lucene (8 issues, all 
upgrades or naming), text "LuceneSearcher" (4, upgrades), "this Analyzer is 
closed" (none); GitHub pull requests "camel-lucene": none about the producers.

_Filed with Claude Code on behalf of allthingssecurity._




--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to