Index: lucene/core/src/test/org/apache/lucene/index/TestIndexWriter.java =================================================================== --- lucene/core/src/test/org/apache/lucene/index/TestIndexWriter.java (revision 1421596) +++ lucene/core/src/test/org/apache/lucene/index/TestIndexWriter.java (working copy) @@ -26,6 +26,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Random; import org.apache.lucene.analysis.*; import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; @@ -57,6 +58,7 @@ import org.apache.lucene.store.SimpleFSLockFactory; import org.apache.lucene.store.SingleInstanceLockFactory; import org.apache.lucene.util.BytesRef; +import org.apache.lucene.util.IOUtils; import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.util.ThreadInterruptedException; import org.apache.lucene.util._TestUtil; @@ -1995,4 +1997,73 @@ dir.close(); } + public void testIterableThrowsException() throws IOException { + Directory dir = newDirectory(); + IndexWriter w = new IndexWriter(dir, newIndexWriterConfig( + TEST_VERSION_CURRENT, new MockAnalyzer(random()))); + int iters = atLeast(100); + int docCount = 0; + for (int i = 0; i < iters; i++) { + List docs = new ArrayList(); + FieldType ft = new FieldType(TextField.TYPE_NOT_STORED); + + int numDocs = atLeast(4); + for (int j = 0; j < numDocs; j++) { + Document doc = new Document(); + doc.add(newField("foo", _TestUtil.randomSimpleString(random()), ft)); + docs.add(doc); + } + boolean success = false; + try { + w.addDocuments(new RandomFailingFieldIterable(docs, random())); + success = true; + } catch (RuntimeException e) { + assertEquals("boom", e.getMessage()); + } finally { + if (success) { + docCount += docs.size(); + } + } + } + DirectoryReader reader = w.getReader(); + assertEquals(docCount, reader.numDocs()); + IOUtils.close(reader, w, dir); + } + + private static class RandomFailingFieldIterable implements Iterable { + private final List docList; + private final Random random; + + public RandomFailingFieldIterable(List docList, Random random) { + this.docList = docList; + this.random = random; + } + + @Override + public Iterator iterator() { + final Iterator docIter = docList.iterator(); + return new Iterator() { + + @Override + public boolean hasNext() { + return docIter.hasNext(); + } + + @Override + public IndexDocument next() { + if (random.nextInt(5) == 0) { + throw new RuntimeException("boom"); + } + return docIter.next(); + } + + @Override + public void remove() {throw new UnsupportedOperationException();} + + + }; + } + + } + } Index: lucene/core/src/java/org/apache/lucene/index/DocumentsWriterPerThread.java =================================================================== --- lucene/core/src/java/org/apache/lucene/index/DocumentsWriterPerThread.java (revision 1421596) +++ lucene/core/src/java/org/apache/lucene/index/DocumentsWriterPerThread.java (working copy) @@ -296,7 +296,9 @@ infoStream.message("DWPT", Thread.currentThread().getName() + " update delTerm=" + delTerm + " docID=" + docState.docID + " seg=" + segmentInfo.name); } int docCount = 0; + boolean allDocsIndexed = false; try { + for(IndexDocument doc : docs) { docState.doc = doc; docState.docID = numDocsInRAM; @@ -343,6 +345,7 @@ finishDocument(null); } + allDocsIndexed = true; // Apply delTerm only after all indexing has // succeeded, but apply it only to docs prior to when @@ -354,6 +357,16 @@ } } finally { + if (!allDocsIndexed && !aborting) { + // the iterator threw an exception that is not aborting + // go and mark all docs from this block as deleted + int docID = numDocsInRAM-1; + final int endDocID = docID - docCount; + while (docID > endDocID) { + deleteDocID(docID); + docID--; + } + } docState.clear(); }