All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.tomcat.dbcp.pool2.impl.DefaultPooledObject Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.tomcat.dbcp.pool2.impl;

import java.io.PrintWriter;
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.util.Deque;

import org.apache.tomcat.dbcp.pool2.PooledObject;
import org.apache.tomcat.dbcp.pool2.PooledObjectState;
import org.apache.tomcat.dbcp.pool2.TrackedUse;

/**
 * This wrapper is used to track the additional information, such as state, for
 * the pooled objects.
 * 

* This class is intended to be thread-safe. *

* * @param the type of object in the pool * * @since 2.0 */ public class DefaultPooledObject implements PooledObject { private final T object; private PooledObjectState state = PooledObjectState.IDLE; // @GuardedBy("this") to ensure transitions are valid private final Clock systemClock = Clock.systemUTC(); private final Instant createInstant = now(); private volatile Instant lastBorrowInstant = createInstant; private volatile Instant lastUseInstant = createInstant; private volatile Instant lastReturnInstant = createInstant; private volatile boolean logAbandoned; private volatile CallStack borrowedBy = NoOpCallStack.INSTANCE; private volatile CallStack usedBy = NoOpCallStack.INSTANCE; private volatile long borrowedCount; /** * Creates a new instance that wraps the provided object so that the pool can * track the state of the pooled object. * * @param object The object to wrap */ public DefaultPooledObject(final T object) { this.object = object; } /** * Allocates the object. * * @return {@code true} if the original state was {@link PooledObjectState#IDLE IDLE} */ @Override public synchronized boolean allocate() { if (state == PooledObjectState.IDLE) { state = PooledObjectState.ALLOCATED; lastBorrowInstant = now(); lastUseInstant = lastBorrowInstant; borrowedCount++; if (logAbandoned) { borrowedBy.fillInStackTrace(); } return true; } if (state == PooledObjectState.EVICTION) { // TODO Allocate anyway and ignore eviction test state = PooledObjectState.EVICTION_RETURN_TO_HEAD; } // TODO if validating and testOnBorrow == true then pre-allocate for // performance return false; } @Override public int compareTo(final PooledObject other) { final int compareTo = getLastReturnInstant().compareTo(other.getLastReturnInstant()); if (compareTo == 0) { // Make sure the natural ordering is broadly consistent with equals // although this will break down if distinct objects have the same // identity hash code. // see java.lang.Comparable Javadocs return System.identityHashCode(this) - System.identityHashCode(other); } return compareTo; } /** * Deallocates the object and sets it {@link PooledObjectState#IDLE IDLE} * if it is currently {@link PooledObjectState#ALLOCATED ALLOCATED} * or {@link PooledObjectState#RETURNING RETURNING}. * * @return {@code true} if the state was {@link PooledObjectState#ALLOCATED ALLOCATED} * or {@link PooledObjectState#RETURNING RETURNING}. */ @Override public synchronized boolean deallocate() { if (state == PooledObjectState.ALLOCATED || state == PooledObjectState.RETURNING) { state = PooledObjectState.IDLE; lastReturnInstant = now(); borrowedBy.clear(); return true; } return false; } @Override public synchronized boolean endEvictionTest( final Deque> idleQueue) { if (state == PooledObjectState.EVICTION) { state = PooledObjectState.IDLE; return true; } if (state == PooledObjectState.EVICTION_RETURN_TO_HEAD) { state = PooledObjectState.IDLE; idleQueue.offerFirst(this); } return false; } @Override public long getActiveTimeMillis() { return getActiveDuration().toMillis(); } /** * Gets the number of times this object has been borrowed. * @return The number of times this object has been borrowed. * @since 2.1 */ @Override public long getBorrowedCount() { return borrowedCount; } @Override public Instant getCreateInstant() { return createInstant; } @Override public long getCreateTime() { return createInstant.toEpochMilli(); } @Override public Duration getIdleDuration() { // elapsed may be negative if: // - another thread updates lastReturnInstant during the calculation window // - System.currentTimeMillis() is not monotonic (e.g. system time is set back) final Duration elapsed = Duration.between(lastReturnInstant, now()); return elapsed.isNegative() ? Duration.ZERO : elapsed; } @Override public Duration getIdleTime() { return getIdleDuration(); } @Override public long getIdleTimeMillis() { return getIdleDuration().toMillis(); } @Override public Instant getLastBorrowInstant() { return lastBorrowInstant; } @Override public long getLastBorrowTime() { return lastBorrowInstant.toEpochMilli(); } @Override public Instant getLastReturnInstant() { return lastReturnInstant; } @Override public long getLastReturnTime() { return lastReturnInstant.toEpochMilli(); } /** * Gets an estimate of the last time this object was used. If the class * of the pooled object implements {@link TrackedUse}, what is returned is * the maximum of {@link TrackedUse#getLastUsedInstant()} and * {@link #getLastBorrowTime()}; otherwise this method gives the same * value as {@link #getLastBorrowTime()}. * * @return the last Instant this object was used. */ @Override public Instant getLastUsedInstant() { if (object instanceof TrackedUse) { return PoolImplUtils.max(((TrackedUse) object).getLastUsedInstant(), lastUseInstant); } return lastUseInstant; } /** * Gets an estimate of the last time this object was used. If the class * of the pooled object implements {@link TrackedUse}, what is returned is * the maximum of {@link TrackedUse#getLastUsedInstant()} and * {@link #getLastBorrowTime()}; otherwise this method gives the same * value as {@link #getLastBorrowTime()}. * * @return the last time this object was used */ @Override public long getLastUsedTime() { return getLastUsedInstant().toEpochMilli(); } @Override public T getObject() { return object; } /** * Gets the state of this object. * @return state */ @Override public synchronized PooledObjectState getState() { return state; } /** * Sets the state to {@link PooledObjectState#INVALID INVALID}. */ @Override public synchronized void invalidate() { state = PooledObjectState.INVALID; } /** * Marks the pooled object as {@link PooledObjectState#ABANDONED ABANDONED}. */ @Override public synchronized void markAbandoned() { state = PooledObjectState.ABANDONED; } /** * Marks the pooled object as {@link PooledObjectState#RETURNING RETURNING}. */ @Override public synchronized void markReturning() { state = PooledObjectState.RETURNING; } /** * Gets the current instant of the clock. * * @return the current instant of the clock. */ private Instant now() { return systemClock.instant(); } @Override public void printStackTrace(final PrintWriter writer) { boolean written = borrowedBy.printStackTrace(writer); written |= usedBy.printStackTrace(writer); if (written) { writer.flush(); } } @Override public void setLogAbandoned(final boolean logAbandoned) { this.logAbandoned = logAbandoned; } /** * Configures the stack trace generation strategy based on whether or not fully * detailed stack traces are required. When set to false, abandoned logs may * only include caller class information rather than method names, line numbers, * and other normal metadata available in a full stack trace. * * @param requireFullStackTrace the new configuration setting for abandoned object * logging * @since 2.5 */ @Override public void setRequireFullStackTrace(final boolean requireFullStackTrace) { borrowedBy = new ThrowableCallStack("'Pooled object created' " + "yyyy-MM-dd HH:mm:ss Z 'by the following code has not been returned to the pool:'", true); usedBy = new ThrowableCallStack("The last code to use this object was:", false); } @Override public synchronized boolean startEvictionTest() { if (state == PooledObjectState.IDLE) { state = PooledObjectState.EVICTION; return true; } return false; } @Override public String toString() { final StringBuilder result = new StringBuilder(); result.append("Object: "); result.append(object.toString()); result.append(", State: "); synchronized (this) { result.append(state.toString()); } return result.toString(); // TODO add other attributes } @Override public void use() { lastUseInstant = now(); usedBy.fillInStackTrace(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy