1 /*
2 Copyright (c) 2007 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.io.IOException;
20 import java.nio.ByteBuffer;
21
22 /**
23 * Manages a reference to a page buffer.
24 *
25 * @author James Ahlborn
26 */
27 public final class TempPageHolder {
28
29 private int _pageNumber = PageChannel.INVALID_PAGE_NUMBER;
30 private final TempBufferHolder _buffer;
31 /** the last "modification" count of the buffer that this holder observed.
32 this is tracked so that the page data can be re-read if the underlying
33 buffer has been discarded since the last page read */
34 private int _bufferModCount;
35
36 private TempPageHolder(TempBufferHolder.Type type) {
37 _buffer = TempBufferHolder.newHolder(type, false);
38 _bufferModCount = _buffer.getModCount();
39 }
40
41 /**
42 * Creates a new TempPageHolder.
43 * @param type the type of reference desired for any create page buffers
44 */
45 public static TempPageHolder newHolder(TempBufferHolder.Type type) {
46 return new TempPageHolder(type);
47 }
48
49 /**
50 * @return the currently set page number
51 */
52 public int getPageNumber() {
53 return _pageNumber;
54 }
55
56 /**
57 * @return the page for the current page number, reading as necessary,
58 * position and limit are unchanged
59 */
60 public ByteBuffer getPage(PageChannel pageChannel)
61 throws IOException
62 {
63 return setPage(pageChannel, _pageNumber, false);
64 }
65
66 /**
67 * Sets the current page number and returns that page
68 * @return the page for the new page number, reading as necessary, resets
69 * position
70 */
71 public ByteBuffer setPage(PageChannel pageChannel, int pageNumber)
72 throws IOException
73 {
74 return setPage(pageChannel, pageNumber, true);
75 }
76
77 private ByteBuffer setPage(PageChannel pageChannel, int pageNumber,
78 boolean rewind)
79 throws IOException
80 {
81 ByteBuffer buffer = _buffer.getPageBuffer(pageChannel);
82 int modCount = _buffer.getModCount();
83 if((pageNumber != _pageNumber) || (_bufferModCount != modCount)) {
84 _pageNumber = pageNumber;
85 _bufferModCount = modCount;
86 pageChannel.readPage(buffer, _pageNumber);
87 } else if(rewind) {
88 buffer.rewind();
89 }
90
91 return buffer;
92 }
93
94 /**
95 * Allocates a new buffer in the database (with undefined data) and returns
96 * a new empty buffer.
97 */
98 public ByteBuffer setNewPage(PageChannel pageChannel)
99 throws IOException
100 {
101 // ditch any current data
102 clear();
103 // allocate a new page in the database
104 _pageNumber = pageChannel.allocateNewPage();
105 // return a new buffer
106 return _buffer.getPageBuffer(pageChannel);
107 }
108
109 /**
110 * Forces any current page data to be disregarded (any
111 * <code>getPage</code>/<code>setPage</code> call must reload page data).
112 * Does not necessarily release any memory.
113 */
114 public void invalidate() {
115 possiblyInvalidate(_pageNumber, null);
116 }
117
118 /**
119 * Forces any current page data to be disregarded if it matches the given
120 * page number (any <code>getPage</code>/<code>setPage</code> call must
121 * reload page data) and is not the given buffer. Does not necessarily
122 * release any memory.
123 */
124 public void possiblyInvalidate(int modifiedPageNumber,
125 ByteBuffer modifiedBuffer) {
126 ByteBuffer curBuffer = _buffer.getExistingBuffer();
127 if((curBuffer != null) && (modifiedBuffer == curBuffer)) {
128 // no worries, our buffer was the one modified
129 return;
130 }
131 // the page is forgotten even when the buffer has gone. a holder which
132 // still names a page which was given back would write into a page the
133 // database has handed to something else, and a holder which only missed a
134 // change loses no more than one read
135 if(modifiedPageNumber == _pageNumber) {
136 _pageNumber = PageChannel.INVALID_PAGE_NUMBER;
137 }
138 }
139
140 /**
141 * Forces any current page data to be disregarded (any
142 * <code>getPage</code>/<code>setPage</code> call must reload page data) and
143 * releases any referenced memory.
144 */
145 public void clear() {
146 invalidate();
147 _buffer.clear();
148 }
149
150 }