DefaultPooledObject.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.pool2.impl;

  18. import java.io.PrintWriter;
  19. import java.time.Clock;
  20. import java.time.Duration;
  21. import java.time.Instant;
  22. import java.util.Deque;

  23. import org.apache.commons.pool2.PooledObject;
  24. import org.apache.commons.pool2.PooledObjectState;
  25. import org.apache.commons.pool2.TrackedUse;

  26. /**
  27.  * This wrapper is used to track the additional information, such as state, for
  28.  * the pooled objects.
  29.  * <p>
  30.  * This class is intended to be thread-safe.
  31.  * </p>
  32.  *
  33.  * @param <T> the type of object in the pool
  34.  * @since 2.0
  35.  */
  36. public class DefaultPooledObject<T> implements PooledObject<T> {

  37.     private final T object;
  38.     private PooledObjectState state = PooledObjectState.IDLE; // @GuardedBy("this") to ensure transitions are valid
  39.     private final Clock systemClock = Clock.systemUTC();
  40.     private final Instant createInstant = now();

  41.     private volatile Instant lastBorrowInstant = createInstant;
  42.     private volatile Instant lastUseInstant = createInstant;
  43.     private volatile Instant lastReturnInstant = createInstant;
  44.     private volatile boolean logAbandoned;
  45.     private volatile CallStack borrowedBy = NoOpCallStack.INSTANCE;
  46.     private volatile CallStack usedBy = NoOpCallStack.INSTANCE;
  47.     private volatile long borrowedCount;

  48.     /**
  49.      * Creates a new instance that wraps the provided object so that the pool can
  50.      * track the state of the pooled object.
  51.      *
  52.      * @param object The object to wrap
  53.      */
  54.     public DefaultPooledObject(final T object) {
  55.         this.object = object;
  56.     }

  57.     /**
  58.      * Allocates the object.
  59.      *
  60.      * @return {@code true} if the original state was {@link PooledObjectState#IDLE IDLE}
  61.      */
  62.     @Override
  63.     public synchronized boolean allocate() {
  64.         if (state == PooledObjectState.IDLE) {
  65.             state = PooledObjectState.ALLOCATED;
  66.             lastBorrowInstant = now();
  67.             lastUseInstant = lastBorrowInstant;
  68.             borrowedCount++;
  69.             if (logAbandoned) {
  70.                 borrowedBy.fillInStackTrace();
  71.             }
  72.             return true;
  73.         }
  74.         if (state == PooledObjectState.EVICTION) {
  75.             // TODO Allocate anyway and ignore eviction test
  76.             state = PooledObjectState.EVICTION_RETURN_TO_HEAD;
  77.         }
  78.         // TODO if validating and testOnBorrow == true then pre-allocate for
  79.         // performance
  80.         return false;
  81.     }

  82.     @Override
  83.     public int compareTo(final PooledObject<T> other) {
  84.         final int compareTo = getLastReturnInstant().compareTo(other.getLastReturnInstant());
  85.         if (compareTo == 0) {
  86.             // Make sure the natural ordering is broadly consistent with equals
  87.             // although this will break down if distinct objects have the same
  88.             // identity hash code.
  89.             // see java.lang.Comparable Javadocs
  90.             return System.identityHashCode(this) - System.identityHashCode(other);
  91.         }
  92.         return compareTo;
  93.     }

  94.     /**
  95.      * Deallocates the object and sets it {@link PooledObjectState#IDLE IDLE}
  96.      * if it is currently {@link PooledObjectState#ALLOCATED ALLOCATED}
  97.      * or {@link PooledObjectState#RETURNING RETURNING}.
  98.      *
  99.      * @return {@code true} if the state was {@link PooledObjectState#ALLOCATED ALLOCATED}
  100.      *         or {@link PooledObjectState#RETURNING RETURNING}.
  101.      */
  102.     @Override
  103.     public synchronized boolean deallocate() {
  104.         if (state == PooledObjectState.ALLOCATED || state == PooledObjectState.RETURNING) {
  105.             state = PooledObjectState.IDLE;
  106.             lastReturnInstant = now();
  107.             borrowedBy.clear();
  108.             return true;
  109.         }

  110.         return false;
  111.     }

  112.     @Override
  113.     public synchronized boolean endEvictionTest(
  114.             final Deque<PooledObject<T>> idleQueue) {
  115.         if (state == PooledObjectState.EVICTION) {
  116.             state = PooledObjectState.IDLE;
  117.             return true;
  118.         }
  119.         if (state == PooledObjectState.EVICTION_RETURN_TO_HEAD) {
  120.             state = PooledObjectState.IDLE;
  121.             idleQueue.offerFirst(this);
  122.         }

  123.         return false;
  124.     }

  125.     @Override
  126.     public long getActiveTimeMillis() {
  127.         return getActiveDuration().toMillis();
  128.     }

  129.     /**
  130.      * Gets the number of times this object has been borrowed.
  131.      * @return The number of times this object has been borrowed.
  132.      * @since 2.1
  133.      */
  134.     @Override
  135.     public long getBorrowedCount() {
  136.         return borrowedCount;
  137.     }

  138.     @Override
  139.     public Instant getCreateInstant() {
  140.         return createInstant;
  141.     }

  142.     @Override
  143.     public long getCreateTime() {
  144.         return createInstant.toEpochMilli();
  145.     }

  146.     @Override
  147.     public Duration getIdleDuration() {
  148.         // elapsed may be negative if:
  149.         // - another thread updates lastReturnInstant during the calculation window
  150.         // - System.currentTimeMillis() is not monotonic (e.g. system time is set back)
  151.         final Duration elapsed = Duration.between(lastReturnInstant, now());
  152.         return elapsed.isNegative() ? Duration.ZERO : elapsed;
  153.     }

  154.     @Override
  155.     public Duration getIdleTime() {
  156.         return getIdleDuration();
  157.     }

  158.     @Override
  159.     public long getIdleTimeMillis() {
  160.         return getIdleDuration().toMillis();
  161.     }

  162.     @Override
  163.     public Instant getLastBorrowInstant() {
  164.         return lastBorrowInstant;
  165.     }

  166.     @Override
  167.     public long getLastBorrowTime() {
  168.         return lastBorrowInstant.toEpochMilli();
  169.     }

  170.     @Override
  171.     public Instant getLastReturnInstant() {
  172.         return lastReturnInstant;
  173.     }

  174.     @Override
  175.     public long getLastReturnTime() {
  176.         return lastReturnInstant.toEpochMilli();
  177.     }

  178.     /**
  179.      * Gets an estimate of the last time this object was used.  If the class
  180.      * of the pooled object implements {@link TrackedUse}, what is returned is
  181.      * the maximum of {@link TrackedUse#getLastUsedInstant()} and
  182.      * {@link #getLastBorrowTime()}; otherwise this method gives the same
  183.      * value as {@link #getLastBorrowTime()}.
  184.      *
  185.      * @return the last Instant this object was used.
  186.      */
  187.     @Override
  188.     public Instant getLastUsedInstant() {
  189.         if (object instanceof TrackedUse) {
  190.             return PoolImplUtils.max(((TrackedUse) object).getLastUsedInstant(), lastUseInstant);
  191.         }
  192.         return lastUseInstant;
  193.     }

  194.     /**
  195.      * Gets an estimate of the last time this object was used.  If the class
  196.      * of the pooled object implements {@link TrackedUse}, what is returned is
  197.      * the maximum of {@link TrackedUse#getLastUsedInstant()} and
  198.      * {@link #getLastBorrowTime()}; otherwise this method gives the same
  199.      * value as {@link #getLastBorrowTime()}.
  200.      *
  201.      * @return the last time this object was used
  202.      */
  203.     @Override
  204.     public long getLastUsedTime() {
  205.         return getLastUsedInstant().toEpochMilli();
  206.     }

  207.     @Override
  208.     public T getObject() {
  209.         return object;
  210.     }

  211.     /**
  212.      * Gets the state of this object.
  213.      * @return state
  214.      */
  215.     @Override
  216.     public synchronized PooledObjectState getState() {
  217.         return state;
  218.     }

  219.     /**
  220.      * Sets the state to {@link PooledObjectState#INVALID INVALID}.
  221.      */
  222.     @Override
  223.     public synchronized void invalidate() {
  224.         state = PooledObjectState.INVALID;
  225.     }

  226.     /**
  227.      * Marks the pooled object as {@link PooledObjectState#ABANDONED ABANDONED}.
  228.      */
  229.     @Override
  230.     public synchronized void markAbandoned() {
  231.         state = PooledObjectState.ABANDONED;
  232.     }

  233.     /**
  234.      * Marks the pooled object as {@link PooledObjectState#RETURNING RETURNING}.
  235.      */
  236.     @Override
  237.     public synchronized void markReturning() {
  238.         state = PooledObjectState.RETURNING;
  239.     }

  240.     /**
  241.      * Gets the current instant of the clock.
  242.      *
  243.      * @return the current instant of the clock.
  244.      */
  245.     private Instant now() {
  246.         return systemClock.instant();
  247.     }

  248.     @Override
  249.     public void printStackTrace(final PrintWriter writer) {
  250.         boolean written = borrowedBy.printStackTrace(writer);
  251.         written |= usedBy.printStackTrace(writer);
  252.         if (written) {
  253.             writer.flush();
  254.         }
  255.     }

  256.     @Override
  257.     public void setLogAbandoned(final boolean logAbandoned) {
  258.         this.logAbandoned = logAbandoned;
  259.     }

  260.     /**
  261.      * Configures the stack trace generation strategy based on whether or not fully
  262.      * detailed stack traces are required. When set to false, abandoned logs may
  263.      * only include caller class information rather than method names, line numbers,
  264.      * and other normal metadata available in a full stack trace.
  265.      *
  266.      * @param requireFullStackTrace the new configuration setting for abandoned object
  267.      *                              logging
  268.      * @since 2.5
  269.      */
  270.     @Override
  271.     public void setRequireFullStackTrace(final boolean requireFullStackTrace) {
  272.         borrowedBy = CallStackUtils.newCallStack("'Pooled object created' " +
  273.             "yyyy-MM-dd HH:mm:ss Z 'by the following code has not been returned to the pool:'",
  274.             true, requireFullStackTrace);
  275.         usedBy = CallStackUtils.newCallStack("The last code to use this object was:",
  276.             false, requireFullStackTrace);
  277.     }

  278.     @Override
  279.     public synchronized boolean startEvictionTest() {
  280.         if (state == PooledObjectState.IDLE) {
  281.             state = PooledObjectState.EVICTION;
  282.             return true;
  283.         }
  284.         return false;
  285.     }

  286.     @Override
  287.     public String toString() {
  288.         final StringBuilder result = new StringBuilder();
  289.         result.append("Object: ");
  290.         result.append(object.toString());
  291.         result.append(", State: ");
  292.         synchronized (this) {
  293.             result.append(state.toString());
  294.         }
  295.         return result.toString();
  296.         // TODO add other attributes
  297.     }

  298.     @Override
  299.     public void use() {
  300.         lastUseInstant = now();
  301.         usedBy.fillInStackTrace();
  302.     }

  303. }