add --shared
[pylucene.git] / lucene-java-3.4.0 / lucene / src / test / org / apache / lucene / index / TestIndexWriter.java
1 package org.apache.lucene.index;
2
3 /**
4  * Licensed to the Apache Software Foundation (ASF) under one or more
5  * contributor license agreements.  See the NOTICE file distributed with
6  * this work for additional information regarding copyright ownership.
7  * The ASF licenses this file to You under the Apache License, Version 2.0
8  * (the "License"); you may not use this file except in compliance with
9  * the License.  You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 import java.io.ByteArrayOutputStream;
21 import java.io.IOException;
22 import java.io.PrintStream;
23 import java.io.Reader;
24 import java.io.StringReader;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.HashMap;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Random;
32 import java.util.Collections;
33
34 import org.apache.lucene.util.LuceneTestCase;
35 import org.apache.lucene.analysis.Analyzer;
36 import org.apache.lucene.analysis.MockAnalyzer;
37 import org.apache.lucene.analysis.TokenStream;
38 import org.apache.lucene.analysis.Tokenizer;
39 import org.apache.lucene.analysis.WhitespaceAnalyzer;
40 import org.apache.lucene.analysis.WhitespaceTokenizer;
41 import org.apache.lucene.analysis.standard.StandardAnalyzer;
42 import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
43 import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
44 import org.apache.lucene.document.Document;
45 import org.apache.lucene.document.Field;
46 import org.apache.lucene.document.Fieldable;
47 import org.apache.lucene.document.Field.Index;
48 import org.apache.lucene.document.Field.Store;
49 import org.apache.lucene.document.Field.TermVector;
50 import org.apache.lucene.index.IndexWriterConfig.OpenMode;
51 import org.apache.lucene.search.TopDocs;
52 import org.apache.lucene.search.IndexSearcher;
53 import org.apache.lucene.search.PhraseQuery;
54 import org.apache.lucene.search.Query;
55 import org.apache.lucene.search.ScoreDoc;
56 import org.apache.lucene.search.TermQuery;
57 import org.apache.lucene.search.spans.SpanTermQuery;
58 import org.apache.lucene.store.AlreadyClosedException;
59 import org.apache.lucene.store.Directory;
60 import org.apache.lucene.store.IndexOutput;
61 import org.apache.lucene.store.Lock;
62 import org.apache.lucene.store.LockFactory;
63 import org.apache.lucene.store.NoLockFactory;
64 import org.apache.lucene.store.MockDirectoryWrapper;
65 import org.apache.lucene.store.RAMDirectory;
66 import org.apache.lucene.store.SingleInstanceLockFactory;
67 import org.apache.lucene.util._TestUtil;
68 import org.apache.lucene.util.ThreadInterruptedException;
69
70 public class TestIndexWriter extends LuceneTestCase {
71
72     public void testDocCount() throws IOException {
73         Directory dir = newDirectory();
74
75         IndexWriter writer = null;
76         IndexReader reader = null;
77         int i;
78
79         long savedWriteLockTimeout = IndexWriterConfig.getDefaultWriteLockTimeout();
80         try {
81           IndexWriterConfig.setDefaultWriteLockTimeout(2000);
82           assertEquals(2000, IndexWriterConfig.getDefaultWriteLockTimeout());
83           writer  = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
84         } finally {
85           IndexWriterConfig.setDefaultWriteLockTimeout(savedWriteLockTimeout);
86         }
87
88         // add 100 documents
89         for (i = 0; i < 100; i++) {
90             addDoc(writer);
91         }
92         assertEquals(100, writer.maxDoc());
93         writer.close();
94
95         // delete 40 documents
96         reader = IndexReader.open(dir, false);
97         for (i = 0; i < 40; i++) {
98             reader.deleteDocument(i);
99         }
100         reader.close();
101
102         reader = IndexReader.open(dir, true);
103         assertEquals(60, reader.numDocs());
104         reader.close();
105
106         // optimize the index and check that the new doc count is correct
107         writer = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
108         assertEquals(60, writer.numDocs());
109         writer.optimize();
110         assertEquals(60, writer.maxDoc());
111         assertEquals(60, writer.numDocs());
112         writer.close();
113
114         // check that the index reader gives the same numbers.
115         reader = IndexReader.open(dir, true);
116         assertEquals(60, reader.maxDoc());
117         assertEquals(60, reader.numDocs());
118         reader.close();
119
120         // make sure opening a new index for create over
121         // this existing one works correctly:
122         writer = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)).setOpenMode(OpenMode.CREATE));
123         assertEquals(0, writer.maxDoc());
124         assertEquals(0, writer.numDocs());
125         writer.close();
126         dir.close();
127     }
128
129     static void addDoc(IndexWriter writer) throws IOException
130     {
131         Document doc = new Document();
132         doc.add(newField("content", "aaa", Field.Store.NO, Field.Index.ANALYZED));
133         writer.addDocument(doc);
134     }
135
136     static void addDocWithIndex(IndexWriter writer, int index) throws IOException
137     {
138         Document doc = new Document();
139         doc.add(newField("content", "aaa " + index, Field.Store.YES, Field.Index.ANALYZED));
140         doc.add(newField("id", "" + index, Field.Store.YES, Field.Index.ANALYZED));
141         writer.addDocument(doc);
142     }                            
143
144     public static void assertNoUnreferencedFiles(Directory dir, String message) throws IOException {
145       String[] startFiles = dir.listAll();
146       SegmentInfos infos = new SegmentInfos();
147       infos.read(dir);
148       new IndexWriter(dir, new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random))).rollback();
149       String[] endFiles = dir.listAll();
150
151       Arrays.sort(startFiles);
152       Arrays.sort(endFiles);
153
154       if (!Arrays.equals(startFiles, endFiles)) {
155         fail(message + ": before delete:\n    " + arrayToString(startFiles) + "\n  after delete:\n    " + arrayToString(endFiles));
156       }
157     }
158
159     /**
160      * Make sure we skip wicked long terms.
161     */
162     public void testWickedLongTerm() throws IOException {
163       MockDirectoryWrapper dir = newDirectory();
164       IndexWriter writer = new IndexWriter(dir, new IndexWriterConfig(
165         TEST_VERSION_CURRENT, new StandardAnalyzer(TEST_VERSION_CURRENT)));
166
167       char[] chars = new char[DocumentsWriter.CHAR_BLOCK_SIZE-1];
168       Arrays.fill(chars, 'x');
169       Document doc = new Document();
170       final String bigTerm = new String(chars);
171
172       // Max length term is 16383, so this contents produces
173       // a too-long term:
174       String contents = "abc xyz x" + bigTerm + " another term";
175       doc.add(new Field("content", contents, Field.Store.NO, Field.Index.ANALYZED));
176       writer.addDocument(doc);
177
178       // Make sure we can add another normal document
179       doc = new Document();
180       doc.add(new Field("content", "abc bbb ccc", Field.Store.NO, Field.Index.ANALYZED));
181       writer.addDocument(doc);
182       writer.close();
183
184       IndexReader reader = IndexReader.open(dir, true);
185
186       // Make sure all terms < max size were indexed
187       assertEquals(2, reader.docFreq(new Term("content", "abc")));
188       assertEquals(1, reader.docFreq(new Term("content", "bbb")));
189       assertEquals(1, reader.docFreq(new Term("content", "term")));
190       assertEquals(1, reader.docFreq(new Term("content", "another")));
191
192       // Make sure position is still incremented when
193       // massive term is skipped:
194       TermPositions tps = reader.termPositions(new Term("content", "another"));
195       assertTrue(tps.next());
196       assertEquals(1, tps.freq());
197       assertEquals(3, tps.nextPosition());
198
199       // Make sure the doc that has the massive term is in
200       // the index:
201       assertEquals("document with wicked long term should is not in the index!", 2, reader.numDocs());
202
203       reader.close();
204
205       // Make sure we can add a document with exactly the
206       // maximum length term, and search on that term:
207       doc = new Document();
208       doc.add(new Field("content", bigTerm, Field.Store.NO, Field.Index.ANALYZED));
209       StandardAnalyzer sa = new StandardAnalyzer(TEST_VERSION_CURRENT);
210       sa.setMaxTokenLength(100000);
211       writer  = new IndexWriter(dir, new IndexWriterConfig(TEST_VERSION_CURRENT, sa));
212       writer.addDocument(doc);
213       writer.close();
214       reader = IndexReader.open(dir, true);
215       assertEquals(1, reader.docFreq(new Term("content", bigTerm)));
216       reader.close();
217
218       dir.close();
219     }
220
221     static String arrayToString(String[] l) {
222       String s = "";
223       for(int i=0;i<l.length;i++) {
224         if (i > 0) {
225           s += "\n    ";
226         }
227         s += l[i];
228       }
229       return s;
230     }
231
232     // Make sure we can open an index for create even when a
233     // reader holds it open (this fails pre lock-less
234     // commits on windows):
235     public void testCreateWithReader() throws IOException {
236       Directory dir = newDirectory();
237       
238       // add one document & close writer
239       IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
240       addDoc(writer);
241       writer.close();
242       
243       // now open reader:
244       IndexReader reader = IndexReader.open(dir, true);
245       assertEquals("should be one document", reader.numDocs(), 1);
246       
247       // now open index for create:
248       writer = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)).setOpenMode(OpenMode.CREATE));
249       assertEquals("should be zero documents", writer.maxDoc(), 0);
250       addDoc(writer);
251       writer.close();
252       
253       assertEquals("should be one document", reader.numDocs(), 1);
254       IndexReader reader2 = IndexReader.open(dir, true);
255       assertEquals("should be one document", reader2.numDocs(), 1);
256       reader.close();
257       reader2.close();
258       
259       dir.close();
260     }
261
262     public void testChangesAfterClose() throws IOException {
263         Directory dir = newDirectory();
264
265         IndexWriter writer = null;
266
267         writer  = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
268         addDoc(writer);
269
270         // close
271         writer.close();
272         try {
273           addDoc(writer);
274           fail("did not hit AlreadyClosedException");
275         } catch (AlreadyClosedException e) {
276           // expected
277         }
278         dir.close();
279     }
280
281     public void testIndexNoDocuments() throws IOException {
282       MockDirectoryWrapper dir = newDirectory();      
283       IndexWriter writer  = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
284       writer.commit();
285       writer.close();
286
287       IndexReader reader = IndexReader.open(dir, true);
288       assertEquals(0, reader.maxDoc());
289       assertEquals(0, reader.numDocs());
290       reader.close();
291
292       writer  = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)).setOpenMode(OpenMode.APPEND));
293       writer.commit();
294       writer.close();
295
296       reader = IndexReader.open(dir, true);
297       assertEquals(0, reader.maxDoc());
298       assertEquals(0, reader.numDocs());
299       reader.close();
300       dir.close();
301     }
302
303     public void testManyFields() throws IOException {
304       MockDirectoryWrapper dir = newDirectory();      
305       IndexWriter writer  = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)).setMaxBufferedDocs(10));
306       for(int j=0;j<100;j++) {
307         Document doc = new Document();
308         doc.add(newField("a"+j, "aaa" + j, Field.Store.YES, Field.Index.ANALYZED));
309         doc.add(newField("b"+j, "aaa" + j, Field.Store.YES, Field.Index.ANALYZED));
310         doc.add(newField("c"+j, "aaa" + j, Field.Store.YES, Field.Index.ANALYZED));
311         doc.add(newField("d"+j, "aaa", Field.Store.YES, Field.Index.ANALYZED));
312         doc.add(newField("e"+j, "aaa", Field.Store.YES, Field.Index.ANALYZED));
313         doc.add(newField("f"+j, "aaa", Field.Store.YES, Field.Index.ANALYZED));
314         writer.addDocument(doc);
315       }
316       writer.close();
317
318       IndexReader reader = IndexReader.open(dir, true);
319       assertEquals(100, reader.maxDoc());
320       assertEquals(100, reader.numDocs());
321       for(int j=0;j<100;j++) {
322         assertEquals(1, reader.docFreq(new Term("a"+j, "aaa"+j)));
323         assertEquals(1, reader.docFreq(new Term("b"+j, "aaa"+j)));
324         assertEquals(1, reader.docFreq(new Term("c"+j, "aaa"+j)));
325         assertEquals(1, reader.docFreq(new Term("d"+j, "aaa")));
326         assertEquals(1, reader.docFreq(new Term("e"+j, "aaa")));
327         assertEquals(1, reader.docFreq(new Term("f"+j, "aaa")));
328       }
329       reader.close();
330       dir.close();
331     }
332
333     public void testSmallRAMBuffer() throws IOException {
334       MockDirectoryWrapper dir = newDirectory();      
335       IndexWriter writer  = new IndexWriter(
336           dir,
337           newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)).
338               setRAMBufferSizeMB(0.000001).
339               setMergePolicy(newLogMergePolicy(10))
340       );
341       int lastNumFile = dir.listAll().length;
342       for(int j=0;j<9;j++) {
343         Document doc = new Document();
344         doc.add(newField("field", "aaa" + j, Field.Store.YES, Field.Index.ANALYZED));
345         writer.addDocument(doc);
346         int numFile = dir.listAll().length;
347         // Verify that with a tiny RAM buffer we see new
348         // segment after every doc
349         assertTrue(numFile > lastNumFile);
350         lastNumFile = numFile;
351       }
352       writer.close();
353       dir.close();
354     }
355
356     /**
357      * Make sure it's OK to change RAM buffer size and // maxBufferedDocs in a
358      * write session
359      * 
360      * @deprecated after all the setters on IW go away (4.0), this test can be
361      *             removed because changing ram buffer settings during a write
362      *             session won't be possible.
363      */
364     @Deprecated
365     public void testChangingRAMBuffer() throws IOException {
366       MockDirectoryWrapper dir = newDirectory();      
367       IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig(
368         TEST_VERSION_CURRENT, new MockAnalyzer(random)).setMaxBufferedDocs(10).setRAMBufferSizeMB(
369         IndexWriterConfig.DISABLE_AUTO_FLUSH));
370
371       int lastFlushCount = -1;
372       for(int j=1;j<52;j++) {
373         Document doc = new Document();
374         doc.add(newField("field", "aaa" + j, Field.Store.YES, Field.Index.ANALYZED));
375         writer.addDocument(doc);
376         _TestUtil.syncConcurrentMerges(writer);
377         int flushCount = writer.getFlushCount();
378         if (j == 1)
379           lastFlushCount = flushCount;
380         else if (j < 10)
381           // No new files should be created
382           assertEquals(flushCount, lastFlushCount);
383         else if (10 == j) {
384           assertTrue(flushCount > lastFlushCount);
385           lastFlushCount = flushCount;
386           writer.setRAMBufferSizeMB(0.000001);
387           writer.setMaxBufferedDocs(IndexWriterConfig.DISABLE_AUTO_FLUSH);
388         } else if (j < 20) {
389           assertTrue(flushCount > lastFlushCount);
390           lastFlushCount = flushCount;
391         } else if (20 == j) {
392           writer.setRAMBufferSizeMB(16);
393           writer.setMaxBufferedDocs(IndexWriterConfig.DISABLE_AUTO_FLUSH);
394           lastFlushCount = flushCount;
395         } else if (j < 30) {
396           assertEquals(flushCount, lastFlushCount);
397         } else if (30 == j) {
398           writer.setRAMBufferSizeMB(0.000001);
399           writer.setMaxBufferedDocs(IndexWriterConfig.DISABLE_AUTO_FLUSH);
400         } else if (j < 40) {
401           assertTrue(flushCount> lastFlushCount);
402           lastFlushCount = flushCount;
403         } else if (40 == j) {
404           writer.setMaxBufferedDocs(10);
405           writer.setRAMBufferSizeMB(IndexWriterConfig.DISABLE_AUTO_FLUSH);
406           lastFlushCount = flushCount;
407         } else if (j < 50) {
408           assertEquals(flushCount, lastFlushCount);
409           writer.setMaxBufferedDocs(10);
410           writer.setRAMBufferSizeMB(IndexWriterConfig.DISABLE_AUTO_FLUSH);
411         } else if (50 == j) {
412           assertTrue(flushCount > lastFlushCount);
413         }
414       }
415       writer.close();
416       dir.close();
417     }
418
419     /**
420      * @deprecated after setters on IW go away, this test can be deleted because
421      *             changing those settings on IW won't be possible.
422      */
423     @Deprecated
424     public void testChangingRAMBuffer2() throws IOException {
425       MockDirectoryWrapper dir = newDirectory();      
426       IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig(
427         TEST_VERSION_CURRENT, new WhitespaceAnalyzer(TEST_VERSION_CURRENT)).setMaxBufferedDocs(10).setMaxBufferedDeleteTerms(
428         10).setRAMBufferSizeMB(IndexWriterConfig.DISABLE_AUTO_FLUSH));
429
430       for(int j=1;j<52;j++) {
431         Document doc = new Document();
432         doc.add(newField("field", "aaa" + j, Field.Store.YES, Field.Index.ANALYZED));
433         writer.addDocument(doc);
434       }
435       
436       int lastFlushCount = -1;
437       for(int j=1;j<52;j++) {
438         writer.deleteDocuments(new Term("field", "aaa" + j));
439         _TestUtil.syncConcurrentMerges(writer);
440         int flushCount = writer.getFlushCount();
441         if (j == 1)
442           lastFlushCount = flushCount;
443         else if (j < 10) {
444           // No new files should be created
445           assertEquals(flushCount, lastFlushCount);
446         } else if (10 == j) {
447           assertTrue(flushCount > lastFlushCount);
448           lastFlushCount = flushCount;
449           writer.setRAMBufferSizeMB(0.000001);
450           writer.setMaxBufferedDeleteTerms(1);
451         } else if (j < 20) {
452           assertTrue(flushCount > lastFlushCount);
453           lastFlushCount = flushCount;
454         } else if (20 == j) {
455           writer.setRAMBufferSizeMB(16);
456           writer.setMaxBufferedDeleteTerms(IndexWriterConfig.DISABLE_AUTO_FLUSH);
457           lastFlushCount = flushCount;
458         } else if (j < 30) {
459           assertEquals(flushCount, lastFlushCount);
460         } else if (30 == j) {
461           writer.setRAMBufferSizeMB(0.000001);
462           writer.setMaxBufferedDeleteTerms(IndexWriterConfig.DISABLE_AUTO_FLUSH);
463           writer.setMaxBufferedDeleteTerms(1);
464         } else if (j < 40) {
465           assertTrue(flushCount> lastFlushCount);
466           lastFlushCount = flushCount;
467         } else if (40 == j) {
468           writer.setMaxBufferedDeleteTerms(10);
469           writer.setRAMBufferSizeMB(IndexWriterConfig.DISABLE_AUTO_FLUSH);
470           lastFlushCount = flushCount;
471         } else if (j < 50) {
472           assertEquals(flushCount, lastFlushCount);
473           writer.setMaxBufferedDeleteTerms(10);
474           writer.setRAMBufferSizeMB(IndexWriterConfig.DISABLE_AUTO_FLUSH);
475         } else if (50 == j) {
476           assertTrue(flushCount > lastFlushCount);
477         }
478       }
479       writer.close();
480       dir.close();
481     }
482
483     // Make sure it's OK to change RAM buffer size and
484     // maxBufferedDocs in a write session, using IW.getConfig()
485     public void testChangingRAMBufferWithIWC() throws IOException {
486       Directory dir = newDirectory();      
487       IndexWriter writer  = new IndexWriter(dir, newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)));
488       writer.getConfig().setMaxBufferedDocs(10);
489       writer.getConfig().setRAMBufferSizeMB(IndexWriterConfig.DISABLE_AUTO_FLUSH);
490
491       int lastFlushCount = -1;
492       for(int j=1;j<52;j++) {
493         Document doc = new Document();
494         doc.add(new Field("field", "aaa" + j, Field.Store.YES, Field.Index.ANALYZED));
495         writer.addDocument(doc);
496         _TestUtil.syncConcurrentMerges(writer);
497         int flushCount = writer.getFlushCount();
498         if (j == 1)
499           lastFlushCount = flushCount;
500         else if (j < 10)
501           // No new files should be created
502           assertEquals(flushCount, lastFlushCount);
503         else if (10 == j) {
504           assertTrue(flushCount > lastFlushCount);
505           lastFlushCount = flushCount;
506           writer.getConfig().setRAMBufferSizeMB(0.000001);
507           writer.getConfig().setMaxBufferedDocs(IndexWriterConfig.DISABLE_AUTO_FLUSH);
508         } else if (j < 20) {
509           assertTrue(flushCount > lastFlushCount);
510           lastFlushCount = flushCount;
511         } else if (20 == j) {
512           writer.getConfig().setRAMBufferSizeMB(16);
513           writer.getConfig().setMaxBufferedDocs(IndexWriterConfig.DISABLE_AUTO_FLUSH);
514           lastFlushCount = flushCount;
515         } else if (j < 30) {
516           assertEquals(flushCount, lastFlushCount);
517         } else if (30 == j) {
518           writer.getConfig().setRAMBufferSizeMB(0.000001);
519           writer.getConfig().setMaxBufferedDocs(IndexWriterConfig.DISABLE_AUTO_FLUSH);
520         } else if (j < 40) {
521           assertTrue(flushCount> lastFlushCount);
522           lastFlushCount = flushCount;
523         } else if (40 == j) {
524           writer.getConfig().setMaxBufferedDocs(10);
525           writer.getConfig().setRAMBufferSizeMB(IndexWriterConfig.DISABLE_AUTO_FLUSH);
526           lastFlushCount = flushCount;
527         } else if (j < 50) {
528           assertEquals(flushCount, lastFlushCount);
529           writer.getConfig().setMaxBufferedDocs(10);
530           writer.getConfig().setRAMBufferSizeMB(IndexWriterConfig.DISABLE_AUTO_FLUSH);
531         } else if (50 == j) {
532           assertTrue(flushCount > lastFlushCount);
533         }
534       }
535       writer.close();
536       dir.close();
537     }
538
539     public void testChangingRAMBuffer2WithIWC() throws IOException {
540       Directory dir = newDirectory();      
541       IndexWriter writer  = new IndexWriter(dir, newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)));
542       writer.getConfig().setMaxBufferedDocs(10);
543       writer.getConfig().setMaxBufferedDeleteTerms(10);
544       writer.getConfig().setRAMBufferSizeMB(IndexWriterConfig.DISABLE_AUTO_FLUSH);
545
546       for(int j=1;j<52;j++) {
547         Document doc = new Document();
548         doc.add(new Field("field", "aaa" + j, Field.Store.YES, Field.Index.ANALYZED));
549         writer.addDocument(doc);
550       }
551       
552       int lastFlushCount = -1;
553       for(int j=1;j<52;j++) {
554         writer.deleteDocuments(new Term("field", "aaa" + j));
555         _TestUtil.syncConcurrentMerges(writer);
556         int flushCount = writer.getFlushCount();
557         if (j == 1)
558           lastFlushCount = flushCount;
559         else if (j < 10) {
560           // No new files should be created
561           assertEquals(flushCount, lastFlushCount);
562         } else if (10 == j) {
563           assertTrue(flushCount > lastFlushCount);
564           lastFlushCount = flushCount;
565           writer.getConfig().setRAMBufferSizeMB(0.000001);
566           writer.getConfig().setMaxBufferedDeleteTerms(1);
567         } else if (j < 20) {
568           assertTrue(flushCount > lastFlushCount);
569           lastFlushCount = flushCount;
570         } else if (20 == j) {
571           writer.getConfig().setRAMBufferSizeMB(16);
572           writer.getConfig().setMaxBufferedDeleteTerms(IndexWriterConfig.DISABLE_AUTO_FLUSH);
573           lastFlushCount = flushCount;
574         } else if (j < 30) {
575           assertEquals(flushCount, lastFlushCount);
576         } else if (30 == j) {
577           writer.getConfig().setRAMBufferSizeMB(0.000001);
578           writer.getConfig().setMaxBufferedDeleteTerms(IndexWriterConfig.DISABLE_AUTO_FLUSH);
579           writer.getConfig().setMaxBufferedDeleteTerms(1);
580         } else if (j < 40) {
581           assertTrue(flushCount> lastFlushCount);
582           lastFlushCount = flushCount;
583         } else if (40 == j) {
584           writer.getConfig().setMaxBufferedDeleteTerms(10);
585           writer.getConfig().setRAMBufferSizeMB(IndexWriterConfig.DISABLE_AUTO_FLUSH);
586           lastFlushCount = flushCount;
587         } else if (j < 50) {
588           assertEquals(flushCount, lastFlushCount);
589           writer.getConfig().setMaxBufferedDeleteTerms(10);
590           writer.getConfig().setRAMBufferSizeMB(IndexWriterConfig.DISABLE_AUTO_FLUSH);
591         } else if (50 == j) {
592           assertTrue(flushCount > lastFlushCount);
593         }
594       }
595       writer.close();
596       dir.close();
597     }
598
599     public void testDiverseDocs() throws IOException {
600       MockDirectoryWrapper dir = newDirectory();      
601       IndexWriter writer  = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)).setRAMBufferSizeMB(0.5));
602       for(int i=0;i<3;i++) {
603         // First, docs where every term is unique (heavy on
604         // Posting instances)
605         for(int j=0;j<100;j++) {
606           Document doc = new Document();
607           for(int k=0;k<100;k++) {
608             doc.add(newField("field", Integer.toString(random.nextInt()), Field.Store.YES, Field.Index.ANALYZED));
609           }
610           writer.addDocument(doc);
611         }
612
613         // Next, many single term docs where only one term
614         // occurs (heavy on byte blocks)
615         for(int j=0;j<100;j++) {
616           Document doc = new Document();
617           doc.add(newField("field", "aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa", Field.Store.YES, Field.Index.ANALYZED));
618           writer.addDocument(doc);
619         }
620
621         // Next, many single term docs where only one term
622         // occurs but the terms are very long (heavy on
623         // char[] arrays)
624         for(int j=0;j<100;j++) {
625           StringBuilder b = new StringBuilder();
626           String x = Integer.toString(j) + ".";
627           for(int k=0;k<1000;k++)
628             b.append(x);
629           String longTerm = b.toString();
630
631           Document doc = new Document();
632           doc.add(newField("field", longTerm, Field.Store.YES, Field.Index.ANALYZED));
633           writer.addDocument(doc);
634         }
635       }
636       writer.close();
637
638       IndexSearcher searcher = new IndexSearcher(dir, false);
639       ScoreDoc[] hits = searcher.search(new TermQuery(new Term("field", "aaa")), null, 1000).scoreDocs;
640       assertEquals(300, hits.length);
641       searcher.close();
642
643       dir.close();
644     }
645
646     public void testEnablingNorms() throws IOException {
647       MockDirectoryWrapper dir = newDirectory();      
648       IndexWriter writer  = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)).setMaxBufferedDocs(10));
649       // Enable norms for only 1 doc, pre flush
650       for(int j=0;j<10;j++) {
651         Document doc = new Document();
652         Field f = newField("field", "aaa", Field.Store.YES, Field.Index.ANALYZED); 
653         if (j != 8) {
654           f.setOmitNorms(true);
655         }
656         doc.add(f);
657         writer.addDocument(doc);
658       }
659       writer.close();
660
661       Term searchTerm = new Term("field", "aaa");
662
663       IndexSearcher searcher = new IndexSearcher(dir, false);
664       ScoreDoc[] hits = searcher.search(new TermQuery(searchTerm), null, 1000).scoreDocs;
665       assertEquals(10, hits.length);
666       searcher.close();
667
668       writer = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random))
669         .setOpenMode(OpenMode.CREATE).setMaxBufferedDocs(10));
670       // Enable norms for only 1 doc, post flush
671       for(int j=0;j<27;j++) {
672         Document doc = new Document();
673         Field f = newField("field", "aaa", Field.Store.YES, Field.Index.ANALYZED); 
674         if (j != 26) {
675           f.setOmitNorms(true);
676         }
677         doc.add(f);
678         writer.addDocument(doc);
679       }
680       writer.close();
681       searcher = new IndexSearcher(dir, false);
682       hits = searcher.search(new TermQuery(searchTerm), null, 1000).scoreDocs;
683       assertEquals(27, hits.length);
684       searcher.close();
685
686       IndexReader reader = IndexReader.open(dir, true);
687       reader.close();
688
689       dir.close();
690     }
691
692     public void testHighFreqTerm() throws IOException {
693       MockDirectoryWrapper dir = newDirectory();      
694       IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig(
695           TEST_VERSION_CURRENT, new MockAnalyzer(random)).setRAMBufferSizeMB(0.01));
696       // Massive doc that has 128 K a's
697       StringBuilder b = new StringBuilder(1024*1024);
698       for(int i=0;i<4096;i++) {
699         b.append(" a a a a a a a a");
700         b.append(" a a a a a a a a");
701         b.append(" a a a a a a a a");
702         b.append(" a a a a a a a a");
703       }
704       Document doc = new Document();
705       doc.add(newField("field", b.toString(), Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
706       writer.addDocument(doc);
707       writer.close();
708
709       IndexReader reader = IndexReader.open(dir, true);
710       assertEquals(1, reader.maxDoc());
711       assertEquals(1, reader.numDocs());
712       Term t = new Term("field", "a");
713       assertEquals(1, reader.docFreq(t));
714       TermDocs td = reader.termDocs(t);
715       td.next();
716       assertEquals(128*1024, td.freq());
717       reader.close();
718       dir.close();
719     }
720
721     // Make sure that a Directory implementation that does
722     // not use LockFactory at all (ie overrides makeLock and
723     // implements its own private locking) works OK.  This
724     // was raised on java-dev as loss of backwards
725     // compatibility.
726     public void testNullLockFactory() throws IOException {
727
728       final class MyRAMDirectory extends MockDirectoryWrapper {
729         private LockFactory myLockFactory;
730         MyRAMDirectory(Directory delegate) {
731           super(random, delegate);
732           lockFactory = null;
733           myLockFactory = new SingleInstanceLockFactory();
734         }
735         @Override
736         public Lock makeLock(String name) {
737           return myLockFactory.makeLock(name);
738         }
739       }
740       
741       Directory dir = new MyRAMDirectory(new RAMDirectory());
742       IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig(
743         TEST_VERSION_CURRENT, new MockAnalyzer(random)));
744       for (int i = 0; i < 100; i++) {
745         addDoc(writer);
746       }
747       writer.close();
748       Term searchTerm = new Term("content", "aaa");        
749       IndexSearcher searcher = new IndexSearcher(dir, false);
750       ScoreDoc[] hits = searcher.search(new TermQuery(searchTerm), null, 1000).scoreDocs;
751       assertEquals("did not get right number of hits", 100, hits.length);
752       searcher.close();
753
754       writer = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random))
755         .setOpenMode(OpenMode.CREATE));
756       writer.close();
757       searcher.close();
758       dir.close();
759     }
760
761     public void testFlushWithNoMerging() throws IOException {
762       Directory dir = newDirectory();
763       IndexWriter writer = new IndexWriter(
764           dir,
765           newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)).
766               setMaxBufferedDocs(2).
767               setMergePolicy(newLogMergePolicy(10))
768       );
769       Document doc = new Document();
770       doc.add(newField("field", "aaa", Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
771       for(int i=0;i<19;i++)
772         writer.addDocument(doc);
773       writer.flush(false, true);
774       writer.close();
775       SegmentInfos sis = new SegmentInfos();
776       sis.read(dir);
777       // Since we flushed w/o allowing merging we should now
778       // have 10 segments
779       assertEquals(10, sis.size());
780       dir.close();
781     }
782
783     // Make sure we can flush segment w/ norms, then add
784     // empty doc (no norms) and flush
785     public void testEmptyDocAfterFlushingRealDoc() throws IOException {
786       Directory dir = newDirectory();
787       IndexWriter writer  = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
788       writer.setInfoStream(VERBOSE ? System.out : null);
789       Document doc = new Document();
790       doc.add(newField("field", "aaa", Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
791       writer.addDocument(doc);
792       writer.commit();
793       if (VERBOSE) {
794         System.out.println("\nTEST: now add empty doc");
795       }
796       writer.addDocument(new Document());
797       writer.close();
798       IndexReader reader = IndexReader.open(dir, true);
799       assertEquals(2, reader.numDocs());
800       reader.close();
801       dir.close();
802     }
803
804   /**
805    * Test that no NullPointerException will be raised,
806    * when adding one document with a single, empty field
807    * and term vectors enabled.
808    * @throws IOException
809    *
810    */
811   public void testBadSegment() throws IOException {
812     Directory dir = newDirectory();
813     IndexWriter iw = new IndexWriter(dir, newIndexWriterConfig(
814         TEST_VERSION_CURRENT, new MockAnalyzer(random)));
815    
816     Document document = new Document();
817     document.add(newField("tvtest", "", Store.NO, Index.ANALYZED, TermVector.YES));
818     iw.addDocument(document);
819     iw.close();
820     dir.close();
821   }
822
823   // LUCENE-1036
824   public void testMaxThreadPriority() throws IOException {
825     int pri = Thread.currentThread().getPriority();
826     try {
827       Directory dir = newDirectory();
828       IndexWriterConfig conf = newIndexWriterConfig(
829           TEST_VERSION_CURRENT, new MockAnalyzer(random))
830         .setMaxBufferedDocs(2).setMergePolicy(newLogMergePolicy());
831       ((LogMergePolicy) conf.getMergePolicy()).setMergeFactor(2);
832       IndexWriter iw = new IndexWriter(dir, conf);
833       Document document = new Document();
834       document.add(newField("tvtest", "a b c", Field.Store.NO, Field.Index.ANALYZED,
835                              Field.TermVector.YES));
836       Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
837       for(int i=0;i<4;i++)
838         iw.addDocument(document);
839       iw.close();
840       dir.close();
841     } finally {
842       Thread.currentThread().setPriority(pri);
843     }
844   }
845
846   // Just intercepts all merges & verifies that we are never
847   // merging a segment with >= 20 (maxMergeDocs) docs
848   private class MyMergeScheduler extends MergeScheduler {
849     @Override
850     synchronized public void merge(IndexWriter writer)
851       throws CorruptIndexException, IOException {
852
853       while(true) {
854         MergePolicy.OneMerge merge = writer.getNextMerge();
855         if (merge == null) {
856           break;
857         }
858         for(int i=0;i<merge.segments.size();i++) {
859           assert merge.segments.get(i).docCount < 20;
860         }
861         writer.merge(merge);
862       }
863     }
864
865     @Override
866     public void close() {}
867   }
868
869   public void testVariableSchema() throws Exception {
870     Directory dir = newDirectory();
871     int delID = 0;
872     for(int i=0;i<20;i++) {
873       if (VERBOSE) {
874         System.out.println("TEST: iter=" + i);
875       }
876       IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)).setMaxBufferedDocs(2).setMergePolicy(newLogMergePolicy()));
877       writer.setInfoStream(VERBOSE ? System.out : null);
878       //LogMergePolicy lmp = (LogMergePolicy) writer.getConfig().getMergePolicy();
879       //lmp.setMergeFactor(2);
880       //lmp.setUseCompoundFile(false);
881       Document doc = new Document();
882       String contents = "aa bb cc dd ee ff gg hh ii jj kk";
883
884       if (i == 7) {
885         // Add empty docs here
886         doc.add(newField("content3", "", Field.Store.NO,
887                           Field.Index.ANALYZED));
888       } else {
889         Field.Store storeVal;
890         if (i%2 == 0) {
891           doc.add(newField("content4", contents, Field.Store.YES,
892                             Field.Index.ANALYZED));
893           storeVal = Field.Store.YES;
894         } else
895           storeVal = Field.Store.NO;
896         doc.add(newField("content1", contents, storeVal,
897                           Field.Index.ANALYZED));
898         doc.add(newField("content3", "", Field.Store.YES,
899                           Field.Index.ANALYZED));
900         doc.add(newField("content5", "", storeVal,
901                           Field.Index.ANALYZED));
902       }
903
904       for(int j=0;j<4;j++)
905         writer.addDocument(doc);
906
907       writer.close();
908       IndexReader reader = IndexReader.open(dir, false);
909       reader.deleteDocument(delID++);
910       reader.close();
911
912       if (0 == i % 4) {
913         writer = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
914         //LogMergePolicy lmp2 = (LogMergePolicy) writer.getConfig().getMergePolicy();
915         //lmp2.setUseCompoundFile(false);
916         writer.optimize();
917         writer.close();
918       }
919     }
920     dir.close();
921   }
922
923   public void testNoWaitClose() throws Throwable {
924     Directory directory = newDirectory();
925
926     final Document doc = new Document();
927     Field idField = newField("id", "", Field.Store.YES, Field.Index.NOT_ANALYZED);
928     doc.add(idField);
929
930     for(int pass=0;pass<2;pass++) {
931       if (VERBOSE) {
932         System.out.println("TEST: pass=" + pass);
933       }
934
935       IndexWriterConfig conf = newIndexWriterConfig(
936           TEST_VERSION_CURRENT, new MockAnalyzer(random)).setOpenMode(OpenMode.CREATE)
937           .setMaxBufferedDocs(2).setMergePolicy(newLogMergePolicy());
938       if (pass == 2) {
939         conf.setMergeScheduler(new SerialMergeScheduler());
940       }
941       IndexWriter writer = new IndexWriter(directory, conf);
942       ((LogMergePolicy) writer.getConfig().getMergePolicy()).setMergeFactor(100);
943       writer.setInfoStream(VERBOSE ? System.out : null);
944
945       // have to use compound file to prevent running out of
946       // descripters when newDirectory returns a file-system
947       // backed directory:
948       ((LogMergePolicy) writer.getConfig().getMergePolicy()).setUseCompoundFile(true);
949       
950       for(int iter=0;iter<10;iter++) {
951         if (VERBOSE) {
952           System.out.println("TEST: iter=" + iter);
953         }
954         for(int j=0;j<199;j++) {
955           idField.setValue(Integer.toString(iter*201+j));
956           writer.addDocument(doc);
957         }
958
959         int delID = iter*199;
960         for(int j=0;j<20;j++) {
961           writer.deleteDocuments(new Term("id", Integer.toString(delID)));
962           delID += 5;
963         }
964
965         // Force a bunch of merge threads to kick off so we
966         // stress out aborting them on close:
967         ((LogMergePolicy) writer.getConfig().getMergePolicy()).setMergeFactor(2);
968
969         final IndexWriter finalWriter = writer;
970         final ArrayList<Throwable> failure = new ArrayList<Throwable>();
971         Thread t1 = new Thread() {
972             @Override
973             public void run() {
974               boolean done = false;
975               while(!done) {
976                 for(int i=0;i<100;i++) {
977                   try {
978                     finalWriter.addDocument(doc);
979                   } catch (AlreadyClosedException e) {
980                     done = true;
981                     break;
982                   } catch (NullPointerException e) {
983                     done = true;
984                     break;
985                   } catch (Throwable e) {
986                     e.printStackTrace(System.out);
987                     failure.add(e);
988                     done = true;
989                     break;
990                   }
991                 }
992                 Thread.yield();
993               }
994
995             }
996           };
997
998         if (failure.size() > 0) {
999           throw failure.get(0);
1000         }
1001
1002         t1.start();
1003
1004         writer.close(false);
1005         t1.join();
1006
1007         // Make sure reader can read
1008         IndexReader reader = IndexReader.open(directory, true);
1009         reader.close();
1010
1011         // Reopen
1012         writer = new IndexWriter(directory, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)).setOpenMode(OpenMode.APPEND).setMergePolicy(newLogMergePolicy()));
1013         writer.setInfoStream(VERBOSE ? System.out : null);
1014       }
1015       writer.close();
1016     }
1017
1018     directory.close();
1019   }
1020
1021   // LUCENE-1084: test unlimited field length
1022   public void testUnlimitedMaxFieldLength() throws IOException {
1023     Directory dir = newDirectory();
1024
1025     IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
1026
1027     Document doc = new Document();
1028     StringBuilder b = new StringBuilder();
1029     for(int i=0;i<10000;i++)
1030       b.append(" a");
1031     b.append(" x");
1032     doc.add(newField("field", b.toString(), Field.Store.NO, Field.Index.ANALYZED));
1033     writer.addDocument(doc);
1034     writer.close();
1035
1036     IndexReader reader = IndexReader.open(dir, true);
1037     Term t = new Term("field", "x");
1038     assertEquals(1, reader.docFreq(t));
1039     reader.close();
1040     dir.close();
1041   }
1042
1043   // LUCENE-1084: test user-specified field length
1044   public void testUserSpecifiedMaxFieldLength() throws IOException {
1045     Directory dir = newDirectory();
1046
1047     IndexWriter writer = new IndexWriter(dir, new IndexWriterConfig(
1048         TEST_VERSION_CURRENT, new WhitespaceAnalyzer(TEST_VERSION_CURRENT)));
1049     writer.setMaxFieldLength(100000);
1050
1051     Document doc = new Document();
1052     StringBuilder b = new StringBuilder();
1053     for(int i=0;i<10000;i++)
1054       b.append(" a");
1055     b.append(" x");
1056     doc.add(newField("field", b.toString(), Field.Store.NO, Field.Index.ANALYZED));
1057     writer.addDocument(doc);
1058     writer.close();
1059
1060     IndexReader reader = IndexReader.open(dir, true);
1061     Term t = new Term("field", "x");
1062     assertEquals(1, reader.docFreq(t));
1063     reader.close();
1064     dir.close();
1065   }
1066
1067   // LUCENE-1179
1068   public void testEmptyFieldName() throws IOException {
1069     Directory dir = newDirectory();
1070     IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
1071     Document doc = new Document();
1072     doc.add(newField("", "a b c", Field.Store.NO, Field.Index.ANALYZED));
1073     writer.addDocument(doc);
1074     writer.close();
1075     dir.close();
1076   }
1077
1078
1079
1080   private static final class MockIndexWriter extends IndexWriter {
1081
1082     public MockIndexWriter(Directory dir, IndexWriterConfig conf) throws IOException {
1083       super(dir, conf);
1084     }
1085
1086     boolean afterWasCalled;
1087     boolean beforeWasCalled;
1088
1089     @Override
1090     public void doAfterFlush() {
1091       afterWasCalled = true;
1092     }
1093     
1094     @Override
1095     protected void doBeforeFlush() throws IOException {
1096       beforeWasCalled = true;
1097     }
1098   }
1099   
1100
1101   // LUCENE-1222
1102   public void testDoBeforeAfterFlush() throws IOException {
1103     Directory dir = newDirectory();
1104     MockIndexWriter w = new MockIndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
1105     Document doc = new Document();
1106     doc.add(newField("field", "a field", Field.Store.YES,
1107                       Field.Index.ANALYZED));
1108     w.addDocument(doc);
1109     w.commit();
1110     assertTrue(w.beforeWasCalled);
1111     assertTrue(w.afterWasCalled);
1112     w.beforeWasCalled = false;
1113     w.afterWasCalled = false;
1114     w.deleteDocuments(new Term("field", "field"));
1115     w.commit();
1116     assertTrue(w.beforeWasCalled);
1117     assertTrue(w.afterWasCalled);
1118     w.close();
1119
1120     IndexReader ir = IndexReader.open(dir, true);
1121     assertEquals(0, ir.numDocs());
1122     ir.close();
1123
1124     dir.close();
1125   }
1126
1127   // LUCENE-1255
1128   public void testNegativePositions() throws Throwable {
1129     final TokenStream tokens = new TokenStream() {
1130       final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class);
1131       final PositionIncrementAttribute posIncrAtt = addAttribute(PositionIncrementAttribute.class);
1132       
1133       final Iterator<String> terms = Arrays.asList("a","b","c").iterator();
1134       boolean first = true;
1135       
1136       @Override
1137       public boolean incrementToken() {
1138         if (!terms.hasNext()) return false;
1139         clearAttributes();
1140         termAtt.append(terms.next());
1141         posIncrAtt.setPositionIncrement(first ? 0 : 1);
1142         first = false;
1143         return true;
1144       }
1145     };
1146
1147     Directory dir = newDirectory();
1148     IndexWriter w = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
1149     Document doc = new Document();
1150     doc.add(new Field("field", tokens));
1151     w.addDocument(doc);
1152     w.commit();
1153
1154     IndexSearcher s = new IndexSearcher(dir, false);
1155     PhraseQuery pq = new PhraseQuery();
1156     pq.add(new Term("field", "a"));
1157     pq.add(new Term("field", "b"));
1158     pq.add(new Term("field", "c"));
1159     ScoreDoc[] hits = s.search(pq, null, 1000).scoreDocs;
1160     assertEquals(1, hits.length);
1161
1162     Query q = new SpanTermQuery(new Term("field", "a"));
1163     hits = s.search(q, null, 1000).scoreDocs;
1164     assertEquals(1, hits.length);
1165     TermPositions tps = s.getIndexReader().termPositions(new Term("field", "a"));
1166     assertTrue(tps.next());
1167     assertEquals(1, tps.freq());
1168     assertEquals(0, tps.nextPosition());
1169     w.close();
1170
1171     s.close();
1172     dir.close();
1173   }
1174
1175   // LUCENE-1219
1176   public void testBinaryFieldOffsetLength() throws IOException {
1177     Directory dir = newDirectory();
1178     IndexWriter w = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
1179     byte[] b = new byte[50];
1180     for(int i=0;i<50;i++)
1181       b[i] = (byte) (i+77);
1182     
1183     Document doc = new Document();
1184     Field f = new Field("binary", b, 10, 17);
1185     byte[] bx = f.getBinaryValue();
1186     assertTrue(bx != null);
1187     assertEquals(50, bx.length);
1188     assertEquals(10, f.getBinaryOffset());
1189     assertEquals(17, f.getBinaryLength());
1190     doc.add(f);
1191     w.addDocument(doc);
1192     w.close();
1193
1194     IndexReader ir = IndexReader.open(dir, true);
1195     doc = ir.document(0);
1196     f = doc.getField("binary");
1197     b = f.getBinaryValue();
1198     assertTrue(b != null);
1199     assertEquals(17, b.length, 17);
1200     assertEquals(87, b[0]);
1201     ir.close();
1202     dir.close();
1203   }
1204
1205   // LUCENE-2529
1206   public void testPositionIncrementGapEmptyField() throws Exception {
1207     Directory dir = newDirectory();
1208     Analyzer analyzer = new Analyzer(){
1209       Analyzer a = new WhitespaceAnalyzer( TEST_VERSION_CURRENT );
1210       @Override
1211       public TokenStream tokenStream(String fieldName, Reader reader){
1212         return a.tokenStream(fieldName, reader);
1213       }
1214       @Override
1215       public int getPositionIncrementGap(String fieldName) {
1216         return 100;
1217       }
1218     };
1219     IndexWriter w = new IndexWriter(dir, newIndexWriterConfig( 
1220         TEST_VERSION_CURRENT, analyzer));
1221     Document doc = new Document();
1222     Field f = newField("field", "", Field.Store.NO,
1223                         Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS);
1224     Field f2 = newField("field", "crunch man", Field.Store.NO,
1225         Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS);
1226     doc.add(f);
1227     doc.add(f2);
1228     w.addDocument(doc);
1229     w.close();
1230
1231     IndexReader r = IndexReader.open(dir, true);
1232     TermPositionVector tpv = ((TermPositionVector) r.getTermFreqVector(0, "field"));
1233     int[] poss = tpv.getTermPositions(0);
1234     assertEquals(1, poss.length);
1235     assertEquals(100, poss[0]);
1236     poss = tpv.getTermPositions(1);
1237     assertEquals(1, poss.length);
1238     assertEquals(101, poss[0]);
1239     r.close();
1240     dir.close();
1241   }
1242
1243
1244   // LUCENE-1468 -- make sure opening an IndexWriter with
1245   // create=true does not remove non-index files
1246   
1247   public void testOtherFiles() throws Throwable {
1248     Directory dir = newDirectory();
1249     try {
1250       // Create my own random file:
1251       IndexOutput out = dir.createOutput("myrandomfile");
1252       out.writeByte((byte) 42);
1253       out.close();
1254
1255       new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random))).close();
1256
1257       assertTrue(dir.fileExists("myrandomfile"));
1258
1259       // Make sure this does not copy myrandomfile:
1260       Directory dir2 = new MockDirectoryWrapper(random, new RAMDirectory(dir));
1261       assertTrue(!dir2.fileExists("myrandomfile"));
1262       dir2.close();
1263     } finally {
1264       dir.close();
1265     }
1266   }
1267
1268   public void testDeadlock() throws Exception {
1269     Directory dir = newDirectory();
1270     IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)).setMaxBufferedDocs(2));
1271     Document doc = new Document();
1272     doc.add(newField("content", "aaa bbb ccc ddd eee fff ggg hhh iii", Field.Store.YES,
1273                       Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
1274     writer.addDocument(doc);
1275     writer.addDocument(doc);
1276     writer.addDocument(doc);
1277     writer.commit();
1278     // index has 2 segments
1279
1280     Directory dir2 = newDirectory();
1281     IndexWriter writer2 = new IndexWriter(dir2, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
1282     writer2.addDocument(doc);
1283     writer2.close();
1284
1285     IndexReader r1 = IndexReader.open(dir2, true);
1286     IndexReader r2 = (IndexReader) r1.clone();
1287     writer.addIndexes(new IndexReader[] {r1, r2});
1288     writer.close();
1289
1290     IndexReader r3 = IndexReader.open(dir, true);
1291     assertEquals(5, r3.numDocs());
1292     r3.close();
1293
1294     r1.close();
1295     r2.close();
1296
1297     dir2.close();
1298     dir.close();
1299   }
1300
1301   private class IndexerThreadInterrupt extends Thread {
1302     volatile boolean failed;
1303     volatile boolean finish;
1304
1305     volatile boolean allowInterrupt = false;
1306
1307     @Override
1308     public void run() {
1309       // LUCENE-2239: won't work with NIOFS/MMAP
1310       Directory dir = new MockDirectoryWrapper(random, new RAMDirectory()); 
1311       IndexWriter w = null;
1312       while(!finish) {
1313         try {
1314
1315           while(!finish) {
1316             if (w != null) {
1317               w.close();
1318               w = null;
1319             }
1320             IndexWriterConfig conf = newIndexWriterConfig( 
1321                                                           TEST_VERSION_CURRENT, new MockAnalyzer(random)).setMaxBufferedDocs(2);
1322             w = new IndexWriter(dir, conf);
1323             w.setInfoStream(VERBOSE ? System.out : null);
1324
1325             Document doc = new Document();
1326             doc.add(newField("field", "some text contents", Field.Store.YES, Field.Index.ANALYZED));
1327             for(int i=0;i<100;i++) {
1328               w.addDocument(doc);
1329               if (i%10 == 0) {
1330                 w.commit();
1331               }
1332             }
1333             w.close();
1334             w = null;
1335             _TestUtil.checkIndex(dir);
1336             IndexReader.open(dir, true).close();
1337
1338             // Strangely, if we interrupt a thread before
1339             // all classes are loaded, the class loader
1340             // seems to do scary things with the interrupt
1341             // status.  In java 1.5, it'll throw an
1342             // incorrect ClassNotFoundException.  In java
1343             // 1.6, it'll silently clear the interrupt.
1344             // So, on first iteration through here we
1345             // don't open ourselves up for interrupts
1346             // until we've done the above loop.
1347             allowInterrupt = true;
1348           }
1349         } catch (ThreadInterruptedException re) {
1350           if (VERBOSE) {
1351             System.out.println("TEST: got interrupt");
1352             re.printStackTrace(System.out);
1353           }
1354           Throwable e = re.getCause();
1355           assertTrue(e instanceof InterruptedException);
1356           if (finish) {
1357             break;
1358           }
1359         } catch (Throwable t) {
1360           System.out.println("FAILED; unexpected exception");
1361           t.printStackTrace(System.out);
1362           failed = true;
1363           break;
1364         }
1365       }
1366
1367       if (!failed) {
1368         // clear interrupt state:
1369         Thread.interrupted();
1370         if (w != null) {
1371           try {
1372             w.rollback();
1373           } catch (IOException ioe) {
1374             throw new RuntimeException(ioe);
1375           }
1376         }
1377
1378         try {
1379           _TestUtil.checkIndex(dir);
1380         } catch (Exception e) {
1381           failed = true;
1382           System.out.println("CheckIndex FAILED: unexpected exception");
1383           e.printStackTrace(System.out);
1384         }
1385         try {
1386           IndexReader r = IndexReader.open(dir, true);
1387           //System.out.println("doc count=" + r.numDocs());
1388           r.close();
1389         } catch (Exception e) {
1390           failed = true;
1391           System.out.println("IndexReader.open FAILED: unexpected exception");
1392           e.printStackTrace(System.out);
1393         }
1394       }
1395       try { 
1396         dir.close();
1397       } catch (IOException e) { 
1398         throw new RuntimeException(e); 
1399       }
1400     }
1401   }
1402
1403   public void testThreadInterruptDeadlock() throws Exception {
1404     IndexerThreadInterrupt t = new IndexerThreadInterrupt();
1405     t.setDaemon(true);
1406     t.start();
1407
1408     // Force class loader to load ThreadInterruptedException
1409     // up front... else we can see a false failure if 2nd
1410     // interrupt arrives while class loader is trying to
1411     // init this class (in servicing a first interrupt):
1412     assertTrue(new ThreadInterruptedException(new InterruptedException()).getCause() instanceof InterruptedException);
1413     
1414     // issue 100 interrupts to child thread
1415     int i = 0;
1416     while(i < 100) {
1417       Thread.sleep(10);
1418       if (t.allowInterrupt) {
1419         i++;
1420         t.interrupt();
1421       }
1422       if (!t.isAlive()) {
1423         break;
1424       }
1425     }
1426     t.finish = true;
1427     t.join();
1428     assertFalse(t.failed);
1429   }
1430
1431
1432   public void testIndexStoreCombos() throws Exception {
1433     Directory dir = newDirectory();
1434     IndexWriter w = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
1435     byte[] b = new byte[50];
1436     for(int i=0;i<50;i++)
1437       b[i] = (byte) (i+77);
1438
1439     Document doc = new Document();
1440     Field f = new Field("binary", b, 10, 17);
1441     f.setTokenStream(new WhitespaceTokenizer(TEST_VERSION_CURRENT, new StringReader("doc1field1")));
1442     Field f2 = newField("string", "value", Field.Store.YES,Field.Index.ANALYZED);
1443     f2.setTokenStream(new WhitespaceTokenizer(TEST_VERSION_CURRENT, new StringReader("doc1field2")));
1444     doc.add(f);
1445     doc.add(f2);
1446     w.addDocument(doc);
1447     
1448     // add 2 docs to test in-memory merging
1449     f.setTokenStream(new WhitespaceTokenizer(TEST_VERSION_CURRENT, new StringReader("doc2field1")));
1450     f2.setTokenStream(new WhitespaceTokenizer(TEST_VERSION_CURRENT, new StringReader("doc2field2")));
1451     w.addDocument(doc);
1452   
1453     // force segment flush so we can force a segment merge with doc3 later.
1454     w.commit();
1455
1456     f.setTokenStream(new WhitespaceTokenizer(TEST_VERSION_CURRENT, new StringReader("doc3field1")));
1457     f2.setTokenStream(new WhitespaceTokenizer(TEST_VERSION_CURRENT, new StringReader("doc3field2")));
1458
1459     w.addDocument(doc);
1460     w.commit();
1461     w.optimize();   // force segment merge.
1462     w.close();
1463
1464     IndexReader ir = IndexReader.open(dir, true);
1465     doc = ir.document(0);
1466     f = doc.getField("binary");
1467     b = f.getBinaryValue();
1468     assertTrue(b != null);
1469     assertEquals(17, b.length, 17);
1470     assertEquals(87, b[0]);
1471
1472     assertTrue(ir.document(0).getFieldable("binary").isBinary());
1473     assertTrue(ir.document(1).getFieldable("binary").isBinary());
1474     assertTrue(ir.document(2).getFieldable("binary").isBinary());
1475     
1476     assertEquals("value", ir.document(0).get("string"));
1477     assertEquals("value", ir.document(1).get("string"));
1478     assertEquals("value", ir.document(2).get("string"));
1479
1480
1481     // test that the terms were indexed.
1482     assertTrue(ir.termDocs(new Term("binary","doc1field1")).next());
1483     assertTrue(ir.termDocs(new Term("binary","doc2field1")).next());
1484     assertTrue(ir.termDocs(new Term("binary","doc3field1")).next());
1485     assertTrue(ir.termDocs(new Term("string","doc1field2")).next());
1486     assertTrue(ir.termDocs(new Term("string","doc2field2")).next());
1487     assertTrue(ir.termDocs(new Term("string","doc3field2")).next());
1488
1489     ir.close();
1490     dir.close();
1491
1492   }
1493
1494   // LUCENE-1727: make sure doc fields are stored in order
1495   public void testStoredFieldsOrder() throws Throwable {
1496     Directory d = newDirectory();
1497     IndexWriter w = new IndexWriter(d, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
1498     Document doc = new Document();
1499     doc.add(newField("zzz", "a b c", Field.Store.YES, Field.Index.NO));
1500     doc.add(newField("aaa", "a b c", Field.Store.YES, Field.Index.NO));
1501     doc.add(newField("zzz", "1 2 3", Field.Store.YES, Field.Index.NO));
1502     w.addDocument(doc);
1503     IndexReader r = w.getReader();
1504     doc = r.document(0);
1505     Iterator<Fieldable> it = doc.getFields().iterator();
1506     assertTrue(it.hasNext());
1507     Field f = (Field) it.next();
1508     assertEquals(f.name(), "zzz");
1509     assertEquals(f.stringValue(), "a b c");
1510
1511     assertTrue(it.hasNext());
1512     f = (Field) it.next();
1513     assertEquals(f.name(), "aaa");
1514     assertEquals(f.stringValue(), "a b c");
1515
1516     assertTrue(it.hasNext());
1517     f = (Field) it.next();
1518     assertEquals(f.name(), "zzz");
1519     assertEquals(f.stringValue(), "1 2 3");
1520     assertFalse(it.hasNext());
1521     r.close();
1522     w.close();
1523     d.close();
1524   }
1525
1526   public void testNoDocsIndex() throws Throwable {
1527     Directory dir = newDirectory();
1528     IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig( 
1529         TEST_VERSION_CURRENT, new MockAnalyzer(random)));
1530     ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
1531     writer.setInfoStream(new PrintStream(bos));
1532     writer.addDocument(new Document());
1533     writer.close();
1534
1535     dir.close();
1536   }
1537
1538   public void testDeleteUnusedFiles() throws Exception {
1539
1540     for(int iter=0;iter<2;iter++) {
1541       Directory dir = newDirectory();
1542
1543       LogMergePolicy mergePolicy = newLogMergePolicy(true);
1544       mergePolicy.setNoCFSRatio(1); // This test expects all of its segments to be in CFS
1545
1546       IndexWriter w = new IndexWriter(
1547           dir,
1548           newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)).
1549               setMergePolicy(mergePolicy)
1550       );
1551       Document doc = new Document();
1552       doc.add(newField("field", "go", Field.Store.NO, Field.Index.ANALYZED));
1553       w.addDocument(doc);
1554       IndexReader r;
1555       if (iter == 0) {
1556         // use NRT
1557         r = w.getReader();
1558       } else {
1559         // don't use NRT
1560         w.commit();
1561         r = IndexReader.open(dir);
1562       }
1563
1564       List<String> files = Arrays.asList(dir.listAll());
1565       assertTrue(files.contains("_0.cfs"));
1566       w.addDocument(doc);
1567       w.optimize();
1568       if (iter == 1) {
1569         w.commit();
1570       }
1571       IndexReader r2 = r.reopen();
1572       assertTrue(r != r2);
1573       files = Arrays.asList(dir.listAll());
1574
1575       // NOTE: here we rely on "Windows" behavior, ie, even
1576       // though IW wanted to delete _0.cfs since it was
1577       // optimized away, because we have a reader open
1578       // against this file, it should still be here:
1579       assertTrue(files.contains("_0.cfs"));
1580       // optimize created this
1581       //assertTrue(files.contains("_2.cfs"));
1582       w.deleteUnusedFiles();
1583
1584       files = Arrays.asList(dir.listAll());
1585       // r still holds this file open
1586       assertTrue(files.contains("_0.cfs"));
1587       //assertTrue(files.contains("_2.cfs"));
1588
1589       r.close();
1590       if (iter == 0) {
1591         // on closing NRT reader, it calls writer.deleteUnusedFiles
1592         files = Arrays.asList(dir.listAll());
1593         assertFalse(files.contains("_0.cfs"));
1594       } else {
1595         // now writer can remove it
1596         w.deleteUnusedFiles();
1597         files = Arrays.asList(dir.listAll());
1598         assertFalse(files.contains("_0.cfs"));
1599       }
1600       //assertTrue(files.contains("_2.cfs"));
1601
1602       w.close();
1603       r2.close();
1604
1605       dir.close();
1606     }
1607   }
1608
1609   public void testDeleteUnsedFiles2() throws Exception {
1610     // Validates that iw.deleteUnusedFiles() also deletes unused index commits
1611     // in case a deletion policy which holds onto commits is used.
1612     Directory dir = newDirectory();
1613     SnapshotDeletionPolicy sdp = new SnapshotDeletionPolicy(new KeepOnlyLastCommitDeletionPolicy());
1614     IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig( 
1615         TEST_VERSION_CURRENT, new MockAnalyzer(random))
1616         .setIndexDeletionPolicy(sdp));
1617     
1618     // First commit
1619     Document doc = new Document();
1620     doc.add(newField("c", "val", Store.YES, Index.ANALYZED, TermVector.WITH_POSITIONS_OFFSETS));
1621     writer.addDocument(doc);
1622     writer.commit();
1623     assertEquals(1, IndexReader.listCommits(dir).size());
1624
1625     // Keep that commit
1626     sdp.snapshot("id");
1627     
1628     // Second commit - now KeepOnlyLastCommit cannot delete the prev commit.
1629     doc = new Document();
1630     doc.add(newField("c", "val", Store.YES, Index.ANALYZED, TermVector.WITH_POSITIONS_OFFSETS));
1631     writer.addDocument(doc);
1632     writer.commit();
1633     assertEquals(2, IndexReader.listCommits(dir).size());
1634
1635     // Should delete the unreferenced commit
1636     sdp.release("id");
1637     writer.deleteUnusedFiles();
1638     assertEquals(1, IndexReader.listCommits(dir).size());
1639     
1640     writer.close();
1641     dir.close();
1642   }
1643   
1644   private static class FlushCountingIndexWriter extends IndexWriter {
1645     int flushCount;
1646     public FlushCountingIndexWriter(Directory dir, IndexWriterConfig iwc) throws IOException {
1647       super(dir, iwc);
1648     }
1649     @Override
1650     public void doAfterFlush() {
1651       flushCount++;
1652     }
1653   }
1654
1655   public void testEmptyFSDirWithNoLock() throws Exception {
1656     // Tests that if FSDir is opened w/ a NoLockFactory (or SingleInstanceLF),
1657     // then IndexWriter ctor succeeds. Previously (LUCENE-2386) it failed 
1658     // when listAll() was called in IndexFileDeleter.
1659     Directory dir = newFSDirectory(_TestUtil.getTempDir("emptyFSDirNoLock"), NoLockFactory.getNoLockFactory());
1660     new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random))).close();
1661     dir.close();
1662   }
1663
1664   public void testEmptyDirRollback() throws Exception {
1665     // Tests that if IW is created over an empty Directory, some documents are
1666     // indexed, flushed (but not committed) and then IW rolls back, then no 
1667     // files are left in the Directory.
1668     Directory dir = newDirectory();
1669     IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig( 
1670         TEST_VERSION_CURRENT, new MockAnalyzer(random))
1671                                          .setMaxBufferedDocs(2).setMergePolicy(newLogMergePolicy()));
1672     String[] files = dir.listAll();
1673
1674     writer.setInfoStream(VERBOSE ? System.out : null);
1675
1676     // Creating over empty dir should not create any files,
1677     // or, at most the write.lock file
1678     final int extraFileCount;
1679     if (files.length == 1) {
1680       assertTrue(files[0].endsWith("write.lock"));
1681       extraFileCount = 1;
1682     } else {
1683       assertEquals(0, files.length);
1684       extraFileCount = 0;
1685     }
1686
1687     Document doc = new Document();
1688     // create as many files as possible
1689     doc.add(newField("c", "val", Store.YES, Index.ANALYZED, TermVector.WITH_POSITIONS_OFFSETS));
1690     writer.addDocument(doc);
1691     // Adding just one document does not call flush yet.
1692     assertEquals("only the stored and term vector files should exist in the directory", 5 + extraFileCount, dir.listAll().length);
1693     
1694     doc = new Document();
1695     doc.add(newField("c", "val", Store.YES, Index.ANALYZED, TermVector.WITH_POSITIONS_OFFSETS));
1696     writer.addDocument(doc);
1697
1698     // The second document should cause a flush.
1699     assertTrue("flush should have occurred and files should have been created", dir.listAll().length > 5 + extraFileCount);
1700
1701     // After rollback, IW should remove all files
1702     writer.rollback();
1703     assertEquals("no files should exist in the directory after rollback", 0, dir.listAll().length);
1704
1705     // Since we rolled-back above, that close should be a no-op
1706     writer.close();
1707     assertEquals("expected a no-op close after IW.rollback()", 0, dir.listAll().length);
1708     dir.close();
1709   }
1710
1711   public void testNoSegmentFile() throws IOException {
1712     Directory dir = newDirectory();
1713     dir.setLockFactory(NoLockFactory.getNoLockFactory());
1714     IndexWriter w = new IndexWriter(dir, newIndexWriterConfig( 
1715         TEST_VERSION_CURRENT, new MockAnalyzer(random)).setMaxBufferedDocs(2));
1716     
1717     Document doc = new Document();
1718     doc.add(newField("c", "val", Store.YES, Index.ANALYZED, TermVector.WITH_POSITIONS_OFFSETS));
1719     w.addDocument(doc);
1720     w.addDocument(doc);
1721     IndexWriter w2 = new IndexWriter(dir, newIndexWriterConfig( 
1722         TEST_VERSION_CURRENT, new MockAnalyzer(random)).setMaxBufferedDocs(2)
1723         .setOpenMode(OpenMode.CREATE));
1724     
1725     w2.close();
1726     w.rollback();
1727     dir.close();
1728   }
1729
1730   public void testRandomStoredFields() throws IOException {
1731     Directory dir = newDirectory();
1732     Random rand = random;
1733     RandomIndexWriter w = new RandomIndexWriter(rand, dir, newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)).setMaxBufferedDocs(_TestUtil.nextInt(rand, 5, 20)));
1734     //w.w.setInfoStream(System.out);
1735     //w.w.setUseCompoundFile(false);
1736     if (VERBOSE) {
1737       w.w.setInfoStream(System.out);
1738     }
1739     final int docCount = atLeast(200);
1740     final int fieldCount = _TestUtil.nextInt(rand, 1, 5);
1741       
1742     final List<Integer> fieldIDs = new ArrayList<Integer>();
1743
1744     Field idField = newField("id", "", Field.Store.YES, Field.Index.NOT_ANALYZED);
1745
1746     for(int i=0;i<fieldCount;i++) {
1747       fieldIDs.add(i);
1748     }
1749
1750     final Map<String,Document> docs = new HashMap<String,Document>();
1751     
1752     if (VERBOSE) {
1753       System.out.println("TEST: build index docCount=" + docCount);
1754     }
1755
1756     for(int i=0;i<docCount;i++) {
1757       Document doc = new Document();
1758       doc.add(idField);
1759       final String id = ""+i;
1760       idField.setValue(id);
1761       docs.put(id, doc);
1762
1763       for(int field: fieldIDs) {
1764         final String s;
1765         if (rand.nextInt(4) != 3) {
1766           s = _TestUtil.randomUnicodeString(rand, 1000);
1767           doc.add(newField("f"+field, s, Field.Store.YES, Field.Index.NO));
1768         } else {
1769           s = null;
1770         }
1771       }
1772       w.addDocument(doc);
1773       if (rand.nextInt(50) == 17) {
1774         // mixup binding of field name -> Number every so often
1775         Collections.shuffle(fieldIDs);
1776       }
1777       if (rand.nextInt(5) == 3 && i > 0) {
1778         final String delID = ""+rand.nextInt(i);
1779         if (VERBOSE) {
1780           System.out.println("TEST: delete doc " + delID);
1781         }
1782         w.deleteDocuments(new Term("id", delID));
1783         docs.remove(delID);
1784       }
1785     }
1786
1787     if (VERBOSE) {
1788       System.out.println("TEST: " + docs.size() + " docs in index; now load fields");
1789     }
1790     if (docs.size() > 0) {
1791       String[] idsList = docs.keySet().toArray(new String[docs.size()]);
1792
1793       for(int x=0;x<2;x++) {
1794         IndexReader r = w.getReader();
1795         IndexSearcher s = newSearcher(r);
1796
1797         if (VERBOSE) {
1798           System.out.println("TEST: cycle x=" + x + " r=" + r);
1799         }
1800
1801         int num = atLeast(1000);
1802         for(int iter=0;iter<num;iter++) {
1803           String testID = idsList[rand.nextInt(idsList.length)];
1804           TopDocs hits = s.search(new TermQuery(new Term("id", testID)), 1);
1805           assertEquals(1, hits.totalHits);
1806           Document doc = r.document(hits.scoreDocs[0].doc);
1807           Document docExp = docs.get(testID);
1808           for(int i=0;i<fieldCount;i++) {
1809             assertEquals("doc " + testID + ", field f" + fieldCount + " is wrong", docExp.get("f"+i),  doc.get("f"+i));
1810           }
1811         }
1812         s.close();
1813         r.close();
1814         w.optimize();
1815       }
1816     }
1817     w.close();
1818     dir.close();
1819   }
1820
1821   public void testNoUnwantedTVFiles() throws Exception {
1822
1823     Directory dir = newDirectory();
1824     IndexWriter indexWriter = new IndexWriter(dir, newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)).setRAMBufferSizeMB(0.01).setMergePolicy(newLogMergePolicy()));
1825     ((LogMergePolicy) indexWriter.getConfig().getMergePolicy()).setUseCompoundFile(false);
1826
1827     String BIG="alskjhlaksjghlaksjfhalksvjepgjioefgjnsdfjgefgjhelkgjhqewlrkhgwlekgrhwelkgjhwelkgrhwlkejg";
1828     BIG=BIG+BIG+BIG+BIG;
1829
1830     for (int i=0; i<2; i++) {
1831       Document doc = new Document();
1832       doc.add(new Field("id", Integer.toString(i)+BIG, Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
1833       doc.add(new Field("str", Integer.toString(i)+BIG, Field.Store.YES, Field.Index.NOT_ANALYZED));
1834       doc.add(new Field("str2", Integer.toString(i)+BIG, Field.Store.YES, Field.Index.ANALYZED));
1835       doc.add(new Field("str3", Integer.toString(i)+BIG, Field.Store.YES, Field.Index.ANALYZED_NO_NORMS));
1836       indexWriter.addDocument(doc);
1837     }
1838
1839     indexWriter.close();
1840
1841     assertNoUnreferencedFiles(dir, "no tv files");
1842     String[] files = dir.listAll();
1843     for(String file : files) {
1844       assertTrue(!file.endsWith(IndexFileNames.VECTORS_FIELDS_EXTENSION));
1845       assertTrue(!file.endsWith(IndexFileNames.VECTORS_INDEX_EXTENSION));
1846       assertTrue(!file.endsWith(IndexFileNames.VECTORS_DOCUMENTS_EXTENSION));
1847     }
1848
1849     dir.close();
1850   }
1851
1852   static final class StringSplitAnalyzer extends Analyzer {
1853     @Override
1854     public TokenStream tokenStream(String fieldName, Reader reader) {
1855       return new StringSplitTokenizer(reader);
1856     }
1857   }
1858
1859   private static class StringSplitTokenizer extends Tokenizer {
1860     private String[] tokens;
1861     private int upto;
1862     private final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class);
1863
1864     public StringSplitTokenizer(Reader r) {
1865       try {
1866         reset(r);
1867       } catch (IOException e) {
1868         throw new RuntimeException(e);
1869       }
1870     }
1871
1872     @Override
1873     public final boolean incrementToken() throws IOException {
1874       clearAttributes();      
1875       if (upto < tokens.length) {
1876         termAtt.setEmpty();
1877         termAtt.append(tokens[upto]);
1878         upto++;
1879         return true;
1880       } else {
1881         return false;
1882       }
1883     }
1884
1885     @Override
1886     public void reset(Reader input) throws IOException {
1887        this.upto = 0;
1888        final StringBuilder b = new StringBuilder();
1889        final char[] buffer = new char[1024];
1890        int n;
1891        while ((n = input.read(buffer)) != -1) {
1892          b.append(buffer, 0, n);
1893        }
1894        this.tokens = b.toString().split(" ");
1895     }
1896   }
1897
1898   // LUCENE-3183
1899   public void testEmptyFieldNameTIIOne() throws IOException {
1900     Directory dir = newDirectory();
1901     IndexWriterConfig iwc = newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random));
1902     iwc.setTermIndexInterval(1);
1903     iwc.setReaderTermsIndexDivisor(1);
1904     IndexWriter writer = new IndexWriter(dir, iwc);
1905     Document doc = new Document();
1906     doc.add(newField("", "a b c", Field.Store.NO, Field.Index.ANALYZED));
1907     writer.addDocument(doc);
1908     final IndexReader r = IndexReader.open(writer, true);
1909     writer.close();
1910     r.terms(new Term("", ""));
1911     r.terms(new Term("", ""));
1912     r.terms(new Term("", "a"));
1913     r.terms(new Term("", ""));
1914     r.close();
1915     dir.close();
1916   }
1917
1918   public void testDeleteAllNRTLeftoverFiles() throws Exception {
1919
1920     Directory d = new MockDirectoryWrapper(random, new RAMDirectory());
1921     IndexWriter w = new IndexWriter(d, new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)));
1922     Document doc = new Document();
1923     for(int i = 0; i < 20; i++) {
1924       for(int j = 0; j < 100; ++j) {
1925         w.addDocument(doc);
1926       }
1927       w.commit();
1928       IndexReader.open(w, true).close();
1929
1930       w.deleteAll();
1931       w.commit();
1932
1933       // Make sure we accumulate no files except for empty
1934       // segments_N and segments.gen:
1935       assertTrue(d.listAll().length <= 2);
1936     }
1937
1938     w.close();
1939     d.close();
1940   }
1941 }