Skip to content

Commit b59deb5

Browse files
authored
Always set soft-deletes field of IndexWriterConfig (#36196)
Today we configure the soft-deletes field iff soft-deletes enabled. Although this choice was correct, it prevents an engine with soft-deletes disabled from opening a Lucene index with soft-deletes. Moreover, this change should not have any side-effect if a Lucene index does not have any soft-deletes. Relates #36141
1 parent 166d9a9 commit b59deb5

File tree

3 files changed

+88
-9
lines changed

3 files changed

+88
-9
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2108,8 +2108,9 @@ private IndexWriterConfig getIndexWriterConfig() {
21082108
// Give us the opportunity to upgrade old segments while performing
21092109
// background merges
21102110
MergePolicy mergePolicy = config().getMergePolicy();
2111+
// always configure soft-deletes field so an engine with soft-deletes disabled can open a Lucene index with soft-deletes.
2112+
iwc.setSoftDeletesField(Lucene.SOFT_DELETES_FIELD);
21112113
if (softDeleteEnabled) {
2112-
iwc.setSoftDeletesField(Lucene.SOFT_DELETES_FIELD);
21132114
mergePolicy = new RecoverySourcePruneMergePolicy(SourceFieldMapper.RECOVERY_SOURCE_NAME, softDeletesPolicy::getRetentionQuery,
21142115
new SoftDeletesRetentionMergePolicy(Lucene.SOFT_DELETES_FIELD, softDeletesPolicy::getRetentionQuery, mergePolicy));
21152116
}

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5454,6 +5454,34 @@ public void testRebuildLocalCheckpointTracker() throws Exception {
54545454
}
54555455
}
54565456

5457+
public void testOpenSoftDeletesIndexWithSoftDeletesDisabled() throws Exception {
5458+
try (Store store = createStore()) {
5459+
Path translogPath = createTempDir();
5460+
final AtomicLong globalCheckpoint = new AtomicLong(SequenceNumbers.NO_OPS_PERFORMED);
5461+
final IndexSettings softDeletesEnabled = IndexSettingsModule.newIndexSettings(
5462+
IndexMetaData.builder(defaultSettings.getIndexMetaData()).settings(Settings.builder().
5463+
put(defaultSettings.getSettings()).put(IndexSettings.INDEX_SOFT_DELETES_SETTING.getKey(), true)).build());
5464+
final List<DocIdSeqNoAndTerm> docs;
5465+
try (InternalEngine engine = createEngine(
5466+
config(softDeletesEnabled, store, translogPath, newMergePolicy(), null, null, globalCheckpoint::get))) {
5467+
List<Engine.Operation> ops = generateReplicaHistory(between(1, 100), randomBoolean());
5468+
applyOperations(engine, ops);
5469+
globalCheckpoint.set(randomLongBetween(globalCheckpoint.get(), engine.getLocalCheckpoint()));
5470+
engine.syncTranslog();
5471+
engine.flush();
5472+
docs = getDocIds(engine, true);
5473+
}
5474+
final IndexSettings softDeletesDisabled = IndexSettingsModule.newIndexSettings(
5475+
IndexMetaData.builder(defaultSettings.getIndexMetaData()).settings(Settings.builder()
5476+
.put(defaultSettings.getSettings()).put(IndexSettings.INDEX_SOFT_DELETES_SETTING.getKey(), false)).build());
5477+
EngineConfig config = config(softDeletesDisabled, store, translogPath, newMergePolicy(), null, null, globalCheckpoint::get);
5478+
trimUnsafeCommits(config);
5479+
try (InternalEngine engine = createEngine(config)) {
5480+
assertThat(getDocIds(engine, true), equalTo(docs));
5481+
}
5482+
}
5483+
}
5484+
54575485
static void trimUnsafeCommits(EngineConfig config) throws IOException {
54585486
final Store store = config.getStore();
54595487
final TranslogConfig translogConfig = config.getTranslogConfig();

test/framework/src/main/java/org/elasticsearch/index/engine/EngineTestCase.java

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import org.elasticsearch.cluster.routing.AllocationId;
5252
import org.elasticsearch.common.CheckedFunction;
5353
import org.elasticsearch.common.Nullable;
54+
import org.elasticsearch.common.Randomness;
5455
import org.elasticsearch.common.Strings;
5556
import org.elasticsearch.common.bytes.BytesArray;
5657
import org.elasticsearch.common.bytes.BytesReference;
@@ -704,6 +705,32 @@ public static List<Engine.Operation> generateSingleDocHistory(boolean forReplica
704705
return ops;
705706
}
706707

708+
public List<Engine.Operation> generateReplicaHistory(int numOps, boolean allowGapInSeqNo) {
709+
long seqNo = 0;
710+
List<Engine.Operation> operations = new ArrayList<>(numOps);
711+
for (int i = 0; i < numOps; i++) {
712+
String id = Integer.toString(between(1, 100));
713+
final ParsedDocument doc = EngineTestCase.createParsedDoc(id, null);
714+
if (randomBoolean()) {
715+
operations.add(new Engine.Index(EngineTestCase.newUid(doc), doc, seqNo, primaryTerm.get(),
716+
i, null, Engine.Operation.Origin.REPLICA, threadPool.relativeTimeInMillis(),
717+
-1, true));
718+
} else if (randomBoolean()) {
719+
operations.add(new Engine.Delete(doc.type(), doc.id(), EngineTestCase.newUid(doc), seqNo, primaryTerm.get(),
720+
i, null, Engine.Operation.Origin.REPLICA, threadPool.relativeTimeInMillis()));
721+
} else {
722+
operations.add(new Engine.NoOp(seqNo, primaryTerm.get(), Engine.Operation.Origin.REPLICA,
723+
threadPool.relativeTimeInMillis(), "test-" + i));
724+
}
725+
seqNo++;
726+
if (allowGapInSeqNo && rarely()) {
727+
seqNo++;
728+
}
729+
}
730+
Randomness.shuffle(operations);
731+
return operations;
732+
}
733+
707734
public static void assertOpsOnReplica(
708735
final List<Engine.Operation> ops,
709736
final InternalEngine replicaEngine,
@@ -788,14 +815,7 @@ public static void concurrentlyApplyOps(List<Engine.Operation> ops, InternalEngi
788815
int docOffset;
789816
while ((docOffset = offset.incrementAndGet()) < ops.size()) {
790817
try {
791-
final Engine.Operation op = ops.get(docOffset);
792-
if (op instanceof Engine.Index) {
793-
engine.index((Engine.Index) op);
794-
} else if (op instanceof Engine.Delete){
795-
engine.delete((Engine.Delete) op);
796-
} else {
797-
engine.noOp((Engine.NoOp) op);
798-
}
818+
applyOperation(engine, ops.get(docOffset));
799819
if ((docOffset + 1) % 4 == 0) {
800820
engine.refresh("test");
801821
}
@@ -814,6 +834,36 @@ public static void concurrentlyApplyOps(List<Engine.Operation> ops, InternalEngi
814834
}
815835
}
816836

837+
public static void applyOperations(Engine engine, List<Engine.Operation> operations) throws IOException {
838+
for (Engine.Operation operation : operations) {
839+
applyOperation(engine, operation);
840+
if (randomInt(100) < 10) {
841+
engine.refresh("test");
842+
}
843+
if (rarely()) {
844+
engine.flush();
845+
}
846+
}
847+
}
848+
849+
public static Engine.Result applyOperation(Engine engine, Engine.Operation operation) throws IOException {
850+
final Engine.Result result;
851+
switch (operation.operationType()) {
852+
case INDEX:
853+
result = engine.index((Engine.Index) operation);
854+
break;
855+
case DELETE:
856+
result = engine.delete((Engine.Delete) operation);
857+
break;
858+
case NO_OP:
859+
result = engine.noOp((Engine.NoOp) operation);
860+
break;
861+
default:
862+
throw new IllegalStateException("No operation defined for [" + operation + "]");
863+
}
864+
return result;
865+
}
866+
817867
/**
818868
* Gets a collection of tuples of docId, sequence number, and primary term of all live documents in the provided engine.
819869
*/

0 commit comments

Comments
 (0)