KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jacorb > orb > BufferManager


1 package org.jacorb.orb;
2 /*
3  * JacORB - a free Java ORB
4  *
5  * Copyright (C) 1997-2004 Gerald Brose.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the Free
19  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */

21
22 import java.util.*;
23
24 import org.apache.avalon.framework.configuration.*;
25
26 import org.omg.CORBA.NO_MEMORY JavaDoc;
27 import org.omg.CORBA.BAD_INV_ORDER JavaDoc;
28
29 /**
30  * A BufferManager is used to share a pool of buffers and to implement
31  * a buffer allocation policy. This reduces the number of memory
32  * allocations and deallocations and the overall memory footprint.
33  * Buffers are generally created on demand.
34  *
35  * The BufferManager uses a singleton pattern, so will only be a single
36  * shared BuffferManager across all ORBs in a process.
37  *
38  * @author Gerald Brose, FU Berlin
39  * @version $Id: BufferManager.java,v 1.19 2004/10/07 16:29:08 simon.mcqueen Exp $
40 */

41
42 public final class BufferManager
43 {
44     /** the buffer pool */
45     private List[] bufferPool;
46     // The 'extra-large' buffer cache.
47
private byte[] bufferMax = null;
48
49     /** the maximal buffer size managed since the buffer
50     pool is ordered by buffer size in log2 steps */

51
52     private static int MAX;
53
54     /** the buffer at pos n has size 2**(n+MIN_OFFSET)
55     so the smallest available buffer is 2**MIN_OFFSET,
56         the largest buffers managed are 2**(MIN_OFFSET+MAX-1)
57     */

58
59     private static final int MIN_OFFSET = 5;
60
61     /** max number of buffers of the same size held in pool */
62
63     private static final int THRESHOLD = 20;
64     private static final int MEM_BUFSIZE = 256;
65     private static final int MIN_PREFERRED_BUFS = 10;
66
67     // Purge thread for QoS purging of the bufferMax cache.
68
private Reaper reaper;
69
70     /**
71      * <code>time</code> denotes whether the maxCache will be active:
72      * -1: Not active
73      * 0 : Active, never flushed
74      * >0: Active with reaper flush thread.
75      */

76     private static int time = 0;
77
78     /** the singleton instance */
79     private static BufferManager singleton = new BufferManager();
80
81     private static boolean configured = false;
82
83     /**
84      * configures the BufferManager, in turn configures the singleton.
85      * Must be called before getInstance() !
86      */

87     public static void configure(Configuration configuration)
88         throws ConfigurationException
89     {
90         singleton.singletonConfigure(configuration);
91         configured = true;
92     }
93
94     private BufferManager()
95     {
96     }
97
98     /**
99      * configures the singleton
100      */

101  
102     private void singletonConfigure(Configuration configuration)
103         throws ConfigurationException
104     {
105         time =
106             configuration.getAttributeAsInteger("jacorb.bufferManagerMaxFlush", 0);
107
108         MAX =
109             configuration.getAttributeAsInteger("jacorb.maxManagedBufSize", 18);
110
111     bufferPool = new List[ MAX ];
112
113     for( int i = 0; i < MAX; i++)
114         {
115         bufferPool[ i ] = new ArrayList();
116         }
117
118         /* create a number of buffers for the preferred memory buffer
119            size */

120
121         int m_pos = 0;
122         int j = MEM_BUFSIZE;
123
124         while( j > 1 )
125         {
126             j = j >> 1;
127             m_pos++;
128         }
129         for( int min = 0; min < MIN_PREFERRED_BUFS; min++ )
130         {
131             bufferPool[ m_pos -MIN_OFFSET ].add(new byte[ MEM_BUFSIZE ]);
132         }
133
134         if (time > 0)
135         {
136             // create new reaper
137
reaper = new Reaper (time);
138             reaper.setName ("BufferManager MaxCache Reaper");
139             reaper.setDaemon (true);
140             reaper.start();
141         }
142     }
143
144     /**
145      * May only be called after configure()
146      * @throws BAD_INV_ORDER if not previously configured
147      */

148
149     public static BufferManager getInstance()
150         throws BAD_INV_ORDER JavaDoc
151     {
152         if (!configured)
153             throw new BAD_INV_ORDER JavaDoc("Buffer Manager not configured");
154         return singleton;
155     }
156
157     /**
158      * Log 2, rounded up
159      */

160
161     private static final int log2up(int n)
162     {
163     int l =0;
164     int nn = n-1;
165     while( (nn >>l) != 0 )
166         l++;
167
168     return l;
169     }
170
171
172     /**
173      * Log 2, rounded down
174      */

175
176     private static final int log2down(int n)
177     {
178     int l =0;
179     int nn = n;
180     while( (nn >>l) != 0 )
181         l++;
182
183     return l-1;
184     }
185
186
187     public byte[] getPreferredMemoryBuffer()
188     {
189         return getBuffer( MEM_BUFSIZE );
190     }
191
192
193     public synchronized byte[] getBuffer( int initial )
194     {
195         return getBuffer(initial, false);
196     }
197
198
199     /**
200      * <code>getBuffer</code> returns a new buffer.
201      *
202      * @param initial an <code>int</code> value
203      * @param cdrStr a <code>boolean</code> value to denote if CDROuputStream is caller
204      * (may use cache in this situation)
205      * @return a <code>byte[]</code> value
206      */

207
208     public synchronized byte[] getBuffer( int initial, boolean cdrStr )
209     {
210         byte [] result;
211         List s;
212
213         int log = log2up(initial);
214
215         if (log >= MAX)
216         {
217             try
218             {
219                 if (cdrStr==false || time < 0)
220                 {
221                     // Defaults to returning asked for size
222
result = new byte[initial];
223                 }
224                 else
225                 {
226                     // Using cache so do below determination
227
if (bufferMax == null || bufferMax.length < initial)
228                     {
229                         // Autocache really large values for speed
230
bufferMax = new byte[initial*2];
231                     }
232                     // Else return the cached buffer
233
result = bufferMax;
234                     bufferMax = null;
235                 }
236             }
237             catch (OutOfMemoryError JavaDoc e)
238             {
239                 throw new NO_MEMORY JavaDoc();
240             }
241         }
242         else
243         {
244             s = bufferPool[log > MIN_OFFSET ? log-MIN_OFFSET : 0 ];
245
246             if(!s.isEmpty())
247             {
248                 // pop least recently added buffer from the list
249
result = (byte[])s.remove(s.size()-1);
250             }
251             else
252             {
253                 result = new byte[log > MIN_OFFSET ? 1<<log : 1 << MIN_OFFSET ];
254             }
255         }
256         return result;
257     }
258
259     public synchronized void returnBuffer(byte[] current)
260     {
261         returnBuffer (current, false);
262     }
263
264
265     /**
266      * Describe <code>returnBuffer</code> method here.
267      *
268      * @param current a <code>byte[]</code> value
269      * @param cdrStr a <code>boolean</code> value value to denote if CDROuputStream is
270      * caller (may use cache in this situation)
271      */

272     synchronized void returnBuffer(byte[] current, boolean cdrStr)
273     {
274         if (current != null)
275         {
276             int log_curr = log2down(current.length);
277
278             if( log_curr >= MIN_OFFSET )
279             {
280                 if( log_curr > MAX )
281                 {
282                     // Only cache if CDROutputStream is called, cache is enabled &
283
// the new value is > than the cached value.
284
if (cdrStr==true &&
285                         (time >= 0 &&
286                          (bufferMax == null || bufferMax.length < current.length)))
287                     {
288                         bufferMax = current;
289                     }
290                     return;
291                 }
292
293                 List s = bufferPool[ log_curr-MIN_OFFSET ];
294                 if( s.size() < THRESHOLD )
295                 {
296                     s.add( current );
297                 }
298             }
299         }
300     }
301
302     public void release()
303     {
304         // printStatistics();
305
for( int i= MAX; i > 0; )
306     {
307         i--;
308         bufferPool[i].clear();
309     }
310         if (reaper != null)
311         {
312             reaper.done = true;
313             reaper.wake();
314         }
315     }
316
317
318     private class Reaper extends Thread JavaDoc
319     {
320         public boolean done = false;
321         private int sleepInterval = 0;
322
323         public Reaper (int sleepInterval)
324         {
325             // Convert from seconds to milliseconds
326
this.sleepInterval = (sleepInterval * 1000);
327         }
328
329         public void run()
330         {
331             long time;
332
333             while (true)
334             {
335                 // Sleep (note time check on wake to catch premature awakening bug)
336

337                 try
338                 {
339                     time = sleepInterval + System.currentTimeMillis();
340                     do
341                     {
342                         sleep (sleepInterval);
343                     }
344                     while (System.currentTimeMillis() <= time);
345                 }
346                 catch (InterruptedException JavaDoc ex) {}
347
348                 // Check not shutting down
349

350                 if (done)
351                 {
352                     break;
353                 }
354
355  // if ( Debug.isDebugEnabled() )
356
// {
357
// org.jacorb.util.Debug.output
358
// (
359
// 4,
360
// "Reaper thread purging maxBufferCache. It had size: " +
361
// (bufferMax == null ? 0 : bufferMax.length)
362
// );
363
// }
364
bufferMax = null;
365             }
366         }
367
368         public synchronized void wake()
369         {
370             // Only one thread waiting so safe to use notify rather than notifyAll.
371
notify();
372         }
373     }
374 }
375
Popular Tags