@@ -722,14 +722,13 @@ public void testTranslogRecoveryDoesNotReplayIntoTranslog() throws IOException {
722722 recoveringEngine = new InternalEngine (copy (initialEngine .config (), EngineConfig .OpenMode .OPEN_INDEX_AND_TRANSLOG )) {
723723 @ Override
724724 public CommitId flush (boolean force , boolean waitIfOngoing ) throws EngineException {
725- assertThat (getTranslog ().uncommittedOperations (), equalTo (docs ));
725+ assertThat (getTranslog ().stats (). getUncommittedOperations (), equalTo (docs ));
726726 final CommitId commitId = super .flush (force , waitIfOngoing );
727727 flushed .set (true );
728728 return commitId ;
729729 }
730730 };
731-
732- assertThat (recoveringEngine .getTranslog ().uncommittedOperations (), equalTo (docs ));
731+ assertThat (recoveringEngine .getTranslog ().stats ().getUncommittedOperations (), equalTo (docs ));
733732 recoveringEngine .recoverFromTranslog ();
734733 assertTrue (flushed .get ());
735734 } finally {
@@ -2883,7 +2882,7 @@ public void testCurrentTranslogIDisCommitted() throws IOException {
28832882 assertEquals (engine .getTranslog ().getTranslogUUID (), userData .get (Translog .TRANSLOG_UUID_KEY ));
28842883 expectThrows (IllegalStateException .class , () -> engine .recoverFromTranslog ());
28852884 assertEquals (2 , engine .getTranslog ().currentFileGeneration ());
2886- assertEquals (0L , engine .getTranslog ().uncommittedOperations ());
2885+ assertEquals (0L , engine .getTranslog ().stats (). getUncommittedOperations ());
28872886 }
28882887 }
28892888
@@ -3839,7 +3838,7 @@ protected long doGenerateSeqNoForOperation(Operation operation) {
38393838 System .nanoTime (),
38403839 reason ));
38413840 assertThat (noOpEngine .getLocalCheckpointTracker ().getCheckpoint (), equalTo ((long ) (maxSeqNo + 1 )));
3842- assertThat (noOpEngine .getTranslog ().uncommittedOperations (), equalTo (1 + gapsFilled ));
3841+ assertThat (noOpEngine .getTranslog ().stats (). getUncommittedOperations (), equalTo (1 + gapsFilled ));
38433842 // skip to the op that we added to the translog
38443843 Translog .Operation op ;
38453844 Translog .Operation last = null ;
@@ -4040,7 +4039,7 @@ public void testFillUpSequenceIdGapsOnRecovery() throws IOException {
40404039 assertEquals (checkpointOnReplica , replicaEngine .getLocalCheckpointTracker ().getCheckpoint ());
40414040 recoveringEngine = new InternalEngine (copy (
40424041 replicaEngine .config (), EngineConfig .OpenMode .OPEN_INDEX_AND_TRANSLOG , globalCheckpoint ::get ));
4043- assertEquals (numDocsOnReplica , recoveringEngine .getTranslog ().uncommittedOperations ());
4042+ assertEquals (numDocsOnReplica , recoveringEngine .getTranslog ().stats (). getUncommittedOperations ());
40444043 recoveringEngine .recoverFromTranslog ();
40454044 assertEquals (maxSeqIDOnReplica , recoveringEngine .getLocalCheckpointTracker ().getMaxSeqNo ());
40464045 assertEquals (checkpointOnReplica , recoveringEngine .getLocalCheckpointTracker ().getCheckpoint ());
@@ -4075,7 +4074,7 @@ public void testFillUpSequenceIdGapsOnRecovery() throws IOException {
40754074 recoveringEngine = new InternalEngine (
40764075 copy (replicaEngine .config (), EngineConfig .OpenMode .OPEN_INDEX_AND_TRANSLOG , globalCheckpoint ::get ));
40774076 if (flushed ) {
4078- assertEquals ( 0 , recoveringEngine .getTranslog ().uncommittedOperations ( ));
4077+ assertThat ( recoveringEngine .getTranslog ().stats (). getUncommittedOperations (), equalTo ( 0 ));
40794078 }
40804079 recoveringEngine .recoverFromTranslog ();
40814080 assertEquals (maxSeqIDOnReplica , recoveringEngine .getLocalCheckpointTracker ().getMaxSeqNo ());
@@ -4505,39 +4504,80 @@ public void testCleanupCommitsWhenReleaseSnapshot() throws Exception {
45054504 public void testShouldPeriodicallyFlush () throws Exception {
45064505 assertThat ("Empty engine does not need flushing" , engine .shouldPeriodicallyFlush (), equalTo (false ));
45074506 // A new engine may have more than one empty translog files - the test should account this extra.
4508- final long extraTranslogSizeInNewEngine = engine .getTranslog ().uncommittedSizeInBytes () - Translog .DEFAULT_HEADER_SIZE_IN_BYTES ;
4507+ final Translog translog = engine .getTranslog ();
4508+ final long extraTranslogSizeInNewEngine = engine .getTranslog ().stats ().getUncommittedSizeInBytes () - Translog .DEFAULT_HEADER_SIZE_IN_BYTES ;
45094509 int numDocs = between (10 , 100 );
45104510 for (int id = 0 ; id < numDocs ; id ++) {
45114511 final ParsedDocument doc = testParsedDocument (Integer .toString (id ), null , testDocumentWithTextField (), SOURCE , null );
45124512 engine .index (indexForDoc (doc ));
45134513 }
45144514 assertThat ("Not exceeded translog flush threshold yet" , engine .shouldPeriodicallyFlush (), equalTo (false ));
45154515 long flushThreshold = RandomNumbers .randomLongBetween (random (), 100 ,
4516- engine .getTranslog ().uncommittedSizeInBytes () - extraTranslogSizeInNewEngine );
4516+ engine .getTranslog ().stats (). getUncommittedSizeInBytes () - extraTranslogSizeInNewEngine );
45174517 final IndexSettings indexSettings = engine .config ().getIndexSettings ();
45184518 final IndexMetaData indexMetaData = IndexMetaData .builder (indexSettings .getIndexMetaData ())
45194519 .settings (Settings .builder ().put (indexSettings .getSettings ())
45204520 .put (IndexSettings .INDEX_TRANSLOG_FLUSH_THRESHOLD_SIZE_SETTING .getKey (), flushThreshold + "b" )).build ();
45214521 indexSettings .updateIndexMetaData (indexMetaData );
45224522 engine .onSettingsChanged ();
4523- assertThat (engine .getTranslog ().uncommittedOperations (), equalTo (numDocs ));
4523+ assertThat (engine .getTranslog ().stats (). getUncommittedOperations (), equalTo (numDocs ));
45244524 assertThat (engine .shouldPeriodicallyFlush (), equalTo (true ));
45254525 engine .flush ();
4526- assertThat (engine .getTranslog ().uncommittedOperations (), equalTo (0 ));
4526+ assertThat (engine .getTranslog ().stats (). getUncommittedOperations (), equalTo (0 ));
45274527 // Stale operations skipped by Lucene but added to translog - still able to flush
45284528 for (int id = 0 ; id < numDocs ; id ++) {
45294529 final ParsedDocument doc = testParsedDocument (Integer .toString (id ), null , testDocumentWithTextField (), SOURCE , null );
45304530 final Engine .IndexResult result = engine .index (replicaIndexForDoc (doc , 1L , id , false ));
45314531 assertThat (result .isCreated (), equalTo (false ));
45324532 }
45334533 SegmentInfos lastCommitInfo = engine .getLastCommittedSegmentInfos ();
4534- assertThat (engine .getTranslog ().uncommittedOperations (), equalTo (numDocs ));
4534+ assertThat (engine .getTranslog ().stats (). getUncommittedOperations (), equalTo (numDocs ));
45354535 assertThat (engine .shouldPeriodicallyFlush (), equalTo (true ));
45364536 engine .flush (false , false );
45374537 assertThat (engine .getLastCommittedSegmentInfos (), not (sameInstance (lastCommitInfo )));
4538- assertThat (engine .getTranslog ().uncommittedOperations (), equalTo (0 ));
4538+ assertThat (engine .getTranslog ().stats ().getUncommittedOperations (), equalTo (0 ));
4539+ // If the new index commit still points to the same translog generation as the current index commit,
4540+ // we should not enable the periodically flush condition; otherwise we can get into an infinite loop of flushes.
4541+ engine .getLocalCheckpointTracker ().generateSeqNo (); // create a gap here
4542+ for (int id = 0 ; id < numDocs ; id ++) {
4543+ if (randomBoolean ()) {
4544+ translog .rollGeneration ();
4545+ }
4546+ final ParsedDocument doc = testParsedDocument ("new" + id , null , testDocumentWithTextField (), SOURCE , null );
4547+ engine .index (replicaIndexForDoc (doc , 2L , engine .getLocalCheckpointTracker ().generateSeqNo (), false ));
4548+ if (engine .shouldPeriodicallyFlush ()) {
4549+ engine .flush ();
4550+ assertThat (engine .getLastCommittedSegmentInfos (), not (sameInstance (lastCommitInfo )));
4551+ assertThat (engine .shouldPeriodicallyFlush (), equalTo (false ));
4552+ }
4553+ }
45394554 }
45404555
4556+ public void testStressShouldPeriodicallyFlush () throws Exception {
4557+ final long flushThreshold = randomLongBetween (100 , 5000 );
4558+ final long generationThreshold = randomLongBetween (1000 , 5000 );
4559+ final IndexSettings indexSettings = engine .config ().getIndexSettings ();
4560+ final IndexMetaData indexMetaData = IndexMetaData .builder (indexSettings .getIndexMetaData ())
4561+ .settings (Settings .builder ().put (indexSettings .getSettings ())
4562+ .put (IndexSettings .INDEX_TRANSLOG_GENERATION_THRESHOLD_SIZE_SETTING .getKey (), generationThreshold + "b" )
4563+ .put (IndexSettings .INDEX_TRANSLOG_FLUSH_THRESHOLD_SIZE_SETTING .getKey (), flushThreshold + "b" )).build ();
4564+ indexSettings .updateIndexMetaData (indexMetaData );
4565+ engine .onSettingsChanged ();
4566+ final int numOps = scaledRandomIntBetween (100 , 10_000 );
4567+ for (int i = 0 ; i < numOps ; i ++) {
4568+ final long localCheckPoint = engine .getLocalCheckpointTracker ().getCheckpoint ();
4569+ final long seqno = randomLongBetween (Math .max (0 , localCheckPoint ), localCheckPoint + 5 );
4570+ final ParsedDocument doc = testParsedDocument (Long .toString (seqno ), null , testDocumentWithTextField (), SOURCE , null );
4571+ engine .index (replicaIndexForDoc (doc , 1L , seqno , false ));
4572+ if (rarely () && engine .getTranslog ().shouldRollGeneration ()) {
4573+ engine .rollTranslogGeneration ();
4574+ }
4575+ if (rarely () || engine .shouldPeriodicallyFlush ()) {
4576+ engine .flush ();
4577+ assertThat (engine .shouldPeriodicallyFlush (), equalTo (false ));
4578+ }
4579+ }
4580+ }
45414581
45424582 public void testStressUpdateSameDocWhileGettingIt () throws IOException , InterruptedException {
45434583 final int iters = randomIntBetween (1 , 15 );
0 commit comments