You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-commits@lucene.apache.org by mi...@apache.org on 2009/02/22 13:20:27 UTC
svn commit: r746661 - in /lucene/java/trunk: CHANGES.txt
src/java/org/apache/lucene/index/IndexWriter.java
src/test/org/apache/lucene/index/TestIndexWriter.java
Author: mikemccand
Date: Sun Feb 22 12:20:27 2009
New Revision: 746661
URL: http://svn.apache.org/viewvc?rev=746661&view=rev
Log:
LUCENE-1544: fix deadlock in IW.addIndexes(IndexReader[])
Modified:
lucene/java/trunk/CHANGES.txt
lucene/java/trunk/src/java/org/apache/lucene/index/IndexWriter.java
lucene/java/trunk/src/test/org/apache/lucene/index/TestIndexWriter.java
Modified: lucene/java/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/java/trunk/CHANGES.txt?rev=746661&r1=746660&r2=746661&view=diff
==============================================================================
--- lucene/java/trunk/CHANGES.txt (original)
+++ lucene/java/trunk/CHANGES.txt Sun Feb 22 12:20:27 2009
@@ -73,6 +73,9 @@
happen if you use IndexReader.open with a File or String argument.
(Mark Miller via Mike McCandless)
+5. LUCENE-1544: Fix deadlock in IndexWriter.addIndexes(IndexReader[]).
+ (Mike McCandless via Doug Sale)
+
New features
1. LUCENE-1411: Added expert API to open an IndexWriter on a prior
Modified: lucene/java/trunk/src/java/org/apache/lucene/index/IndexWriter.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/index/IndexWriter.java?rev=746661&r1=746660&r2=746661&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/index/IndexWriter.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/index/IndexWriter.java Sun Feb 22 12:20:27 2009
@@ -367,8 +367,10 @@
// TODO: use ReadWriteLock once we are on 5.0
private int readCount; // count of how many threads are holding read lock
private Thread writeThread; // non-null if any thread holds write lock
-
+ private int upgradeCount;
+
synchronized void acquireWrite() {
+ assert writeThread != Thread.currentThread();
while(writeThread != null || readCount > 0)
doWait();
@@ -392,11 +394,25 @@
readCount++;
}
+ // Allows one readLock to upgrade to a writeLock even if
+ // there are other readLocks as long as all other
+ // readLocks are also blocked in this method:
+ synchronized void upgradeReadToWrite() {
+ assert readCount > 0;
+ upgradeCount++;
+ while(readCount > upgradeCount || writeThread != null) {
+ doWait();
+ }
+
+ writeThread = Thread.currentThread();
+ readCount--;
+ upgradeCount--;
+ }
+
synchronized void releaseRead() {
readCount--;
assert readCount >= 0;
- if (0 == readCount)
- notifyAll();
+ notifyAll();
}
/**
@@ -2680,7 +2696,7 @@
* within the transactions, so they must be flushed before the
* transaction is started.
*/
- private synchronized void startTransaction(boolean haveWriteLock) throws IOException {
+ private synchronized void startTransaction(boolean haveReadLock) throws IOException {
boolean success = false;
try {
@@ -2705,12 +2721,15 @@
} finally {
// Release the write lock if our caller held it, on
// hitting an exception
- if (!success && haveWriteLock)
- releaseWrite();
+ if (!success && haveReadLock)
+ releaseRead();
}
- if (!haveWriteLock)
+ if (haveReadLock) {
+ upgradeReadToWrite();
+ } else {
acquireWrite();
+ }
success = false;
try {
@@ -3351,34 +3370,37 @@
// Do not allow add docs or deletes while we are running:
docWriter.pauseAllThreads();
- // We must pre-acquire the write lock here (and not in
- // startTransaction below) so that no other addIndexes
- // is allowed to start up after we have flushed &
- // optimized but before we then start our transaction.
- // This is because the merging below requires that only
- // one segment is present in the index:
- acquireWrite();
+ // We must pre-acquire a read lock here (and upgrade to
+ // write lock in startTransaction below) so that no
+ // other addIndexes is allowed to start up after we have
+ // flushed & optimized but before we then start our
+ // transaction. This is because the merging below
+ // requires that only one segment is present in the
+ // index:
+ acquireRead();
try {
- boolean success = false;
SegmentInfo info = null;
String mergedName = null;
SegmentMerger merger = null;
+ boolean success = false;
+
try {
flush(true, false, true);
optimize(); // start with zero or 1 seg
success = true;
} finally {
- // Take care to release the write lock if we hit an
+ // Take care to release the read lock if we hit an
// exception before starting the transaction
if (!success)
- releaseWrite();
+ releaseRead();
}
- // true means we already have write lock; if this call
- // hits an exception it will release the write lock:
+ // true means we already have a read lock; if this
+ // call hits an exception it will release the write
+ // lock:
startTransaction(true);
try {
Modified: lucene/java/trunk/src/test/org/apache/lucene/index/TestIndexWriter.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/test/org/apache/lucene/index/TestIndexWriter.java?rev=746661&r1=746660&r2=746661&view=diff
==============================================================================
--- lucene/java/trunk/src/test/org/apache/lucene/index/TestIndexWriter.java (original)
+++ lucene/java/trunk/src/test/org/apache/lucene/index/TestIndexWriter.java Sun Feb 22 12:20:27 2009
@@ -4283,4 +4283,38 @@
_TestUtil.rmDir(indexDir);
}
}
+
+ public void testDeadlock() throws Exception {
+ MockRAMDirectory dir = new MockRAMDirectory();
+ IndexWriter writer = new IndexWriter(dir, true, new WhitespaceAnalyzer());
+ writer.setMaxBufferedDocs(2);
+ Document doc = new Document();
+ doc.add(new Field("content", "aaa bbb ccc ddd eee fff ggg hhh iii", Field.Store.YES,
+ Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
+ writer.addDocument(doc);
+ writer.addDocument(doc);
+ writer.addDocument(doc);
+ writer.commit();
+ // index has 2 segments
+
+ MockRAMDirectory dir2 = new MockRAMDirectory();
+ IndexWriter writer2 = new IndexWriter(dir2, new WhitespaceAnalyzer(), IndexWriter.MaxFieldLength.LIMITED);
+ writer2.addDocument(doc);
+ writer2.close();
+
+ IndexReader r1 = IndexReader.open(dir2);
+ IndexReader r2 = (IndexReader) r1.clone();
+ writer.addIndexes(new IndexReader[] {r1, r2});
+ writer.close();
+
+ IndexReader r3 = IndexReader.open(dir);
+ assertEquals(5, r3.numDocs());
+ r3.close();
+
+ r1.close();
+ r2.close();
+
+ dir2.close();
+ dir.close();
+ }
}