Skip to content

Conversation

@ohadzeliger
Copy link
Contributor

The issue at hand is that when running multiple update operations in a single transaction, the partition's document counts and the PK-segment index may get into an inconsistent state. The root cause is that the first update in the transaction clears the doc from the Lucene index and the PK index. Since the changes are not flushed, the IndexWriter has them cached in the NRT cache. The second record update would then not find the record in the PK index (because the segment has changed but the IndexReader does not yet reflect that) and therefore the delete is skipped, including updating the partition count. Note that it does attempt a delete-by-query that actually removes the doc from the Lucene index, but since we can't know that, the partition is not updated.
The solution is to refresh the DirectoryReader when doing an update, so that any previously written changes are showing up. The refresh operation uses DirectoryReader.openIfChanged that is more efficient in resources than using a brand new open call.

Resolve #3704

@ohadzeliger ohadzeliger self-assigned this Nov 4, 2025
@ohadzeliger ohadzeliger added the bug fix Change that fixes a bug label Nov 4, 2025
@ohadzeliger ohadzeliger marked this pull request as ready for review November 7, 2025 20:06
# Conflicts:
#	fdb-record-layer-lucene/src/test/java/com/apple/foundationdb/record/lucene/LuceneIndexMaintenanceTest.java

/**
* Try to find the document for the given record in the segment index.
* This method would first try to find the document using teh existing reader. If it can't, it will refresh the reader
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
* This method would first try to find the document using teh existing reader. If it can't, it will refresh the reader
* This method would first try to find the document using the existing reader. If it can't, it will refresh the reader

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

* writer may cache the changes in NRT and the reader (created earlier) can't see them. Refreshing the reader from the
* writer can alleviate this. If the index can't find the document with the refresh reader, null is returned.
* Note that the refresh of the reader will do so at the {@link com.apple.foundationdb.record.lucene.directory.FDBDirectoryWrapper}
* and so has impact on the entire directory.
Copy link
Contributor

Choose a reason for hiding this comment

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

Please consider rewording.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

if (newReader != null) {
// previous reader instantiated but then writer changed
readersToClose.add(writerReader);
writerReader = LazyCloseable.supply(() -> newReader);
Copy link
Collaborator

Choose a reason for hiding this comment

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

What happens if this is touched concurrently?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added test to update the readers concurrently

ParameterizedTestUtils.booleans("isGrouped"),
Stream.of(0, 10),
Stream.of(0, 1, 4),
Stream.of(5365));
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should this use RandomizedTestUtils.randomizedSeeds to run extra seeds during nightly?

Copy link
Contributor Author

@ohadzeliger ohadzeliger Nov 18, 2025

Choose a reason for hiding this comment

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

Done

@ParameterizedTest
@MethodSource("multiUpdate")
void multipleUpdatesInTransaction(boolean isSynthetic, boolean isGrouped, int highWatermark, int updateCount, long seed) throws IOException {
final int documentCount = 15;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would it make sense to have this be random, perhaps between 11 and 19?
As it is you either have 15 documents in the partition, or 10 and 5. Putting some randomness in there might find some interesting edge cases.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

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

Labels

bug fix Change that fixes a bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Lucene partition record counts are inaccurate when a document is updated multiple times in the same transaction

3 participants