Index: src/test/org/apache/lucene/index/TestIndexReader.java =================================================================== --- src/test/org/apache/lucene/index/TestIndexReader.java (revision 507871) +++ src/test/org/apache/lucene/index/TestIndexReader.java (working copy) @@ -25,6 +25,7 @@ import org.apache.lucene.store.Directory; import org.apache.lucene.store.RAMDirectory; import org.apache.lucene.store.FSDirectory; +import org.apache.lucene.store.LockObtainFailedException; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.analysis.WhitespaceAnalyzer; import org.apache.lucene.document.Document; @@ -245,6 +246,96 @@ reader.close(); } + // Make sure attempts to make changes after reader is + // closed throws IOException: + public void testChangesAfterClose() throws IOException + { + Directory dir = new RAMDirectory(); + + IndexWriter writer = null; + IndexReader reader = null; + Term searchTerm = new Term("content", "aaa"); + + // add 11 documents with term : aaa + writer = new IndexWriter(dir, new WhitespaceAnalyzer(), true); + for (int i = 0; i < 11; i++) + { + addDoc(writer, searchTerm.text()); + } + writer.close(); + + reader = IndexReader.open(dir); + + // Close reader: + reader.close(); + + // Then, try to make changes: + try { + reader.deleteDocument(4); + fail("deleteDocument after close failed to throw IOException"); + } catch (IOException e) { + // expected + } + + try { + reader.setNorm(5, "aaa", 2.0f); + fail("setNorm after close failed to throw IOException"); + } catch (IOException e) { + // expected + } + + try { + reader.undeleteAll(); + fail("undeleteAll after close failed to throw IOException"); + } catch (IOException e) { + // expected + } + } + + // Make sure we get lock obtain failed exception with 2 writers: + public void testLockObtainFailed() throws IOException + { + Directory dir = new RAMDirectory(); + + IndexWriter writer = null; + IndexReader reader = null; + Term searchTerm = new Term("content", "aaa"); + + // add 11 documents with term : aaa + writer = new IndexWriter(dir, new WhitespaceAnalyzer(), true); + for (int i = 0; i < 11; i++) + { + addDoc(writer, searchTerm.text()); + } + + // Create reader: + reader = IndexReader.open(dir); + + // Try to make changes + try { + reader.deleteDocument(4); + fail("deleteDocument should have hit LockObtainFailedException"); + } catch (LockObtainFailedException e) { + // expected + } + + try { + reader.setNorm(5, "aaa", 2.0f); + fail("setNorm should have hit LockObtainFailedException"); + } catch (LockObtainFailedException e) { + // expected + } + + try { + reader.undeleteAll(); + fail("undeleteAll should have hit LockObtainFailedException"); + } catch (LockObtainFailedException e) { + // expected + } + writer.close(); + reader.close(); + } + // Make sure you can set norms & commit even if a reader // is open against the index: public void testWritingNorms() throws IOException @@ -371,7 +462,7 @@ try { deleted = reader.deleteDocuments(searchTerm); fail("Delete allowed on an index reader with stale segment information"); - } catch (IOException e) { + } catch (StaleReaderException e) { /* success */ } Index: src/java/org/apache/lucene/queryParser/QueryParser.java =================================================================== --- src/java/org/apache/lucene/queryParser/QueryParser.java (revision 507871) +++ src/java/org/apache/lucene/queryParser/QueryParser.java (working copy) @@ -53,7 +53,7 @@ * By default a date is converted into a search term using the deprecated * {@link DateField} for compatibility reasons. * To use the new {@link DateTools} to convert dates, a - * {@link DateTools.Resolution} has to be set. + * {@link org.apache.lucene.document.DateTools.Resolution} has to be set. *

*

