/*
* 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;
/**
* An Allocator is responsible for the creation and destruction of
* {@link Poolable} objects.
*
* This is where the objects in the Pool comes from. Clients of the Stormpot
* library needs to provide their own Allocator implementations.
*
* Implementations of this interface must be thread-safe, because there is no
* knowing whether pools will try to access it concurrently or not. The easiest
* way to achieve this is to just make the
* {@link Allocator#allocate(Slot) allocate}
* and {@link Allocator#deallocate(Poolable) deallocate} methods synchronised,
* but this might cause problems for the pools ability to allocate objects fast
* enough, if they are very slow to construct. Pools might want to deal with
* very slow allocations by allocating in more than one thread, but
* synchronizing the {@link #allocate(Slot)} method will render that strategy
* ineffective.
*
* A better approach to thread-safety is to not have any shared mutable state
* in the allocator, if at all possible.
*
* @author Chris Vest <mr.chrisvest@gmail.com>
* @see stormpot.Reallocator
* @param <T> any type that implements Poolable.
*/
public interface Allocator<T extends Poolable> {
/**
* Create a fresh new instance of T for the given slot.
*
* The returned {@link Poolable} must obey the contract that, when
* {@link Poolable#release()} is called on it, it must delegate
* the call onto the {@link Slot#release(Poolable)} method of the here
* given slot object.
*
* Exceptions thrown by this method may propagate out through the
* {@link Pool#claim(Timeout) claim} method of a pool, in the form of being
* wrapped inside a {@link PoolException}. Pools must be able to handle these
* exceptions in a sane manner, and are guaranteed to return to a working
* state if an Allocator stops throwing exceptions from its allocate method.
* @param slot The slot the pool wish to allocate an object for.
* Implementers do not need to concern themselves with the details of a
* pools slot objects. They just have to call release on them as the
* protocol demands.
* @return A newly created instance of T. Never `null`.
* @throws Exception If the allocation fails.
*/
T allocate(Slot slot) throws Exception;
/**
* Deallocate, if applicable, the given Poolable and free any resources
* associated with it.
*
* This is an opportunity to close any connections or files, flush buffers,
* empty caches or what ever might need to be done to completely free any
* resources represented by this Poolable.
*
* Note that a Poolable must never touch its slot object after it has been
* deallocated.
*
* Pools, on the other hand, will guarantee that the same object is never
* deallocated more than once.
*
* Note that pools will always silently swallow exceptions thrown by the
* deallocate method. They do this because there is no knowing whether the
* deallocation of an object will be done synchronously by a thread calling
* {@link Poolable#release() release} on a Poolable, or asynchronously by
* a clean-up thread inside the pool.
*
* Deallocation from the release of an expired object, and deallocation from
* the shut down procedure of a {@link Pool} behave the same way in this
* regard. They will both silently swallow any exception thrown.
*
* On the other hand, pools are guaranteed to otherwise correctly deal with
* any exception that might be thrown. The shut down procedure will still
* complete, and release will still maintain the internal data structures of
* the pool to make the slot available for new allocations.
*
* If you need to somehow specially deal with the exceptions thrown by the
* deallocation of objects, then you should do this in the allocator itself,
* or in a wrapper around your allocator.
* @param poolable The non-null Poolable instance to be deallocated.
* @throws Exception if the deallocation encounters an error.
*/
void deallocate(T poolable) throws Exception;
}