|
1 |
| |
|
2 |
| |
|
3 |
| |
|
4 |
| |
|
5 |
| |
|
6 |
| |
|
7 |
| |
|
8 |
| |
|
9 |
| |
|
10 |
| |
|
11 |
| |
|
12 |
| |
|
13 |
| |
|
14 |
| |
|
15 |
| |
|
16 |
| |
|
17 |
| |
|
18 |
| |
|
19 |
| |
|
20 |
| package org.apache.xindice.core.filer; |
|
21 |
| |
|
22 |
| import org.apache.commons.logging.Log; |
|
23 |
| import org.apache.commons.logging.LogFactory; |
|
24 |
| import org.apache.xindice.core.DBException; |
|
25 |
| import org.apache.xindice.core.FaultCodes; |
|
26 |
| import org.apache.xindice.core.data.Key; |
|
27 |
| import org.apache.xindice.core.data.Record; |
|
28 |
| import org.apache.xindice.core.data.RecordSet; |
|
29 |
| import org.apache.xindice.core.data.Value; |
|
30 |
| |
|
31 |
| import java.io.DataInput; |
|
32 |
| import java.io.DataOutput; |
|
33 |
| import java.io.File; |
|
34 |
| import java.io.IOException; |
|
35 |
| import java.io.RandomAccessFile; |
|
36 |
| import java.util.ArrayList; |
|
37 |
| import java.util.HashMap; |
|
38 |
| import java.util.Iterator; |
|
39 |
| import java.util.List; |
|
40 |
| |
|
41 |
| |
|
42 |
| |
|
43 |
| |
|
44 |
| |
|
45 |
| |
|
46 |
| |
|
47 |
| |
|
48 |
| |
|
49 |
| |
|
50 |
| |
|
51 |
| |
|
52 |
| |
|
53 |
| |
|
54 |
| |
|
55 |
| |
|
56 |
| |
|
57 |
| |
|
58 |
| |
|
59 |
| |
|
60 |
| |
|
61 |
| |
|
62 |
| |
|
63 |
| |
|
64 |
| |
|
65 |
| public class BTreeFiler extends BTree |
|
66 |
| implements Filer { |
|
67 |
| |
|
68 |
| private static final Log log = LogFactory.getLog(BTreeFiler.class); |
|
69 |
| |
|
70 |
| |
|
71 |
| |
|
72 |
| |
|
73 |
| protected static final byte RECORD = 20; |
|
74 |
| |
|
75 |
| |
|
76 |
| private BTreeFilerHeader fileHeader; |
|
77 |
| |
|
78 |
| |
|
79 |
1301
| public BTreeFiler() {
|
|
80 |
1301
| super();
|
|
81 |
1301
| fileHeader = (BTreeFilerHeader) getFileHeader();
|
|
82 |
| } |
|
83 |
| |
|
84 |
1301
| public void setLocation(File root, String location) {
|
|
85 |
1301
| setFile(new File(root, location + ".tbl"));
|
|
86 |
| } |
|
87 |
| |
|
88 |
20
| public String getName() {
|
|
89 |
20
| return "BTreeFiler";
|
|
90 |
| } |
|
91 |
| |
|
92 |
44231
| public Record readRecord(Key key) throws DBException {
|
|
93 |
44231
| return readRecord(key, false);
|
|
94 |
| } |
|
95 |
| |
|
96 |
46194
| public Record readRecord(Key key, boolean metaOnly) throws DBException {
|
|
97 |
46194
| if (key == null || key.getLength() == 0) {
|
|
98 |
8
| return null;
|
|
99 |
| } |
|
100 |
| |
|
101 |
46186
| checkOpened();
|
|
102 |
46186
| try {
|
|
103 |
46186
| long pos = findValue(key);
|
|
104 |
46186
| if (pos == VALUE_DOES_NOT_EXIST) {
|
|
105 |
8995
| return null;
|
|
106 |
| } |
|
107 |
| |
|
108 |
37191
| Page startPage = getPage(pos);
|
|
109 |
37191
| Value v = metaOnly ? null : readValue(startPage);
|
|
110 |
37191
| BTreeFilerPageHeader sph = (BTreeFilerPageHeader) startPage.getPageHeader();
|
|
111 |
| |
|
112 |
37191
| HashMap meta = new HashMap(2, 1.5F);
|
|
113 |
37191
| meta.put(Record.CREATED, new Long(sph.getCreated()));
|
|
114 |
37191
| meta.put(Record.MODIFIED, new Long(sph.getModified()));
|
|
115 |
| |
|
116 |
37191
| return new Record(key, v, meta);
|
|
117 |
| } catch (IOException e) { |
|
118 |
0
| throw new FilerException(FaultCodes.DBE_CANNOT_READ,
|
|
119 |
| "Can't read record '" + key + "': " + e.getMessage(), e); |
|
120 |
| } |
|
121 |
| } |
|
122 |
| |
|
123 |
13246
| public Record writeRecord(Key key, Value value) throws DBException {
|
|
124 |
13246
| if (key == null || key.getLength() == 0) {
|
|
125 |
2
| throw new FilerException(FaultCodes.DBE_CANNOT_CREATE, "Invalid key: null or empty");
|
|
126 |
| } |
|
127 |
13244
| if (value == null) {
|
|
128 |
1
| throw new FilerException(FaultCodes.DBE_CANNOT_CREATE, "Invalid value: null");
|
|
129 |
| } |
|
130 |
| |
|
131 |
13243
| checkOpened();
|
|
132 |
13243
| try {
|
|
133 |
13243
| long pos = addKey(key);
|
|
134 |
13243
| Page p = getPage(pos);
|
|
135 |
| |
|
136 |
13243
| BTreeFilerPageHeader ph = (BTreeFilerPageHeader) p.getPageHeader();
|
|
137 |
13242
| long t = System.currentTimeMillis();
|
|
138 |
13243
| if (ph.getStatus() == UNUSED) {
|
|
139 |
8206
| ph.setCreated(t);
|
|
140 |
| } |
|
141 |
13243
| ph.setModified(t);
|
|
142 |
13243
| ph.setStatus(RECORD);
|
|
143 |
| |
|
144 |
13243
| writeValue(p, value);
|
|
145 |
13243
| flush();
|
|
146 |
| |
|
147 |
13243
| HashMap meta = new HashMap(3);
|
|
148 |
13243
| meta.put(Record.CREATED, new Long(ph.getCreated()));
|
|
149 |
13243
| meta.put(Record.MODIFIED, new Long(t));
|
|
150 |
13242
| return new Record(key, value, meta);
|
|
151 |
| |
|
152 |
| } catch (IOException e) { |
|
153 |
| |
|
154 |
0
| throw new FilerException(FaultCodes.DBE_CANNOT_CREATE,
|
|
155 |
| "Can't write record '" + key + "': " + e.getMessage(), e); |
|
156 |
| } |
|
157 |
| } |
|
158 |
| |
|
159 |
2981
| public boolean deleteRecord(Key key) throws DBException {
|
|
160 |
2981
| if (key == null || key.getLength() == 0) {
|
|
161 |
2
| return false;
|
|
162 |
| } |
|
163 |
| |
|
164 |
2979
| checkOpened();
|
|
165 |
2979
| try {
|
|
166 |
2979
| long pos = removeValue(key);
|
|
167 |
2979
| if (pos == VALUE_DOES_NOT_EXIST) {
|
|
168 |
235
| return false;
|
|
169 |
| } |
|
170 |
| |
|
171 |
2744
| Page p = getPage(pos);
|
|
172 |
2744
| unlinkPages(p);
|
|
173 |
| |
|
174 |
2744
| fileHeader.decRecordCount();
|
|
175 |
| |
|
176 |
2744
| flush();
|
|
177 |
2744
| return true;
|
|
178 |
| } catch (IOException e) { |
|
179 |
0
| throw new FilerException(FaultCodes.DBE_CANNOT_DROP,
|
|
180 |
| "Can't delete record '" + key + "': " + e.getMessage(), e); |
|
181 |
| } |
|
182 |
| } |
|
183 |
| |
|
184 |
148
| public long getRecordCount() throws DBException {
|
|
185 |
148
| checkOpened();
|
|
186 |
148
| return fileHeader.getRecordCount();
|
|
187 |
| } |
|
188 |
| |
|
189 |
435
| public RecordSet getRecordSet() throws DBException {
|
|
190 |
435
| checkOpened();
|
|
191 |
435
| return new BTreeFilerRecordSet();
|
|
192 |
| } |
|
193 |
| |
|
194 |
| |
|
195 |
| |
|
196 |
| |
|
197 |
| private class BTreeFilerRecordSet implements RecordSet, BTreeCallback { |
|
198 |
| private List keys = new ArrayList(); |
|
199 |
| private Iterator iter; |
|
200 |
| |
|
201 |
435
| public BTreeFilerRecordSet() throws DBException {
|
|
202 |
435
| try {
|
|
203 |
435
| query(null, this);
|
|
204 |
435
| iter = keys.iterator();
|
|
205 |
| } catch (IOException e) { |
|
206 |
0
| throw new FilerException(FaultCodes.GEN_CRITICAL_ERROR,
|
|
207 |
| "Error generating RecordSet", e); |
|
208 |
| } |
|
209 |
| } |
|
210 |
| |
|
211 |
42987
| public synchronized boolean indexInfo(Value value, long pointer) {
|
|
212 |
42987
| keys.add(new Key(value));
|
|
213 |
42987
| return true;
|
|
214 |
| } |
|
215 |
| |
|
216 |
42983
| public synchronized Key getNextKey() {
|
|
217 |
42983
| return (Key) iter.next();
|
|
218 |
| } |
|
219 |
| |
|
220 |
4
| public synchronized Record getNextRecord() throws DBException {
|
|
221 |
4
| return readRecord((Key) iter.next(), false);
|
|
222 |
| } |
|
223 |
| |
|
224 |
0
| public synchronized Value getNextValue() throws DBException {
|
|
225 |
0
| return getNextRecord().getValue();
|
|
226 |
| } |
|
227 |
| |
|
228 |
43421
| public synchronized boolean hasMoreRecords() {
|
|
229 |
43421
| return iter.hasNext();
|
|
230 |
| } |
|
231 |
| } |
|
232 |
| |
|
233 |
| |
|
234 |
| |
|
235 |
1301
| protected FileHeader createFileHeader() {
|
|
236 |
1301
| return new BTreeFilerHeader();
|
|
237 |
| } |
|
238 |
| |
|
239 |
46819
| protected PageHeader createPageHeader() {
|
|
240 |
46819
| return new BTreeFilerPageHeader();
|
|
241 |
| } |
|
242 |
| |
|
243 |
| |
|
244 |
| |
|
245 |
| |
|
246 |
| private final class BTreeFilerHeader extends BTreeFileHeader { |
|
247 |
| private long totalBytes; |
|
248 |
| |
|
249 |
1301
| public BTreeFilerHeader() {
|
|
250 |
| } |
|
251 |
| |
|
252 |
2364
| protected synchronized void read(RandomAccessFile raf) throws IOException {
|
|
253 |
2364
| super.read(raf);
|
|
254 |
2364
| totalBytes = raf.readLong();
|
|
255 |
| } |
|
256 |
| |
|
257 |
17877
| protected synchronized void write(RandomAccessFile raf) throws IOException {
|
|
258 |
17877
| super.write(raf);
|
|
259 |
17877
| raf.writeLong(totalBytes);
|
|
260 |
| } |
|
261 |
| |
|
262 |
| |
|
263 |
25339
| public synchronized void setTotalBytes(long totalBytes) {
|
|
264 |
25339
| this.totalBytes = totalBytes;
|
|
265 |
25339
| setDirty();
|
|
266 |
| } |
|
267 |
| |
|
268 |
| |
|
269 |
0
| public synchronized long getTotalBytes() {
|
|
270 |
0
| return totalBytes;
|
|
271 |
| } |
|
272 |
| } |
|
273 |
| |
|
274 |
| |
|
275 |
| |
|
276 |
| |
|
277 |
| private final class BTreeFilerPageHeader extends BTreePageHeader { |
|
278 |
| private long created; |
|
279 |
| private long modified; |
|
280 |
| |
|
281 |
46819
| public BTreeFilerPageHeader() {
|
|
282 |
| } |
|
283 |
| |
|
284 |
0
| public BTreeFilerPageHeader(DataInput dis) throws IOException {
|
|
285 |
0
| super(dis);
|
|
286 |
| } |
|
287 |
| |
|
288 |
38383
| public synchronized void read(DataInput dis) throws IOException {
|
|
289 |
38383
| super.read(dis);
|
|
290 |
| |
|
291 |
38383
| if (getStatus() == UNUSED) {
|
|
292 |
3
| return;
|
|
293 |
| } |
|
294 |
| |
|
295 |
38380
| created = dis.readLong();
|
|
296 |
38380
| modified = dis.readLong();
|
|
297 |
| } |
|
298 |
| |
|
299 |
27636
| public synchronized void write(DataOutput dos) throws IOException {
|
|
300 |
27636
| super.write(dos);
|
|
301 |
27636
| dos.writeLong(created);
|
|
302 |
27636
| dos.writeLong(modified);
|
|
303 |
| } |
|
304 |
| |
|
305 |
25339
| public synchronized void setRecordLen(int recordLen) {
|
|
306 |
25339
| fileHeader.setTotalBytes((fileHeader.totalBytes - getRecordLen()) + recordLen);
|
|
307 |
25339
| super.setRecordLen(recordLen);
|
|
308 |
| } |
|
309 |
| |
|
310 |
| |
|
311 |
8206
| public synchronized void setCreated(long created) {
|
|
312 |
8206
| this.created = created;
|
|
313 |
8206
| setDirty();
|
|
314 |
| } |
|
315 |
| |
|
316 |
| |
|
317 |
50434
| public synchronized long getCreated() {
|
|
318 |
50434
| return created;
|
|
319 |
| } |
|
320 |
| |
|
321 |
| |
|
322 |
13243
| public synchronized void setModified(long modified) {
|
|
323 |
13243
| this.modified = modified;
|
|
324 |
13243
| setDirty();
|
|
325 |
| } |
|
326 |
| |
|
327 |
| |
|
328 |
37191
| public synchronized long getModified() {
|
|
329 |
37191
| return modified;
|
|
330 |
| } |
|
331 |
| } |
|
332 |
| } |