@@ -494,6 +494,212 @@ public void testSegments() throws Exception {
494
494
}
495
495
}
496
496
497
+ public void testMergeSegmentsOnCommitIsDisabled () throws Exception {
498
+ final AtomicLong globalCheckpoint = new AtomicLong (SequenceNumbers .NO_OPS_PERFORMED );
499
+
500
+ final Settings .Builder settings = Settings .builder ()
501
+ .put (defaultSettings .getSettings ())
502
+ .put (IndexSettings .INDEX_MERGE_ON_FLUSH_MAX_FULL_FLUSH_MERGE_WAIT_TIME .getKey (), TimeValue .timeValueMillis (0 ))
503
+ .put (IndexSettings .INDEX_MERGE_ON_FLUSH_ENABLED .getKey (), true );
504
+ final IndexMetadata indexMetadata = IndexMetadata .builder (defaultSettings .getIndexMetadata ()).settings (settings ).build ();
505
+ final IndexSettings indexSettings = IndexSettingsModule .newIndexSettings (indexMetadata );
506
+
507
+ try (
508
+ Store store = createStore ();
509
+ InternalEngine engine = createEngine (
510
+ config (indexSettings , store , createTempDir (), NoMergePolicy .INSTANCE , null , null , globalCheckpoint ::get )
511
+ )
512
+ ) {
513
+ assertThat (engine .segments (false ), empty ());
514
+ int numDocsFirstSegment = randomIntBetween (5 , 50 );
515
+ Set <String > liveDocsFirstSegment = new HashSet <>();
516
+ for (int i = 0 ; i < numDocsFirstSegment ; i ++) {
517
+ String id = Integer .toString (i );
518
+ ParsedDocument doc = testParsedDocument (id , null , testDocument (), B_1 , null );
519
+ engine .index (indexForDoc (doc ));
520
+ liveDocsFirstSegment .add (id );
521
+ }
522
+ engine .refresh ("test" );
523
+ List <Segment > segments = engine .segments (randomBoolean ());
524
+ assertThat (segments , hasSize (1 ));
525
+ assertThat (segments .get (0 ).getNumDocs (), equalTo (liveDocsFirstSegment .size ()));
526
+ assertThat (segments .get (0 ).getDeletedDocs (), equalTo (0 ));
527
+ assertFalse (segments .get (0 ).committed );
528
+ int deletes = 0 ;
529
+ int updates = 0 ;
530
+ int appends = 0 ;
531
+ int iterations = scaledRandomIntBetween (1 , 50 );
532
+ for (int i = 0 ; i < iterations && liveDocsFirstSegment .isEmpty () == false ; i ++) {
533
+ String idToUpdate = randomFrom (liveDocsFirstSegment );
534
+ liveDocsFirstSegment .remove (idToUpdate );
535
+ ParsedDocument doc = testParsedDocument (idToUpdate , null , testDocument (), B_1 , null );
536
+ if (randomBoolean ()) {
537
+ engine .delete (new Engine .Delete (doc .id (), newUid (doc ), primaryTerm .get ()));
538
+ deletes ++;
539
+ } else {
540
+ engine .index (indexForDoc (doc ));
541
+ updates ++;
542
+ }
543
+ if (randomBoolean ()) {
544
+ engine .index (indexForDoc (testParsedDocument (UUIDs .randomBase64UUID (), null , testDocument (), B_1 , null )));
545
+ appends ++;
546
+ }
547
+ }
548
+
549
+ boolean committed = randomBoolean ();
550
+ if (committed ) {
551
+ engine .flush ();
552
+ }
553
+
554
+ engine .refresh ("test" );
555
+ segments = engine .segments (randomBoolean ());
556
+
557
+ assertThat (segments , hasSize (2 ));
558
+ assertThat (segments , hasSize (2 ));
559
+ assertThat (segments .get (0 ).getNumDocs (), equalTo (liveDocsFirstSegment .size ()));
560
+ assertThat (segments .get (0 ).getDeletedDocs (), equalTo (updates + deletes ));
561
+ assertThat (segments .get (0 ).committed , equalTo (committed ));
562
+
563
+ assertThat (segments .get (1 ).getNumDocs (), equalTo (updates + appends ));
564
+ assertThat (segments .get (1 ).getDeletedDocs (), equalTo (deletes )); // delete tombstones
565
+ assertThat (segments .get (1 ).committed , equalTo (committed ));
566
+ }
567
+ }
568
+
569
+ public void testMergeSegmentsOnCommit () throws Exception {
570
+ final AtomicLong globalCheckpoint = new AtomicLong (SequenceNumbers .NO_OPS_PERFORMED );
571
+
572
+ final Settings .Builder settings = Settings .builder ()
573
+ .put (defaultSettings .getSettings ())
574
+ .put (IndexSettings .INDEX_MERGE_ON_FLUSH_MAX_FULL_FLUSH_MERGE_WAIT_TIME .getKey (), TimeValue .timeValueMillis (5000 ))
575
+ .put (IndexSettings .INDEX_MERGE_ON_FLUSH_ENABLED .getKey (), true );
576
+ final IndexMetadata indexMetadata = IndexMetadata .builder (defaultSettings .getIndexMetadata ()).settings (settings ).build ();
577
+ final IndexSettings indexSettings = IndexSettingsModule .newIndexSettings (indexMetadata );
578
+
579
+ try (
580
+ Store store = createStore ();
581
+ InternalEngine engine = createEngine (
582
+ config (indexSettings , store , createTempDir (), NoMergePolicy .INSTANCE , null , null , globalCheckpoint ::get )
583
+ )
584
+ ) {
585
+ assertThat (engine .segments (false ), empty ());
586
+ int numDocsFirstSegment = randomIntBetween (5 , 50 );
587
+ Set <String > liveDocsFirstSegment = new HashSet <>();
588
+ for (int i = 0 ; i < numDocsFirstSegment ; i ++) {
589
+ String id = Integer .toString (i );
590
+ ParsedDocument doc = testParsedDocument (id , null , testDocument (), B_1 , null );
591
+ engine .index (indexForDoc (doc ));
592
+ liveDocsFirstSegment .add (id );
593
+ }
594
+ engine .refresh ("test" );
595
+ List <Segment > segments = engine .segments (randomBoolean ());
596
+ assertThat (segments , hasSize (1 ));
597
+ assertThat (segments .get (0 ).getNumDocs (), equalTo (liveDocsFirstSegment .size ()));
598
+ assertThat (segments .get (0 ).getDeletedDocs (), equalTo (0 ));
599
+ assertFalse (segments .get (0 ).committed );
600
+ int deletes = 0 ;
601
+ int updates = 0 ;
602
+ int appends = 0 ;
603
+ int iterations = scaledRandomIntBetween (1 , 50 );
604
+ for (int i = 0 ; i < iterations && liveDocsFirstSegment .isEmpty () == false ; i ++) {
605
+ String idToUpdate = randomFrom (liveDocsFirstSegment );
606
+ liveDocsFirstSegment .remove (idToUpdate );
607
+ ParsedDocument doc = testParsedDocument (idToUpdate , null , testDocument (), B_1 , null );
608
+ if (randomBoolean ()) {
609
+ engine .delete (new Engine .Delete (doc .id (), newUid (doc ), primaryTerm .get ()));
610
+ deletes ++;
611
+ } else {
612
+ engine .index (indexForDoc (doc ));
613
+ updates ++;
614
+ }
615
+ if (randomBoolean ()) {
616
+ engine .index (indexForDoc (testParsedDocument (UUIDs .randomBase64UUID (), null , testDocument (), B_1 , null )));
617
+ appends ++;
618
+ }
619
+ }
620
+
621
+ boolean committed = randomBoolean ();
622
+ if (committed ) {
623
+ engine .flush ();
624
+ }
625
+
626
+ engine .refresh ("test" );
627
+ segments = engine .segments (randomBoolean ());
628
+
629
+ // All segments have to be merged into one
630
+ assertThat (segments , hasSize (1 ));
631
+ assertThat (segments .get (0 ).getNumDocs (), equalTo (numDocsFirstSegment + appends - deletes ));
632
+ assertThat (segments .get (0 ).getDeletedDocs (), equalTo (0 ));
633
+ assertThat (segments .get (0 ).committed , equalTo (committed ));
634
+ }
635
+ }
636
+
637
+ // this test writes documents to the engine while concurrently flushing/commit
638
+ public void testConcurrentMergeSegmentsOnCommit () throws Exception {
639
+ final AtomicLong globalCheckpoint = new AtomicLong (SequenceNumbers .NO_OPS_PERFORMED );
640
+
641
+ final Settings .Builder settings = Settings .builder ()
642
+ .put (defaultSettings .getSettings ())
643
+ .put (IndexSettings .INDEX_MERGE_ON_FLUSH_MAX_FULL_FLUSH_MERGE_WAIT_TIME .getKey (), TimeValue .timeValueMillis (5000 ))
644
+ .put (IndexSettings .INDEX_MERGE_ON_FLUSH_ENABLED .getKey (), true );
645
+ final IndexMetadata indexMetadata = IndexMetadata .builder (defaultSettings .getIndexMetadata ()).settings (settings ).build ();
646
+ final IndexSettings indexSettings = IndexSettingsModule .newIndexSettings (indexMetadata );
647
+
648
+ try (
649
+ Store store = createStore ();
650
+ InternalEngine engine = createEngine (
651
+ config (indexSettings , store , createTempDir (), NoMergePolicy .INSTANCE , null , null , globalCheckpoint ::get )
652
+ )
653
+ ) {
654
+ final int numIndexingThreads = scaledRandomIntBetween (3 , 8 );
655
+ final int numDocsPerThread = randomIntBetween (500 , 1000 );
656
+ final CyclicBarrier barrier = new CyclicBarrier (numIndexingThreads + 1 );
657
+ final List <Thread > indexingThreads = new ArrayList <>();
658
+ final CountDownLatch doneLatch = new CountDownLatch (numIndexingThreads );
659
+ // create N indexing threads to index documents simultaneously
660
+ for (int threadNum = 0 ; threadNum < numIndexingThreads ; threadNum ++) {
661
+ final int threadIdx = threadNum ;
662
+ Thread indexingThread = new Thread (() -> {
663
+ try {
664
+ barrier .await (); // wait for all threads to start at the same time
665
+ // index random number of docs
666
+ for (int i = 0 ; i < numDocsPerThread ; i ++) {
667
+ final String id = "thread" + threadIdx + "#" + i ;
668
+ ParsedDocument doc = testParsedDocument (id , null , testDocument (), B_1 , null );
669
+ engine .index (indexForDoc (doc ));
670
+ }
671
+ } catch (Exception e ) {
672
+ throw new RuntimeException (e );
673
+ } finally {
674
+ doneLatch .countDown ();
675
+ }
676
+
677
+ });
678
+ indexingThreads .add (indexingThread );
679
+ }
680
+
681
+ // start the indexing threads
682
+ for (Thread thread : indexingThreads ) {
683
+ thread .start ();
684
+ }
685
+ barrier .await (); // wait for indexing threads to all be ready to start
686
+ assertThat (doneLatch .await (10 , TimeUnit .SECONDS ), is (true ));
687
+
688
+ boolean committed = randomBoolean ();
689
+ if (committed ) {
690
+ engine .flush ();
691
+ }
692
+
693
+ engine .refresh ("test" );
694
+ List <Segment > segments = engine .segments (randomBoolean ());
695
+
696
+ // All segments have to be merged into one
697
+ assertThat (segments , hasSize (1 ));
698
+ assertThat (segments .get (0 ).getNumDocs (), equalTo (numIndexingThreads * numDocsPerThread ));
699
+ assertThat (segments .get (0 ).committed , equalTo (committed ));
700
+ }
701
+ }
702
+
497
703
public void testCommitStats () throws IOException {
498
704
final AtomicLong maxSeqNo = new AtomicLong (SequenceNumbers .NO_OPS_PERFORMED );
499
705
final AtomicLong localCheckpoint = new AtomicLong (SequenceNumbers .NO_OPS_PERFORMED );
0 commit comments