/*
* Copyright 2004-2009 the original author or authors.
*
* Licensed 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.
*/
package org.compass.core.lucene.engine.manager;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.index.IndexDeletionPolicy;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.store.Directory;
import org.compass.core.config.CompassSettings;
import org.compass.core.lucene.LuceneEnvironment;
import org.compass.core.lucene.engine.LuceneSearchEngineFactory;
import org.compass.core.lucene.engine.LuceneSettings;
import org.compass.core.lucene.engine.merge.policy.MergePolicyFactory;
import org.compass.core.lucene.engine.merge.scheduler.MergeSchedulerFactory;
/**
* A manager responsible for opening {@link org.apache.lucene.index.IndexWriter}. Also provides tracking
* of opened {@link org.apache.lucene.index.IndexWriter} if enabled and if used by other components.
*
* <p>Other components, in order to use tracking, should call {@link #trackOpenIndexWriter(String, org.apache.lucene.index.IndexWriter)}
* once an index writer is opened, and {@link #trackCloseIndexWriter(String, org.apache.lucene.index.IndexWriter)} once
* the index writer is closed or rolled back.
*
* @author kimchy
*/
public class IndexWritersManager {
private static final Log logger = LogFactory.getLog(IndexWritersManager.class);
private final LuceneSearchEngineIndexManager indexManager;
private final LuceneSearchEngineFactory searchEngineFactory;
private LuceneSettings luceneSettings;
private final ConcurrentMap<String, IndexWriter> trackedOpenIndexWriters;
private final boolean trackOpenIndexWriters;
public IndexWritersManager(LuceneSearchEngineIndexManager indexManager) {
this.indexManager = indexManager;
this.searchEngineFactory = indexManager.getSearchEngineFactory();
this.luceneSettings = indexManager.getSettings();
trackOpenIndexWriters =
luceneSettings.getSettings().getSettingAsBoolean(LuceneEnvironment.SearchEngineIndex.TRACK_OPENED_INDEX_WRITERS, true) || indexManager.getSearchEngineFactory().isDebug();
if (trackOpenIndexWriters) {
if (logger.isTraceEnabled()) {
logger.trace("Tracking open index writers");
}
trackedOpenIndexWriters = new ConcurrentHashMap<String, IndexWriter>();
} else {
trackedOpenIndexWriters = null;
}
}
public void close() {
if (trackOpenIndexWriters) {
for (Map.Entry<String, IndexWriter> entry : trackedOpenIndexWriters.entrySet()) {
logger.error("[INDEX WRITER] Sub Index [" + entry.getKey() + "] is still open, rolling back");
try {
entry.getValue().rollback();
} catch (Exception e) {
// do nothing, ignore
}
}
}
}
public void trackOpenIndexWriter(String subIndex, IndexWriter indexWriter) {
if (trackOpenIndexWriters) {
IndexWriter oldValue = trackedOpenIndexWriters.put(subIndex, indexWriter);
if (oldValue != null) {
logger.error("Illegal state, marking an index writer as open, while another is marked as open for sub index [" + subIndex + "]");
}
}
}
public void trackCloseIndexWriter(String subIndex, IndexWriter indexWriter) {
if (trackOpenIndexWriters) {
IndexWriter value = trackedOpenIndexWriters.remove(subIndex);
if (value == null) {
logger.error("Illegal state, marking an index writer as closed, but none was opened before (or closed twice) for sub index [" + subIndex + "]");
} else if (value != indexWriter) {
logger.error("Illegal state, marking an index writer as closed, but a different was opened before for sub index [" + subIndex + "]");
}
}
}
public IndexWriter openIndexWriter(CompassSettings settings, String subIndex) throws IOException {
return openIndexWriter(settings, indexManager.getDirectory(subIndex), false);
}
public IndexWriter openIndexWriter(CompassSettings settings, Directory dir, boolean create) throws IOException {
return openIndexWriter(settings, dir, create, null);
}
public IndexWriter openIndexWriter(CompassSettings settings, Directory dir, IndexDeletionPolicy deletionPolicy) throws IOException {
return openIndexWriter(settings, dir, false, deletionPolicy);
}
public IndexWriter openIndexWriter(CompassSettings settings, Directory dir, boolean create, IndexDeletionPolicy deletionPolicy) throws IOException {
return openIndexWriter(settings, dir, create, deletionPolicy, null);
}
public IndexWriter openIndexWriter(CompassSettings settings, Directory dir, boolean create, IndexDeletionPolicy deletionPolicy, Analyzer analyzer) throws IOException {
if (deletionPolicy == null) {
deletionPolicy = searchEngineFactory.getIndexDeletionPolicyManager().createIndexDeletionPolicy(dir);
}
if (analyzer == null) {
analyzer = searchEngineFactory.getAnalyzerManager().getDefaultAnalyzer();
}
IndexWriter indexWriter = new IndexWriter(dir, analyzer, create, deletionPolicy, new IndexWriter.MaxFieldLength(luceneSettings.getMaxFieldLength()));
indexWriter.setMergePolicy(MergePolicyFactory.createMergePolicy(settings));
indexWriter.setMergeScheduler(MergeSchedulerFactory.create(indexManager, settings));
indexWriter.setMaxMergeDocs(settings.getSettingAsInt(LuceneEnvironment.SearchEngineIndex.MAX_MERGE_DOCS, luceneSettings.getMaxMergeDocs()));
indexWriter.setMergeFactor(settings.getSettingAsInt(LuceneEnvironment.SearchEngineIndex.MERGE_FACTOR, luceneSettings.getMergeFactor()));
indexWriter.setRAMBufferSizeMB(settings.getSettingAsDouble(LuceneEnvironment.SearchEngineIndex.RAM_BUFFER_SIZE, luceneSettings.getRamBufferSize()));
indexWriter.setMaxBufferedDocs(settings.getSettingAsInt(LuceneEnvironment.SearchEngineIndex.MAX_BUFFERED_DOCS, luceneSettings.getMaxBufferedDocs()));
indexWriter.setMaxBufferedDeleteTerms(settings.getSettingAsInt(LuceneEnvironment.SearchEngineIndex.MAX_BUFFERED_DELETED_TERMS, luceneSettings.getMaxBufferedDeletedTerms()));
indexWriter.setUseCompoundFile(indexManager.getStore().isUseCompoundFile());
indexWriter.setMaxFieldLength(luceneSettings.getMaxFieldLength());
indexWriter.setTermIndexInterval(luceneSettings.getTermIndexInterval());
indexWriter.setSimilarity(searchEngineFactory.getSimilarityManager().getIndexSimilarity());
return indexWriter;
}
}