[ 
https://issues.apache.org/jira/browse/SOLR-18505?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Nick Shanin updated SOLR-18505:
-------------------------------
    Description: 
AI-generated, human-approved text below.

DirectUpdateHandlerTest fails intermittently in CI (seen on a Solr Tests via 
Crave run for an unrelated PR). With the run's seed, 71E7F210A62A9B8C, it fails 
deterministically in local forced re-runs: 6 of 6 across current main and the 
parent of the SOLR-18317 merge, so it predates those changes and is not caused 
by them.

Failure signature
 - testExpungeDeletes: AssertionError "maxDoc !> numDocs ... expected some 
deletions" at DirectUpdateHandlerTest.java:494 (one run showed the sibling 
variant "expected:<5> but was:<4>" at line 501).
 - testDeleteRollback: AssertionError in teardown (knock-on, see below).
 - classMethod: ObjectTracker reports unreleased objects (knock-on).

Root cause

testExpungeDeletes adds a duplicate document, creating one deletion. The test 
class
pins TieredMergePolicy, which schedules a natural merge when the index's deleted
documents exceed deletesPctAllowed (20 percent by default in Lucene 10.4) of 
its total
documents; the budget is index-wide, not per segment. In the end state the test
describes (two segments, five documents, one deletion) the allowed count is 1, 
so no
merge is selected there. The merge the failing runs show was admitted at a 
moment when
the index still held four documents with the deletion already counted, which is 
the
state when the seed's flush settings split the second batch into more than one
segment: there the allowed count is 0 and one deletion exceeds it. (That 
admission
point is inferred from the policy's arithmetic together with the merged segment 
below;
the failing runs did not record their flush settings.) The merge runs on the
ConcurrentMergeScheduler thread. If it lands before Solr opens the post-commit
searcher, the sample at line 494 reads the already-merged index and finds no 
deletions
left to observe, so the assertion fails even though nothing is wrong with the 
update
handler. In failing runs the surviving segment's diagnostics record 
source=merge and
there is no live-docs file, confirming the deletions were removed by the 
background
merge before the sample.

Knock-on failures

The failed assertion skips closing the sample request, the leaked request pins 
the core's directory, and the next test's deleteCore() then fails in 
CachingDirectoryFactory.close; that is the whole of the testDeleteRollback 
teardown failure and the ObjectTracker report. testDeleteRollback's own body 
does not fail.

Proposed fix


In testExpungeDeletes only: wrap the core's live merge policy for the duration 
of the
test in a FilterMergePolicy that returns null from findMerges and from
findFullFlushMerges (the entry point that commits and searcher opens consult), 
saving
the live policy beforehand and restoring it in a finally block, and delegating
findForcedDeletesMerges to the live policy so the expungeDeletes commit still 
performs
a real expunge. That removes natural merges from the test outright, so the test 
keeps
verifying what it verifies today. Also put the two sample requests in 
try-with-resources
so a failed assertion can never leak a searcher again. (NoMergePolicy is not a
substitute: its forced-deletes merge lookup returns null, which would turn the 
expunge
into a no-op and gut the test.)

This section originally proposed raising deletesPctAllowed to 100.0 instead. 
That value
is illegal (the setter accepts at most 50), and although the maximum of 50 
would also
have blocked the merge in this test, the wrapper was shipped because it does 
not rest
on the deletes-budget arithmetic at all. The fix is implemented in PR #5028.

  was:
AI-generated, human-approved text below.

DirectUpdateHandlerTest fails intermittently in CI (seen on a Solr Tests via 
Crave run for an unrelated PR). With the run's seed, 71E7F210A62A9B8C, it fails 
deterministically in local forced re-runs: 6 of 6 across current main and the 
parent of the SOLR-18317 merge, so it predates those changes and is not caused 
by them.

Failure signature

- testExpungeDeletes: AssertionError "maxDoc !> numDocs ... expected some 
deletions" at DirectUpdateHandlerTest.java:494 (one run showed the sibling 
variant "expected:<5> but was:<4>" at line 501).
- testDeleteRollback: AssertionError in teardown (knock-on, see below).
- classMethod: ObjectTracker reports unreleased objects (knock-on).

Root cause

testExpungeDeletes adds a duplicate document, leaving one segment 50 percent 
deleted. The test class pins TieredMergePolicy, and that policy treats any 
segment whose deleted percentage exceeds deletesPctAllowed (20 percent by 
default in Lucene 10.4) as eligible for a deletion-driven merge, even in a 
two-segment index where tier merging never fires. The merge runs on the 
ConcurrentMergeScheduler thread during the second commit. If it lands before 
Solr opens the post-commit searcher, the sample at line 494 reads the 
already-merged index and finds no deletions left to observe, so the assertion 
fails even though nothing is wrong with the update handler. In failing runs the 
surviving segment's diagnostics record source=merge and there is no live-docs 
file, confirming the deletions were expunged by the background merge before the 
sample.

