/**
* 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 java.util.Arrays;
import java.util.concurrent.atomic.AtomicLong;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.linkedin.pinot.core.common.BlockDocIdIterator;
import com.linkedin.pinot.core.common.Constants;
public final class AndDocIdIterator implements BlockDocIdIterator {
static final Logger LOGGER = LoggerFactory.getLogger(AndDocIdIterator.class);
public final BlockDocIdIterator[] docIdIterators;
public ScanBasedDocIdIterator[] scanBasedDocIdIterators;
public final int[] docIdPointers;
public boolean reachedEnd = false;
public int currentDocId = -1;
int currentMax = -1;
private boolean hasScanBasedIterators;
public AndDocIdIterator(BlockDocIdIterator[] blockDocIdIterators) {
int numIndexBasedIterators = 0;
int numScanBasedIterators = 0;
for (int i = 0; i < blockDocIdIterators.length; i++) {
if (blockDocIdIterators[i] instanceof IndexBasedDocIdIterator) {
numIndexBasedIterators = numIndexBasedIterators + 1;
} else if (blockDocIdIterators[i] instanceof ScanBasedDocIdIterator) {
numScanBasedIterators = numScanBasedIterators + 1;
}
}
// if we have at least one index based then do intersection based on index based only, and then
// check if matching docs apply on scan based iterator
if (numIndexBasedIterators > 0 && numScanBasedIterators > 0) {
hasScanBasedIterators = true;
int nonScanIteratorsSize = blockDocIdIterators.length - numScanBasedIterators;
this.docIdIterators = new BlockDocIdIterator[nonScanIteratorsSize];
this.scanBasedDocIdIterators = new ScanBasedDocIdIterator[numScanBasedIterators];
int nonScanBasedIndex = 0;
int scanBasedIndex = 0;
for (int i = 0; i < blockDocIdIterators.length; i++) {
if (blockDocIdIterators[i] instanceof ScanBasedDocIdIterator) {
this.scanBasedDocIdIterators[scanBasedIndex++] =
(ScanBasedDocIdIterator) blockDocIdIterators[i];
} else {
this.docIdIterators[nonScanBasedIndex++] = blockDocIdIterators[i];
}
}
} else {
hasScanBasedIterators = false;
this.docIdIterators = blockDocIdIterators;
}
this.docIdPointers = new int[docIdIterators.length];
Arrays.fill(docIdPointers, -1);
}
@Override
public int advance(int targetDocId) {
if (currentDocId == Constants.EOF) {
return currentDocId;
}
if (currentDocId >= targetDocId) {
return currentDocId;
}
// next() method will always increment currentMax by 1.
currentMax = targetDocId - 1;
return next();
}
@Override
public int next() {
if (currentDocId == Constants.EOF) {
return currentDocId;
}
currentMax = currentMax + 1;
// always increment the pointer to current max, when this is called first time, every one will
// be set to start of posting list.
for (int i = 0; i < docIdIterators.length; i++) {
docIdPointers[i] = docIdIterators[i].advance(currentMax);
if (docIdPointers[i] == Constants.EOF) {
reachedEnd = true;
currentMax = Constants.EOF;
break;
}
if (docIdPointers[i] > currentMax) {
currentMax = docIdPointers[i];
if (i > 0) {
// we need to advance all pointer since we found a new max
i = -1;
}
}
if (hasScanBasedIterators && i == docIdIterators.length - 1 ) {
// this means we found the docId common to all nonScanBased iterators, now we need to ensure
// that its also found in scanBasedIterator, if not matched, we restart the intersection
for (ScanBasedDocIdIterator iterator : scanBasedDocIdIterators) {
if (!iterator.isMatch(currentMax)) {
i = -1;
currentMax = currentMax + 1;
break;
}
}
}
}
currentDocId = currentMax;
return currentDocId;
}
@Override
public int currentDocId() {
return currentDocId;
}
public String toString() {
return Arrays.toString(docIdIterators);
}
}