* The date resolution that shall be used for RangeQueries can be set @@ -321,7 +321,7 @@ /** * Sets the date resolution used by RangeQueries for a specific field. * - * @param field field for which the date resolution is to be set + * @param fieldName field for which the date resolution is to be set * @param dateResolution date resolution to set */ public void setDateResolution(String fieldName, DateTools.Resolution dateResolution) { Index: src/java/org/apache/lucene/search/RemoteSearchable.java =================================================================== --- src/java/org/apache/lucene/search/RemoteSearchable.java (revision 507871) +++ src/java/org/apache/lucene/search/RemoteSearchable.java (working copy) @@ -19,6 +19,7 @@ import org.apache.lucene.document.Document; import org.apache.lucene.index.Term; +import org.apache.lucene.index.CorruptIndexException; import java.io.IOException; import java.rmi.Naming; @@ -76,7 +77,7 @@ return local.search (weight, filter, n, sort); } - public Document doc(int i) throws IOException { + public Document doc(int i) throws CorruptIndexException, IOException { return local.doc(i); } Index: src/java/org/apache/lucene/search/Searcher.java =================================================================== --- src/java/org/apache/lucene/search/Searcher.java (revision 507871) +++ src/java/org/apache/lucene/search/Searcher.java (working copy) @@ -19,6 +19,7 @@ import java.io.IOException; +import org.apache.lucene.index.CorruptIndexException; import org.apache.lucene.index.Term; import org.apache.lucene.document.Document; @@ -187,7 +188,7 @@ abstract public int docFreq(Term term) throws IOException; abstract public int maxDoc() throws IOException; abstract public TopDocs search(Weight weight, Filter filter, int n) throws IOException; - abstract public Document doc(int i) throws IOException; + abstract public Document doc(int i) throws CorruptIndexException, IOException; abstract public Query rewrite(Query query) throws IOException; abstract public Explanation explain(Weight weight, int doc) throws IOException; abstract public TopFieldDocs search(Weight weight, Filter filter, int n, Sort sort) throws IOException; Index: src/java/org/apache/lucene/search/Searchable.java =================================================================== --- src/java/org/apache/lucene/search/Searchable.java (revision 507871) +++ src/java/org/apache/lucene/search/Searchable.java (working copy) @@ -20,6 +20,7 @@ import org.apache.lucene.document.Document; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.Term; +import org.apache.lucene.index.CorruptIndexException; import java.io.IOException; // for javadoc @@ -92,8 +93,10 @@ /** Expert: Returns the stored fields of document i. * Called by {@link HitCollector} implementations. * @see IndexReader#document(int) + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ - Document doc(int i) throws IOException; + Document doc(int i) throws CorruptIndexException, IOException; /** Expert: called to re-write queries into primitive queries. * @throws BooleanQuery.TooManyClauses Index: src/java/org/apache/lucene/search/MultiSearcher.java =================================================================== --- src/java/org/apache/lucene/search/MultiSearcher.java (revision 507871) +++ src/java/org/apache/lucene/search/MultiSearcher.java (working copy) @@ -25,6 +25,7 @@ import org.apache.lucene.document.Document; import org.apache.lucene.index.Term; +import org.apache.lucene.index.CorruptIndexException; /** Implements search over a set of Searchables. * @@ -142,7 +143,7 @@ } // inherit javadoc - public Document doc(int n) throws IOException { + public Document doc(int n) throws CorruptIndexException, IOException { int i = subSearcher(n); // find searcher index return searchables[i].doc(n - starts[i]); // dispatch to searcher } Index: src/java/org/apache/lucene/search/Hits.java =================================================================== --- src/java/org/apache/lucene/search/Hits.java (revision 507871) +++ src/java/org/apache/lucene/search/Hits.java (working copy) @@ -22,6 +22,7 @@ import java.util.Iterator; import org.apache.lucene.document.Document; +import org.apache.lucene.index.CorruptIndexException; /** A ranked list of documents, used to hold search results. */ public final class Hits { @@ -86,9 +87,12 @@ } /** Returns the stored fields of the nth document in this set. -

Documents are cached, so that repeated requests for the same element may - return the same Document object. */ - public final Document doc(int n) throws IOException { + *

Documents are cached, so that repeated requests for the same element may + * return the same Document object. + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error + */ + public final Document doc(int n) throws CorruptIndexException, IOException { HitDoc hitDoc = hitDoc(n); // Update LRU cache of documents Index: src/java/org/apache/lucene/search/Hit.java =================================================================== --- src/java/org/apache/lucene/search/Hit.java (revision 507871) +++ src/java/org/apache/lucene/search/Hit.java (working copy) @@ -20,6 +20,7 @@ import java.io.IOException; import org.apache.lucene.document.Document; +import org.apache.lucene.index.CorruptIndexException; /** * Wrapper used by {@link HitIterator} to provide a lazily loaded hit @@ -50,8 +51,10 @@ * Returns document for this hit. * * @see Hits#doc(int) + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ - public Document getDocument() throws IOException { + public Document getDocument() throws CorruptIndexException, IOException { if (!resolved) fetchTheHit(); return doc; } @@ -74,7 +77,7 @@ return hits.id(hitNumber); } - private void fetchTheHit() throws IOException { + private void fetchTheHit() throws CorruptIndexException, IOException { doc = hits.doc(hitNumber); resolved = true; } @@ -85,8 +88,10 @@ * Returns the boost factor for this hit on any field of the underlying document. * * @see Document#getBoost() + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ - public float getBoost() throws IOException { + public float getBoost() throws CorruptIndexException, IOException { return getDocument().getBoost(); } @@ -97,8 +102,10 @@ * exist, returns null. * * @see Document#get(String) + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ - public String get(String name) throws IOException { + public String get(String name) throws CorruptIndexException, IOException { return getDocument().get(name); } Index: src/java/org/apache/lucene/search/IndexSearcher.java =================================================================== --- src/java/org/apache/lucene/search/IndexSearcher.java (revision 507871) +++ src/java/org/apache/lucene/search/IndexSearcher.java (working copy) @@ -24,6 +24,7 @@ import org.apache.lucene.document.Document; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.Term; +import org.apache.lucene.index.CorruptIndexException; /** Implements search over a single IndexReader. * @@ -38,13 +39,19 @@ IndexReader reader; private boolean closeReader; - /** Creates a searcher searching the index in the named directory. */ - public IndexSearcher(String path) throws IOException { + /** Creates a searcher searching the index in the named directory. + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error + */ + public IndexSearcher(String path) throws CorruptIndexException, IOException { this(IndexReader.open(path), true); } - /** Creates a searcher searching the index in the provided directory. */ - public IndexSearcher(Directory directory) throws IOException { + /** Creates a searcher searching the index in the provided directory. + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error + */ + public IndexSearcher(Directory directory) throws CorruptIndexException, IOException { this(IndexReader.open(directory), true); } @@ -80,7 +87,7 @@ } // inherit javadoc - public Document doc(int i) throws IOException { + public Document doc(int i) throws CorruptIndexException, IOException { return reader.document(i); } Index: src/java/org/apache/lucene/index/MultiReader.java =================================================================== --- src/java/org/apache/lucene/index/MultiReader.java (revision 507871) +++ src/java/org/apache/lucene/index/MultiReader.java (working copy) @@ -103,7 +103,8 @@ return maxDoc; } - public Document document(int n, FieldSelector fieldSelector) throws IOException { + // inherit javadoc + public Document document(int n, FieldSelector fieldSelector) throws CorruptIndexException, IOException { int i = readerIndex(n); // find segment num return subReaders[i].document(n - starts[i], fieldSelector); // dispatch to segment reader } @@ -115,16 +116,17 @@ public boolean hasDeletions() { return hasDeletions; } - protected void doDelete(int n) throws IOException { + protected void doDelete(int n) throws CorruptIndexException, IOException { numDocs = -1; // invalidate cache int i = readerIndex(n); // find segment num subReaders[i].deleteDocument(n - starts[i]); // dispatch to segment reader hasDeletions = true; } - protected void doUndeleteAll() throws IOException { + protected void doUndeleteAll() throws CorruptIndexException, IOException { for (int i = 0; i < subReaders.length; i++) subReaders[i].undeleteAll(); + hasDeletions = false; numDocs = -1; // invalidate cache } @@ -189,7 +191,7 @@ } protected void doSetNorm(int n, String field, byte value) - throws IOException { + throws CorruptIndexException, IOException { normsCache.remove(field); // clear cache int i = readerIndex(n); // find segment num subReaders[i].setNorm(n-starts[i], field, value); // dispatch Index: src/java/org/apache/lucene/index/SegmentTermEnum.java =================================================================== --- src/java/org/apache/lucene/index/SegmentTermEnum.java (revision 507871) +++ src/java/org/apache/lucene/index/SegmentTermEnum.java (working copy) @@ -40,7 +40,7 @@ private int formatM1SkipInterval; SegmentTermEnum(IndexInput i, FieldInfos fis, boolean isi) - throws IOException { + throws CorruptIndexException, IOException { input = i; fieldInfos = fis; isIndex = isi; @@ -61,7 +61,7 @@ // check that it is a format we can understand if (format < TermInfosWriter.FORMAT) - throw new IOException("Unknown format version:" + format); + throw new CorruptIndexException("Unknown format version:" + format); size = input.readLong(); // read the size Index: src/java/org/apache/lucene/index/FieldsReader.java =================================================================== --- src/java/org/apache/lucene/index/FieldsReader.java (revision 507871) +++ src/java/org/apache/lucene/index/FieldsReader.java (working copy) @@ -79,7 +79,7 @@ return size; } - final Document doc(int n, FieldSelector fieldSelector) throws IOException { + final Document doc(int n, FieldSelector fieldSelector) throws CorruptIndexException, IOException { indexStream.seek(n * 8L); long position = indexStream.readLong(); fieldsStream.seek(position); @@ -199,7 +199,7 @@ doc.add(new FieldForMerge(data, fi, binary, compressed, tokenize)); } - private void addField(Document doc, FieldInfo fi, boolean binary, boolean compressed, boolean tokenize) throws IOException { + private void addField(Document doc, FieldInfo fi, boolean binary, boolean compressed, boolean tokenize) throws CorruptIndexException, IOException { //we have a binary stored field, and it may be compressed if (binary) { @@ -397,7 +397,7 @@ } private final byte[] uncompress(final byte[] input) - throws IOException { + throws CorruptIndexException, IOException { Inflater decompressor = new Inflater(); decompressor.setInput(input); @@ -414,7 +414,7 @@ } catch (DataFormatException e) { // this will happen if the field is not compressed - IOException newException = new IOException("field data are in wrong format: " + e.toString()); + CorruptIndexException newException = new CorruptIndexException("field data are in wrong format: " + e.toString()); newException.initCause(e); throw newException; } Index: src/java/org/apache/lucene/index/TermInfosReader.java =================================================================== --- src/java/org/apache/lucene/index/TermInfosReader.java (revision 507871) +++ src/java/org/apache/lucene/index/TermInfosReader.java (working copy) @@ -41,7 +41,7 @@ private SegmentTermEnum indexEnum; TermInfosReader(Directory dir, String seg, FieldInfos fis) - throws IOException { + throws CorruptIndexException, IOException { directory = dir; segment = seg; fieldInfos = fis; Index: src/java/org/apache/lucene/index/IndexReader.java =================================================================== --- src/java/org/apache/lucene/index/IndexReader.java (revision 507871) +++ src/java/org/apache/lucene/index/IndexReader.java (working copy) @@ -24,6 +24,7 @@ import org.apache.lucene.store.FSDirectory; import org.apache.lucene.store.IndexInput; import org.apache.lucene.store.Lock; +import org.apache.lucene.store.LockObtainFailedException; import java.io.File; import java.io.FileOutputStream; @@ -114,6 +115,7 @@ private boolean directoryOwner; private boolean closeDirectory; protected IndexFileDeleter deleter; + private boolean isClosed; private SegmentInfos segmentInfos; private Lock writeLock; @@ -126,27 +128,36 @@ private SegmentInfos rollbackSegmentInfos; /** Returns an IndexReader reading the index in an FSDirectory in the named - path. */ - public static IndexReader open(String path) throws IOException { + path. + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error + */ + public static IndexReader open(String path) throws CorruptIndexException, IOException { return open(FSDirectory.getDirectory(path), true); } /** Returns an IndexReader reading the index in an FSDirectory in the named - path. */ - public static IndexReader open(File path) throws IOException { + path. + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error + */ + public static IndexReader open(File path) throws CorruptIndexException, IOException { return open(FSDirectory.getDirectory(path), true); } - /** Returns an IndexReader reading the index in the given Directory. */ - public static IndexReader open(final Directory directory) throws IOException { + /** Returns an IndexReader reading the index in the given Directory. + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error + */ + public static IndexReader open(final Directory directory) throws CorruptIndexException, IOException { return open(directory, false); } - private static IndexReader open(final Directory directory, final boolean closeDirectory) throws IOException { + private static IndexReader open(final Directory directory, final boolean closeDirectory) throws CorruptIndexException, IOException { return (IndexReader) new SegmentInfos.FindSegmentsFile(directory) { - public Object doBody(String segmentFileName) throws IOException { + public Object doBody(String segmentFileName) throws CorruptIndexException, IOException { SegmentInfos infos = new SegmentInfos(); infos.read(directory, segmentFileName); @@ -186,8 +197,10 @@ * Returns the time the index in the named directory was last modified. * Do not use this to check whether the reader is still up-to-date, use * {@link #isCurrent()} instead. + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ - public static long lastModified(String directory) throws IOException { + public static long lastModified(String directory) throws CorruptIndexException, IOException { return lastModified(new File(directory)); } @@ -195,8 +208,10 @@ * Returns the time the index in the named directory was last modified. * Do not use this to check whether the reader is still up-to-date, use * {@link #isCurrent()} instead. + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ - public static long lastModified(File fileDirectory) throws IOException { + public static long lastModified(File fileDirectory) throws CorruptIndexException, IOException { return ((Long) new SegmentInfos.FindSegmentsFile(fileDirectory) { public Object doBody(String segmentFileName) { return new Long(FSDirectory.fileModified(fileDirectory, segmentFileName)); @@ -208,8 +223,10 @@ * Returns the time the index in the named directory was last modified. * Do not use this to check whether the reader is still up-to-date, use * {@link #isCurrent()} instead. + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ - public static long lastModified(final Directory directory2) throws IOException { + public static long lastModified(final Directory directory2) throws CorruptIndexException, IOException { return ((Long) new SegmentInfos.FindSegmentsFile(directory2) { public Object doBody(String segmentFileName) throws IOException { return new Long(directory2.fileModified(segmentFileName)); @@ -224,9 +241,10 @@ * * @param directory where the index resides. * @return version number. - * @throws IOException if segments file cannot be read + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ - public static long getCurrentVersion(String directory) throws IOException { + public static long getCurrentVersion(String directory) throws CorruptIndexException, IOException { return getCurrentVersion(new File(directory)); } @@ -237,9 +255,10 @@ * * @param directory where the index resides. * @return version number. - * @throws IOException if segments file cannot be read + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ - public static long getCurrentVersion(File directory) throws IOException { + public static long getCurrentVersion(File directory) throws CorruptIndexException, IOException { Directory dir = FSDirectory.getDirectory(directory); long version = getCurrentVersion(dir); dir.close(); @@ -253,9 +272,10 @@ * * @param directory where the index resides. * @return version number. - * @throws IOException if segments file cannot be read. + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ - public static long getCurrentVersion(Directory directory) throws IOException { + public static long getCurrentVersion(Directory directory) throws CorruptIndexException, IOException { return SegmentInfos.readCurrentVersion(directory); } @@ -271,9 +291,10 @@ * If this is not the case you will need to re-open the IndexReader to * make sure you see the latest changes made to the index. * - * @throws IOException + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ - public boolean isCurrent() throws IOException { + public boolean isCurrent() throws CorruptIndexException, IOException { return SegmentInfos.readCurrentVersion(directory) == segmentInfos.getVersion(); } @@ -363,8 +384,11 @@ public abstract int maxDoc(); /** Returns the stored fields of the nth - Document in this index. */ - public Document document(int n) throws IOException{ + Document in this index. + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error + */ + public Document document(int n) throws CorruptIndexException, IOException { return document(n, null); } @@ -372,7 +396,7 @@ * Get the {@link org.apache.lucene.document.Document} at the nth position. The {@link org.apache.lucene.document.FieldSelector} * may be used to determine what {@link org.apache.lucene.document.Field}s to load and how they should be loaded. * - * NOTE: If this Reader (more specifically, the underlying {@link FieldsReader} is closed before the lazy {@link org.apache.lucene.document.Field} is + * NOTE: If this Reader (more specifically, the underlying FieldsReader is closed before the lazy {@link org.apache.lucene.document.Field} is * loaded an exception may be thrown. If you want the value of a lazy {@link org.apache.lucene.document.Field} to be available after closing you must * explicitly load it or fetch the Document again with a new loader. * @@ -380,7 +404,8 @@ * @param n Get the document at the nth position * @param fieldSelector The {@link org.apache.lucene.document.FieldSelector} to use to determine what Fields should be loaded on the Document. May be null, in which case all Fields will be loaded. * @return The stored fields of the {@link org.apache.lucene.document.Document} at the nth position - * @throws IOException If there is a problem reading this document + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error * * @see org.apache.lucene.document.Fieldable * @see org.apache.lucene.document.FieldSelector @@ -388,7 +413,7 @@ * @see org.apache.lucene.document.LoadFirstFieldSelector */ //When we convert to JDK 1.5 make this Set - public abstract Document document(int n, FieldSelector fieldSelector) throws IOException; + public abstract Document document(int n, FieldSelector fieldSelector) throws CorruptIndexException, IOException; @@ -422,33 +447,50 @@ /** Expert: Resets the normalization factor for the named field of the named * document. The norm represents the product of the field's {@link - * Fieldable#setBoost(float) boost} and its {@link Similarity#lengthNorm(String, + * org.apache.lucene.document.Fieldable#setBoost(float) boost} and its {@link Similarity#lengthNorm(String, * int) length normalization}. Thus, to preserve the length normalization * values when resetting this, one should base the new value upon the old. * * @see #norms(String) * @see Similarity#decodeNorm(byte) + * @throws StaleReaderException if the index has changed + * since this reader was opened + * @throws CorruptIndexException if the index is corrupt + * @throws LockObtainFailedException if another writer + * has this index open (write.lock could not + * be obtained) + * @throws IOException if this reader was closed already + * or there is a low-level IO error */ public final synchronized void setNorm(int doc, String field, byte value) - throws IOException{ + throws StaleReaderException, CorruptIndexException, LockObtainFailedException, IOException { if(directoryOwner) - aquireWriteLock(); + acquireWriteLock(); hasChanges = true; doSetNorm(doc, field, value); } /** Implements setNorm in subclass.*/ protected abstract void doSetNorm(int doc, String field, byte value) - throws IOException; + throws CorruptIndexException, IOException; /** Expert: Resets the normalization factor for the named field of the named * document. * * @see #norms(String) * @see Similarity#decodeNorm(byte) + * + * @throws StaleReaderException if the index has changed + * since this reader was opened + * @throws CorruptIndexException if the index is corrupt + * @throws LockObtainFailedException if another writer + * has this index open (write.lock could not + * be obtained) + * @throws IOException if this reader was closed already + * or there is a low-level IO error */ public void setNorm(int doc, String field, float value) - throws IOException { + throws StaleReaderException, CorruptIndexException, LockObtainFailedException, IOException { setNorm(doc, field, Similarity.encodeNorm(value)); } @@ -515,16 +557,24 @@ * Tries to acquire the WriteLock on this directory. * this method is only valid if this IndexReader is directory owner. * - * @throws IOException If WriteLock cannot be acquired. + * @throws StaleReaderException if the index has changed + * since this reader was opened + * @throws CorruptIndexException if the index is corrupt + * @throws LockObtainFailedException if another writer + * has this index open (write.lock could not + * be obtained) + * @throws IOException if there is a low-level IO error */ - private void aquireWriteLock() throws IOException { + private void acquireWriteLock() throws StaleReaderException, CorruptIndexException, LockObtainFailedException, IOException { if (stale) - throw new IOException("IndexReader out of date and no longer valid for delete, undelete, or setNorm operations"); + throw new StaleReaderException("IndexReader out of date and no longer valid for delete, undelete, or setNorm operations"); + if (isClosed) + throw new IOException("this reader is closed"); if (writeLock == null) { Lock writeLock = directory.makeLock(IndexWriter.WRITE_LOCK_NAME); if (!writeLock.obtain(IndexWriter.WRITE_LOCK_TIMEOUT)) // obtain write lock - throw new IOException("Index locked for write: " + writeLock); + throw new LockObtainFailedException("Index locked for write: " + writeLock); this.writeLock = writeLock; // we have to check whether index has changed since this reader was opened. @@ -533,7 +583,7 @@ stale = true; this.writeLock.release(); this.writeLock = null; - throw new IOException("IndexReader out of date and no longer valid for delete, undelete, or setNorm operations"); + throw new StaleReaderException("IndexReader out of date and no longer valid for delete, undelete, or setNorm operations"); } } } @@ -545,10 +595,19 @@ * method will result in an error. The presence of this document may still be * reflected in the {@link #docFreq} statistic, though * this will be corrected eventually as the index is further modified. + * + * @throws StaleReaderException if the index has changed + * since this reader was opened + * @throws CorruptIndexException if the index is corrupt + * @throws LockObtainFailedException if another writer + * has this index open (write.lock could not + * be obtained) + * @throws IOException if this reader was closed already + * or there is a low-level IO error */ - public final synchronized void deleteDocument(int docNum) throws IOException { + public final synchronized void deleteDocument(int docNum) throws StaleReaderException, CorruptIndexException, LockObtainFailedException, IOException { if(directoryOwner) - aquireWriteLock(); + acquireWriteLock(); hasChanges = true; doDelete(docNum); } @@ -557,7 +616,7 @@ /** Implements deletion of the document numbered docNum. * Applications should call {@link #deleteDocument(int)} or {@link #deleteDocuments(Term)}. */ - protected abstract void doDelete(int docNum) throws IOException; + protected abstract void doDelete(int docNum) throws CorruptIndexException, IOException; /** Deletes all documents that have a given term indexed. @@ -567,9 +626,18 @@ * passes it to this method. * See {@link #deleteDocument(int)} for information about when this deletion will * become effective. + * * @return the number of documents deleted + * @throws StaleReaderException if the index has changed + * since this reader was opened + * @throws CorruptIndexException if the index is corrupt + * @throws LockObtainFailedException if another writer + * has this index open (write.lock could not + * be obtained) + * @throws IOException if this reader was closed already + * or there is a low-level IO error */ - public final int deleteDocuments(Term term) throws IOException { + public final int deleteDocuments(Term term) throws StaleReaderException, CorruptIndexException, LockObtainFailedException, IOException { TermDocs docs = termDocs(term); if (docs == null) return 0; int n = 0; @@ -584,16 +652,26 @@ return n; } - /** Undeletes all documents currently marked as deleted in this index.*/ - public final synchronized void undeleteAll() throws IOException{ + /** Undeletes all documents currently marked as deleted in this index. + * + * @throws StaleReaderException if the index has changed + * since this reader was opened + * @throws LockObtainFailedException if another writer + * has this index open (write.lock could not + * be obtained) + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if this reader was closed already + * or there is a low-level IO error + */ + public final synchronized void undeleteAll() throws StaleReaderException, CorruptIndexException, LockObtainFailedException, IOException { if(directoryOwner) - aquireWriteLock(); + acquireWriteLock(); hasChanges = true; doUndeleteAll(); } /** Implements actual undeleteAll() in subclass. */ - protected abstract void doUndeleteAll() throws IOException; + protected abstract void doUndeleteAll() throws CorruptIndexException, IOException; /** * Should internally checkpoint state that will change @@ -633,10 +711,9 @@ * If an exception is hit, then either no changes or all * changes will have been committed to the index * (transactional semantics). - * - * @throws IOException + * @throws IOException if there is a low-level IO error */ - protected final synchronized void commit() throws IOException{ + protected final synchronized void commit() throws IOException { if(hasChanges){ if (deleter == null) { // In the MultiReader case, we share this deleter @@ -716,12 +793,20 @@ * Closes files associated with this index. * Also saves any new deletions to disk. * No other methods should be called after this has been called. + * @throws IOException if this reader was closed already + * or there is a low-level IO error */ public final synchronized void close() throws IOException { + if (directoryOwner && isClosed) { + throw new IOException("this reader is already closed"); + } commit(); doClose(); if(closeDirectory) directory.close(); + if (directoryOwner) { + isClosed = true; + } } /** Implements close. */ @@ -753,7 +838,7 @@ * Returns true iff the index in the named directory is * currently locked. * @param directory the directory to check for a lock - * @throws IOException if there is a problem with accessing the index + * @throws IOException if there is a low-level IO error */ public static boolean isLocked(Directory directory) throws IOException { return @@ -764,7 +849,7 @@ * Returns true iff the index in the named directory is * currently locked. * @param directory the directory to check for a lock - * @throws IOException if there is a problem with accessing the index + * @throws IOException if there is a low-level IO error */ public static boolean isLocked(String directory) throws IOException { Directory dir = FSDirectory.getDirectory(directory); Index: src/java/org/apache/lucene/index/FilterIndexReader.java =================================================================== --- src/java/org/apache/lucene/index/FilterIndexReader.java (revision 507871) +++ src/java/org/apache/lucene/index/FilterIndexReader.java (working copy) @@ -103,11 +103,11 @@ public int numDocs() { return in.numDocs(); } public int maxDoc() { return in.maxDoc(); } - public Document document(int n, FieldSelector fieldSelector) throws IOException { return in.document(n, fieldSelector); } + public Document document(int n, FieldSelector fieldSelector) throws CorruptIndexException, IOException { return in.document(n, fieldSelector); } public boolean isDeleted(int n) { return in.isDeleted(n); } public boolean hasDeletions() { return in.hasDeletions(); } - protected void doUndeleteAll() throws IOException { in.undeleteAll(); } + protected void doUndeleteAll() throws CorruptIndexException, IOException {in.undeleteAll();} public boolean hasNorms(String field) throws IOException { return in.hasNorms(field); @@ -117,7 +117,7 @@ public void norms(String f, byte[] bytes, int offset) throws IOException { in.norms(f, bytes, offset); } - protected void doSetNorm(int d, String f, byte b) throws IOException { + protected void doSetNorm(int d, String f, byte b) throws CorruptIndexException, IOException { in.setNorm(d, f, b); } @@ -132,7 +132,7 @@ return in.termPositions(); } - protected void doDelete(int n) throws IOException { in.deleteDocument(n); } + protected void doDelete(int n) throws CorruptIndexException, IOException { in.deleteDocument(n); } protected void doCommit() throws IOException { in.commit(); } protected void doClose() throws IOException { in.close(); } @@ -142,5 +142,5 @@ } public long getVersion() { return in.getVersion(); } - public boolean isCurrent() throws IOException { return in.isCurrent(); } + public boolean isCurrent() throws CorruptIndexException, IOException { return in.isCurrent(); } } Index: src/java/org/apache/lucene/index/TermVectorsReader.java =================================================================== --- src/java/org/apache/lucene/index/TermVectorsReader.java (revision 507871) +++ src/java/org/apache/lucene/index/TermVectorsReader.java (working copy) @@ -37,7 +37,7 @@ private int tvfFormat; TermVectorsReader(Directory d, String segment, FieldInfos fieldInfos) - throws IOException { + throws CorruptIndexException, IOException { if (d.fileExists(segment + TermVectorsWriter.TVX_EXTENSION)) { tvx = d.openInput(segment + TermVectorsWriter.TVX_EXTENSION); checkValidFormat(tvx); @@ -51,13 +51,13 @@ this.fieldInfos = fieldInfos; } - private int checkValidFormat(IndexInput in) throws IOException + private int checkValidFormat(IndexInput in) throws CorruptIndexException, IOException { int format = in.readInt(); if (format > TermVectorsWriter.FORMAT_VERSION) { - throw new IOException("Incompatible format version: " + format + " expected " - + TermVectorsWriter.FORMAT_VERSION + " or less"); + throw new CorruptIndexException("Incompatible format version: " + format + " expected " + + TermVectorsWriter.FORMAT_VERSION + " or less"); } return format; } Index: src/java/org/apache/lucene/index/SegmentInfos.java =================================================================== --- src/java/org/apache/lucene/index/SegmentInfos.java (revision 507871) +++ src/java/org/apache/lucene/index/SegmentInfos.java (working copy) @@ -173,8 +173,10 @@ * * @param directory -- directory containing the segments file * @param segmentFileName -- segment file to load + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ - public final void read(Directory directory, String segmentFileName) throws IOException { + public final void read(Directory directory, String segmentFileName) throws CorruptIndexException, IOException { boolean success = false; IndexInput input = directory.openInput(segmentFileName); @@ -192,7 +194,7 @@ if(format < 0){ // file contains explicit format info // check that it is a format we can understand if (format < FORMAT_SINGLE_NORM_FILE) - throw new IOException("Unknown format version: " + format); + throw new CorruptIndexException("Unknown format version: " + format); version = input.readLong(); // read version counter = input.readInt(); // read counter } @@ -224,14 +226,16 @@ /** * This version of read uses the retry logic (for lock-less * commits) to find the right segments file to load. + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ - public final void read(Directory directory) throws IOException { + public final void read(Directory directory) throws CorruptIndexException, IOException { generation = lastGeneration = -1; new FindSegmentsFile(directory) { - public Object doBody(String segmentFileName) throws IOException { + public Object doBody(String segmentFileName) throws CorruptIndexException, IOException { read(directory, segmentFileName); return null; } @@ -304,12 +308,14 @@ /** * Current version number from segments file. + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ public static long readCurrentVersion(Directory directory) - throws IOException { + throws CorruptIndexException, IOException { return ((Long) new FindSegmentsFile(directory) { - public Object doBody(String segmentFileName) throws IOException { + public Object doBody(String segmentFileName) throws CorruptIndexException, IOException { IndexInput input = directory.openInput(segmentFileName); @@ -319,7 +325,7 @@ format = input.readInt(); if(format < 0){ if (format < FORMAT_SINGLE_NORM_FILE) - throw new IOException("Unknown format version: " + format); + throw new CorruptIndexException("Unknown format version: " + format); version = input.readLong(); // read version } } @@ -436,7 +442,7 @@ this.directory = directory; } - public Object run() throws IOException { + public Object run() throws CorruptIndexException, IOException { String segmentFileName = null; long lastGen = -1; long gen = 0; @@ -624,5 +630,5 @@ * during the processing that could have been caused by * a writer committing. */ - protected abstract Object doBody(String segmentFileName) throws IOException;} + protected abstract Object doBody(String segmentFileName) throws CorruptIndexException, IOException;} } Index: src/java/org/apache/lucene/index/TermInfosWriter.java =================================================================== --- src/java/org/apache/lucene/index/TermInfosWriter.java (revision 507871) +++ src/java/org/apache/lucene/index/TermInfosWriter.java (working copy) @@ -91,15 +91,15 @@ Term must be lexicographically greater than all previous Terms added. TermInfo pointers must be positive and greater than all previous.*/ final void add(Term term, TermInfo ti) - throws IOException { + throws CorruptIndexException, IOException { if (!isIndex && term.compareTo(lastTerm) <= 0) - throw new IOException("term out of order (\"" + term + + throw new CorruptIndexException("term out of order (\"" + term + "\".compareTo(\"" + lastTerm + "\") <= 0)"); if (ti.freqPointer < lastTi.freqPointer) - throw new IOException("freqPointer out of order (" + ti.freqPointer + + throw new CorruptIndexException("freqPointer out of order (" + ti.freqPointer + " < " + lastTi.freqPointer + ")"); if (ti.proxPointer < lastTi.proxPointer) - throw new IOException("proxPointer out of order (" + ti.proxPointer + + throw new CorruptIndexException("proxPointer out of order (" + ti.proxPointer + " < " + lastTi.proxPointer + ")"); if (!isIndex && size % indexInterval == 0) Index: src/java/org/apache/lucene/index/SegmentMerger.java =================================================================== --- src/java/org/apache/lucene/index/SegmentMerger.java (revision 507871) +++ src/java/org/apache/lucene/index/SegmentMerger.java (working copy) @@ -87,9 +87,10 @@ /** * Merges the readers specified by the {@link #add} method into the directory passed to the constructor * @return The number of documents that were merged - * @throws IOException + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ - final int merge() throws IOException { + final int merge() throws CorruptIndexException, IOException { int value; value = mergeFields(); @@ -167,9 +168,10 @@ /** * * @return The number of documents in all of the readers - * @throws IOException + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ - private final int mergeFields() throws IOException { + private final int mergeFields() throws CorruptIndexException, IOException { fieldInfos = new FieldInfos(); // merge field names int docCount = 0; for (int i = 0; i < readers.size(); i++) { @@ -240,7 +242,7 @@ private int skipInterval; private SegmentMergeQueue queue = null; - private final void mergeTerms() throws IOException { + private final void mergeTerms() throws CorruptIndexException, IOException { try { freqOutput = directory.createOutput(segment + ".frq"); proxOutput = directory.createOutput(segment + ".prx"); @@ -260,7 +262,7 @@ } } - private final void mergeTermInfos() throws IOException { + private final void mergeTermInfos() throws CorruptIndexException, IOException { int base = 0; for (int i = 0; i < readers.size(); i++) { IndexReader reader = (IndexReader) readers.elementAt(i); @@ -306,9 +308,11 @@ * * @param smis array of segments * @param n number of cells in the array actually occupied + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ private final void mergeTermInfo(SegmentMergeInfo[] smis, int n) - throws IOException { + throws CorruptIndexException, IOException { long freqPointer = freqOutput.getFilePointer(); long proxPointer = proxOutput.getFilePointer(); @@ -330,9 +334,11 @@ * @param smis array of segments * @param n number of cells in the array actually occupied * @return number of documents across all segments where this term was found + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ private final int appendPostings(SegmentMergeInfo[] smis, int n) - throws IOException { + throws CorruptIndexException, IOException { int lastDoc = 0; int df = 0; // number of docs w/ term resetSkip(); @@ -349,7 +355,7 @@ doc += base; // convert to merged space if (doc < 0 || (df > 0 && doc <= lastDoc)) - throw new IllegalStateException("docs out of order (" + doc + + throw new CorruptIndexException("docs out of order (" + doc + " <= " + lastDoc + " )"); df++; Index: src/java/org/apache/lucene/index/IndexWriter.java =================================================================== --- src/java/org/apache/lucene/index/IndexWriter.java (revision 507871) +++ src/java/org/apache/lucene/index/IndexWriter.java (working copy) @@ -25,6 +25,7 @@ import org.apache.lucene.store.IndexInput; import org.apache.lucene.store.IndexOutput; import org.apache.lucene.store.Lock; +import org.apache.lucene.store.LockObtainFailedException; import org.apache.lucene.store.RAMDirectory; import java.io.File; @@ -57,7 +58,8 @@ method should be called before the index is closed.

Opening an IndexWriter creates a lock file for the directory in use. Trying to open - another IndexWriter on the same directory will lead to an IOException. The IOException + another IndexWriter on the same directory will lead to a + {@link LockObtainFailedException}. The {@link LockObtainFailedException} is also thrown if an IndexReader on the same directory is used to delete documents from the index.

@@ -227,12 +229,17 @@ * @param create true to create the index or overwrite * the existing one; false to append to the existing * index + * @throws CorruptIndexException if the index is corrupt + * @throws LockObtainFailedException if another writer + * has this index open (write.lock could not + * be obtained) * @throws IOException if the directory cannot be read/written to, or - * if it does not exist, and create is - * false + * if it does not exist and create is + * false or if there is any other low-level + * IO error */ public IndexWriter(String path, Analyzer a, boolean create) - throws IOException { + throws CorruptIndexException, LockObtainFailedException, IOException { init(path, a, create); } @@ -247,12 +254,17 @@ * @param create true to create the index or overwrite * the existing one; false to append to the existing * index + * @throws CorruptIndexException if the index is corrupt + * @throws LockObtainFailedException if another writer + * has this index open (write.lock could not + * be obtained) * @throws IOException if the directory cannot be read/written to, or - * if it does not exist, and create is - * false + * if it does not exist and create is + * false or if there is any other low-level + * IO error */ public IndexWriter(File path, Analyzer a, boolean create) - throws IOException { + throws CorruptIndexException, LockObtainFailedException, IOException { init(path, a, create); } @@ -267,12 +279,17 @@ * @param create true to create the index or overwrite * the existing one; false to append to the existing * index + * @throws CorruptIndexException if the index is corrupt + * @throws LockObtainFailedException if another writer + * has this index open (write.lock could not + * be obtained) * @throws IOException if the directory cannot be read/written to, or - * if it does not exist, and create is - * false + * if it does not exist and create is + * false or if there is any other low-level + * IO error */ public IndexWriter(Directory d, Analyzer a, boolean create) - throws IOException { + throws CorruptIndexException, LockObtainFailedException, IOException { init(d, a, create, false); } @@ -284,11 +301,16 @@ * * @param path the path to the index directory * @param a the analyzer to use + * @throws CorruptIndexException if the index is corrupt + * @throws LockObtainFailedException if another writer + * has this index open (write.lock could not + * be obtained) * @throws IOException if the directory cannot be - * created or read/written to + * read/written to or if there is any other low-level + * IO error */ public IndexWriter(String path, Analyzer a) - throws IOException { + throws CorruptIndexException, LockObtainFailedException, IOException { if (IndexReader.indexExists(path)) { init(path, a, false); } else { @@ -305,11 +327,16 @@ * * @param path the path to the index directory * @param a the analyzer to use + * @throws CorruptIndexException if the index is corrupt + * @throws LockObtainFailedException if another writer + * has this index open (write.lock could not + * be obtained) * @throws IOException if the directory cannot be - * created or read/written to + * read/written to or if there is any other low-level + * IO error */ public IndexWriter(File path, Analyzer a) - throws IOException { + throws CorruptIndexException, LockObtainFailedException, IOException { if (IndexReader.indexExists(path)) { init(path, a, false); } else { @@ -325,11 +352,16 @@ * * @param d the index directory * @param a the analyzer to use + * @throws CorruptIndexException if the index is corrupt + * @throws LockObtainFailedException if another writer + * has this index open (write.lock could not + * be obtained) * @throws IOException if the directory cannot be - * created or read/written to + * read/written to or if there is any other low-level + * IO error */ public IndexWriter(Directory d, Analyzer a) - throws IOException { + throws CorruptIndexException, LockObtainFailedException, IOException { if (IndexReader.indexExists(d)) { init(d, a, false, false); } else { @@ -338,22 +370,22 @@ } private IndexWriter(Directory d, Analyzer a, final boolean create, boolean closeDir) - throws IOException { + throws CorruptIndexException, LockObtainFailedException, IOException { init(d, a, create, closeDir); } private void init(String path, Analyzer a, final boolean create) - throws IOException { + throws CorruptIndexException, LockObtainFailedException, IOException { init(FSDirectory.getDirectory(path), a, create, true); } private void init(File path, Analyzer a, final boolean create) - throws IOException { + throws CorruptIndexException, LockObtainFailedException, IOException { init(FSDirectory.getDirectory(path), a, create, true); } private void init(Directory d, Analyzer a, final boolean create, boolean closeDir) - throws IOException { + throws CorruptIndexException, LockObtainFailedException, IOException { this.closeDir = closeDir; directory = d; analyzer = a; @@ -365,7 +397,7 @@ Lock writeLock = directory.makeLock(IndexWriter.WRITE_LOCK_NAME); if (!writeLock.obtain(writeLockTimeout)) // obtain write lock - throw new IOException("Index locked for write: " + writeLock); + throw new LockObtainFailedException("Index locked for write: " + writeLock); this.writeLock = writeLock; // save it try { @@ -583,8 +615,10 @@ * * after which, you must be certain not to use the writer * instance anymore.

+ * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ - public synchronized void close() throws IOException { + public synchronized void close() throws CorruptIndexException, IOException { flushRamSegments(); ramDirectory.close(); if (writeLock != null) { @@ -675,8 +709,11 @@ * segments in the index, which is the worst case for * temporary space usage) then the maximum free disk space * required is the same as {@link #optimize}.

+ * + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ - public void addDocument(Document doc) throws IOException { + public void addDocument(Document doc) throws CorruptIndexException, IOException { addDocument(doc, analyzer); } @@ -689,8 +726,11 @@ *

See {@link #addDocument(Document)} for details on * index and IndexWriter state after an Exception, and * flushing/merging temporary free space requirements.

+ * + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ - public void addDocument(Document doc, Analyzer analyzer) throws IOException { + public void addDocument(Document doc, Analyzer analyzer) throws CorruptIndexException, IOException { SegmentInfo newSegmentInfo = buildSingleDocSegment(doc, analyzer); synchronized (this) { ramSegmentInfos.addElement(newSegmentInfo); @@ -699,7 +739,7 @@ } SegmentInfo buildSingleDocSegment(Document doc, Analyzer analyzer) - throws IOException { + throws CorruptIndexException, IOException { DocumentWriter dw = new DocumentWriter(ramDirectory, analyzer, this); dw.setInfoStream(infoStream); String segmentName = newRamSegmentName(); @@ -710,8 +750,10 @@ /** * Deletes the document(s) containing term. * @param term the term to identify the documents to be deleted + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ - public synchronized void deleteDocuments(Term term) throws IOException { + public synchronized void deleteDocuments(Term term) throws CorruptIndexException, IOException { bufferDeleteTerm(term); maybeFlushRamSegments(); } @@ -721,8 +763,10 @@ * terms. All deletes are flushed at the same time. * @param terms array of terms to identify the documents * to be deleted + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ - public synchronized void deleteDocuments(Term[] terms) throws IOException { + public synchronized void deleteDocuments(Term[] terms) throws CorruptIndexException, IOException { for (int i = 0; i < terms.length; i++) { bufferDeleteTerm(terms[i]); } @@ -738,8 +782,10 @@ * @param term the term to identify the document(s) to be * deleted * @param doc the document to be added + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ - public void updateDocument(Term term, Document doc) throws IOException { + public void updateDocument(Term term, Document doc) throws CorruptIndexException, IOException { updateDocument(term, doc, getAnalyzer()); } @@ -753,9 +799,11 @@ * deleted * @param doc the document to be added * @param analyzer the analyzer to use when analyzing the document + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ public void updateDocument(Term term, Document doc, Analyzer analyzer) - throws IOException { + throws CorruptIndexException, IOException { SegmentInfo newSegmentInfo = buildSingleDocSegment(doc, analyzer); synchronized (this) { bufferDeleteTerm(term); @@ -886,8 +934,10 @@ * using compound file format. This will occur when the * Exception is hit during conversion of the segment into * compound format.

+ * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ - public synchronized void optimize() throws IOException { + public synchronized void optimize() throws CorruptIndexException, IOException { flushRamSegments(); while (segmentInfos.size() > 1 || (segmentInfos.size() == 1 && @@ -1023,9 +1073,11 @@ *

See LUCENE-702 * for details.

+ * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ public synchronized void addIndexes(Directory[] dirs) - throws IOException { + throws CorruptIndexException, IOException { optimize(); // start with zero or 1 seg @@ -1079,9 +1131,11 @@ * details on transactional semantics, temporary free * space required in the Directory, and non-CFS segments * on an Exception.

+ * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ public synchronized void addIndexesNoOptimize(Directory[] dirs) - throws IOException { + throws CorruptIndexException, IOException { // Adding indexes can be viewed as adding a sequence of segments S to // a sequence of segments T. Segments in T follow the invariants but // segments in S may not since they could come from multiple indexes. @@ -1215,9 +1269,11 @@ * details on transactional semantics, temporary free * space required in the Directory, and non-CFS segments * on an Exception.

+ * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ public synchronized void addIndexes(IndexReader[] readers) - throws IOException { + throws CorruptIndexException, IOException { optimize(); // start with zero or 1 seg @@ -1337,7 +1393,7 @@ throws IOException { } - protected final void maybeFlushRamSegments() throws IOException { + protected final void maybeFlushRamSegments() throws CorruptIndexException, IOException { // A flush is triggered if enough new documents are buffered or // if enough delete terms are buffered if (ramSegmentInfos.size() >= minMergeDocs || numBufferedDeleteTerms >= maxBufferedDeleteTerms) { @@ -1346,7 +1402,7 @@ } /** Expert: Flushes all RAM-resident segments (buffered documents), then may merge segments. */ - private final synchronized void flushRamSegments() throws IOException { + private final synchronized void flushRamSegments() throws CorruptIndexException, IOException { if (ramSegmentInfos.size() > 0 || bufferedDeleteTerms.size() > 0) { mergeSegments(ramSegmentInfos, 0, ramSegmentInfos.size()); maybeMergeSegments(minMergeDocs); @@ -1356,9 +1412,10 @@ /** * Flush all in-memory buffered updates (adds and deletes) * to the Directory. - * @throws IOException + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ - public final synchronized void flush() throws IOException { + public final synchronized void flush() throws CorruptIndexException, IOException { flushRamSegments(); } @@ -1377,7 +1434,7 @@ } /** Incremental segment merger. */ - private final void maybeMergeSegments(int startUpperBound) throws IOException { + private final void maybeMergeSegments(int startUpperBound) throws CorruptIndexException, IOException { long lowerBound = -1; long upperBound = startUpperBound; @@ -1442,7 +1499,7 @@ * single segment. */ private final int mergeSegments(SegmentInfos sourceSegments, int minSegment, int end) - throws IOException { + throws CorruptIndexException, IOException { // We may be called solely because there are deletes // pending, in which case doMerge is false: @@ -1631,7 +1688,7 @@ // Called during flush to apply any buffered deletes. If // doMerge is true then a new segment was just created and // flushed from the ram segments. - private final void maybeApplyDeletes(boolean doMerge) throws IOException { + private final void maybeApplyDeletes(boolean doMerge) throws CorruptIndexException, IOException { if (bufferedDeleteTerms.size() > 0) { if (infoStream != null) @@ -1743,7 +1800,7 @@ // apply appropriately so that a delete term is only applied to // the documents buffered before it, not those buffered after it. private final void applyDeletesSelectively(HashMap deleteTerms, - IndexReader reader) throws IOException { + IndexReader reader) throws CorruptIndexException, IOException { Iterator iter = deleteTerms.entrySet().iterator(); while (iter.hasNext()) { Entry entry = (Entry) iter.next(); @@ -1769,7 +1826,7 @@ // Apply buffered delete terms to this reader. private final void applyDeletes(HashMap deleteTerms, IndexReader reader) - throws IOException { + throws CorruptIndexException, IOException { Iterator iter = deleteTerms.entrySet().iterator(); while (iter.hasNext()) { Entry entry = (Entry) iter.next(); Index: src/java/org/apache/lucene/index/CorruptIndexException.java =================================================================== --- src/java/org/apache/lucene/index/CorruptIndexException.java (revision 0) +++ src/java/org/apache/lucene/index/CorruptIndexException.java (revision 0) @@ -0,0 +1,30 @@ +/** + * 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. + */ + +package org.apache.lucene.index; + +import java.io.IOException; + +/** + * This exception is thrown when Lucene detects + * an inconsistency in the index. + */ +public class CorruptIndexException extends IOException { + public CorruptIndexException(String message) { + super(message); + } +} Index: src/java/org/apache/lucene/index/StaleReaderException.java =================================================================== --- src/java/org/apache/lucene/index/StaleReaderException.java (revision 0) +++ src/java/org/apache/lucene/index/StaleReaderException.java (revision 0) @@ -0,0 +1,36 @@ +/** + * 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. + */ + +package org.apache.lucene.index; + +import java.io.IOException; + +/** + * This exception is thrown when an {@link IndexReader} + * tries to make changes to the index (via {@link + * IndexReader#deleteDocument}, {@link + * IndexReader#undeleteAll} or {@link IndexReader#setNorm}) + * but changes have already been committed to the index + * since this reader was instantiated. When this happens + * you must open a new reader on the current index to make + * the changes. + */ +public class StaleReaderException extends IOException { + public StaleReaderException(String message) { + super(message); + } +} Index: src/java/org/apache/lucene/index/DocumentWriter.java =================================================================== --- src/java/org/apache/lucene/index/DocumentWriter.java (revision 507871) +++ src/java/org/apache/lucene/index/DocumentWriter.java (working copy) @@ -68,7 +68,7 @@ } final void addDocument(String segment, Document doc) - throws IOException { + throws CorruptIndexException, IOException { // write field names fieldInfos = new FieldInfos(); fieldInfos.add(doc); @@ -295,7 +295,7 @@ } private final void writePostings(Posting[] postings, String segment) - throws IOException { + throws CorruptIndexException, IOException { IndexOutput freq = null, prox = null; TermInfosWriter tis = null; TermVectorsWriter termVectorWriter = null; Index: src/java/org/apache/lucene/index/ParallelReader.java =================================================================== --- src/java/org/apache/lucene/index/ParallelReader.java (revision 507871) +++ src/java/org/apache/lucene/index/ParallelReader.java (working copy) @@ -124,7 +124,7 @@ } // delete in all readers - protected void doDelete(int n) throws IOException { + protected void doDelete(int n) throws CorruptIndexException, IOException { for (int i = 0; i < readers.size(); i++) { ((IndexReader)readers.get(i)).deleteDocument(n); } @@ -132,7 +132,7 @@ } // undeleteAll in all readers - protected void doUndeleteAll() throws IOException { + protected void doUndeleteAll() throws CorruptIndexException, IOException { for (int i = 0; i < readers.size(); i++) { ((IndexReader)readers.get(i)).undeleteAll(); } @@ -140,7 +140,7 @@ } // append fields from storedFieldReaders - public Document document(int n, FieldSelector fieldSelector) throws IOException { + public Document document(int n, FieldSelector fieldSelector) throws CorruptIndexException, IOException { Document result = new Document(); for (int i = 0; i < storedFieldReaders.size(); i++) { IndexReader reader = (IndexReader)storedFieldReaders.get(i); @@ -204,7 +204,7 @@ } protected void doSetNorm(int n, String field, byte value) - throws IOException { + throws CorruptIndexException, IOException { IndexReader reader = ((IndexReader)fieldToReader.get(field)); if (reader!=null) reader.doSetNorm(n, field, value); Index: src/java/org/apache/lucene/index/SegmentReader.java =================================================================== --- src/java/org/apache/lucene/index/SegmentReader.java (revision 507871) +++ src/java/org/apache/lucene/index/SegmentReader.java (working copy) @@ -117,19 +117,31 @@ protected SegmentReader() { super(null); } - public static SegmentReader get(SegmentInfo si) throws IOException { + /** + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error + */ + public static SegmentReader get(SegmentInfo si) throws CorruptIndexException, IOException { return get(si.dir, si, null, false, false); } + /** + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error + */ public static SegmentReader get(SegmentInfos sis, SegmentInfo si, - boolean closeDir) throws IOException { + boolean closeDir) throws CorruptIndexException, IOException { return get(si.dir, si, sis, closeDir, true); } + /** + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error + */ public static SegmentReader get(Directory dir, SegmentInfo si, SegmentInfos sis, boolean closeDir, boolean ownDir) - throws IOException { + throws CorruptIndexException, IOException { SegmentReader instance; try { instance = (SegmentReader)IMPL.newInstance(); @@ -141,7 +153,7 @@ return instance; } - private void initialize(SegmentInfo si) throws IOException { + private void initialize(SegmentInfo si) throws CorruptIndexException, IOException { segment = si.name; this.si = si; @@ -161,7 +173,7 @@ // Verify two sources of "maxDoc" agree: if (fieldsReader.size() != si.docCount) { - throw new IllegalStateException("doc counts differ for segment " + si.name + ": fieldsReader shows " + fieldsReader.size() + " but segmentInfo shows " + si.docCount); + throw new CorruptIndexException("doc counts differ for segment " + si.name + ": fieldsReader shows " + fieldsReader.size() + " but segmentInfo shows " + si.docCount); } tis = new TermInfosReader(cfsDir, segment, fieldInfos); @@ -172,7 +184,7 @@ // Verify # deletes does not exceed maxDoc for this segment: if (deletedDocs.count() > maxDoc()) { - throw new IllegalStateException("number of deletes (" + deletedDocs.count() + ") exceeds max doc (" + maxDoc() + ") for segment " + si.name); + throw new CorruptIndexException("number of deletes (" + deletedDocs.count() + ") exceeds max doc (" + maxDoc() + ") for segment " + si.name); } } @@ -335,7 +347,11 @@ return tis.terms(t); } - public synchronized Document document(int n, FieldSelector fieldSelector) throws IOException { + /** + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error + */ + public synchronized Document document(int n, FieldSelector fieldSelector) throws CorruptIndexException, IOException { if (isDeleted(n)) throw new IllegalArgumentException ("attempt to access a deleted document"); Index: src/java/org/apache/lucene/index/IndexModifier.java =================================================================== --- src/java/org/apache/lucene/index/IndexModifier.java (revision 507871) +++ src/java/org/apache/lucene/index/IndexModifier.java (working copy) @@ -21,6 +21,7 @@ import org.apache.lucene.document.Document; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; +import org.apache.lucene.store.LockObtainFailedException; import java.io.File; import java.io.IOException; @@ -112,8 +113,13 @@ * @param analyzer the analyzer to use for adding new documents * @param create true to create the index or overwrite the existing one; * false to append to the existing index + * @throws CorruptIndexException if the index is corrupt + * @throws LockObtainFailedException if another writer + * has this index open (write.lock could not + * be obtained) + * @throws IOException if there is a low-level IO error */ - public IndexModifier(Directory directory, Analyzer analyzer, boolean create) throws IOException { + public IndexModifier(Directory directory, Analyzer analyzer, boolean create) throws CorruptIndexException, LockObtainFailedException, IOException { init(directory, analyzer, create); } @@ -124,8 +130,13 @@ * @param analyzer the analyzer to use for adding new documents * @param create true to create the index or overwrite the existing one; * false to append to the existing index + * @throws CorruptIndexException if the index is corrupt + * @throws LockObtainFailedException if another writer + * has this index open (write.lock could not + * be obtained) + * @throws IOException if there is a low-level IO error */ - public IndexModifier(String dirName, Analyzer analyzer, boolean create) throws IOException { + public IndexModifier(String dirName, Analyzer analyzer, boolean create) throws CorruptIndexException, LockObtainFailedException, IOException { Directory dir = FSDirectory.getDirectory(dirName); init(dir, analyzer, create); } @@ -137,17 +148,26 @@ * @param analyzer the analyzer to use for adding new documents * @param create true to create the index or overwrite the existing one; * false to append to the existing index + * @throws CorruptIndexException if the index is corrupt + * @throws LockObtainFailedException if another writer + * has this index open (write.lock could not + * be obtained) + * @throws IOException if there is a low-level IO error */ - public IndexModifier(File file, Analyzer analyzer, boolean create) throws IOException { + public IndexModifier(File file, Analyzer analyzer, boolean create) throws CorruptIndexException, LockObtainFailedException, IOException { Directory dir = FSDirectory.getDirectory(file); init(dir, analyzer, create); } /** * Initialize an IndexWriter. - * @throws IOException + * @throws CorruptIndexException if the index is corrupt + * @throws LockObtainFailedException if another writer + * has this index open (write.lock could not + * be obtained) + * @throws IOException if there is a low-level IO error */ - protected void init(Directory directory, Analyzer analyzer, boolean create) throws IOException { + protected void init(Directory directory, Analyzer analyzer, boolean create) throws CorruptIndexException, LockObtainFailedException, IOException { this.directory = directory; synchronized(this.directory) { this.analyzer = analyzer; @@ -168,9 +188,13 @@ /** * Close the IndexReader and open an IndexWriter. - * @throws IOException + * @throws CorruptIndexException if the index is corrupt + * @throws LockObtainFailedException if another writer + * has this index open (write.lock could not + * be obtained) + * @throws IOException if there is a low-level IO error */ - protected void createIndexWriter() throws IOException { + protected void createIndexWriter() throws CorruptIndexException, LockObtainFailedException, IOException { if (indexWriter == null) { if (indexReader != null) { indexReader.close(); @@ -187,9 +211,10 @@ /** * Close the IndexWriter and open an IndexReader. - * @throws IOException + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ - protected void createIndexReader() throws IOException { + protected void createIndexReader() throws CorruptIndexException, IOException { if (indexReader == null) { if (indexWriter != null) { indexWriter.close(); @@ -201,9 +226,13 @@ /** * Make sure all changes are written to disk. - * @throws IOException + * @throws CorruptIndexException if the index is corrupt + * @throws LockObtainFailedException if another writer + * has this index open (write.lock could not + * be obtained) + * @throws IOException if there is a low-level IO error */ - public void flush() throws IOException { + public void flush() throws CorruptIndexException, LockObtainFailedException, IOException { synchronized(directory) { assureOpen(); if (indexWriter != null) { @@ -225,8 +254,13 @@ * discarded. * @see IndexWriter#addDocument(Document, Analyzer) * @throws IllegalStateException if the index is closed + * @throws CorruptIndexException if the index is corrupt + * @throws LockObtainFailedException if another writer + * has this index open (write.lock could not + * be obtained) + * @throws IOException if there is a low-level IO error */ - public void addDocument(Document doc, Analyzer docAnalyzer) throws IOException { + public void addDocument(Document doc, Analyzer docAnalyzer) throws CorruptIndexException, LockObtainFailedException, IOException { synchronized(directory) { assureOpen(); createIndexWriter(); @@ -243,8 +277,13 @@ * discarded. * @see IndexWriter#addDocument(Document) * @throws IllegalStateException if the index is closed + * @throws CorruptIndexException if the index is corrupt + * @throws LockObtainFailedException if another writer + * has this index open (write.lock could not + * be obtained) + * @throws IOException if there is a low-level IO error */ - public void addDocument(Document doc) throws IOException { + public void addDocument(Document doc) throws CorruptIndexException, LockObtainFailedException, IOException { addDocument(doc, null); } @@ -257,8 +296,15 @@ * @return the number of documents deleted * @see IndexReader#deleteDocuments(Term) * @throws IllegalStateException if the index is closed + * @throws StaleReaderException if the index has changed + * since this reader was opened + * @throws CorruptIndexException if the index is corrupt + * @throws LockObtainFailedException if another writer + * has this index open (write.lock could not + * be obtained) + * @throws IOException if there is a low-level IO error */ - public int deleteDocuments(Term term) throws IOException { + public int deleteDocuments(Term term) throws StaleReaderException, CorruptIndexException, LockObtainFailedException, IOException { synchronized(directory) { assureOpen(); createIndexReader(); @@ -269,9 +315,15 @@ /** * Deletes the document numbered docNum. * @see IndexReader#deleteDocument(int) + * @throws StaleReaderException if the index has changed + * since this reader was opened + * @throws CorruptIndexException if the index is corrupt + * @throws LockObtainFailedException if another writer + * has this index open (write.lock could not + * be obtained) * @throws IllegalStateException if the index is closed */ - public void deleteDocument(int docNum) throws IOException { + public void deleteDocument(int docNum) throws StaleReaderException, CorruptIndexException, LockObtainFailedException, IOException { synchronized(directory) { assureOpen(); createIndexReader(); @@ -302,8 +354,13 @@ * for search. * @see IndexWriter#optimize() * @throws IllegalStateException if the index is closed + * @throws CorruptIndexException if the index is corrupt + * @throws LockObtainFailedException if another writer + * has this index open (write.lock could not + * be obtained) + * @throws IOException if there is a low-level IO error */ - public void optimize() throws IOException { + public void optimize() throws CorruptIndexException, LockObtainFailedException, IOException { synchronized(directory) { assureOpen(); createIndexWriter(); @@ -329,10 +386,14 @@ } /** - * @throws IOException * @see IndexModifier#setInfoStream(PrintStream) + * @throws CorruptIndexException if the index is corrupt + * @throws LockObtainFailedException if another writer + * has this index open (write.lock could not + * be obtained) + * @throws IOException if there is a low-level IO error */ - public PrintStream getInfoStream() throws IOException { + public PrintStream getInfoStream() throws CorruptIndexException, LockObtainFailedException, IOException { synchronized(directory) { assureOpen(); createIndexWriter(); @@ -358,10 +419,14 @@ } /** - * @throws IOException * @see IndexModifier#setUseCompoundFile(boolean) + * @throws CorruptIndexException if the index is corrupt + * @throws LockObtainFailedException if another writer + * has this index open (write.lock could not + * be obtained) + * @throws IOException if there is a low-level IO error */ - public boolean getUseCompoundFile() throws IOException { + public boolean getUseCompoundFile() throws CorruptIndexException, LockObtainFailedException, IOException { synchronized(directory) { assureOpen(); createIndexWriter(); @@ -394,10 +459,14 @@ } /** - * @throws IOException * @see IndexModifier#setMaxFieldLength(int) + * @throws CorruptIndexException if the index is corrupt + * @throws LockObtainFailedException if another writer + * has this index open (write.lock could not + * be obtained) + * @throws IOException if there is a low-level IO error */ - public int getMaxFieldLength() throws IOException { + public int getMaxFieldLength() throws CorruptIndexException, LockObtainFailedException, IOException { synchronized(directory) { assureOpen(); createIndexWriter(); @@ -429,10 +498,14 @@ } /** - * @throws IOException * @see IndexModifier#setMaxBufferedDocs(int) + * @throws CorruptIndexException if the index is corrupt + * @throws LockObtainFailedException if another writer + * has this index open (write.lock could not + * be obtained) + * @throws IOException if there is a low-level IO error */ - public int getMaxBufferedDocs() throws IOException { + public int getMaxBufferedDocs() throws CorruptIndexException, LockObtainFailedException, IOException { synchronized(directory) { assureOpen(); createIndexWriter(); @@ -464,10 +537,14 @@ } /** - * @throws IOException * @see IndexModifier#setMergeFactor(int) + * @throws CorruptIndexException if the index is corrupt + * @throws LockObtainFailedException if another writer + * has this index open (write.lock could not + * be obtained) + * @throws IOException if there is a low-level IO error */ - public int getMergeFactor() throws IOException { + public int getMergeFactor() throws CorruptIndexException, LockObtainFailedException, IOException { synchronized(directory) { assureOpen(); createIndexWriter(); @@ -479,8 +556,10 @@ * Close this index, writing all pending changes to disk. * * @throws IllegalStateException if the index has been closed before already + * @throws CorruptIndexException if the index is corrupt + * @throws IOException if there is a low-level IO error */ - public void close() throws IOException { + public void close() throws CorruptIndexException, IOException { synchronized(directory) { if (!open) throw new IllegalStateException("Index is closed already"); Index: src/java/org/apache/lucene/store/Directory.java =================================================================== --- src/java/org/apache/lucene/store/Directory.java (revision 507871) +++ src/java/org/apache/lucene/store/Directory.java (working copy) @@ -94,7 +94,7 @@ * Attempt to clear (forcefully unlock and remove) the * specified lock. Only call this at a time when you are * certain this lock is no longer in use. - * @param lockName name of the lock to be cleared. + * @param name name of the lock to be cleared. */ public void clearLock(String name) throws IOException { if (lockFactory != null) { Index: src/java/org/apache/lucene/store/LockObtainFailedException.java =================================================================== --- src/java/org/apache/lucene/store/LockObtainFailedException.java (revision 0) +++ src/java/org/apache/lucene/store/LockObtainFailedException.java (revision 0) @@ -0,0 +1,33 @@ +/** + * 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. + */ + +package org.apache.lucene.store; + +import java.io.IOException; + +/** + * This exception is thrown when the write.lock + * could not be acquired. This + * happens when a writer tries to open an index + * that another writer already has open. + * @see Lock#obtain(long). + */ +public class LockObtainFailedException extends IOException { + public LockObtainFailedException(String message) { + super(message); + } +} Index: src/java/org/apache/lucene/store/Lock.java =================================================================== --- src/java/org/apache/lucene/store/Lock.java (revision 507871) +++ src/java/org/apache/lucene/store/Lock.java (working copy) @@ -53,9 +53,10 @@ * lockWaitTimeout is passed. * @param lockWaitTimeout length of time to wait in ms * @return true if lock was obtained - * @throws IOException if lock wait times out or obtain() throws an IOException + * @throws LockObtainFailedException if lock wait times out + * @throws IOException if obtain() throws IOException */ - public boolean obtain(long lockWaitTimeout) throws IOException { + public boolean obtain(long lockWaitTimeout) throws LockObtainFailedException, IOException { failureReason = null; boolean locked = obtain(); int maxSleepCount = (int)(lockWaitTimeout / LOCK_POLL_INTERVAL); @@ -66,7 +67,7 @@ if (failureReason != null) { reason += ": " + failureReason; } - IOException e = new IOException(reason); + LockObtainFailedException e = new LockObtainFailedException(reason); if (failureReason != null) { e.initCause(failureReason); } @@ -108,8 +109,12 @@ /** Calls {@link #doBody} while lock is obtained. Blocks if lock * cannot be obtained immediately. Retries to obtain lock once per second * until it is obtained, or until it has tried ten times. Lock is released when - * {@link #doBody} exits. */ - public Object run() throws IOException { + * {@link #doBody} exits. + * @throws LockObtainFailedException if lock could not + * be obtained + * @throws IOException if {@link Lock#obtain} throws IOException + */ + public Object run() throws LockObtainFailedException, IOException { boolean locked = false; try { locked = lock.obtain(lockWaitTimeout);