/*
* Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership. Crate licenses
* this file to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may
* obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* However, if you have executed another commercial license agreement
* with Crate these terms will supersede the license and you may use the
* software solely pursuant to the terms of the relevant commercial agreement.
*/
package io.crate.executor.transport;
import com.carrotsearch.hppc.IntObjectMap;
import io.crate.Streamer;
import io.crate.jobs.JobContextService;
import io.crate.operation.collect.stats.JobsLogs;
import io.crate.operation.fetch.NodeFetchOperation;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.inject.Singleton;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
import java.util.concurrent.CompletableFuture;
@Singleton
public class TransportFetchNodeAction implements NodeAction<NodeFetchRequest, NodeFetchResponse> {
private static final String TRANSPORT_ACTION = "crate/sql/node/fetch";
private static final String EXECUTOR_NAME = ThreadPool.Names.SEARCH;
private static final String RESPONSE_EXECUTOR = ThreadPool.Names.SAME;
private final Transports transports;
private final NodeFetchOperation nodeFetchOperation;
@Inject
public TransportFetchNodeAction(TransportService transportService,
Transports transports,
ThreadPool threadPool,
JobsLogs jobsLogs,
JobContextService jobContextService) {
this.transports = transports;
this.nodeFetchOperation = new NodeFetchOperation(threadPool, jobsLogs, jobContextService);
transportService.registerRequestHandler(
TRANSPORT_ACTION,
NodeFetchRequest::new,
EXECUTOR_NAME,
// force execution because this handler might receive empty close requests which
// need to be processed to not leak the FetchContext.
// This shouldn't cause too much of an issue because fetch requests always happen after a query phase.
// If the threadPool is overloaded the query phase would fail first.
true,
false,
new NodeActionRequestHandler<NodeFetchRequest, NodeFetchResponse>(this) {}
);
}
public void execute(String targetNode,
final IntObjectMap<Streamer[]> streamers,
final NodeFetchRequest request,
ActionListener<NodeFetchResponse> listener) {
transports.sendRequest(TRANSPORT_ACTION, targetNode, request, listener,
new DefaultTransportResponseHandler<NodeFetchResponse>(listener, RESPONSE_EXECUTOR) {
@Override
public NodeFetchResponse newInstance() {
return NodeFetchResponse.forReceiveing(streamers);
}
});
}
@Override
public CompletableFuture<NodeFetchResponse> nodeOperation(final NodeFetchRequest request) {
CompletableFuture<IntObjectMap<StreamBucket>> resultFuture = nodeFetchOperation.fetch(
request.jobId(),
request.fetchPhaseId(),
request.toFetch(),
request.isCloseContext()
);
return resultFuture.thenApply(NodeFetchResponse::forSending);
}
}