/* * Copyright (C) 2011-2014 Chris Vest (mr.chrisvest@gmail.com) * * Licensed 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 stormpot; /** * The expiration is used to determine if a given slot has expired, or * otherwise become invalid. * * Note that Expiration instances must be thread-safe, as they may be * accessed concurrently by multiple threads. However, for a given * {@link SlotInfo} and {@link Poolable} instance, only a single thread will * invoke the expiration at a time. This means that there is no need to * synchronise on the SlotInfo or Poolable objects. * * The easiest way to ensure that an Expiration implementation is thread-safe, * is to make sure that they never mutate any state. If they do, however, * then they must do so in a thread-safe manner, unless the mutable state is * contained within the SlotInfo or Poolable objects – in this case, the * mutable state will be thread-local. Be aware that making the * {@link #hasExpired(SlotInfo) hasExpired} method {@code synchronized} will * most likely severely reduce the performance and scalability of the pool. * * The Expiration can be invoked several times during a * {@link Pool#claim(Timeout) claim} call, so it is important that the * Expiration is fast. It can easily be the dominating factor in the * performance of the pool. * * TIP: If the expiration is too slow, you can alternatively use a time-based * expiration, such as {@link stormpot.TimeExpiration}, that has been * configured with a very low expiration time, like a few seconds. Then you can * configure the pool to use a {@link stormpot.Reallocator}, where you do the * expensive expiration check in the * {@link stormpot.Reallocator#reallocate(Slot, Poolable) reallocate} method, * returning the same Poolable back if it hasn't expired. * Be aware, though, that such a scheme has to be tuned to the load of the * application, such that the objects in the pool don't all expire at the same * time, leaving the pool empty. * * @author Chris Vest <mr.chrisvest@gmail.com> */ public interface Expiration<T extends Poolable> { /** * Test whether the Slot and Poolable object, represented by the given * {@link SlotInfo} object, is still valid, or if the pool should * deallocate it and allocate a replacement. * * If the method throws an exception, then that is taken to mean that the * slot is invalid. The exception will bubble out of the * {@link Pool#claim(Timeout) claim} method, but the mechanism is * implementation specific. For this reason, it is generally advised that * Expirations do not throw exceptions. * * Note that this method can be called as often as several times per * {@link Pool#claim(Timeout) claim}. The performance of this method therefor * has a big influence on the perceived performance of the pool. * * @param info An informative representative of the slot being tested. * Never `null`. * @return `true` if the Slot and Poolable in question should be * deallocated, `false` if it is valid and eligible for claiming. * @throws Exception If checking the validity of the Slot or Poolable somehow * went wrong. In this case, the Poolable will be assumed to be expired. */ boolean hasExpired(SlotInfo<? extends T> info) throws Exception; }