blob: 9bc08028b1dfc0f7da368ec177cff7f127eac58c [file] [log] [blame]
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.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.apache.lucene.analysis.MockAnalyzer;
import org.apache.lucene.codecs.Codec;
import org.apache.lucene.codecs.FieldInfosFormat;
import org.apache.lucene.codecs.StoredFieldsFormat;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.index.DocumentsWriterPerThread.IndexingChain;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.similarities.DefaultSimilarity;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.InfoStream;
import org.apache.lucene.util.LuceneTestCase;
import org.junit.Test;
public class TestIndexWriterConfig extends LuceneTestCase {
private static final class MySimilarity extends DefaultSimilarity {
// Does not implement anything - used only for type checking on IndexWriterConfig.
}
private static final class MyIndexingChain extends IndexingChain {
// Does not implement anything - used only for type checking on IndexWriterConfig.
@Override
DocConsumer getChain(DocumentsWriterPerThread documentsWriter) {
return null;
}
}
@Test
public void testDefaults() throws Exception {
IndexWriterConfig conf = new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random()));
assertEquals(MockAnalyzer.class, conf.getAnalyzer().getClass());
assertNull(conf.getIndexCommit());
assertEquals(KeepOnlyLastCommitDeletionPolicy.class, conf.getIndexDeletionPolicy().getClass());
assertEquals(ConcurrentMergeScheduler.class, conf.getMergeScheduler().getClass());
assertEquals(OpenMode.CREATE_OR_APPEND, conf.getOpenMode());
// we don't need to assert this, it should be unspecified
assertTrue(IndexSearcher.getDefaultSimilarity() == conf.getSimilarity());
assertEquals(IndexWriterConfig.DEFAULT_TERM_INDEX_INTERVAL, conf.getTermIndexInterval());
assertEquals(IndexWriterConfig.getDefaultWriteLockTimeout(), conf.getWriteLockTimeout());
assertEquals(IndexWriterConfig.WRITE_LOCK_TIMEOUT, IndexWriterConfig.getDefaultWriteLockTimeout());
assertEquals(IndexWriterConfig.DEFAULT_MAX_BUFFERED_DELETE_TERMS, conf.getMaxBufferedDeleteTerms());
assertEquals(IndexWriterConfig.DEFAULT_RAM_BUFFER_SIZE_MB, conf.getRAMBufferSizeMB(), 0.0);
assertEquals(IndexWriterConfig.DEFAULT_MAX_BUFFERED_DOCS, conf.getMaxBufferedDocs());
assertEquals(IndexWriterConfig.DEFAULT_READER_POOLING, conf.getReaderPooling());
assertTrue(DocumentsWriterPerThread.defaultIndexingChain == conf.getIndexingChain());
assertNull(conf.getMergedSegmentWarmer());
assertEquals(IndexWriterConfig.DEFAULT_READER_TERMS_INDEX_DIVISOR, conf.getReaderTermsIndexDivisor());
assertEquals(TieredMergePolicy.class, conf.getMergePolicy().getClass());
assertEquals(ThreadAffinityDocumentsWriterThreadPool.class, conf.getIndexerThreadPool().getClass());
assertEquals(FlushByRamOrCountsPolicy.class, conf.getFlushPolicy().getClass());
assertEquals(IndexWriterConfig.DEFAULT_RAM_PER_THREAD_HARD_LIMIT_MB, conf.getRAMPerThreadHardLimitMB());
assertEquals(Codec.getDefault(), conf.getCodec());
assertEquals(InfoStream.getDefault(), conf.getInfoStream());
assertEquals(IndexWriterConfig.DEFAULT_USE_COMPOUND_FILE_SYSTEM, conf.getUseCompoundFile());
// Sanity check - validate that all getters are covered.
Set<String> getters = new HashSet<String>();
getters.add("getAnalyzer");
getters.add("getIndexCommit");
getters.add("getIndexDeletionPolicy");
getters.add("getMaxFieldLength");
getters.add("getMergeScheduler");
getters.add("getOpenMode");
getters.add("getSimilarity");
getters.add("getTermIndexInterval");
getters.add("getWriteLockTimeout");
getters.add("getDefaultWriteLockTimeout");
getters.add("getMaxBufferedDeleteTerms");
getters.add("getRAMBufferSizeMB");
getters.add("getMaxBufferedDocs");
getters.add("getIndexingChain");
getters.add("getMergedSegmentWarmer");
getters.add("getMergePolicy");
getters.add("getMaxThreadStates");
getters.add("getReaderPooling");
getters.add("getIndexerThreadPool");
getters.add("getReaderTermsIndexDivisor");
getters.add("getFlushPolicy");
getters.add("getRAMPerThreadHardLimitMB");
getters.add("getCodec");
getters.add("getInfoStream");
getters.add("getUseCompoundFile");
for (Method m : IndexWriterConfig.class.getDeclaredMethods()) {
if (m.getDeclaringClass() == IndexWriterConfig.class && m.getName().startsWith("get")) {
assertTrue("method " + m.getName() + " is not tested for defaults", getters.contains(m.getName()));
}
}
}
@Test
public void testSettersChaining() throws Exception {
// Ensures that every setter returns IndexWriterConfig to allow chaining.
HashSet<String> liveSetters = new HashSet<String>();
HashSet<String> allSetters = new HashSet<String>();
for (Method m : IndexWriterConfig.class.getDeclaredMethods()) {
if (m.getName().startsWith("set") && !Modifier.isStatic(m.getModifiers())) {
allSetters.add(m.getName());
// setters overridden from LiveIndexWriterConfig are returned twice, once with
// IndexWriterConfig return type and second with LiveIndexWriterConfig. The ones
// from LiveIndexWriterConfig are marked 'synthetic', so just collect them and
// assert in the end that we also received them from IWC.
if (m.isSynthetic()) {
liveSetters.add(m.getName());
} else {
assertEquals("method " + m.getName() + " does not return IndexWriterConfig",
IndexWriterConfig.class, m.getReturnType());
}
}
}
for (String setter : liveSetters) {
assertTrue("setter method not overridden by IndexWriterConfig: " + setter, allSetters.contains(setter));
}
}
@Test
public void testReuse() throws Exception {
Directory dir = newDirectory();
// test that if the same IWC is reused across two IWs, it is cloned by each.
IndexWriterConfig conf = newIndexWriterConfig(TEST_VERSION_CURRENT, null);
RandomIndexWriter iw = new RandomIndexWriter(random(), dir, conf);
LiveIndexWriterConfig liveConf1 = iw.w.getConfig();
iw.close();
iw = new RandomIndexWriter(random(), dir, conf);
LiveIndexWriterConfig liveConf2 = iw.w.getConfig();
iw.close();
// LiveIndexWriterConfig's "copy" constructor doesn't clone objects.
assertNotSame("IndexWriterConfig should have been cloned", liveConf1.getMergePolicy(), liveConf2.getMergePolicy());
dir.close();
}
@Test
public void testOverrideGetters() throws Exception {
// Test that IndexWriterConfig overrides all getters, so that javadocs
// contain all methods for the users. Also, ensures that IndexWriterConfig
// doesn't declare getters that are not declared on LiveIWC.
HashSet<String> liveGetters = new HashSet<String>();
for (Method m : LiveIndexWriterConfig.class.getDeclaredMethods()) {
if (m.getName().startsWith("get") && !Modifier.isStatic(m.getModifiers())) {
liveGetters.add(m.getName());
}
}
for (Method m : IndexWriterConfig.class.getDeclaredMethods()) {
if (m.getName().startsWith("get") && !Modifier.isStatic(m.getModifiers())) {
assertEquals("method " + m.getName() + " not overrided by IndexWriterConfig",
IndexWriterConfig.class, m.getDeclaringClass());
assertTrue("method " + m.getName() + " not declared on LiveIndexWriterConfig",
liveGetters.contains(m.getName()));
}
}
}
@Test
public void testConstants() throws Exception {
// Tests that the values of the constants does not change
assertEquals(1000, IndexWriterConfig.WRITE_LOCK_TIMEOUT);
assertEquals(32, IndexWriterConfig.DEFAULT_TERM_INDEX_INTERVAL);
assertEquals(-1, IndexWriterConfig.DISABLE_AUTO_FLUSH);
assertEquals(IndexWriterConfig.DISABLE_AUTO_FLUSH, IndexWriterConfig.DEFAULT_MAX_BUFFERED_DELETE_TERMS);
assertEquals(IndexWriterConfig.DISABLE_AUTO_FLUSH, IndexWriterConfig.DEFAULT_MAX_BUFFERED_DOCS);
assertEquals(16.0, IndexWriterConfig.DEFAULT_RAM_BUFFER_SIZE_MB, 0.0);
assertEquals(false, IndexWriterConfig.DEFAULT_READER_POOLING);
assertEquals(true, IndexWriterConfig.DEFAULT_USE_COMPOUND_FILE_SYSTEM);
assertEquals(DirectoryReader.DEFAULT_TERMS_INDEX_DIVISOR, IndexWriterConfig.DEFAULT_READER_TERMS_INDEX_DIVISOR);
}
@Test
public void testToString() throws Exception {
String str = new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random())).toString();
for (Field f : IndexWriterConfig.class.getDeclaredFields()) {
int modifiers = f.getModifiers();
if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) {
// Skip static final fields, they are only constants
continue;
} else if ("indexingChain".equals(f.getName())) {
// indexingChain is a package-private setting and thus is not output by
// toString.
continue;
}
if (f.getName().equals("inUseByIndexWriter")) {
continue;
}
assertTrue(f.getName() + " not found in toString", str.indexOf(f.getName()) != -1);
}
}
@Test
public void testClone() throws Exception {
IndexWriterConfig conf = new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random()));
IndexWriterConfig clone = conf.clone();
// Make sure parameters that can't be reused are cloned
IndexDeletionPolicy delPolicy = conf.delPolicy;
IndexDeletionPolicy delPolicyClone = clone.delPolicy;
assertTrue(delPolicy.getClass() == delPolicyClone.getClass() && (delPolicy != delPolicyClone || delPolicy.clone() == delPolicyClone.clone()));
FlushPolicy flushPolicy = conf.flushPolicy;
FlushPolicy flushPolicyClone = clone.flushPolicy;
assertTrue(flushPolicy.getClass() == flushPolicyClone.getClass() && (flushPolicy != flushPolicyClone || flushPolicy.clone() == flushPolicyClone.clone()));
DocumentsWriterPerThreadPool pool = conf.indexerThreadPool;
DocumentsWriterPerThreadPool poolClone = clone.indexerThreadPool;
assertTrue(pool.getClass() == poolClone.getClass() && (pool != poolClone || pool.clone() == poolClone.clone()));
MergePolicy mergePolicy = conf.mergePolicy;
MergePolicy mergePolicyClone = clone.mergePolicy;
assertTrue(mergePolicy.getClass() == mergePolicyClone.getClass() && (mergePolicy != mergePolicyClone || mergePolicy.clone() == mergePolicyClone.clone()));
MergeScheduler mergeSched = conf.mergeScheduler;
MergeScheduler mergeSchedClone = clone.mergeScheduler;
assertTrue(mergeSched.getClass() == mergeSchedClone.getClass() && (mergeSched != mergeSchedClone || mergeSched.clone() == mergeSchedClone.clone()));
conf.setMergeScheduler(new SerialMergeScheduler());
assertEquals(ConcurrentMergeScheduler.class, clone.getMergeScheduler().getClass());
}
@Test
public void testInvalidValues() throws Exception {
IndexWriterConfig conf = new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random()));
// Test IndexDeletionPolicy
assertEquals(KeepOnlyLastCommitDeletionPolicy.class, conf.getIndexDeletionPolicy().getClass());
conf.setIndexDeletionPolicy(new SnapshotDeletionPolicy(null));
assertEquals(SnapshotDeletionPolicy.class, conf.getIndexDeletionPolicy().getClass());
try {
conf.setIndexDeletionPolicy(null);
fail();
} catch (IllegalArgumentException e) {
// ok
}
// Test MergeScheduler
assertEquals(ConcurrentMergeScheduler.class, conf.getMergeScheduler().getClass());
conf.setMergeScheduler(new SerialMergeScheduler());
assertEquals(SerialMergeScheduler.class, conf.getMergeScheduler().getClass());
try {
conf.setMergeScheduler(null);
fail();
} catch (IllegalArgumentException e) {
// ok
}
// Test Similarity:
// we shouldnt assert what the default is, just that its not null.
assertTrue(IndexSearcher.getDefaultSimilarity() == conf.getSimilarity());
conf.setSimilarity(new MySimilarity());
assertEquals(MySimilarity.class, conf.getSimilarity().getClass());
try {
conf.setSimilarity(null);
fail();
} catch (IllegalArgumentException e) {
// ok
}
// Test IndexingChain
assertTrue(DocumentsWriterPerThread.defaultIndexingChain == conf.getIndexingChain());
conf.setIndexingChain(new MyIndexingChain());
assertEquals(MyIndexingChain.class, conf.getIndexingChain().getClass());
try {
conf.setIndexingChain(null);
fail();
} catch (IllegalArgumentException e) {
// ok
}
try {
conf.setMaxBufferedDeleteTerms(0);
fail("should not have succeeded to set maxBufferedDeleteTerms to 0");
} catch (IllegalArgumentException e) {
// this is expected
}
try {
conf.setMaxBufferedDocs(1);
fail("should not have succeeded to set maxBufferedDocs to 1");
} catch (IllegalArgumentException e) {
// this is expected
}
try {
// Disable both MAX_BUF_DOCS and RAM_SIZE_MB
conf.setMaxBufferedDocs(4);
conf.setRAMBufferSizeMB(IndexWriterConfig.DISABLE_AUTO_FLUSH);
conf.setMaxBufferedDocs(IndexWriterConfig.DISABLE_AUTO_FLUSH);
fail("should not have succeeded to disable maxBufferedDocs when ramBufferSizeMB is disabled as well");
} catch (IllegalArgumentException e) {
// this is expected
}
conf.setRAMBufferSizeMB(IndexWriterConfig.DEFAULT_RAM_BUFFER_SIZE_MB);
conf.setMaxBufferedDocs(IndexWriterConfig.DEFAULT_MAX_BUFFERED_DOCS);
try {
conf.setRAMBufferSizeMB(IndexWriterConfig.DISABLE_AUTO_FLUSH);
fail("should not have succeeded to disable ramBufferSizeMB when maxBufferedDocs is disabled as well");
} catch (IllegalArgumentException e) {
// this is expected
}
// Test setReaderTermsIndexDivisor
try {
conf.setReaderTermsIndexDivisor(0);
fail("should not have succeeded to set termsIndexDivisor to 0");
} catch (IllegalArgumentException e) {
// this is expected
}
// Setting to -1 is ok
conf.setReaderTermsIndexDivisor(-1);
try {
conf.setReaderTermsIndexDivisor(-2);
fail("should not have succeeded to set termsIndexDivisor to < -1");
} catch (IllegalArgumentException e) {
// this is expected
}
try {
conf.setRAMPerThreadHardLimitMB(2048);
fail("should not have succeeded to set RAMPerThreadHardLimitMB to >= 2048");
} catch (IllegalArgumentException e) {
// this is expected
}
try {
conf.setRAMPerThreadHardLimitMB(0);
fail("should not have succeeded to set RAMPerThreadHardLimitMB to 0");
} catch (IllegalArgumentException e) {
// this is expected
}
// Test MergePolicy
assertEquals(TieredMergePolicy.class, conf.getMergePolicy().getClass());
conf.setMergePolicy(new LogDocMergePolicy());
assertEquals(LogDocMergePolicy.class, conf.getMergePolicy().getClass());
try {
conf.setMergePolicy(null);
fail();
} catch (IllegalArgumentException e) {
// ok
}
}
public void testLiveChangeToCFS() throws Exception {
Directory dir = newDirectory();
IndexWriterConfig iwc = new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random()));
iwc.setMergePolicy(newLogMergePolicy(true));
// Start false:
iwc.setUseCompoundFile(false);
iwc.getMergePolicy().setNoCFSRatio(0.0d);
IndexWriter w = new IndexWriter(dir, iwc);
// Change to true:
w.getConfig().setUseCompoundFile(true);
Document doc = new Document();
doc.add(newStringField("field", "foo", Store.NO));
w.addDocument(doc);
w.commit();
assertTrue("Expected CFS after commit", w.newestSegment().info.getUseCompoundFile());
doc.add(newStringField("field", "foo", Store.NO));
w.addDocument(doc);
w.commit();
w.forceMerge(1);
w.commit();
// no compound files after merge
assertFalse("Expected Non-CFS after merge", w.newestSegment().info.getUseCompoundFile());
MergePolicy lmp = w.getConfig().getMergePolicy();
lmp.setNoCFSRatio(1.0);
lmp.setMaxCFSSegmentSizeMB(Double.POSITIVE_INFINITY);
w.addDocument(doc);
w.forceMerge(1);
w.commit();
assertTrue("Expected CFS after merge", w.newestSegment().info.getUseCompoundFile());
w.close();
dir.close();
}
}