private boolean unsynchronizedIsFull() { if (!isFullInternal()) { return false; } // If we're not full, don't worry about cleaning up just yet. cleanupFinishedOperations(); return isFullInternal(); }
private void setParallelism(long meanLatencyNanos, String type, int newValue) { int currentValue = getCurrentInFlightMaxRpcs(); if (newValue != currentValue) { setCurrentInFlightMaxRpcs(newValue); LOG.debug("Latency is at %d ms. %s paralellelism from %d to %d.", TimeUnit.NANOSECONDS.toMillis(meanLatencyNanos), type, currentValue, newValue); } } };
private synchronized void markOperationsCompleted(List<Long> operationSequenceIds) { for (Long operationSequenceId : operationSequenceIds) { markOperationComplete(operationSequenceId); } }
/** * Register an operation with the given size before sending. * This call WILL BLOCK until resources are available. This method must * be paired with a call to {@code markCanBeCompleted} in order to make sure * resources are properly released. * * @param heapSize The serialized size of the RPC to be sent * @return A unique operation id * @throws java.lang.InterruptedException if any. */ public long registerOperationWithHeapSize(long heapSize) throws InterruptedException { long start = clock.nanoTime(); synchronized (this) { while (unsynchronizedIsFull()) { waitForCompletions(REGISTER_WAIT_MILLIS); } long waitComplete = clock.nanoTime(); stats.markThrottling(waitComplete - start); long operationId = operationSequenceGenerator.incrementAndGet(); pendingOperationsWithSize.put(operationId, heapSize); currentWriteBufferSize += heapSize; starTimes.put(operationId, waitComplete); return operationId; } }
private synchronized static ResourceLimiter initializeResourceLimiter(BigtableOptions options) { BigtableInstanceName instanceName = options.getInstanceName(); String key = instanceName.toString(); ResourceLimiter resourceLimiter = resourceLimiterMap.get(key); if (resourceLimiter == null) { int maxInflightRpcs = options.getBulkOptions().getMaxInflightRpcs(); long maxMemory = options.getBulkOptions().getMaxMemory(); ResourceLimiterStats stats = ResourceLimiterStats.getInstance(instanceName); resourceLimiter = new ResourceLimiter(stats, maxMemory, maxInflightRpcs); BulkOptions bulkOptions = options.getBulkOptions(); if (bulkOptions.isEnableBulkMutationThrottling()) { resourceLimiter.throttle(bulkOptions.getBulkMutationRpcTargetMs()); } resourceLimiterMap.put(key, resourceLimiter); } return resourceLimiter; }
/** * <p>isFull.</p> * * @return true if no more RPCs can be started, false otherwise */ public synchronized boolean isFull() { return unsynchronizedIsFull(); }
/** * <p>hasInflightRequests.</p> * * @return true if there are currently in-flight RPCs */ public synchronized boolean hasInflightRequests() { cleanupFinishedOperations(); return !pendingOperationsWithSize.isEmpty(); }
private void cleanupFinishedOperations() { List<Long> toClean = new ArrayList<>(); completedOperationIds.drainTo(toClean); if (!toClean.isEmpty()) { markOperationsCompleted(toClean); } }
@Override public void sendMessage(ReqT message) { Preconditions.checkState(delegateCall == null, "ThrottlingClientInterceptor only supports unary operations"); Preconditions.checkState(id == null, "ThrottlingClientInterceptor only supports unary operations"); Preconditions.checkState(delegateListener != null, "start() has to be called before sendMessage()."); Preconditions.checkState(headers != null, "start() has to be called before sendMessage()."); try { id = resourceLimiter .registerOperationWithHeapSize(((MessageLite) message).getSerializedSize()); } catch (InterruptedException e) { delegateListener.onClose(Status.INTERNAL.withDescription("Operation was interrupted"), new Metadata()); return; } delegateCall = delegateChannel.newCall(method, callOptions); SimpleForwardingClientCallListener<RespT> markCompletionListener = new SimpleForwardingClientCallListener<RespT>(this.delegateListener) { @Override public void onClose(io.grpc.Status status, Metadata trailers) { resourceLimiter.markCanBeCompleted(id); delegate().onClose(status, trailers); } }; delegate().start(markCompletionListener, headers); delegate().request(numMessagesRequested); delegate().sendMessage(message); }
/** * Waits for a completion and then marks it as complete. * @throws InterruptedException */ private void waitForCompletions(long timeoutMs) throws InterruptedException { Long completedOperation = this.completedOperationIds.pollFirst(timeoutMs, TimeUnit.MILLISECONDS); if (completedOperation != null) { markOperationComplete(completedOperation); } }