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

org.apache.commons.pool2.impl.DefaultPooledObject Maven / Gradle / Ivy

There is a newer version: 2.12.0
Show 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.commons.pool2.impl;

import java.io.PrintWriter;
import java.util.Deque;

import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectState;
import org.apache.commons.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 long createTimeMillis = System.currentTimeMillis(); private volatile long lastBorrowTimeMillis = createTimeMillis; private volatile long lastUseTimeMillis = createTimeMillis; private volatile long lastReturnTimeMillis = createTimeMillis; private volatile boolean logAbandoned = false; 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; lastBorrowTimeMillis = System.currentTimeMillis(); lastUseTimeMillis = lastBorrowTimeMillis; 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 long lastActiveDiff = this.getLastReturnTime() - other.getLastReturnTime(); if (lastActiveDiff == 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); } // handle int overflow return (int)Math.min(Math.max(lastActiveDiff, Integer.MIN_VALUE), Integer.MAX_VALUE); } /** * 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; lastReturnTimeMillis = System.currentTimeMillis(); 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; if (!idleQueue.offerFirst(this)) { // TODO - Should never happen } } return false; } @Override public long getActiveTimeMillis() { // Take copies to avoid threading issues final long rTime = lastReturnTimeMillis; final long bTime = lastBorrowTimeMillis; if (rTime > bTime) { return rTime - bTime; } return System.currentTimeMillis() - bTime; } /** * 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 long getCreateTime() { return createTimeMillis; } @Override public long getIdleTimeMillis() { final long elapsed = System.currentTimeMillis() - lastReturnTimeMillis; // elapsed may be negative if: // - another thread updates lastReturnTime during the calculation window // - System.currentTimeMillis() is not monotonic (e.g. system time is set back) return elapsed >= 0 ? elapsed : 0; } @Override public long getLastBorrowTime() { return lastBorrowTimeMillis; } @Override public long getLastReturnTime() { return lastReturnTimeMillis; } /** * 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#getLastUsed()} 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() { if (object instanceof TrackedUse) { return Math.max(((TrackedUse) object).getLastUsed(), lastUseTimeMillis); } return lastUseTimeMillis; } @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 abandoned. */ @Override public synchronized void markAbandoned() { state = PooledObjectState.ABANDONED; } /** * Marks the object as returning to the pool. */ @Override public synchronized void markReturning() { state = PooledObjectState.RETURNING; } @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 = CallStackUtils.newCallStack("'Pooled object created' " + "yyyy-MM-dd HH:mm:ss Z 'by the following code has not been returned to the pool:'", true, requireFullStackTrace); usedBy = CallStackUtils.newCallStack("The last code to use this object was:", false, requireFullStackTrace); } @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() { lastUseTimeMillis = System.currentTimeMillis(); usedBy.fillInStackTrace(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy