/* * The contents of this file are subject to the terms of the Common Development and * Distribution License (the License). You may not use this file except in compliance with the * License. * * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the * specific language governing permission and limitations under the License. * * When distributing Covered Software, include this CDDL Header Notice in each file and include * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL * Header, with the fields enclosed by brackets [] replaced by your own identifying * information: "Portions Copyright [year] [name of copyright owner]". * * Copyright 2010 Sun Microsystems, Inc. * Portions copyright 2011-2016 ForgeRock AS. */ package org.forgerock.opendj.grizzly; import java.io.IOException; import org.forgerock.i18n.LocalizableMessage; import org.forgerock.i18n.slf4j.LocalizedLogger; import org.glassfish.grizzly.memory.PooledMemoryManager; import org.glassfish.grizzly.nio.transport.TCPNIOTransport; import org.glassfish.grizzly.nio.transport.TCPNIOTransportBuilder; import org.glassfish.grizzly.strategies.SameThreadIOStrategy; import org.glassfish.grizzly.threadpool.ThreadPoolConfig; import com.forgerock.opendj.util.ReferenceCountedObject; /** * The default {@link TCPNIOTransport} which all {@code LDAPConnectionFactory}s * and {@code LDAPListener}s will use unless otherwise specified in their * options. */ final class ServerTCPNIOTransport extends ReferenceCountedObject { private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); static final ServerTCPNIOTransport SERVER_TRANSPORT = new ServerTCPNIOTransport(); private static final long MB = 1024 * 1024; private ServerTCPNIOTransport() { // Prevent instantiation. } @Override protected void destroyInstance(final TCPNIOTransport instance) { try { instance.shutdownNow(); } catch (final IOException e) { // TODO: I18N logger.warn(LocalizableMessage.raw("An error occurred while shutting down the Grizzly transport", e)); } } @Override protected TCPNIOTransport newInstance() { final TCPNIOTransportBuilder builder = TCPNIOTransportBuilder.newInstance(); builder.setIOStrategy(SameThreadIOStrategy.getInstance()); // Calculate thread counts. final int cpus = Runtime.getRuntime().availableProcessors(); // Calculate the number of selector threads. final String selectorsStr = System.getProperty("org.forgerock.opendj.transport.selectors"); final int selectorThreadCount; if (selectorsStr != null) { selectorThreadCount = Integer.parseInt(selectorsStr); } else { selectorThreadCount = Math.max(5, (cpus / 2) - 1); } builder.setSelectorThreadPoolConfig( ThreadPoolConfig.defaultConfig() .setCorePoolSize(selectorThreadCount) .setMaxPoolSize(selectorThreadCount) .setPoolName("OpenDJ LDAP SDK Grizzly selector thread")); // Parse IO related options. final String lingerStr = System.getProperty("org.forgerock.opendj.transport.linger"); if (lingerStr != null) { // Disabled by default. builder.setLinger(Integer.parseInt(lingerStr)); } final String tcpNoDelayStr = System.getProperty("org.forgerock.opendj.transport.tcpNoDelay"); if (tcpNoDelayStr != null) { // Enabled by default. builder.setTcpNoDelay(Boolean.parseBoolean(tcpNoDelayStr)); } final String reuseAddressStr = System.getProperty("org.forgerock.opendj.transport.reuseAddress"); if (reuseAddressStr != null) { // Enabled by default. builder.setReuseAddress(Boolean.parseBoolean(reuseAddressStr)); } float heapPercent; if (Runtime.getRuntime().maxMemory() < 1024 * MB) { // Low heap heapPercent = 0.01f; } else { // Compute a percentage to try to reach roughly 64Mb (big enough (tm)) heapPercent = 64f * MB / Runtime.getRuntime().maxMemory(); } // Force usage of PooledMemoryManager which allows to use grizzly's buffers across threads. builder.setMemoryManager(new PooledMemoryManager( 1024, // Initial buffer size 3, // Number of pools (with growing factor below this give us pools of 1K, 4K, 16k buffers) 4, // Growing factor to apply on the size of the buffer polled by the next pool selectorThreadCount, // Number of pool slices that every pool will stripe allocation requests across heapPercent, // The percentage of the heap that this manager will use when populating the pools (5%) 1f, // The percentage of buffers to be pre-allocated during MemoryManager initialization (100%) true // true to use direct buffers or false to use heap buffers )); final TCPNIOTransport transport = builder.build(); // FIXME: raise bug in Grizzly. We should not need to do this, but // failure to do so causes many deadlocks. transport.setSelectorRunnersCount(selectorThreadCount); try { transport.start(); } catch (final IOException e) { throw new RuntimeException(e); } return transport; } }