LUCENE-3365: Create or Append mode determined before obtaining write lock

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1156053 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Simon Willnauer 2011-08-10 07:34:32 +00:00
parent 25e1cf93dc
commit 06ffbbdc1e
3 changed files with 83 additions and 7 deletions

View File

@ -551,7 +551,11 @@ Bug fixes
* LUCENE-3348: Fix thread safety hazards in IndexWriter that could
rarely cause deletions to be incorrectly applied. (Yonik Seeley,
Simon Willnauer, Mike McCandless)
* LUCENE-3365: Create or Append mode determined before obtaining write lock
can cause IndexWriter overriding an existing index.
(Geoff Cooney via Simon Willnauer)
New Features
* LUCENE-3290: Added FieldInvertState.numUniqueTerms

View File

@ -835,6 +835,11 @@ public class IndexWriter implements Closeable, TwoPhaseCommit {
bufferedDeletesStream.setInfoStream(infoStream);
poolReaders = conf.getReaderPooling();
writeLock = directory.makeLock(WRITE_LOCK_NAME);
if (!writeLock.obtain(conf.getWriteLockTimeout())) // obtain write lock
throw new LockObtainFailedException("Index locked for write: " + writeLock);
OpenMode mode = conf.getOpenMode();
boolean create;
if (mode == OpenMode.CREATE) {
@ -845,12 +850,6 @@ public class IndexWriter implements Closeable, TwoPhaseCommit {
// CREATE_OR_APPEND - create only if an index does not exist
create = !IndexReader.indexExists(directory);
}
writeLock = directory.makeLock(WRITE_LOCK_NAME);
if (!writeLock.obtain(conf.getWriteLockTimeout())) // obtain write lock
throw new LockObtainFailedException("Index locked for write: " + writeLock);
boolean success = false;
// If index is too old, reading the segments will throw

View File

@ -18,6 +18,7 @@ package org.apache.lucene.index;
*/
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import org.apache.lucene.analysis.MockAnalyzer;
import org.apache.lucene.document.Document;
@ -408,4 +409,76 @@ public class TestIndexWriterWithThreads extends LuceneTestCase {
public void testIOExceptionDuringWriteSegmentWithThreadsOnlyOnce() throws Exception {
_testMultipleThreadsFailure(new FailOnlyInWriteSegment(true));
}
// LUCENE-3365: Test adding two documents with the same field from two different IndexWriters
// that we attempt to open at the same time. As long as the first IndexWriter completes
// and closes before the second IndexWriter time's out trying to get the Lock,
// we should see both documents
public void testOpenTwoIndexWritersOnDifferentThreads() throws IOException, InterruptedException {
final MockDirectoryWrapper dir = newDirectory();
CountDownLatch oneIWConstructed = new CountDownLatch(1);
DelayedIndexAndCloseRunnable thread1 = new DelayedIndexAndCloseRunnable(
dir, oneIWConstructed);
DelayedIndexAndCloseRunnable thread2 = new DelayedIndexAndCloseRunnable(
dir, oneIWConstructed);
thread1.start();
thread2.start();
oneIWConstructed.await();
thread1.startIndexing();
thread2.startIndexing();
thread1.join();
thread2.join();
assertFalse("Failed due to: " + thread1.failure, thread1.failed);
assertFalse("Failed due to: " + thread2.failure, thread2.failed);
// now verify that we have two documents in the index
IndexReader reader = IndexReader.open(dir, true);
assertEquals("IndexReader should have one document per thread running", 2,
reader.numDocs());
reader.close();
dir.close();
}
static class DelayedIndexAndCloseRunnable extends Thread {
private final Directory dir;
boolean failed = false;
Throwable failure = null;
private final CountDownLatch startIndexing = new CountDownLatch(1);
private CountDownLatch iwConstructed;
public DelayedIndexAndCloseRunnable(Directory dir,
CountDownLatch iwConstructed) {
this.dir = dir;
this.iwConstructed = iwConstructed;
}
public void startIndexing() {
this.startIndexing.countDown();
}
@Override
public void run() {
try {
Document doc = new Document();
Field field = newField("field", "testData", Field.Store.YES,
Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS);
doc.add(field);
IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig(
TEST_VERSION_CURRENT, new MockAnalyzer(random)));
iwConstructed.countDown();
startIndexing.await();
writer.addDocument(doc);
writer.close();
} catch (Throwable e) {
failed = true;
failure = e;
failure.printStackTrace(System.out);
return;
}
}
}
}