diff --git a/CHANGES.txt b/CHANGES.txt
index 89135fdba3f..16b9d69dd0f 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -29,6 +29,11 @@ API Changes
share an index over NFS by customizing when prior commits are
deleted. (Mike McCandless)
+ 4. LUCENE-818: changed most public methods of IndexWriter,
+ IndexReader (and its subclasses), FieldsReader and RAMDirectory to
+ throw AlreadyClosedException if they are accessed after being
+ closed. (Mike McCandless)
+
Bug fixes
1. LUCENE-804: Fixed build.xml to pack a fully compilable src dist. (Doron Cohen)
diff --git a/src/java/org/apache/lucene/index/FieldsReader.java b/src/java/org/apache/lucene/index/FieldsReader.java
index 4f0898b6353..6a56883c38a 100644
--- a/src/java/org/apache/lucene/index/FieldsReader.java
+++ b/src/java/org/apache/lucene/index/FieldsReader.java
@@ -20,6 +20,7 @@ package org.apache.lucene.index;
import org.apache.lucene.document.*;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.IndexInput;
+import org.apache.lucene.store.AlreadyClosedException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -46,6 +47,7 @@ final class FieldsReader {
private final IndexInput indexStream;
private int size;
+ private boolean closed;
private ThreadLocal fieldsStreamTL = new ThreadLocal();
@@ -58,6 +60,15 @@ final class FieldsReader {
size = (int) (indexStream.length() / 8);
}
+ /**
+ * @throws AlreadyClosedException if this FieldsReader is closed
+ */
+ protected final void ensureOpen() throws AlreadyClosedException {
+ if (closed) {
+ throw new AlreadyClosedException("this FieldsReader is closed");
+ }
+ }
+
/**
* Closes the underlying {@link org.apache.lucene.store.IndexInput} streams, including any ones associated with a
* lazy implementation of a Field. This means that the Fields values will not be accessible.
@@ -65,13 +76,16 @@ final class FieldsReader {
* @throws IOException
*/
final void close() throws IOException {
- fieldsStream.close();
- cloneableFieldsStream.close();
- indexStream.close();
- IndexInput localFieldsStream = (IndexInput) fieldsStreamTL.get();
- if (localFieldsStream != null) {
- localFieldsStream.close();
- fieldsStreamTL.set(null);
+ if (!closed) {
+ fieldsStream.close();
+ cloneableFieldsStream.close();
+ indexStream.close();
+ IndexInput localFieldsStream = (IndexInput) fieldsStreamTL.get();
+ if (localFieldsStream != null) {
+ localFieldsStream.close();
+ fieldsStreamTL.set(null);
+ }
+ closed = true;
}
}
@@ -323,6 +337,7 @@ final class FieldsReader {
* binaryValue() must be set.
*/
public byte[] binaryValue() {
+ ensureOpen();
if (fieldsData == null) {
final byte[] b = new byte[toRead];
IndexInput localFieldsStream = getFieldStream();
@@ -349,6 +364,7 @@ final class FieldsReader {
* and binaryValue() must be set.
*/
public Reader readerValue() {
+ ensureOpen();
return fieldsData instanceof Reader ? (Reader) fieldsData : null;
}
@@ -358,6 +374,7 @@ final class FieldsReader {
* binaryValue() must be set.
*/
public String stringValue() {
+ ensureOpen();
if (fieldsData == null) {
IndexInput localFieldsStream = getFieldStream();
try {
@@ -380,18 +397,22 @@ final class FieldsReader {
}
public long getPointer() {
+ ensureOpen();
return pointer;
}
public void setPointer(long pointer) {
+ ensureOpen();
this.pointer = pointer;
}
public int getToRead() {
+ ensureOpen();
return toRead;
}
public void setToRead(int toRead) {
+ ensureOpen();
this.toRead = toRead;
}
}
diff --git a/src/java/org/apache/lucene/index/FilterIndexReader.java b/src/java/org/apache/lucene/index/FilterIndexReader.java
index 99dc3e36618..f23c0e79d49 100644
--- a/src/java/org/apache/lucene/index/FilterIndexReader.java
+++ b/src/java/org/apache/lucene/index/FilterIndexReader.java
@@ -92,43 +92,84 @@ public class FilterIndexReader extends IndexReader {
public TermFreqVector[] getTermFreqVectors(int docNumber)
throws IOException {
+ ensureOpen();
return in.getTermFreqVectors(docNumber);
}
public TermFreqVector getTermFreqVector(int docNumber, String field)
throws IOException {
+ ensureOpen();
return in.getTermFreqVector(docNumber, field);
}
- public int numDocs() { return in.numDocs(); }
- public int maxDoc() { return in.maxDoc(); }
+ public int numDocs() {
+ // Don't call ensureOpen() here (it could affect performance)
+ return in.numDocs();
+ }
- public Document document(int n, FieldSelector fieldSelector) throws CorruptIndexException, IOException { return in.document(n, fieldSelector); }
+ public int maxDoc() {
+ // Don't call ensureOpen() here (it could affect performance)
+ return in.maxDoc();
+ }
+
+ public Document document(int n, FieldSelector fieldSelector) throws CorruptIndexException, IOException {
+ ensureOpen();
+ return in.document(n, fieldSelector);
+ }
+
+ public boolean isDeleted(int n) {
+ // Don't call ensureOpen() here (it could affect performance)
+ return in.isDeleted(n);
+ }
+
+ public boolean hasDeletions() {
+ // Don't call ensureOpen() here (it could affect performance)
+ return in.hasDeletions();
+ }
- public boolean isDeleted(int n) { return in.isDeleted(n); }
- public boolean hasDeletions() { return in.hasDeletions(); }
protected void doUndeleteAll() throws CorruptIndexException, IOException {in.undeleteAll();}
public boolean hasNorms(String field) throws IOException {
+ ensureOpen();
return in.hasNorms(field);
}
- public byte[] norms(String f) throws IOException { return in.norms(f); }
+ public byte[] norms(String f) throws IOException {
+ ensureOpen();
+ return in.norms(f);
+ }
+
public void norms(String f, byte[] bytes, int offset) throws IOException {
+ ensureOpen();
in.norms(f, bytes, offset);
}
+
protected void doSetNorm(int d, String f, byte b) throws CorruptIndexException, IOException {
in.setNorm(d, f, b);
}
- public TermEnum terms() throws IOException { return in.terms(); }
- public TermEnum terms(Term t) throws IOException { return in.terms(t); }
+ public TermEnum terms() throws IOException {
+ ensureOpen();
+ return in.terms();
+ }
- public int docFreq(Term t) throws IOException { return in.docFreq(t); }
+ public TermEnum terms(Term t) throws IOException {
+ ensureOpen();
+ return in.terms(t);
+ }
- public TermDocs termDocs() throws IOException { return in.termDocs(); }
+ public int docFreq(Term t) throws IOException {
+ ensureOpen();
+ return in.docFreq(t);
+ }
+
+ public TermDocs termDocs() throws IOException {
+ ensureOpen();
+ return in.termDocs();
+ }
public TermPositions termPositions() throws IOException {
+ ensureOpen();
return in.termPositions();
}
@@ -138,9 +179,17 @@ public class FilterIndexReader extends IndexReader {
public Collection getFieldNames(IndexReader.FieldOption fieldNames) {
+ ensureOpen();
return in.getFieldNames(fieldNames);
}
- public long getVersion() { return in.getVersion(); }
- public boolean isCurrent() throws CorruptIndexException, IOException { return in.isCurrent(); }
+ public long getVersion() {
+ ensureOpen();
+ return in.getVersion();
+ }
+
+ public boolean isCurrent() throws CorruptIndexException, IOException {
+ ensureOpen();
+ return in.isCurrent();
+ }
}
diff --git a/src/java/org/apache/lucene/index/IndexReader.java b/src/java/org/apache/lucene/index/IndexReader.java
index 625d1684279..b0c21c535e8 100644
--- a/src/java/org/apache/lucene/index/IndexReader.java
+++ b/src/java/org/apache/lucene/index/IndexReader.java
@@ -25,6 +25,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 org.apache.lucene.store.AlreadyClosedException;
import java.io.File;
import java.io.FileOutputStream;
@@ -115,7 +116,16 @@ public abstract class IndexReader {
private boolean directoryOwner;
private boolean closeDirectory;
private IndexDeletionPolicy deletionPolicy;
- private boolean isClosed;
+ private boolean closed;
+
+ /**
+ * @throws AlreadyClosedException if this IndexReader is closed
+ */
+ protected final void ensureOpen() throws AlreadyClosedException {
+ if (closed) {
+ throw new AlreadyClosedException("this IndexReader is closed");
+ }
+ }
private SegmentInfos segmentInfos;
private Lock writeLock;
@@ -208,8 +218,12 @@ public abstract class IndexReader {
}.run();
}
- /** Returns the directory this index resides in. */
- public Directory directory() { return directory; }
+ /** Returns the directory this index resides in.
+ */
+ public Directory directory() {
+ ensureOpen();
+ return directory;
+ }
/**
* Returns the time the index in the named directory was last modified.
@@ -301,6 +315,7 @@ public abstract class IndexReader {
* Version number when this IndexReader was opened.
*/
public long getVersion() {
+ ensureOpen();
return segmentInfos.getVersion();
}
@@ -313,6 +328,7 @@ public abstract class IndexReader {
* @throws IOException if there is a low-level IO error
*/
public boolean isCurrent() throws CorruptIndexException, IOException {
+ ensureOpen();
return SegmentInfos.readCurrentVersion(directory) == segmentInfos.getVersion();
}
@@ -321,7 +337,8 @@ public abstract class IndexReader {
* @return true
if the index is optimized; false
otherwise
*/
public boolean isOptimized() {
- return segmentInfos.size() == 1 && hasDeletions() == false;
+ ensureOpen();
+ return segmentInfos.size() == 1 && hasDeletions() == false;
}
/**
@@ -407,6 +424,7 @@ public abstract class IndexReader {
* @throws IOException if there is a low-level IO error
*/
public Document document(int n) throws CorruptIndexException, IOException {
+ ensureOpen();
return document(n, null);
}
@@ -445,6 +463,7 @@ public abstract class IndexReader {
public boolean hasNorms(String field) throws IOException {
// backward compatible implementation.
// SegmentReader has an efficient implementation.
+ ensureOpen();
return norms(field) != null;
}
@@ -477,11 +496,11 @@ public abstract class IndexReader {
* @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
+ * @throws IOException if there is a low-level IO error
*/
public final synchronized void setNorm(int doc, String field, byte value)
throws StaleReaderException, CorruptIndexException, LockObtainFailedException, IOException {
+ ensureOpen();
if(directoryOwner)
acquireWriteLock();
hasChanges = true;
@@ -504,27 +523,31 @@ public abstract class IndexReader {
* @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
+ * @throws IOException if there is a low-level IO error
*/
public void setNorm(int doc, String field, float value)
throws StaleReaderException, CorruptIndexException, LockObtainFailedException, IOException {
+ ensureOpen();
setNorm(doc, field, Similarity.encodeNorm(value));
}
/** Returns an enumeration of all the terms in the index.
* The enumeration is ordered by Term.compareTo(). Each term
* is greater than all that precede it in the enumeration.
+ * @throws IOException if there is a low-level IO error
*/
public abstract TermEnum terms() throws IOException;
/** Returns an enumeration of all terms after a given term.
* The enumeration is ordered by Term.compareTo(). Each term
* is greater than all that precede it in the enumeration.
+ * @throws IOException if there is a low-level IO error
*/
public abstract TermEnum terms(Term t) throws IOException;
- /** Returns the number of documents containing the term t
. */
+ /** Returns the number of documents containing the term t
.
+ * @throws IOException if there is a low-level IO error
+ */
public abstract int docFreq(Term t) throws IOException;
/** Returns an enumeration of all the documents which contain
@@ -536,14 +559,18 @@ public abstract class IndexReader {
*
*
The enumeration is ordered by document number. Each document number * is greater than all that precede it in the enumeration. + * @throws IOException if there is a low-level IO error */ public TermDocs termDocs(Term term) throws IOException { + ensureOpen(); TermDocs termDocs = termDocs(); termDocs.seek(term); return termDocs; } - /** Returns an unpositioned {@link TermDocs} enumerator. */ + /** Returns an unpositioned {@link TermDocs} enumerator. + * @throws IOException if there is a low-level IO error + */ public abstract TermDocs termDocs() throws IOException; /** Returns an enumeration of all the documents which contain @@ -561,14 +588,18 @@ public abstract class IndexReader { *
This positional information faciliates phrase and proximity searching. *
The enumeration is ordered by document number. Each document number is
* greater than all that precede it in the enumeration.
+ * @throws IOException if there is a low-level IO error
*/
public TermPositions termPositions(Term term) throws IOException {
+ ensureOpen();
TermPositions termPositions = termPositions();
termPositions.seek(term);
return termPositions;
}
- /** Returns an unpositioned {@link TermPositions} enumerator. */
+ /** Returns an unpositioned {@link TermPositions} enumerator.
+ * @throws IOException if there is a low-level IO error
+ */
public abstract TermPositions termPositions() throws IOException;
/**
@@ -584,10 +615,9 @@ public abstract class IndexReader {
* @throws IOException if there is a low-level IO error
*/
private void acquireWriteLock() throws StaleReaderException, CorruptIndexException, LockObtainFailedException, IOException {
+ ensureOpen();
if (stale)
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);
@@ -620,10 +650,10 @@ public abstract class IndexReader {
* @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
+ * @throws IOException if there is a low-level IO error
*/
public final synchronized void deleteDocument(int docNum) throws StaleReaderException, CorruptIndexException, LockObtainFailedException, IOException {
+ ensureOpen();
if(directoryOwner)
acquireWriteLock();
hasChanges = true;
@@ -652,10 +682,10 @@ public abstract class IndexReader {
* @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
+ * @throws IOException if there is a low-level IO error
*/
public final int deleteDocuments(Term term) throws StaleReaderException, CorruptIndexException, LockObtainFailedException, IOException {
+ ensureOpen();
TermDocs docs = termDocs(term);
if (docs == null) return 0;
int n = 0;
@@ -678,10 +708,10 @@ public abstract class IndexReader {
* 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
+ * @throws IOException if there is a low-level IO error
*/
public final synchronized void undeleteAll() throws StaleReaderException, CorruptIndexException, LockObtainFailedException, IOException {
+ ensureOpen();
if(directoryOwner)
acquireWriteLock();
hasChanges = true;
@@ -790,19 +820,16 @@ public abstract class IndexReader {
* 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
+ * @throws IOException if 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;
+ if (!closed) {
+ commit();
+ doClose();
+ if (directoryOwner)
+ closed = true;
+ if(closeDirectory)
+ directory.close();
}
}
diff --git a/src/java/org/apache/lucene/index/IndexWriter.java b/src/java/org/apache/lucene/index/IndexWriter.java
index 6eb1b412a4e..09383a86f88 100644
--- a/src/java/org/apache/lucene/index/IndexWriter.java
+++ b/src/java/org/apache/lucene/index/IndexWriter.java
@@ -24,6 +24,7 @@ import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.Lock;
import org.apache.lucene.store.LockObtainFailedException;
+import org.apache.lucene.store.AlreadyClosedException;
import org.apache.lucene.store.RAMDirectory;
import java.io.File;
@@ -208,6 +209,16 @@ public class IndexWriter {
private boolean useCompoundFile = true;
private boolean closeDir;
+ private boolean closed;
+
+ /**
+ * @throws AlreadyClosedException if this IndexWriter is closed
+ */
+ protected final void ensureOpen() throws AlreadyClosedException {
+ if (closed) {
+ throw new AlreadyClosedException("this IndexWriter is closed");
+ }
+ }
/** Get the current setting of whether to use the compound file format.
* Note that this just returns the value you set with setUseCompoundFile(boolean)
@@ -215,6 +226,7 @@ public class IndexWriter {
* @see #setUseCompoundFile(boolean)
*/
public boolean getUseCompoundFile() {
+ ensureOpen();
return useCompoundFile;
}
@@ -223,6 +235,7 @@ public class IndexWriter {
* is finished. This is done regardless of what directory is in use.
*/
public void setUseCompoundFile(boolean value) {
+ ensureOpen();
useCompoundFile = value;
}
@@ -231,6 +244,7 @@ public class IndexWriter {
* @see Similarity#setDefault(Similarity)
*/
public void setSimilarity(Similarity similarity) {
+ ensureOpen();
this.similarity = similarity;
}
@@ -239,6 +253,7 @@ public class IndexWriter {
*
This defaults to the current value of {@link Similarity#getDefault()}.
*/
public Similarity getSimilarity() {
+ ensureOpen();
return this.similarity;
}
@@ -264,6 +279,7 @@ public class IndexWriter {
* @see #DEFAULT_TERM_INDEX_INTERVAL
*/
public void setTermIndexInterval(int interval) {
+ ensureOpen();
this.termIndexInterval = interval;
}
@@ -271,7 +287,10 @@ public class IndexWriter {
*
* @see #setTermIndexInterval(int)
*/
- public int getTermIndexInterval() { return termIndexInterval; }
+ public int getTermIndexInterval() {
+ ensureOpen();
+ return termIndexInterval;
+ }
/**
* Constructs an IndexWriter for the index in path
.
@@ -580,6 +599,7 @@ public class IndexWriter {
*
The default value is {@link Integer#MAX_VALUE}. */ public void setMaxMergeDocs(int maxMergeDocs) { + ensureOpen(); this.maxMergeDocs = maxMergeDocs; } @@ -587,6 +607,7 @@ public class IndexWriter { * @see #setMaxMergeDocs */ public int getMaxMergeDocs() { + ensureOpen(); return maxMergeDocs; } @@ -603,6 +624,7 @@ public class IndexWriter { * By default, no more than 10,000 terms will be indexed for a field. */ public void setMaxFieldLength(int maxFieldLength) { + ensureOpen(); this.maxFieldLength = maxFieldLength; } @@ -610,6 +632,7 @@ public class IndexWriter { * @see #setMaxFieldLength */ public int getMaxFieldLength() { + ensureOpen(); return maxFieldLength; } @@ -624,6 +647,7 @@ public class IndexWriter { * @throws IllegalArgumentException if maxBufferedDocs is smaller than 2 */ public void setMaxBufferedDocs(int maxBufferedDocs) { + ensureOpen(); if (maxBufferedDocs < 2) throw new IllegalArgumentException("maxBufferedDocs must at least be 2"); this.minMergeDocs = maxBufferedDocs; @@ -633,6 +657,7 @@ public class IndexWriter { * @see #setMaxBufferedDocs */ public int getMaxBufferedDocs() { + ensureOpen(); return minMergeDocs; } @@ -646,6 +671,7 @@ public class IndexWriter { * @throws IllegalArgumentException if maxBufferedDeleteTerms is smaller than 1
*/ public void setMaxBufferedDeleteTerms(int maxBufferedDeleteTerms) { + ensureOpen(); if (maxBufferedDeleteTerms < 1) throw new IllegalArgumentException("maxBufferedDeleteTerms must at least be 1"); this.maxBufferedDeleteTerms = maxBufferedDeleteTerms; @@ -655,6 +681,7 @@ public class IndexWriter { * @see #setMaxBufferedDeleteTerms */ public int getMaxBufferedDeleteTerms() { + ensureOpen(); return maxBufferedDeleteTerms; } @@ -669,6 +696,7 @@ public class IndexWriter { *This must never be less than 2. The default value is 10. */ public void setMergeFactor(int mergeFactor) { + ensureOpen(); if (mergeFactor < 2) throw new IllegalArgumentException("mergeFactor cannot be less than 2"); this.mergeFactor = mergeFactor; @@ -678,6 +706,7 @@ public class IndexWriter { * @see #setMergeFactor */ public int getMergeFactor() { + ensureOpen(); return mergeFactor; } @@ -701,6 +730,7 @@ public class IndexWriter { * to this. */ public void setInfoStream(PrintStream infoStream) { + ensureOpen(); this.infoStream = infoStream; deleter.setInfoStream(infoStream); } @@ -709,6 +739,7 @@ public class IndexWriter { * @see #setInfoStream */ public PrintStream getInfoStream() { + ensureOpen(); return infoStream; } @@ -717,6 +748,7 @@ public class IndexWriter { * @see #setDefaultWriteLockTimeout to change the default value for all instances of IndexWriter. */ public void setWriteLockTimeout(long writeLockTimeout) { + ensureOpen(); this.writeLockTimeout = writeLockTimeout; } @@ -724,6 +756,7 @@ public class IndexWriter { * @see #setWriteLockTimeout */ public long getWriteLockTimeout() { + ensureOpen(); return writeLockTimeout; } @@ -777,22 +810,26 @@ public class IndexWriter { * @throws IOException if there is a low-level IO error */ public synchronized void close() throws CorruptIndexException, IOException { - flushRamSegments(); + if (!closed) { + flushRamSegments(); - if (commitPending) { - segmentInfos.write(directory); // now commit changes - deleter.checkpoint(segmentInfos, true); - commitPending = false; - rollbackSegmentInfos = null; - } + if (commitPending) { + segmentInfos.write(directory); // now commit changes + deleter.checkpoint(segmentInfos, true); + commitPending = false; + rollbackSegmentInfos = null; + } - ramDirectory.close(); - if (writeLock != null) { - writeLock.release(); // release write lock - writeLock = null; + ramDirectory.close(); + if (writeLock != null) { + writeLock.release(); // release write lock + writeLock = null; + } + closed = true; + + if(closeDir) + directory.close(); } - if(closeDir) - directory.close(); } /** Release the write lock, if needed. */ @@ -809,17 +846,20 @@ public class IndexWriter { /** Returns the Directory used by this index. */ public Directory getDirectory() { - return directory; + ensureOpen(); + return directory; } /** Returns the analyzer used by this index. */ public Analyzer getAnalyzer() { - return analyzer; + ensureOpen(); + return analyzer; } /** Returns the number of documents currently in this index. */ public synchronized int docCount() { + ensureOpen(); int count = ramSegmentInfos.size(); for (int i = 0; i < segmentInfos.size(); i++) { SegmentInfo si = segmentInfos.info(i); @@ -897,6 +937,7 @@ public class IndexWriter { * @throws IOException if there is a low-level IO error */ public void addDocument(Document doc, Analyzer analyzer) throws CorruptIndexException, IOException { + ensureOpen(); SegmentInfo newSegmentInfo = buildSingleDocSegment(doc, analyzer); synchronized (this) { ramSegmentInfos.addElement(newSegmentInfo); @@ -922,6 +963,7 @@ public class IndexWriter { * @throws IOException if there is a low-level IO error */ public synchronized void deleteDocuments(Term term) throws CorruptIndexException, IOException { + ensureOpen(); bufferDeleteTerm(term); maybeFlushRamSegments(); } @@ -935,6 +977,7 @@ public class IndexWriter { * @throws IOException if there is a low-level IO error */ public synchronized void deleteDocuments(Term[] terms) throws CorruptIndexException, IOException { + ensureOpen(); for (int i = 0; i < terms.length; i++) { bufferDeleteTerm(terms[i]); } @@ -954,6 +997,7 @@ public class IndexWriter { * @throws IOException if there is a low-level IO error */ public void updateDocument(Term term, Document doc) throws CorruptIndexException, IOException { + ensureOpen(); updateDocument(term, doc, getAnalyzer()); } @@ -972,6 +1016,7 @@ public class IndexWriter { */ public void updateDocument(Term term, Document doc, Analyzer analyzer) throws CorruptIndexException, IOException { + ensureOpen(); SegmentInfo newSegmentInfo = buildSingleDocSegment(doc, analyzer); synchronized (this) { bufferDeleteTerm(term); @@ -1107,6 +1152,7 @@ public class IndexWriter { * @throws IOException if there is a low-level IO error */ public synchronized void optimize() throws CorruptIndexException, IOException { + ensureOpen(); flushRamSegments(); while (segmentInfos.size() > 1 || (segmentInfos.size() == 1 && @@ -1200,6 +1246,7 @@ public class IndexWriter { * @throws IOException if there is a low-level IO error */ public void abort() throws IOException { + ensureOpen(); if (!autoCommit) { // Keep the same segmentInfos instance but replace all @@ -1290,6 +1337,7 @@ public class IndexWriter { public synchronized void addIndexes(Directory[] dirs) throws CorruptIndexException, IOException { + ensureOpen(); optimize(); // start with zero or 1 seg int start = segmentInfos.size(); @@ -1375,6 +1423,7 @@ public class IndexWriter { // 1 flush ram segments + ensureOpen(); flushRamSegments(); // 2 copy segment infos and find the highest level from dirs @@ -1479,6 +1528,7 @@ public class IndexWriter { public synchronized void addIndexes(IndexReader[] readers) throws CorruptIndexException, IOException { + ensureOpen(); optimize(); // start with zero or 1 seg final String mergedName = newSegmentName(); @@ -1610,6 +1660,7 @@ public class IndexWriter { * @throws IOException if there is a low-level IO error */ public final synchronized void flush() throws CorruptIndexException, IOException { + ensureOpen(); flushRamSegments(); } @@ -1617,6 +1668,7 @@ public class IndexWriter { * Useful for size management with flushRamDocs() */ public final long ramSizeInBytes() { + ensureOpen(); return ramDirectory.sizeInBytes(); } @@ -1624,6 +1676,7 @@ public class IndexWriter { * Useful when calling flushRamSegments() */ public final synchronized int numRamDocs() { + ensureOpen(); return ramSegmentInfos.size(); } diff --git a/src/java/org/apache/lucene/index/MultiReader.java b/src/java/org/apache/lucene/index/MultiReader.java index d5c8b1e8d5b..c936cad7022 100644 --- a/src/java/org/apache/lucene/index/MultiReader.java +++ b/src/java/org/apache/lucene/index/MultiReader.java @@ -72,24 +72,21 @@ public class MultiReader extends IndexReader { } - /** Return an array of term frequency vectors for the specified document. - * The array contains a vector for each vectorized field in the document. - * Each vector vector contains term numbers and frequencies for all terms - * in a given vectorized field. - * If no such fields existed, the method returns null. - */ public TermFreqVector[] getTermFreqVectors(int n) throws IOException { + ensureOpen(); int i = readerIndex(n); // find segment num return subReaders[i].getTermFreqVectors(n - starts[i]); // dispatch to segment } public TermFreqVector getTermFreqVector(int n, String field) throws IOException { + ensureOpen(); int i = readerIndex(n); // find segment num return subReaders[i].getTermFreqVector(n - starts[i], field); } public synchronized int numDocs() { + // Don't call ensureOpen() here (it could affect performance) if (numDocs == -1) { // check cache int n = 0; // cache miss--recompute for (int i = 0; i < subReaders.length; i++) @@ -100,21 +97,27 @@ public class MultiReader extends IndexReader { } public int maxDoc() { + // Don't call ensureOpen() here (it could affect performance) return maxDoc; } // inherit javadoc public Document document(int n, FieldSelector fieldSelector) throws CorruptIndexException, IOException { + ensureOpen(); int i = readerIndex(n); // find segment num return subReaders[i].document(n - starts[i], fieldSelector); // dispatch to segment reader } public boolean isDeleted(int n) { + // Don't call ensureOpen() here (it could affect performance) int i = readerIndex(n); // find segment num return subReaders[i].isDeleted(n - starts[i]); // dispatch to segment reader } - public boolean hasDeletions() { return hasDeletions; } + public boolean hasDeletions() { + // Don't call ensureOpen() here (it could affect performance) + return hasDeletions; + } protected void doDelete(int n) throws CorruptIndexException, IOException { numDocs = -1; // invalidate cache @@ -153,6 +156,7 @@ public class MultiReader extends IndexReader { } public boolean hasNorms(String field) throws IOException { + ensureOpen(); for (int i = 0; i < subReaders.length; i++) { if (subReaders[i].hasNorms(field)) return true; } @@ -166,6 +170,7 @@ public class MultiReader extends IndexReader { } public synchronized byte[] norms(String field) throws IOException { + ensureOpen(); byte[] bytes = (byte[])normsCache.get(field); if (bytes != null) return bytes; // cache hit @@ -181,6 +186,7 @@ public class MultiReader extends IndexReader { public synchronized void norms(String field, byte[] result, int offset) throws IOException { + ensureOpen(); byte[] bytes = (byte[])normsCache.get(field); if (bytes==null && !hasNorms(field)) bytes=fakeNorms(); if (bytes != null) // cache hit @@ -198,14 +204,17 @@ public class MultiReader extends IndexReader { } public TermEnum terms() throws IOException { + ensureOpen(); return new MultiTermEnum(subReaders, starts, null); } public TermEnum terms(Term term) throws IOException { + ensureOpen(); return new MultiTermEnum(subReaders, starts, term); } public int docFreq(Term t) throws IOException { + ensureOpen(); int total = 0; // sum freqs in segments for (int i = 0; i < subReaders.length; i++) total += subReaders[i].docFreq(t); @@ -213,10 +222,12 @@ public class MultiReader extends IndexReader { } public TermDocs termDocs() throws IOException { + ensureOpen(); return new MultiTermDocs(subReaders, starts); } public TermPositions termPositions() throws IOException { + ensureOpen(); return new MultiTermPositions(subReaders, starts); } @@ -244,11 +255,9 @@ public class MultiReader extends IndexReader { subReaders[i].close(); } - /** - * @see IndexReader#getFieldNames(IndexReader.FieldOption) - */ public Collection getFieldNames (IndexReader.FieldOption fieldNames) { // maintain a unique set of field names + ensureOpen(); Set fieldSet = new HashSet(); for (int i = 0; i < subReaders.length; i++) { IndexReader reader = subReaders[i]; diff --git a/src/java/org/apache/lucene/index/ParallelReader.java b/src/java/org/apache/lucene/index/ParallelReader.java index bfc6d73dca8..b0497bd3f87 100644 --- a/src/java/org/apache/lucene/index/ParallelReader.java +++ b/src/java/org/apache/lucene/index/ParallelReader.java @@ -66,8 +66,11 @@ public class ParallelReader extends IndexReader { /** Construct a ParallelReader. */ public ParallelReader() throws IOException { super(null); } - /** Add an IndexReader. */ + /** Add an IndexReader. + * @throws IOException if there is a low-level IO error + */ public void add(IndexReader reader) throws IOException { + ensureOpen(); add(reader, false); } @@ -79,10 +82,12 @@ public class ParallelReader extends IndexReader { * of documents * @throws IllegalArgumentException if not all indexes have the same value * of {@link IndexReader#maxDoc()} + * @throws IOException if there is a low-level IO error */ public void add(IndexReader reader, boolean ignoreStoredFields) throws IOException { + ensureOpen(); if (readers.size() == 0) { this.maxDoc = reader.maxDoc(); this.numDocs = reader.numDocs(); @@ -110,14 +115,24 @@ public class ParallelReader extends IndexReader { readers.add(reader); } - public int numDocs() { return numDocs; } + public int numDocs() { + // Don't call ensureOpen() here (it could affect performance) + return numDocs; + } - public int maxDoc() { return maxDoc; } + public int maxDoc() { + // Don't call ensureOpen() here (it could affect performance) + return maxDoc; + } - public boolean hasDeletions() { return hasDeletions; } + public boolean hasDeletions() { + // Don't call ensureOpen() here (it could affect performance) + return hasDeletions; + } // check first reader public boolean isDeleted(int n) { + // Don't call ensureOpen() here (it could affect performance) if (readers.size() > 0) return ((IndexReader)readers.get(0)).isDeleted(n); return false; @@ -141,6 +156,7 @@ public class ParallelReader extends IndexReader { // append fields from storedFieldReaders public Document document(int n, FieldSelector fieldSelector) throws CorruptIndexException, IOException { + ensureOpen(); Document result = new Document(); for (int i = 0; i < storedFieldReaders.size(); i++) { IndexReader reader = (IndexReader)storedFieldReaders.get(i); @@ -166,6 +182,7 @@ public class ParallelReader extends IndexReader { // get all vectors public TermFreqVector[] getTermFreqVectors(int n) throws IOException { + ensureOpen(); ArrayList results = new ArrayList(); Iterator i = fieldToReader.entrySet().iterator(); while (i.hasNext()) { @@ -182,22 +199,26 @@ public class ParallelReader extends IndexReader { public TermFreqVector getTermFreqVector(int n, String field) throws IOException { + ensureOpen(); IndexReader reader = ((IndexReader)fieldToReader.get(field)); return reader==null ? null : reader.getTermFreqVector(n, field); } public boolean hasNorms(String field) throws IOException { + ensureOpen(); IndexReader reader = ((IndexReader)fieldToReader.get(field)); return reader==null ? false : reader.hasNorms(field); } public byte[] norms(String field) throws IOException { + ensureOpen(); IndexReader reader = ((IndexReader)fieldToReader.get(field)); return reader==null ? null : reader.norms(field); } public void norms(String field, byte[] result, int offset) throws IOException { + ensureOpen(); IndexReader reader = ((IndexReader)fieldToReader.get(field)); if (reader!=null) reader.norms(field, result, offset); @@ -211,31 +232,38 @@ public class ParallelReader extends IndexReader { } public TermEnum terms() throws IOException { + ensureOpen(); return new ParallelTermEnum(); } public TermEnum terms(Term term) throws IOException { + ensureOpen(); return new ParallelTermEnum(term); } public int docFreq(Term term) throws IOException { + ensureOpen(); IndexReader reader = ((IndexReader)fieldToReader.get(term.field())); return reader==null ? 0 : reader.docFreq(term); } public TermDocs termDocs(Term term) throws IOException { + ensureOpen(); return new ParallelTermDocs(term); } public TermDocs termDocs() throws IOException { + ensureOpen(); return new ParallelTermDocs(); } public TermPositions termPositions(Term term) throws IOException { + ensureOpen(); return new ParallelTermPositions(term); } public TermPositions termPositions() throws IOException { + ensureOpen(); return new ParallelTermPositions(); } @@ -251,6 +279,7 @@ public class ParallelReader extends IndexReader { public Collection getFieldNames (IndexReader.FieldOption fieldNames) { + ensureOpen(); Set fieldSet = new HashSet(); for (int i = 0; i < readers.size(); i++) { IndexReader reader = ((IndexReader)readers.get(i)); diff --git a/src/java/org/apache/lucene/index/SegmentReader.java b/src/java/org/apache/lucene/index/SegmentReader.java index baca6a8bcde..c5cefd306ea 100644 --- a/src/java/org/apache/lucene/index/SegmentReader.java +++ b/src/java/org/apache/lucene/index/SegmentReader.java @@ -266,10 +266,12 @@ class SegmentReader extends IndexReader { } static boolean hasDeletions(SegmentInfo si) throws IOException { + // Don't call ensureOpen() here (it could affect performance) return si.hasDeletions(); } public boolean hasDeletions() { + // Don't call ensureOpen() here (it could affect performance) return deletedDocs != null; } @@ -300,10 +302,12 @@ class SegmentReader extends IndexReader { } public TermEnum terms() { + ensureOpen(); return tis.terms(); } public TermEnum terms(Term t) throws IOException { + ensureOpen(); return tis.terms(t); } @@ -312,6 +316,7 @@ class SegmentReader extends IndexReader { * @throws IOException if there is a low-level IO error */ public synchronized Document document(int n, FieldSelector fieldSelector) throws CorruptIndexException, IOException { + ensureOpen(); if (isDeleted(n)) throw new IllegalArgumentException ("attempt to access a deleted document"); @@ -323,14 +328,17 @@ class SegmentReader extends IndexReader { } public TermDocs termDocs() throws IOException { + ensureOpen(); return new SegmentTermDocs(this); } public TermPositions termPositions() throws IOException { + ensureOpen(); return new SegmentTermPositions(this); } public int docFreq(Term t) throws IOException { + ensureOpen(); TermInfo ti = tis.get(t); if (ti != null) return ti.docFreq; @@ -339,6 +347,7 @@ class SegmentReader extends IndexReader { } public int numDocs() { + // Don't call ensureOpen() here (it could affect performance) int n = maxDoc(); if (deletedDocs != null) n -= deletedDocs.count(); @@ -346,6 +355,7 @@ class SegmentReader extends IndexReader { } public int maxDoc() { + // Don't call ensureOpen() here (it could affect performance) return si.docCount; } @@ -353,6 +363,7 @@ class SegmentReader extends IndexReader { * @see IndexReader#getFieldNames(IndexReader.FieldOption fldOption) */ public Collection getFieldNames(IndexReader.FieldOption fieldOption) { + ensureOpen(); Set fieldSet = new HashSet(); for (int i = 0; i < fieldInfos.size(); i++) { @@ -394,6 +405,7 @@ class SegmentReader extends IndexReader { public synchronized boolean hasNorms(String field) { + ensureOpen(); return norms.containsKey(field); } @@ -426,6 +438,7 @@ class SegmentReader extends IndexReader { // returns fake norms if norms aren't available public synchronized byte[] norms(String field) throws IOException { + ensureOpen(); byte[] bytes = getNorms(field); if (bytes==null) bytes=fakeNorms(); return bytes; @@ -447,6 +460,7 @@ class SegmentReader extends IndexReader { public synchronized void norms(String field, byte[] bytes, int offset) throws IOException { + ensureOpen(); Norm norm = (Norm) norms.get(field); if (norm == null) { System.arraycopy(fakeNorms(), 0, bytes, offset, maxDoc()); @@ -537,6 +551,7 @@ class SegmentReader extends IndexReader { */ public TermFreqVector getTermFreqVector(int docNumber, String field) throws IOException { // Check if this field is invalid or has no stored term vector + ensureOpen(); FieldInfo fi = fieldInfos.fieldInfo(field); if (fi == null || !fi.storeTermVector || termVectorsReaderOrig == null) return null; @@ -557,6 +572,7 @@ class SegmentReader extends IndexReader { * @throws IOException */ public TermFreqVector[] getTermFreqVectors(int docNumber) throws IOException { + ensureOpen(); if (termVectorsReaderOrig == null) return null; diff --git a/src/java/org/apache/lucene/store/AlreadyClosedException.java b/src/java/org/apache/lucene/store/AlreadyClosedException.java new file mode 100644 index 00000000000..435b9ddf487 --- /dev/null +++ b/src/java/org/apache/lucene/store/AlreadyClosedException.java @@ -0,0 +1,28 @@ +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. + */ + +/** + * This exception is thrown when there is an attempt to + * access something that has already been closed. + */ +public class AlreadyClosedException extends IllegalStateException { + public AlreadyClosedException(String message) { + super(message); + } +} diff --git a/src/java/org/apache/lucene/store/RAMDirectory.java b/src/java/org/apache/lucene/store/RAMDirectory.java index 1c895656747..cd7ad1a6ce7 100644 --- a/src/java/org/apache/lucene/store/RAMDirectory.java +++ b/src/java/org/apache/lucene/store/RAMDirectory.java @@ -97,6 +97,7 @@ public class RAMDirectory extends Directory implements Serializable { /** Returns an array of strings, one for each file in the directory. */ public synchronized final String[] list() { + ensureOpen(); Set fileNames = fileMap.keySet(); String[] result = new String[fileNames.size()]; int i = 0; @@ -108,6 +109,7 @@ public class RAMDirectory extends Directory implements Serializable { /** Returns true iff the named file exists in this directory. */ public final boolean fileExists(String name) { + ensureOpen(); RAMFile file; synchronized (this) { file = (RAMFile)fileMap.get(name); @@ -119,6 +121,7 @@ public class RAMDirectory extends Directory implements Serializable { * @throws IOException if the file does not exist */ public final long fileModified(String name) throws IOException { + ensureOpen(); RAMFile file; synchronized (this) { file = (RAMFile)fileMap.get(name); @@ -132,6 +135,7 @@ public class RAMDirectory extends Directory implements Serializable { * @throws IOException if the file does not exist */ public void touchFile(String name) throws IOException { + ensureOpen(); RAMFile file; synchronized (this) { file = (RAMFile)fileMap.get(name); @@ -154,6 +158,7 @@ public class RAMDirectory extends Directory implements Serializable { * @throws IOException if the file does not exist */ public final long fileLength(String name) throws IOException { + ensureOpen(); RAMFile file; synchronized (this) { file = (RAMFile)fileMap.get(name); @@ -167,6 +172,7 @@ public class RAMDirectory extends Directory implements Serializable { * directory. This is currently quantized to * BufferedIndexOutput.BUFFER_SIZE. */ public synchronized final long sizeInBytes() { + ensureOpen(); return sizeInBytes; } @@ -174,6 +180,7 @@ public class RAMDirectory extends Directory implements Serializable { * @throws IOException if the file does not exist */ public synchronized void deleteFile(String name) throws IOException { + ensureOpen(); RAMFile file = (RAMFile)fileMap.get(name); if (file!=null) { fileMap.remove(name); @@ -188,6 +195,7 @@ public class RAMDirectory extends Directory implements Serializable { * @deprecated */ public synchronized final void renameFile(String from, String to) throws IOException { + ensureOpen(); RAMFile fromFile = (RAMFile)fileMap.get(from); if (fromFile==null) throw new FileNotFoundException(from); @@ -202,6 +210,7 @@ public class RAMDirectory extends Directory implements Serializable { /** Creates a new, empty file in the directory with the given name. Returns a stream writing this file. */ public IndexOutput createOutput(String name) { + ensureOpen(); RAMFile file = new RAMFile(this); synchronized (this) { RAMFile existing = (RAMFile)fileMap.get(name); @@ -216,6 +225,7 @@ public class RAMDirectory extends Directory implements Serializable { /** Returns a stream reading an existing file. */ public IndexInput openInput(String name) throws IOException { + ensureOpen(); RAMFile file; synchronized (this) { file = (RAMFile)fileMap.get(name); @@ -230,4 +240,12 @@ public class RAMDirectory extends Directory implements Serializable { fileMap = null; } + /** + * @throws AlreadyClosedException if this IndexReader is closed + */ + protected final void ensureOpen() throws AlreadyClosedException { + if (fileMap == null) { + throw new AlreadyClosedException("this RAMDirectory is closed"); + } + } } diff --git a/src/test/org/apache/lucene/index/TestFieldsReader.java b/src/test/org/apache/lucene/index/TestFieldsReader.java index 25ca4e74cb7..2d2e83c496c 100644 --- a/src/test/org/apache/lucene/index/TestFieldsReader.java +++ b/src/test/org/apache/lucene/index/TestFieldsReader.java @@ -23,6 +23,7 @@ import org.apache.lucene.document.*; import org.apache.lucene.search.Similarity; import org.apache.lucene.store.FSDirectory; import org.apache.lucene.store.RAMDirectory; +import org.apache.lucene.store.AlreadyClosedException; import org.apache.lucene.util._TestUtil; import java.io.File; @@ -133,6 +134,36 @@ public class TestFieldsReader extends TestCase { } } + public void testLazyFieldsAfterClose() throws Exception { + assertTrue(dir != null); + assertTrue(fieldInfos != null); + FieldsReader reader = new FieldsReader(dir, "test", fieldInfos); + assertTrue(reader != null); + assertTrue(reader.size() == 1); + Set loadFieldNames = new HashSet(); + loadFieldNames.add(DocHelper.TEXT_FIELD_1_KEY); + loadFieldNames.add(DocHelper.TEXT_FIELD_UTF1_KEY); + Set lazyFieldNames = new HashSet(); + lazyFieldNames.add(DocHelper.LARGE_LAZY_FIELD_KEY); + lazyFieldNames.add(DocHelper.LAZY_FIELD_KEY); + lazyFieldNames.add(DocHelper.LAZY_FIELD_BINARY_KEY); + lazyFieldNames.add(DocHelper.TEXT_FIELD_UTF2_KEY); + lazyFieldNames.add(DocHelper.COMPRESSED_TEXT_FIELD_2_KEY); + SetBasedFieldSelector fieldSelector = new SetBasedFieldSelector(loadFieldNames, lazyFieldNames); + Document doc = reader.doc(0, fieldSelector); + assertTrue("doc is null and it shouldn't be", doc != null); + Fieldable field = doc.getFieldable(DocHelper.LAZY_FIELD_KEY); + assertTrue("field is null and it shouldn't be", field != null); + assertTrue("field is not lazy and it should be", field.isLazy()); + reader.close(); + try { + String value = field.stringValue(); + fail("did not hit AlreadyClosedException as expected"); + } catch (AlreadyClosedException e) { + // expected + } + } + public void testLoadFirst() throws Exception { assertTrue(dir != null); assertTrue(fieldInfos != null); diff --git a/src/test/org/apache/lucene/index/TestIndexReader.java b/src/test/org/apache/lucene/index/TestIndexReader.java index 7a401cc82f8..b24f71c335e 100644 --- a/src/test/org/apache/lucene/index/TestIndexReader.java +++ b/src/test/org/apache/lucene/index/TestIndexReader.java @@ -26,6 +26,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.store.AlreadyClosedException; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.analysis.WhitespaceAnalyzer; import org.apache.lucene.document.Document; @@ -279,21 +280,21 @@ public class TestIndexReader extends TestCase try { reader.deleteDocument(4); fail("deleteDocument after close failed to throw IOException"); - } catch (IOException e) { + } catch (AlreadyClosedException e) { // expected } try { reader.setNorm(5, "aaa", 2.0f); fail("setNorm after close failed to throw IOException"); - } catch (IOException e) { + } catch (AlreadyClosedException e) { // expected } try { reader.undeleteAll(); fail("undeleteAll after close failed to throw IOException"); - } catch (IOException e) { + } catch (AlreadyClosedException e) { // expected } } diff --git a/src/test/org/apache/lucene/index/TestIndexWriter.java b/src/test/org/apache/lucene/index/TestIndexWriter.java index 341899489ba..11acacaa396 100644 --- a/src/test/org/apache/lucene/index/TestIndexWriter.java +++ b/src/test/org/apache/lucene/index/TestIndexWriter.java @@ -19,6 +19,7 @@ import org.apache.lucene.store.FSDirectory; import org.apache.lucene.store.RAMDirectory; import org.apache.lucene.store.IndexInput; import org.apache.lucene.store.IndexOutput; +import org.apache.lucene.store.AlreadyClosedException; import org.apache.lucene.store.MockRAMDirectory; import org.apache.lucene.store.LockFactory; @@ -724,6 +725,25 @@ public class TestIndexWriter extends TestCase } } + public void testChangesAfterClose() throws IOException { + Directory dir = new RAMDirectory(); + + IndexWriter writer = null; + + writer = new IndexWriter(dir, new WhitespaceAnalyzer(), true); + addDoc(writer); + + // close + writer.close(); + try { + addDoc(writer); + fail("did not hit AlreadyClosedException"); + } catch (AlreadyClosedException e) { + // expected + } + } + + // Simulate a corrupt index by removing one of the cfs // files and make sure we get an IOException trying to // open the index: