49
49
import org .opensearch .core .common .breaker .NoopCircuitBreaker ;
50
50
import org .opensearch .core .index .Index ;
51
51
import org .opensearch .core .index .shard .ShardId ;
52
+ import org .opensearch .core .tasks .TaskCancelledException ;
52
53
import org .opensearch .core .tasks .resourcetracker .TaskResourceInfo ;
53
54
import org .opensearch .core .tasks .resourcetracker .TaskResourceUsage ;
54
55
import org .opensearch .index .query .MatchAllQueryBuilder ;
66
67
import org .opensearch .threadpool .TestThreadPool ;
67
68
import org .opensearch .threadpool .ThreadPool ;
68
69
import org .opensearch .transport .Transport ;
70
+ import org .opensearch .transport .TransportException ;
69
71
import org .junit .After ;
70
72
import org .junit .Before ;
71
73
@@ -136,6 +138,7 @@ private AbstractSearchAsyncAction<SearchPhaseResult> createAction(
136
138
controlled ,
137
139
false ,
138
140
false ,
141
+ false ,
139
142
expected ,
140
143
resourceUsage ,
141
144
new SearchShardIterator (null , null , Collections .emptyList (), null )
@@ -148,6 +151,7 @@ private AbstractSearchAsyncAction<SearchPhaseResult> createAction(
148
151
ActionListener <SearchResponse > listener ,
149
152
final boolean controlled ,
150
153
final boolean failExecutePhaseOnShard ,
154
+ final boolean throw4xxExceptionOnShard ,
151
155
final boolean catchExceptionWhenExecutePhaseOnShard ,
152
156
final AtomicLong expected ,
153
157
final TaskResourceUsage resourceUsage ,
@@ -217,7 +221,11 @@ protected void executePhaseOnShard(
217
221
final SearchActionListener <SearchPhaseResult > listener
218
222
) {
219
223
if (failExecutePhaseOnShard ) {
220
- listener .onFailure (new ShardNotFoundException (shardIt .shardId ()));
224
+ if (throw4xxExceptionOnShard ) {
225
+ listener .onFailure (new TransportException (new TaskCancelledException (shardIt .shardId ().toString ())));
226
+ } else {
227
+ listener .onFailure (new ShardNotFoundException (shardIt .shardId ()));
228
+ }
221
229
} else {
222
230
if (catchExceptionWhenExecutePhaseOnShard ) {
223
231
try {
@@ -585,6 +593,7 @@ public void onFailure(Exception e) {
585
593
false ,
586
594
true ,
587
595
false ,
596
+ false ,
588
597
new AtomicLong (),
589
598
new TaskResourceUsage (randomLong (), randomLong ()),
590
599
shards
@@ -601,6 +610,62 @@ public void onFailure(Exception e) {
601
610
assertThat (searchResponse .getSuccessfulShards (), equalTo (0 ));
602
611
}
603
612
613
+ public void testSkipInValidRetryInMultiReplicas () throws InterruptedException {
614
+ final Index index = new Index ("test" , UUID .randomUUID ().toString ());
615
+ final CountDownLatch latch = new CountDownLatch (1 );
616
+ final AtomicBoolean fail = new AtomicBoolean (true );
617
+
618
+ List <String > targetNodeIds = List .of ("n1" , "n2" , "n3" );
619
+ final SearchShardIterator [] shards = IntStream .range (2 , 4 )
620
+ .mapToObj (i -> new SearchShardIterator (null , new ShardId (index , i ), targetNodeIds , null , null , null ))
621
+ .toArray (SearchShardIterator []::new );
622
+
623
+ SearchRequest searchRequest = new SearchRequest ().allowPartialSearchResults (true );
624
+ searchRequest .setMaxConcurrentShardRequests (1 );
625
+
626
+ final ArraySearchPhaseResults <SearchPhaseResult > queryResult = new ArraySearchPhaseResults <>(shards .length );
627
+ AbstractSearchAsyncAction <SearchPhaseResult > action = createAction (
628
+ searchRequest ,
629
+ queryResult ,
630
+ new ActionListener <SearchResponse >() {
631
+ @ Override
632
+ public void onResponse (SearchResponse response ) {
633
+
634
+ }
635
+
636
+ @ Override
637
+ public void onFailure (Exception e ) {
638
+ if (fail .compareAndExchange (true , false )) {
639
+ try {
640
+ throw new RuntimeException ("Simulated exception" );
641
+ } finally {
642
+ executor .submit (() -> latch .countDown ());
643
+ }
644
+ }
645
+ }
646
+ },
647
+ false ,
648
+ true ,
649
+ true ,
650
+ false ,
651
+ new AtomicLong (),
652
+ new TaskResourceUsage (randomLong (), randomLong ()),
653
+ shards
654
+ );
655
+ action .run ();
656
+ assertTrue (latch .await (1 , TimeUnit .SECONDS ));
657
+ InternalSearchResponse internalSearchResponse = InternalSearchResponse .empty ();
658
+ SearchResponse searchResponse = action .buildSearchResponse (internalSearchResponse , action .buildShardFailures (), null , null );
659
+ assertSame (searchResponse .getAggregations (), internalSearchResponse .aggregations ());
660
+ assertSame (searchResponse .getSuggest (), internalSearchResponse .suggest ());
661
+ assertSame (searchResponse .getProfileResults (), internalSearchResponse .profile ());
662
+ assertSame (searchResponse .getHits (), internalSearchResponse .hits ());
663
+ assertThat (searchResponse .getSuccessfulShards (), equalTo (0 ));
664
+ for (int i = 0 ; i < shards .length ; i ++) {
665
+ assertEquals (targetNodeIds .size () - 1 , shards [i ].remaining ());
666
+ }
667
+ }
668
+
604
669
public void testOnShardSuccessPhaseDoneFailure () throws InterruptedException {
605
670
final Index index = new Index ("test" , UUID .randomUUID ().toString ());
606
671
final CountDownLatch latch = new CountDownLatch (1 );
@@ -633,6 +698,7 @@ public void onFailure(Exception e) {
633
698
false ,
634
699
false ,
635
700
false ,
701
+ false ,
636
702
new AtomicLong (),
637
703
new TaskResourceUsage (randomLong (), randomLong ()),
638
704
shards
@@ -685,6 +751,7 @@ public void onFailure(Exception e) {
685
751
},
686
752
false ,
687
753
false ,
754
+ false ,
688
755
catchExceptionWhenExecutePhaseOnShard ,
689
756
new AtomicLong (),
690
757
new TaskResourceUsage (randomLong (), randomLong ()),
0 commit comments