Skip to content

Commit 13b8cdd

Browse files
authored
RATIS-2186. Raft log should not purge index lower than the log start index (#1175)
1 parent 26c1f04 commit 13b8cdd

File tree

3 files changed

+44
-10
lines changed

3 files changed

+44
-10
lines changed

ratis-server/src/main/java/org/apache/ratis/server/raftlog/RaftLogBase.java

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -318,20 +318,28 @@ public final CompletableFuture<Long> truncate(long index) {
318318

319319
@Override
320320
public final CompletableFuture<Long> purge(long suggestedIndex) {
321+
final long adjustedIndex;
321322
if (purgePreservation > 0) {
322323
final long currentIndex = getNextIndex() - 1;
323-
suggestedIndex = Math.min(suggestedIndex, currentIndex - purgePreservation);
324+
adjustedIndex = Math.min(suggestedIndex, currentIndex - purgePreservation);
325+
} else {
326+
adjustedIndex = suggestedIndex;
324327
}
325328
final long lastPurge = purgeIndex.get();
326-
if (suggestedIndex - lastPurge < purgeGap) {
329+
if (adjustedIndex - lastPurge < purgeGap) {
330+
return CompletableFuture.completedFuture(lastPurge);
331+
}
332+
final long startIndex = getStartIndex();
333+
if (adjustedIndex < startIndex) {
334+
LOG.info("{}: purge({}) is skipped: adjustedIndex = {} < startIndex = {}, purgePreservation = {}",
335+
getName(), suggestedIndex, adjustedIndex, startIndex, purgePreservation);
327336
return CompletableFuture.completedFuture(lastPurge);
328337
}
329-
LOG.info("{}: purge {}", getName(), suggestedIndex);
330-
final long finalSuggestedIndex = suggestedIndex;
331-
return purgeImpl(suggestedIndex).whenComplete((purged, e) -> {
338+
LOG.info("{}: purge {}", getName(), adjustedIndex );
339+
return purgeImpl(adjustedIndex).whenComplete((purged, e) -> {
332340
updatePurgeIndex(purged);
333341
if (e != null) {
334-
LOG.warn(getName() + ": Failed to purge " + finalSuggestedIndex, e);
342+
LOG.warn(getName() + ": Failed to purge " + adjustedIndex, e);
335343
}
336344
});
337345
}

ratis-server/src/main/java/org/apache/ratis/server/raftlog/segmented/SegmentedRaftLogCache.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,10 @@ TruncationSegments truncate(long index, LogSegment openSegment, Runnable clearOp
358358
TruncationSegments purge(long index) {
359359
try (AutoCloseableLock writeLock = writeLock()) {
360360
int segmentIndex = binarySearch(index);
361+
if (segmentIndex == -1) {
362+
// nothing to purge
363+
return null;
364+
}
361365
List<LogSegment> list = new LinkedList<>();
362366

363367
if (segmentIndex == -segments.size() - 1) {

ratis-test/src/test/java/org/apache/ratis/server/raftlog/segmented/TestSegmentedRaftLog.java

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,7 @@ public void testPurgeOnOpenSegment() throws Exception {
566566
int segmentSize = 200;
567567
long beginIndexOfOpenSegment = segmentSize * (endTerm - startTerm - 1);
568568
long expectedIndex = segmentSize * (endTerm - startTerm - 1);
569+
long purgePreservation = 0L;
569570
purgeAndVerify(startTerm, endTerm, segmentSize, 1, beginIndexOfOpenSegment, expectedIndex);
570571
}
571572

@@ -602,15 +603,36 @@ public void testPurgeOnClosedSegmentsWithPurgeGap() throws Exception {
602603
purgeAndVerify(startTerm, endTerm, segmentSize, 1000, endIndexOfClosedSegment, expectedIndex);
603604
}
604605

606+
@Test
607+
public void testPurgeWithLargePurgePreservationAndSmallPurgeGap() throws Exception {
608+
int startTerm = 0;
609+
int endTerm = 5;
610+
int segmentSize = 200;
611+
long endIndex = segmentSize * (endTerm - startTerm) - 1;
612+
// start index is set so that the suggested index will not be negative, which will not trigger any purge
613+
long startIndex = 200;
614+
// purge preservation is larger than the total size of the log entries
615+
// which causes suggested index to be lower than the start index
616+
long purgePreservation = (segmentSize * (endTerm - startTerm )) + 100;
617+
// if the suggested index is lower than the start index due to the purge preservation, we should not purge anything
618+
purgeAndVerify(startTerm, endTerm, segmentSize, 1, endIndex, startIndex, startIndex, purgePreservation);
619+
}
620+
605621
private void purgeAndVerify(int startTerm, int endTerm, int segmentSize, int purgeGap, long purgeIndex,
606-
long expectedIndex) throws Exception {
607-
List<SegmentRange> ranges = prepareRanges(startTerm, endTerm, segmentSize, 0);
622+
long expectedIndex) throws Exception {
623+
purgeAndVerify(startTerm, endTerm, segmentSize, purgeGap, purgeIndex, expectedIndex, 0, 0);
624+
}
625+
626+
private void purgeAndVerify(int startTerm, int endTerm, int segmentSize, int purgeGap, long purgeIndex,
627+
long expectedIndex, long startIndex, long purgePreservation) throws Exception {
628+
List<SegmentRange> ranges = prepareRanges(startTerm, endTerm, segmentSize, startIndex);
608629
List<LogEntryProto> entries = prepareLogEntries(ranges, null);
609630

610631
final RaftProperties p = new RaftProperties();
611632
RaftServerConfigKeys.Log.setPurgeGap(p, purgeGap);
612-
try (SegmentedRaftLog raftLog = newSegmentedRaftLog(storage, p)) {
613-
raftLog.open(RaftLog.INVALID_LOG_INDEX, null);
633+
RaftServerConfigKeys.Log.setPurgePreservationLogNum(p, purgePreservation);
634+
try (SegmentedRaftLog raftLog = newSegmentedRaftLogWithSnapshotIndex(storage, p, () -> startIndex - 1)) {
635+
raftLog.open(startIndex - 1, null);
614636
entries.stream().map(raftLog::appendEntry).forEach(CompletableFuture::join);
615637
final CompletableFuture<Long> f = raftLog.purge(purgeIndex);
616638
final Long purged = f.get();

0 commit comments

Comments
 (0)