Skip to content

Keep the unclean-shutdown marker when the search index is replaced - #264

Open
mraible wants to merge 2 commits into
apache:masterfrom
mraible:keep-index-rebuild-marker
Open

mraible wants to merge 2 commits into
apache:masterfrom
mraible:keep-index-rebuild-marker

Conversation

@mraible

@mraible mraible commented Nov 14, 2026

Copy link
Copy Markdown
Contributor

LuceneIndexManager creates .index-inconsistent in the index directory at startup and deletes it in shutdown(). If the marker is there at the next start, the last run ended early and the index is rebuilt.

deleteIndex() removed every file in the index directory, the marker included. Startup replaces the index in four cases: the marker was found, the index is missing, it holds removed fields, or it can't be opened. In each of them the marker disappeared for the rest of the run. So if Roller was stopped or crashed during the background rebuild that follows, the next start found no marker, opened the partial index, and kept it until someone deleted the directory by hand.

deleteIndex() now skips the marker.

IndexConsistencyMarkerTest:

  • starts on an empty index directory (rebuild scheduled), then starts a second manager without a shutdown() and checks that it schedules a rebuild again. This fails on master.
  • checks that a clean shutdown removes the marker and the next start doesn't rebuild.

The other search tests still pass. #261 also changes LuceneIndexManager, in initialize()'s catch block rather than deleteIndex(), so the two shouldn't conflict.

LuceneIndexManager creates .index-inconsistent at startup and deletes it at a clean shutdown, so finding it at the next start means the index may be incomplete and is rebuilt. deleteIndex() removed every file in the index directory, the marker included. Each time startup replaced the index (marker found, missing index, removed fields, unreadable index) the marker was gone for the rest of the run, so if Roller was stopped during the background rebuild, the next start kept the partial index.

deleteIndex() now leaves the marker in place. IndexConsistencyMarkerTest starts on an empty index directory, then starts a second manager without a shutdown and checks that it rebuilds again; it also checks that a clean shutdown removes the marker and the next start does not rebuild. The first case fails on master.
@mraible
mraible requested a review from snoopdave November 14, 2026 21:16
@mraible

mraible commented Nov 15, 2026

Copy link
Copy Markdown
Contributor Author

I saw this happen on real data while rehearsing an upgrade and rollback on a copy of raibledesigns.com (3,553 entries, MySQL 8.4, Tomcat 11).

  • On master at f3d1207 after a normal start, the index directory held .index-inconsistent while Roller was running, as expected.
  • On master plus Require Java 21 and upgrade to Lucene 10.6.0 and Derby 10.17.1.0 #261, I killed the container so the next start would rebuild. After that rebuild the directory held only _0.cfe, _0.cfs, _0.si, segments_2 and write.lock. The marker was gone while Roller was still running.
  • Going back to master at f3d1207 (Lucene 9.12.3), Roller found the Lucene 10 index unreadable and rebuilt it. Again the marker was missing afterwards, with Roller running.

So in both rebuild cases a crash during or after the rebuild would have gone unnoticed at the next start, which is what this pull request describes. I haven't run this branch against the same data.

@mraible

mraible commented Nov 15, 2026

Copy link
Copy Markdown
Contributor Author

I've now run this branch against the same data, with plain master as a control. Each build went through the same sequence, and I looked in the index directory after each step.

Step master (f3d1207) master + this branch
Normal start marker present marker present
Container killed, restarted: index rebuilt marker gone while running marker present
Killed again after that rebuild no rebuild, index file untouched rebuilt again
Clean stop not checked marker removed
Start after a clean stop no rebuild no rebuild

So master reproduces the bug: after one rebuild, a second crash goes unnoticed. With this branch the marker survives the rebuild, the second crash is caught, and a clean shutdown still removes the marker so the next start doesn't rebuild.

Search returned the same counts throughout on both builds, and neither logged an error.

One limit: this index is small (3,553 entries, under 5 MB) and rebuilds in a few seconds, so my kills landed after the rebuild had finished, not during it. I didn't exercise a crash in the middle of a rebuild.

@snoopdave snoopdave left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

PR-Review: no issues. All four index-replacing paths now keep the marker, and the test fails on master. Minor: at startup (LuceneIndexManager.java:131-134) the marker isn't recreated, which is correct only because deleteIndex() now keeps it. A one-line comment there would make that dependency clear.

Startup relies on deleteIndex() keeping the consistency marker, so a rebuild interrupted again still starts over next time. Suggested in review.
@mraible

mraible commented Nov 15, 2026

Copy link
Copy Markdown
Contributor Author

794edc6 adds the comment at startup: deleteIndex() keeps the marker, so it stays in place until the rebuild that follows completes.

@mraible
mraible requested a review from snoopdave November 15, 2026 03:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants