001/*
002 * Copyright 2009-2024 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2009-2024 Ping Identity Corporation
007 *
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *    http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 */
020/*
021 * Copyright (C) 2009-2024 Ping Identity Corporation
022 *
023 * This program is free software; you can redistribute it and/or modify
024 * it under the terms of the GNU General Public License (GPLv2 only)
025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
026 * as published by the Free Software Foundation.
027 *
028 * This program is distributed in the hope that it will be useful,
029 * but WITHOUT ANY WARRANTY; without even the implied warranty of
030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
031 * GNU General Public License for more details.
032 *
033 * You should have received a copy of the GNU General Public License
034 * along with this program; if not, see <http://www.gnu.org/licenses>.
035 */
036package com.unboundid.ldap.sdk;
037
038
039
040import java.io.Serializable;
041import java.util.concurrent.atomic.AtomicLong;
042
043import com.unboundid.util.Mutable;
044import com.unboundid.util.NotNull;
045import com.unboundid.util.ThreadSafety;
046import com.unboundid.util.ThreadSafetyLevel;
047
048
049
050/**
051 * This class provides a data structure with information about usage of an LDAP
052 * connection pool.  Calls to update statistics maintained by this class are
053 * threadsafe, but attempts to access different statistics may not be consistent
054 * if operations may be in progress in the connection pool.
055 * <BR><BR>
056 * The set of statistics maintained for connection pools include:
057 * <UL>
058 *   <LI>The current number of connections that are available within the
059 *       pool.</LI>
060 *   <LI>The maximum number of connections that may be available within the
061 *       pool.</LI>
062 *   <LI>The total number of connections that have been successfully checked out
063 *       of the pool.</LI>
064 *   <LI>The number of connections that have been successfully checked out of
065 *       of the pool without needing to wait for a connection to become
066 *       available.
067 *   <LI>The number of connections that have been successfully checked out of
068 *       the pool after waiting for a connection to become available.</LI>
069 *   <LI>The number of connections that have been successfully checked out of
070 *       the pool after creating a new connection to service the request.</LI>
071 *   <LI>The number of failed attempts to check a connection out of the
072 *       pool.</LI>
073 *   <LI>The number of connections that have been released back to the pool as
074 *       valid.</LI>
075 *   <LI>The number of connections that have been closed as defunct.</LI>
076 *   <LI>The number of connections that have been closed as expired (i.e., that
077 *       had been established for the maximum connection age).</LI>
078 *   <LI>The number of connections that have been closed as unneeded (because
079 *       the pool already had the maximum number of available connections).</LI>
080 *   <LI>The number of successful attempts to create a new connection for use in
081 *       the pool.</LI>
082 *   <LI>The number of failed attempts to create a new connection for use in the
083 *       pool.</LI>
084 * </UL>
085 */
086@Mutable()
087@ThreadSafety(level=ThreadSafetyLevel.MOSTLY_THREADSAFE)
088public final class LDAPConnectionPoolStatistics
089       implements Serializable
090{
091  /**
092   * The serial version UID for this serializable class.
093   */
094  private static final long serialVersionUID = 1493039391352814874L;
095
096
097
098  // The number of connections that have been closed as defunct.
099  @NotNull private final AtomicLong numConnectionsClosedDefunct;
100
101  // The number of connections that have been closed because they were expired.
102  @NotNull private final AtomicLong numConnectionsClosedExpired;
103
104  // The number of connections that have been closed because they were no longer
105  // needed.
106  @NotNull private final AtomicLong numConnectionsClosedUnneeded;
107
108  // The number of failed attempts to check out a connection from the pool.
109  @NotNull private final AtomicLong numFailedCheckouts;
110
111  // The number of failed attempts to create a connection for use in the pool.
112  @NotNull private final AtomicLong numFailedConnectionAttempts;
113
114  // The number of valid connections released back to the pool.
115  @NotNull private final AtomicLong numReleasedValid;
116
117  // The number of successful attempts to check out a connection from the pool.
118  @NotNull private final AtomicLong numSuccessfulCheckouts;
119
120  // The number of successful checkout attempts that retrieved a connection from
121  // the pool after waiting for it to become available.
122  @NotNull private final AtomicLong numSuccessfulCheckoutsAfterWait;
123
124  // The number of successful checkout attempts that had to create a new
125  // connection because none were available.
126  @NotNull private final AtomicLong numSuccessfulCheckoutsNewConnection;
127
128  // The number of successful checkout attempts that were able to take an
129  // existing connection without waiting.
130  @NotNull private final AtomicLong numSuccessfulCheckoutsWithoutWait;
131
132  // The number successful attempts to create a connection for use in the pool.
133  @NotNull private final AtomicLong numSuccessfulConnectionAttempts;
134
135  // The connection pool with which these statistics are associated.
136  @NotNull private final AbstractConnectionPool pool;
137
138
139
140  /**
141   * Creates a new instance of this LDAP connection pool statistics object.  All
142   * of the counts will be initialized to zero.
143   *
144   * @param  pool  The connection pool with which these statistics are
145   *               associated.
146   */
147  public LDAPConnectionPoolStatistics(
148              @NotNull final AbstractConnectionPool pool)
149  {
150    this.pool = pool;
151
152    numSuccessfulConnectionAttempts     = new AtomicLong(0L);
153    numFailedConnectionAttempts         = new AtomicLong(0L);
154    numConnectionsClosedDefunct         = new AtomicLong(0L);
155    numConnectionsClosedExpired         = new AtomicLong(0L);
156    numConnectionsClosedUnneeded        = new AtomicLong(0L);
157    numSuccessfulCheckouts              = new AtomicLong(0L);
158    numSuccessfulCheckoutsAfterWait     = new AtomicLong(0L);
159    numSuccessfulCheckoutsNewConnection = new AtomicLong(0L);
160    numSuccessfulCheckoutsWithoutWait   = new AtomicLong(0L);
161    numFailedCheckouts                  = new AtomicLong(0L);
162    numReleasedValid                    = new AtomicLong(0L);
163  }
164
165
166
167  /**
168   * Resets all counters back to zero.
169   */
170  public void reset()
171  {
172    numSuccessfulConnectionAttempts.set(0L);
173    numFailedConnectionAttempts.set(0L);
174    numConnectionsClosedDefunct.set(0L);
175    numConnectionsClosedExpired.set(0L);
176    numConnectionsClosedUnneeded.set(0L);
177    numSuccessfulCheckouts.set(0L);
178    numSuccessfulCheckoutsAfterWait.set(0L);
179    numSuccessfulCheckoutsNewConnection.set(0L);
180    numSuccessfulCheckoutsWithoutWait.set(0L);
181    numFailedCheckouts.set(0L);
182    numReleasedValid.set(0L);
183  }
184
185
186
187  /**
188   * Retrieves the number of connections that have been successfully created for
189   * use in conjunction with the connection pool.
190   *
191   * @return  The number of connections that have been created for use in
192   *          conjunction with the connection pool.
193   */
194  public long getNumSuccessfulConnectionAttempts()
195  {
196    return numSuccessfulConnectionAttempts.get();
197  }
198
199
200
201  /**
202   * Increments the number of connections that have been successfully created
203   * for use in conjunction with the connection pool.
204   */
205  void incrementNumSuccessfulConnectionAttempts()
206  {
207    numSuccessfulConnectionAttempts.incrementAndGet();
208  }
209
210
211
212  /**
213   * Retrieves the number of failed attempts to create a connection for use in
214   * the connection pool.
215   *
216   * @return  The number of failed attempts to create a connection for use in
217   *          the connection pool.
218   */
219  public long getNumFailedConnectionAttempts()
220  {
221    return numFailedConnectionAttempts.get();
222  }
223
224
225
226  /**
227   * Increments the number of failed attempts to create a connection for use in
228   * the connection pool.
229   */
230  void incrementNumFailedConnectionAttempts()
231  {
232    numFailedConnectionAttempts.incrementAndGet();
233  }
234
235
236
237  /**
238   * Retrieves the number of connections that have been closed as defunct (i.e.,
239   * they are no longer believed to be valid).
240   *
241   * @return  The number of connections that have been closed as defunct.
242   */
243  public long getNumConnectionsClosedDefunct()
244  {
245    return numConnectionsClosedDefunct.get();
246  }
247
248
249
250  /**
251   * Increments the number of connections that have been closed as defunct.
252   */
253  void incrementNumConnectionsClosedDefunct()
254  {
255    numConnectionsClosedDefunct.incrementAndGet();
256  }
257
258
259
260  /**
261   * Retrieves the number of connections that have been closed as expired (i.e.,
262   * they have been established for longer than the maximum connection age for
263   * the pool).
264   *
265   * @return  The number of connections that have been closed as expired.
266   */
267  public long getNumConnectionsClosedExpired()
268  {
269    return numConnectionsClosedExpired.get();
270  }
271
272
273
274  /**
275   * Increments the number of connections that have been closed as expired.
276   */
277  void incrementNumConnectionsClosedExpired()
278  {
279    numConnectionsClosedExpired.incrementAndGet();
280  }
281
282
283
284  /**
285   * Retrieves the number of connections that have been closed as unneeded
286   * (i.e., they were created in response to heavy load but are no longer needed
287   * to meet the current load, or they were closed when the pool was closed).
288   *
289   * @return  The number of connections that have been closed as unneeded.
290   */
291  public long getNumConnectionsClosedUnneeded()
292  {
293    return numConnectionsClosedUnneeded.get();
294  }
295
296
297
298  /**
299   * Increments the number of connections that have been closed as unneeded.
300   */
301  void incrementNumConnectionsClosedUnneeded()
302  {
303    numConnectionsClosedUnneeded.incrementAndGet();
304  }
305
306
307
308  /**
309   * Retrieves the number of successful attempts to check out a connection from
310   * the pool (including connections checked out for internal use by operations
311   * processed as part of the pool).
312   *
313   * @return  The number of successful attempts to check out a connection from
314   *          the pool.
315   */
316  public long getNumSuccessfulCheckouts()
317  {
318    return numSuccessfulCheckouts.get();
319  }
320
321
322
323  /**
324   * Retrieves the number of successful attempts to check out a connection from
325   * the pool that were able to obtain an existing connection without waiting.
326   *
327   * @return  The number of successful attempts to check out a connection from
328   *          the pool that were able to obtain an existing connection without
329   *          waiting.
330   */
331  public long getNumSuccessfulCheckoutsWithoutWaiting()
332  {
333    return numSuccessfulCheckoutsWithoutWait.get();
334  }
335
336
337
338  /**
339   * Retrieves the number of successful attempts to check out a connection from
340   * the pool that had to wait for a connection to become available.
341   *
342   * @return  The number of successful attempts to check out a connection from
343   *          the pool that had to wait for a connection to become available.
344   */
345  public long getNumSuccessfulCheckoutsAfterWaiting()
346  {
347    return numSuccessfulCheckoutsAfterWait.get();
348  }
349
350
351
352  /**
353   * Retrieves the number of successful attempts to check out a connection from
354   * the pool that had to create a new connection because no existing
355   * connections were available.
356   *
357   * @return  The number of successful attempts to check out a connection from
358   *          the pool that had to create a new connection because no existing
359   *          connections were available.
360   */
361  public long getNumSuccessfulCheckoutsNewConnection()
362  {
363    return numSuccessfulCheckoutsNewConnection.get();
364  }
365
366
367
368  /**
369   * Increments the number of successful attempts to check out a connection from
370   * the pool without waiting.
371   */
372  void incrementNumSuccessfulCheckoutsWithoutWaiting()
373  {
374   numSuccessfulCheckouts.incrementAndGet();
375   numSuccessfulCheckoutsWithoutWait.incrementAndGet();
376  }
377
378
379
380  /**
381   * Increments the number of successful attempts to check out a connection from
382   * the pool after waiting.
383   */
384  void incrementNumSuccessfulCheckoutsAfterWaiting()
385  {
386   numSuccessfulCheckouts.incrementAndGet();
387   numSuccessfulCheckoutsAfterWait.incrementAndGet();
388  }
389
390
391
392  /**
393   * Increments the number of successful attempts to check out a connection from
394   * the pool after creating a new connection.
395   */
396  void incrementNumSuccessfulCheckoutsNewConnection()
397  {
398   numSuccessfulCheckouts.incrementAndGet();
399   numSuccessfulCheckoutsNewConnection.incrementAndGet();
400  }
401
402
403
404  /**
405   * Retrieves the number of failed attempts to check out a connection from
406   * the pool (including connections checked out for internal use by operations
407   * processed as part of the pool).
408   *
409   * @return  The number of failed attempts to check out a connection from
410   *          the pool.
411   */
412  public long getNumFailedCheckouts()
413  {
414    return numFailedCheckouts.get();
415  }
416
417
418
419  /**
420   * Increments the number of failed attempts to check out a connection from
421   * the pool.
422   */
423  void incrementNumFailedCheckouts()
424  {
425   numFailedCheckouts.incrementAndGet();
426  }
427
428
429
430  /**
431   * Retrieves the number of times a valid, usable connection has been released
432   * back to the pool after being checked out (including connections checked out
433   * for internal use by operations processed within the pool).
434   *
435   * @return  The number of times a valid connection has been released back to
436   *          the pool.
437   */
438  public long getNumReleasedValid()
439  {
440    return numReleasedValid.get();
441  }
442
443
444
445  /**
446   * Increments the number of times a valid, usable connection has been released
447   * back to the pool.
448   */
449  void incrementNumReleasedValid()
450  {
451   numReleasedValid.incrementAndGet();
452  }
453
454
455
456  /**
457   * Retrieves the number of connections currently available for use in the
458   * pool, if that information is available.
459   *
460   * @return  The number of connections currently available for use in the pool,
461   *          or -1 if that is not applicable for the associated connection pool
462   *          implementation.
463   */
464  public int getNumAvailableConnections()
465  {
466    return pool.getCurrentAvailableConnections();
467  }
468
469
470
471  /**
472   * Retrieves the maximum number of connections that may be available in the
473   * pool at any time, if that information is available.
474   *
475   * @return  The maximum number of connections that may be available in the
476   *          pool at any time, or -1 if that is not applicable for the
477   *          associated connection pool implementation.
478   */
479  public int getMaximumAvailableConnections()
480  {
481    return pool.getMaximumAvailableConnections();
482  }
483
484
485
486  /**
487   * Retrieves a string representation of this LDAP connection pool statistics
488   * object.
489   *
490   * @return  A string representation of this LDAP connection pool statistics
491   *          object.
492   */
493  @Override()
494  @NotNull()
495  public String toString()
496  {
497    final StringBuilder buffer = new StringBuilder();
498    toString(buffer);
499    return buffer.toString();
500  }
501
502
503
504  /**
505   * Appends a string representation of this LDAP connection pool statistics
506   * object to the provided buffer.
507   *
508   * @param  buffer  The buffer to which the string representation should be
509   *                 appended.
510   */
511  public void toString(@NotNull final StringBuilder buffer)
512  {
513    final long availableConns      = pool.getCurrentAvailableConnections();
514    final long maxConns            = pool.getMaximumAvailableConnections();
515    final long successfulConns     = numSuccessfulConnectionAttempts.get();
516    final long failedConns         = numFailedConnectionAttempts.get();
517    final long connsClosedDefunct  = numConnectionsClosedDefunct.get();
518    final long connsClosedExpired  = numConnectionsClosedExpired.get();
519    final long connsClosedUnneeded = numConnectionsClosedUnneeded.get();
520    final long successfulCheckouts = numSuccessfulCheckouts.get();
521    final long failedCheckouts     = numFailedCheckouts.get();
522    final long releasedValid       = numReleasedValid.get();
523
524    buffer.append("LDAPConnectionPoolStatistics(numAvailableConnections=");
525    buffer.append(availableConns);
526    buffer.append(", maxAvailableConnections=");
527    buffer.append(maxConns);
528    buffer.append(", numSuccessfulConnectionAttempts=");
529    buffer.append(successfulConns);
530    buffer.append(", numFailedConnectionAttempts=");
531    buffer.append(failedConns);
532    buffer.append(", numConnectionsClosedDefunct=");
533    buffer.append(connsClosedDefunct);
534    buffer.append(", numConnectionsClosedExpired=");
535    buffer.append(connsClosedExpired);
536    buffer.append(", numConnectionsClosedUnneeded=");
537    buffer.append(connsClosedUnneeded);
538    buffer.append(", numSuccessfulCheckouts=");
539    buffer.append(successfulCheckouts);
540    buffer.append(", numFailedCheckouts=");
541    buffer.append(failedCheckouts);
542    buffer.append(", numReleasedValid=");
543    buffer.append(releasedValid);
544    buffer.append(')');
545  }
546}