/**
* Copyright (C) 2014-2016 LinkedIn Corp. (pinot-core@linkedin.com)
*
* 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 com.linkedin.pinot.core.operator.dociditerators;
import com.linkedin.pinot.core.common.BlockMetadata;
import com.linkedin.pinot.core.common.BlockMultiValIterator;
import com.linkedin.pinot.core.common.BlockValSet;
import com.linkedin.pinot.core.common.Constants;
import com.linkedin.pinot.core.operator.filter.predicate.PredicateEvaluator;
import java.util.Arrays;
import org.roaringbitmap.IntIterator;
import org.roaringbitmap.buffer.MutableRoaringBitmap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MVScanDocIdIterator implements ScanBasedDocIdIterator {
static final Logger LOGGER = LoggerFactory.getLogger(MVScanDocIdIterator.class);
BlockMultiValIterator valueIterator;
int currentDocId = -1;
final int[] intArray;
private int startDocId;
private int endDocId;
private PredicateEvaluator evaluator;
private String datasourceName;
private int _numEntriesScanned = 0;
public MVScanDocIdIterator(String datasourceName, BlockValSet blockValSet, BlockMetadata blockMetadata,
PredicateEvaluator evaluator) {
this.datasourceName = datasourceName;
this.evaluator = evaluator;
if (evaluator.alwaysFalse()) {
this.intArray = new int[0];
setStartDocId(Constants.EOF);
setEndDocId(Constants.EOF);
currentDocId = Constants.EOF;
} else {
this.intArray = new int[blockMetadata.getMaxNumberOfMultiValues()];
Arrays.fill(intArray, 0);
setStartDocId(blockMetadata.getStartDocId());
setEndDocId(blockMetadata.getEndDocId());
}
valueIterator = (BlockMultiValIterator) blockValSet.iterator();
}
/**
* After setting the startDocId, next calls will always return from >=startDocId
* @param startDocId
*/
public void setStartDocId(int startDocId) {
this.startDocId = startDocId;
}
/**
* After setting the endDocId, next call will return Constants.EOF after currentDocId exceeds
* endDocId
* @param endDocId
*/
public void setEndDocId(int endDocId) {
this.endDocId = endDocId;
}
@Override
public boolean isMatch(int docId) {
if (currentDocId == Constants.EOF) {
return false;
}
valueIterator.skipTo(docId);
_numEntriesScanned++;
int length = valueIterator.nextIntVal(intArray);
return evaluator.apply(intArray, length);
}
@Override
public int advance(int targetDocId) {
if (currentDocId == Constants.EOF) {
return currentDocId;
}
if (targetDocId < startDocId) {
targetDocId = startDocId;
} else if (targetDocId > endDocId) {
currentDocId = Constants.EOF;
}
if (currentDocId >= targetDocId) {
return currentDocId;
} else {
currentDocId = targetDocId - 1;
valueIterator.skipTo(targetDocId);
int next = next();
return next;
}
}
@Override
public int next() {
if (currentDocId == Constants.EOF) {
return currentDocId;
}
while (valueIterator.hasNext() && currentDocId < endDocId) {
currentDocId = currentDocId + 1;
_numEntriesScanned++;
int length = valueIterator.nextIntVal(intArray);
if (evaluator.apply(intArray, length)) {
return currentDocId;
}
}
currentDocId = Constants.EOF;
return Constants.EOF;
}
@Override
public int currentDocId() {
return currentDocId;
}
@Override
public String toString() {
return MVScanDocIdIterator.class.getSimpleName() + "[" + datasourceName + "]";
}
@Override
public MutableRoaringBitmap applyAnd(MutableRoaringBitmap answer) {
MutableRoaringBitmap result = new MutableRoaringBitmap();
if (evaluator.alwaysFalse()) {
return result;
}
IntIterator intIterator = answer.getIntIterator();
int docId = -1, length;
while (intIterator.hasNext() && docId < endDocId) {
docId = intIterator.next();
if (docId >= startDocId) {
valueIterator.skipTo(docId);
_numEntriesScanned++;
length = valueIterator.nextIntVal(intArray);
if (evaluator.apply(intArray, length)) {
result.add(docId);
}
}
}
return result;
}
@Override
public int getNumEntriesScanned() {
return _numEntriesScanned;
}
}