Skip to content

Conversation

tlrx
Copy link
Member

@tlrx tlrx commented Aug 5, 2025

This change introduces a new merge policy wrapper that checks if the merge has been aborted before accessing fields/docs to merge and before executing data integrity checks. The goal here is to address #107513 by aborting the merge earlier than the Lucene SegmentMerger would do.

Relates #107513
Relates ES-11749
Relates ES-11384

Relates elastic#107513
Relates ES-11749
Relates ES-11384
@tlrx tlrx requested a review from a team as a code owner August 5, 2025 14:30
@tlrx tlrx added >enhancement :Distributed Indexing/Engine Anything around managing Lucene and the Translog in an open shard. v9.2.0 labels Aug 5, 2025
@elasticsearchmachine elasticsearchmachine added the Team:Distributed Indexing Meta label for Distributed Indexing team label Aug 5, 2025
@elasticsearchmachine
Copy link
Collaborator

Pinging @elastic/es-distributed-indexing (Team:Distributed Indexing)

@elasticsearchmachine
Copy link
Collaborator

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

Copy link
Contributor

@henningandersen henningandersen left a comment

Choose a reason for hiding this comment

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

LGTM, just a few minor comments.


@Override
public void document(int docID, StoredFieldVisitor visitor) throws IOException {
if (visitedDocs % 100L == 0L) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if either modulo 128 or using a bit and would be slightly faster? Or just reseting the counter when checking.

);

assertBusy(() -> {
if (checkAbortedMerges) {
Copy link
Contributor

Choose a reason for hiding this comment

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

if/else can be removed.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'll keep them but I'll revert this:

 final boolean checkAbortedMerges = false;
        randomBoolean();

to

 final boolean checkAbortedMerges = randomBoolean();


void ensureNotAborted() throws MergeAbortedException;

void ensureNotAborted(CheckedRunnable<IOException> runnable, String method) throws IOException;
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this variant necessary?

Copy link
Contributor

Choose a reason for hiding this comment

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

I mean, it looks to me that the above void ensureNotAborted() throws MergeAbortedException; is sufficient.

Copy link
Contributor

@albertzaharovits albertzaharovits left a comment

Choose a reason for hiding this comment

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

The IT is a bit of a stretch, IMO. I'm not sure it really adds to coverage. A simple unit test is sufficient (assuming that throwing in those methods is OK from Lucene's POV).

Copy link
Contributor

@fcofdez fcofdez left a comment

Choose a reason for hiding this comment

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

LGTM. I left a question and some minor suggestions 👍

// Number of time a field has been accessed during merges
private final AtomicLong mergedFieldsCount = new AtomicLong(0L);

// Number of time a doc has been accessed during merges
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: // Number of times

internalCluster().startMasterOnlyNode();
var nodeA = internalCluster().startDataOnlyNode();

var pluginA = internalCluster().getInstance(PluginsService.class, nodeA)
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: maybe we can name this nodeAMergePolicy instead?

ensureGreen(indexName);

var indexServiceB = internalCluster().getInstance(IndicesService.class, nodeB).indexService(resolveIndex(indexName));
assertBusy(() -> assertThat(indexServiceB.hasShard(0), equalTo(true)));
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: isn't this implicitly asserted by ensureGreen? it waits for relocations to complete, but maybe it's good to have the explicit assertion.

// Only the first integrity check is completed, the following ones should have been aborted
assertThat(pluginA.checkIntegrityCount.get(), equalTo(1L));
} else {
assertThat(pluginA.mergedDocsCount.get(), greaterThan(0L));
Copy link
Contributor

Choose a reason for hiding this comment

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

Just for my understanding, Lucene would check the aborted flag likely at the beginning of the merge and that's why we see the same numbers here? wouldn't it make sense to let the merge make some progress so we actually see/check the effects of this PR code?

@tlrx
Copy link
Member Author

tlrx commented Aug 12, 2025

Thanks for the feedback everyone.

I'd like to adjust the PR and improve test before merging, mostly:

  • move to a node setting
  • also wrap KnnVectorsReader (for large HSNW graphs merges)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

:Distributed Indexing/Engine Anything around managing Lucene and the Translog in an open shard. >enhancement Team:Distributed Indexing Meta label for Distributed Indexing team v9.3.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants