blob: 26a50e3260fc82aa6a9f70a3049685889b52427a [file] [log] [blame]
// Copyright 2004 The Apache Software Foundation
//
// 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 org.apache.tapestry.util.pool;
/**
* A wrapper around a list of objects for a given key in a {@link Pool}.
* The current implementation of this is FIFO. This class is closely
* tied to {@link Pool}, which controls synchronization for it.
*
* <p>This class, and {@link Pool}, were heavily revised in 1.0.5
* to support generational cleaning. The PoolList acts like a first-in
* first-out queue and each pooled object is tagged with a "generation
* count", provided by the {@link Pool}. The generation count is
* incremented periodically. This allows us to track, roughly,
* how often a pooled object has been accessed; unused objects will
* be buried with relatively low generation counts.
*
* @author Howard Lewis Ship
* @version $Id$
*
**/
class PoolList
{
/** @since 3.0 **/
private Pool _pool;
/**
* Linked list of pooled objects.
*
* @since 1.0.5
**/
private Entry _first;
/**
* Linked list of "spare" Entries, ready to be re-used.
*
* @since 1.0.5
**/
private Entry _spare;
/**
* Overall count of items pooled.
*
**/
private int _count;
/**
* A simple linked-list entry for items stored in the PoolList.
*
* @since 1.0.5
*
**/
private static class Entry
{
int generation;
Object pooled;
Entry next;
}
/**
* @since 3.0
*
**/
PoolList(Pool pool)
{
_pool = pool;
}
/**
* Returns the number of pooled objects currently stored.
*
* @since 1.0.5
**/
public int getPooledCount()
{
return _count;
}
/**
* Returns an object previously stored into the list, or null if the list
* is empty. The returned object is removed from the list.
*
**/
public Object retrieve()
{
if (_count == 0)
return null;
_count--;
Entry e = _first;
Object result = e.pooled;
// Okay, store e into the list of spare entries.
_first = e.next;
e.next = _spare;
_spare = e;
e.generation = 0;
e.pooled = null;
return result;
}
/**
* Adds the object to this PoolList. An arbitrary number of objects can be
* stored. The objects can later be retrieved using {@link #get()}.
* The list requires that generation never decrease. On each subsequent
* invocation, it should be the same as, or greater, than the previous value.
*
* @return The number of objects stored in the list (after adding the new object).
**/
public int store(int generation, Object object)
{
Entry e;
if (_spare == null)
{
e = new Entry();
}
else
{
e = _spare;
_spare = _spare.next;
}
e.generation = generation;
e.pooled = object;
e.next = _first;
_first = e;
return ++_count;
}
/**
* Invoked to cleanup the list, freeing unneeded objects.
*
* @param generation pooled objects stored in this generation or
* earlier are released.
*
* @since 1.0.5
**/
public int cleanup(int generation)
{
_spare = null;
_count = 0;
Entry prev = null;
// Walk through the list. They'll be sorted by generation.
Entry e = _first;
while (true)
{
if (e == null)
break;
// If found a too-old entry then we want to
// delete it.
if (e.generation <= generation)
{
Object pooled = e.pooled;
// Notify the object that it is being dropped
// through the cracks!
_pool.getAdaptor(pooled).discardFromPool(pooled);
// Set the next pointer of the previous node to null.
// If the very first node inspected was too old,
// set the first pointer to null.
if (prev == null)
_first = null;
else
prev.next = null;
}
else
_count++;
prev = e;
e = e.next;
}
return _count;
}
public String toString()
{
return "PoolList[" + _count + "]";
}
/**
* Much like {@link #cleanup(int)}, but discards all
* pooled objects.
*
* @since 3.0
*
**/
void discardAll()
{
Entry e = _first;
while (e != null)
{
Object pooled = e.pooled;
_pool.getAdaptor(pooled).discardFromPool(pooled);
e = e.next;
}
_first = null;
_spare = null;
_count = 0;
}
}