use of io.crate.concurrent.limits.ConcurrencyLimit in project crate by crate.
the class NodeLimits method get.
/**
* Retrieve the current ConcurrencyLimit for a node.
*
* <p>
* Instances may change if the settings are updated.
* Consumers of the ConcurrencyLimit need to hold onto the same instance for
* {@link ConcurrencyLimit#startSample()} and
* {@link ConcurrencyLimit#onSample(long, boolean)} calls to ensure the number
* of inflight requests are accurate.
* </p>
*/
public ConcurrencyLimit get(@Nullable String nodeId) {
if (nodeId == null) {
ConcurrencyLimit unknown = unknownNodelimit;
if (unknown == null) {
// Here be dragons: Two threads calling .get at the same time could end up
// creating two different unknown instances.
// This is acceptable because of the startSample/onSample contract.
// (ConcurrencyLimit user must hold onto references and use the same instance)
//
// Due to settings changes and nodeDisconnected events, we must be able to cope
// with multiple instances anyways.
unknown = newLimit();
unknownNodelimit = unknown;
}
return unknown;
}
return limitsPerNode.computeIfAbsent(nodeId, ignored -> newLimit());
}
use of io.crate.concurrent.limits.ConcurrencyLimit in project crate by crate.
the class NodeLimitsTest method test_updating_node_limit_settings_results_in_new_concurrency_limit_instances.
@Test
public void test_updating_node_limit_settings_results_in_new_concurrency_limit_instances() throws Exception {
ConcurrencyLimit limit = nodeLimits.get("n1");
clusterSettings.applySettings(Settings.builder().put("overload_protection.dml.initial_concurrency", 10).build());
ConcurrencyLimit updatedLimit = nodeLimits.get("n1");
assertThat(limit, not(sameInstance(updatedLimit)));
assertThat(limit.getLimit(), is(5));
assertThat(updatedLimit.getLimit(), is(10));
}
use of io.crate.concurrent.limits.ConcurrencyLimit in project crate by crate.
the class ShardingUpsertExecutor method execRequests.
private CompletableFuture<UpsertResults> execRequests(ShardedRequests<ShardUpsertRequest, ShardUpsertRequest.Item> requests, final UpsertResults upsertResults) {
if (requests.itemsByShard.isEmpty()) {
requests.close();
// could be that processing the source uri only results in errors, so no items per shard exists
return CompletableFuture.completedFuture(upsertResults);
}
final AtomicInteger numRequests = new AtomicInteger(requests.itemsByShard.size());
final AtomicReference<Exception> interrupt = new AtomicReference<>(null);
final CompletableFuture<UpsertResults> resultFuture = new CompletableFuture<>();
Iterator<Map.Entry<ShardLocation, ShardUpsertRequest>> it = requests.itemsByShard.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<ShardLocation, ShardUpsertRequest> entry = it.next();
ShardUpsertRequest request = entry.getValue();
it.remove();
String nodeId = entry.getKey().nodeId;
ConcurrencyLimit nodeLimit = nodeLimits.get(nodeId);
ActionListener<ShardResponse> listener = new ShardResponseActionListener(numRequests, interrupt, upsertResults, resultCollector.accumulator(), requests.rowSourceInfos, nodeLimit, resultFuture);
listener = new RetryListener<>(scheduler, l -> requestExecutor.execute(request, l), listener, BackoffPolicy.unlimitedDynamic(nodeLimit));
requestExecutor.execute(request, listener);
}
return resultFuture.whenComplete((r, err) -> requests.close());
}
use of io.crate.concurrent.limits.ConcurrencyLimit in project crate by crate.
the class ShardingUpsertExecutor method apply.
@Override
public CompletableFuture<? extends Iterable<Row>> apply(BatchIterator<Row> batchIterator) {
final ConcurrencyLimit nodeLimit = nodeLimits.get(localNode);
long startTime = nodeLimit.startSample();
var isUsedBytesOverThreshold = new IsUsedBytesOverThreshold(queryCircuitBreaker, nodeLimit);
var reqBatchIterator = BatchIterators.partition(batchIterator, bulkSize, () -> new ShardedRequests<>(requestFactory, ramAccounting), grouper, bulkShardCreationLimiter.or(isUsedBytesOverThreshold));
// If IO is involved the source iterator should pause when the target node reaches a concurrent job counter limit.
// Without IO, we assume that the source iterates over in-memory structures which should be processed as
// fast as possible to free resources.
Predicate<ShardedRequests<ShardUpsertRequest, ShardUpsertRequest.Item>> shouldPause = this::shouldPauseOnPartitionCreation;
if (batchIterator.hasLazyResultSet()) {
shouldPause = shouldPause.or(this::shouldPauseOnTargetNodeJobsCounter).or(isUsedBytesOverThreshold);
}
BatchIteratorBackpressureExecutor<ShardedRequests<ShardUpsertRequest, ShardUpsertRequest.Item>, UpsertResults> executor = new BatchIteratorBackpressureExecutor<>(jobId, scheduler, this.executor, reqBatchIterator, this::execute, resultCollector.combiner(), resultCollector.supplier().get(), shouldPause, earlyTerminationCondition, earlyTerminationExceptionGenerator, this::getMaxLastRttInMs);
return executor.consumeIteratorAndExecute().thenApply(upsertResults -> resultCollector.finisher().apply(upsertResults)).whenComplete((res, err) -> {
nodeLimit.onSample(startTime, err != null);
});
}
use of io.crate.concurrent.limits.ConcurrencyLimit in project crate by crate.
the class ShardingUpsertExecutor method shouldPauseOnTargetNodeJobsCounter.
private boolean shouldPauseOnTargetNodeJobsCounter(ShardedRequests<ShardUpsertRequest, ShardUpsertRequest.Item> requests) {
for (ShardLocation shardLocation : requests.itemsByShard.keySet()) {
String requestNodeId = shardLocation.nodeId;
ConcurrencyLimit nodeLimit = nodeLimits.get(requestNodeId);
if (nodeLimit.exceedsLimit()) {
if (isDebugEnabled) {
LOGGER.debug("reached maximum concurrent operations for node {} (limit={}, rrt={}ms, inflight={})", requestNodeId, nodeLimit.getLimit(), nodeLimit.getLastRtt(TimeUnit.MILLISECONDS), nodeLimit.numInflight());
}
return true;
}
}
return false;
}
Aggregations