private synchronized void purgeAll() { purgeBatches(this.batches.asMap().values().iterator()); }
private synchronized boolean tryTake(long permits) { purgeExpiredBatches(); if (this.totalAvailablePermits < permits) { return false; } this.totalAvailablePermits -= permits; Iterator<PermitBatch> batchesIterator = this.batches.values().iterator(); while (batchesIterator.hasNext()) { PermitBatch batch = batchesIterator.next(); if (batch.getPermits() < permits) { permits -= batch.getPermits(); batchesIterator.remove(); } else { batch.decrementPermits(permits); return true; } } // This can only happen if totalAvailablePermits is not in sync with the actual batches throw new RuntimeException("Total permits was unsynced! This is an error in code."); }
@Builder private BatchedPermitsRequester(String resourceId, String requestorIdentifier, long targetMillisBetweenRequests, RequestSender requestSender, MetricContext metricContext) { Preconditions.checkArgument(!Strings.isNullOrEmpty(resourceId), "Must provide a resource id."); Preconditions.checkArgument(!Strings.isNullOrEmpty(requestorIdentifier), "Must provide a requestor identifier."); this.permitBatchContainer = new PermitBatchContainer(); this.lock = new ReentrantLock(); this.newPermitsAvailable = this.lock.newCondition(); /** Ensures there is only one in-flight request at a time. */ this.requestSemaphore = new Semaphore(1); /** Number of not-yet-satisfied permits. */ this.permitsOutstanding = new SynchronizedAverager(); this.targetMillisBetweenRequests = targetMillisBetweenRequests > 0 ? targetMillisBetweenRequests : DEFAULT_TARGET_MILLIS_BETWEEN_REQUESTS; this.requestSender = requestSender; this.retryStatus = new RetryStatus(); this.basePermitRequest = new PermitRequest(); this.basePermitRequest.setResource(resourceId); this.basePermitRequest.setRequestorIdentifier(requestorIdentifier); this.restRequestTimer = metricContext == null ? null : metricContext.timer(REST_REQUEST_TIMER); this.restRequestHistogram = metricContext == null ? null : metricContext.histogram(REST_REQUEST_PERMITS_HISTOGRAM); this.callbackCounter = new AtomicLong(); }
private synchronized void purgeExpiredBatches() { long now = System.currentTimeMillis(); purgeBatches(this.batches.asMap().subMap(Long.MIN_VALUE, now).values().iterator()); }
/** * @return the number of permits acquired from the server and not yet used. */ @VisibleForTesting public long getUnusedPermits() { return this.bachedPermitsContainer.getPermitBatchContainer().getTotalAvailablePermits(); }