001: /*
002: Copyright (c) 2007 Health Market Science, Inc.
003:
004: This library is free software; you can redistribute it and/or
005: modify it under the terms of the GNU Lesser General Public
006: License as published by the Free Software Foundation; either
007: version 2.1 of the License, or (at your option) any later version.
008:
009: This library is distributed in the hope that it will be useful,
010: but WITHOUT ANY WARRANTY; without even the implied warranty of
011: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: Lesser General Public License for more details.
013:
014: You should have received a copy of the GNU Lesser General Public
015: License along with this library; if not, write to the Free Software
016: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
017: USA
018:
019: You can contact Health Market Science at info@healthmarketscience.com
020: or at the following address:
021:
022: Health Market Science
023: 2700 Horizon Drive
024: Suite 200
025: King of Prussia, PA 19406
026: */
027:
028: package com.healthmarketscience.jackcess;
029:
030: import java.io.IOException;
031: import java.nio.ByteBuffer;
032:
033: /**
034: * Manages a reference to a page buffer.
035: *
036: * @author James Ahlborn
037: */
038: public final class TempPageHolder {
039:
040: private int _pageNumber = PageChannel.INVALID_PAGE_NUMBER;
041: private final TempBufferHolder _buffer;
042: /** the last "modification" count of the buffer that this holder observed.
043: this is tracked so that the page data can be re-read if the underlying
044: buffer has been discarded since the last page read */
045: private int _bufferModCount;
046:
047: private TempPageHolder(TempBufferHolder.Type type) {
048: _buffer = TempBufferHolder.newHolder(type, false);
049: _bufferModCount = _buffer.getModCount();
050: }
051:
052: /**
053: * Creates a new TempPageHolder.
054: * @param type the type of reference desired for any create page buffers
055: */
056: public static TempPageHolder newHolder(TempBufferHolder.Type type) {
057: return new TempPageHolder(type);
058: }
059:
060: /**
061: * @return the currently set page number
062: */
063: public int getPageNumber() {
064: return _pageNumber;
065: }
066:
067: /**
068: * @return the page for the current page number, reading as necessary,
069: * position and limit are unchanged
070: */
071: public ByteBuffer getPage(PageChannel pageChannel)
072: throws IOException {
073: return setPage(pageChannel, _pageNumber, false);
074: }
075:
076: /**
077: * Sets the current page number and returns that page
078: * @return the page for the new page number, reading as necessary, resets
079: * position
080: */
081: public ByteBuffer setPage(PageChannel pageChannel, int pageNumber)
082: throws IOException {
083: return setPage(pageChannel, pageNumber, true);
084: }
085:
086: private ByteBuffer setPage(PageChannel pageChannel, int pageNumber,
087: boolean rewind) throws IOException {
088: ByteBuffer buffer = _buffer.getPageBuffer(pageChannel);
089: int modCount = _buffer.getModCount();
090: if ((pageNumber != _pageNumber)
091: || (_bufferModCount != modCount)) {
092: _pageNumber = pageNumber;
093: _bufferModCount = modCount;
094: pageChannel.readPage(buffer, _pageNumber);
095: } else if (rewind) {
096: buffer.rewind();
097: }
098:
099: return buffer;
100: }
101:
102: /**
103: * Allocates a new buffer in the database (with undefined data) and returns
104: * a new empty buffer.
105: */
106: public ByteBuffer setNewPage(PageChannel pageChannel)
107: throws IOException {
108: // ditch any current data
109: clear();
110: // allocate a new page in the database
111: _pageNumber = pageChannel.allocateNewPage();
112: // return a new buffer
113: return _buffer.getPageBuffer(pageChannel);
114: }
115:
116: /**
117: * Forces any current page data to be disregarded (any
118: * <code>getPage</code>/<code>setPage</code> call must reload page data).
119: * Does not necessarily release any memory.
120: */
121: public void invalidate() {
122: possiblyInvalidate(_pageNumber, null);
123: }
124:
125: /**
126: * Forces any current page data to be disregarded if it matches the given
127: * page number (any <code>getPage</code>/<code>setPage</code> call must
128: * reload page data) and is not the given buffer. Does not necessarily
129: * release any memory.
130: */
131: public void possiblyInvalidate(int modifiedPageNumber,
132: ByteBuffer modifiedBuffer) {
133: if (modifiedBuffer == _buffer.getExistingBuffer()) {
134: // no worries, our buffer was the one modified (or is null, either way
135: // we'll need to reload)
136: return;
137: }
138: if (modifiedPageNumber == _pageNumber) {
139: _pageNumber = PageChannel.INVALID_PAGE_NUMBER;
140: }
141: }
142:
143: /**
144: * Forces any current page data to be disregarded (any
145: * <code>getPage</code>/<code>setPage</code> call must reload page data) and
146: * releases any referenced memory.
147: */
148: public void clear() {
149: invalidate();
150: _buffer.clear();
151: }
152:
153: }
|