mirror of https://github.com/apache/lucene.git
LUCENE-1611: fix case where OutOfMemoryException in IndexWriter could cause infinite merging to happen
git-svn-id: https://svn.apache.org/repos/asf/lucene/java/trunk@770414 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
9ba59706b0
commit
b58e470eb7
|
@ -150,6 +150,10 @@ Bug fixes
|
||||||
when loading documents from the index. (P Eger via Mike
|
when loading documents from the index. (P Eger via Mike
|
||||||
McCandless)
|
McCandless)
|
||||||
|
|
||||||
|
7. LUCENE-1611: Fix case where OutOfMemoryException in IndexWriter
|
||||||
|
could cause "infinite merging" to happen. (Christiaan Fluit via
|
||||||
|
Mike McCandless)
|
||||||
|
|
||||||
New features
|
New features
|
||||||
|
|
||||||
1. LUCENE-1411: Added expert API to open an IndexWriter on a prior
|
1. LUCENE-1411: Added expert API to open an IndexWriter on a prior
|
||||||
|
|
|
@ -2043,7 +2043,9 @@ public class IndexWriter {
|
||||||
|
|
||||||
// Only allow a new merge to be triggered if we are
|
// Only allow a new merge to be triggered if we are
|
||||||
// going to wait for merges:
|
// going to wait for merges:
|
||||||
flush(waitForMerges, true, true);
|
if (!hitOOM) {
|
||||||
|
flush(waitForMerges, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
if (waitForMerges)
|
if (waitForMerges)
|
||||||
// Give merge scheduler last chance to run, in case
|
// Give merge scheduler last chance to run, in case
|
||||||
|
@ -2059,7 +2061,9 @@ public class IndexWriter {
|
||||||
if (infoStream != null)
|
if (infoStream != null)
|
||||||
message("now call final commit()");
|
message("now call final commit()");
|
||||||
|
|
||||||
commit(0);
|
if (!hitOOM) {
|
||||||
|
commit(0);
|
||||||
|
}
|
||||||
|
|
||||||
if (infoStream != null)
|
if (infoStream != null)
|
||||||
message("at close: " + segString());
|
message("at close: " + segString());
|
||||||
|
@ -2081,8 +2085,7 @@ public class IndexWriter {
|
||||||
closed = true;
|
closed = true;
|
||||||
}
|
}
|
||||||
} catch (OutOfMemoryError oom) {
|
} catch (OutOfMemoryError oom) {
|
||||||
hitOOM = true;
|
handleOOM(oom, "closeInternal");
|
||||||
throw oom;
|
|
||||||
} finally {
|
} finally {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
closing = false;
|
closing = false;
|
||||||
|
@ -2356,8 +2359,7 @@ public class IndexWriter {
|
||||||
if (doFlush)
|
if (doFlush)
|
||||||
flush(true, false, false);
|
flush(true, false, false);
|
||||||
} catch (OutOfMemoryError oom) {
|
} catch (OutOfMemoryError oom) {
|
||||||
hitOOM = true;
|
handleOOM(oom, "addDocument");
|
||||||
throw oom;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2379,8 +2381,7 @@ public class IndexWriter {
|
||||||
if (doFlush)
|
if (doFlush)
|
||||||
flush(true, false, false);
|
flush(true, false, false);
|
||||||
} catch (OutOfMemoryError oom) {
|
} catch (OutOfMemoryError oom) {
|
||||||
hitOOM = true;
|
handleOOM(oom, "deleteDocuments(Term)");
|
||||||
throw oom;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2404,8 +2405,7 @@ public class IndexWriter {
|
||||||
if (doFlush)
|
if (doFlush)
|
||||||
flush(true, false, false);
|
flush(true, false, false);
|
||||||
} catch (OutOfMemoryError oom) {
|
} catch (OutOfMemoryError oom) {
|
||||||
hitOOM = true;
|
handleOOM(oom, "deleteDocuments(Term[])");
|
||||||
throw oom;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2514,8 +2514,7 @@ public class IndexWriter {
|
||||||
if (doFlush)
|
if (doFlush)
|
||||||
flush(true, false, false);
|
flush(true, false, false);
|
||||||
} catch (OutOfMemoryError oom) {
|
} catch (OutOfMemoryError oom) {
|
||||||
hitOOM = true;
|
handleOOM(oom, "updateDocument");
|
||||||
throw oom;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2708,6 +2707,11 @@ public class IndexWriter {
|
||||||
if (doWait) {
|
if (doWait) {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
while(true) {
|
while(true) {
|
||||||
|
|
||||||
|
if (hitOOM) {
|
||||||
|
throw new IllegalStateException("this writer hit an OutOfMemoryError; cannot complete optimize");
|
||||||
|
}
|
||||||
|
|
||||||
if (mergeExceptions.size() > 0) {
|
if (mergeExceptions.size() > 0) {
|
||||||
// Forward any exceptions in background merge
|
// Forward any exceptions in background merge
|
||||||
// threads to the current thread:
|
// threads to the current thread:
|
||||||
|
@ -2795,6 +2799,10 @@ public class IndexWriter {
|
||||||
boolean running = true;
|
boolean running = true;
|
||||||
while(running) {
|
while(running) {
|
||||||
|
|
||||||
|
if (hitOOM) {
|
||||||
|
throw new IllegalStateException("this writer hit an OutOfMemoryError; cannot complete expungeDeletes");
|
||||||
|
}
|
||||||
|
|
||||||
// Check each merge that MergePolicy asked us to
|
// Check each merge that MergePolicy asked us to
|
||||||
// do, to see if any of them are still running and
|
// do, to see if any of them are still running and
|
||||||
// if any of them have hit an exception.
|
// if any of them have hit an exception.
|
||||||
|
@ -2883,6 +2891,11 @@ public class IndexWriter {
|
||||||
if (stopMerges)
|
if (stopMerges)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Do not start new merges if we've hit OOME
|
||||||
|
if (hitOOM) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final MergePolicy.MergeSpecification spec;
|
final MergePolicy.MergeSpecification spec;
|
||||||
if (optimize) {
|
if (optimize) {
|
||||||
spec = mergePolicy.findMergesForOptimize(segmentInfos, this, maxNumSegmentsOptimize, segmentsToOptimize);
|
spec = mergePolicy.findMergesForOptimize(segmentInfos, this, maxNumSegmentsOptimize, segmentsToOptimize);
|
||||||
|
@ -3196,8 +3209,7 @@ public class IndexWriter {
|
||||||
|
|
||||||
success = true;
|
success = true;
|
||||||
} catch (OutOfMemoryError oom) {
|
} catch (OutOfMemoryError oom) {
|
||||||
hitOOM = true;
|
handleOOM(oom, "rollbackInternal");
|
||||||
throw oom;
|
|
||||||
} finally {
|
} finally {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
@ -3375,8 +3387,7 @@ public class IndexWriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (OutOfMemoryError oom) {
|
} catch (OutOfMemoryError oom) {
|
||||||
hitOOM = true;
|
handleOOM(oom, "addIndexes(Directory[])");
|
||||||
throw oom;
|
|
||||||
} finally {
|
} finally {
|
||||||
if (docWriter != null) {
|
if (docWriter != null) {
|
||||||
docWriter.resumeAllThreads();
|
docWriter.resumeAllThreads();
|
||||||
|
@ -3518,8 +3529,7 @@ public class IndexWriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (OutOfMemoryError oom) {
|
} catch (OutOfMemoryError oom) {
|
||||||
hitOOM = true;
|
handleOOM(oom, "addIndexesNoOptimize");
|
||||||
throw oom;
|
|
||||||
} finally {
|
} finally {
|
||||||
if (docWriter != null) {
|
if (docWriter != null) {
|
||||||
docWriter.resumeAllThreads();
|
docWriter.resumeAllThreads();
|
||||||
|
@ -3761,8 +3771,7 @@ public class IndexWriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (OutOfMemoryError oom) {
|
} catch (OutOfMemoryError oom) {
|
||||||
hitOOM = true;
|
handleOOM(oom, "addIndexes(IndexReader[])");
|
||||||
throw oom;
|
|
||||||
} finally {
|
} finally {
|
||||||
if (docWriter != null) {
|
if (docWriter != null) {
|
||||||
docWriter.resumeAllThreads();
|
docWriter.resumeAllThreads();
|
||||||
|
@ -3794,8 +3803,9 @@ public class IndexWriter {
|
||||||
* @throws IOException if there is a low-level IO error
|
* @throws IOException if there is a low-level IO error
|
||||||
*/
|
*/
|
||||||
public final void flush() throws CorruptIndexException, IOException {
|
public final void flush() throws CorruptIndexException, IOException {
|
||||||
if (hitOOM)
|
if (hitOOM) {
|
||||||
throw new IllegalStateException("this writer hit an OutOfMemoryError; cannot flush");
|
throw new IllegalStateException("this writer hit an OutOfMemoryError; cannot flush");
|
||||||
|
}
|
||||||
|
|
||||||
flush(true, false, true);
|
flush(true, false, true);
|
||||||
}
|
}
|
||||||
|
@ -3850,8 +3860,9 @@ public class IndexWriter {
|
||||||
|
|
||||||
private final void prepareCommit(String commitUserData, boolean internal) throws CorruptIndexException, IOException {
|
private final void prepareCommit(String commitUserData, boolean internal) throws CorruptIndexException, IOException {
|
||||||
|
|
||||||
if (hitOOM)
|
if (hitOOM) {
|
||||||
throw new IllegalStateException("this writer hit an OutOfMemoryError; cannot commit");
|
throw new IllegalStateException("this writer hit an OutOfMemoryError; cannot commit");
|
||||||
|
}
|
||||||
|
|
||||||
if (autoCommit && !internal)
|
if (autoCommit && !internal)
|
||||||
throw new IllegalStateException("this method can only be used when autoCommit is false");
|
throw new IllegalStateException("this method can only be used when autoCommit is false");
|
||||||
|
@ -3980,6 +3991,21 @@ public class IndexWriter {
|
||||||
// synchronized, ie, merges should be allowed to commit
|
// synchronized, ie, merges should be allowed to commit
|
||||||
// even while a flush is happening
|
// even while a flush is happening
|
||||||
private synchronized final boolean doFlush(boolean flushDocStores, boolean flushDeletes) throws CorruptIndexException, IOException {
|
private synchronized final boolean doFlush(boolean flushDocStores, boolean flushDeletes) throws CorruptIndexException, IOException {
|
||||||
|
try {
|
||||||
|
return doFlushInternal(flushDocStores, flushDeletes);
|
||||||
|
} finally {
|
||||||
|
docWriter.clearFlushPending();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: this method should not have to be entirely
|
||||||
|
// synchronized, ie, merges should be allowed to commit
|
||||||
|
// even while a flush is happening
|
||||||
|
private synchronized final boolean doFlushInternal(boolean flushDocStores, boolean flushDeletes) throws CorruptIndexException, IOException {
|
||||||
|
|
||||||
|
if (hitOOM) {
|
||||||
|
throw new IllegalStateException("this writer hit an OutOfMemoryError; cannot flush");
|
||||||
|
}
|
||||||
|
|
||||||
ensureOpen(false);
|
ensureOpen(false);
|
||||||
|
|
||||||
|
@ -4133,10 +4159,10 @@ public class IndexWriter {
|
||||||
return flushDocs;
|
return flushDocs;
|
||||||
|
|
||||||
} catch (OutOfMemoryError oom) {
|
} catch (OutOfMemoryError oom) {
|
||||||
hitOOM = true;
|
handleOOM(oom, "doFlush");
|
||||||
throw oom;
|
// never hit
|
||||||
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
docWriter.clearFlushPending();
|
|
||||||
docWriter.resumeAllThreads();
|
docWriter.resumeAllThreads();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4260,8 +4286,9 @@ public class IndexWriter {
|
||||||
|
|
||||||
assert testPoint("startCommitMerge");
|
assert testPoint("startCommitMerge");
|
||||||
|
|
||||||
if (hitOOM)
|
if (hitOOM) {
|
||||||
return false;
|
throw new IllegalStateException("this writer hit an OutOfMemoryError; cannot complete merge");
|
||||||
|
}
|
||||||
|
|
||||||
if (infoStream != null)
|
if (infoStream != null)
|
||||||
message("commitMerge: " + merge.segString(directory) + " index=" + segString());
|
message("commitMerge: " + merge.segString(directory) + " index=" + segString());
|
||||||
|
@ -4401,8 +4428,7 @@ public class IndexWriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (OutOfMemoryError oom) {
|
} catch (OutOfMemoryError oom) {
|
||||||
hitOOM = true;
|
handleOOM(oom, "merge");
|
||||||
throw oom;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4477,6 +4503,10 @@ public class IndexWriter {
|
||||||
assert merge.registerDone;
|
assert merge.registerDone;
|
||||||
assert !merge.optimize || merge.maxNumSegmentsOptimize > 0;
|
assert !merge.optimize || merge.maxNumSegmentsOptimize > 0;
|
||||||
|
|
||||||
|
if (hitOOM) {
|
||||||
|
throw new IllegalStateException("this writer hit an OutOfMemoryError; cannot merge");
|
||||||
|
}
|
||||||
|
|
||||||
if (merge.info != null)
|
if (merge.info != null)
|
||||||
// mergeInit already done
|
// mergeInit already done
|
||||||
return;
|
return;
|
||||||
|
@ -5095,8 +5125,9 @@ public class IndexWriter {
|
||||||
|
|
||||||
assert testPoint("startStartCommit");
|
assert testPoint("startStartCommit");
|
||||||
|
|
||||||
if (hitOOM)
|
if (hitOOM) {
|
||||||
return;
|
throw new IllegalStateException("this writer hit an OutOfMemoryError; cannot commit");
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
@ -5273,8 +5304,7 @@ public class IndexWriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (OutOfMemoryError oom) {
|
} catch (OutOfMemoryError oom) {
|
||||||
hitOOM = true;
|
handleOOM(oom, "startCommit");
|
||||||
throw oom;
|
|
||||||
}
|
}
|
||||||
assert testPoint("finishStartCommit");
|
assert testPoint("finishStartCommit");
|
||||||
}
|
}
|
||||||
|
@ -5397,6 +5427,14 @@ public class IndexWriter {
|
||||||
return mergedSegmentWarmer;
|
return mergedSegmentWarmer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleOOM(OutOfMemoryError oom, String location) {
|
||||||
|
if (infoStream != null) {
|
||||||
|
message("hit OutOfMemoryError inside " + location);
|
||||||
|
}
|
||||||
|
hitOOM = true;
|
||||||
|
throw oom;
|
||||||
|
}
|
||||||
|
|
||||||
// Used only by assert for testing. Current points:
|
// Used only by assert for testing. Current points:
|
||||||
// startDoFlush
|
// startDoFlush
|
||||||
// startCommitMerge
|
// startCommitMerge
|
||||||
|
|
Loading…
Reference in New Issue