File D:\maven-qcr-plugin-testsunitaires\qcr4java\h2-1.3.170-sources\target\site\qc\lecode\store\PageStreamTrunk.java.html

1 /*
2 * Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
3 * Version 1.0, and under the Eclipse Public License, Version 1.0
4 * (http://h2database.com/html/license.html).
5 * Initial Developer: H2 Group
6 */
7 package org.h2.store;
8
9 import org.h2.constant.ErrorCode;
10 import org.h2.engine.Session;
11 import org.h2.message.DbException;
12
13 /**
14 * A trunk page of a stream. It contains the page numbers of the stream, and the
15 * page number of the next trunk. The format is:
16 * <ul>
17 * <li>page type: byte (0)</li>
18 * <li>checksum: short (1-2)</li>
19 * <li>previous trunk page, or 0 if none: int (3-6)</li>
20 * <li>log key: int (7-10)</li>
21 * <li>next trunk page: int (11-14)</li>
22 * <li>number of pages: short (15-16)</li>
23 * <li>page ids (17-)</li>
24 * </ul>
25 */
26 public class PageStreamTrunk extends Page {
27
28 private static final int DATA_START = 17;
29
30 /**
31 * The previous stream trunk.
32 */
33 int parent;
34
35 /**
36 * The next stream trunk.
37 */
38 int nextTrunk;
39
40 private final PageStore store;
41 private int logKey;
42 private int[] pageIds;
43 private int pageCount;
44 private Data data;
45
46 private PageStreamTrunk(PageStore store, int parent, int pageId, int next, int logKey, int[] pageIds) {
47 setPos(pageId);
48 this.parent = parent;
49 this.store = store;
50 this.nextTrunk = next;
51 this.logKey = logKey;
52 this.pageCount = pageIds.length;
53 this.pageIds = pageIds;
54 }
55
56 private PageStreamTrunk(PageStore store, Data data, int pageId) {
57 setPos(pageId);
58 this.data = data;
59 this.store = store;
60 }
61
62 /**
63 * Read a stream trunk page.
64 *
65 * @param store the page store
66 * @param data the data
67 * @param pageId the page id
68 * @return the page
69 */
70 static PageStreamTrunk read(PageStore store, Data data, int pageId) {
71 PageStreamTrunk p = new PageStreamTrunk(store, data, pageId);
72 p.read();
73 return p;
74 }
75
76 /**
77 * Create a new stream trunk page.
78 *
79 * @param store the page store
80 * @param parent the parent page
81 * @param pageId the page id
82 * @param next the next trunk page
83 * @param logKey the log key
84 * @param pageIds the stream data page ids
85 * @return the page
86 */
87 static PageStreamTrunk create(PageStore store, int parent, int pageId, int next, int logKey, int[] pageIds) {
88 return new PageStreamTrunk(store, parent, pageId, next, logKey, pageIds);
89 }
90
91 /**
92 * Read the page from the disk.
93 */
94 private void read() {
95 data.reset();
96 data.readByte();
97 data.readShortInt();
98 parent = data.readInt();
99 logKey = data.readInt();
100 nextTrunk = data.readInt();
101 pageCount = data.readShortInt();
102 pageIds = new int[pageCount];
103 for (int i = 0; i < pageCount; i++) {
104 pageIds[i] = data.readInt();
105 }
106 }
107
108 /**
109 * Get the data page id at the given position.
110 *
111 * @param index the index (0, 1, ...)
112 * @return the value, or -1 if the index is too large
113 */
114 int getPageData(int index) {
115 if (index >= pageIds.length) {
116 return -1;
117 }
118 return pageIds[index];
119 }
120
121 public void write() {
122 data = store.createData();
123 data.writeByte((byte) Page.TYPE_STREAM_TRUNK);
124 data.writeShortInt(0);
125 data.writeInt(parent);
126 data.writeInt(logKey);
127 data.writeInt(nextTrunk);
128 data.writeShortInt(pageCount);
129 for (int i = 0; i < pageCount; i++) {
130 data.writeInt(pageIds[i]);
131 }
132 store.writePage(getPos(), data);
133 }
134
135 /**
136 * Get the number of pages that can be addressed in a stream trunk page.
137 *
138 * @param pageSize the page size
139 * @return the number of pages
140 */
141 static int getPagesAddressed(int pageSize) {
142 return (pageSize - DATA_START) / 4;
143 }
144
145 /**
146 * Check if the given data page is in this trunk page.
147 *
148 * @param dataPageId the page id
149 * @return true if it is
150 */
151 boolean contains(int dataPageId) {
152 for (int i = 0; i < pageCount; i++) {
153 if (pageIds[i] == dataPageId) {
154 return true;
155 }
156 }
157 return false;
158 }
159
160 /**
161 * Free this page and all data pages. Pages after the last used data page
162 * (if within this list) are empty and therefore not just freed, but marked
163 * as not used.
164 *
165 * @param lastUsedPage the last used data page
166 * @return the number of pages freed
167 */
168 int free(int lastUsedPage) {
169 store.free(getPos(), false);
170 int freed = 1;
171 boolean notUsed = false;
172 for (int i = 0; i < pageCount; i++) {
173 int page = pageIds[i];
174 if (notUsed) {
175 store.freeUnused(page);
176 } else {
177 store.free(page, false);
178 }
179 freed++;
180 if (page == lastUsedPage) {
181 notUsed = true;
182 }
183 }
184 return freed;
185 }
186
187 /**
188 * Get the estimated memory size.
189 *
190 * @return number of double words (4 bytes)
191 */
192 public int getMemory() {
193 return store.getPageSize() >> 2;
194 }
195
196 public void moveTo(Session session, int newPos) {
197 // not required
198 }
199
200 int getLogKey() {
201 return logKey;
202 }
203
204 public int getNextTrunk() {
205 return nextTrunk;
206 }
207
208 /**
209 * An iterator over page stream trunk pages.
210 */
211 static class Iterator {
212
213 private final PageStore store;
214 private int first;
215 private int next;
216 private int previous;
217 private boolean canDelete;
218 private int current;
219
220 Iterator(PageStore store, int first) {
221 this.store = store;
222 this.next = first;
223 }
224
225 int getCurrentPageId() {
226 return current;
227 }
228
229 /**
230 * Get the next trunk page or null if no next trunk page.
231 *
232 * @return the next trunk page or null
233 */
234 PageStreamTrunk next() {
235 canDelete = false;
236 if (first == 0) {
237 first = next;
238 } else if (first == next) {
239 return null;
240 }
241 if (next == 0 || next >= store.getPageCount()) {
242 return null;
243 }
244 Page p;
245 current = next;
246 try {
247 p = store.getPage(next);
248 } catch (DbException e) {
249 if (e.getErrorCode() == ErrorCode.FILE_CORRUPTED_1) {
250 // wrong checksum means end of stream
251 return null;
252 }
253 throw e;
254 }
255 if (p == null || p instanceof PageStreamTrunk || p instanceof PageStreamData) {
256 canDelete = true;
257 }
258 if (!(p instanceof PageStreamTrunk)) {
259 return null;
260 }
261 PageStreamTrunk t = (PageStreamTrunk) p;
262 if (previous > 0 && t.parent != previous) {
263 return null;
264 }
265 previous = next;
266 next = t.nextTrunk;
267 return t;
268 }
269
270 /**
271 * Check if the current page can be deleted. It can if it's empty, a
272 * stream trunk, or a stream data page.
273 *
274 * @return true if it can be deleted
275 */
276 boolean canDelete() {
277 return canDelete;
278 }
279
280 }
281
282 public boolean canRemove() {
283 return true;
284 }
285
286 public String toString() {
287 return "page[" + getPos() + "] stream trunk key:" + logKey + " next:" + nextTrunk;
288 }
289
290 public boolean canMove() {
291 return false;
292 }
293
294 }
295