File D:\maven-qcr-plugin-testsunitaires\qcr4java\h2-1.3.170-sources\target\site\qc\lecode\result\ResultDiskBuffer.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.result;
8
9 import java.io.ByteArrayOutputStream;
10 import java.util.ArrayList;
11 import org.h2.engine.Constants;
12 import org.h2.engine.Database;
13 import org.h2.engine.Session;
14 import org.h2.message.DbException;
15 import org.h2.store.Data;
16 import org.h2.store.FileStore;
17 import org.h2.util.New;
18 import org.h2.value.Value;
19
20 /**
21 * This class implements the disk buffer for the LocalResult class.
22 */
23 class ResultDiskBuffer implements ResultExternal {
24
25 private static final int READ_AHEAD = 128;
26
27 private final Data rowBuff;
28 private final ArrayList<ResultDiskTape> tapes;
29 private final ResultDiskTape mainTape;
30 private final SortOrder sort;
31 private final int columnCount;
32 private final int maxBufferSize;
33
34 private FileStore file;
35 private int rowCount;
36
37 private final ResultDiskBuffer parent;
38 private boolean closed;
39 private int childCount;
40
41 /**
42 * Represents a virtual disk tape for the merge sort algorithm.
43 * Each virtual disk tape is a region of the temp file.
44 */
45 static class ResultDiskTape {
46
47 /**
48 * The start position of this tape in the file.
49 */
50 long start;
51
52 /**
53 * The end position of this tape in the file.
54 */
55 long end;
56
57 /**
58 * The current read position.
59 */
60 long pos;
61
62 /**
63 * A list of rows in the buffer.
64 */
65 ArrayList<Value[]> buffer = New.arrayList();
66 }
67
68 ResultDiskBuffer(Session session, SortOrder sort, int columnCount) {
69 this.parent = null;
70 this.sort = sort;
71 this.columnCount = columnCount;
72 Database db = session.getDatabase();
73 rowBuff = Data.create(db, Constants.DEFAULT_PAGE_SIZE);
74 String fileName = db.createTempFile();
75 file = db.openFile(fileName, "rw", false);
76 file.setCheckedWriting(false);
77 file.seek(FileStore.HEADER_LENGTH);
78 if (sort != null) {
79 tapes = New.arrayList();
80 mainTape = null;
81 } else {
82 tapes = null;
83 mainTape = new ResultDiskTape();
84 mainTape.pos = FileStore.HEADER_LENGTH;
85 }
86 this.maxBufferSize = db.getSettings().largeResultBufferSize;
87 }
88
89 private ResultDiskBuffer(ResultDiskBuffer parent) {
90 this.parent = parent;
91 rowBuff = Data.create(parent.rowBuff.getHandler(), Constants.DEFAULT_PAGE_SIZE);
92 file = parent.file;
93 if (parent.tapes != null) {
94 tapes = New.arrayList();
95 for (ResultDiskTape t : parent.tapes) {
96 ResultDiskTape t2 = new ResultDiskTape();
97 t2.pos = t2.start = t.start;
98 t2.end = t.end;
99 tapes.add(t2);
100 }
101 } else {
102 tapes = null;
103 }
104 if (parent.mainTape != null) {
105 mainTape = new ResultDiskTape();
106 mainTape.pos = FileStore.HEADER_LENGTH;
107 mainTape.start = parent.mainTape.start;
108 mainTape.end = parent.mainTape.end;
109 } else {
110 mainTape = null;
111 }
112 sort = parent.sort;
113 columnCount = parent.columnCount;
114 maxBufferSize = parent.maxBufferSize;
115 }
116
117 public synchronized ResultDiskBuffer createShallowCopy() {
118 if (closed || parent != null) {
119 return null;
120 }
121 childCount++;
122 return new ResultDiskBuffer(this);
123 }
124
125 public int addRows(ArrayList<Value[]> rows) {
126 if (sort != null) {
127 sort.sort(rows);
128 }
129 Data buff = rowBuff;
130 long start = file.getFilePointer();
131 ByteArrayOutputStream buffer = new ByteArrayOutputStream();
132 int bufferLen = 0;
133 for (Value[] row : rows) {
134 buff.reset();
135 buff.writeInt(0);
136 for (int j = 0; j < columnCount; j++) {
137 Value v = row[j];
138 buff.checkCapacity(buff.getValueLen(v));
139 buff.writeValue(v);
140 }
141 buff.fillAligned();
142 int len = buff.length();
143 buff.setInt(0, len);
144 if (maxBufferSize > 0) {
145 buffer.write(buff.getBytes(), 0, len);
146 bufferLen += len;
147 if (bufferLen > maxBufferSize) {
148 byte[] data = buffer.toByteArray();
149 buffer.reset();
150 file.write(data, 0, data.length);
151 bufferLen = 0;
152 }
153 } else {
154 file.write(buff.getBytes(), 0, len);
155 }
156 }
157 if (bufferLen > 0) {
158 byte[] data = buffer.toByteArray();
159 file.write(data, 0, data.length);
160 }
161 if (sort != null) {
162 ResultDiskTape tape = new ResultDiskTape();
163 tape.start = start;
164 tape.end = file.getFilePointer();
165 tapes.add(tape);
166 } else {
167 mainTape.end = file.getFilePointer();
168 }
169 rowCount += rows.size();
170 return rowCount;
171 }
172
173 public void done() {
174 file.seek(FileStore.HEADER_LENGTH);
175 file.autoDelete();
176 }
177
178 public void reset() {
179 if (sort != null) {
180 for (ResultDiskTape tape : tapes) {
181 tape.pos = tape.start;
182 tape.buffer = New.arrayList();
183 }
184 } else {
185 mainTape.pos = FileStore.HEADER_LENGTH;
186 mainTape.buffer = New.arrayList();
187 }
188 }
189
190 private void readRow(ResultDiskTape tape) {
191 int min = Constants.FILE_BLOCK_SIZE;
192 Data buff = rowBuff;
193 buff.reset();
194 file.readFully(buff.getBytes(), 0, min);
195 int len = buff.readInt();
196 buff.checkCapacity(len);
197 if (len - min > 0) {
198 file.readFully(buff.getBytes(), min, len - min);
199 }
200 tape.pos += len;
201 Value[] row = new Value[columnCount];
202 for (int k = 0; k < columnCount; k++) {
203 row[k] = buff.readValue();
204 }
205 tape.buffer.add(row);
206 }
207
208 public Value[] next() {
209 return sort != null ? nextSorted() : nextUnsorted();
210 }
211
212 private Value[] nextUnsorted() {
213 file.seek(mainTape.pos);
214 if (mainTape.buffer.size() == 0) {
215 for (int j = 0; mainTape.pos < mainTape.end && j < READ_AHEAD; j++) {
216 readRow(mainTape);
217 }
218 }
219 Value[] row = mainTape.buffer.get(0);
220 mainTape.buffer.remove(0);
221 return row;
222 }
223
224 private Value[] nextSorted() {
225 int next = -1;
226 for (int i = 0, size = tapes.size(); i < size; i++) {
227 ResultDiskTape tape = tapes.get(i);
228 if (tape.buffer.size() == 0 && tape.pos < tape.end) {
229 file.seek(tape.pos);
230 for (int j = 0; tape.pos < tape.end && j < READ_AHEAD; j++) {
231 readRow(tape);
232 }
233 }
234 if (tape.buffer.size() > 0) {
235 if (next == -1) {
236 next = i;
237 } else if (compareTapes(tape, tapes.get(next)) < 0) {
238 next = i;
239 }
240 }
241 }
242 ResultDiskTape t = tapes.get(next);
243 Value[] row = t.buffer.get(0);
244 t.buffer.remove(0);
245 return row;
246 }
247
248 private int compareTapes(ResultDiskTape a, ResultDiskTape b) {
249 Value[] va = a.buffer.get(0);
250 Value[] vb = b.buffer.get(0);
251 return sort.compare(va, vb);
252 }
253
254 private synchronized void closeChild() {
255 if (--childCount == 0 && closed) {
256 file.closeAndDeleteSilently();
257 file = null;
258 }
259 }
260
261 protected void finalize() {
262 close();
263 }
264
265 public synchronized void close() {
266 if (closed) {
267 return;
268 }
269 closed = true;
270 if (parent != null) {
271 parent.closeChild();
272 } else if (file != null) {
273 if (childCount == 0) {
274 file.closeAndDeleteSilently();
275 file = null;
276 }
277 }
278 }
279
280 public int removeRow(Value[] values) {
281 throw DbException.throwInternalError();
282 }
283
284 public boolean contains(Value[] values) {
285 throw DbException.throwInternalError();
286 }
287
288 public int addRow(Value[] values) {
289 throw DbException.throwInternalError();
290 }
291
292 }
293