diff --git a/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java b/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java
index e8c9805805..80c97102db 100644
--- a/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java
+++ b/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java
@@ -289,8 +289,6 @@ public class IndexInfo
private long writeLockTimeout = IndexWriter.WRITE_LOCK_TIMEOUT;
- private long commitLockTimeout = IndexWriter.COMMIT_LOCK_TIMEOUT;
-
private int maxFieldLength = IndexWriter.DEFAULT_MAX_FIELD_LENGTH;
private int termIndexInterval = IndexWriter.DEFAULT_TERM_INDEX_INTERVAL;
@@ -370,7 +368,6 @@ public class IndexInfo
writer.setMaxBufferedDocs(writerMinMergeDocs);
writer.setMergeFactor(writerMergeFactor);
writer.setMaxMergeDocs(writerMaxMergeDocs);
- writer.setCommitLockTimeout(commitLockTimeout);
writer.setWriteLockTimeout(writeLockTimeout);
writer.setMaxFieldLength(maxFieldLength);
writer.setTermIndexInterval(termIndexInterval);
@@ -436,7 +433,6 @@ public class IndexInfo
writer.setMaxBufferedDocs(writerMinMergeDocs);
writer.setMergeFactor(writerMergeFactor);
writer.setMaxMergeDocs(writerMaxMergeDocs);
- writer.setCommitLockTimeout(commitLockTimeout);
writer.setWriteLockTimeout(writeLockTimeout);
writer.setMaxFieldLength(maxFieldLength);
writer.setTermIndexInterval(termIndexInterval);
@@ -715,7 +711,6 @@ public class IndexInfo
writer.setMaxBufferedDocs(writerMinMergeDocs);
writer.setMergeFactor(writerMergeFactor);
writer.setMaxMergeDocs(writerMaxMergeDocs);
- writer.setCommitLockTimeout(commitLockTimeout);
writer.setWriteLockTimeout(writeLockTimeout);
writer.setMaxFieldLength(maxFieldLength);
writer.setTermIndexInterval(termIndexInterval);
@@ -2930,7 +2925,6 @@ public class IndexInfo
writer.setMaxBufferedDocs(mergerMinMergeDocs);
writer.setMergeFactor(mergerMergeFactor);
writer.setMaxMergeDocs(mergerMaxMergeDocs);
- writer.setCommitLockTimeout(commitLockTimeout);
writer.setWriteLockTimeout(writeLockTimeout);
}
}
diff --git a/source/java/org/apache/lucene/store/FSDirectory.java b/source/java/org/apache/lucene/store/FSDirectory.java
index c1132bb4c8..c3a1c7c068 100644
--- a/source/java/org/apache/lucene/store/FSDirectory.java
+++ b/source/java/org/apache/lucene/store/FSDirectory.java
@@ -1,535 +1,608 @@
-package org.apache.lucene.store;
-
-/**
- * Copyright 2004 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.Hashtable;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.lucene.index.IndexFileNameFilter;
-
-/**
- * Straightforward implementation of {@link Directory} as a directory of files.
- *
- * @see Directory
- * @author Doug Cutting
- */
-public class FSDirectory extends Directory {
-
- private static Log s_logger = LogFactory.getLog(FSDirectory.class);
-
- /** This cache of directories ensures that there is a unique Directory
- * instance per path, so that synchronization on the Directory can be used to
- * synchronize access between readers and writers.
- *
- * This should be a WeakHashMap, so that entries can be GC'd, but that would
- * require Java 1.2. Instead we use refcounts...
- */
- private static final Hashtable DIRECTORIES = new Hashtable();
-
- private static boolean disableLocks = false;
-
- /**
- * Set whether Lucene's use of lock files is disabled. By default,
- * lock files are enabled. They should only be disabled if the index
- * is on a read-only medium like a CD-ROM.
- */
- public static void setDisableLocks(boolean doDisableLocks) {
- FSDirectory.disableLocks = doDisableLocks;
- }
-
- /**
- * Returns whether Lucene's use of lock files is disabled.
- * @return true if locks are disabled, false if locks are enabled.
- */
- public static boolean getDisableLocks() {
- return FSDirectory.disableLocks;
- }
-
- /**
- * Directory specified by org.apache.lucene.lockDir
- * or java.io.tmpdir
system property
- */
- public static final String LOCK_DIR =
- System.getProperty("org.apache.lucene.lockDir",
- System.getProperty("java.io.tmpdir"));
-
- /** The default class which implements filesystem-based directories. */
- private static Class IMPL;
- static {
- try {
- String name =
- System.getProperty("org.apache.lucene.FSDirectory.class",
- FSDirectory.class.getName());
- IMPL = Class.forName(name);
- } catch (ClassNotFoundException e) {
- throw new RuntimeException("cannot load FSDirectory class: " + e.toString(), e);
- } catch (SecurityException se) {
- try {
- IMPL = Class.forName(FSDirectory.class.getName());
- } catch (ClassNotFoundException e) {
- throw new RuntimeException("cannot load default FSDirectory class: " + e.toString(), e);
- }
- }
- }
-
- private static MessageDigest DIGESTER;
-
- static {
- try {
- DIGESTER = MessageDigest.getInstance("MD5");
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException(e.toString(), e);
- }
- }
-
- /** A buffer optionally used in renameTo method */
- private byte[] buffer = null;
-
- /** Returns the directory instance for the named location.
- *
- *
Directories are cached, so that, for a given canonical path, the same - * FSDirectory instance will always be returned. This permits - * synchronization on directories. - * - * @param path the path to the directory. - * @param create if true, create, or erase any existing contents. - * @return the FSDirectory for the named file. */ - public static FSDirectory getDirectory(String path, boolean create) - throws IOException { - return getDirectory(new File(path), create); - } - - /** Returns the directory instance for the named location. - * - *
Directories are cached, so that, for a given canonical path, the same
- * FSDirectory instance will always be returned. This permits
- * synchronization on directories.
- *
- * @param file the path to the directory.
- * @param create if true, create, or erase any existing contents.
- * @return the FSDirectory for the named file. */
- public static FSDirectory getDirectory(File file, boolean create)
- throws IOException {
- file = new File(file.getCanonicalPath());
- FSDirectory dir;
- synchronized (DIRECTORIES) {
- dir = (FSDirectory)DIRECTORIES.get(file);
- if (dir == null) {
- try {
- dir = (FSDirectory)IMPL.newInstance();
- } catch (Exception e) {
- throw new RuntimeException("cannot load FSDirectory class: " + e.toString(), e);
- }
- dir.init(file, create);
- DIRECTORIES.put(file, dir);
- } else if (create) {
- dir.create();
- }
- }
- synchronized (dir) {
- dir.refCount++;
- }
- return dir;
- }
-
- private File directory = null;
- private int refCount;
- private File lockDir;
-
- protected FSDirectory() {}; // permit subclassing
-
- private void init(File path, boolean create) throws IOException {
- directory = path;
-
- if(s_logger.isDebugEnabled())
- {
- s_logger.debug("Alfresco FSDirectory used for "+path+" create = "+create);
- }
-
- if (LOCK_DIR == null) {
- lockDir = directory;
- }
- else {
- lockDir = new File(LOCK_DIR);
- }
- // Ensure that lockDir exists and is a directory.
- if (!lockDir.exists()) {
- if (!lockDir.mkdirs())
- throw new IOException("Cannot create directory: " + lockDir.getAbsolutePath());
- } else if (!lockDir.isDirectory()) {
- throw new IOException("Found regular file where directory expected: " +
- lockDir.getAbsolutePath());
- }
- if (create) {
- create();
- }
-
- if (!directory.isDirectory())
- throw new IOException(path + " not a directory");
- }
-
- private synchronized void create() throws IOException {
- if (!directory.exists())
- if (!directory.mkdirs())
- throw new IOException("Cannot create directory: " + directory);
-
- if (!directory.isDirectory())
- throw new IOException(directory + " not a directory");
-
- String[] files = directory.list(new IndexFileNameFilter()); // clear old files
- if (files == null)
- throw new IOException("Cannot read directory " + directory.getAbsolutePath());
- for (int i = 0; i < files.length; i++) {
- File file = new File(directory, files[i]);
- if (!file.delete())
- throw new IOException("Cannot delete " + file);
- }
-
- String lockPrefix = getLockPrefix().toString(); // clear old locks
- files = lockDir.list();
- if (files == null)
- throw new IOException("Cannot read lock directory " + lockDir.getAbsolutePath());
- for (int i = 0; i < files.length; i++) {
- if (!files[i].startsWith(lockPrefix))
- continue;
- File lockFile = new File(lockDir, files[i]);
- if (!lockFile.delete())
- throw new IOException("Cannot delete " + lockFile);
- }
- }
-
- /** Returns an array of strings, one for each file in the directory. */
- public String[] list() {
- return directory.list();
- }
-
- /** Returns true iff a file with the given name exists. */
- public boolean fileExists(String name) {
- File file = new File(directory, name);
- return file.exists();
- }
-
- /** Returns the time the named file was last modified. */
- public long fileModified(String name) {
- File file = new File(directory, name);
- return file.lastModified();
- }
-
- /** Returns the time the named file was last modified. */
- public static long fileModified(File directory, String name) {
- File file = new File(directory, name);
- return file.lastModified();
- }
-
- /** Set the modified time of an existing file to now. */
- public void touchFile(String name) {
- File file = new File(directory, name);
- file.setLastModified(System.currentTimeMillis());
- }
-
- /** Returns the length in bytes of a file in the directory. */
- public long fileLength(String name) {
- File file = new File(directory, name);
- return file.length();
- }
-
- /** Removes an existing file in the directory. */
- public void deleteFile(String name) throws IOException {
- File file = new File(directory, name);
- if (!file.delete())
- throw new IOException("Cannot delete " + file);
- }
-
- /** Renames an existing file in the directory. */
- public synchronized void renameFile(String from, String to)
- throws IOException {
- File old = new File(directory, from);
- File nu = new File(directory, to);
-
- /* This is not atomic. If the program crashes between the call to
- delete() and the call to renameTo() then we're screwed, but I've
- been unable to figure out how else to do this... */
-
- if (nu.exists())
- if (!nu.delete())
- throw new IOException("Cannot delete " + nu);
-
- // Rename the old file to the new one. Unfortunately, the renameTo()
- // method does not work reliably under some JVMs. Therefore, if the
- // rename fails, we manually rename by copying the old file to the new one
- if (!old.renameTo(nu)) {
- java.io.InputStream in = null;
- java.io.OutputStream out = null;
- try {
- in = new FileInputStream(old);
- out = new FileOutputStream(nu);
- // see if the buffer needs to be initialized. Initialization is
- // only done on-demand since many VM's will never run into the renameTo
- // bug and hence shouldn't waste 1K of mem for no reason.
- if (buffer == null) {
- buffer = new byte[1024];
- }
- int len;
- while ((len = in.read(buffer)) >= 0) {
- out.write(buffer, 0, len);
- }
-
- // delete the old file.
- old.delete();
- }
- catch (IOException ioe) {
- IOException newExc = new IOException("Cannot rename " + old + " to " + nu);
- newExc.initCause(ioe);
- throw newExc;
- }
- finally {
- if (in != null) {
- try {
- in.close();
- } catch (IOException e) {
- throw new RuntimeException("Cannot close input stream: " + e.toString(), e);
- }
- }
- if (out != null) {
- try {
- out.close();
- } catch (IOException e) {
- throw new RuntimeException("Cannot close output stream: " + e.toString(), e);
- }
- }
- }
- }
- }
-
- /** Creates a new, empty file in the directory with the given name.
- Returns a stream writing this file. */
- public IndexOutput createOutput(String name) throws IOException {
- File file = new File(directory, name);
- if (file.exists() && !file.delete()) // delete existing, if any
- throw new IOException("Cannot overwrite: " + file);
-
- return new FSIndexOutput(file);
- }
-
- /** Returns a stream reading an existing file. */
- public IndexInput openInput(String name) throws IOException {
- return new FSIndexInput(new File(directory, name));
- }
-
- /**
- * So we can do some byte-to-hexchar conversion below
- */
- private static final char[] HEX_DIGITS =
- {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
-
- /** Constructs a {@link Lock} with the specified name. Locks are implemented
- * with {@link File#createNewFile()}.
- *
- * @param name the name of the lock file
- * @return an instance of Lock
holding the lock
- */
- public Lock makeLock(String name) {
- StringBuffer buf = getLockPrefix();
- buf.append("-");
- buf.append(name);
-
- // create a lock file
- final File lockFile = new File(lockDir, buf.toString());
-
- return new Lock() {
- public boolean obtain() throws IOException {
- if (disableLocks)
- return true;
-
- if (!lockDir.exists()) {
- if (!lockDir.mkdirs()) {
- throw new IOException("Cannot create lock directory: " + lockDir);
- }
- }
-
- return lockFile.createNewFile();
- }
- public void release() {
- if (disableLocks)
- return;
- lockFile.delete();
- }
- public boolean isLocked() {
- if (disableLocks)
- return false;
- return lockFile.exists();
- }
-
- public String toString() {
- return "Lock@" + lockFile;
- }
- };
- }
-
- private StringBuffer getLockPrefix() {
- String dirName; // name to be hashed
- try {
- dirName = directory.getCanonicalPath();
- } catch (IOException e) {
- throw new RuntimeException(e.toString(), e);
- }
-
- byte digest[];
- synchronized (DIGESTER) {
- digest = DIGESTER.digest(dirName.getBytes());
- }
- StringBuffer buf = new StringBuffer();
- buf.append("lucene-");
- for (int i = 0; i < digest.length; i++) {
- int b = digest[i];
- buf.append(HEX_DIGITS[(b >> 4) & 0xf]);
- buf.append(HEX_DIGITS[b & 0xf]);
- }
-
- return buf;
- }
-
- /** Closes the store to future operations. */
- public synchronized void close() {
- if (--refCount <= 0) {
- synchronized (DIRECTORIES) {
- DIRECTORIES.remove(directory);
- }
- }
- }
-
- public File getFile() {
- return directory;
- }
-
- /** For debug output. */
- public String toString() {
- return this.getClass().getName() + "@" + directory;
- }
-}
-
-
-class FSIndexInput extends BufferedIndexInput {
-
- private class Descriptor extends RandomAccessFile {
- public long position;
- public Descriptor(File file, String mode) throws IOException {
- super(file, mode);
- }
- }
-
- private Descriptor file = null;
- boolean isClone;
- private long length;
-
- public FSIndexInput(File path) throws IOException {
- file = new Descriptor(path, "r");
- file.getChannel();
- length = file.length();
- }
-
- /** IndexInput methods */
- protected void readInternal(byte[] b, int offset, int len)
- throws IOException {
- synchronized (file) {
- long position = getFilePointer();
- if (position != file.position) {
- file.seek(position);
- file.position = position;
- }
- int total = 0;
- do {
- int i = file.read(b, offset+total, len-total);
- if (i == -1)
- throw new IOException("read past EOF");
- file.position += i;
- total += i;
- } while (total < len);
- }
- }
-
- public void close() throws IOException {
- if (!isClone)
- file.close();
- }
-
- protected void seekInternal(long position) {
- }
-
- public long length() {
- return length;
- }
-
- protected void finalize() throws IOException {
- close(); // close the file
- }
-
- public Object clone() {
- FSIndexInput clone = (FSIndexInput)super.clone();
- clone.isClone = true;
- return clone;
- }
-
- /** Method used for testing. Returns true if the underlying
- * file descriptor is valid.
- */
- boolean isFDValid() throws IOException {
- return file.getFD().valid();
- }
-}
-
-
-class FSIndexOutput extends BufferedIndexOutput {
- RandomAccessFile file = null;
-
- public FSIndexOutput(File path) throws IOException {
- file = new RandomAccessFile(path, "rw");
- file.getChannel();
- }
-
- /** output methods: */
- public void flushBuffer(byte[] b, int size) throws IOException {
- file.write(b, 0, size);
- }
- public void close() throws IOException {
- super.close();
- file.close();
- }
-
- /** Random-access methods */
- public void seek(long pos) throws IOException {
- super.seek(pos);
- file.seek(pos);
- }
- public long length() throws IOException {
- return file.length();
- }
-
- protected void finalize() throws IOException {
- file.close(); // close the file
- }
-
-}
-
+package org.apache.lucene.store;
+
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Hashtable;
+
+import org.apache.lucene.index.IndexFileNameFilter;
+
+// Used only for WRITE_LOCK_NAME in deprecated create=true case:
+import org.apache.lucene.index.IndexWriter;
+
+/**
+ * Straightforward implementation of {@link Directory} as a directory of files.
+ * Locking implementation is by default the {@link SimpleFSLockFactory}, but
+ * can be changed either by passing in a {@link LockFactory} instance to
+ * getDirectory
, or specifying the LockFactory class by setting
+ * org.apache.lucene.store.FSDirectoryLockFactoryClass
Java system
+ * property, or by calling {@link #setLockFactory} after creating
+ * the Directory.
+
+ *
Directories are cached, so that, for a given canonical
+ * path, the same FSDirectory instance will always be
+ * returned by getDirectory
. This permits
+ * synchronization on directories.
org.apache.lucene.lockDir
+ * or java.io.tmpdir
system property.
+
+ * @deprecated As of 2.1, LOCK_DIR
is unused
+ * because the write.lock is now stored by default in the
+ * index directory. If you really want to store locks
+ * elsewhere you can create your own {@link
+ * SimpleFSLockFactory} (or {@link NativeFSLockFactory},
+ * etc.) passing in your preferred lock directory. Then,
+ * pass this LockFactory
instance to one of
+ * the getDirectory
methods that take a
+ * lockFactory
(for example, {@link #getDirectory(String, LockFactory)}).
+ */
+ public static final String LOCK_DIR = System.getProperty("org.apache.lucene.lockDir",
+ System.getProperty("java.io.tmpdir"));
+
+ /** The default class which implements filesystem-based directories. */
+ private static Class IMPL;
+ static {
+ try {
+ String name =
+ System.getProperty("org.apache.lucene.FSDirectory.class",
+ FSDirectory.class.getName());
+ IMPL = Class.forName(name);
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException("cannot load FSDirectory class: " + e.toString(), e);
+ } catch (SecurityException se) {
+ try {
+ IMPL = Class.forName(FSDirectory.class.getName());
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException("cannot load default FSDirectory class: " + e.toString(), e);
+ }
+ }
+ }
+
+ private static MessageDigest DIGESTER;
+
+ static {
+ try {
+ DIGESTER = MessageDigest.getInstance("MD5");
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e.toString(), e);
+ }
+ }
+
+ /** A buffer optionally used in renameTo method */
+ private byte[] buffer = null;
+
+ /** Returns the directory instance for the named location.
+ * @param path the path to the directory.
+ * @return the FSDirectory for the named file. */
+ public static FSDirectory getDirectory(String path)
+ throws IOException {
+ return getDirectory(new File(path), null);
+ }
+
+ /** Returns the directory instance for the named location.
+ * @param path the path to the directory.
+ * @param lockFactory instance of {@link LockFactory} providing the
+ * locking implementation.
+ * @return the FSDirectory for the named file. */
+ public static FSDirectory getDirectory(String path, LockFactory lockFactory)
+ throws IOException {
+ return getDirectory(new File(path), lockFactory);
+ }
+
+ /** Returns the directory instance for the named location.
+ * @param file the path to the directory.
+ * @return the FSDirectory for the named file. */
+ public static FSDirectory getDirectory(File file)
+ throws IOException {
+ return getDirectory(file, null);
+ }
+
+ /** Returns the directory instance for the named location.
+ * @param file the path to the directory.
+ * @param lockFactory instance of {@link LockFactory} providing the
+ * locking implementation.
+ * @return the FSDirectory for the named file. */
+ public static FSDirectory getDirectory(File file, LockFactory lockFactory)
+ throws IOException
+ {
+ file = new File(file.getCanonicalPath());
+
+ if (file.exists() && !file.isDirectory())
+ throw new IOException(file + " not a directory");
+
+ if (!file.exists())
+ if (!file.mkdirs())
+ throw new IOException("Cannot create directory: " + file);
+
+ FSDirectory dir;
+ synchronized (DIRECTORIES) {
+ dir = (FSDirectory)DIRECTORIES.get(file);
+ if (dir == null) {
+ try {
+ dir = (FSDirectory)IMPL.newInstance();
+ } catch (Exception e) {
+ throw new RuntimeException("cannot load FSDirectory class: " + e.toString(), e);
+ }
+ dir.init(file, lockFactory);
+ DIRECTORIES.put(file, dir);
+ } else {
+ // Catch the case where a Directory is pulled from the cache, but has a
+ // different LockFactory instance.
+ if (lockFactory != null && lockFactory != dir.getLockFactory()) {
+ throw new IOException("Directory was previously created with a different LockFactory instance; please pass null as the lockFactory instance and use setLockFactory to change it");
+ }
+ }
+ }
+ synchronized (dir) {
+ dir.refCount++;
+ }
+ return dir;
+ }
+
+
+ /** Returns the directory instance for the named location.
+ *
+ * @deprecated Use IndexWriter's create flag, instead, to
+ * create a new index.
+ *
+ * @param path the path to the directory.
+ * @param create if true, create, or erase any existing contents.
+ * @return the FSDirectory for the named file. */
+ public static FSDirectory getDirectory(String path, boolean create)
+ throws IOException {
+ return getDirectory(new File(path), create);
+ }
+
+ /** Returns the directory instance for the named location.
+ *
+ * @deprecated Use IndexWriter's create flag, instead, to
+ * create a new index.
+ *
+ * @param file the path to the directory.
+ * @param create if true, create, or erase any existing contents.
+ * @return the FSDirectory for the named file. */
+ public static FSDirectory getDirectory(File file, boolean create)
+ throws IOException
+ {
+ FSDirectory dir = getDirectory(file, null);
+
+ // This is now deprecated (creation should only be done
+ // by IndexWriter):
+ if (create) {
+ dir.create();
+ }
+
+ return dir;
+ }
+
+ private void create() throws IOException {
+ if (directory.exists()) {
+ String[] files = directory.list(IndexFileNameFilter.getFilter()); // clear old files
+ if (files == null)
+ throw new IOException("Cannot read directory " + directory.getAbsolutePath());
+ for (int i = 0; i < files.length; i++) {
+ File file = new File(directory, files[i]);
+ if (!file.delete())
+ throw new IOException("Cannot delete " + file);
+ }
+ }
+ lockFactory.clearLock(IndexWriter.WRITE_LOCK_NAME);
+ }
+
+ private File directory = null;
+ private int refCount;
+
+ protected FSDirectory() {}; // permit subclassing
+
+ private void init(File path, LockFactory lockFactory) throws IOException {
+
+ // Set up lockFactory with cascaded defaults: if an instance was passed in,
+ // use that; else if locks are disabled, use NoLockFactory; else if the
+ // system property org.apache.lucene.store.FSDirectoryLockFactoryClass is set,
+ // instantiate that; else, use SimpleFSLockFactory:
+
+ directory = path;
+
+ boolean doClearLockID = false;
+
+ if (lockFactory == null) {
+
+ if (disableLocks) {
+ // Locks are disabled:
+ lockFactory = NoLockFactory.getNoLockFactory();
+ } else {
+ String lockClassName = System.getProperty("org.apache.lucene.store.FSDirectoryLockFactoryClass");
+
+ if (lockClassName != null && !lockClassName.equals("")) {
+ Class c;
+
+ try {
+ c = Class.forName(lockClassName);
+ } catch (ClassNotFoundException e) {
+ throw new IOException("unable to find LockClass " + lockClassName);
+ }
+
+ try {
+ lockFactory = (LockFactory) c.newInstance();
+ } catch (IllegalAccessException e) {
+ throw new IOException("IllegalAccessException when instantiating LockClass " + lockClassName);
+ } catch (InstantiationException e) {
+ throw new IOException("InstantiationException when instantiating LockClass " + lockClassName);
+ } catch (ClassCastException e) {
+ throw new IOException("unable to cast LockClass " + lockClassName + " instance to a LockFactory");
+ }
+ } else {
+ // Our default lock is SimpleFSLockFactory;
+ // default lockDir is our index directory:
+ lockFactory = new SimpleFSLockFactory(path);
+ doClearLockID = true;
+ }
+ }
+ }
+
+ setLockFactory(lockFactory);
+
+ if (doClearLockID) {
+ // Clear the prefix because write.lock will be
+ // stored in our directory:
+ lockFactory.setLockPrefix(null);
+ }
+ }
+
+ /** Returns an array of strings, one for each Lucene index file in the directory. */
+ public String[] list() {
+ return directory.list(IndexFileNameFilter.getFilter());
+ }
+
+ /** Returns true iff a file with the given name exists. */
+ public boolean fileExists(String name) {
+ File file = new File(directory, name);
+ return file.exists();
+ }
+
+ /** Returns the time the named file was last modified. */
+ public long fileModified(String name) {
+ File file = new File(directory, name);
+ return file.lastModified();
+ }
+
+ /** Returns the time the named file was last modified. */
+ public static long fileModified(File directory, String name) {
+ File file = new File(directory, name);
+ return file.lastModified();
+ }
+
+ /** Set the modified time of an existing file to now. */
+ public void touchFile(String name) {
+ File file = new File(directory, name);
+ file.setLastModified(System.currentTimeMillis());
+ }
+
+ /** Returns the length in bytes of a file in the directory. */
+ public long fileLength(String name) {
+ File file = new File(directory, name);
+ return file.length();
+ }
+
+ /** Removes an existing file in the directory. */
+ public void deleteFile(String name) throws IOException {
+ File file = new File(directory, name);
+ if (!file.delete())
+ throw new IOException("Cannot delete " + file);
+ }
+
+ /** Renames an existing file in the directory.
+ * Warning: This is not atomic.
+ * @deprecated
+ */
+ public synchronized void renameFile(String from, String to)
+ throws IOException {
+ File old = new File(directory, from);
+ File nu = new File(directory, to);
+
+ /* This is not atomic. If the program crashes between the call to
+ delete() and the call to renameTo() then we're screwed, but I've
+ been unable to figure out how else to do this... */
+
+ if (nu.exists())
+ if (!nu.delete())
+ throw new IOException("Cannot delete " + nu);
+
+ // Rename the old file to the new one. Unfortunately, the renameTo()
+ // method does not work reliably under some JVMs. Therefore, if the
+ // rename fails, we manually rename by copying the old file to the new one
+ if (!old.renameTo(nu)) {
+ java.io.InputStream in = null;
+ java.io.OutputStream out = null;
+ try {
+ in = new FileInputStream(old);
+ out = new FileOutputStream(nu);
+ // see if the buffer needs to be initialized. Initialization is
+ // only done on-demand since many VM's will never run into the renameTo
+ // bug and hence shouldn't waste 1K of mem for no reason.
+ if (buffer == null) {
+ buffer = new byte[1024];
+ }
+ int len;
+ while ((len = in.read(buffer)) >= 0) {
+ out.write(buffer, 0, len);
+ }
+
+ // delete the old file.
+ old.delete();
+ }
+ catch (IOException ioe) {
+ IOException newExc = new IOException("Cannot rename " + old + " to " + nu);
+ newExc.initCause(ioe);
+ throw newExc;
+ }
+ finally {
+ try {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot close input stream: " + e.toString(), e);
+ }
+ }
+ } finally {
+ if (out != null) {
+ try {
+ out.close();
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot close output stream: " + e.toString(), e);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /** Creates a new, empty file in the directory with the given name.
+ Returns a stream writing this file. */
+ public IndexOutput createOutput(String name) throws IOException {
+
+ File file = new File(directory, name);
+ if (file.exists() && !file.delete()) // delete existing, if any
+ throw new IOException("Cannot overwrite: " + file);
+
+ return new FSIndexOutput(file);
+ }
+
+ /** Returns a stream reading an existing file. */
+ public IndexInput openInput(String name) throws IOException {
+ return new FSIndexInput(new File(directory, name));
+ }
+
+ /**
+ * So we can do some byte-to-hexchar conversion below
+ */
+ private static final char[] HEX_DIGITS =
+ {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
+
+
+ public String getLockID() {
+ String dirName; // name to be hashed
+ try {
+ dirName = directory.getCanonicalPath();
+ } catch (IOException e) {
+ throw new RuntimeException(e.toString(), e);
+ }
+
+ byte digest[];
+ synchronized (DIGESTER) {
+ digest = DIGESTER.digest(dirName.getBytes());
+ }
+ StringBuffer buf = new StringBuffer();
+ buf.append("lucene-");
+ for (int i = 0; i < digest.length; i++) {
+ int b = digest[i];
+ buf.append(HEX_DIGITS[(b >> 4) & 0xf]);
+ buf.append(HEX_DIGITS[b & 0xf]);
+ }
+
+ return buf.toString();
+ }
+
+ /** Closes the store to future operations. */
+ public synchronized void close() {
+ if (--refCount <= 0) {
+ synchronized (DIRECTORIES) {
+ DIRECTORIES.remove(directory);
+ }
+ }
+ }
+
+ public File getFile() {
+ return directory;
+ }
+
+ /** For debug output. */
+ public String toString() {
+ return this.getClass().getName() + "@" + directory;
+ }
+}
+
+
+class FSIndexInput extends BufferedIndexInput {
+
+ private static class Descriptor extends RandomAccessFile {
+ // remember if the file is open, so that we don't try to close it
+ // more than once
+ private boolean isOpen;
+ long position;
+ final long length;
+
+ public Descriptor(File file, String mode) throws IOException {
+ super(file, mode);
+ isOpen=true;
+ length=length();
+ getChannel();
+ }
+
+ public void close() throws IOException {
+ if (isOpen) {
+ isOpen=false;
+ super.close();
+ }
+ }
+
+ protected void finalize() throws Throwable {
+ try {
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+ }
+
+ private final Descriptor file;
+ boolean isClone;
+
+ public FSIndexInput(File path) throws IOException {
+ file = new Descriptor(path, "r");
+ }
+
+ /** IndexInput methods */
+ protected void readInternal(byte[] b, int offset, int len)
+ throws IOException {
+ synchronized (file) {
+ long position = getFilePointer();
+ if (position != file.position) {
+ file.seek(position);
+ file.position = position;
+ }
+ int total = 0;
+ do {
+ int i = file.read(b, offset+total, len-total);
+ if (i == -1)
+ throw new IOException("read past EOF");
+ file.position += i;
+ total += i;
+ } while (total < len);
+ }
+ }
+
+ public void close() throws IOException {
+ // only close the file if this is not a clone
+ if (!isClone) file.close();
+ }
+
+ protected void seekInternal(long position) {
+ }
+
+ public long length() {
+ return file.length;
+ }
+
+ public Object clone() {
+ FSIndexInput clone = (FSIndexInput)super.clone();
+ clone.isClone = true;
+ return clone;
+ }
+
+ /** Method used for testing. Returns true if the underlying
+ * file descriptor is valid.
+ */
+ boolean isFDValid() throws IOException {
+ return file.getFD().valid();
+ }
+}
+
+
+class FSIndexOutput extends BufferedIndexOutput {
+ RandomAccessFile file = null;
+
+ // remember if the file is open, so that we don't try to close it
+ // more than once
+ private boolean isOpen;
+
+ public FSIndexOutput(File path) throws IOException {
+ file = new RandomAccessFile(path, "rw");
+ file.getChannel();
+ isOpen = true;
+ }
+
+ /** output methods: */
+ public void flushBuffer(byte[] b, int size) throws IOException {
+ file.write(b, 0, size);
+ }
+ public void close() throws IOException {
+ // only close the file if it has not been closed yet
+ if (isOpen) {
+ super.close();
+ file.close();
+ isOpen = false;
+ }
+ }
+
+ /** Random-access methods */
+ public void seek(long pos) throws IOException {
+ super.seek(pos);
+ file.seek(pos);
+ }
+ public long length() throws IOException {
+ return file.length();
+ }
+
+}