/*********************************************************************
* ByteBufferCache.java
* created on 17.03.2007 by netseeker
* $Id: ByteBufferCache.java,v 1.2 2007/03/25 15:03:22 netseeker Exp $
* $Log: ByteBufferCache.java,v $
* Revision 1.2 2007/03/25 15:03:22 netseeker
* *** empty log message ***
*
* Revision 1.1 2007/03/22 21:01:33 netseeker
* *** empty log message ***
*
*
* ====================================================================
*
* Copyright 2005-2006 netseeker aka Michael Manske
*
* 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.
* ====================================================================
*
* This file is part of the EJOE framework.
* For more information on the author, please see
* <http://www.manskes.de/>.
*
*********************************************************************/
package de.netseeker.ejoe.cache;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* A pool for direct ByteBuffers which is able to borrow ByteBuffers according to a requested capacity.
*
* @author netseeker
* @since 0.3.9.2
*/
class ByteBufferCache
{
/**
* default max. pool size in bytes
*/
public static final int DEFAULT_MAX_POOL_SIZE = 1048576;
private static final Logger LOG = Logger.getLogger( ByteBufferCache.class.getName() );
final ReferenceQueue _refQueue = new ReferenceQueue();
final List _pool = Collections.synchronizedList( new LinkedList() );
int _sizeB = DEFAULT_MAX_POOL_SIZE;
int _currentSize = 0;
/**
*
*/
public ByteBufferCache()
{
}
/**
* @param size
*/
public ByteBufferCache(int size)
{
_sizeB = size;
}
/**
* @param capacity
* @return
*/
public ByteBuffer borrow( int capacity )
{
ByteBuffer buffer = null;
clean();
int size = _pool.size();
int i = 0;
while ( i < size )
{
try
{
SoftReference ref = (SoftReference) _pool.get( i );
buffer = (ByteBuffer) ref.get();
if ( buffer != null && buffer.capacity() >= capacity )
{
ref.clear();
_pool.remove( i );
_currentSize -= buffer.capacity();
buffer.limit( capacity );
LOG.log( Level.FINEST, "Borrowed buffer with capacity of " + buffer.capacity() + "(limit="
+ capacity + "). Pool max size: " + _sizeB + " Current pool size: " + _currentSize );
return buffer;
}
i++;
size = _pool.size();
}
catch ( IndexOutOfBoundsException e )
{
// just one or more concurrent borrow processes modified the pool
break;
}
}
return ByteBuffer.allocateDirect( capacity );
}
/**
* @param buffer
*/
public void pushBack( ByteBuffer buffer )
{
clean();
if ( _currentSize <= _sizeB )
{
buffer.clear();
SoftReference ref = new SoftReference( buffer, this._refQueue );
_pool.add( ref );
_currentSize += buffer.capacity();
LOG.log( Level.FINEST, "Pushed back buffer with capacity of " + buffer.capacity() + ". Pool max size: "
+ _sizeB + " Current pool size: " + _currentSize );
}
else
{
LOG.log( Level.FINEST, "Not pushing back buffer with capacity of " + buffer.capacity()
+ " because max pool size of " + _sizeB + "bytes is reached." );
}
}
/**
* garbage collects all dereferenced objects in this cache
*/
private synchronized void clean()
{
Reference ref;
while ( (ref = this._refQueue.poll()) != null )
{
ByteBuffer buffer = (ByteBuffer) ref.get();
_pool.remove( ref );
if ( buffer != null )
{
LOG.log( Level.FINEST, "Collecting Buffer with capacity of " + buffer.capacity() );
_currentSize -= buffer.capacity();
}
else
{
LOG.log( Level.FINEST, "Clearing cache..." );
_pool.clear();
_currentSize = 0;
break;
}
}
}
}