Java tutorial
/* * 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. */ package cn.hbu.cs.esearch.index; import java.io.IOException; import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.IndexReader; import org.apache.lucene.store.Directory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import cn.hbu.cs.esearch.core.EsearchMultiReader; import cn.hbu.cs.esearch.document.DirectoryManager; import cn.hbu.cs.esearch.document.DocIDMapper; public class IndexReaderDispenser<R extends IndexReader> { public static final Logger LOGGER = LoggerFactory.getLogger(IndexReaderDispenser.class); private static final int INDEX_OPEN_NUM_RETRIES = 5; private volatile EsearchMultiReader<R> _currentReader; private volatile IndexSignature _currentSignature; private final IndexReaderDecorator<R> _decorator; private final DirectoryManager _dirMgr; private final DiskSearchIndex<R> _idx; public IndexReaderDispenser(DirectoryManager dirMgr, IndexReaderDecorator<R> decorator, DiskSearchIndex<R> idx) { _idx = idx; _dirMgr = dirMgr; _decorator = decorator; _currentSignature = null; try { IndexSignature sig = new IndexSignature(_dirMgr.getVersion()); if (sig != null) { getNewReader(); } } catch (IOException e) { LOGGER.error("{}", e); } } public String getCurrentVersion() { return _currentSignature != null ? _currentSignature.getVersion() : null; } /** * constructs a new IndexReader instance * <p/> * Where the index is. * * @return Constructed IndexReader instance. * * @throws java.io.IOException */ private EsearchMultiReader<R> newReader(DirectoryManager dirMgr, IndexReaderDecorator<R> decorator, IndexSignature signature) throws IOException { if (!dirMgr.exists()) { return null; } Directory dir = dirMgr.getDirectory(); if (!DirectoryReader.indexExists(dir)) { return null; } int numTries = INDEX_OPEN_NUM_RETRIES; EsearchMultiReader<R> reader = null; // try max of 5 times, there might be a case where the segment file is being updated while (reader == null) { if (numTries == 0) { LOGGER.error("Problem refreshing disk index, all attempts failed."); throw new IOException("problem opening new index"); } numTries--; try { if (LOGGER.isDebugEnabled()) { LOGGER.debug("opening index reader at: " + dirMgr.getPath()); } DirectoryReader srcReader = DirectoryReader.open(dir); try { reader = new EsearchMultiReader<R>(srcReader, decorator); _currentSignature = signature; } catch (IOException ioe) { // close the source reader if EsearchMultiReader construction fails if (srcReader != null) { srcReader.close(); } throw ioe; } } catch (IOException ioe) { try { Thread.sleep(100); } catch (InterruptedException e) { LOGGER.warn("thread interrupted."); continue; } } } return reader; } /** * get a fresh new reader instance * * @return an IndexReader instance, can be null if index does not yet exit * * @throws java.io.IOException */ public EsearchMultiReader<R> getNewReader() throws IOException { int numTries = INDEX_OPEN_NUM_RETRIES; EsearchMultiReader<R> reader = null; // try it for a few times, there is a case where lucene is swapping the segment file, // or a case where the index directory file is updated, both are legitimate, // trying again does not block searchers, // the extra time it takes to get the reader, and to sync the index, memory index is collecting // docs while (reader == null) { if (numTries == 0) { break; } numTries--; try { IndexSignature sig = new IndexSignature(_dirMgr.getVersion()); if (_currentReader == null) { reader = newReader(_dirMgr, _decorator, sig); break; } else { reader = _currentReader.reopen(); _currentSignature = sig; } } catch (IOException ioe) { try { Thread.sleep(100); } catch (InterruptedException e) { LOGGER.warn("thread interrupted."); continue; } } } // swap the internal readers if (_currentReader != reader) { if (reader != null) { DocIDMapper mapper = _idx._idxMgr._docIDMapperFactory.getDocIDMapper(reader); reader.setDocIDMapper(mapper); } // assume that this is the only place that _currentReader gets refreshed EsearchMultiReader<R> oldReader = _currentReader; _currentReader = reader; // we release our hold on the old reader so that it will be closed when // all the clients release their hold on it, the reader will be closed // automatically. LOGGER.info("swap disk reader and release old one from system"); if (oldReader != null) { oldReader.decEsearchRef(); } } return reader; } public EsearchMultiReader<R> getIndexReader() { if (_currentReader != null) { return _currentReader; } else { return null; } } /** * Closes the factory. */ public void close() { closeReader(); } /** * Closes the index reader */ public void closeReader() { if (_currentReader != null) { _currentReader.decEsearchRef(); int count = _currentReader.getInnerRefCount(); LOGGER.info("final closeReader in dispenser and current refCount: " + count); if (count > 0) { LOGGER.warn( "final closeReader call with reference count == " + count + " greater than 0. Potentially, " + "the IndexReaders are not properly return to EsearchSystem."); } _currentReader = null; } } }