Skip to content

Commit 084e06e

Browse files
authored
Require soft-deletes when access changes snapshot (#36446)
Today we do not enforce soft-deletes when accessing the Lucene changes snapshot. This might lead to internal errors because we assume soft-deletes are enabled in that code path.
1 parent 8b82170 commit 084e06e

File tree

4 files changed

+29
-5
lines changed

4 files changed

+29
-5
lines changed

server/src/main/java/org/elasticsearch/index/engine/Engine.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -722,7 +722,8 @@ public enum SearcherScope {
722722
public abstract Closeable acquireRetentionLockForPeerRecovery();
723723

724724
/**
725-
* Creates a new history snapshot from Lucene for reading operations whose seqno in the requesting seqno range (both inclusive)
725+
* Creates a new history snapshot from Lucene for reading operations whose seqno in the requesting seqno range (both inclusive).
726+
* This feature requires soft-deletes enabled. If soft-deletes are disabled, this method will throw an {@link IllegalStateException}.
726727
*/
727728
public abstract Translog.Snapshot newChangesSnapshot(String source, MapperService mapperService,
728729
long fromSeqNo, long toSeqNo, boolean requiredFullRange) throws IOException;

server/src/main/java/org/elasticsearch/index/engine/InternalEngine.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2481,7 +2481,9 @@ long getNumDocUpdates() {
24812481
@Override
24822482
public Translog.Snapshot newChangesSnapshot(String source, MapperService mapperService,
24832483
long fromSeqNo, long toSeqNo, boolean requiredFullRange) throws IOException {
2484-
// TODO: Should we defer the refresh until we really need it?
2484+
if (softDeleteEnabled == false) {
2485+
throw new IllegalStateException("accessing changes snapshot requires soft-deletes enabled");
2486+
}
24852487
ensureOpen();
24862488
refreshIfNeeded(source, toSeqNo);
24872489
Searcher searcher = acquireSearcher(source, SearcherScope.INTERNAL);

server/src/main/java/org/elasticsearch/index/engine/ReadOnlyEngine.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,9 @@ public Closeable acquireRetentionLockForPeerRecovery() {
243243
@Override
244244
public Translog.Snapshot newChangesSnapshot(String source, MapperService mapperService, long fromSeqNo, long toSeqNo,
245245
boolean requiredFullRange) throws IOException {
246+
if (engineConfig.getIndexSettings().isSoftDeleteEnabled() == false) {
247+
throw new IllegalStateException("accessing changes snapshot requires soft-deletes enabled");
248+
}
246249
return readHistoryOperations(source, mapperService, fromSeqNo);
247250
}
248251

server/src/test/java/org/elasticsearch/index/engine/InternalEngineTests.java

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3411,8 +3411,10 @@ public void testDoubleDeliveryReplica() throws IOException {
34113411
TopDocs topDocs = searcher.searcher().search(new MatchAllDocsQuery(), 10);
34123412
assertEquals(1, topDocs.totalHits.value);
34133413
}
3414-
List<Translog.Operation> ops = readAllOperationsInLucene(engine, createMapperService("test"));
3415-
assertThat(ops.stream().map(o -> o.seqNo()).collect(Collectors.toList()), hasItem(20L));
3414+
if (engine.engineConfig.getIndexSettings().isSoftDeleteEnabled()) {
3415+
List<Translog.Operation> ops = readAllOperationsInLucene(engine, createMapperService("test"));
3416+
assertThat(ops.stream().map(o -> o.seqNo()).collect(Collectors.toList()), hasItem(20L));
3417+
}
34163418
}
34173419

34183420
public void testRetryWithAutogeneratedIdWorksAndNoDuplicateDocs() throws IOException {
@@ -5292,8 +5294,11 @@ public void testLuceneSnapshotRefreshesOnlyOnce() throws Exception {
52925294
final MapperService mapperService = createMapperService("test");
52935295
final long maxSeqNo = randomLongBetween(10, 50);
52945296
final AtomicLong refreshCounter = new AtomicLong();
5297+
final IndexSettings indexSettings = IndexSettingsModule.newIndexSettings(
5298+
IndexMetaData.builder(defaultSettings.getIndexMetaData()).settings(Settings.builder().
5299+
put(defaultSettings.getSettings()).put(IndexSettings.INDEX_SOFT_DELETES_SETTING.getKey(), true)).build());
52955300
try (Store store = createStore();
5296-
InternalEngine engine = createEngine(config(defaultSettings, store, createTempDir(), newMergePolicy(),
5301+
InternalEngine engine = createEngine(config(indexSettings, store, createTempDir(), newMergePolicy(),
52975302
null,
52985303
new ReferenceManager.RefreshListener() {
52995304
@Override
@@ -5481,6 +5486,19 @@ public void testOpenSoftDeletesIndexWithSoftDeletesDisabled() throws Exception {
54815486
}
54825487
}
54835488

5489+
public void testRequireSoftDeletesWhenAccessingChangesSnapshot() throws Exception {
5490+
try (Store store = createStore()) {
5491+
final IndexSettings indexSettings = IndexSettingsModule.newIndexSettings(
5492+
IndexMetaData.builder(defaultSettings.getIndexMetaData()).settings(Settings.builder().
5493+
put(defaultSettings.getSettings()).put(IndexSettings.INDEX_SOFT_DELETES_SETTING.getKey(), false)).build());
5494+
try (InternalEngine engine = createEngine(config(indexSettings, store, createTempDir(), newMergePolicy(), null))) {
5495+
IllegalStateException error = expectThrows(IllegalStateException.class,
5496+
() -> engine.newChangesSnapshot("test", createMapperService("test"), 0, randomNonNegativeLong(), randomBoolean()));
5497+
assertThat(error.getMessage(), equalTo("accessing changes snapshot requires soft-deletes enabled"));
5498+
}
5499+
}
5500+
}
5501+
54845502
static void trimUnsafeCommits(EngineConfig config) throws IOException {
54855503
final Store store = config.getStore();
54865504
final TranslogConfig translogConfig = config.getTranslogConfig();

0 commit comments

Comments
 (0)