/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2013 ForgeRock AS */ package org.opends.server.core; import java.util.concurrent.atomic.AtomicInteger; import org.opends.server.types.DirectoryException; import org.opends.server.types.Operation; /** * A QueueingStrategy that concurrently enqueues a bounded number of operations * to the DirectoryServer work queue. If the maximum number of concurrently * enqueued operations has been reached or if the work queue if full, then the * operation will be executed on the current thread. */ public class BoundedWorkQueueStrategy implements QueueingStrategy { /** * The number of concurrently running operations for this * BoundedWorkQueueStrategy. */ private final AtomicInteger nbRunningOperations = new AtomicInteger(0); /** Maximum number of concurrent operations. 0 means "unlimited". */ private final int maxNbConcurrentOperations; /** * Constructor for BoundedWorkQueueStrategy. * * @param maxNbConcurrentOperations * the maximum number of operations that can be concurrently enqueued * to the DirectoryServer work queue */ public BoundedWorkQueueStrategy(Integer maxNbConcurrentOperations) { if (maxNbConcurrentOperations != null) { this.maxNbConcurrentOperations = maxNbConcurrentOperations; } else { int cpus = Runtime.getRuntime().availableProcessors(); int numWorkerThreads = DirectoryServer.getWorkQueue().getNumWorkerThreads(); this.maxNbConcurrentOperations = Math.max(cpus, numWorkerThreads * 25 / 100); } } /** {@inheritDoc} */ @Override public void enqueueRequest(final Operation operation) throws DirectoryException { if (!operation.getClientConnection().isConnectionValid()) { // do not bother enqueueing return; } if (maxNbConcurrentOperations == 0) { // unlimited concurrent operations if (!DirectoryServer.tryEnqueueRequest(operation)) { // avoid potential deadlocks by running in the current thread operation.run(); } } else if (nbRunningOperations.getAndIncrement() > maxNbConcurrentOperations || !DirectoryServer.tryEnqueueRequest(wrap(operation))) { // avoid potential deadlocks by running in the current thread try { operation.run(); } finally { // only decrement when the operation is run synchronously. // Otherwise it'll be decremented twice (once more in the wrapper). nbRunningOperations.decrementAndGet(); } } } private Operation wrap(final Operation operation) { if (operation instanceof AbandonOperation) { return new AbandonOperationWrapper((AbandonOperation) operation) { @Override public void run() { runWrapped(operation); } }; } else if (operation instanceof AddOperation) { return new AddOperationWrapper((AddOperation) operation) { @Override public void run() { runWrapped(operation); } }; } else if (operation instanceof BindOperation) { return new BindOperationWrapper((BindOperation) operation) { @Override public void run() { runWrapped(operation); } }; } else if (operation instanceof CompareOperation) { return new CompareOperationWrapper((CompareOperation) operation) { @Override public void run() { runWrapped(operation); } }; } else if (operation instanceof DeleteOperation) { return new DeleteOperationWrapper((DeleteOperation) operation) { @Override public void run() { runWrapped(operation); } }; } else if (operation instanceof ExtendedOperation) { return new ExtendedOperationWrapper((ExtendedOperation) operation) { @Override public void run() { runWrapped(operation); } }; } else if (operation instanceof ModifyDNOperation) { return new ModifyDNOperationWrapper((ModifyDNOperation) operation) { @Override public void run() { runWrapped(operation); } }; } else if (operation instanceof ModifyOperation) { return new ModifyOperationWrapper((ModifyOperation) operation) { @Override public void run() { runWrapped(operation); } }; } else if (operation instanceof SearchOperation) { return new SearchOperationWrapper((SearchOperation) operation) { @Override public void run() { runWrapped(operation); } }; } else if (operation instanceof UnbindOperation) { return new UnbindOperationWrapper((UnbindOperation) operation) { @Override public void run() { runWrapped(operation); } }; } else { throw new RuntimeException( "Not implemented for " + operation == null ? null : operation .getClass().getName()); } } /** * Execute the provided operation and decrement the number of currently * running operations after it has finished executing. * * @param the * operation to execute */ private void runWrapped(final Operation operation) { try { operation.run(); } finally { nbRunningOperations.decrementAndGet(); } } }