/* * @(#)ByteBufferPoolImpl.java 1.12 04/06/21 * * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package com.sun.corba.se.impl.transport; import java.nio.ByteBuffer; import java.util.ArrayList; import com.sun.corba.se.spi.orb.ORB; import com.sun.corba.se.pept.transport.ByteBufferPool; /** * @author Charlie Hunt */ public class ByteBufferPoolImpl implements ByteBufferPool { private ORB itsOrb; private int itsByteBufferSize; private ArrayList 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(); 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 = (ByteBuffer)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 = (ByteBuffer)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.