1 package org.apache.lucene.store.db; 2 3 /** 4 * Licensed to the Apache Software Foundation (ASF) under one or more 5 * contributor license agreements. See the NOTICE file distributed with 6 * this work for additional information regarding copyright ownership. 7 * The ASF licenses this file to You under the Apache License, Version 2.0 8 * (the "License"); you may not use this file except in compliance with 9 * the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 */ 19 20 import java.io.IOException; 21 import java.io.ByteArrayOutputStream; 22 import java.io.DataOutputStream; 23 import java.io.ByteArrayInputStream; 24 import java.io.DataInputStream; 25 import java.util.Random; 26 27 import com.sleepycat.db.DatabaseEntry; 28 import com.sleepycat.db.internal.DbConstants; 29 import com.sleepycat.db.internal.Dbc; 30 import com.sleepycat.db.internal.Db; 31 import com.sleepycat.db.internal.DbTxn; 32 import com.sleepycat.db.DatabaseException; 33 34 35 36 public class File extends Object { 37 38 static protected Random random = new Random(); 39 40 protected DatabaseEntry key, data; 41 protected long length, timeModified; 42 protected String name; 43 protected byte[] uuid; 44 45 protected File(String name) 46 throws IOException 47 { 48 setName(name); 49 50 data = new DatabaseEntry(new byte[32]); 51 data.setUserBuffer(data.getSize(), true); 52 } 53 54 protected File(DbDirectory directory, String name, boolean create) 55 throws IOException 56 { 57 this(name); 58 59 if (!exists(directory)) 60 { 61 if (!create) 62 throw new IOException("File does not exist: " + name); 63 else 64 { 65 DatabaseEntry key = new DatabaseEntry(new byte[24]); 66 DatabaseEntry data = new DatabaseEntry((byte[]) null); 67 Db blocks = directory.blocks; 68 DbTxn txn = directory.txn; 69 int flags = directory.flags; 70 71 key.setUserBuffer(24, true); 72 data.setPartial(true); 73 74 uuid = new byte[16]; 75 76 try { 77 do { 78 /* generate a v.4 random-uuid unique to this db */ 79 random.nextBytes(uuid); 80 uuid[6] = (byte) ((byte) 0x40 | 81 (uuid[6] & (byte) 0x0f)); 82 uuid[8] = (byte) ((byte) 0x80 | 83 (uuid[8] & (byte) 0x3f)); 84 System.arraycopy(uuid, 0, key.getData(), 0, 16); 85 } while (blocks.get(txn, key, data, 86 flags) != DbConstants.DB_NOTFOUND); 87 } catch (DatabaseException e) { 88 throw new IOException(e.getMessage()); 89 } 90 } 91 } 92 else if (create) 93 length = 0L; 94 } 95 96 protected String getName() 97 { 98 return name; 99 } 100 101 private void setName(String name) 102 throws IOException 103 { 104 ByteArrayOutputStream buffer = new ByteArrayOutputStream(128); 105 DataOutputStream out = new DataOutputStream(buffer); 106 107 out.writeUTF(name); 108 out.close(); 109 110 key = new DatabaseEntry(buffer.toByteArray()); 111 key.setUserBuffer(key.getSize(), true); 112 113 this.name = name; 114 } 115 116 protected byte[] getKey() 117 throws IOException 118 { 119 if (uuid == null) 120 throw new IOException("Uninitialized file"); 121 122 return uuid; 123 } 124 125 protected long getLength() 126 { 127 return length; 128 } 129 130 protected long getTimeModified() 131 { 132 return timeModified; 133 } 134 135 protected boolean exists(DbDirectory directory) 136 throws IOException 137 { 138 Db files = directory.files; 139 DbTxn txn = directory.txn; 140 int flags = directory.flags; 141 142 try { 143 if (files.get(txn, key, data, flags) == DbConstants.DB_NOTFOUND) 144 return false; 145 } catch (DatabaseException e) { 146 throw new IOException(e.getMessage()); 147 } 148 149 byte[] bytes = data.getData(); 150 ByteArrayInputStream buffer = new ByteArrayInputStream(bytes); 151 DataInputStream in = new DataInputStream(buffer); 152 153 length = in.readLong(); 154 timeModified = in.readLong(); 155 in.close(); 156 157 uuid = new byte[16]; 158 System.arraycopy(bytes, 16, uuid, 0, 16); 159 160 return true; 161 } 162 163 protected void modify(DbDirectory directory, long length, long timeModified) 164 throws IOException 165 { 166 ByteArrayOutputStream buffer = new ByteArrayOutputStream(32); 167 DataOutputStream out = new DataOutputStream(buffer); 168 Db files = directory.files; 169 DbTxn txn = directory.txn; 170 171 out.writeLong(length); 172 out.writeLong(timeModified); 173 out.write(getKey()); 174 out.close(); 175 176 System.arraycopy(buffer.toByteArray(), 0, data.getData(), 0, 32); 177 178 try { 179 files.put(txn, key, data, 0); 180 } catch (DatabaseException e) { 181 throw new IOException(e.getMessage()); 182 } 183 184 this.length = length; 185 this.timeModified = timeModified; 186 } 187 188 protected void delete(DbDirectory directory) 189 throws IOException 190 { 191 if (!exists(directory)) 192 throw new IOException("File does not exist: " + getName()); 193 194 Dbc cursor = null; 195 196 try { 197 try { 198 byte[] bytes = getKey(); 199 int ulen = bytes.length + 8; 200 byte[] cursorBytes = new byte[ulen]; 201 DatabaseEntry cursorKey = new DatabaseEntry(cursorBytes); 202 DatabaseEntry cursorData = new DatabaseEntry((byte[]) null); 203 Db files = directory.files; 204 Db blocks = directory.blocks; 205 DbTxn txn = directory.txn; 206 int flags = directory.flags; 207 208 System.arraycopy(bytes, 0, cursorBytes, 0, bytes.length); 209 cursorKey.setUserBuffer(ulen, true); 210 cursorData.setPartial(true); 211 212 cursor = blocks.cursor(txn, flags); 213 214 if (cursor.get(cursorKey, cursorData, 215 DbConstants.DB_SET_RANGE | flags) != DbConstants.DB_NOTFOUND) 216 { 217 cursor.del(0); 218 219 outer: 220 while (cursor.get(cursorKey, cursorData, 221 DbConstants.DB_NEXT | flags) != DbConstants.DB_NOTFOUND) 222 { 223 for (int i = 0; i < bytes.length; i++) 224 if (bytes[i] != cursorBytes[i]) 225 break outer; 226 227 cursor.del(0); 228 } 229 } 230 231 files.del(txn, key, 0); 232 } finally { 233 if (cursor != null) 234 cursor.close(); 235 } 236 } catch (DatabaseException e) { 237 throw new IOException(e.getMessage()); 238 } 239 } 240 241 protected void rename(DbDirectory directory, String name) 242 throws IOException 243 { 244 if (!exists(directory)) 245 throw new IOException("File does not exist: " + getName()); 246 247 File newFile = new File(name); 248 249 if (newFile.exists(directory)) 250 newFile.delete(directory); 251 252 try { 253 Db files = directory.files; 254 DbTxn txn = directory.txn; 255 256 files.del(txn, key, 0); 257 setName(name); 258 files.put(txn, key, data, 0); 259 } catch (DatabaseException e) { 260 throw new IOException(e.getMessage()); 261 } 262 } 263 }