View Javadoc
1   /*
2   Copyright (c) 2008 Health Market Science, Inc.
3   
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7   
8       http://www.apache.org/licenses/LICENSE-2.0
9   
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15  */
16  
17  package com.healthmarketscience.jackcess.impl;
18  
19  import java.lang.ref.Reference;
20  import java.lang.ref.SoftReference;
21  import java.nio.ByteBuffer;
22  import java.nio.ByteOrder;
23  
24  /**
25   * Manages a reference to a ByteBuffer.
26   *
27   * @author James Ahlborn
28   */
29  public abstract class TempBufferHolder {
30  
31    private static final Reference<ByteBuffer> EMPTY_BUFFER_REF =
32      new SoftReference<ByteBuffer>(null);
33  
34    /**
35     * The caching type for the buffer holder.
36     */
37    public enum Type {
38      /** a hard reference is maintained to the created buffer */
39      HARD,
40      /** a soft reference is maintained to the created buffer (may be garbage
41          collected if memory gets tight) */
42      SOFT,
43      /** no reference is maintained to a created buffer (new buffer every
44          time) */
45      NONE;
46    }
47    
48    /** whether or not every get automatically rewinds the buffer */
49    private final boolean _autoRewind;
50    /** ByteOrder for all allocated buffers */
51    private final ByteOrder _order;
52    /** the mod count of the current buffer (changes on every realloc) */
53    private int _modCount;
54    
55    protected TempBufferHolder(boolean autoRewind, ByteOrder order) {
56      _autoRewind = autoRewind;
57      _order = order;
58    }
59  
60    /**
61     * @return the modification count of the current buffer (this count is
62     *         changed every time the buffer is reallocated)
63     */
64    public int getModCount() {
65      return _modCount;
66    }
67    
68    /**
69     * Creates a new TempBufferHolder.
70     * @param type the type of reference desired for any created buffer
71     * @param autoRewind whether or not every get automatically rewinds the
72     *                   buffer
73     */
74    public static TempBufferHolder newHolder(Type type, boolean autoRewind) {
75      return newHolder(type, autoRewind, PageChannel.DEFAULT_BYTE_ORDER);
76    }
77    
78    /**
79     * Creates a new TempBufferHolder.
80     * @param type the type of reference desired for any created buffer
81     * @param autoRewind whether or not every get automatically rewinds the
82     *                   buffer
83     * @param order byte order for all allocated buffers
84     */
85    public static TempBufferHolder newHolder(Type type, boolean autoRewind,
86                                             ByteOrder order)
87    {
88      switch(type) {
89      case HARD:
90        return new HardTempBufferHolder(autoRewind, order);
91      case SOFT:
92        return new SoftTempBufferHolder(autoRewind, order);
93      case NONE:
94        return new NoneTempBufferHolder(autoRewind, order);
95      default:
96        throw new IllegalStateException("Unknown type " + type);
97      }
98    }
99  
100   /**
101    * Returns a ByteBuffer of at least the defined page size, with the limit
102    * set to the page size, and the predefined byteOrder.  Will be rewound iff
103    * autoRewind is enabled for this buffer.
104    */
105   public final ByteBuffer getPageBuffer(PageChannel pageChannel) {
106     return getBuffer(pageChannel, pageChannel.getFormat().PAGE_SIZE);
107   }
108 
109   /**
110    * Returns a ByteBuffer of at least the given size, with the limit set to
111    * the given size, and the predefined byteOrder.  Will be rewound iff
112    * autoRewind is enabled for this buffer.
113    */
114   public final ByteBuffer getBuffer(PageChannel pageChannel, int size) {
115     ByteBuffer buffer = getExistingBuffer();
116     if((buffer == null) || (buffer.capacity() < size)) {
117       buffer = PageChannel.createBuffer(size, _order);
118       ++_modCount;
119       setNewBuffer(buffer);
120     } else {
121       buffer.limit(size);
122     }
123     if(_autoRewind) {
124       buffer.rewind();
125     }
126     return buffer;
127   }
128 
129   /**
130    * @return the currently referenced buffer, {@code null} if none
131    */
132   public abstract ByteBuffer getExistingBuffer();
133   
134   /**
135    * Releases any referenced memory.
136    */
137   public abstract void clear();
138 
139   /**
140    * Sets a new buffer for this holder.
141    */
142   protected abstract void setNewBuffer(ByteBuffer newBuffer);
143   
144   /**
145    * TempBufferHolder which has a hard reference to the buffer.
146    */
147   private static final class HardTempBufferHolder extends TempBufferHolder
148   {
149     private ByteBuffer _buffer;
150 
151     private HardTempBufferHolder(boolean autoRewind, ByteOrder order) {
152       super(autoRewind, order);
153     }
154     
155     @Override
156     public ByteBuffer getExistingBuffer() {
157       return _buffer;
158     }
159     
160     @Override
161     protected void setNewBuffer(ByteBuffer newBuffer) {
162       _buffer = newBuffer;
163     }
164 
165     @Override
166     public void clear() {
167       _buffer = null;
168     }
169   }
170   
171   /**
172    * TempBufferHolder which has a soft reference to the buffer.
173    */
174   private static final class SoftTempBufferHolder extends TempBufferHolder
175   {
176     private Reference<ByteBuffer> _buffer = EMPTY_BUFFER_REF;
177 
178     private SoftTempBufferHolder(boolean autoRewind, ByteOrder order) {
179       super(autoRewind, order);
180     }
181     
182     @Override
183     public ByteBuffer getExistingBuffer() {
184       return _buffer.get();
185     }
186     
187     @Override
188     protected void setNewBuffer(ByteBuffer newBuffer) {
189       _buffer.clear();
190       _buffer = new SoftReference<ByteBuffer>(newBuffer);
191     }
192 
193     @Override
194     public void clear() {
195       _buffer.clear();
196     }
197   }
198   
199   /**
200    * TempBufferHolder which has a no reference to the buffer.
201    */
202   private static final class NoneTempBufferHolder extends TempBufferHolder
203   {
204     private NoneTempBufferHolder(boolean autoRewind, ByteOrder order) {
205       super(autoRewind, order);
206     }
207     
208     @Override
209     public ByteBuffer getExistingBuffer() {
210       return null;
211     }
212     
213     @Override
214     protected void setNewBuffer(ByteBuffer newBuffer) {
215       // nothing to do
216     }
217 
218     @Override
219     public void clear() {
220       // nothing to do
221     }
222   }
223   
224 }