add --shared
[pylucene.git] / lucene-java-3.4.0 / lucene / backwards / src / test-framework / org / apache / lucene / index / RandomIndexWriter.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.Closeable;
21 import java.io.IOException;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.Random;
25
26 import org.apache.lucene.analysis.Analyzer;
27 import org.apache.lucene.analysis.MockAnalyzer;
28 import org.apache.lucene.document.Document;
29 import org.apache.lucene.index.IndexWriter; // javadoc
30 import org.apache.lucene.store.Directory;
31 import org.apache.lucene.util.LuceneTestCase;
32 import org.apache.lucene.util.Version;
33 import org.apache.lucene.util._TestUtil;
34
35 /** Silly class that randomizes the indexing experience.  EG
36  *  it may swap in a different merge policy/scheduler; may
37  *  commit periodically; may or may not optimize in the end,
38  *  may flush by doc count instead of RAM, etc. 
39  */
40
41 public class RandomIndexWriter implements Closeable {
42
43   public IndexWriter w;
44   private final Random r;
45   int docCount;
46   int flushAt;
47   private double flushAtFactor = 1.0;
48   private boolean getReaderCalled;
49
50   // Randomly calls Thread.yield so we mixup thread scheduling
51   private static final class MockIndexWriter extends IndexWriter {
52
53     private final Random r;
54
55     public MockIndexWriter(Random r,Directory dir, IndexWriterConfig conf) throws IOException {
56       super(dir, conf);
57       // must make a private random since our methods are
58       // called from different threads; else test failures may
59       // not be reproducible from the original seed
60       this.r = new Random(r.nextInt());
61     }
62
63     @Override
64     boolean testPoint(String name) {
65       if (r.nextInt(4) == 2)
66         Thread.yield();
67       return true;
68     }
69   }
70
71   /** create a RandomIndexWriter with a random config: Uses TEST_VERSION_CURRENT and Whitespace+LowercasingAnalyzer */
72   public RandomIndexWriter(Random r, Directory dir) throws IOException {
73     this(r, dir, LuceneTestCase.newIndexWriterConfig(r, LuceneTestCase.TEST_VERSION_CURRENT, new MockAnalyzer(r)));
74   }
75   
76   /** create a RandomIndexWriter with a random config: Uses TEST_VERSION_CURRENT */
77   public RandomIndexWriter(Random r, Directory dir, Analyzer a) throws IOException {
78     this(r, dir, LuceneTestCase.newIndexWriterConfig(r, LuceneTestCase.TEST_VERSION_CURRENT, a));
79   }
80   
81   /** create a RandomIndexWriter with a random config */
82   public RandomIndexWriter(Random r, Directory dir, Version v, Analyzer a) throws IOException {
83     this(r, dir, LuceneTestCase.newIndexWriterConfig(r, v, a));
84   }
85   
86   /** create a RandomIndexWriter with the provided config */
87   public RandomIndexWriter(Random r, Directory dir, IndexWriterConfig c) throws IOException {
88     this.r = r;
89     w = new MockIndexWriter(r, dir, c);
90     flushAt = _TestUtil.nextInt(r, 10, 1000);
91     if (LuceneTestCase.VERBOSE) {
92       System.out.println("RIW config=" + w.getConfig());
93     }
94   } 
95
96   /**
97    * Adds a Document.
98    * @see IndexWriter#addDocument(Document)
99    */
100   public void addDocument(final Document doc) throws IOException {
101     if (r.nextInt(5) == 3) {
102       // TODO: maybe, we should simply buffer up added docs
103       // (but we need to clone them), and only when
104       // getReader, commit, etc. are called, we do an
105       // addDocuments?  Would be better testing.
106       w.addDocuments(Collections.singletonList(doc));
107     } else {
108       w.addDocument(doc);
109     }
110     maybeCommit();
111   }
112   
113   public void addDocuments(Collection<Document> docs) throws IOException {
114     w.addDocuments(docs);
115     maybeCommit();
116   }
117
118   public void updateDocuments(Term delTerm, Collection<Document> docs) throws IOException {
119     w.updateDocuments(delTerm, docs);
120     maybeCommit();
121   }
122
123   private void maybeCommit() throws IOException {
124     if (docCount++ == flushAt) {
125       if (LuceneTestCase.VERBOSE) {
126         System.out.println("RIW.add/updateDocument: now doing a commit at docCount=" + docCount);
127       }
128       w.commit();
129       flushAt += _TestUtil.nextInt(r, (int) (flushAtFactor * 10), (int) (flushAtFactor * 1000));
130       if (flushAtFactor < 2e6) {
131         // gradually but exponentially increase time b/w flushes
132         flushAtFactor *= 1.05;
133       }
134     }
135   }
136
137   /**
138    * Updates a document.
139    * @see IndexWriter#updateDocument(Term, Document)
140    */
141   public void updateDocument(Term t, final Document doc) throws IOException {
142     if (r.nextInt(5) == 3) {
143       w.updateDocuments(t, Collections.singletonList(doc));
144     } else {
145       w.updateDocument(t, doc);
146     }
147     maybeCommit();
148   }
149   
150   public void addIndexes(Directory... dirs) throws CorruptIndexException, IOException {
151     w.addIndexes(dirs);
152   }
153   
154   public void deleteDocuments(Term term) throws CorruptIndexException, IOException {
155     w.deleteDocuments(term);
156   }
157   
158   public void commit() throws CorruptIndexException, IOException {
159     w.commit();
160   }
161   
162   public int numDocs() throws IOException {
163     return w.numDocs();
164   }
165
166   public int maxDoc() {
167     return w.maxDoc();
168   }
169
170   public void deleteAll() throws IOException {
171     w.deleteAll();
172   }
173
174   private boolean doRandomOptimize = true;
175
176   public void setDoRandomOptimize(boolean v) {
177     doRandomOptimize = v;
178   }
179
180   private void doRandomOptimize() throws IOException {
181     if (doRandomOptimize) {
182       final int segCount = w.getSegmentCount();
183       if (r.nextBoolean() || segCount == 0) {
184         // full optimize
185         w.optimize();
186       } else {
187         // partial optimize
188         final int limit = _TestUtil.nextInt(r, 1, segCount);
189         w.optimize(limit);
190         assert w.getSegmentCount() <= limit: "limit=" + limit + " actual=" + w.getSegmentCount();
191       }
192     }
193   }
194
195   public IndexReader getReader() throws IOException {
196     return getReader(true);
197   }
198
199   public IndexReader getReader(boolean applyDeletions) throws IOException {
200     getReaderCalled = true;
201     if (r.nextInt(4) == 2) {
202       doRandomOptimize();
203     }
204     if (r.nextBoolean()) {
205       if (LuceneTestCase.VERBOSE) {
206         System.out.println("RIW.getReader: use NRT reader");
207       }
208       return w.getReader(applyDeletions);
209     } else {
210       if (LuceneTestCase.VERBOSE) {
211         System.out.println("RIW.getReader: open new reader");
212       }
213       w.commit();
214       return IndexReader.open(w.getDirectory(), new KeepOnlyLastCommitDeletionPolicy(), r.nextBoolean(), _TestUtil.nextInt(r, 1, 10));
215     }
216   }
217
218   /**
219    * Close this writer.
220    * @see IndexWriter#close()
221    */
222   public void close() throws IOException {
223     // if someone isn't using getReader() API, we want to be sure to
224     // maybeOptimize since presumably they might open a reader on the dir.
225     if (getReaderCalled == false && r.nextInt(8) == 2) {
226       doRandomOptimize();
227     }
228     w.close();
229   }
230
231   /**
232    * Forces an optimize.
233    * <p>
234    * NOTE: this should be avoided in tests unless absolutely necessary,
235    * as it will result in less test coverage.
236    * @see IndexWriter#optimize()
237    */
238   public void optimize() throws IOException {
239     w.optimize();
240   }
241 }