/*
* Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.jboss.com.sun.corba.se.impl.transport;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import org.jboss.com.sun.corba.se.pept.transport.ByteBufferPool;
import org.jboss.com.sun.corba.se.spi.orb.ORB;
/**
* @author Charlie Hunt
*/
public class ByteBufferPoolImpl implements ByteBufferPool
{
private ORB itsOrb;
private int itsByteBufferSize;
private ArrayList<ByteBuffer> itsPool;
private int itsObjectCounter = 0;
private boolean debug;
// Construct a ByteBufferPool for a pool of NIO ByteBuffers of ORB fragment size.
public ByteBufferPoolImpl(ORB theORB)
{
itsByteBufferSize = theORB.getORBData().getGIOPFragmentSize();
itsPool = new ArrayList<ByteBuffer>();
itsOrb = theORB;
debug = theORB.transportDebugFlag;
}
/*
* Locations where ByteBuffers are gotten from the pool: 1. ContactInfoBase.createMessageMediator() 2.
* ByteBufferWithInfo.growBuffer() 3. ByteBufferWithInfo(ORB, BufferManagerWrite) - constructor
*/
// If the requested ByteBuffer size is less than or equal to the ORB fragment size, and we have not disabled use of
// direct byte buffers (normally for debugging purposes) then get a DirectByteBuffer from the pool if there is one,
// if there is not one in the pool, then allocate a a DirectByteBuffer of ORB fragment size.
//
// If the request ByteBuffer size is greater than the ORB fragment size, allocate a new non-direct ByteBuffer.
public ByteBuffer getByteBuffer(int theAskSize)
{
ByteBuffer abb = null;
if ((theAskSize <= itsByteBufferSize) && !itsOrb.getORBData().disableDirectByteBufferUse())
{
// check if there's one in the pool, if not allocate one.
int poolSize;
synchronized (itsPool)
{
poolSize = itsPool.size();
if (poolSize > 0)
{
abb = itsPool.remove(poolSize - 1);
// clear ByteBuffer before returning it
abb.clear();
}
}
// NOTE: Moved the 'else' part of the above if statement outside the synchronized block since it is likely
// less expensive to check poolSize than to allocate a DirectByteBuffer in the synchronized block.
if (poolSize <= 0)
{
abb = ByteBuffer.allocateDirect(itsByteBufferSize);
}
// increment the number of ByteBuffers gotten from pool IMPORTANT: Since this counter is used only for
// information purposes, it does not use synchronized access.
itsObjectCounter++;
}
else
{
// Requested ByteBuffer size larger than the pool manages. Just allocate a non-direct ByteBuffer
abb = ByteBuffer.allocate(theAskSize);
}
return abb;
}
/*
* Locations where ByteBuffers are released to the pool: 1. ByteBufferWithInfo.growBuffer() 2.
* BufferManagerWriteCollect.sendMessage() 3. CDROutputStream_1_0.close() 4. CDRInputStream_1_0.close() 5.
* BufferManagerReadStream.underflow() 6. BufferManagerWrite.close() 7. BufferManagerRead.close() 8.
* CorbaMessageMediatorImpl.releaseByteBufferToPool()
*/
// If the ByteBuffer is a DirectByteBuffer, add it to the pool. Otherwise, set its reference to null since it's not
// kept in the pool and caller is saying he/she is done with it.
// NOTE: The size of the ByteBuffer is not checked with the this pool's ByteBuffer size since only DirectByteBuffers
// ever allocated. Hence, only DirectByteBuffer are checked here. An additional check could be added here for that
// though.
public void releaseByteBuffer(ByteBuffer thebb)
{
if (thebb.isDirect())
{
synchronized (itsPool)
{
// use with debug to determine if byteBuffer is already in the pool.
boolean refInPool = false;
int bbAddr = 0;
if (debug)
{
// Check to make sure we don't have 'thebb' reference already in the pool before adding it.
for (int i = 0; i < itsPool.size() && refInPool == false; i++)
{
ByteBuffer tmpbb = itsPool.get(i);
if (thebb == tmpbb)
{
refInPool = true;
bbAddr = System.identityHashCode(thebb);
}
}
}
// NOTE: The else part of this if will only get called if debug = true and refInPool = true, see logic
// above.
if (refInPool == false || debug == false)
{
// add ByteBuffer back to the pool
itsPool.add(thebb);
}
else
// otherwise, log a stack trace with duplicate message
{
String threadName = Thread.currentThread().getName();
Throwable t = new Throwable(threadName + ": Duplicate ByteBuffer reference (" + bbAddr + ")");
t.printStackTrace(System.out);
}
}
// decrement the count of ByteBuffers released
// IMPORTANT: Since this counter is used only for information purposes, it does not use synchronized access.
itsObjectCounter--;
}
else
{
// ByteBuffer not pooled nor needed
thebb = null;
}
}
// Get a count of the outstanding allocated DirectByteBuffers. (Those allocated and have not been returned to the
// pool).
// IMPORTANT: Since this counter is used only for information purposes, it does not use synchronized access.
public int activeCount()
{
return itsObjectCounter;
}
}
// End of file.