Skip to content

Commit a649055

Browse files
committed
Account soft deletes in committed segments (#43126)
This change fixes the delete count issue in segment stats where we don't account soft-deleted documents from committed segments. Relates #43103
1 parent 78ff7c2 commit a649055

File tree

2 files changed

+66
-4
lines changed

2 files changed

+66
-4
lines changed

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -944,7 +944,7 @@ protected void writerSegmentStats(SegmentsStats stats) {
944944
/** How much heap is used that would be freed by a refresh. Note that this may throw {@link AlreadyClosedException}. */
945945
public abstract long getIndexBufferRAMBytesUsed();
946946

947-
protected Segment[] getSegmentInfo(SegmentInfos lastCommittedSegmentInfos, boolean verbose) {
947+
final Segment[] getSegmentInfo(SegmentInfos lastCommittedSegmentInfos, boolean verbose) {
948948
ensureOpen();
949949
Map<String, Segment> segments = new HashMap<>();
950950
// first, go over and compute the search ones...
@@ -972,8 +972,8 @@ protected Segment[] getSegmentInfo(SegmentInfos lastCommittedSegmentInfos, boole
972972
segment = new Segment(info.info.name);
973973
segment.search = false;
974974
segment.committed = true;
975-
segment.docCount = info.info.maxDoc();
976-
segment.delDocCount = info.getDelCount();
975+
segment.delDocCount = info.getDelCount() + info.getSoftDelCount();
976+
segment.docCount = info.info.maxDoc() - segment.delDocCount;
977977
segment.version = info.info.getVersion();
978978
segment.compound = info.info.getUseCompoundFile();
979979
try {

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

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ public void testVersionMapAfterAutoIDDocument() throws IOException {
264264
}
265265
}
266266

267-
public void testSegments() throws Exception {
267+
public void testSegmentsWithoutSoftDeletes() throws Exception {
268268
Settings settings = Settings.builder()
269269
.put(defaultSettings.getSettings())
270270
.put(IndexSettings.INDEX_SOFT_DELETES_SETTING.getKey(), false).build();
@@ -594,6 +594,68 @@ public void testSegmentsStatsIncludingFileSizes() throws Exception {
594594
}
595595
}
596596

597+
public void testSegmentsWithSoftDeletes() throws Exception {
598+
Settings.Builder settings = Settings.builder()
599+
.put(defaultSettings.getSettings())
600+
.put(IndexSettings.INDEX_SOFT_DELETES_SETTING.getKey(), true);
601+
final IndexMetaData indexMetaData = IndexMetaData.builder(defaultSettings.getIndexMetaData()).settings(settings).build();
602+
final IndexSettings indexSettings = IndexSettingsModule.newIndexSettings(indexMetaData);
603+
final AtomicLong globalCheckpoint = new AtomicLong(SequenceNumbers.NO_OPS_PERFORMED);
604+
try (Store store = createStore();
605+
InternalEngine engine = createEngine(config(indexSettings, store, createTempDir(), NoMergePolicy.INSTANCE, null,
606+
null, globalCheckpoint::get))) {
607+
assertThat(engine.segments(false), empty());
608+
int numDocsFirstSegment = randomIntBetween(5, 50);
609+
Set<String> liveDocsFirstSegment = new HashSet<>();
610+
for (int i = 0; i < numDocsFirstSegment; i++) {
611+
String id = Integer.toString(i);
612+
ParsedDocument doc = testParsedDocument(id, null, testDocument(), B_1, null);
613+
engine.index(indexForDoc(doc));
614+
liveDocsFirstSegment.add(id);
615+
}
616+
engine.refresh("test");
617+
List<Segment> segments = engine.segments(randomBoolean());
618+
assertThat(segments, hasSize(1));
619+
assertThat(segments.get(0).getNumDocs(), equalTo(liveDocsFirstSegment.size()));
620+
assertThat(segments.get(0).getDeletedDocs(), equalTo(0));
621+
assertFalse(segments.get(0).committed);
622+
int deletes = 0;
623+
int updates = 0;
624+
int appends = 0;
625+
int iterations = scaledRandomIntBetween(1, 50);
626+
for (int i = 0; i < iterations && liveDocsFirstSegment.isEmpty() == false; i++) {
627+
String idToUpdate = randomFrom(liveDocsFirstSegment);
628+
liveDocsFirstSegment.remove(idToUpdate);
629+
ParsedDocument doc = testParsedDocument(idToUpdate, null, testDocument(), B_1, null);
630+
if (randomBoolean()) {
631+
engine.delete(new Engine.Delete(doc.type(), doc.id(), newUid(doc), primaryTerm.get()));
632+
deletes++;
633+
} else {
634+
engine.index(indexForDoc(doc));
635+
updates++;
636+
}
637+
if (randomBoolean()) {
638+
engine.index(indexForDoc(testParsedDocument(UUIDs.randomBase64UUID(), null, testDocument(), B_1, null)));
639+
appends++;
640+
}
641+
}
642+
boolean committed = randomBoolean();
643+
if (committed) {
644+
engine.flush();
645+
}
646+
engine.refresh("test");
647+
segments = engine.segments(randomBoolean());
648+
assertThat(segments, hasSize(2));
649+
assertThat(segments.get(0).getNumDocs(), equalTo(liveDocsFirstSegment.size()));
650+
assertThat(segments.get(0).getDeletedDocs(), equalTo(updates + deletes));
651+
assertThat(segments.get(0).committed, equalTo(committed));
652+
653+
assertThat(segments.get(1).getNumDocs(), equalTo(updates + appends));
654+
assertThat(segments.get(1).getDeletedDocs(), equalTo(deletes)); // delete tombstones
655+
assertThat(segments.get(1).committed, equalTo(committed));
656+
}
657+
}
658+
597659
public void testCommitStats() throws IOException {
598660
final AtomicLong maxSeqNo = new AtomicLong(SequenceNumbers.NO_OPS_PERFORMED);
599661
final AtomicLong localCheckpoint = new AtomicLong(SequenceNumbers.NO_OPS_PERFORMED);

0 commit comments

Comments
 (0)