19
19
20
20
package org .elasticsearch .action .bulk ;
21
21
22
+ import org .apache .logging .log4j .LogManager ;
23
+ import org .apache .logging .log4j .Logger ;
22
24
import org .apache .logging .log4j .message .ParameterizedMessage ;
23
25
import org .apache .lucene .util .SparseFixedBitSet ;
24
26
import org .elasticsearch .Assertions ;
57
59
import org .elasticsearch .common .inject .Inject ;
58
60
import org .elasticsearch .common .settings .Settings ;
59
61
import org .elasticsearch .common .unit .TimeValue ;
62
+ import org .elasticsearch .common .util .concurrent .AbstractRunnable ;
60
63
import org .elasticsearch .common .util .concurrent .AtomicArray ;
61
64
import org .elasticsearch .index .Index ;
62
65
import org .elasticsearch .index .IndexNotFoundException ;
82
85
import java .util .Set ;
83
86
import java .util .concurrent .TimeUnit ;
84
87
import java .util .concurrent .atomic .AtomicInteger ;
88
+ import java .util .concurrent .atomic .AtomicIntegerArray ;
85
89
import java .util .function .LongSupplier ;
86
90
import java .util .stream .Collectors ;
87
91
@@ -644,14 +648,13 @@ private long relativeTime() {
644
648
}
645
649
646
650
void processBulkIndexIngestRequest (Task task , BulkRequest original , ActionListener <BulkResponse > listener ) {
647
- long ingestStartTimeInNanos = System .nanoTime ();
648
- BulkRequestModifier bulkRequestModifier = new BulkRequestModifier (original );
649
- ingestService .executeBulkRequest (() -> bulkRequestModifier ,
650
- (indexRequest , exception ) -> {
651
- logger .debug (() -> new ParameterizedMessage ("failed to execute pipeline [{}] for document [{}/{}/{}]" ,
652
- indexRequest .getPipeline (), indexRequest .index (), indexRequest .type (), indexRequest .id ()), exception );
653
- bulkRequestModifier .markCurrentItemAsFailed (exception );
654
- }, (exception ) -> {
651
+ final long ingestStartTimeInNanos = System .nanoTime ();
652
+ final BulkRequestModifier bulkRequestModifier = new BulkRequestModifier (original );
653
+ ingestService .executeBulkRequest (
654
+ original .numberOfActions (),
655
+ () -> bulkRequestModifier ,
656
+ bulkRequestModifier ::markItemAsFailed ,
657
+ (originalThread , exception ) -> {
655
658
if (exception != null ) {
656
659
logger .error ("failed to execute pipeline for a bulk request" , exception );
657
660
listener .onFailure (exception );
@@ -666,26 +669,56 @@ void processBulkIndexIngestRequest(Task task, BulkRequest original, ActionListen
666
669
// (this will happen if pre-processing all items in the bulk failed)
667
670
actionListener .onResponse (new BulkResponse (new BulkItemResponse [0 ], 0 ));
668
671
} else {
669
- doExecute (task , bulkRequest , actionListener );
672
+ // If a processor went async and returned a response on a different thread then
673
+ // before we continue the bulk request we should fork back on a write thread:
674
+ if (originalThread == Thread .currentThread ()) {
675
+ assert Thread .currentThread ().getName ().contains (ThreadPool .Names .WRITE );
676
+ doExecute (task , bulkRequest , actionListener );
677
+ } else {
678
+ threadPool .executor (ThreadPool .Names .WRITE ).execute (new AbstractRunnable () {
679
+ @ Override
680
+ public void onFailure (Exception e ) {
681
+ listener .onFailure (e );
682
+ }
683
+
684
+ @ Override
685
+ protected void doRun () throws Exception {
686
+ doExecute (task , bulkRequest , actionListener );
687
+ }
688
+
689
+ @ Override
690
+ public boolean isForceExecution () {
691
+ // If we fork back to a write thread we **not** should fail, because tp queue is full.
692
+ // (Otherwise the work done during ingest will be lost)
693
+ // It is okay to force execution here. Throttling of write requests happens prior to
694
+ // ingest when a node receives a bulk request.
695
+ return true ;
696
+ }
697
+ });
698
+ }
670
699
}
671
700
}
672
701
},
673
- indexRequest -> bulkRequestModifier .markCurrentItemAsDropped ());
702
+ bulkRequestModifier ::markItemAsDropped
703
+ );
674
704
}
675
705
676
706
static final class BulkRequestModifier implements Iterator <DocWriteRequest <?>> {
677
707
708
+ private static final Logger LOGGER = LogManager .getLogger (BulkRequestModifier .class );
709
+
678
710
final BulkRequest bulkRequest ;
679
711
final SparseFixedBitSet failedSlots ;
680
712
final List <BulkItemResponse > itemResponses ;
713
+ final AtomicIntegerArray originalSlots ;
681
714
682
- int currentSlot = -1 ;
683
- int [] originalSlots ;
715
+ volatile int currentSlot = -1 ;
684
716
685
717
BulkRequestModifier (BulkRequest bulkRequest ) {
686
718
this .bulkRequest = bulkRequest ;
687
719
this .failedSlots = new SparseFixedBitSet (bulkRequest .requests ().size ());
688
720
this .itemResponses = new ArrayList <>(bulkRequest .requests ().size ());
721
+ this .originalSlots = new AtomicIntegerArray (bulkRequest .requests ().size ()); // oversize, but that's ok
689
722
}
690
723
691
724
@ Override
@@ -709,12 +742,11 @@ BulkRequest getBulkRequest() {
709
742
710
743
int slot = 0 ;
711
744
List <DocWriteRequest <?>> requests = bulkRequest .requests ();
712
- originalSlots = new int [requests .size ()]; // oversize, but that's ok
713
745
for (int i = 0 ; i < requests .size (); i ++) {
714
746
DocWriteRequest <?> request = requests .get (i );
715
747
if (failedSlots .get (i ) == false ) {
716
748
modifiedBulkRequest .add (request );
717
- originalSlots [ slot ++] = i ;
749
+ originalSlots . set ( slot ++, i ) ;
718
750
}
719
751
}
720
752
return modifiedBulkRequest ;
@@ -729,7 +761,7 @@ ActionListener<BulkResponse> wrapActionListenerIfNeeded(long ingestTookInMillis,
729
761
return ActionListener .delegateFailure (actionListener , (delegatedListener , response ) -> {
730
762
BulkItemResponse [] items = response .getItems ();
731
763
for (int i = 0 ; i < items .length ; i ++) {
732
- itemResponses .add (originalSlots [ i ] , response .getItems ()[i ]);
764
+ itemResponses .add (originalSlots . get ( i ) , response .getItems ()[i ]);
733
765
}
734
766
delegatedListener .onResponse (
735
767
new BulkResponse (
@@ -738,12 +770,12 @@ ActionListener<BulkResponse> wrapActionListenerIfNeeded(long ingestTookInMillis,
738
770
}
739
771
}
740
772
741
- void markCurrentItemAsDropped ( ) {
742
- IndexRequest indexRequest = getIndexWriteRequest (bulkRequest .requests ().get (currentSlot ));
743
- failedSlots .set (currentSlot );
773
+ synchronized void markItemAsDropped ( int slot ) {
774
+ IndexRequest indexRequest = getIndexWriteRequest (bulkRequest .requests ().get (slot ));
775
+ failedSlots .set (slot );
744
776
final String id = indexRequest .id () == null ? DROPPED_ITEM_WITH_AUTO_GENERATED_ID : indexRequest .id ();
745
777
itemResponses .add (
746
- new BulkItemResponse (currentSlot , indexRequest .opType (),
778
+ new BulkItemResponse (slot , indexRequest .opType (),
747
779
new UpdateResponse (
748
780
new ShardId (indexRequest .index (), IndexMetaData .INDEX_UUID_NA_VALUE , 0 ),
749
781
indexRequest .type (), id , SequenceNumbers .UNASSIGNED_SEQ_NO , SequenceNumbers .UNASSIGNED_PRIMARY_TERM ,
@@ -753,16 +785,19 @@ void markCurrentItemAsDropped() {
753
785
);
754
786
}
755
787
756
- void markCurrentItemAsFailed (Exception e ) {
757
- IndexRequest indexRequest = getIndexWriteRequest (bulkRequest .requests ().get (currentSlot ));
788
+ synchronized void markItemAsFailed (int slot , Exception e ) {
789
+ IndexRequest indexRequest = getIndexWriteRequest (bulkRequest .requests ().get (slot ));
790
+ LOGGER .debug (() -> new ParameterizedMessage ("failed to execute pipeline [{}] for document [{}/{}/{}]" ,
791
+ indexRequest .getPipeline (), indexRequest .index (), indexRequest .type (), indexRequest .id ()), e );
792
+
758
793
// We hit a error during preprocessing a request, so we:
759
794
// 1) Remember the request item slot from the bulk, so that we're done processing all requests we know what failed
760
795
// 2) Add a bulk item failure for this request
761
796
// 3) Continue with the next request in the bulk.
762
- failedSlots .set (currentSlot );
797
+ failedSlots .set (slot );
763
798
BulkItemResponse .Failure failure = new BulkItemResponse .Failure (indexRequest .index (), indexRequest .type (),
764
799
indexRequest .id (), e );
765
- itemResponses .add (new BulkItemResponse (currentSlot , indexRequest .opType (), failure ));
800
+ itemResponses .add (new BulkItemResponse (slot , indexRequest .opType (), failure ));
766
801
}
767
802
768
803
}
0 commit comments