19
19
import org .elasticsearch .action .search .ShardSearchFailure ;
20
20
import org .elasticsearch .action .support .ActionTestUtils ;
21
21
import org .elasticsearch .client .internal .Client ;
22
+ import org .elasticsearch .common .breaker .CircuitBreaker ;
23
+ import org .elasticsearch .common .breaker .CircuitBreakingException ;
22
24
import org .elasticsearch .common .settings .Settings ;
23
25
import org .elasticsearch .core .TimeValue ;
24
26
import org .elasticsearch .index .reindex .BulkByScrollResponse ;
35
37
import org .elasticsearch .xpack .core .indexing .IndexerState ;
36
38
import org .elasticsearch .xpack .core .indexing .IterationResult ;
37
39
import org .elasticsearch .xpack .core .transform .action .ValidateTransformAction ;
40
+ import org .elasticsearch .xpack .core .transform .transforms .SettingsConfig ;
38
41
import org .elasticsearch .xpack .core .transform .transforms .TimeRetentionPolicyConfigTests ;
39
42
import org .elasticsearch .xpack .core .transform .transforms .TimeSyncConfig ;
40
43
import org .elasticsearch .xpack .core .transform .transforms .TransformCheckpoint ;
43
46
import org .elasticsearch .xpack .core .transform .transforms .TransformIndexerStats ;
44
47
import org .elasticsearch .xpack .core .transform .transforms .TransformState ;
45
48
import org .elasticsearch .xpack .core .transform .transforms .TransformTaskState ;
49
+ import org .elasticsearch .xpack .transform .Transform ;
46
50
import org .elasticsearch .xpack .transform .TransformNode ;
47
51
import org .elasticsearch .xpack .transform .TransformServices ;
48
52
import org .elasticsearch .xpack .transform .checkpoint .CheckpointProvider ;
59
63
import java .time .Clock ;
60
64
import java .util .Collections ;
61
65
import java .util .Map ;
66
+ import java .util .concurrent .BlockingDeque ;
62
67
import java .util .concurrent .CountDownLatch ;
68
+ import java .util .concurrent .LinkedBlockingDeque ;
63
69
import java .util .concurrent .TimeUnit ;
64
70
import java .util .concurrent .atomic .AtomicBoolean ;
65
71
import java .util .concurrent .atomic .AtomicReference ;
@@ -107,9 +113,13 @@ class MockedTransformIndexer extends TransformIndexer {
107
113
private CountDownLatch searchLatch ;
108
114
private CountDownLatch doProcessLatch ;
109
115
private CountDownLatch doSaveStateLatch ;
116
+ private CountDownLatch afterFinishOrFailureLatch ;
110
117
111
118
private AtomicBoolean saveStateInProgress = new AtomicBoolean (false );
112
119
120
+ private BlockingDeque <Exception > searchExceptions = new LinkedBlockingDeque <>();
121
+ private BlockingDeque <Runnable > runBeforeOnFinish = new LinkedBlockingDeque <>();
122
+
113
123
// how many loops to execute until reporting done
114
124
private int numberOfLoops ;
115
125
@@ -211,7 +221,11 @@ protected void doNextSearch(long waitTimeInNanos, ActionListener<SearchResponse>
211
221
throw new IllegalStateException (e );
212
222
}
213
223
}
214
- threadPool .generic ().execute (() -> nextPhase .onResponse (ONE_HIT_SEARCH_RESPONSE ));
224
+ if (searchExceptions .isEmpty () == false ) {
225
+ nextPhase .onFailure (searchExceptions .poll ());
226
+ } else {
227
+ threadPool .generic ().execute (() -> nextPhase .onResponse (ONE_HIT_SEARCH_RESPONSE ));
228
+ }
215
229
}
216
230
217
231
@ Override
@@ -261,6 +275,22 @@ void doMaybeCreateDestIndex(Map<String, String> deducedDestIndexMappings, Action
261
275
listener .onResponse (null );
262
276
}
263
277
278
+ @ Override
279
+ protected void onFinish (ActionListener <Void > listener ) {
280
+ while (runBeforeOnFinish .isEmpty () == false ) {
281
+ runBeforeOnFinish .poll ().run ();
282
+ }
283
+ super .onFinish (listener );
284
+ }
285
+
286
+ @ Override
287
+ protected void afterFinishOrFailure () {
288
+ super .afterFinishOrFailure ();
289
+ if (afterFinishOrFailureLatch != null ) {
290
+ afterFinishOrFailureLatch .countDown ();
291
+ }
292
+ }
293
+
264
294
public boolean waitingForNextSearch () {
265
295
return super .getScheduledNextSearch () != null ;
266
296
}
@@ -278,6 +308,14 @@ void persistState(TransformState state, ActionListener<Void> listener) {
278
308
void validate (ActionListener <ValidateTransformAction .Response > listener ) {
279
309
listener .onResponse (null );
280
310
}
311
+
312
+ public void addAfterFinishOrFailureLatch () {
313
+ afterFinishOrFailureLatch = new CountDownLatch (1 );
314
+ }
315
+
316
+ public void waitForAfterFinishOrFailureLatch (long timeout , TimeUnit unit ) throws InterruptedException {
317
+ assertTrue (afterFinishOrFailureLatch .await (timeout , unit ));
318
+ }
281
319
}
282
320
283
321
@ Before
@@ -439,6 +477,135 @@ public void testInterActionWhileIndexerShutsdown() throws Exception {
439
477
assertBusy (() -> assertEquals (IndexerState .STOPPED , indexer .getState ()), 5 , TimeUnit .SECONDS );
440
478
}
441
479
480
+ public void testMaxPageSearchSizeIsResetToDefaultValue () throws Exception {
481
+ TransformConfig config = new TransformConfig (
482
+ randomAlphaOfLength (10 ),
483
+ randomSourceConfig (),
484
+ randomDestConfig (),
485
+ null ,
486
+ new TimeSyncConfig ("timestamp" , TimeValue .timeValueSeconds (1 )),
487
+ null ,
488
+ randomPivotConfig (),
489
+ null ,
490
+ randomBoolean () ? null : randomAlphaOfLengthBetween (1 , 1000 ),
491
+ null ,
492
+ null ,
493
+ null ,
494
+ null ,
495
+ null
496
+ );
497
+ AtomicReference <IndexerState > state = new AtomicReference <>(IndexerState .STARTED );
498
+
499
+ TransformContext context = new TransformContext (TransformTaskState .STARTED , "" , 0 , mock (TransformContext .Listener .class ));
500
+ final MockedTransformIndexer indexer = createMockIndexer (
501
+ 1 ,
502
+ config ,
503
+ state ,
504
+ null ,
505
+ threadPool ,
506
+ auditor ,
507
+ new TransformIndexerStats (),
508
+ context
509
+ );
510
+
511
+ // add latches
512
+ CountDownLatch searchLatch = indexer .createAwaitForSearchLatch (1 );
513
+ indexer .addAfterFinishOrFailureLatch ();
514
+
515
+ indexer .start ();
516
+ assertTrue (indexer .maybeTriggerAsyncJob (System .currentTimeMillis ()));
517
+ assertEquals (indexer .getState (), IndexerState .INDEXING );
518
+
519
+ // set circuit breaker to 50%
520
+ indexer .searchExceptions .offer (new CircuitBreakingException ("hello" , 2 , 1 , CircuitBreaker .Durability .TRANSIENT ));
521
+ indexer .runBeforeOnFinish .offer (() -> {
522
+ assertEquals (Math .round (Transform .DEFAULT_INITIAL_MAX_PAGE_SEARCH_SIZE / 2.0 ), context .getPageSize ());
523
+ });
524
+ assertFalse (indexer .runBeforeOnFinish .isEmpty ());
525
+
526
+ // run and wait
527
+ searchLatch .countDown ();
528
+ indexer .waitForAfterFinishOrFailureLatch (5 , TimeUnit .SECONDS );
529
+
530
+ // rerun, don't throw an exception this time
531
+ searchLatch = indexer .createAwaitForSearchLatch (1 );
532
+ indexer .addAfterFinishOrFailureLatch ();
533
+ assertBusy (() -> assertTrue (indexer .maybeTriggerAsyncJob (System .currentTimeMillis ())));
534
+ searchLatch .countDown ();
535
+ indexer .waitForAfterFinishOrFailureLatch (5 , TimeUnit .SECONDS );
536
+
537
+ // verify that we checked the pageSize decreased
538
+ assertTrue (indexer .runBeforeOnFinish .isEmpty ());
539
+ // verify that the pageSize reset
540
+ assertEquals (Transform .DEFAULT_INITIAL_MAX_PAGE_SEARCH_SIZE .intValue (), context .getPageSize ());
541
+ }
542
+
543
+ public void testMaxPageSearchSizeIsResetToConfiguredValue () throws Exception {
544
+ TransformConfig config = new TransformConfig (
545
+ randomAlphaOfLength (10 ),
546
+ randomSourceConfig (),
547
+ randomDestConfig (),
548
+ null ,
549
+ new TimeSyncConfig ("timestamp" , TimeValue .timeValueSeconds (1 )),
550
+ null ,
551
+ randomPivotConfig (),
552
+ null ,
553
+ randomBoolean () ? null : randomAlphaOfLengthBetween (1 , 1000 ),
554
+ null ,
555
+ null ,
556
+ null ,
557
+ null ,
558
+ null
559
+ );
560
+ AtomicReference <IndexerState > state = new AtomicReference <>(IndexerState .STARTED );
561
+
562
+ TransformContext context = new TransformContext (TransformTaskState .STARTED , "" , 0 , mock (TransformContext .Listener .class ));
563
+ final MockedTransformIndexer indexer = createMockIndexer (
564
+ 1 ,
565
+ config ,
566
+ state ,
567
+ null ,
568
+ threadPool ,
569
+ auditor ,
570
+ new TransformIndexerStats (),
571
+ context
572
+ );
573
+
574
+ // add latches
575
+ CountDownLatch searchLatch = indexer .createAwaitForSearchLatch (1 );
576
+ indexer .addAfterFinishOrFailureLatch ();
577
+
578
+ indexer .start ();
579
+ assertTrue (indexer .maybeTriggerAsyncJob (System .currentTimeMillis ()));
580
+ assertEquals (indexer .getState (), IndexerState .INDEXING );
581
+
582
+ var configuredMaxPageSearchSize = 20_000 ;
583
+ indexer .applyNewSettings (
584
+ new SettingsConfig .Builder (SettingsConfig .EMPTY ).setMaxPageSearchSize (configuredMaxPageSearchSize ).build ()
585
+ );
586
+
587
+ // set circuit breaker to 50%
588
+ indexer .searchExceptions .offer (new CircuitBreakingException ("hello" , 2 , 1 , CircuitBreaker .Durability .TRANSIENT ));
589
+ indexer .runBeforeOnFinish .offer (() -> { assertEquals (Math .round (configuredMaxPageSearchSize / 2.0 ), context .getPageSize ()); });
590
+ assertFalse (indexer .runBeforeOnFinish .isEmpty ());
591
+
592
+ // run and wait
593
+ searchLatch .countDown ();
594
+ indexer .waitForAfterFinishOrFailureLatch (5 , TimeUnit .SECONDS );
595
+
596
+ // rerun, don't throw an exception this time
597
+ searchLatch = indexer .createAwaitForSearchLatch (1 );
598
+ indexer .addAfterFinishOrFailureLatch ();
599
+ assertBusy (() -> assertTrue (indexer .maybeTriggerAsyncJob (System .currentTimeMillis ())));
600
+ searchLatch .countDown ();
601
+ indexer .waitForAfterFinishOrFailureLatch (5 , TimeUnit .SECONDS );
602
+
603
+ // verify that we checked the pageSize decreased
604
+ assertTrue (indexer .runBeforeOnFinish .isEmpty ());
605
+ // verify that the pageSize reset
606
+ assertEquals (configuredMaxPageSearchSize , context .getPageSize ());
607
+ }
608
+
442
609
private MockedTransformIndexer createMockIndexer (
443
610
int numberOfLoops ,
444
611
TransformConfig config ,
0 commit comments