LUCENE-1547: fix rare thread hazard in IndexWriter.commit()

git-svn-id: https://svn.apache.org/repos/asf/lucene/java/trunk@747251 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Michael McCandless 2009-02-24 01:30:35 +00:00
parent 90d98045d8
commit 6fc659a345
1 changed files with 50 additions and 67 deletions

View File

@ -3610,20 +3610,6 @@ public class IndexWriter {
finishCommit(); finishCommit();
} }
private boolean committing;
synchronized private void waitForCommit() {
// Only allow a single thread to do the commit, at a time:
while(committing)
doWait();
committing = true;
}
synchronized private void doneCommit() {
committing = false;
notifyAll();
}
/** /**
* <p>Commits all pending updates (added & deleted * <p>Commits all pending updates (added & deleted
* documents) to the index, and syncs all referenced index * documents) to the index, and syncs all referenced index
@ -3670,24 +3656,17 @@ public class IndexWriter {
ensureOpen(); ensureOpen();
// Only let one thread do the prepare/finish at a time if (infoStream != null)
waitForCommit(); message("commit: start");
try { if (autoCommit || pendingCommit == null) {
if (infoStream != null) if (infoStream != null)
message("commit: start"); message("commit: now prepare");
prepareCommit(commitUserData, true);
} else if (infoStream != null)
message("commit: already prepared");
if (autoCommit || pendingCommit == null) { finishCommit();
if (infoStream != null)
message("commit: now prepare");
prepareCommit(commitUserData, true);
} else if (infoStream != null)
message("commit: already prepared");
finishCommit();
} finally {
doneCommit();
}
} }
private synchronized final void finishCommit() throws CorruptIndexException, IOException { private synchronized final void finishCommit() throws CorruptIndexException, IOException {
@ -3745,8 +3724,6 @@ public class IndexWriter {
flushCount++; flushCount++;
// Make sure no threads are actively adding a document
flushDeletes |= docWriter.deletesFull(); flushDeletes |= docWriter.deletesFull();
// When autoCommit=true we must always flush deletes // When autoCommit=true we must always flush deletes
@ -3755,6 +3732,7 @@ public class IndexWriter {
// from an updateDocument call // from an updateDocument call
flushDeletes |= autoCommit; flushDeletes |= autoCommit;
// Make sure no threads are actively adding a document.
// Returns true if docWriter is currently aborting, in // Returns true if docWriter is currently aborting, in
// which case we skip flushing this segment // which case we skip flushing this segment
if (docWriter.pauseAllThreads()) { if (docWriter.pauseAllThreads()) {
@ -4891,45 +4869,50 @@ public class IndexWriter {
// since I first started syncing my version, I can // since I first started syncing my version, I can
// safely skip saving myself since I've been // safely skip saving myself since I've been
// superseded: // superseded:
if (myChangeCount > lastCommitChangeCount && (pendingCommit == null || myChangeCount > pendingCommitChangeCount)) {
// Wait now for any current pending commit to complete: while(true) {
while(pendingCommit != null) { if (myChangeCount <= lastCommitChangeCount) {
if (infoStream != null) if (infoStream != null) {
message("wait for existing pendingCommit to finish..."); message("sync superseded by newer infos");
}
break;
} else if (pendingCommit == null) {
// My turn to commit
if (segmentInfos.getGeneration() > toSync.getGeneration())
toSync.updateGeneration(segmentInfos);
boolean success = false;
try {
// Exception here means nothing is prepared
// (this method unwinds everything it did on
// an exception)
try {
toSync.prepareCommit(directory);
} finally {
// Have our master segmentInfos record the
// generations we just prepared. We do this
// on error or success so we don't
// double-write a segments_N file.
segmentInfos.updateGeneration(toSync);
}
assert pendingCommit == null;
setPending = true;
pendingCommit = toSync;
pendingCommitChangeCount = myChangeCount;
success = true;
} finally {
if (!success && infoStream != null)
message("hit exception committing segments file");
}
break;
} else {
// Must wait for other commit to complete
doWait(); doWait();
} }
}
if (segmentInfos.getGeneration() > toSync.getGeneration())
toSync.updateGeneration(segmentInfos);
boolean success = false;
try {
// Exception here means nothing is prepared
// (this method unwinds everything it did on
// an exception)
try {
toSync.prepareCommit(directory);
} finally {
// Have our master segmentInfos record the
// generations we just prepared. We do this
// on error or success so we don't
// double-write a segments_N file.
segmentInfos.updateGeneration(toSync);
}
assert pendingCommit == null;
setPending = true;
pendingCommit = toSync;
pendingCommitChangeCount = myChangeCount;
success = true;
} finally {
if (!success && infoStream != null)
message("hit exception committing segments file");
}
} else if (infoStream != null)
message("sync superseded by newer infos");
} }
if (infoStream != null) if (infoStream != null)