lucene-java-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mikemcc...@apache.org
Subject svn commit: r746662 - in /lucene/java/branches/lucene_2_4: ./ CHANGES.txt src/java/org/apache/lucene/index/IndexWriter.java src/test/org/apache/lucene/index/TestIndexWriter.java
Date Sun, 22 Feb 2009 12:27:20 GMT
Author: mikemccand
Date: Sun Feb 22 12:27:19 2009
New Revision: 746662

URL: http://svn.apache.org/viewvc?rev=746662&view=rev
Log:
LUCENE-1544: fix deadlock in IW.addIndexes(IndexReader[])

Modified:
    lucene/java/branches/lucene_2_4/   (props changed)
    lucene/java/branches/lucene_2_4/CHANGES.txt
    lucene/java/branches/lucene_2_4/src/java/org/apache/lucene/index/IndexWriter.java
    lucene/java/branches/lucene_2_4/src/test/org/apache/lucene/index/TestIndexWriter.java

Propchange: lucene/java/branches/lucene_2_4/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Sun Feb 22 12:27:19 2009
@@ -1 +1 @@
-/lucene/java/trunk:708549,709456,712233,718540,719716,723149,734415,735043
+/lucene/java/trunk:708549,709456,712233,718540,719716,723149,734415,735043,746661

Modified: lucene/java/branches/lucene_2_4/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/java/branches/lucene_2_4/CHANGES.txt?rev=746662&r1=746661&r2=746662&view=diff
==============================================================================
--- lucene/java/branches/lucene_2_4/CHANGES.txt (original)
+++ lucene/java/branches/lucene_2_4/CHANGES.txt Sun Feb 22 12:27:19 2009
@@ -44,6 +44,8 @@
 10. LUCENE-1521: Fix int overflow bug when flushing segment.
     (Shon Vella via Mike McCandless).
 
+11. LUCENE-1544: Fix deadlock in IndexWriter.addIndexes(IndexReader[]).
+   (Mike McCandless via Doug Sale)
 
 ======================= Release 2.4.0 2008-10-06 =======================
 

Modified: lucene/java/branches/lucene_2_4/src/java/org/apache/lucene/index/IndexWriter.java
URL: http://svn.apache.org/viewvc/lucene/java/branches/lucene_2_4/src/java/org/apache/lucene/index/IndexWriter.java?rev=746662&r1=746661&r2=746662&view=diff
==============================================================================
--- lucene/java/branches/lucene_2_4/src/java/org/apache/lucene/index/IndexWriter.java (original)
+++ lucene/java/branches/lucene_2_4/src/java/org/apache/lucene/index/IndexWriter.java Sun
Feb 22 12:27:19 2009
@@ -353,8 +353,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();
 
@@ -378,11 +380,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();
   }
 
   /**
@@ -2480,7 +2496,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 {
@@ -2505,12 +2521,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 {
@@ -3144,34 +3163,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/branches/lucene_2_4/src/test/org/apache/lucene/index/TestIndexWriter.java
URL: http://svn.apache.org/viewvc/lucene/java/branches/lucene_2_4/src/test/org/apache/lucene/index/TestIndexWriter.java?rev=746662&r1=746661&r2=746662&view=diff
==============================================================================
--- lucene/java/branches/lucene_2_4/src/test/org/apache/lucene/index/TestIndexWriter.java
(original)
+++ lucene/java/branches/lucene_2_4/src/test/org/apache/lucene/index/TestIndexWriter.java
Sun Feb 22 12:27:19 2009
@@ -4190,4 +4190,38 @@
     r.close();
     dir.close();
   }
+
+  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.open(dir2);
+    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();
+  }
 }



Mime
View raw message