1/*
2 * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.corba.se.impl.transport;
27
28import java.nio.ByteBuffer;
29import java.util.ArrayList;
30
31import com.sun.corba.se.spi.orb.ORB;
32
33import com.sun.corba.se.pept.transport.ByteBufferPool;
34
35/**
36 * @author Charlie Hunt
37 */
38
39public class ByteBufferPoolImpl implements ByteBufferPool
40{
41    private ORB itsOrb;
42    private int itsByteBufferSize;
43    private ArrayList itsPool;
44    private int itsObjectCounter = 0;
45    private boolean debug;
46
47    // Construct a ByteBufferPool for a pool of NIO ByteBuffers
48    // of ORB fragment size.
49    public ByteBufferPoolImpl(ORB theORB)
50    {
51        itsByteBufferSize = theORB.getORBData().getGIOPFragmentSize();
52        itsPool = new ArrayList();
53        itsOrb = theORB;
54        debug = theORB.transportDebugFlag;
55    }
56
57    /*
58     * Locations where ByteBuffers are gotten from the pool:
59     * 1. ContactInfoBase.createMessageMediator()
60     * 2. ByteBufferWithInfo.growBuffer()
61     * 3. ByteBufferWithInfo(ORB, BufferManagerWrite) - constructor
62    */
63
64    // If the requested ByteBuffer size is less than or equal to
65    // the ORB fragment size, and we have not disabled use of
66    // direct byte buffers (normally for debugging purposes)
67    // then get a DirectByteBuffer from the
68    // pool if there is one, if there is not one in the pool,
69    // then allocate a a DirectByteBuffer of ORB fragment size.
70    //
71    // If the request ByteBuffer size is greater than the ORB fragment
72    // size, allocate a new non-direct ByteBuffer.
73    public ByteBuffer getByteBuffer(int theAskSize)
74    {
75        ByteBuffer abb = null;
76
77        if ((theAskSize <= itsByteBufferSize) &&
78            !itsOrb.getORBData().disableDirectByteBufferUse())
79        {
80            // check if there's one in the pool, if not allocate one.
81            int poolSize;
82            synchronized (itsPool)
83            {
84                poolSize = itsPool.size();
85                if (poolSize > 0)
86                {
87                    abb = (ByteBuffer)itsPool.remove(poolSize - 1);
88
89                    // clear ByteBuffer before returning it
90                    abb.clear();
91                }
92            }
93
94            // NOTE: Moved the 'else' part of the above if statement
95            //       outside the synchronized block since it is likely
96            //       less expensive to check poolSize than to allocate a
97            //       DirectByteBuffer in the synchronized block.
98            if (poolSize <= 0)
99            {
100                abb = ByteBuffer.allocateDirect(itsByteBufferSize);
101            }
102
103            // increment the number of ByteBuffers gotten from pool
104            // IMPORTANT: Since this counter is used only for information
105            //            purposes, it does not use synchronized access.
106            itsObjectCounter++;
107        }
108        else
109        {
110            // Requested ByteBuffer size larger than the pool manages.
111            // Just allocate a non-direct ByteBuffer
112            abb = ByteBuffer.allocate(theAskSize);
113        }
114
115        return abb;
116    }
117
118
119    /*
120     * Locations where ByteBuffers are released to the pool:
121     * 1. ByteBufferWithInfo.growBuffer()
122     * 2. BufferManagerWriteCollect.sendMessage()
123     * 3. CDROutputStream_1_0.close()
124     * 4. CDRInputStream_1_0.close()
125     * 5. BufferManagerReadStream.underflow()
126     * 6. BufferManagerWrite.close()
127     * 7. BufferManagerRead.close()
128     * 8. CorbaMessageMediatorImpl.releaseByteBufferToPool()
129    */
130
131    // If the ByteBuffer is a DirectByteBuffer, add it to the pool.
132    // Otherwise, set its reference to null since it's not kept in
133    // the pool and caller is saying he/she is done with it.
134    // NOTE: The size of the ByteBuffer is not checked with the
135    //       this pool's ByteBuffer size since only DirectByteBuffers
136    //       ever allocated. Hence, only DirectByteBuffer are checked
137    //       here. An additional check could be added here for that though.
138    public void releaseByteBuffer(ByteBuffer thebb)
139    {
140        if (thebb.isDirect())
141        {
142            synchronized (itsPool)
143            {
144                // use with debug to determine if byteBuffer is already
145                // in the pool.
146                boolean refInPool = false;
147                int bbAddr = 0;
148
149                if (debug)
150                {
151                    // Check to make sure we don't have 'thebb' reference
152                    // already in the pool before adding it.
153
154                    for (int i = 0; i < itsPool.size() && refInPool == false; i++)
155                    {
156                         ByteBuffer tmpbb = (ByteBuffer)itsPool.get(i);
157                         if (thebb == tmpbb)
158                         {
159                             refInPool = true;
160                             bbAddr = System.identityHashCode(thebb);
161                         }
162                    }
163
164                }
165
166                // NOTE: The else part of this if will only get called
167                //       if debug = true and refInPool = true, see logic above.
168                if (refInPool == false || debug == false)
169                {
170                    // add ByteBuffer back to the pool
171                    itsPool.add(thebb);
172                }
173                else // otherwise, log a stack trace with duplicate message
174                {
175                    String threadName = Thread.currentThread().getName();
176                    Throwable t =
177                            new Throwable(threadName +
178                                         ": Duplicate ByteBuffer reference (" +
179                                         bbAddr + ")");
180                    t.printStackTrace(System.out);
181                }
182            }
183
184            // decrement the count of ByteBuffers released
185            // IMPORTANT: Since this counter is used only for information
186            //            purposes, it does not use synchronized access.
187            itsObjectCounter--;
188        }
189        else
190        {
191            // ByteBuffer not pooled nor needed
192            thebb = null;
193        }
194    }
195
196
197    // Get a count of the outstanding allocated DirectByteBuffers.
198    // (Those allocated and have not been returned to the pool).
199    // IMPORTANT: Since this counter is used only for information
200    //            purposes, it does not use synchronized access.
201    public int activeCount()
202    {
203         return itsObjectCounter;
204    }
205}
206
207// End of file.
208