The seed pins everything except merge-thread scheduling, which is why the 
failure is near-deterministic on a quiet machine with this seed but flips on 
loaded CI runners.

Knock-on failures

The failed assertion skips closing the sample request, the leaked request pins 
the core's directory, and the next test's deleteCore() then fails in 
CachingDirectoryFactory.close; that is the whole of the testDeleteRollback 
teardown failure and the ObjectTracker report. testDeleteRollback's own body 
does not fail.

Proposed fix

In testExpungeDeletes only: set deletesPctAllowed to 100.0 on the live writer's 
TieredMergePolicy for the duration of the test, saving and restoring the 
previous value in a finally block. That removes the deletion-merge trigger 
while forceMergeDeletes still performs a real expunge, so the test keeps 
verifying what it verifies today. Also put the two sample requests in 
try-with-resources so a failed assertion can never leak a searcher again. 
(NoMergePolicy is not a substitute: its forced-deletes merge lookup returns 
null, which would turn the expunge into a no-op and gut the test.)

A PR with this fix is prepared and will be linked here.


> DirectUpdateHandlerTest.testExpungeDeletes is flaky: a deletion-driven merge 
> races the post-commit searcher sample
> ------------------------------------------------------------------------------------------------------------------
>
>                 Key: SOLR-18505
>                 URL: https://issues.apache.org/jira/browse/SOLR-18505
>             Project: Solr
>          Issue Type: Bug
>            Reporter: Nick Shanin
>            Priority: Minor
>              Labels: pull-request-available
>          Time Spent: 10m
>  Remaining Estimate: 0h
>
> AI-generated, human-approved text below.
> DirectUpdateHandlerTest fails intermittently in CI (seen on a Solr Tests via 
> Crave run for an unrelated PR). With the run's seed, 71E7F210A62A9B8C, it 
> fails deterministically in local forced re-runs: 6 of 6 across current main 
> and the parent of the SOLR-18317 merge, so it predates those changes and is 
> not caused by them.
> Failure signature
>  - testExpungeDeletes: AssertionError "maxDoc !> numDocs ... expected some 
> deletions" at DirectUpdateHandlerTest.java:494 (one run showed the sibling 
> variant "expected:<5> but was:<4>" at line 501).
>  - testDeleteRollback: AssertionError in teardown (knock-on, see below).
>  - classMethod: ObjectTracker reports unreleased objects (knock-on).
> Root cause
> testExpungeDeletes adds a duplicate document, creating one deletion. The test 
> class
> pins TieredMergePolicy, which schedules a natural merge when the index's 
> deleted
> documents exceed deletesPctAllowed (20 percent by default in Lucene 10.4) of 
> its total
> documents; the budget is index-wide, not per segment. In the end state the 
> test
> describes (two segments, five documents, one deletion) the allowed count is 
> 1, so no
> merge is selected there. The merge the failing runs show was admitted at a 
> moment when
> the index still held four documents with the deletion already counted, which 
> is the
> state when the seed's flush settings split the second batch into more than one
> segment: there the allowed count is 0 and one deletion exceeds it. (That 
> admission
> point is inferred from the policy's arithmetic together with the merged 
> segment below;
> the failing runs did not record their flush settings.) The merge runs on the
> ConcurrentMergeScheduler thread. If it lands before Solr opens the post-commit
> searcher, the sample at line 494 reads the already-merged index and finds no 
> deletions
> left to observe, so the assertion fails even though nothing is wrong with the 
> update
> handler. In failing runs the surviving segment's diagnostics record 
> source=merge and
> there is no live-docs file, confirming the deletions were removed by the 
> background
> merge before the sample.
> Knock-on failures
> The failed assertion skips closing the sample request, the leaked request 
> pins the core's directory, and the next test's deleteCore() then fails in 
> CachingDirectoryFactory.close; that is the whole of the testDeleteRollback 
> teardown failure and the ObjectTracker report. testDeleteRollback's own body 
> does not fail.
> Proposed fix
> In testExpungeDeletes only: wrap the core's live merge policy for the 
> duration of the
> test in a FilterMergePolicy that returns null from findMerges and from
> findFullFlushMerges (the entry point that commits and searcher opens 
> consult), saving
> the live policy beforehand and restoring it in a finally block, and delegating
> findForcedDeletesMerges to the live policy so the expungeDeletes commit still 
> performs
> a real expunge. That removes natural merges from the test outright, so the 
> test keeps
> verifying what it verifies today. Also put the two sample requests in 
> try-with-resources
> so a failed assertion can never leak a searcher again. (NoMergePolicy is not a
> substitute: its forced-deletes merge lookup returns null, which would turn 
> the expunge
> into a no-op and gut the test.)
> This section originally proposed raising deletesPctAllowed to 100.0 instead. 
> That value
> is illegal (the setter accepts at most 50), and although the maximum of 50 
> would also
> have blocked the merge in this test, the wrapper was shipped because it does 
> not rest
> on the deletes-budget arithmetic at all. The fix is implemented in PR #5028.



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

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to