View Javadoc

1   /*
2   Copyright (c) 2008 Health Market Science, Inc.
3   
4   This library is free software; you can redistribute it and/or
5   modify it under the terms of the GNU Lesser General Public
6   License as published by the Free Software Foundation; either
7   version 2.1 of the License, or (at your option) any later version.
8   
9   This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  Lesser General Public License for more details.
13  
14  You should have received a copy of the GNU Lesser General Public
15  License along with this library; if not, write to the Free Software
16  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
17  USA
18  
19  You can contact Health Market Science at info@healthmarketscience.com
20  or at the following address:
21  
22  Health Market Science
23  2700 Horizon Drive
24  Suite 200
25  King of Prussia, PA 19406
26  */
27  
28  package com.healthmarketscience.jackcess;
29  
30  import java.lang.ref.Reference;
31  import java.lang.ref.SoftReference;
32  import java.nio.ByteBuffer;
33  import java.nio.ByteOrder;
34  
35  /**
36   * Manages a reference to a ByteBuffer.
37   *
38   * @author James Ahlborn
39   */
40  public abstract class TempBufferHolder {
41  
42    private static final Reference<ByteBuffer> EMPTY_BUFFER_REF =
43      new SoftReference<ByteBuffer>(null);
44  
45    /**
46     * The caching type for the buffer holder.
47     */
48    public enum Type {
49      /** a hard reference is maintained to the created buffer */
50      HARD,
51      /** a soft reference is maintained to the created buffer (may be garbage
52          collected if memory gets tight) */
53      SOFT,
54      /** no reference is maintained to a created buffer (new buffer every
55          time) */
56      NONE;
57    }
58    
59    /** whether or not every get automatically rewinds the buffer */
60    private final boolean _autoRewind;
61    /** ByteOrder for all allocated buffers */
62    private final ByteOrder _order;
63    /** the mod count of the current buffer (changes on every realloc) */
64    private int _modCount;
65    
66    protected TempBufferHolder(boolean autoRewind, ByteOrder order) {
67      _autoRewind = autoRewind;
68      _order = order;
69    }
70  
71    /**
72     * @return the modification count of the current buffer (this count is
73     *         changed every time the buffer is reallocated)
74     */
75    public int getModCount() {
76      return _modCount;
77    }
78    
79    /**
80     * Creates a new TempBufferHolder.
81     * @param type the type of reference desired for any created buffer
82     * @param autoRewind whether or not every get automatically rewinds the
83     *                   buffer
84     */
85    public static TempBufferHolder newHolder(Type type, boolean autoRewind) {
86      return newHolder(type, autoRewind, PageChannel.DEFAULT_BYTE_ORDER);
87    }
88    
89    /**
90     * Creates a new TempBufferHolder.
91     * @param type the type of reference desired for any created buffer
92     * @param autoRewind whether or not every get automatically rewinds the
93     *                   buffer
94     * @param order byte order for all allocated buffers
95     */
96    public static TempBufferHolder newHolder(Type type, boolean autoRewind,
97                                             ByteOrder order)
98    {
99      switch(type) {
100     case HARD:
101       return new HardTempBufferHolder(autoRewind, order);
102     case SOFT:
103       return new SoftTempBufferHolder(autoRewind, order);
104     case NONE:
105       return new NoneTempBufferHolder(autoRewind, order);
106     default:
107       throw new IllegalStateException("Unknown type " + type);
108     }
109   }
110 
111   /**
112    * Returns a ByteBuffer of at least the defined page size, with the limit
113    * set to the page size, and the predefined byteOrder.  Will be rewound iff
114    * autoRewind is enabled for this buffer.
115    */
116   public final ByteBuffer getPageBuffer(PageChannel pageChannel) {
117     return getBuffer(pageChannel, pageChannel.getFormat().PAGE_SIZE);
118   }
119 
120   /**
121    * Returns a ByteBuffer of at least the given size, with the limit set to
122    * the given size, and the predefined byteOrder.  Will be rewound iff
123    * autoRewind is enabled for this buffer.
124    */
125   public final ByteBuffer getBuffer(PageChannel pageChannel, int size) {
126     ByteBuffer buffer = getExistingBuffer();
127     if((buffer == null) || (buffer.capacity() < size)) {
128       buffer = pageChannel.createBuffer(size, _order);
129       ++_modCount;
130       setNewBuffer(buffer);
131     } else {
132       buffer.limit(size);
133     }
134     if(_autoRewind) {
135       buffer.rewind();
136     }
137     return buffer;
138   }
139 
140   /**
141    * @return the currently referenced buffer, {@code null} if none
142    */
143   public abstract ByteBuffer getExistingBuffer();
144   
145   /**
146    * Releases any referenced memory.
147    */
148   public abstract void clear();
149 
150   /**
151    * Sets a new buffer for this holder.
152    */
153   protected abstract void setNewBuffer(ByteBuffer newBuffer);
154   
155   /**
156    * TempBufferHolder which has a hard reference to the buffer.
157    */
158   private static final class HardTempBufferHolder extends TempBufferHolder
159   {
160     private ByteBuffer _buffer;
161 
162     private HardTempBufferHolder(boolean autoRewind, ByteOrder order) {
163       super(autoRewind, order);
164     }
165     
166     @Override
167     public ByteBuffer getExistingBuffer() {
168       return _buffer;
169     }
170     
171     @Override
172     protected void setNewBuffer(ByteBuffer newBuffer) {
173       _buffer = newBuffer;
174     }
175 
176     @Override
177     public void clear() {
178       _buffer = null;
179     }
180   }
181   
182   /**
183    * TempBufferHolder which has a soft reference to the buffer.
184    */
185   private static final class SoftTempBufferHolder extends TempBufferHolder
186   {
187     private Reference<ByteBuffer> _buffer = EMPTY_BUFFER_REF;
188 
189     private SoftTempBufferHolder(boolean autoRewind, ByteOrder order) {
190       super(autoRewind, order);
191     }
192     
193     @Override
194     public ByteBuffer getExistingBuffer() {
195       return _buffer.get();
196     }
197     
198     @Override
199     protected void setNewBuffer(ByteBuffer newBuffer) {
200       _buffer.clear();
201       _buffer = new SoftReference<ByteBuffer>(newBuffer);
202     }
203 
204     @Override
205     public void clear() {
206       _buffer.clear();
207     }
208   }
209   
210   /**
211    * TempBufferHolder which has a no reference to the buffer.
212    */
213   private static final class NoneTempBufferHolder extends TempBufferHolder
214   {
215     private NoneTempBufferHolder(boolean autoRewind, ByteOrder order) {
216       super(autoRewind, order);
217     }
218     
219     @Override
220     public ByteBuffer getExistingBuffer() {
221       return null;
222     }
223     
224     @Override
225     protected void setNewBuffer(ByteBuffer newBuffer) {
226       // nothing to do
227     }
228 
229     @Override
230     public void clear() {
231       // nothing to do
232     }
233   }
234   
235 }