Skip to content

Commit 768753c

Browse files
committed
Add lower bound for translog flush threshold (#28382)
If the translog flush threshold is too small (eg. smaller than the translog header), we may repeatedly flush even there is no uncommitted operation because the shouldFlush condition can still be true after flushing. This is currently avoided by adding an extra guard against the uncommitted operations. However, this extra guard makes the shouldFlush complicated. This commit replaces that extra guard by a lower bound for translog flush threshold. We keep the lower bound small for convenience in testing. Relates #28350 Relates #23606
1 parent b5f3ce2 commit 768753c

File tree

4 files changed

+20
-14
lines changed

4 files changed

+20
-14
lines changed

server/src/main/java/org/elasticsearch/index/IndexSettings.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,15 @@ public final class IndexSettings {
186186
Setting.timeSetting("index.refresh_interval", DEFAULT_REFRESH_INTERVAL, new TimeValue(-1, TimeUnit.MILLISECONDS),
187187
Property.Dynamic, Property.IndexScope);
188188
public static final Setting<ByteSizeValue> INDEX_TRANSLOG_FLUSH_THRESHOLD_SIZE_SETTING =
189-
Setting.byteSizeSetting("index.translog.flush_threshold_size", new ByteSizeValue(512, ByteSizeUnit.MB), Property.Dynamic,
190-
Property.IndexScope);
189+
Setting.byteSizeSetting("index.translog.flush_threshold_size", new ByteSizeValue(512, ByteSizeUnit.MB),
190+
/*
191+
* An empty translog occupies 43 bytes on disk. If the flush threshold is below this, the flush thread
192+
* can get stuck in an infinite loop as the shouldPeriodicallyFlush can still be true after flushing.
193+
* However, small thresholds are useful for testing so we do not add a large lower bound here.
194+
*/
195+
new ByteSizeValue(Translog.DEFAULT_HEADER_SIZE_IN_BYTES + 1, ByteSizeUnit.BYTES),
196+
new ByteSizeValue(Long.MAX_VALUE, ByteSizeUnit.BYTES),
197+
Property.Dynamic, Property.IndexScope);
191198

192199
/**
193200
* Controls how long translog files that are no longer needed for persistence reasons
@@ -222,9 +229,9 @@ public final class IndexSettings {
222229
* generation threshold. However, small thresholds are useful for testing so we
223230
* do not add a large lower bound here.
224231
*/
225-
new ByteSizeValue(64, ByteSizeUnit.BYTES),
232+
new ByteSizeValue(Translog.DEFAULT_HEADER_SIZE_IN_BYTES + 1, ByteSizeUnit.BYTES),
226233
new ByteSizeValue(Long.MAX_VALUE, ByteSizeUnit.BYTES),
227-
new Property[]{Property.Dynamic, Property.IndexScope});
234+
Property.Dynamic, Property.IndexScope);
228235

229236
/**
230237
* Index setting to enable / disable deletes garbage collection.

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

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,21 +1526,16 @@ public boolean shouldPeriodicallyFlush() {
15261526
if (uncommittedSizeOfCurrentCommit < flushThreshold) {
15271527
return false;
15281528
}
1529+
assert translog.uncommittedOperations() > 0 : "translog required to flush periodically but not contain any uncommitted operation; "
1530+
+ "uncommitted translog size [" + uncommittedSizeOfCurrentCommit + "], flush threshold [" + flushThreshold + "]";
15291531
/*
15301532
* We should only flush ony if the shouldFlush condition can become false after flushing.
15311533
* This condition will change if the `uncommittedSize` of the new commit is smaller than
15321534
* the `uncommittedSize` of the current commit. This method is to maintain translog only,
15331535
* thus the IndexWriter#hasUncommittedChanges condition is not considered.
15341536
*/
15351537
final long uncommittedSizeOfNewCommit = translog.sizeOfGensAboveSeqNoInBytes(localCheckpointTracker.getCheckpoint() + 1);
1536-
/*
1537-
* If flushThreshold is too small, we may repeatedly flush even there is no uncommitted operation
1538-
* as #sizeOfGensAboveSeqNoInByte and #uncommittedSizeInBytes can return different values.
1539-
* An empty translog file has non-zero `uncommittedSize` (the translog header), and method #sizeOfGensAboveSeqNoInBytes can
1540-
* return 0 now(no translog gen contains ops above local checkpoint) but method #uncommittedSizeInBytes will return an actual
1541-
* non-zero value after rolling a new translog generation. This can be avoided by checking the actual uncommitted operations.
1542-
*/
1543-
return uncommittedSizeOfNewCommit < uncommittedSizeOfCurrentCommit && translog.uncommittedOperations() > 0;
1538+
return uncommittedSizeOfNewCommit < uncommittedSizeOfCurrentCommit;
15441539
}
15451540

15461541
@Override

server/src/main/java/org/elasticsearch/index/translog/Translog.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ public class Translog extends AbstractIndexShardComponent implements IndexShardC
108108
public static final String CHECKPOINT_FILE_NAME = "translog" + CHECKPOINT_SUFFIX;
109109

110110
static final Pattern PARSE_STRICT_ID_PATTERN = Pattern.compile("^" + TRANSLOG_FILE_PREFIX + "(\\d+)(\\.tlog)$");
111+
public static final int DEFAULT_HEADER_SIZE_IN_BYTES = TranslogWriter.getHeaderLength(UUIDs.randomBase64UUID());
111112

112113
// the list of translog readers is guaranteed to be in order of translog generation
113114
private final List<TranslogReader> readers = new ArrayList<>();
@@ -451,7 +452,10 @@ public long sizeOfGensAboveSeqNoInBytes(long minSeqNo) {
451452
* @throws IOException if creating the translog failed
452453
*/
453454
TranslogWriter createWriter(long fileGeneration) throws IOException {
454-
return createWriter(fileGeneration, getMinFileGeneration(), globalCheckpointSupplier.getAsLong());
455+
final TranslogWriter writer = createWriter(fileGeneration, getMinFileGeneration(), globalCheckpointSupplier.getAsLong());
456+
assert writer.sizeInBytes() == DEFAULT_HEADER_SIZE_IN_BYTES : "Mismatch translog header size; " +
457+
"empty translog size [" + writer.sizeInBytes() + ", header size [" + DEFAULT_HEADER_SIZE_IN_BYTES + "]";
458+
return writer;
455459
}
456460

457461
/**

server/src/test/java/org/elasticsearch/index/shard/IndexShardIT.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ public void testMaybeFlush() throws Exception {
367367
});
368368
assertEquals(0, translog.uncommittedOperations());
369369
translog.sync();
370-
long size = translog.uncommittedSizeInBytes();
370+
long size = Math.max(translog.uncommittedSizeInBytes(), Translog.DEFAULT_HEADER_SIZE_IN_BYTES + 1);
371371
logger.info("--> current translog size: [{}] num_ops [{}] generation [{}]", translog.uncommittedSizeInBytes(),
372372
translog.uncommittedOperations(), translog.getGeneration());
373373
client().admin().indices().prepareUpdateSettings("test").setSettings(Settings.builder().put(

0 commit comments

Comments
 (0)