1 package org.apache.lucene.store; 2 3 18 19 import java.io.File ; 20 import java.io.FileInputStream ; 21 import java.io.FileOutputStream ; 22 import java.io.IOException ; 23 import java.io.RandomAccessFile ; 24 import java.security.MessageDigest ; 25 import java.security.NoSuchAlgorithmException ; 26 import java.util.Hashtable ; 27 28 import org.apache.lucene.index.IndexFileNameFilter; 29 30 36 public class FSDirectory extends Directory { 37 38 45 private static final Hashtable DIRECTORIES = new Hashtable (); 46 47 private static boolean disableLocks = false; 48 49 54 public static void setDisableLocks(boolean doDisableLocks) { 55 FSDirectory.disableLocks = doDisableLocks; 56 } 57 58 62 public static boolean getDisableLocks() { 63 return FSDirectory.disableLocks; 64 } 65 66 70 public static final String LOCK_DIR = 71 System.getProperty("org.apache.lucene.lockDir", 72 System.getProperty("java.io.tmpdir")); 73 74 75 private static Class IMPL; 76 static { 77 try { 78 String name = 79 System.getProperty("org.apache.lucene.FSDirectory.class", 80 FSDirectory.class.getName()); 81 IMPL = Class.forName(name); 82 } catch (ClassNotFoundException e) { 83 throw new RuntimeException ("cannot load FSDirectory class: " + e.toString()); 84 } catch (SecurityException se) { 85 try { 86 IMPL = Class.forName(FSDirectory.class.getName()); 87 } catch (ClassNotFoundException e) { 88 throw new RuntimeException ("cannot load default FSDirectory class: " + e.toString()); 89 } 90 } 91 } 92 93 private static MessageDigest DIGESTER; 94 95 static { 96 try { 97 DIGESTER = MessageDigest.getInstance("MD5"); 98 } catch (NoSuchAlgorithmException e) { 99 throw new RuntimeException (e.toString()); 100 } 101 } 102 103 104 private byte[] buffer = null; 105 106 115 public static FSDirectory getDirectory(String path, boolean create) 116 throws IOException { 117 return getDirectory(new File (path), create); 118 } 119 120 129 public static FSDirectory getDirectory(File file, boolean create) 130 throws IOException { 131 file = new File (file.getCanonicalPath()); 132 FSDirectory dir; 133 synchronized (DIRECTORIES) { 134 dir = (FSDirectory)DIRECTORIES.get(file); 135 if (dir == null) { 136 try { 137 dir = (FSDirectory)IMPL.newInstance(); 138 } catch (Exception e) { 139 throw new RuntimeException ("cannot load FSDirectory class: " + e.toString()); 140 } 141 dir.init(file, create); 142 DIRECTORIES.put(file, dir); 143 } else if (create) { 144 dir.create(); 145 } 146 } 147 synchronized (dir) { 148 dir.refCount++; 149 } 150 return dir; 151 } 152 153 private File directory = null; 154 private int refCount; 155 private File lockDir; 156 157 protected FSDirectory() {}; 159 private void init(File path, boolean create) throws IOException { 160 directory = path; 161 162 if (LOCK_DIR == null) { 163 lockDir = directory; 164 } 165 else { 166 lockDir = new File (LOCK_DIR); 167 } 168 if (!lockDir.exists()) { 170 if (!lockDir.mkdirs()) 171 throw new IOException ("Cannot create directory: " + lockDir); 172 } else if (!lockDir.isDirectory()) { 173 throw new IOException ("Found regular file where directory expected: " + lockDir); 174 } 175 if (create) { 176 create(); 177 } 178 179 if (!directory.isDirectory()) 180 throw new IOException (path + " not a directory"); 181 } 182 183 private synchronized void create() throws IOException { 184 if (!directory.exists()) 185 if (!directory.mkdirs()) 186 throw new IOException ("Cannot create directory: " + directory); 187 188 if (!directory.isDirectory()) 189 throw new IOException (directory + " not a directory"); 190 191 String [] files = directory.list(new IndexFileNameFilter()); for (int i = 0; i < files.length; i++) { 193 File file = new File (directory, files[i]); 194 if (!file.delete()) 195 throw new IOException ("Cannot delete " + files[i]); 196 } 197 198 String lockPrefix = getLockPrefix().toString(); files = lockDir.list(); 200 if (files == null) 201 throw new IOException ("Cannot read lock directory " + lockDir.getAbsolutePath()); 202 for (int i = 0; i < files.length; i++) { 203 if (!files[i].startsWith(lockPrefix)) 204 continue; 205 File lockFile = new File (lockDir, files[i]); 206 if (!lockFile.delete()) 207 throw new IOException ("Cannot delete " + files[i]); 208 } 209 } 210 211 212 public String [] list() { 213 return directory.list(); 214 } 215 216 217 public boolean fileExists(String name) { 218 File file = new File (directory, name); 219 return file.exists(); 220 } 221 222 223 public long fileModified(String name) { 224 File file = new File (directory, name); 225 return file.lastModified(); 226 } 227 228 229 public static long fileModified(File directory, String name) { 230 File file = new File (directory, name); 231 return file.lastModified(); 232 } 233 234 235 public void touchFile(String name) { 236 File file = new File (directory, name); 237 file.setLastModified(System.currentTimeMillis()); 238 } 239 240 241 public long fileLength(String name) { 242 File file = new File (directory, name); 243 return file.length(); 244 } 245 246 247 public void deleteFile(String name) throws IOException { 248 File file = new File (directory, name); 249 if (!file.delete()) 250 throw new IOException ("Cannot delete " + file); 251 } 252 253 254 public synchronized void renameFile(String from, String to) 255 throws IOException { 256 File old = new File (directory, from); 257 File nu = new File (directory, to); 258 259 262 263 if (nu.exists()) 264 if (!nu.delete()) 265 throw new IOException ("Cannot delete " + nu); 266 267 if (!old.renameTo(nu)) { 271 java.io.InputStream in = null; 272 java.io.OutputStream out = null; 273 try { 274 in = new FileInputStream (old); 275 out = new FileOutputStream (nu); 276 if (buffer == null) { 280 buffer = new byte[1024]; 281 } 282 int len; 283 while ((len = in.read(buffer)) >= 0) { 284 out.write(buffer, 0, len); 285 } 286 287 old.delete(); 289 } 290 catch (IOException ioe) { 291 throw new IOException ("Cannot rename " + old + " to " + nu); 292 } 293 finally { 294 if (in != null) { 295 try { 296 in.close(); 297 } catch (IOException e) { 298 throw new RuntimeException ("Cannot close input stream: " + e.toString()); 299 } 300 } 301 if (out != null) { 302 try { 303 out.close(); 304 } catch (IOException e) { 305 throw new RuntimeException ("Cannot close output stream: " + e.toString()); 306 } 307 } 308 } 309 } 310 } 311 312 314 public IndexOutput createOutput(String name) throws IOException { 315 File file = new File (directory, name); 316 if (file.exists() && !file.delete()) throw new IOException ("Cannot overwrite: " + file); 318 319 return new FSIndexOutput(file); 320 } 321 322 323 public IndexInput openInput(String name) throws IOException { 324 return new FSIndexInput(new File (directory, name)); 325 } 326 327 330 private static final char[] HEX_DIGITS = 331 {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; 332 333 339 public Lock makeLock(String name) { 340 StringBuffer buf = getLockPrefix(); 341 buf.append("-"); 342 buf.append(name); 343 344 final File lockFile = new File (lockDir, buf.toString()); 346 347 return new Lock() { 348 public boolean obtain() throws IOException { 349 if (disableLocks) 350 return true; 351 352 if (!lockDir.exists()) { 353 if (!lockDir.mkdirs()) { 354 throw new IOException ("Cannot create lock directory: " + lockDir); 355 } 356 } 357 358 return lockFile.createNewFile(); 359 } 360 public void release() { 361 if (disableLocks) 362 return; 363 lockFile.delete(); 364 } 365 public boolean isLocked() { 366 if (disableLocks) 367 return false; 368 return lockFile.exists(); 369 } 370 371 public String toString() { 372 return "Lock@" + lockFile; 373 } 374 }; 375 } 376 377 private StringBuffer getLockPrefix() { 378 String dirName; try { 380 dirName = directory.getCanonicalPath(); 381 } catch (IOException e) { 382 throw new RuntimeException (e.toString()); 383 } 384 385 byte digest[]; 386 synchronized (DIGESTER) { 387 digest = DIGESTER.digest(dirName.getBytes()); 388 } 389 StringBuffer buf = new StringBuffer (); 390 buf.append("lucene-"); 391 for (int i = 0; i < digest.length; i++) { 392 int b = digest[i]; 393 buf.append(HEX_DIGITS[(b >> 4) & 0xf]); 394 buf.append(HEX_DIGITS[b & 0xf]); 395 } 396 397 return buf; 398 } 399 400 401 public synchronized void close() { 402 if (--refCount <= 0) { 403 synchronized (DIRECTORIES) { 404 DIRECTORIES.remove(directory); 405 } 406 } 407 } 408 409 public File getFile() { 410 return directory; 411 } 412 413 414 public String toString() { 415 return this.getClass().getName() + "@" + directory; 416 } 417 } 418 419 420 class FSIndexInput extends BufferedIndexInput { 421 422 private class Descriptor extends RandomAccessFile { 423 public long position; 424 public Descriptor(File file, String mode) throws IOException { 425 super(file, mode); 426 } 427 } 428 429 private Descriptor file = null; 430 boolean isClone; 431 private long length; 432 433 public FSIndexInput(File path) throws IOException { 434 file = new Descriptor(path, "r"); 435 length = file.length(); 436 } 437 438 439 protected void readInternal(byte[] b, int offset, int len) 440 throws IOException { 441 synchronized (file) { 442 long position = getFilePointer(); 443 if (position != file.position) { 444 file.seek(position); 445 file.position = position; 446 } 447 int total = 0; 448 do { 449 int i = file.read(b, offset+total, len-total); 450 if (i == -1) 451 throw new IOException ("read past EOF"); 452 file.position += i; 453 total += i; 454 } while (total < len); 455 } 456 } 457 458 public void close() throws IOException { 459 if (!isClone) 460 file.close(); 461 } 462 463 protected void seekInternal(long position) { 464 } 465 466 public long length() { 467 return length; 468 } 469 470 protected void finalize() throws IOException { 471 close(); } 473 474 public Object clone() { 475 FSIndexInput clone = (FSIndexInput)super.clone(); 476 clone.isClone = true; 477 return clone; 478 } 479 480 483 boolean isFDValid() throws IOException { 484 return file.getFD().valid(); 485 } 486 } 487 488 489 class FSIndexOutput extends BufferedIndexOutput { 490 RandomAccessFile file = null; 491 492 public FSIndexOutput(File path) throws IOException { 493 file = new RandomAccessFile (path, "rw"); 494 } 495 496 497 public void flushBuffer(byte[] b, int size) throws IOException { 498 file.write(b, 0, size); 499 } 500 public void close() throws IOException { 501 super.close(); 502 file.close(); 503 } 504 505 506 public void seek(long pos) throws IOException { 507 super.seek(pos); 508 file.seek(pos); 509 } 510 public long length() throws IOException { 511 return file.length(); 512 } 513 514 protected void finalize() throws IOException { 515 file.close(); } 517 518 } 519 | Popular Tags |