|
@@ -30,6 +30,7 @@ import java.util.List;
|
|
|
import java.util.Objects;
|
|
|
import java.util.Set;
|
|
|
import java.util.concurrent.atomic.AtomicIntegerArray;
|
|
|
+import java.util.function.Function;
|
|
|
import java.util.stream.Collectors;
|
|
|
import java.util.stream.IntStream;
|
|
|
|
|
@@ -105,47 +106,87 @@ final class BulkRequestModifier implements Iterator<DocWriteRequest<?>> {
|
|
|
* If documents were dropped or failed in ingest, this method wraps the action listener that will be notified when the
|
|
|
* updated bulk operation is completed. The wrapped listener combines the dropped and failed document results from the ingest
|
|
|
* service with the results returned from running the remaining write operations.
|
|
|
+ * <br>
|
|
|
+ * Use this method when you want the ingest time to be taken from the actual {@link BulkResponse} such as if you are wrapping
|
|
|
+ * a response multiple times and wish to preserve an already calculated ingest time.
|
|
|
*
|
|
|
- * @param ingestTookInMillis Time elapsed for ingestion to be passed to final result.
|
|
|
- * @param actionListener The action listener that expects the final bulk response.
|
|
|
- * @return An action listener that combines ingest failure results with the results from writing the remaining documents.
|
|
|
+ * @param actionListener the listener to wrap
|
|
|
+ * @return a wrapped listener that merges ingest and bulk results, or the original listener if no items were dropped/failed
|
|
|
+ */
|
|
|
+ ActionListener<BulkResponse> wrapActionListenerIfNeeded(ActionListener<BulkResponse> actionListener) {
|
|
|
+ if (itemResponses.isEmpty()) {
|
|
|
+ return actionListener;
|
|
|
+ } else {
|
|
|
+ return doWrapActionListenerIfNeeded(BulkResponse::getIngestTookInMillis, actionListener);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * If documents were dropped or failed in ingest, this method wraps the action listener that will be notified when the
|
|
|
+ * updated bulk operation is completed. The wrapped listener combines the dropped and failed document results from the ingest
|
|
|
+ * service with the results returned from running the remaining write operations.
|
|
|
+ * <br>
|
|
|
+ * This variant is used when the ingest time is already known and should be explicitly set in the final response,
|
|
|
+ * rather than extracted from the {@link BulkResponse}.
|
|
|
+ *
|
|
|
+ * @param ingestTookInMillis the ingest time in milliseconds to use in the final response
|
|
|
+ * @param actionListener the listener to wrap
|
|
|
+ * @return a wrapped listener that merges ingest and bulk results, or the original listener if no items were dropped/failed
|
|
|
*/
|
|
|
ActionListener<BulkResponse> wrapActionListenerIfNeeded(long ingestTookInMillis, ActionListener<BulkResponse> actionListener) {
|
|
|
if (itemResponses.isEmpty()) {
|
|
|
return actionListener.map(
|
|
|
response -> new BulkResponse(
|
|
|
response.getItems(),
|
|
|
- response.getTook().getMillis(),
|
|
|
+ response.getTookInMillis(),
|
|
|
ingestTookInMillis,
|
|
|
response.getIncrementalState()
|
|
|
)
|
|
|
);
|
|
|
} else {
|
|
|
- return actionListener.map(response -> {
|
|
|
- // these items are the responses from the subsequent bulk request, their 'slots'
|
|
|
- // are not correct for this response we're building
|
|
|
- final BulkItemResponse[] bulkResponses = response.getItems();
|
|
|
+ return doWrapActionListenerIfNeeded(ignoredResponse -> ingestTookInMillis, actionListener);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * If documents were dropped or failed in ingest, this method wraps the action listener that will be notified when the
|
|
|
+ * updated bulk operation is completed. The wrapped listener combines the dropped and failed document results from the ingest
|
|
|
+ * service with the results returned from running the remaining write operations.
|
|
|
+ *
|
|
|
+ * @param ingestTimeProviderFunction A function to provide the ingest time taken for this response
|
|
|
+ * @param actionListener The action listener that expects the final bulk response.
|
|
|
+ * @return An action listener that combines ingest failure results with the results from writing the remaining documents.
|
|
|
+ */
|
|
|
+ private ActionListener<BulkResponse> doWrapActionListenerIfNeeded(
|
|
|
+ Function<BulkResponse, Long> ingestTimeProviderFunction,
|
|
|
+ ActionListener<BulkResponse> actionListener
|
|
|
+ ) {
|
|
|
+ return actionListener.map(response -> {
|
|
|
+ // these items are the responses from the subsequent bulk request, their 'slots'
|
|
|
+ // are not correct for this response we're building
|
|
|
+ final BulkItemResponse[] bulkResponses = response.getItems();
|
|
|
|
|
|
- final BulkItemResponse[] allResponses = new BulkItemResponse[bulkResponses.length + itemResponses.size()];
|
|
|
+ final BulkItemResponse[] allResponses = new BulkItemResponse[bulkResponses.length + itemResponses.size()];
|
|
|
|
|
|
- // the item responses are from the original request, so their slots are correct.
|
|
|
- // these are the responses for requests that failed early and were not passed on to the subsequent bulk.
|
|
|
- for (BulkItemResponse item : itemResponses) {
|
|
|
- allResponses[item.getItemId()] = item;
|
|
|
- }
|
|
|
+ // the item responses are from the original request, so their slots are correct.
|
|
|
+ // these are the responses for requests that failed early and were not passed on to the subsequent bulk.
|
|
|
+ for (BulkItemResponse item : itemResponses) {
|
|
|
+ allResponses[item.getItemId()] = item;
|
|
|
+ }
|
|
|
|
|
|
- // use the original slots for the responses from the bulk
|
|
|
- for (int i = 0; i < bulkResponses.length; i++) {
|
|
|
- allResponses[originalSlots.get(i)] = bulkResponses[i];
|
|
|
- }
|
|
|
+ // use the original slots for the responses from the bulk
|
|
|
+ for (int i = 0; i < bulkResponses.length; i++) {
|
|
|
+ allResponses[originalSlots.get(i)] = bulkResponses[i];
|
|
|
+ }
|
|
|
|
|
|
- if (Assertions.ENABLED) {
|
|
|
- assertResponsesAreCorrect(bulkResponses, allResponses);
|
|
|
- }
|
|
|
+ if (Assertions.ENABLED) {
|
|
|
+ assertResponsesAreCorrect(bulkResponses, allResponses);
|
|
|
+ }
|
|
|
|
|
|
- return new BulkResponse(allResponses, response.getTook().getMillis(), ingestTookInMillis, response.getIncrementalState());
|
|
|
- });
|
|
|
- }
|
|
|
+ var ingestTookInMillis = ingestTimeProviderFunction.apply(response);
|
|
|
+
|
|
|
+ return new BulkResponse(allResponses, response.getTook().getMillis(), ingestTookInMillis, response.getIncrementalState());
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
private void assertResponsesAreCorrect(BulkItemResponse[] bulkResponses, BulkItemResponse[] allResponses) {
|