package proj.zoie.api;
/**
* 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 it.unimi.dsi.fastutil.longs.LongSet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.log4j.Logger;
import org.apache.lucene.index.AtomicReader;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.FilterDirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.SegmentReader;
import org.apache.lucene.util.BytesRef;
import proj.zoie.api.indexing.IndexReaderDecorator;
public class ZoieMultiReader<R extends IndexReader> extends FilterDirectoryReader {
private static final Logger log = Logger.getLogger(ZoieMultiReader.class.getName());
private final Map<String, ZoieSegmentReader<R>> _readerMap;
private final List<ZoieSegmentReader<R>> _subZoieReaders;
private List<R> _decoratedReaders;
private final IndexReaderDecorator<R> _decorator;
private DocIDMapper _docIDMapper;
public ZoieMultiReader(DirectoryReader in, IndexReaderDecorator<R> decorator) throws IOException {
this(in, decorator, new ZoieSubReaderWrapper<R>(decorator));
}
@SuppressWarnings("unchecked")
private ZoieMultiReader(DirectoryReader in, IndexReaderDecorator<R> decorator,
ZoieSubReaderWrapper<R> wrapper) throws IOException {
super(in, wrapper);
_subZoieReaders = (List<ZoieSegmentReader<R>>) getSequentialSubReaders();
_decorator = decorator;
_readerMap = new HashMap<String, ZoieSegmentReader<R>>();
_decoratedReaders = null;
init();
}
private final AtomicLong zoieRefCounter = new AtomicLong(1);
public void incZoieRef() {
zoieRefCounter.incrementAndGet();
}
public void decZoieRef() {
long refCount = zoieRefCounter.decrementAndGet();
if (refCount < 0) {
log.warn("refCount should never be lower than 0");
}
if (refCount == 0) {
try {
in.decRef();
} catch (IOException e) {
log.error("decZoieRef exception, ", e);
}
}
}
public int getInnerRefCount() {
return in.getRefCount();
}
public int getSubReaderBase(int idx) {
return readerBase(idx);
}
public DocIDMapper getDocIDMapper() {
return _docIDMapper;
}
public void setDocIDMapper(DocIDMapper docIDMapper) {
_docIDMapper = docIDMapper;
}
public BytesRef getStoredValue(long uid) throws IOException {
int docid = _docIDMapper.getDocID(uid);
if (docid < 0) {
return null;
}
int idx = readerIndex(docid);
if (idx < 0) {
return null;
}
ZoieSegmentReader<R> subReader = _subZoieReaders.get(idx);
return subReader.getStoredValue(docid - readerBase(idx));
}
private void init() throws IOException {
for (ZoieSegmentReader<R> subReader : _subZoieReaders) {
String segmentName = subReader.getSegmentName();
_readerMap.put(segmentName, subReader);
}
ArrayList<R> decoratedList = new ArrayList<R>(_subZoieReaders.size());
for (ZoieSegmentReader<R> subReader : _subZoieReaders) {
R decoratedReader = subReader.getDecoratedReader();
decoratedList.add(decoratedReader);
}
_decoratedReaders = decoratedList;
}
@SuppressWarnings("unchecked")
public ZoieSegmentReader<R>[] getSubReaders() {
return (_subZoieReaders.toArray(new ZoieSegmentReader[_subZoieReaders.size()]));
}
public void markDeletes(LongSet delDocs, LongSet deletedUIDs) {
ZoieSegmentReader<R>[] subReaders = getSubReaders();
if (subReaders != null && subReaders.length > 0) {
for (ZoieSegmentReader<R> subReader : subReaders) {
subReader.markDeletes(delDocs, deletedUIDs);
}
}
}
public void commitDeletes() {
ZoieSegmentReader<R>[] subReaders = getSubReaders();
if (subReaders != null && subReaders.length > 0) {
for (ZoieSegmentReader<R> subReader : subReaders) {
subReader.commitDeletes();
}
}
}
public List<R> getDecoratedReaders() throws IOException {
return _decoratedReaders;
}
public static <R extends IndexReader> List<R> extractDecoratedReaders(
List<ZoieMultiReader<R>> readerList) throws IOException {
LinkedList<R> retList = new LinkedList<R>();
for (ZoieMultiReader<R> reader : readerList) {
retList.addAll(reader.getDecoratedReaders());
}
return retList;
}
public boolean isDeleted(int docid) {
int idx = readerIndex(docid);
ZoieSegmentReader<R> subReader = _subZoieReaders.get(idx);
return subReader.isDeleted(docid - readerBase(idx));
}
public ZoieMultiReader<R> reopen() throws IOException {
long t0 = System.currentTimeMillis();
DirectoryReader inner = DirectoryReader.openIfChanged(in);
if (inner == null) {
t0 = System.currentTimeMillis() - t0;
if (t0 > 1000) {
log.info("reopen returns in " + t0 + "ms without change");
} else {
if (log.isDebugEnabled()) {
log.debug("reopen returns in " + t0 + "ms without change");
}
}
return this;
}
ZoieMultiReader<R> ret = new ZoieMultiReader<R>(inner, _decorator, new ZoieSubReaderWrapper<R>(
_decorator, _readerMap));
t0 = System.currentTimeMillis() - t0;
if (t0 > 1000) {
log.info("reopen returns in " + t0 + "ms with change");
} else {
if (log.isDebugEnabled()) {
log.debug("reopen returns in " + t0 + "ms with change");
}
}
return ret;
}
/**
* makes exact shallow copy of a given ZoieMultiReader
* @throws IOException
*/
public ZoieMultiReader<R> copy() throws IOException {
// increase DirectoryReader reference counter
this.in.incRef();
ZoieMultiReader<R> ret = new ZoieMultiReader<R>(this.in, this._decorator,
new ZoieSubReaderWrapper<R>(this._decorator, this._readerMap));
ret._docIDMapper = this._docIDMapper;
return ret;
}
@Override
protected DirectoryReader doWrapDirectoryReader(DirectoryReader in) {
return in;
}
public static class ZoieSubReaderWrapper<R extends IndexReader> extends SubReaderWrapper {
private final IndexReaderDecorator<R> _decorator;
private final Map<String, ZoieSegmentReader<R>> _readerMap;
/** Constructor */
public ZoieSubReaderWrapper(IndexReaderDecorator<R> decorator) {
this(decorator, null);
}
public ZoieSubReaderWrapper(IndexReaderDecorator<R> decorator,
Map<String, ZoieSegmentReader<R>> readerMap) {
_decorator = decorator;
_readerMap = readerMap;
}
@Override
public AtomicReader wrap(AtomicReader reader) {
if (!(reader instanceof SegmentReader)) {
throw new IllegalStateException("reader not insance of " + SegmentReader.class);
}
try {
if (_readerMap != null && !_readerMap.isEmpty()) {
SegmentReader sr = (SegmentReader) reader;
String segmentName = sr.getSegmentName();
ZoieSegmentReader<R> zoieSegmentReader = _readerMap.get(segmentName);
if (zoieSegmentReader != null && zoieSegmentReader.getInnerReader() == sr) {
return new ZoieSegmentReader<R>(zoieSegmentReader, sr);
}
}
return new ZoieSegmentReader<R>(reader, _decorator);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
}