pylucene 3.5.0-3
[pylucene.git] / lucene-java-3.5.0 / lucene / backwards / src / test / org / apache / lucene / index / TestIndexWriter.java
diff --git a/lucene-java-3.5.0/lucene/backwards/src/test/org/apache/lucene/index/TestIndexWriter.java b/lucene-java-3.5.0/lucene/backwards/src/test/org/apache/lucene/index/TestIndexWriter.java
new file mode 100644 (file)
index 0000000..6138622
--- /dev/null
@@ -0,0 +1,1941 @@
+package org.apache.lucene.index;
+
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Collections;
+
+import org.apache.lucene.util.LuceneTestCase;
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.MockAnalyzer;
+import org.apache.lucene.analysis.TokenStream;
+import org.apache.lucene.analysis.Tokenizer;
+import org.apache.lucene.analysis.WhitespaceAnalyzer;
+import org.apache.lucene.analysis.WhitespaceTokenizer;
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
+import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.document.Fieldable;
+import org.apache.lucene.document.Field.Index;
+import org.apache.lucene.document.Field.Store;
+import org.apache.lucene.document.Field.TermVector;
+import org.apache.lucene.index.IndexWriterConfig.OpenMode;
+import org.apache.lucene.search.TopDocs;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.PhraseQuery;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.ScoreDoc;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.search.spans.SpanTermQuery;
+import org.apache.lucene.store.AlreadyClosedException;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.IndexOutput;
+import org.apache.lucene.store.Lock;
+import org.apache.lucene.store.LockFactory;
+import org.apache.lucene.store.NoLockFactory;
+import org.apache.lucene.store.MockDirectoryWrapper;
+import org.apache.lucene.store.RAMDirectory;
+import org.apache.lucene.store.SingleInstanceLockFactory;
+import org.apache.lucene.util._TestUtil;
+import org.apache.lucene.util.ThreadInterruptedException;
+
+public class TestIndexWriter extends LuceneTestCase {
+
+    public void testDocCount() throws IOException {
+        Directory dir = newDirectory();
+
+        IndexWriter writer = null;
+        IndexReader reader = null;
+        int i;
+
+        long savedWriteLockTimeout = IndexWriterConfig.getDefaultWriteLockTimeout();
+        try {
+          IndexWriterConfig.setDefaultWriteLockTimeout(2000);
+          assertEquals(2000, IndexWriterConfig.getDefaultWriteLockTimeout());
+          writer  = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
+        } finally {
+          IndexWriterConfig.setDefaultWriteLockTimeout(savedWriteLockTimeout);
+        }
+
+        // add 100 documents
+        for (i = 0; i < 100; i++) {
+            addDoc(writer);
+        }
+        assertEquals(100, writer.maxDoc());
+        writer.close();
+
+        // delete 40 documents
+        reader = IndexReader.open(dir, false);
+        for (i = 0; i < 40; i++) {
+            reader.deleteDocument(i);
+        }
+        reader.close();
+
+        reader = IndexReader.open(dir, true);
+        assertEquals(60, reader.numDocs());
+        reader.close();
+
+        // optimize the index and check that the new doc count is correct
+        writer = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
+        assertEquals(60, writer.numDocs());
+        writer.optimize();
+        assertEquals(60, writer.maxDoc());
+        assertEquals(60, writer.numDocs());
+        writer.close();
+
+        // check that the index reader gives the same numbers.
+        reader = IndexReader.open(dir, true);
+        assertEquals(60, reader.maxDoc());
+        assertEquals(60, reader.numDocs());
+        reader.close();
+
+        // make sure opening a new index for create over
+        // this existing one works correctly:
+        writer = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)).setOpenMode(OpenMode.CREATE));
+        assertEquals(0, writer.maxDoc());
+        assertEquals(0, writer.numDocs());
+        writer.close();
+        dir.close();
+    }
+
+    static void addDoc(IndexWriter writer) throws IOException
+    {
+        Document doc = new Document();
+        doc.add(newField("content", "aaa", Field.Store.NO, Field.Index.ANALYZED));
+        writer.addDocument(doc);
+    }
+
+    static void addDocWithIndex(IndexWriter writer, int index) throws IOException
+    {
+        Document doc = new Document();
+        doc.add(newField("content", "aaa " + index, Field.Store.YES, Field.Index.ANALYZED));
+        doc.add(newField("id", "" + index, Field.Store.YES, Field.Index.ANALYZED));
+        writer.addDocument(doc);
+    }                            
+
+    public static void assertNoUnreferencedFiles(Directory dir, String message) throws IOException {
+      String[] startFiles = dir.listAll();
+      SegmentInfos infos = new SegmentInfos();
+      infos.read(dir);
+      new IndexWriter(dir, new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random))).rollback();
+      String[] endFiles = dir.listAll();
+
+      Arrays.sort(startFiles);
+      Arrays.sort(endFiles);
+
+      if (!Arrays.equals(startFiles, endFiles)) {
+        fail(message + ": before delete:\n    " + arrayToString(startFiles) + "\n  after delete:\n    " + arrayToString(endFiles));
+      }
+    }
+
+    /**
+     * Make sure we skip wicked long terms.
+    */
+    public void testWickedLongTerm() throws IOException {
+      MockDirectoryWrapper dir = newDirectory();
+      IndexWriter writer = new IndexWriter(dir, new IndexWriterConfig(
+        TEST_VERSION_CURRENT, new StandardAnalyzer(TEST_VERSION_CURRENT)));
+
+      char[] chars = new char[DocumentsWriter.CHAR_BLOCK_SIZE-1];
+      Arrays.fill(chars, 'x');
+      Document doc = new Document();
+      final String bigTerm = new String(chars);
+
+      // Max length term is 16383, so this contents produces
+      // a too-long term:
+      String contents = "abc xyz x" + bigTerm + " another term";
+      doc.add(new Field("content", contents, Field.Store.NO, Field.Index.ANALYZED));
+      writer.addDocument(doc);
+
+      // Make sure we can add another normal document
+      doc = new Document();
+      doc.add(new Field("content", "abc bbb ccc", Field.Store.NO, Field.Index.ANALYZED));
+      writer.addDocument(doc);
+      writer.close();
+
+      IndexReader reader = IndexReader.open(dir, true);
+
+      // Make sure all terms < max size were indexed
+      assertEquals(2, reader.docFreq(new Term("content", "abc")));
+      assertEquals(1, reader.docFreq(new Term("content", "bbb")));
+      assertEquals(1, reader.docFreq(new Term("content", "term")));
+      assertEquals(1, reader.docFreq(new Term("content", "another")));
+
+      // Make sure position is still incremented when
+      // massive term is skipped:
+      TermPositions tps = reader.termPositions(new Term("content", "another"));
+      assertTrue(tps.next());
+      assertEquals(1, tps.freq());
+      assertEquals(3, tps.nextPosition());
+
+      // Make sure the doc that has the massive term is in
+      // the index:
+      assertEquals("document with wicked long term should is not in the index!", 2, reader.numDocs());
+
+      reader.close();
+
+      // Make sure we can add a document with exactly the
+      // maximum length term, and search on that term:
+      doc = new Document();
+      doc.add(new Field("content", bigTerm, Field.Store.NO, Field.Index.ANALYZED));
+      StandardAnalyzer sa = new StandardAnalyzer(TEST_VERSION_CURRENT);
+      sa.setMaxTokenLength(100000);
+      writer  = new IndexWriter(dir, new IndexWriterConfig(TEST_VERSION_CURRENT, sa));
+      writer.addDocument(doc);
+      writer.close();
+      reader = IndexReader.open(dir, true);
+      assertEquals(1, reader.docFreq(new Term("content", bigTerm)));
+      reader.close();
+
+      dir.close();
+    }
+
+    static String arrayToString(String[] l) {
+      String s = "";
+      for(int i=0;i<l.length;i++) {
+        if (i > 0) {
+          s += "\n    ";
+        }
+        s += l[i];
+      }
+      return s;
+    }
+
+    // Make sure we can open an index for create even when a
+    // reader holds it open (this fails pre lock-less
+    // commits on windows):
+    public void testCreateWithReader() throws IOException {
+      Directory dir = newDirectory();
+      
+      // add one document & close writer
+      IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
+      addDoc(writer);
+      writer.close();
+      
+      // now open reader:
+      IndexReader reader = IndexReader.open(dir, true);
+      assertEquals("should be one document", reader.numDocs(), 1);
+      
+      // now open index for create:
+      writer = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)).setOpenMode(OpenMode.CREATE));
+      assertEquals("should be zero documents", writer.maxDoc(), 0);
+      addDoc(writer);
+      writer.close();
+      
+      assertEquals("should be one document", reader.numDocs(), 1);
+      IndexReader reader2 = IndexReader.open(dir, true);
+      assertEquals("should be one document", reader2.numDocs(), 1);
+      reader.close();
+      reader2.close();
+      
+      dir.close();
+    }
+
+    public void testChangesAfterClose() throws IOException {
+        Directory dir = newDirectory();
+
+        IndexWriter writer = null;
+
+        writer  = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
+        addDoc(writer);
+
+        // close
+        writer.close();
+        try {
+          addDoc(writer);
+          fail("did not hit AlreadyClosedException");
+        } catch (AlreadyClosedException e) {
+          // expected
+        }
+        dir.close();
+    }
+
+    public void testIndexNoDocuments() throws IOException {
+      MockDirectoryWrapper dir = newDirectory();      
+      IndexWriter writer  = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
+      writer.commit();
+      writer.close();
+
+      IndexReader reader = IndexReader.open(dir, true);
+      assertEquals(0, reader.maxDoc());
+      assertEquals(0, reader.numDocs());
+      reader.close();
+
+      writer  = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)).setOpenMode(OpenMode.APPEND));
+      writer.commit();
+      writer.close();
+
+      reader = IndexReader.open(dir, true);
+      assertEquals(0, reader.maxDoc());
+      assertEquals(0, reader.numDocs());
+      reader.close();
+      dir.close();
+    }
+
+    public void testManyFields() throws IOException {
+      MockDirectoryWrapper dir = newDirectory();      
+      IndexWriter writer  = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)).setMaxBufferedDocs(10));
+      for(int j=0;j<100;j++) {
+        Document doc = new Document();
+        doc.add(newField("a"+j, "aaa" + j, Field.Store.YES, Field.Index.ANALYZED));
+        doc.add(newField("b"+j, "aaa" + j, Field.Store.YES, Field.Index.ANALYZED));
+        doc.add(newField("c"+j, "aaa" + j, Field.Store.YES, Field.Index.ANALYZED));
+        doc.add(newField("d"+j, "aaa", Field.Store.YES, Field.Index.ANALYZED));
+        doc.add(newField("e"+j, "aaa", Field.Store.YES, Field.Index.ANALYZED));
+        doc.add(newField("f"+j, "aaa", Field.Store.YES, Field.Index.ANALYZED));
+        writer.addDocument(doc);
+      }
+      writer.close();
+
+      IndexReader reader = IndexReader.open(dir, true);
+      assertEquals(100, reader.maxDoc());
+      assertEquals(100, reader.numDocs());
+      for(int j=0;j<100;j++) {
+        assertEquals(1, reader.docFreq(new Term("a"+j, "aaa"+j)));
+        assertEquals(1, reader.docFreq(new Term("b"+j, "aaa"+j)));
+        assertEquals(1, reader.docFreq(new Term("c"+j, "aaa"+j)));
+        assertEquals(1, reader.docFreq(new Term("d"+j, "aaa")));
+        assertEquals(1, reader.docFreq(new Term("e"+j, "aaa")));
+        assertEquals(1, reader.docFreq(new Term("f"+j, "aaa")));
+      }
+      reader.close();
+      dir.close();
+    }
+
+    public void testSmallRAMBuffer() throws IOException {
+      MockDirectoryWrapper dir = newDirectory();      
+      IndexWriter writer  = new IndexWriter(
+          dir,
+          newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)).
+              setRAMBufferSizeMB(0.000001).
+              setMergePolicy(newLogMergePolicy(10))
+      );
+      int lastNumFile = dir.listAll().length;
+      for(int j=0;j<9;j++) {
+        Document doc = new Document();
+        doc.add(newField("field", "aaa" + j, Field.Store.YES, Field.Index.ANALYZED));
+        writer.addDocument(doc);
+        int numFile = dir.listAll().length;
+        // Verify that with a tiny RAM buffer we see new
+        // segment after every doc
+        assertTrue(numFile > lastNumFile);
+        lastNumFile = numFile;
+      }
+      writer.close();
+      dir.close();
+    }
+
+    /**
+     * Make sure it's OK to change RAM buffer size and // maxBufferedDocs in a
+     * write session
+     * 
+     * @deprecated after all the setters on IW go away (4.0), this test can be
+     *             removed because changing ram buffer settings during a write
+     *             session won't be possible.
+     */
+    @Deprecated
+    public void testChangingRAMBuffer() throws IOException {
+      MockDirectoryWrapper dir = newDirectory();      
+      IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig(
+        TEST_VERSION_CURRENT, new MockAnalyzer(random)).setMaxBufferedDocs(10).setRAMBufferSizeMB(
+        IndexWriterConfig.DISABLE_AUTO_FLUSH));
+
+      int lastFlushCount = -1;
+      for(int j=1;j<52;j++) {
+        Document doc = new Document();
+        doc.add(newField("field", "aaa" + j, Field.Store.YES, Field.Index.ANALYZED));
+        writer.addDocument(doc);
+        _TestUtil.syncConcurrentMerges(writer);
+        int flushCount = writer.getFlushCount();
+        if (j == 1)
+          lastFlushCount = flushCount;
+        else if (j < 10)
+          // No new files should be created
+          assertEquals(flushCount, lastFlushCount);
+        else if (10 == j) {
+          assertTrue(flushCount > lastFlushCount);
+          lastFlushCount = flushCount;
+          writer.setRAMBufferSizeMB(0.000001);
+          writer.setMaxBufferedDocs(IndexWriterConfig.DISABLE_AUTO_FLUSH);
+        } else if (j < 20) {
+          assertTrue(flushCount > lastFlushCount);
+          lastFlushCount = flushCount;
+        } else if (20 == j) {
+          writer.setRAMBufferSizeMB(16);
+          writer.setMaxBufferedDocs(IndexWriterConfig.DISABLE_AUTO_FLUSH);
+          lastFlushCount = flushCount;
+        } else if (j < 30) {
+          assertEquals(flushCount, lastFlushCount);
+        } else if (30 == j) {
+          writer.setRAMBufferSizeMB(0.000001);
+          writer.setMaxBufferedDocs(IndexWriterConfig.DISABLE_AUTO_FLUSH);
+        } else if (j < 40) {
+          assertTrue(flushCount> lastFlushCount);
+          lastFlushCount = flushCount;
+        } else if (40 == j) {
+          writer.setMaxBufferedDocs(10);
+          writer.setRAMBufferSizeMB(IndexWriterConfig.DISABLE_AUTO_FLUSH);
+          lastFlushCount = flushCount;
+        } else if (j < 50) {
+          assertEquals(flushCount, lastFlushCount);
+          writer.setMaxBufferedDocs(10);
+          writer.setRAMBufferSizeMB(IndexWriterConfig.DISABLE_AUTO_FLUSH);
+        } else if (50 == j) {
+          assertTrue(flushCount > lastFlushCount);
+        }
+      }
+      writer.close();
+      dir.close();
+    }
+
+    /**
+     * @deprecated after setters on IW go away, this test can be deleted because
+     *             changing those settings on IW won't be possible.
+     */
+    @Deprecated
+    public void testChangingRAMBuffer2() throws IOException {
+      MockDirectoryWrapper dir = newDirectory();      
+      IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig(
+        TEST_VERSION_CURRENT, new WhitespaceAnalyzer(TEST_VERSION_CURRENT)).setMaxBufferedDocs(10).setMaxBufferedDeleteTerms(
+        10).setRAMBufferSizeMB(IndexWriterConfig.DISABLE_AUTO_FLUSH));
+
+      for(int j=1;j<52;j++) {
+        Document doc = new Document();
+        doc.add(newField("field", "aaa" + j, Field.Store.YES, Field.Index.ANALYZED));
+        writer.addDocument(doc);
+      }
+      
+      int lastFlushCount = -1;
+      for(int j=1;j<52;j++) {
+        writer.deleteDocuments(new Term("field", "aaa" + j));
+        _TestUtil.syncConcurrentMerges(writer);
+        int flushCount = writer.getFlushCount();
+        if (j == 1)
+          lastFlushCount = flushCount;
+        else if (j < 10) {
+          // No new files should be created
+          assertEquals(flushCount, lastFlushCount);
+        } else if (10 == j) {
+          assertTrue(flushCount > lastFlushCount);
+          lastFlushCount = flushCount;
+          writer.setRAMBufferSizeMB(0.000001);
+          writer.setMaxBufferedDeleteTerms(1);
+        } else if (j < 20) {
+          assertTrue(flushCount > lastFlushCount);
+          lastFlushCount = flushCount;
+        } else if (20 == j) {
+          writer.setRAMBufferSizeMB(16);
+          writer.setMaxBufferedDeleteTerms(IndexWriterConfig.DISABLE_AUTO_FLUSH);
+          lastFlushCount = flushCount;
+        } else if (j < 30) {
+          assertEquals(flushCount, lastFlushCount);
+        } else if (30 == j) {
+          writer.setRAMBufferSizeMB(0.000001);
+          writer.setMaxBufferedDeleteTerms(IndexWriterConfig.DISABLE_AUTO_FLUSH);
+          writer.setMaxBufferedDeleteTerms(1);
+        } else if (j < 40) {
+          assertTrue(flushCount> lastFlushCount);
+          lastFlushCount = flushCount;
+        } else if (40 == j) {
+          writer.setMaxBufferedDeleteTerms(10);
+          writer.setRAMBufferSizeMB(IndexWriterConfig.DISABLE_AUTO_FLUSH);
+          lastFlushCount = flushCount;
+        } else if (j < 50) {
+          assertEquals(flushCount, lastFlushCount);
+          writer.setMaxBufferedDeleteTerms(10);
+          writer.setRAMBufferSizeMB(IndexWriterConfig.DISABLE_AUTO_FLUSH);
+        } else if (50 == j) {
+          assertTrue(flushCount > lastFlushCount);
+        }
+      }
+      writer.close();
+      dir.close();
+    }
+
+    // Make sure it's OK to change RAM buffer size and
+    // maxBufferedDocs in a write session, using IW.getConfig()
+    public void testChangingRAMBufferWithIWC() throws IOException {
+      Directory dir = newDirectory();      
+      IndexWriter writer  = new IndexWriter(dir, newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)));
+      writer.getConfig().setMaxBufferedDocs(10);
+      writer.getConfig().setRAMBufferSizeMB(IndexWriterConfig.DISABLE_AUTO_FLUSH);
+
+      int lastFlushCount = -1;
+      for(int j=1;j<52;j++) {
+        Document doc = new Document();
+        doc.add(new Field("field", "aaa" + j, Field.Store.YES, Field.Index.ANALYZED));
+        writer.addDocument(doc);
+        _TestUtil.syncConcurrentMerges(writer);
+        int flushCount = writer.getFlushCount();
+        if (j == 1)
+          lastFlushCount = flushCount;
+        else if (j < 10)
+          // No new files should be created
+          assertEquals(flushCount, lastFlushCount);
+        else if (10 == j) {
+          assertTrue(flushCount > lastFlushCount);
+          lastFlushCount = flushCount;
+          writer.getConfig().setRAMBufferSizeMB(0.000001);
+          writer.getConfig().setMaxBufferedDocs(IndexWriterConfig.DISABLE_AUTO_FLUSH);
+        } else if (j < 20) {
+          assertTrue(flushCount > lastFlushCount);
+          lastFlushCount = flushCount;
+        } else if (20 == j) {
+          writer.getConfig().setRAMBufferSizeMB(16);
+          writer.getConfig().setMaxBufferedDocs(IndexWriterConfig.DISABLE_AUTO_FLUSH);
+          lastFlushCount = flushCount;
+        } else if (j < 30) {
+          assertEquals(flushCount, lastFlushCount);
+        } else if (30 == j) {
+          writer.getConfig().setRAMBufferSizeMB(0.000001);
+          writer.getConfig().setMaxBufferedDocs(IndexWriterConfig.DISABLE_AUTO_FLUSH);
+        } else if (j < 40) {
+          assertTrue(flushCount> lastFlushCount);
+          lastFlushCount = flushCount;
+        } else if (40 == j) {
+          writer.getConfig().setMaxBufferedDocs(10);
+          writer.getConfig().setRAMBufferSizeMB(IndexWriterConfig.DISABLE_AUTO_FLUSH);
+          lastFlushCount = flushCount;
+        } else if (j < 50) {
+          assertEquals(flushCount, lastFlushCount);
+          writer.getConfig().setMaxBufferedDocs(10);
+          writer.getConfig().setRAMBufferSizeMB(IndexWriterConfig.DISABLE_AUTO_FLUSH);
+        } else if (50 == j) {
+          assertTrue(flushCount > lastFlushCount);
+        }
+      }
+      writer.close();
+      dir.close();
+    }
+
+    public void testChangingRAMBuffer2WithIWC() throws IOException {
+      Directory dir = newDirectory();      
+      IndexWriter writer  = new IndexWriter(dir, newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)));
+      writer.getConfig().setMaxBufferedDocs(10);
+      writer.getConfig().setMaxBufferedDeleteTerms(10);
+      writer.getConfig().setRAMBufferSizeMB(IndexWriterConfig.DISABLE_AUTO_FLUSH);
+
+      for(int j=1;j<52;j++) {
+        Document doc = new Document();
+        doc.add(new Field("field", "aaa" + j, Field.Store.YES, Field.Index.ANALYZED));
+        writer.addDocument(doc);
+      }
+      
+      int lastFlushCount = -1;
+      for(int j=1;j<52;j++) {
+        writer.deleteDocuments(new Term("field", "aaa" + j));
+        _TestUtil.syncConcurrentMerges(writer);
+        int flushCount = writer.getFlushCount();
+        if (j == 1)
+          lastFlushCount = flushCount;
+        else if (j < 10) {
+          // No new files should be created
+          assertEquals(flushCount, lastFlushCount);
+        } else if (10 == j) {
+          assertTrue(flushCount > lastFlushCount);
+          lastFlushCount = flushCount;
+          writer.getConfig().setRAMBufferSizeMB(0.000001);
+          writer.getConfig().setMaxBufferedDeleteTerms(1);
+        } else if (j < 20) {
+          assertTrue(flushCount > lastFlushCount);
+          lastFlushCount = flushCount;
+        } else if (20 == j) {
+          writer.getConfig().setRAMBufferSizeMB(16);
+          writer.getConfig().setMaxBufferedDeleteTerms(IndexWriterConfig.DISABLE_AUTO_FLUSH);
+          lastFlushCount = flushCount;
+        } else if (j < 30) {
+          assertEquals(flushCount, lastFlushCount);
+        } else if (30 == j) {
+          writer.getConfig().setRAMBufferSizeMB(0.000001);
+          writer.getConfig().setMaxBufferedDeleteTerms(IndexWriterConfig.DISABLE_AUTO_FLUSH);
+          writer.getConfig().setMaxBufferedDeleteTerms(1);
+        } else if (j < 40) {
+          assertTrue(flushCount> lastFlushCount);
+          lastFlushCount = flushCount;
+        } else if (40 == j) {
+          writer.getConfig().setMaxBufferedDeleteTerms(10);
+          writer.getConfig().setRAMBufferSizeMB(IndexWriterConfig.DISABLE_AUTO_FLUSH);
+          lastFlushCount = flushCount;
+        } else if (j < 50) {
+          assertEquals(flushCount, lastFlushCount);
+          writer.getConfig().setMaxBufferedDeleteTerms(10);
+          writer.getConfig().setRAMBufferSizeMB(IndexWriterConfig.DISABLE_AUTO_FLUSH);
+        } else if (50 == j) {
+          assertTrue(flushCount > lastFlushCount);
+        }
+      }
+      writer.close();
+      dir.close();
+    }
+
+    public void testDiverseDocs() throws IOException {
+      MockDirectoryWrapper dir = newDirectory();      
+      IndexWriter writer  = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)).setRAMBufferSizeMB(0.5));
+      for(int i=0;i<3;i++) {
+        // First, docs where every term is unique (heavy on
+        // Posting instances)
+        for(int j=0;j<100;j++) {
+          Document doc = new Document();
+          for(int k=0;k<100;k++) {
+            doc.add(newField("field", Integer.toString(random.nextInt()), Field.Store.YES, Field.Index.ANALYZED));
+          }
+          writer.addDocument(doc);
+        }
+
+        // Next, many single term docs where only one term
+        // occurs (heavy on byte blocks)
+        for(int j=0;j<100;j++) {
+          Document doc = new Document();
+          doc.add(newField("field", "aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa", Field.Store.YES, Field.Index.ANALYZED));
+          writer.addDocument(doc);
+        }
+
+        // Next, many single term docs where only one term
+        // occurs but the terms are very long (heavy on
+        // char[] arrays)
+        for(int j=0;j<100;j++) {
+          StringBuilder b = new StringBuilder();
+          String x = Integer.toString(j) + ".";
+          for(int k=0;k<1000;k++)
+            b.append(x);
+          String longTerm = b.toString();
+
+          Document doc = new Document();
+          doc.add(newField("field", longTerm, Field.Store.YES, Field.Index.ANALYZED));
+          writer.addDocument(doc);
+        }
+      }
+      writer.close();
+
+      IndexSearcher searcher = new IndexSearcher(dir, false);
+      ScoreDoc[] hits = searcher.search(new TermQuery(new Term("field", "aaa")), null, 1000).scoreDocs;
+      assertEquals(300, hits.length);
+      searcher.close();
+
+      dir.close();
+    }
+
+    public void testEnablingNorms() throws IOException {
+      MockDirectoryWrapper dir = newDirectory();      
+      IndexWriter writer  = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)).setMaxBufferedDocs(10));
+      // Enable norms for only 1 doc, pre flush
+      for(int j=0;j<10;j++) {
+        Document doc = new Document();
+        Field f = newField("field", "aaa", Field.Store.YES, Field.Index.ANALYZED); 
+        if (j != 8) {
+          f.setOmitNorms(true);
+        }
+        doc.add(f);
+        writer.addDocument(doc);
+      }
+      writer.close();
+
+      Term searchTerm = new Term("field", "aaa");
+
+      IndexSearcher searcher = new IndexSearcher(dir, false);
+      ScoreDoc[] hits = searcher.search(new TermQuery(searchTerm), null, 1000).scoreDocs;
+      assertEquals(10, hits.length);
+      searcher.close();
+
+      writer = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random))
+        .setOpenMode(OpenMode.CREATE).setMaxBufferedDocs(10));
+      // Enable norms for only 1 doc, post flush
+      for(int j=0;j<27;j++) {
+        Document doc = new Document();
+        Field f = newField("field", "aaa", Field.Store.YES, Field.Index.ANALYZED); 
+        if (j != 26) {
+          f.setOmitNorms(true);
+        }
+        doc.add(f);
+        writer.addDocument(doc);
+      }
+      writer.close();
+      searcher = new IndexSearcher(dir, false);
+      hits = searcher.search(new TermQuery(searchTerm), null, 1000).scoreDocs;
+      assertEquals(27, hits.length);
+      searcher.close();
+
+      IndexReader reader = IndexReader.open(dir, true);
+      reader.close();
+
+      dir.close();
+    }
+
+    public void testHighFreqTerm() throws IOException {
+      MockDirectoryWrapper dir = newDirectory();      
+      IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig(
+          TEST_VERSION_CURRENT, new MockAnalyzer(random)).setRAMBufferSizeMB(0.01));
+      // Massive doc that has 128 K a's
+      StringBuilder b = new StringBuilder(1024*1024);
+      for(int i=0;i<4096;i++) {
+        b.append(" a a a a a a a a");
+        b.append(" a a a a a a a a");
+        b.append(" a a a a a a a a");
+        b.append(" a a a a a a a a");
+      }
+      Document doc = new Document();
+      doc.add(newField("field", b.toString(), Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
+      writer.addDocument(doc);
+      writer.close();
+
+      IndexReader reader = IndexReader.open(dir, true);
+      assertEquals(1, reader.maxDoc());
+      assertEquals(1, reader.numDocs());
+      Term t = new Term("field", "a");
+      assertEquals(1, reader.docFreq(t));
+      TermDocs td = reader.termDocs(t);
+      td.next();
+      assertEquals(128*1024, td.freq());
+      reader.close();
+      dir.close();
+    }
+
+    // Make sure that a Directory implementation that does
+    // not use LockFactory at all (ie overrides makeLock and
+    // implements its own private locking) works OK.  This
+    // was raised on java-dev as loss of backwards
+    // compatibility.
+    public void testNullLockFactory() throws IOException {
+
+      final class MyRAMDirectory extends MockDirectoryWrapper {
+        private LockFactory myLockFactory;
+        MyRAMDirectory(Directory delegate) {
+          super(random, delegate);
+          lockFactory = null;
+          myLockFactory = new SingleInstanceLockFactory();
+        }
+        @Override
+        public Lock makeLock(String name) {
+          return myLockFactory.makeLock(name);
+        }
+      }
+      
+      Directory dir = new MyRAMDirectory(new RAMDirectory());
+      IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig(
+        TEST_VERSION_CURRENT, new MockAnalyzer(random)));
+      for (int i = 0; i < 100; i++) {
+        addDoc(writer);
+      }
+      writer.close();
+      Term searchTerm = new Term("content", "aaa");        
+      IndexSearcher searcher = new IndexSearcher(dir, false);
+      ScoreDoc[] hits = searcher.search(new TermQuery(searchTerm), null, 1000).scoreDocs;
+      assertEquals("did not get right number of hits", 100, hits.length);
+      searcher.close();
+
+      writer = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random))
+        .setOpenMode(OpenMode.CREATE));
+      writer.close();
+      searcher.close();
+      dir.close();
+    }
+
+    public void testFlushWithNoMerging() throws IOException {
+      Directory dir = newDirectory();
+      IndexWriter writer = new IndexWriter(
+          dir,
+          newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)).
+              setMaxBufferedDocs(2).
+              setMergePolicy(newLogMergePolicy(10))
+      );
+      Document doc = new Document();
+      doc.add(newField("field", "aaa", Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
+      for(int i=0;i<19;i++)
+        writer.addDocument(doc);
+      writer.flush(false, true);
+      writer.close();
+      SegmentInfos sis = new SegmentInfos();
+      sis.read(dir);
+      // Since we flushed w/o allowing merging we should now
+      // have 10 segments
+      assertEquals(10, sis.size());
+      dir.close();
+    }
+
+    // Make sure we can flush segment w/ norms, then add
+    // empty doc (no norms) and flush
+    public void testEmptyDocAfterFlushingRealDoc() throws IOException {
+      Directory dir = newDirectory();
+      IndexWriter writer  = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
+      writer.setInfoStream(VERBOSE ? System.out : null);
+      Document doc = new Document();
+      doc.add(newField("field", "aaa", Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
+      writer.addDocument(doc);
+      writer.commit();
+      if (VERBOSE) {
+        System.out.println("\nTEST: now add empty doc");
+      }
+      writer.addDocument(new Document());
+      writer.close();
+      IndexReader reader = IndexReader.open(dir, true);
+      assertEquals(2, reader.numDocs());
+      reader.close();
+      dir.close();
+    }
+
+  /**
+   * Test that no NullPointerException will be raised,
+   * when adding one document with a single, empty field
+   * and term vectors enabled.
+   * @throws IOException
+   *
+   */
+  public void testBadSegment() throws IOException {
+    Directory dir = newDirectory();
+    IndexWriter iw = new IndexWriter(dir, newIndexWriterConfig(
+        TEST_VERSION_CURRENT, new MockAnalyzer(random)));
+   
+    Document document = new Document();
+    document.add(newField("tvtest", "", Store.NO, Index.ANALYZED, TermVector.YES));
+    iw.addDocument(document);
+    iw.close();
+    dir.close();
+  }
+
+  // LUCENE-1036
+  public void testMaxThreadPriority() throws IOException {
+    int pri = Thread.currentThread().getPriority();
+    try {
+      Directory dir = newDirectory();
+      IndexWriterConfig conf = newIndexWriterConfig(
+          TEST_VERSION_CURRENT, new MockAnalyzer(random))
+        .setMaxBufferedDocs(2).setMergePolicy(newLogMergePolicy());
+      ((LogMergePolicy) conf.getMergePolicy()).setMergeFactor(2);
+      IndexWriter iw = new IndexWriter(dir, conf);
+      Document document = new Document();
+      document.add(newField("tvtest", "a b c", Field.Store.NO, Field.Index.ANALYZED,
+                             Field.TermVector.YES));
+      Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
+      for(int i=0;i<4;i++)
+        iw.addDocument(document);
+      iw.close();
+      dir.close();
+    } finally {
+      Thread.currentThread().setPriority(pri);
+    }
+  }
+
+  // Just intercepts all merges & verifies that we are never
+  // merging a segment with >= 20 (maxMergeDocs) docs
+  private class MyMergeScheduler extends MergeScheduler {
+    @Override
+    synchronized public void merge(IndexWriter writer)
+      throws CorruptIndexException, IOException {
+
+      while(true) {
+        MergePolicy.OneMerge merge = writer.getNextMerge();
+        if (merge == null) {
+          break;
+        }
+        for(int i=0;i<merge.segments.size();i++) {
+          assert merge.segments.get(i).docCount < 20;
+        }
+        writer.merge(merge);
+      }
+    }
+
+    @Override
+    public void close() {}
+  }
+
+  public void testVariableSchema() throws Exception {
+    Directory dir = newDirectory();
+    int delID = 0;
+    for(int i=0;i<20;i++) {
+      if (VERBOSE) {
+        System.out.println("TEST: iter=" + i);
+      }
+      IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)).setMaxBufferedDocs(2).setMergePolicy(newLogMergePolicy()));
+      writer.setInfoStream(VERBOSE ? System.out : null);
+      //LogMergePolicy lmp = (LogMergePolicy) writer.getConfig().getMergePolicy();
+      //lmp.setMergeFactor(2);
+      //lmp.setUseCompoundFile(false);
+      Document doc = new Document();
+      String contents = "aa bb cc dd ee ff gg hh ii jj kk";
+
+      if (i == 7) {
+        // Add empty docs here
+        doc.add(newField("content3", "", Field.Store.NO,
+                          Field.Index.ANALYZED));
+      } else {
+        Field.Store storeVal;
+        if (i%2 == 0) {
+          doc.add(newField("content4", contents, Field.Store.YES,
+                            Field.Index.ANALYZED));
+          storeVal = Field.Store.YES;
+        } else
+          storeVal = Field.Store.NO;
+        doc.add(newField("content1", contents, storeVal,
+                          Field.Index.ANALYZED));
+        doc.add(newField("content3", "", Field.Store.YES,
+                          Field.Index.ANALYZED));
+        doc.add(newField("content5", "", storeVal,
+                          Field.Index.ANALYZED));
+      }
+
+      for(int j=0;j<4;j++)
+        writer.addDocument(doc);
+
+      writer.close();
+      IndexReader reader = IndexReader.open(dir, false);
+      reader.deleteDocument(delID++);
+      reader.close();
+
+      if (0 == i % 4) {
+        writer = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
+        //LogMergePolicy lmp2 = (LogMergePolicy) writer.getConfig().getMergePolicy();
+        //lmp2.setUseCompoundFile(false);
+        writer.optimize();
+        writer.close();
+      }
+    }
+    dir.close();
+  }
+
+  public void testNoWaitClose() throws Throwable {
+    Directory directory = newDirectory();
+
+    final Document doc = new Document();
+    Field idField = newField("id", "", Field.Store.YES, Field.Index.NOT_ANALYZED);
+    doc.add(idField);
+
+    for(int pass=0;pass<2;pass++) {
+      if (VERBOSE) {
+        System.out.println("TEST: pass=" + pass);
+      }
+
+      IndexWriterConfig conf = newIndexWriterConfig(
+          TEST_VERSION_CURRENT, new MockAnalyzer(random)).setOpenMode(OpenMode.CREATE)
+          .setMaxBufferedDocs(2).setMergePolicy(newLogMergePolicy());
+      if (pass == 2) {
+        conf.setMergeScheduler(new SerialMergeScheduler());
+      }
+      IndexWriter writer = new IndexWriter(directory, conf);
+      ((LogMergePolicy) writer.getConfig().getMergePolicy()).setMergeFactor(100);
+      writer.setInfoStream(VERBOSE ? System.out : null);
+
+      // have to use compound file to prevent running out of
+      // descripters when newDirectory returns a file-system
+      // backed directory:
+      ((LogMergePolicy) writer.getConfig().getMergePolicy()).setUseCompoundFile(true);
+      
+      for(int iter=0;iter<10;iter++) {
+        if (VERBOSE) {
+          System.out.println("TEST: iter=" + iter);
+        }
+        for(int j=0;j<199;j++) {
+          idField.setValue(Integer.toString(iter*201+j));
+          writer.addDocument(doc);
+        }
+
+        int delID = iter*199;
+        for(int j=0;j<20;j++) {
+          writer.deleteDocuments(new Term("id", Integer.toString(delID)));
+          delID += 5;
+        }
+
+        // Force a bunch of merge threads to kick off so we
+        // stress out aborting them on close:
+        ((LogMergePolicy) writer.getConfig().getMergePolicy()).setMergeFactor(2);
+
+        final IndexWriter finalWriter = writer;
+        final ArrayList<Throwable> failure = new ArrayList<Throwable>();
+        Thread t1 = new Thread() {
+            @Override
+            public void run() {
+              boolean done = false;
+              while(!done) {
+                for(int i=0;i<100;i++) {
+                  try {
+                    finalWriter.addDocument(doc);
+                  } catch (AlreadyClosedException e) {
+                    done = true;
+                    break;
+                  } catch (NullPointerException e) {
+                    done = true;
+                    break;
+                  } catch (Throwable e) {
+                    e.printStackTrace(System.out);
+                    failure.add(e);
+                    done = true;
+                    break;
+                  }
+                }
+                Thread.yield();
+              }
+
+            }
+          };
+
+        if (failure.size() > 0) {
+          throw failure.get(0);
+        }
+
+        t1.start();
+
+        writer.close(false);
+        t1.join();
+
+        // Make sure reader can read
+        IndexReader reader = IndexReader.open(directory, true);
+        reader.close();
+
+        // Reopen
+        writer = new IndexWriter(directory, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)).setOpenMode(OpenMode.APPEND).setMergePolicy(newLogMergePolicy()));
+        writer.setInfoStream(VERBOSE ? System.out : null);
+      }
+      writer.close();
+    }
+
+    directory.close();
+  }
+
+  // LUCENE-1084: test unlimited field length
+  public void testUnlimitedMaxFieldLength() throws IOException {
+    Directory dir = newDirectory();
+
+    IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
+
+    Document doc = new Document();
+    StringBuilder b = new StringBuilder();
+    for(int i=0;i<10000;i++)
+      b.append(" a");
+    b.append(" x");
+    doc.add(newField("field", b.toString(), Field.Store.NO, Field.Index.ANALYZED));
+    writer.addDocument(doc);
+    writer.close();
+
+    IndexReader reader = IndexReader.open(dir, true);
+    Term t = new Term("field", "x");
+    assertEquals(1, reader.docFreq(t));
+    reader.close();
+    dir.close();
+  }
+
+  // LUCENE-1084: test user-specified field length
+  public void testUserSpecifiedMaxFieldLength() throws IOException {
+    Directory dir = newDirectory();
+
+    IndexWriter writer = new IndexWriter(dir, new IndexWriterConfig(
+        TEST_VERSION_CURRENT, new WhitespaceAnalyzer(TEST_VERSION_CURRENT)));
+    writer.setMaxFieldLength(100000);
+
+    Document doc = new Document();
+    StringBuilder b = new StringBuilder();
+    for(int i=0;i<10000;i++)
+      b.append(" a");
+    b.append(" x");
+    doc.add(newField("field", b.toString(), Field.Store.NO, Field.Index.ANALYZED));
+    writer.addDocument(doc);
+    writer.close();
+
+    IndexReader reader = IndexReader.open(dir, true);
+    Term t = new Term("field", "x");
+    assertEquals(1, reader.docFreq(t));
+    reader.close();
+    dir.close();
+  }
+
+  // LUCENE-1179
+  public void testEmptyFieldName() throws IOException {
+    Directory dir = newDirectory();
+    IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
+    Document doc = new Document();
+    doc.add(newField("", "a b c", Field.Store.NO, Field.Index.ANALYZED));
+    writer.addDocument(doc);
+    writer.close();
+    dir.close();
+  }
+
+
+
+  private static final class MockIndexWriter extends IndexWriter {
+
+    public MockIndexWriter(Directory dir, IndexWriterConfig conf) throws IOException {
+      super(dir, conf);
+    }
+
+    boolean afterWasCalled;
+    boolean beforeWasCalled;
+
+    @Override
+    public void doAfterFlush() {
+      afterWasCalled = true;
+    }
+    
+    @Override
+    protected void doBeforeFlush() throws IOException {
+      beforeWasCalled = true;
+    }
+  }
+  
+
+  // LUCENE-1222
+  public void testDoBeforeAfterFlush() throws IOException {
+    Directory dir = newDirectory();
+    MockIndexWriter w = new MockIndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
+    Document doc = new Document();
+    doc.add(newField("field", "a field", Field.Store.YES,
+                      Field.Index.ANALYZED));
+    w.addDocument(doc);
+    w.commit();
+    assertTrue(w.beforeWasCalled);
+    assertTrue(w.afterWasCalled);
+    w.beforeWasCalled = false;
+    w.afterWasCalled = false;
+    w.deleteDocuments(new Term("field", "field"));
+    w.commit();
+    assertTrue(w.beforeWasCalled);
+    assertTrue(w.afterWasCalled);
+    w.close();
+
+    IndexReader ir = IndexReader.open(dir, true);
+    assertEquals(0, ir.numDocs());
+    ir.close();
+
+    dir.close();
+  }
+
+  // LUCENE-1255
+  public void testNegativePositions() throws Throwable {
+    final TokenStream tokens = new TokenStream() {
+      final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class);
+      final PositionIncrementAttribute posIncrAtt = addAttribute(PositionIncrementAttribute.class);
+      
+      final Iterator<String> terms = Arrays.asList("a","b","c").iterator();
+      boolean first = true;
+      
+      @Override
+      public boolean incrementToken() {
+        if (!terms.hasNext()) return false;
+        clearAttributes();
+        termAtt.append(terms.next());
+        posIncrAtt.setPositionIncrement(first ? 0 : 1);
+        first = false;
+        return true;
+      }
+    };
+
+    Directory dir = newDirectory();
+    IndexWriter w = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
+    Document doc = new Document();
+    doc.add(new Field("field", tokens));
+    w.addDocument(doc);
+    w.commit();
+
+    IndexSearcher s = new IndexSearcher(dir, false);
+    PhraseQuery pq = new PhraseQuery();
+    pq.add(new Term("field", "a"));
+    pq.add(new Term("field", "b"));
+    pq.add(new Term("field", "c"));
+    ScoreDoc[] hits = s.search(pq, null, 1000).scoreDocs;
+    assertEquals(1, hits.length);
+
+    Query q = new SpanTermQuery(new Term("field", "a"));
+    hits = s.search(q, null, 1000).scoreDocs;
+    assertEquals(1, hits.length);
+    TermPositions tps = s.getIndexReader().termPositions(new Term("field", "a"));
+    assertTrue(tps.next());
+    assertEquals(1, tps.freq());
+    assertEquals(0, tps.nextPosition());
+    w.close();
+
+    s.close();
+    dir.close();
+  }
+
+  // LUCENE-1219
+  public void testBinaryFieldOffsetLength() throws IOException {
+    Directory dir = newDirectory();
+    IndexWriter w = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
+    byte[] b = new byte[50];
+    for(int i=0;i<50;i++)
+      b[i] = (byte) (i+77);
+    
+    Document doc = new Document();
+    Field f = new Field("binary", b, 10, 17);
+    byte[] bx = f.getBinaryValue();
+    assertTrue(bx != null);
+    assertEquals(50, bx.length);
+    assertEquals(10, f.getBinaryOffset());
+    assertEquals(17, f.getBinaryLength());
+    doc.add(f);
+    w.addDocument(doc);
+    w.close();
+
+    IndexReader ir = IndexReader.open(dir, true);
+    doc = ir.document(0);
+    f = doc.getField("binary");
+    b = f.getBinaryValue();
+    assertTrue(b != null);
+    assertEquals(17, b.length, 17);
+    assertEquals(87, b[0]);
+    ir.close();
+    dir.close();
+  }
+
+  // LUCENE-2529
+  public void testPositionIncrementGapEmptyField() throws Exception {
+    Directory dir = newDirectory();
+    Analyzer analyzer = new Analyzer(){
+      Analyzer a = new WhitespaceAnalyzer( TEST_VERSION_CURRENT );
+      @Override
+      public TokenStream tokenStream(String fieldName, Reader reader){
+        return a.tokenStream(fieldName, reader);
+      }
+      @Override
+      public int getPositionIncrementGap(String fieldName) {
+        return 100;
+      }
+    };
+    IndexWriter w = new IndexWriter(dir, newIndexWriterConfig( 
+        TEST_VERSION_CURRENT, analyzer));
+    Document doc = new Document();
+    Field f = newField("field", "", Field.Store.NO,
+                        Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS);
+    Field f2 = newField("field", "crunch man", Field.Store.NO,
+        Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS);
+    doc.add(f);
+    doc.add(f2);
+    w.addDocument(doc);
+    w.close();
+
+    IndexReader r = IndexReader.open(dir, true);
+    TermPositionVector tpv = ((TermPositionVector) r.getTermFreqVector(0, "field"));
+    int[] poss = tpv.getTermPositions(0);
+    assertEquals(1, poss.length);
+    assertEquals(100, poss[0]);
+    poss = tpv.getTermPositions(1);
+    assertEquals(1, poss.length);
+    assertEquals(101, poss[0]);
+    r.close();
+    dir.close();
+  }
+
+
+  // LUCENE-1468 -- make sure opening an IndexWriter with
+  // create=true does not remove non-index files
+  
+  public void testOtherFiles() throws Throwable {
+    Directory dir = newDirectory();
+    try {
+      // Create my own random file:
+      IndexOutput out = dir.createOutput("myrandomfile");
+      out.writeByte((byte) 42);
+      out.close();
+
+      new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random))).close();
+
+      assertTrue(dir.fileExists("myrandomfile"));
+
+      // Make sure this does not copy myrandomfile:
+      Directory dir2 = new MockDirectoryWrapper(random, new RAMDirectory(dir));
+      assertTrue(!dir2.fileExists("myrandomfile"));
+      dir2.close();
+    } finally {
+      dir.close();
+    }
+  }
+
+  public void testDeadlock() throws Exception {
+    Directory dir = newDirectory();
+    IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)).setMaxBufferedDocs(2));
+    Document doc = new Document();
+    doc.add(newField("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
+
+    Directory dir2 = newDirectory();
+    IndexWriter writer2 = new IndexWriter(dir2, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
+    writer2.addDocument(doc);
+    writer2.close();
+
+    IndexReader r1 = IndexReader.open(dir2, true);
+    IndexReader r2 = (IndexReader) r1.clone();
+    writer.addIndexes(new IndexReader[] {r1, r2});
+    writer.close();
+
+    IndexReader r3 = IndexReader.open(dir, true);
+    assertEquals(5, r3.numDocs());
+    r3.close();
+
+    r1.close();
+    r2.close();
+
+    dir2.close();
+    dir.close();
+  }
+
+  private class IndexerThreadInterrupt extends Thread {
+    volatile boolean failed;
+    volatile boolean finish;
+
+    volatile boolean allowInterrupt = false;
+
+    @Override
+    public void run() {
+      // LUCENE-2239: won't work with NIOFS/MMAP
+      Directory dir = new MockDirectoryWrapper(random, new RAMDirectory()); 
+      IndexWriter w = null;
+      while(!finish) {
+        try {
+
+          while(!finish) {
+            if (w != null) {
+              w.close();
+              w = null;
+            }
+            IndexWriterConfig conf = newIndexWriterConfig( 
+                                                          TEST_VERSION_CURRENT, new MockAnalyzer(random)).setMaxBufferedDocs(2);
+            w = new IndexWriter(dir, conf);
+            w.setInfoStream(VERBOSE ? System.out : null);
+
+            Document doc = new Document();
+            doc.add(newField("field", "some text contents", Field.Store.YES, Field.Index.ANALYZED));
+            for(int i=0;i<100;i++) {
+              w.addDocument(doc);
+              if (i%10 == 0) {
+                w.commit();
+              }
+            }
+            w.close();
+            w = null;
+            _TestUtil.checkIndex(dir);
+            IndexReader.open(dir, true).close();
+
+            // Strangely, if we interrupt a thread before
+            // all classes are loaded, the class loader
+            // seems to do scary things with the interrupt
+            // status.  In java 1.5, it'll throw an
+            // incorrect ClassNotFoundException.  In java
+            // 1.6, it'll silently clear the interrupt.
+            // So, on first iteration through here we
+            // don't open ourselves up for interrupts
+            // until we've done the above loop.
+            allowInterrupt = true;
+          }
+        } catch (ThreadInterruptedException re) {
+          if (VERBOSE) {
+            System.out.println("TEST: got interrupt");
+            re.printStackTrace(System.out);
+          }
+          Throwable e = re.getCause();
+          assertTrue(e instanceof InterruptedException);
+          if (finish) {
+            break;
+          }
+        } catch (Throwable t) {
+          System.out.println("FAILED; unexpected exception");
+          t.printStackTrace(System.out);
+          failed = true;
+          break;
+        }
+      }
+
+      if (!failed) {
+        // clear interrupt state:
+        Thread.interrupted();
+        if (w != null) {
+          try {
+            w.rollback();
+          } catch (IOException ioe) {
+            throw new RuntimeException(ioe);
+          }
+        }
+
+        try {
+          _TestUtil.checkIndex(dir);
+        } catch (Exception e) {
+          failed = true;
+          System.out.println("CheckIndex FAILED: unexpected exception");
+          e.printStackTrace(System.out);
+        }
+        try {
+          IndexReader r = IndexReader.open(dir, true);
+          //System.out.println("doc count=" + r.numDocs());
+          r.close();
+        } catch (Exception e) {
+          failed = true;
+          System.out.println("IndexReader.open FAILED: unexpected exception");
+          e.printStackTrace(System.out);
+        }
+      }
+      try { 
+        dir.close();
+      } catch (IOException e) { 
+        throw new RuntimeException(e); 
+      }
+    }
+  }
+
+  public void testThreadInterruptDeadlock() throws Exception {
+    IndexerThreadInterrupt t = new IndexerThreadInterrupt();
+    t.setDaemon(true);
+    t.start();
+
+    // Force class loader to load ThreadInterruptedException
+    // up front... else we can see a false failure if 2nd
+    // interrupt arrives while class loader is trying to
+    // init this class (in servicing a first interrupt):
+    assertTrue(new ThreadInterruptedException(new InterruptedException()).getCause() instanceof InterruptedException);
+    
+    // issue 100 interrupts to child thread
+    int i = 0;
+    while(i < 100) {
+      Thread.sleep(10);
+      if (t.allowInterrupt) {
+        i++;
+        t.interrupt();
+      }
+      if (!t.isAlive()) {
+        break;
+      }
+    }
+    t.finish = true;
+    t.join();
+    assertFalse(t.failed);
+  }
+
+
+  public void testIndexStoreCombos() throws Exception {
+    Directory dir = newDirectory();
+    IndexWriter w = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
+    byte[] b = new byte[50];
+    for(int i=0;i<50;i++)
+      b[i] = (byte) (i+77);
+
+    Document doc = new Document();
+    Field f = new Field("binary", b, 10, 17);
+    f.setTokenStream(new WhitespaceTokenizer(TEST_VERSION_CURRENT, new StringReader("doc1field1")));
+    Field f2 = newField("string", "value", Field.Store.YES,Field.Index.ANALYZED);
+    f2.setTokenStream(new WhitespaceTokenizer(TEST_VERSION_CURRENT, new StringReader("doc1field2")));
+    doc.add(f);
+    doc.add(f2);
+    w.addDocument(doc);
+    
+    // add 2 docs to test in-memory merging
+    f.setTokenStream(new WhitespaceTokenizer(TEST_VERSION_CURRENT, new StringReader("doc2field1")));
+    f2.setTokenStream(new WhitespaceTokenizer(TEST_VERSION_CURRENT, new StringReader("doc2field2")));
+    w.addDocument(doc);
+  
+    // force segment flush so we can force a segment merge with doc3 later.
+    w.commit();
+
+    f.setTokenStream(new WhitespaceTokenizer(TEST_VERSION_CURRENT, new StringReader("doc3field1")));
+    f2.setTokenStream(new WhitespaceTokenizer(TEST_VERSION_CURRENT, new StringReader("doc3field2")));
+
+    w.addDocument(doc);
+    w.commit();
+    w.optimize();   // force segment merge.
+    w.close();
+
+    IndexReader ir = IndexReader.open(dir, true);
+    doc = ir.document(0);
+    f = doc.getField("binary");
+    b = f.getBinaryValue();
+    assertTrue(b != null);
+    assertEquals(17, b.length, 17);
+    assertEquals(87, b[0]);
+
+    assertTrue(ir.document(0).getFieldable("binary").isBinary());
+    assertTrue(ir.document(1).getFieldable("binary").isBinary());
+    assertTrue(ir.document(2).getFieldable("binary").isBinary());
+    
+    assertEquals("value", ir.document(0).get("string"));
+    assertEquals("value", ir.document(1).get("string"));
+    assertEquals("value", ir.document(2).get("string"));
+
+
+    // test that the terms were indexed.
+    assertTrue(ir.termDocs(new Term("binary","doc1field1")).next());
+    assertTrue(ir.termDocs(new Term("binary","doc2field1")).next());
+    assertTrue(ir.termDocs(new Term("binary","doc3field1")).next());
+    assertTrue(ir.termDocs(new Term("string","doc1field2")).next());
+    assertTrue(ir.termDocs(new Term("string","doc2field2")).next());
+    assertTrue(ir.termDocs(new Term("string","doc3field2")).next());
+
+    ir.close();
+    dir.close();
+
+  }
+
+  // LUCENE-1727: make sure doc fields are stored in order
+  public void testStoredFieldsOrder() throws Throwable {
+    Directory d = newDirectory();
+    IndexWriter w = new IndexWriter(d, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
+    Document doc = new Document();
+    doc.add(newField("zzz", "a b c", Field.Store.YES, Field.Index.NO));
+    doc.add(newField("aaa", "a b c", Field.Store.YES, Field.Index.NO));
+    doc.add(newField("zzz", "1 2 3", Field.Store.YES, Field.Index.NO));
+    w.addDocument(doc);
+    IndexReader r = w.getReader();
+    doc = r.document(0);
+    Iterator<Fieldable> it = doc.getFields().iterator();
+    assertTrue(it.hasNext());
+    Field f = (Field) it.next();
+    assertEquals(f.name(), "zzz");
+    assertEquals(f.stringValue(), "a b c");
+
+    assertTrue(it.hasNext());
+    f = (Field) it.next();
+    assertEquals(f.name(), "aaa");
+    assertEquals(f.stringValue(), "a b c");
+
+    assertTrue(it.hasNext());
+    f = (Field) it.next();
+    assertEquals(f.name(), "zzz");
+    assertEquals(f.stringValue(), "1 2 3");
+    assertFalse(it.hasNext());
+    r.close();
+    w.close();
+    d.close();
+  }
+
+  public void testNoDocsIndex() throws Throwable {
+    Directory dir = newDirectory();
+    IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig( 
+        TEST_VERSION_CURRENT, new MockAnalyzer(random)));
+    ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
+    writer.setInfoStream(new PrintStream(bos));
+    writer.addDocument(new Document());
+    writer.close();
+
+    dir.close();
+  }
+
+  public void testDeleteUnusedFiles() throws Exception {
+
+    for(int iter=0;iter<2;iter++) {
+      Directory dir = newDirectory();
+
+      LogMergePolicy mergePolicy = newLogMergePolicy(true);
+      mergePolicy.setNoCFSRatio(1); // This test expects all of its segments to be in CFS
+
+      IndexWriter w = new IndexWriter(
+          dir,
+          newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)).
+              setMergePolicy(mergePolicy)
+      );
+      Document doc = new Document();
+      doc.add(newField("field", "go", Field.Store.NO, Field.Index.ANALYZED));
+      w.addDocument(doc);
+      IndexReader r;
+      if (iter == 0) {
+        // use NRT
+        r = w.getReader();
+      } else {
+        // don't use NRT
+        w.commit();
+        r = IndexReader.open(dir);
+      }
+
+      List<String> files = Arrays.asList(dir.listAll());
+      assertTrue(files.contains("_0.cfs"));
+      w.addDocument(doc);
+      w.optimize();
+      if (iter == 1) {
+        w.commit();
+      }
+      IndexReader r2 = r.reopen();
+      assertTrue(r != r2);
+      files = Arrays.asList(dir.listAll());
+
+      // NOTE: here we rely on "Windows" behavior, ie, even
+      // though IW wanted to delete _0.cfs since it was
+      // optimized away, because we have a reader open
+      // against this file, it should still be here:
+      assertTrue(files.contains("_0.cfs"));
+      // optimize created this
+      //assertTrue(files.contains("_2.cfs"));
+      w.deleteUnusedFiles();
+
+      files = Arrays.asList(dir.listAll());
+      // r still holds this file open
+      assertTrue(files.contains("_0.cfs"));
+      //assertTrue(files.contains("_2.cfs"));
+
+      r.close();
+      if (iter == 0) {
+        // on closing NRT reader, it calls writer.deleteUnusedFiles
+        files = Arrays.asList(dir.listAll());
+        assertFalse(files.contains("_0.cfs"));
+      } else {
+        // now writer can remove it
+        w.deleteUnusedFiles();
+        files = Arrays.asList(dir.listAll());
+        assertFalse(files.contains("_0.cfs"));
+      }
+      //assertTrue(files.contains("_2.cfs"));
+
+      w.close();
+      r2.close();
+
+      dir.close();
+    }
+  }
+
+  public void testDeleteUnsedFiles2() throws Exception {
+    // Validates that iw.deleteUnusedFiles() also deletes unused index commits
+    // in case a deletion policy which holds onto commits is used.
+    Directory dir = newDirectory();
+    SnapshotDeletionPolicy sdp = new SnapshotDeletionPolicy(new KeepOnlyLastCommitDeletionPolicy());
+    IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig( 
+        TEST_VERSION_CURRENT, new MockAnalyzer(random))
+        .setIndexDeletionPolicy(sdp));
+    
+    // First commit
+    Document doc = new Document();
+    doc.add(newField("c", "val", Store.YES, Index.ANALYZED, TermVector.WITH_POSITIONS_OFFSETS));
+    writer.addDocument(doc);
+    writer.commit();
+    assertEquals(1, IndexReader.listCommits(dir).size());
+
+    // Keep that commit
+    sdp.snapshot("id");
+    
+    // Second commit - now KeepOnlyLastCommit cannot delete the prev commit.
+    doc = new Document();
+    doc.add(newField("c", "val", Store.YES, Index.ANALYZED, TermVector.WITH_POSITIONS_OFFSETS));
+    writer.addDocument(doc);
+    writer.commit();
+    assertEquals(2, IndexReader.listCommits(dir).size());
+
+    // Should delete the unreferenced commit
+    sdp.release("id");
+    writer.deleteUnusedFiles();
+    assertEquals(1, IndexReader.listCommits(dir).size());
+    
+    writer.close();
+    dir.close();
+  }
+  
+  private static class FlushCountingIndexWriter extends IndexWriter {
+    int flushCount;
+    public FlushCountingIndexWriter(Directory dir, IndexWriterConfig iwc) throws IOException {
+      super(dir, iwc);
+    }
+    @Override
+    public void doAfterFlush() {
+      flushCount++;
+    }
+  }
+
+  public void testEmptyFSDirWithNoLock() throws Exception {
+    // Tests that if FSDir is opened w/ a NoLockFactory (or SingleInstanceLF),
+    // then IndexWriter ctor succeeds. Previously (LUCENE-2386) it failed 
+    // when listAll() was called in IndexFileDeleter.
+    Directory dir = newFSDirectory(_TestUtil.getTempDir("emptyFSDirNoLock"), NoLockFactory.getNoLockFactory());
+    new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random))).close();
+    dir.close();
+  }
+
+  public void testEmptyDirRollback() throws Exception {
+    // Tests that if IW is created over an empty Directory, some documents are
+    // indexed, flushed (but not committed) and then IW rolls back, then no 
+    // files are left in the Directory.
+    Directory dir = newDirectory();
+    IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig( 
+        TEST_VERSION_CURRENT, new MockAnalyzer(random))
+                                         .setMaxBufferedDocs(2).setMergePolicy(newLogMergePolicy()));
+    String[] files = dir.listAll();
+
+    writer.setInfoStream(VERBOSE ? System.out : null);
+
+    // Creating over empty dir should not create any files,
+    // or, at most the write.lock file
+    final int extraFileCount;
+    if (files.length == 1) {
+      assertTrue(files[0].endsWith("write.lock"));
+      extraFileCount = 1;
+    } else {
+      assertEquals(0, files.length);
+      extraFileCount = 0;
+    }
+
+    Document doc = new Document();
+    // create as many files as possible
+    doc.add(newField("c", "val", Store.YES, Index.ANALYZED, TermVector.WITH_POSITIONS_OFFSETS));
+    writer.addDocument(doc);
+    // Adding just one document does not call flush yet.
+    assertEquals("only the stored and term vector files should exist in the directory", 5 + extraFileCount, dir.listAll().length);
+    
+    doc = new Document();
+    doc.add(newField("c", "val", Store.YES, Index.ANALYZED, TermVector.WITH_POSITIONS_OFFSETS));
+    writer.addDocument(doc);
+
+    // The second document should cause a flush.
+    assertTrue("flush should have occurred and files should have been created", dir.listAll().length > 5 + extraFileCount);
+
+    // After rollback, IW should remove all files
+    writer.rollback();
+    assertEquals("no files should exist in the directory after rollback", 0, dir.listAll().length);
+
+    // Since we rolled-back above, that close should be a no-op
+    writer.close();
+    assertEquals("expected a no-op close after IW.rollback()", 0, dir.listAll().length);
+    dir.close();
+  }
+
+  public void testNoSegmentFile() throws IOException {
+    Directory dir = newDirectory();
+    dir.setLockFactory(NoLockFactory.getNoLockFactory());
+    IndexWriter w = new IndexWriter(dir, newIndexWriterConfig( 
+        TEST_VERSION_CURRENT, new MockAnalyzer(random)).setMaxBufferedDocs(2));
+    
+    Document doc = new Document();
+    doc.add(newField("c", "val", Store.YES, Index.ANALYZED, TermVector.WITH_POSITIONS_OFFSETS));
+    w.addDocument(doc);
+    w.addDocument(doc);
+    IndexWriter w2 = new IndexWriter(dir, newIndexWriterConfig( 
+        TEST_VERSION_CURRENT, new MockAnalyzer(random)).setMaxBufferedDocs(2)
+        .setOpenMode(OpenMode.CREATE));
+    
+    w2.close();
+    w.rollback();
+    dir.close();
+  }
+
+  public void testRandomStoredFields() throws IOException {
+    Directory dir = newDirectory();
+    Random rand = random;
+    RandomIndexWriter w = new RandomIndexWriter(rand, dir, newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)).setMaxBufferedDocs(_TestUtil.nextInt(rand, 5, 20)));
+    //w.w.setInfoStream(System.out);
+    //w.w.setUseCompoundFile(false);
+    if (VERBOSE) {
+      w.w.setInfoStream(System.out);
+    }
+    final int docCount = atLeast(200);
+    final int fieldCount = _TestUtil.nextInt(rand, 1, 5);
+      
+    final List<Integer> fieldIDs = new ArrayList<Integer>();
+
+    Field idField = newField("id", "", Field.Store.YES, Field.Index.NOT_ANALYZED);
+
+    for(int i=0;i<fieldCount;i++) {
+      fieldIDs.add(i);
+    }
+
+    final Map<String,Document> docs = new HashMap<String,Document>();
+    
+    if (VERBOSE) {
+      System.out.println("TEST: build index docCount=" + docCount);
+    }
+
+    for(int i=0;i<docCount;i++) {
+      Document doc = new Document();
+      doc.add(idField);
+      final String id = ""+i;
+      idField.setValue(id);
+      docs.put(id, doc);
+
+      for(int field: fieldIDs) {
+        final String s;
+        if (rand.nextInt(4) != 3) {
+          s = _TestUtil.randomUnicodeString(rand, 1000);
+          doc.add(newField("f"+field, s, Field.Store.YES, Field.Index.NO));
+        } else {
+          s = null;
+        }
+      }
+      w.addDocument(doc);
+      if (rand.nextInt(50) == 17) {
+        // mixup binding of field name -> Number every so often
+        Collections.shuffle(fieldIDs);
+      }
+      if (rand.nextInt(5) == 3 && i > 0) {
+        final String delID = ""+rand.nextInt(i);
+        if (VERBOSE) {
+          System.out.println("TEST: delete doc " + delID);
+        }
+        w.deleteDocuments(new Term("id", delID));
+        docs.remove(delID);
+      }
+    }
+
+    if (VERBOSE) {
+      System.out.println("TEST: " + docs.size() + " docs in index; now load fields");
+    }
+    if (docs.size() > 0) {
+      String[] idsList = docs.keySet().toArray(new String[docs.size()]);
+
+      for(int x=0;x<2;x++) {
+        IndexReader r = w.getReader();
+        IndexSearcher s = newSearcher(r);
+
+        if (VERBOSE) {
+          System.out.println("TEST: cycle x=" + x + " r=" + r);
+        }
+
+        int num = atLeast(1000);
+        for(int iter=0;iter<num;iter++) {
+          String testID = idsList[rand.nextInt(idsList.length)];
+          TopDocs hits = s.search(new TermQuery(new Term("id", testID)), 1);
+          assertEquals(1, hits.totalHits);
+          Document doc = r.document(hits.scoreDocs[0].doc);
+          Document docExp = docs.get(testID);
+          for(int i=0;i<fieldCount;i++) {
+            assertEquals("doc " + testID + ", field f" + fieldCount + " is wrong", docExp.get("f"+i),  doc.get("f"+i));
+          }
+        }
+        s.close();
+        r.close();
+        w.optimize();
+      }
+    }
+    w.close();
+    dir.close();
+  }
+
+  public void testNoUnwantedTVFiles() throws Exception {
+
+    Directory dir = newDirectory();
+    IndexWriter indexWriter = new IndexWriter(dir, newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)).setRAMBufferSizeMB(0.01).setMergePolicy(newLogMergePolicy()));
+    ((LogMergePolicy) indexWriter.getConfig().getMergePolicy()).setUseCompoundFile(false);
+
+    String BIG="alskjhlaksjghlaksjfhalksvjepgjioefgjnsdfjgefgjhelkgjhqewlrkhgwlekgrhwelkgjhwelkgrhwlkejg";
+    BIG=BIG+BIG+BIG+BIG;
+
+    for (int i=0; i<2; i++) {
+      Document doc = new Document();
+      doc.add(new Field("id", Integer.toString(i)+BIG, Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
+      doc.add(new Field("str", Integer.toString(i)+BIG, Field.Store.YES, Field.Index.NOT_ANALYZED));
+      doc.add(new Field("str2", Integer.toString(i)+BIG, Field.Store.YES, Field.Index.ANALYZED));
+      doc.add(new Field("str3", Integer.toString(i)+BIG, Field.Store.YES, Field.Index.ANALYZED_NO_NORMS));
+      indexWriter.addDocument(doc);
+    }
+
+    indexWriter.close();
+
+    assertNoUnreferencedFiles(dir, "no tv files");
+    String[] files = dir.listAll();
+    for(String file : files) {
+      assertTrue(!file.endsWith(IndexFileNames.VECTORS_FIELDS_EXTENSION));
+      assertTrue(!file.endsWith(IndexFileNames.VECTORS_INDEX_EXTENSION));
+      assertTrue(!file.endsWith(IndexFileNames.VECTORS_DOCUMENTS_EXTENSION));
+    }
+
+    dir.close();
+  }
+
+  static final class StringSplitAnalyzer extends Analyzer {
+    @Override
+    public TokenStream tokenStream(String fieldName, Reader reader) {
+      return new StringSplitTokenizer(reader);
+    }
+  }
+
+  private static class StringSplitTokenizer extends Tokenizer {
+    private String[] tokens;
+    private int upto;
+    private final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class);
+
+    public StringSplitTokenizer(Reader r) {
+      try {
+        reset(r);
+      } catch (IOException e) {
+        throw new RuntimeException(e);
+      }
+    }
+
+    @Override
+    public final boolean incrementToken() throws IOException {
+      clearAttributes();      
+      if (upto < tokens.length) {
+        termAtt.setEmpty();
+        termAtt.append(tokens[upto]);
+        upto++;
+        return true;
+      } else {
+        return false;
+      }
+    }
+
+    @Override
+    public void reset(Reader input) throws IOException {
+       this.upto = 0;
+       final StringBuilder b = new StringBuilder();
+       final char[] buffer = new char[1024];
+       int n;
+       while ((n = input.read(buffer)) != -1) {
+         b.append(buffer, 0, n);
+       }
+       this.tokens = b.toString().split(" ");
+    }
+  }
+
+  // LUCENE-3183
+  public void testEmptyFieldNameTIIOne() throws IOException {
+    Directory dir = newDirectory();
+    IndexWriterConfig iwc = newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random));
+    iwc.setTermIndexInterval(1);
+    iwc.setReaderTermsIndexDivisor(1);
+    IndexWriter writer = new IndexWriter(dir, iwc);
+    Document doc = new Document();
+    doc.add(newField("", "a b c", Field.Store.NO, Field.Index.ANALYZED));
+    writer.addDocument(doc);
+    final IndexReader r = IndexReader.open(writer, true);
+    writer.close();
+    r.terms(new Term("", ""));
+    r.terms(new Term("", ""));
+    r.terms(new Term("", "a"));
+    r.terms(new Term("", ""));
+    r.close();
+    dir.close();
+  }
+
+  public void testDeleteAllNRTLeftoverFiles() throws Exception {
+
+    Directory d = new MockDirectoryWrapper(random, new RAMDirectory());
+    IndexWriter w = new IndexWriter(d, new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)));
+    Document doc = new Document();
+    for(int i = 0; i < 20; i++) {
+      for(int j = 0; j < 100; ++j) {
+        w.addDocument(doc);
+      }
+      w.commit();
+      IndexReader.open(w, true).close();
+
+      w.deleteAll();
+      w.commit();
+
+      // Make sure we accumulate no files except for empty
+      // segments_N and segments.gen:
+      assertTrue(d.listAll().length <= 2);
+    }
+
+    w.close();
+    d.close();
+  }
+}