001/* 002 * Copyright 2018-2019 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2018-2019 Ping Identity Corporation 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021package com.unboundid.ldap.sdk; 022 023 024 025import java.util.concurrent.atomic.AtomicReference; 026import java.util.logging.Level; 027 028import com.unboundid.util.Debug; 029import com.unboundid.util.DebugType; 030import com.unboundid.util.ThreadSafety; 031import com.unboundid.util.ThreadSafetyLevel; 032 033 034 035/** 036 * This class provides an implementation of an LDAP connection pool health check 037 * that periodically monitors the number of available connections in the pool. 038 * If the number of available connections has been consistently greater than a 039 * specified minimum for at least a given length of time, then the number of 040 * available connections will be reduced to that minimum. Note that the 041 * size of the pool will only be checked at interval's specified by the 042 * {@link AbstractConnectionPool#getHealthCheckIntervalMillis()} method, so it 043 * is possible that the number of available connections may have dipped below 044 * that minimum on one or more occasions between checks. Also note that this 045 * health check can only be used on instances of the 046 * {@link LDAPConnectionPool} class; it cannot be used with 047 * {@link LDAPThreadLocalConnectionPool} instances. 048 */ 049@ThreadSafety(level= ThreadSafetyLevel.COMPLETELY_THREADSAFE) 050public final class PruneUnneededConnectionsLDAPConnectionPoolHealthCheck 051 extends LDAPConnectionPoolHealthCheck 052{ 053 // A reference to the first time at which the number of available connections 054 // exceeded the minimum number of available connections. It may reference a 055 // null value if the last check indicated that the number of available 056 // connections was not larger than the configured minimum. 057 private final AtomicReference<Long> 058 earliestTimeWithMoreThanMinAvailableConnections; 059 060 // The minimum number of connections that should be maintained in the 061 // connection pool. This health check will only remove connections if the 062 // pool has more than this number of connections for at least the specified 063 // duration. 064 private final int minAvailableConnections; 065 066 // The minimum length of time in milliseconds that the pool should have had 067 // at least the specified minimum number of available connections before any 068 // connections may be removed. 069 private final long minDurationMillisExceedingMinAvailableConnections; 070 071 072 073 /** 074 * Creates a new instance of this LDAP connection pool health check with the 075 * provided information. 076 * 077 * @param minAvailableConnections 078 * The minimum number of connections that should be maintained in 079 * the connection pool. This health check will only remove 080 * connections if the pool has more than this number of 081 * connections for at least the specified duration. A value that 082 * is less than or equal to zero indicates that no minimum number 083 * of connections needs to be maintained. 084 * @param minDurationMillisExceedingMinAvailableConnections 085 * The minimum length of time in milliseconds that the pool 086 * should have reported at least the specified minimum number of 087 * available connections before any connections may be removed. 088 * Note that the number of connections will only be checked at 089 * intervals specified by the 090 * {@link AbstractConnectionPool#getHealthCheckIntervalMillis()} 091 * method, so it may be possible for the number of available 092 * connections to dip below this value one or more time between 093 * intervals and still cause the pool to be reduced in size. A 094 * value that is less than or equal to zero indicates that the 095 * pool size should be reduced to the configured minimum any time 096 * there are more than that number of connections available. 097 */ 098 public PruneUnneededConnectionsLDAPConnectionPoolHealthCheck( 099 final int minAvailableConnections, 100 final long minDurationMillisExceedingMinAvailableConnections) 101 { 102 this.minAvailableConnections = Math.max(0, minAvailableConnections); 103 this.minDurationMillisExceedingMinAvailableConnections = Math.max(0L, 104 minDurationMillisExceedingMinAvailableConnections); 105 106 earliestTimeWithMoreThanMinAvailableConnections = new AtomicReference<>(); 107 } 108 109 110 111 /** 112 * Retrieves the minimum number of connections that should be maintained in 113 * the connection pool. This health check will only remove connections if the 114 * pool has more than this number of connections for at least the specified 115 * duration. 116 * 117 * @return The minimum number of connections that should be maintained in the 118 * connection pool. 119 */ 120 public int getMinAvailableConnections() 121 { 122 return minAvailableConnections; 123 } 124 125 126 127 /** 128 * Retrieves the minimum length of time in milliseconds that the pool should 129 * have reported at least the specified minimum number of available 130 * connections before any connections may be removed. Note that the number of 131 * connections will only be checked at intervals specified by the 132 * {@link AbstractConnectionPool#getHealthCheckIntervalMillis()} method, so it 133 * may be possible for the number of available connections to dip below this 134 * value one or more time between intervals and still cause the pool to be 135 * reduced in size. 136 * 137 * @return The minimum length of time in milliseconds that the pool should 138 * have reported at least the specified minimum number of available 139 * connections before any connections may be removed. 140 */ 141 public long getMinDurationMillisExceedingMinAvailableConnections() 142 { 143 return minDurationMillisExceedingMinAvailableConnections; 144 } 145 146 147 148 /** 149 * {@inheritDoc} 150 */ 151 @Override() 152 public void performPoolMaintenance(final AbstractConnectionPool pool) 153 { 154 if (! (pool instanceof LDAPConnectionPool)) 155 { 156 Debug.debug(Level.WARNING, DebugType.CONNECT, 157 "Only " + LDAPConnectionPool.class.getName() + 158 " instances may be used in conjunction with the " + 159 "PruneUnneededConnectionsLDAPConnectionPoolHealthCheck. " + 160 "The provided pool had an incompatible type of " + 161 pool.getClass().getName() + '.'); 162 163 earliestTimeWithMoreThanMinAvailableConnections.set(null); 164 return; 165 } 166 167 final int availableConnections = pool.getCurrentAvailableConnections(); 168 if (availableConnections <= minAvailableConnections) 169 { 170 earliestTimeWithMoreThanMinAvailableConnections.set(null); 171 return; 172 } 173 174 final Long earliestTime = 175 earliestTimeWithMoreThanMinAvailableConnections.get(); 176 if (earliestTime == null) 177 { 178 if (minDurationMillisExceedingMinAvailableConnections <= 0L) 179 { 180 ((LDAPConnectionPool) pool).shrinkPool(minAvailableConnections); 181 } 182 else 183 { 184 earliestTimeWithMoreThanMinAvailableConnections.set( 185 System.currentTimeMillis()); 186 } 187 } 188 else 189 { 190 final long millisWithMoreThanMinAvailableConnections = 191 System.currentTimeMillis() - earliestTime; 192 if (millisWithMoreThanMinAvailableConnections >= 193 minDurationMillisExceedingMinAvailableConnections) 194 { 195 ((LDAPConnectionPool) pool).shrinkPool(minAvailableConnections); 196 earliestTimeWithMoreThanMinAvailableConnections.set(null); 197 } 198 } 199 } 200 201 202 203 /** 204 * {@inheritDoc} 205 */ 206 @Override() 207 public void toString(final StringBuilder buffer) 208 { 209 buffer.append("PruneUnneededConnectionsLDAPConnectionPoolHealthCheck(" + 210 "minAvailableConnections="); 211 buffer.append(minAvailableConnections); 212 buffer.append(", minDurationMillisExceedingMinAvailableConnections="); 213 buffer.append(minDurationMillisExceedingMinAvailableConnections); 214 buffer.append(')'); 215 } 216}