AbandonedTrace.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.dbcp2;

  18. import java.lang.ref.WeakReference;
  19. import java.sql.SQLException;
  20. import java.time.Instant;
  21. import java.util.ArrayList;
  22. import java.util.Collections;
  23. import java.util.Iterator;
  24. import java.util.List;
  25. import java.util.function.Consumer;

  26. import org.apache.commons.pool2.TrackedUse;

  27. /**
  28.  * Tracks connection usage for recovering and reporting abandoned connections.
  29.  * <p>
  30.  * The JDBC Connection, Statement, and ResultSet classes extend this class.
  31.  * </p>
  32.  *
  33.  * @since 2.0
  34.  */
  35. public class AbandonedTrace implements TrackedUse, AutoCloseable {

  36.     static void add(final AbandonedTrace receiver, final AbandonedTrace trace) {
  37.         if (receiver != null) {
  38.             receiver.addTrace(trace);
  39.         }
  40.     }

  41.     /** A list of objects created by children of this object. */
  42.     private final List<WeakReference<AbandonedTrace>> traceList = new ArrayList<>();

  43.     /** Last time this connection was used. */
  44.     private volatile Instant lastUsedInstant = Instant.EPOCH;

  45.     /**
  46.      * Creates a new AbandonedTrace without config and without doing abandoned tracing.
  47.      */
  48.     public AbandonedTrace() {
  49.         init(null);
  50.     }

  51.     /**
  52.      * Constructs a new AbandonedTrace with a parent object.
  53.      *
  54.      * @param parent
  55.      *            AbandonedTrace parent object.
  56.      */
  57.     public AbandonedTrace(final AbandonedTrace parent) {
  58.         init(parent);
  59.     }

  60.     /**
  61.      * Adds an object to the list of objects being traced.
  62.      *
  63.      * @param trace
  64.      *            AbandonedTrace object to add.
  65.      */
  66.     protected void addTrace(final AbandonedTrace trace) {
  67.         synchronized (this.traceList) {
  68.             this.traceList.add(new WeakReference<>(trace));
  69.         }
  70.         setLastUsed();
  71.     }

  72.     /**
  73.      * Clears the list of objects being traced by this object.
  74.      */
  75.     protected void clearTrace() {
  76.         synchronized (this.traceList) {
  77.             this.traceList.clear();
  78.         }
  79.     }

  80.     /**
  81.      * Subclasses can implement this nop.
  82.      *
  83.      * @throws SQLException Ignored here, for subclasses.
  84.      * @since 2.10.0
  85.      */
  86.     @Override
  87.     public void close() throws SQLException {
  88.         // nop
  89.     }

  90.     /**
  91.      * Closes this resource and if an exception is caught, then calls {@code exceptionHandler}.
  92.      *
  93.      * @param exceptionHandler Consumes exception thrown closing this resource.
  94.      * @since 2.10.0
  95.      */
  96.     protected void close(final Consumer<Exception> exceptionHandler) {
  97.         Utils.close(this, exceptionHandler);
  98.     }

  99.     /**
  100.      * Gets the last time this object was used in milliseconds.
  101.      *
  102.      * @return long time in milliseconds.
  103.      */
  104.     @Override
  105.     @Deprecated
  106.     public long getLastUsed() {
  107.         return lastUsedInstant.toEpochMilli();
  108.     }

  109.     @Override
  110.     public Instant getLastUsedInstant() {
  111.         return lastUsedInstant;
  112.     }

  113.     /**
  114.      * Gets a list of objects being traced by this object.
  115.      *
  116.      * @return List of objects.
  117.      */
  118.     protected List<AbandonedTrace> getTrace() {
  119.         final int size = traceList.size();
  120.         if (size == 0) {
  121.             return Collections.emptyList();
  122.         }
  123.         final ArrayList<AbandonedTrace> result = new ArrayList<>(size);
  124.         synchronized (this.traceList) {
  125.             final Iterator<WeakReference<AbandonedTrace>> iter = traceList.iterator();
  126.             while (iter.hasNext()) {
  127.                 final AbandonedTrace trace = iter.next().get();
  128.                 if (trace == null) {
  129.                     // Clean-up since we are here anyway
  130.                     iter.remove();
  131.                 } else {
  132.                     result.add(trace);
  133.                 }
  134.             }
  135.         }
  136.         return result;
  137.     }

  138.     /**
  139.      * Initializes abandoned tracing for this object.
  140.      *
  141.      * @param parent
  142.      *            AbandonedTrace parent object.
  143.      */
  144.     private void init(final AbandonedTrace parent) {
  145.         add(parent, this);
  146.     }

  147.     /**
  148.      * Removes this object the source object is tracing.
  149.      *
  150.      * @param source The object tracing
  151.      * @since 2.7.0
  152.      */
  153.     protected void removeThisTrace(final Object source) {
  154.         if (source instanceof AbandonedTrace) {
  155.             AbandonedTrace.class.cast(source).removeTrace(this);
  156.         }
  157.     }

  158.     /**
  159.      * Removes a child object this object is tracing.
  160.      *
  161.      * @param trace
  162.      *            AbandonedTrace object to remove.
  163.      */
  164.     protected void removeTrace(final AbandonedTrace trace) {
  165.         synchronized (this.traceList) {
  166.             final Iterator<WeakReference<AbandonedTrace>> iter = traceList.iterator();
  167.             while (iter.hasNext()) {
  168.                 final AbandonedTrace traceInList = iter.next().get();
  169.                 if (trace != null && trace.equals(traceInList)) {
  170.                     iter.remove();
  171.                     break;
  172.                 }
  173.                 if (traceInList == null) {
  174.                     // Clean-up since we are here anyway
  175.                     iter.remove();
  176.                 }
  177.             }
  178.         }
  179.     }

  180.     /**
  181.      * Sets the time this object was last used to the current time in milliseconds.
  182.      */
  183.     protected void setLastUsed() {
  184.         lastUsedInstant = Instant.now();
  185.     }

  186.     /**
  187.      * Sets the instant this object was last used.
  188.      *
  189.      * @param lastUsedInstant
  190.      *            instant.
  191.      * @since 2.10.0
  192.      */
  193.     protected void setLastUsed(final Instant lastUsedInstant) {
  194.         this.lastUsedInstant = lastUsedInstant;
  195.     }

  196.     /**
  197.      * Sets the time in milliseconds this object was last used.
  198.      *
  199.      * @param lastUsedMillis
  200.      *            time in milliseconds.
  201.      * @deprecated Use {@link #setLastUsed(Instant)}
  202.      */
  203.     @Deprecated
  204.     protected void setLastUsed(final long lastUsedMillis) {
  205.         this.lastUsedInstant = Instant.ofEpochMilli(lastUsedMillis);
  206.     }
  207. }