View Javadoc

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                 // just one or more concurrent borrow processes modified the pool
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 }