| | |
| | | * |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2013-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC |
| | | */ |
| | | package org.opends.server.extensions; |
| | | |
| | |
| | | import java.util.List; |
| | | import java.util.concurrent.LinkedBlockingQueue; |
| | | import java.util.concurrent.TimeUnit; |
| | | import java.util.concurrent.atomic.AtomicInteger; |
| | | import java.util.concurrent.atomic.AtomicLong; |
| | | import java.util.concurrent.locks.ReentrantReadWriteLock; |
| | | import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; |
| | |
| | | private AtomicLong opsSubmitted; |
| | | |
| | | /** |
| | | * The number of operations that have been accepted by the work queue and are |
| | | * not yet fully processed: this covers operations sitting in the queue as |
| | | * well as operations currently handled by worker threads, including the |
| | | * hand-off window in between, which is invisible to both the queue and the |
| | | * worker thread activity flag. |
| | | */ |
| | | private final AtomicInteger pendingOpsCount = new AtomicInteger(); |
| | | |
| | | /** |
| | | * The number of times that an attempt to submit a new request has been |
| | | * rejected because the work queue is already at its maximum capacity. |
| | | */ |
| | |
| | | killThreads = false; |
| | | opsSubmitted = new AtomicLong(0); |
| | | queueFullRejects = new AtomicLong(0); |
| | | pendingOpsCount.set(0); |
| | | |
| | | // Register to be notified of any configuration changes. |
| | | configuration.addTraditionalChangeListener(this); |
| | |
| | | private void submitOperation(Operation operation, |
| | | boolean blockEnqueuingWhenFull) throws DirectoryException |
| | | { |
| | | // Count the operation before enqueuing it so that isIdle() can never |
| | | // observe an empty queue while the operation is in the process of being |
| | | // submitted; the count is rolled back if the operation is rejected. |
| | | pendingOpsCount.incrementAndGet(); |
| | | boolean submitted = false; |
| | | queueReadLock.lock(); |
| | | try |
| | | { |
| | |
| | | } |
| | | |
| | | opsSubmitted.incrementAndGet(); |
| | | submitted = true; |
| | | } |
| | | finally |
| | | { |
| | | if (!submitted) |
| | | { |
| | | pendingOpsCount.decrementAndGet(); |
| | | } |
| | | queueReadLock.unlock(); |
| | | } |
| | | } |
| | |
| | | if (pendingOperation != null) |
| | | { |
| | | pendingOperation.abort(cancelRequest); |
| | | pendingOpsCount.decrementAndGet(); |
| | | } |
| | | while ((pendingOperation = oldOpQueue.poll()) != null) |
| | | { |
| | | pendingOperation.abort(cancelRequest); |
| | | pendingOpsCount.decrementAndGet(); |
| | | } |
| | | } |
| | | finally |
| | |
| | | @Override |
| | | public boolean isIdle() |
| | | { |
| | | queueReadLock.lock(); |
| | | try |
| | | { |
| | | if (!opQueue.isEmpty()) |
| | | { |
| | | return false; |
| | | return pendingOpsCount.get() == 0; |
| | | } |
| | | |
| | | for (TraditionalWorkerThread t : workerThreads) |
| | | /** |
| | | * Notifies this work queue that a worker thread is done handling an |
| | | * operation previously taken from the queue. |
| | | */ |
| | | void operationDone() |
| | | { |
| | | if (t.isActive()) |
| | | { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | return true; |
| | | } |
| | | finally |
| | | { |
| | | queueReadLock.unlock(); |
| | | } |
| | | pendingOpsCount.decrementAndGet(); |
| | | } |
| | | |
| | | /** |