001: // Copyright (c) 2008 Health Market Science, Inc.
002:
003: package com.healthmarketscience.jackcess;
004:
005: import java.lang.ref.Reference;
006: import java.lang.ref.SoftReference;
007: import java.nio.ByteBuffer;
008: import java.nio.ByteOrder;
009:
010: /**
011: * Manages a reference to a ByteBuffer.
012: *
013: * @author James Ahlborn
014: */
015: public abstract class TempBufferHolder {
016:
017: private static final Reference<ByteBuffer> EMPTY_BUFFER_REF = new SoftReference<ByteBuffer>(
018: null);
019:
020: /**
021: * The caching type for the buffer holder.
022: */
023: public enum Type {
024: /** a hard reference is maintained to the created buffer */
025: HARD,
026: /** a soft reference is maintained to the created buffer (may be garbage
027: collected if memory gets tight) */
028: SOFT,
029: /** no reference is maintained to a created buffer (new buffer every
030: time) */
031: NONE;
032: }
033:
034: /** whether or not every get automatically rewinds the buffer */
035: private final boolean _autoRewind;
036: /** ByteOrder for all allocated buffers */
037: private final ByteOrder _order;
038: /** the mod count of the current buffer (changes on every realloc) */
039: private int _modCount;
040:
041: protected TempBufferHolder(boolean autoRewind, ByteOrder order) {
042: _autoRewind = autoRewind;
043: _order = order;
044: }
045:
046: /**
047: * @return the modification count of the current buffer (this count is
048: * changed every time the buffer is reallocated)
049: */
050: public int getModCount() {
051: return _modCount;
052: }
053:
054: /**
055: * Creates a new TempBufferHolder.
056: * @param type the type of reference desired for any created buffer
057: * @param autoRewind whether or not every get automatically rewinds the
058: * buffer
059: */
060: public static TempBufferHolder newHolder(Type type,
061: boolean autoRewind) {
062: return newHolder(type, autoRewind,
063: PageChannel.DEFAULT_BYTE_ORDER);
064: }
065:
066: /**
067: * Creates a new TempBufferHolder.
068: * @param type the type of reference desired for any created buffer
069: * @param autoRewind whether or not every get automatically rewinds the
070: * buffer
071: * @param order byte order for all allocated buffers
072: */
073: public static TempBufferHolder newHolder(Type type,
074: boolean autoRewind, ByteOrder order) {
075: switch (type) {
076: case HARD:
077: return new HardTempBufferHolder(autoRewind, order);
078: case SOFT:
079: return new SoftTempBufferHolder(autoRewind, order);
080: case NONE:
081: return new NoneTempBufferHolder(autoRewind, order);
082: default:
083: throw new IllegalStateException("Unknown type " + type);
084: }
085: }
086:
087: /**
088: * Returns a ByteBuffer of at least the defined page size, with the limit
089: * set to the page size, and the predefined byteOrder. Will be rewound iff
090: * autoRewind is enabled for this buffer.
091: */
092: public final ByteBuffer getPageBuffer(PageChannel pageChannel) {
093: return getBuffer(pageChannel, pageChannel.getFormat().PAGE_SIZE);
094: }
095:
096: /**
097: * Returns a ByteBuffer of at least the given size, with the limit set to
098: * the given size, and the predefined byteOrder. Will be rewound iff
099: * autoRewind is enabled for this buffer.
100: */
101: public final ByteBuffer getBuffer(PageChannel pageChannel, int size) {
102: ByteBuffer buffer = getExistingBuffer();
103: if ((buffer == null) || (buffer.capacity() < size)) {
104: buffer = pageChannel.createBuffer(size, _order);
105: ++_modCount;
106: setNewBuffer(buffer);
107: } else {
108: buffer.limit(size);
109: }
110: if (_autoRewind) {
111: buffer.rewind();
112: }
113: return buffer;
114: }
115:
116: /**
117: * @returns the currently referenced buffer, {@code null} if none
118: */
119: public abstract ByteBuffer getExistingBuffer();
120:
121: /**
122: * Releases any referenced memory.
123: */
124: public abstract void clear();
125:
126: /**
127: * Sets a new buffer for this holder.
128: */
129: protected abstract void setNewBuffer(ByteBuffer newBuffer);
130:
131: /**
132: * TempBufferHolder which has a hard reference to the buffer.
133: */
134: private static final class HardTempBufferHolder extends
135: TempBufferHolder {
136: private ByteBuffer _buffer;
137:
138: private HardTempBufferHolder(boolean autoRewind, ByteOrder order) {
139: super (autoRewind, order);
140: }
141:
142: @Override
143: public ByteBuffer getExistingBuffer() {
144: return _buffer;
145: }
146:
147: @Override
148: protected void setNewBuffer(ByteBuffer newBuffer) {
149: _buffer = newBuffer;
150: }
151:
152: @Override
153: public void clear() {
154: _buffer = null;
155: }
156: }
157:
158: /**
159: * TempBufferHolder which has a soft reference to the buffer.
160: */
161: private static final class SoftTempBufferHolder extends
162: TempBufferHolder {
163: private Reference<ByteBuffer> _buffer = EMPTY_BUFFER_REF;
164:
165: private SoftTempBufferHolder(boolean autoRewind, ByteOrder order) {
166: super (autoRewind, order);
167: }
168:
169: @Override
170: public ByteBuffer getExistingBuffer() {
171: return _buffer.get();
172: }
173:
174: @Override
175: protected void setNewBuffer(ByteBuffer newBuffer) {
176: _buffer.clear();
177: _buffer = new SoftReference<ByteBuffer>(newBuffer);
178: }
179:
180: @Override
181: public void clear() {
182: _buffer.clear();
183: }
184: }
185:
186: /**
187: * TempBufferHolder which has a no reference to the buffer.
188: */
189: private static final class NoneTempBufferHolder extends
190: TempBufferHolder {
191: private NoneTempBufferHolder(boolean autoRewind, ByteOrder order) {
192: super (autoRewind, order);
193: }
194:
195: @Override
196: public ByteBuffer getExistingBuffer() {
197: return null;
198: }
199:
200: @Override
201: protected void setNewBuffer(ByteBuffer newBuffer) {
202: // nothing to do
203: }
204:
205: @Override
206: public void clear() {
207: // nothing to do
208: }
209: }
210:
211: }
|