24
24
import org .apache .lucene .search .FieldDoc ;
25
25
import org .apache .lucene .search .TopDocs ;
26
26
import org .elasticsearch .ElasticsearchException ;
27
- import org .elasticsearch .ExceptionsHelper ;
28
27
import org .elasticsearch .action .ActionListener ;
29
28
import org .elasticsearch .action .OriginalIndices ;
30
29
import org .elasticsearch .action .search .SearchTask ;
@@ -329,7 +328,7 @@ private DfsSearchResult executeDfsPhase(ShardSearchRequest request, SearchTask t
329
328
} catch (Exception e ) {
330
329
logger .trace ("Dfs phase failed" , e );
331
330
processFailure (context , e );
332
- throw ExceptionsHelper . convertToRuntime ( e ) ;
331
+ throw e ;
333
332
} finally {
334
333
cleanContext (context );
335
334
}
@@ -380,29 +379,24 @@ protected void doRun() {
380
379
});
381
380
}
382
381
383
- private SearchPhaseResult executeQueryPhase (ShardSearchRequest request , SearchTask task ) throws IOException {
382
+ private SearchPhaseResult executeQueryPhase (ShardSearchRequest request , SearchTask task ) throws Exception {
384
383
final SearchContext context = createAndPutContext (request );
385
- final SearchOperationListener operationListener = context .indexShard ().getSearchOperationListener ();
386
384
context .incRef ();
387
- boolean queryPhaseSuccess = false ;
388
385
try {
389
386
context .setTask (task );
390
- operationListener . onPreQueryPhase ( context ) ;
391
- long time = System . nanoTime ();
392
- contextProcessing (context );
393
-
394
- loadOrExecuteQueryPhase ( request , context );
395
-
396
- if ( context . queryResult (). hasSearchContext () == false && context . scrollContext () == null ) {
397
- freeContext (context . id () );
398
- } else {
399
- contextProcessedSuccessfully ( context );
387
+ final long afterQueryTime ;
388
+ try ( SearchOperationListenerExecutor executor = new SearchOperationListenerExecutor ( context )) {
389
+ contextProcessing (context );
390
+ loadOrExecuteQueryPhase ( request , context );
391
+ if ( context . queryResult (). hasSearchContext () == false && context . scrollContext () == null ) {
392
+ freeContext ( context . id ());
393
+ } else {
394
+ contextProcessedSuccessfully (context );
395
+ }
396
+ afterQueryTime = executor . success ( );
400
397
}
401
- final long afterQueryTime = System .nanoTime ();
402
- queryPhaseSuccess = true ;
403
- operationListener .onQueryPhase (context , afterQueryTime - time );
404
398
if (request .numberOfShards () == 1 ) {
405
- return executeFetchPhase (context , operationListener , afterQueryTime );
399
+ return executeFetchPhase (context , afterQueryTime );
406
400
}
407
401
return context .queryResult ();
408
402
} catch (Exception e ) {
@@ -411,56 +405,44 @@ private SearchPhaseResult executeQueryPhase(ShardSearchRequest request, SearchTa
411
405
e = (e .getCause () == null || e .getCause () instanceof Exception ) ?
412
406
(Exception ) e .getCause () : new ElasticsearchException (e .getCause ());
413
407
}
414
- if (!queryPhaseSuccess ) {
415
- operationListener .onFailedQueryPhase (context );
416
- }
417
408
logger .trace ("Query phase failed" , e );
418
409
processFailure (context , e );
419
- throw ExceptionsHelper . convertToRuntime ( e ) ;
410
+ throw e ;
420
411
} finally {
421
412
cleanContext (context );
422
413
}
423
414
}
424
415
425
- private QueryFetchSearchResult executeFetchPhase (SearchContext context , SearchOperationListener operationListener ,
426
- long afterQueryTime ) {
427
- operationListener .onPreFetchPhase (context );
428
- try {
416
+ private QueryFetchSearchResult executeFetchPhase (SearchContext context , long afterQueryTime ) {
417
+ try (SearchOperationListenerExecutor executor = new SearchOperationListenerExecutor (context , true , afterQueryTime )){
429
418
shortcutDocIdsToLoad (context );
430
419
fetchPhase .execute (context );
431
420
if (fetchPhaseShouldFreeContext (context )) {
432
421
freeContext (context .id ());
433
422
} else {
434
423
contextProcessedSuccessfully (context );
435
424
}
436
- } catch (Exception e ) {
437
- operationListener .onFailedFetchPhase (context );
438
- throw ExceptionsHelper .convertToRuntime (e );
425
+ executor .success ();
439
426
}
440
- operationListener .onFetchPhase (context , System .nanoTime () - afterQueryTime );
441
427
return new QueryFetchSearchResult (context .queryResult (), context .fetchResult ());
442
428
}
443
429
444
430
public void executeQueryPhase (InternalScrollSearchRequest request , SearchTask task , ActionListener <ScrollQuerySearchResult > listener ) {
445
431
runAsync (request .id (), () -> {
446
432
final SearchContext context = findContext (request .id (), request );
447
- SearchOperationListener operationListener = context .indexShard ().getSearchOperationListener ();
448
433
context .incRef ();
449
- try {
434
+ try ( SearchOperationListenerExecutor executor = new SearchOperationListenerExecutor ( context )) {
450
435
context .setTask (task );
451
- operationListener .onPreQueryPhase (context );
452
- long time = System .nanoTime ();
453
436
contextProcessing (context );
454
437
processScroll (request , context );
455
438
queryPhase .execute (context );
456
439
contextProcessedSuccessfully (context );
457
- operationListener . onQueryPhase ( context , System . nanoTime () - time );
440
+ executor . success ( );
458
441
return new ScrollQuerySearchResult (context .queryResult (), context .shardTarget ());
459
442
} catch (Exception e ) {
460
- operationListener .onFailedQueryPhase (context );
461
443
logger .trace ("Query phase failed" , e );
462
444
processFailure (context , e );
463
- throw ExceptionsHelper . convertToRuntime ( e ) ;
445
+ throw e ;
464
446
} finally {
465
447
cleanContext (context );
466
448
}
@@ -471,29 +453,23 @@ public void executeQueryPhase(QuerySearchRequest request, SearchTask task, Actio
471
453
runAsync (request .id (), () -> {
472
454
final SearchContext context = findContext (request .id (), request );
473
455
context .setTask (task );
474
- IndexShard indexShard = context .indexShard ();
475
- SearchOperationListener operationListener = indexShard .getSearchOperationListener ();
476
456
context .incRef ();
477
- try {
457
+ try ( SearchOperationListenerExecutor executor = new SearchOperationListenerExecutor ( context )) {
478
458
contextProcessing (context );
479
459
context .searcher ().setAggregatedDfs (request .dfs ());
480
-
481
- operationListener .onPreQueryPhase (context );
482
- long time = System .nanoTime ();
483
460
queryPhase .execute (context );
484
461
if (context .queryResult ().hasSearchContext () == false && context .scrollContext () == null ) {
485
462
// no hits, we can release the context since there will be no fetch phase
486
463
freeContext (context .id ());
487
464
} else {
488
465
contextProcessedSuccessfully (context );
489
466
}
490
- operationListener . onQueryPhase ( context , System . nanoTime () - time );
467
+ executor . success ( );
491
468
return context .queryResult ();
492
469
} catch (Exception e ) {
493
- operationListener .onFailedQueryPhase (context );
494
470
logger .trace ("Query phase failed" , e );
495
471
processFailure (context , e );
496
- throw ExceptionsHelper . convertToRuntime ( e ) ;
472
+ throw e ;
497
473
} finally {
498
474
cleanContext (context );
499
475
}
@@ -527,28 +503,19 @@ public void executeFetchPhase(InternalScrollSearchRequest request, SearchTask ta
527
503
ActionListener <ScrollQueryFetchSearchResult > listener ) {
528
504
runAsync (request .id (), () -> {
529
505
final SearchContext context = findContext (request .id (), request );
506
+ context .setTask (task );
530
507
context .incRef ();
531
- try {
532
- context .setTask (task );
508
+ try (SearchOperationListenerExecutor executor = new SearchOperationListenerExecutor (context )){
533
509
contextProcessing (context );
534
- SearchOperationListener operationListener = context .indexShard ().getSearchOperationListener ();
535
510
processScroll (request , context );
536
- operationListener .onPreQueryPhase (context );
537
- final long time = System .nanoTime ();
538
- try {
539
- queryPhase .execute (context );
540
- } catch (Exception e ) {
541
- operationListener .onFailedQueryPhase (context );
542
- throw ExceptionsHelper .convertToRuntime (e );
543
- }
544
- long afterQueryTime = System .nanoTime ();
545
- operationListener .onQueryPhase (context , afterQueryTime - time );
546
- QueryFetchSearchResult fetchSearchResult = executeFetchPhase (context , operationListener , afterQueryTime );
511
+ queryPhase .execute (context );
512
+ final long afterQueryTime = executor .success ();
513
+ QueryFetchSearchResult fetchSearchResult = executeFetchPhase (context , afterQueryTime );
547
514
return new ScrollQueryFetchSearchResult (fetchSearchResult , context .shardTarget ());
548
515
} catch (Exception e ) {
549
516
logger .trace ("Fetch phase failed" , e );
550
517
processFailure (context , e );
551
- throw ExceptionsHelper . convertToRuntime ( e ) ;
518
+ throw e ;
552
519
} finally {
553
520
cleanContext (context );
554
521
}
@@ -558,7 +525,6 @@ public void executeFetchPhase(InternalScrollSearchRequest request, SearchTask ta
558
525
public void executeFetchPhase (ShardFetchRequest request , SearchTask task , ActionListener <FetchSearchResult > listener ) {
559
526
runAsync (request .id (), () -> {
560
527
final SearchContext context = findContext (request .id (), request );
561
- final SearchOperationListener operationListener = context .indexShard ().getSearchOperationListener ();
562
528
context .incRef ();
563
529
try {
564
530
context .setTask (task );
@@ -567,21 +533,20 @@ public void executeFetchPhase(ShardFetchRequest request, SearchTask task, Action
567
533
context .scrollContext ().lastEmittedDoc = request .lastEmittedDoc ();
568
534
}
569
535
context .docIdsToLoad (request .docIds (), 0 , request .docIdsSize ());
570
- operationListener .onPreFetchPhase (context );
571
- long time = System .nanoTime ();
572
- fetchPhase .execute (context );
573
- if (fetchPhaseShouldFreeContext (context )) {
574
- freeContext (request .id ());
575
- } else {
576
- contextProcessedSuccessfully (context );
536
+ try (SearchOperationListenerExecutor executor = new SearchOperationListenerExecutor (context , true , System .nanoTime ())) {
537
+ fetchPhase .execute (context );
538
+ if (fetchPhaseShouldFreeContext (context )) {
539
+ freeContext (request .id ());
540
+ } else {
541
+ contextProcessedSuccessfully (context );
542
+ }
543
+ executor .success ();
577
544
}
578
- operationListener .onFetchPhase (context , System .nanoTime () - time );
579
545
return context .fetchResult ();
580
546
} catch (Exception e ) {
581
- operationListener .onFailedFetchPhase (context );
582
547
logger .trace ("Fetch phase failed" , e );
583
548
processFailure (context , e );
584
- throw ExceptionsHelper . convertToRuntime ( e ) ;
549
+ throw e ;
585
550
} finally {
586
551
cleanContext (context );
587
552
}
@@ -661,7 +626,7 @@ final SearchContext createContext(ShardSearchRequest request) throws IOException
661
626
context .lowLevelCancellation (lowLevelCancellation );
662
627
} catch (Exception e ) {
663
628
context .close ();
664
- throw ExceptionsHelper . convertToRuntime ( e ) ;
629
+ throw e ;
665
630
}
666
631
667
632
return context ;
@@ -733,7 +698,7 @@ public void freeAllScrollContexts() {
733
698
}
734
699
}
735
700
736
- private void contextScrollKeepAlive (SearchContext context , long keepAlive ) throws IOException {
701
+ private void contextScrollKeepAlive (SearchContext context , long keepAlive ) {
737
702
if (keepAlive > maxKeepAlive ) {
738
703
throw new IllegalArgumentException (
739
704
"Keep alive for scroll (" + TimeValue .timeValueMillis (keepAlive ) + ") is too large. " +
@@ -991,7 +956,7 @@ private void shortcutDocIdsToLoad(SearchContext context) {
991
956
context .docIdsToLoad (docIdsToLoad , 0 , docIdsToLoad .length );
992
957
}
993
958
994
- private void processScroll (InternalScrollSearchRequest request , SearchContext context ) throws IOException {
959
+ private void processScroll (InternalScrollSearchRequest request , SearchContext context ) {
995
960
// process scroll
996
961
context .from (context .from () + context .size ());
997
962
context .scrollContext ().scroll = request .scroll ();
@@ -1147,4 +1112,58 @@ public boolean canMatch() {
1147
1112
return canMatch ;
1148
1113
}
1149
1114
}
1115
+
1116
+ /**
1117
+ * This helper class ensures we only execute either the success or the failure path for {@link SearchOperationListener}.
1118
+ * This is crucial for some implementations like {@link org.elasticsearch.index.search.stats.ShardSearchStats}.
1119
+ */
1120
+ private static final class SearchOperationListenerExecutor implements AutoCloseable {
1121
+ private final SearchOperationListener listener ;
1122
+ private final SearchContext context ;
1123
+ private final long time ;
1124
+ private final boolean fetch ;
1125
+ private long afterQueryTime = -1 ;
1126
+ private boolean closed = false ;
1127
+
1128
+ SearchOperationListenerExecutor (SearchContext context ) {
1129
+ this (context , false , System .nanoTime ());
1130
+ }
1131
+
1132
+ SearchOperationListenerExecutor (SearchContext context , boolean fetch , long startTime ) {
1133
+ this .listener = context .indexShard ().getSearchOperationListener ();
1134
+ this .context = context ;
1135
+ time = startTime ;
1136
+ this .fetch = fetch ;
1137
+ if (fetch ) {
1138
+ listener .onPreFetchPhase (context );
1139
+ } else {
1140
+ listener .onPreQueryPhase (context );
1141
+ }
1142
+ }
1143
+
1144
+ long success () {
1145
+ return afterQueryTime = System .nanoTime ();
1146
+ }
1147
+
1148
+ @ Override
1149
+ public void close () {
1150
+ assert closed == false : "already closed - while technically ok double closing is a likely a bug in this case" ;
1151
+ if (closed == false ) {
1152
+ closed = true ;
1153
+ if (afterQueryTime != -1 ) {
1154
+ if (fetch ) {
1155
+ listener .onFetchPhase (context , afterQueryTime - time );
1156
+ } else {
1157
+ listener .onQueryPhase (context , afterQueryTime - time );
1158
+ }
1159
+ } else {
1160
+ if (fetch ) {
1161
+ listener .onFailedFetchPhase (context );
1162
+ } else {
1163
+ listener .onFailedQueryPhase (context );
1164
+ }
1165
+ }
1166
+ }
1167
+ }
1168
+ }
1150
1169
}
0 commit comments