1 /**********************************************************************
2 * ByteBufferCache.java
3 * created on 17.03.2007 by netseeker
4 * $Id: ByteBufferCache.java,v 1.2 2007/03/25 15:03:22 netseeker Exp $
5 * $Log: ByteBufferCache.java,v $
6 * Revision 1.2 2007/03/25 15:03:22 netseeker
7 * *** empty log message ***
8 *
9 * Revision 1.1 2007/03/22 21:01:33 netseeker
10 * *** empty log message ***
11 *
12 *
13 * ====================================================================
14 *
15 * Copyright 2005-2006 netseeker aka Michael Manske
16 *
17 * Licensed under the Apache License, Version 2.0 (the "License");
18 * you may not use this file except in compliance with the License.
19 * You may obtain a copy of the License at
20 *
21 * http://www.apache.org/licenses/LICENSE-2.0
22 *
23 * Unless required by applicable law or agreed to in writing, software
24 * distributed under the License is distributed on an "AS IS" BASIS,
25 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26 * See the License for the specific language governing permissions and
27 * limitations under the License.
28 * ====================================================================
29 *
30 * This file is part of the EJOE framework.
31 * For more information on the author, please see
32 * <http://www.manskes.de/>.
33 *
34 *********************************************************************/
35 package de.netseeker.ejoe.cache;
36
37 import java.lang.ref.Reference;
38 import java.lang.ref.ReferenceQueue;
39 import java.lang.ref.SoftReference;
40 import java.nio.ByteBuffer;
41 import java.util.Collections;
42 import java.util.LinkedList;
43 import java.util.List;
44 import java.util.logging.Level;
45 import java.util.logging.Logger;
46
47 /***
48 * A pool for direct ByteBuffers which is able to borrow ByteBuffers according to a requested capacity.
49 *
50 * @author netseeker
51 * @since 0.3.9.2
52 */
53 class ByteBufferCache
54 {
55 /***
56 * default max. pool size in bytes
57 */
58 public static final int DEFAULT_MAX_POOL_SIZE = 1048576;
59
60 private static final Logger LOG = Logger.getLogger( ByteBufferCache.class.getName() );
61
62 final ReferenceQueue _refQueue = new ReferenceQueue();
63
64 final List _pool = Collections.synchronizedList( new LinkedList() );
65
66 int _sizeB = DEFAULT_MAX_POOL_SIZE;
67
68 int _currentSize = 0;
69
70 /***
71 *
72 */
73 public ByteBufferCache()
74 {
75 }
76
77 /***
78 * @param size
79 */
80 public ByteBufferCache(int size)
81 {
82 _sizeB = size;
83 }
84
85 /***
86 * @param capacity
87 * @return
88 */
89 public ByteBuffer borrow( int capacity )
90 {
91 ByteBuffer buffer = null;
92 clean();
93 int size = _pool.size();
94 int i = 0;
95 while ( i < size )
96 {
97 try
98 {
99 SoftReference ref = (SoftReference) _pool.get( i );
100 buffer = (ByteBuffer) ref.get();
101 if ( buffer != null && buffer.capacity() >= capacity )
102 {
103 ref.clear();
104 _pool.remove( i );
105 _currentSize -= buffer.capacity();
106 buffer.limit( capacity );
107 LOG.log( Level.FINEST, "Borrowed buffer with capacity of " + buffer.capacity() + "(limit="
108 + capacity + "). Pool max size: " + _sizeB + " Current pool size: " + _currentSize );
109 return buffer;
110 }
111
112 i++;
113 size = _pool.size();
114 }
115 catch ( IndexOutOfBoundsException e )
116 {
117
118 break;
119 }
120 }
121 return ByteBuffer.allocateDirect( capacity );
122 }
123
124 /***
125 * @param buffer
126 */
127 public void pushBack( ByteBuffer buffer )
128 {
129 clean();
130 if ( _currentSize <= _sizeB )
131 {
132 buffer.clear();
133 SoftReference ref = new SoftReference( buffer, this._refQueue );
134 _pool.add( ref );
135 _currentSize += buffer.capacity();
136 LOG.log( Level.FINEST, "Pushed back buffer with capacity of " + buffer.capacity() + ". Pool max size: "
137 + _sizeB + " Current pool size: " + _currentSize );
138 }
139 else
140 {
141 LOG.log( Level.FINEST, "Not pushing back buffer with capacity of " + buffer.capacity()
142 + " because max pool size of " + _sizeB + "bytes is reached." );
143 }
144 }
145
146 /***
147 * garbage collects all dereferenced objects in this cache
148 */
149 private synchronized void clean()
150 {
151 Reference ref;
152
153 while ( (ref = this._refQueue.poll()) != null )
154 {
155 ByteBuffer buffer = (ByteBuffer) ref.get();
156 _pool.remove( ref );
157
158 if ( buffer != null )
159 {
160 LOG.log( Level.FINEST, "Collecting Buffer with capacity of " + buffer.capacity() );
161 _currentSize -= buffer.capacity();
162 }
163 else
164 {
165 LOG.log( Level.FINEST, "Clearing cache..." );
166 _pool.clear();
167 _currentSize = 0;
168 break;
169 }
170 }
171 }
172 }