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.ints.IntRBTreeSet;
import it.unimi.dsi.fastutil.longs.LongIterator;
import it.unimi.dsi.fastutil.longs.LongSet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.MultiZoieTermDocs;
import org.apache.lucene.index.MultiZoieTermPositions;
import org.apache.lucene.index.SegmentReader;
import org.apache.lucene.index.TermDocs;
import org.apache.lucene.index.TermPositions;
import proj.zoie.api.indexing.IndexReaderDecorator;
public class ZoieMultiReader<R extends IndexReader> extends ZoieIndexReader<R> {
private Map<String,ZoieSegmentReader<R>> _readerMap;
private ArrayList<ZoieSegmentReader<R>> _subZoieReaders;
private int[] _starts;
private List<R> _decoratedReaders;
public ZoieMultiReader(IndexReader in,IndexReaderDecorator<R> decorator) throws IOException {
super(in,decorator);
_readerMap = new HashMap<String,ZoieSegmentReader<R>>();
_decoratedReaders = null;
IndexReader[] subReaders = in.getSequentialSubReaders();
init(subReaders);
}
public ZoieMultiReader(IndexReader in,IndexReader[] subReaders,IndexReaderDecorator<R> decorator) throws IOException {
super(in,decorator);
_readerMap = new HashMap<String,ZoieSegmentReader<R>>();
_decoratedReaders = null;
init(subReaders);
}
private void init(IndexReader[] subReaders) throws IOException{
_subZoieReaders = new ArrayList<ZoieSegmentReader<R>>(subReaders.length);
_starts = new int[subReaders.length+1];
int i = 0;
int startCount=0;
for (IndexReader subReader : subReaders){
ZoieSegmentReader<R> zr=null;
if (subReader instanceof ZoieSegmentReader<?>){
zr = (ZoieSegmentReader<R>)subReader;
}
else if (subReader instanceof SegmentReader){
SegmentReader sr = (SegmentReader)subReader;
zr = new ZoieSegmentReader<R>(sr,_decorator);
}
if (zr!=null){
String segmentName = zr.getSegmentName();
_readerMap.put(segmentName, zr);
_subZoieReaders.add(zr);
_starts[i]=startCount;
i++;
startCount+=zr.maxDoc();
}
else{
throw new IllegalStateException("subreader not instance of "+SegmentReader.class);
}
}
_starts[subReaders.length]=in.maxDoc();
ArrayList<R> decoratedList = new ArrayList<R>(_subZoieReaders.size());
for (ZoieSegmentReader<R> subReader : _subZoieReaders){
R decoratedReader = subReader.getDecoratedReader();
decoratedList.add(decoratedReader);
}
_decoratedReaders = decoratedList;
}
@Override
public long getUID(int docid)
{
int idx = readerIndex(docid);
ZoieIndexReader<R> subReader = _subZoieReaders.get(idx);
return subReader.getUID(docid-_starts[idx]);
}
@SuppressWarnings("unchecked")
@Override
public ZoieIndexReader<R>[] getSequentialSubReaders() {
return (ZoieIndexReader<R>[])(_subZoieReaders.toArray(new ZoieIndexReader[_subZoieReaders.size()]));
}
@Override
public void markDeletes(LongSet delDocs, LongSet deletedUIDs)
{
ZoieIndexReader<R>[] subReaders = getSequentialSubReaders();
if(subReaders != null && subReaders.length > 0)
{
for(int i = 0; i < subReaders.length; i++)
{
ZoieSegmentReader<R> subReader = (ZoieSegmentReader)subReaders[i];
subReader.markDeletes(delDocs, deletedUIDs);
}
}
}
@Override
public void commitDeletes()
{
ZoieIndexReader<R>[] subReaders = getSequentialSubReaders();
if(subReaders != null && subReaders.length > 0)
{
for(int i = 0; i < subReaders.length; i++)
{
ZoieSegmentReader<R> subReader = (ZoieSegmentReader)subReaders[i];
subReader.commitDeletes();
}
}
}
@Override
public void setDelDocIds()
{
ZoieIndexReader<R>[] subReaders = getSequentialSubReaders();
for(ZoieIndexReader<R> subReader : subReaders)
{
subReader.setDelDocIds();
}
}
@Override
public List<R> getDecoratedReaders() throws IOException{
return _decoratedReaders;
}
@Override
protected boolean hasIndexDeletions(){
for (ZoieSegmentReader<R> subReader : _subZoieReaders){
if (subReader.hasIndexDeletions()) return true;
}
return false;
}
@Override
public boolean isDeleted(int docid){
int idx = readerIndex(docid);
ZoieIndexReader<R> subReader = _subZoieReaders.get(idx);
return subReader.isDeleted(docid-_starts[idx]);
}
private int readerIndex(int n){
return readerIndex(n,_starts,_starts.length);
}
final static int readerIndex(int n, int[] starts, int numSubReaders) { // find reader for doc n:
int lo = 0; // search starts array
int hi = numSubReaders - 1; // for first element less
while (hi >= lo) {
int mid = (lo + hi) >>> 1;
int midValue = starts[mid];
if (n < midValue)
hi = mid - 1;
else if (n > midValue)
lo = mid + 1;
else { // found a match
while (mid+1 < numSubReaders && starts[mid+1] == midValue) {
mid++; // scan to last match
}
return mid;
}
}
return hi;
}
@Override
public TermDocs termDocs() throws IOException {
return new MultiZoieTermDocs(this,_subZoieReaders.toArray(new ZoieIndexReader<?>[_subZoieReaders.size()]),_starts);
}
@Override
public TermPositions termPositions() throws IOException {
return new MultiZoieTermPositions(this,_subZoieReaders.toArray(new ZoieIndexReader<?>[_subZoieReaders.size()]),_starts);
}
@Override
public DocIDMapper getDocIDMaper() {
return new DocIDMapper() {
public int getDocID(long uid) {
for (int i = 0; i < _subZoieReaders.size(); ++i){
ZoieIndexReader<R> subReader = _subZoieReaders.get(i);
int docid = subReader.getDocIDMaper().getDocID(uid);
if (docid!=DocIDMapper.NOT_FOUND) {
return docid+_starts[i];
}
}
return DocIDMapper.NOT_FOUND;
}
};
}
/*
@Override
protected void doClose() throws IOException {
try{
super.doClose();
}
finally{
for (ZoieSegmentReader<R> r : _subZoieReaders){
r.close();
}
}
}
*/
@Override
public synchronized ZoieIndexReader<R> reopen(boolean openReadOnly)
throws CorruptIndexException, IOException {
long version = in.getVersion();
IndexReader inner = in.reopen(openReadOnly);
if (inner == in && inner.getVersion()==version){
return this;
}
IndexReader[] subReaders = inner.getSequentialSubReaders();
ArrayList<IndexReader> subReaderList = new ArrayList<IndexReader>(subReaders.length);
for (IndexReader subReader : subReaders){
if (subReader instanceof SegmentReader){
SegmentReader sr = (SegmentReader)subReader;
String segmentName = sr.getSegmentName();
ZoieSegmentReader<R> zoieSegmentReader = _readerMap.get(segmentName);
if (zoieSegmentReader!=null){
int numDocs = sr.numDocs();
int maxDocs = sr.maxDoc();
if (zoieSegmentReader.numDocs() != numDocs || zoieSegmentReader.maxDoc() != maxDocs){
// segment has changed
zoieSegmentReader = new ZoieSegmentReader<R>(sr,_decorator);
}
else{
zoieSegmentReader = new ZoieSegmentReader<R>(zoieSegmentReader,sr);
}
}
else{
zoieSegmentReader = new ZoieSegmentReader<R>(sr,_decorator);
}
subReaderList.add(zoieSegmentReader);
}
else{
throw new IllegalStateException("reader not insance of "+SegmentReader.class);
}
}
return newInstance(inner, subReaderList.toArray(new IndexReader[subReaderList.size()]));
}
protected ZoieMultiReader<R> newInstance(IndexReader inner,IndexReader[] subReaders) throws IOException{
return new ZoieMultiReader<R>(inner, subReaders ,_decorator);
}
}