001: package org.apache.lucene.store.je;
002:
003: /**
004: * Licensed to the Apache Software Foundation (ASF) under one or more
005: * contributor license agreements. See the NOTICE file distributed with
006: * this work for additional information regarding copyright ownership.
007: * The ASF licenses this file to You under the Apache License, Version 2.0
008: * (the "License"); you may not use this file except in compliance with
009: * the License. You may obtain a copy of the License at
010: *
011: * http://www.apache.org/licenses/LICENSE-2.0
012: *
013: * Unless required by applicable law or agreed to in writing, software
014: * distributed under the License is distributed on an "AS IS" BASIS,
015: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016: * See the License for the specific language governing permissions and
017: * limitations under the License.
018: */
019:
020: import java.io.ByteArrayInputStream;
021: import java.io.ByteArrayOutputStream;
022: import java.io.DataInputStream;
023: import java.io.DataOutputStream;
024: import java.io.IOException;
025: import java.util.Random;
026:
027: import com.sleepycat.je.Cursor;
028: import com.sleepycat.je.Database;
029: import com.sleepycat.je.DatabaseEntry;
030: import com.sleepycat.je.DatabaseException;
031: import com.sleepycat.je.OperationStatus;
032: import com.sleepycat.je.Transaction;
033:
034: /**
035: * Port of Andi Vajda's DbDirectory to Java Edition of Berkeley Database
036: *
037: * @author Aaron Donovan
038: */
039:
040: public class File extends Object {
041:
042: static protected Random random = new Random();
043:
044: protected DatabaseEntry key, data;
045:
046: protected long length, timeModified;
047:
048: protected String name;
049:
050: protected byte[] uuid;
051:
052: protected File(String name) throws IOException {
053: setName(name);
054:
055: data = new DatabaseEntry(new byte[32]);
056: }
057:
058: protected File(JEDirectory directory, String name, boolean create)
059: throws IOException {
060: this (name);
061:
062: if (!exists(directory)) {
063: if (!create)
064: throw new IOException("File does not exist: " + name);
065: else {
066: DatabaseEntry key = new DatabaseEntry(new byte[24]);
067: DatabaseEntry data = new DatabaseEntry(null);
068: Database blocks = directory.blocks;
069: Transaction txn = directory.txn;
070:
071: data.setPartial(true);
072:
073: uuid = new byte[16];
074:
075: try {
076: do {
077: /* generate a v.4 random-uuid unique to this db */
078: random.nextBytes(uuid);
079: uuid[6] = (byte) ((byte) 0x40 | (uuid[6] & (byte) 0x0f));
080: uuid[8] = (byte) ((byte) 0x80 | (uuid[8] & (byte) 0x3f));
081: System.arraycopy(uuid, 0, key.getData(), 0, 16);
082: // TODO check LockMode
083: } while (blocks.get(txn, key, data, null) != OperationStatus.NOTFOUND);
084: } catch (DatabaseException e) {
085: throw new IOException(e.getMessage());
086: }
087: }
088: } else if (create)
089: length = 0L;
090: }
091:
092: protected String getName() {
093: return name;
094: }
095:
096: private void setName(String name) throws IOException {
097: ByteArrayOutputStream buffer = new ByteArrayOutputStream(128);
098: DataOutputStream out = new DataOutputStream(buffer);
099:
100: out.writeUTF(name);
101: out.close();
102:
103: key = new DatabaseEntry(buffer.toByteArray());
104: this .name = name;
105: }
106:
107: protected byte[] getKey() throws IOException {
108: if (uuid == null)
109: throw new IOException("Uninitialized file");
110:
111: return uuid;
112: }
113:
114: protected long getLength() {
115: return length;
116: }
117:
118: protected long getTimeModified() {
119: return timeModified;
120: }
121:
122: protected boolean exists(JEDirectory directory) throws IOException {
123: Database files = directory.files;
124: Transaction txn = directory.txn;
125: try {
126: // TODO check LockMode
127: if (files.get(txn, key, data, null) == OperationStatus.NOTFOUND)
128: return false;
129: } catch (DatabaseException e) {
130: throw new IOException(e.getMessage());
131: }
132:
133: byte[] bytes = data.getData();
134: ByteArrayInputStream buffer = new ByteArrayInputStream(bytes);
135: DataInputStream in = new DataInputStream(buffer);
136:
137: length = in.readLong();
138: timeModified = in.readLong();
139: in.close();
140:
141: uuid = new byte[16];
142: System.arraycopy(bytes, 16, uuid, 0, 16);
143:
144: return true;
145: }
146:
147: protected void modify(JEDirectory directory, long length,
148: long timeModified) throws IOException {
149: ByteArrayOutputStream buffer = new ByteArrayOutputStream(32);
150: DataOutputStream out = new DataOutputStream(buffer);
151: Database files = directory.files;
152: Transaction txn = directory.txn;
153:
154: out.writeLong(length);
155: out.writeLong(timeModified);
156: out.write(getKey());
157: out.close();
158:
159: System
160: .arraycopy(buffer.toByteArray(), 0, data.getData(), 0,
161: 32);
162:
163: try {
164: files.put(txn, key, data);
165: } catch (DatabaseException e) {
166: throw new IOException(e.getMessage());
167: }
168:
169: this .length = length;
170: this .timeModified = timeModified;
171: }
172:
173: protected void delete(JEDirectory directory) throws IOException {
174: if (!exists(directory))
175: throw new IOException("File does not exist: " + getName());
176:
177: Cursor cursor = null;
178:
179: try {
180: try {
181: byte[] bytes = getKey();
182: int ulen = bytes.length + 8;
183: byte[] cursorBytes = new byte[ulen];
184: DatabaseEntry cursorKey = new DatabaseEntry(cursorBytes);
185: DatabaseEntry cursorData = new DatabaseEntry(null);
186: Database files = directory.files;
187: Database blocks = directory.blocks;
188: Transaction txn = directory.txn;
189:
190: System
191: .arraycopy(bytes, 0, cursorBytes, 0,
192: bytes.length);
193:
194: cursorData.setPartial(true);
195:
196: cursor = blocks.openCursor(txn, null);
197:
198: if (cursor.getSearchKey(cursorKey, cursorData, null) != OperationStatus.NOTFOUND) {
199: cursor.delete();
200: advance: while (cursor.getNext(cursorKey,
201: cursorData, null) != OperationStatus.NOTFOUND) {
202: byte[] temp = cursorKey.getData();
203: for (int i = 0; i < bytes.length; i++)
204: if (bytes[i] != temp[i]) {
205: break advance;
206: }
207: cursor.delete();
208: }
209: }
210:
211: files.delete(txn, key);
212: } finally {
213: if (cursor != null)
214: cursor.close();
215: }
216: } catch (DatabaseException e) {
217: throw new IOException(e.getMessage());
218: }
219:
220: }
221:
222: protected void rename(JEDirectory directory, String name)
223: throws IOException {
224: if (!exists(directory))
225: throw new IOException("File does not exist: " + getName());
226:
227: File newFile = new File(name);
228:
229: if (newFile.exists(directory))
230: newFile.delete(directory);
231:
232: try {
233: Database files = directory.files;
234: Transaction txn = directory.txn;
235:
236: files.delete(txn, key);
237: setName(name);
238: files.put(txn, key, data);
239: } catch (DatabaseException e) {
240: throw new IOException(e.getMessage());
241: }
242: }
243: }
|