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 |
| } |