/**
* 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.startree;
import com.linkedin.pinot.core.segment.creator.impl.V1Constants;
import java.util.Iterator;
import xerial.larray.buffer.LBufferAPI;
public class StarTreeIndexNodeOffHeap implements StarTreeIndexNodeInterf {
public static final int INVALID_INDEX = -1;
// Number of fields of this class that will be serialized.
private static final int NUMBER_OF_SERIALIZABLE_FIELDS = 7;
// Hard-coded the serializable size of StarTreeIndexNodeOffHeap object.
private static final int NODE_SERIALIZABLE_SIZE = V1Constants.Numbers.INTEGER_SIZE * NUMBER_OF_SERIALIZABLE_FIELDS;
private static final long DIMENSION_NAME_OFFSET = 0;
private static final long DIMENSION_VALUE_OFFSET = DIMENSION_NAME_OFFSET + V1Constants.Numbers.INTEGER_SIZE;
private static final long START_DOCUMENT_ID_OFFSET = DIMENSION_VALUE_OFFSET + V1Constants.Numbers.INTEGER_SIZE;
private static final long END_DOCUMENT_ID_OFFSET = START_DOCUMENT_ID_OFFSET + V1Constants.Numbers.INTEGER_SIZE;
private static final long AGGREGATED_DOCUMENT_ID_OFFSET = END_DOCUMENT_ID_OFFSET + V1Constants.Numbers.INTEGER_SIZE;
private static final long CHILDREN_START_INDEX_OFFSET =
AGGREGATED_DOCUMENT_ID_OFFSET + V1Constants.Numbers.INTEGER_SIZE;
private static final long CHILDREN_END_INDEX_OFFSET = CHILDREN_START_INDEX_OFFSET + V1Constants.Numbers.INTEGER_SIZE;
private final LBufferAPI dataBuffer;
private int dimensionName;
private int dimensionValue;
private int startDocumentId;
private int endDocumentId;
private int aggregatedDocumentId;
private int childrenStartIndex;
private int childrenEndIndex;
/**
* Constructor for the class.
* - Reads all fields from the data buffer.
*
* @param dataBuffer
* @param nodeId
*/
public StarTreeIndexNodeOffHeap(LBufferAPI dataBuffer, int nodeId) {
this.dataBuffer = dataBuffer;
long offset = nodeId * NODE_SERIALIZABLE_SIZE;
dimensionName = dataBuffer.getInt(offset);
offset += V1Constants.Numbers.INTEGER_SIZE;
dimensionValue = dataBuffer.getInt(offset);
offset += V1Constants.Numbers.INTEGER_SIZE;
startDocumentId = dataBuffer.getInt(offset);
offset += V1Constants.Numbers.INTEGER_SIZE;
endDocumentId = dataBuffer.getInt(offset);
offset += V1Constants.Numbers.INTEGER_SIZE;
aggregatedDocumentId = dataBuffer.getInt(offset);
offset += V1Constants.Numbers.INTEGER_SIZE;
childrenStartIndex = dataBuffer.getInt(offset);
offset += V1Constants.Numbers.INTEGER_SIZE;
childrenEndIndex = dataBuffer.getInt(offset);
}
/**
* {@inheritDoc}
* @return
*/
@Override
public int getDimensionName() {
return dimensionName;
}
/**
* {@inheritDoc}
* @param dimensionName
*/
@Override
public void setDimensionName(int dimensionName) {
this.dimensionName = dimensionName;
}
/**
* {@inheritDoc}
* @return
*/
@Override
public int getDimensionValue() {
return dimensionValue;
}
/**
* {@inheritDoc}
* @param dimensionValue
*/
@Override
public void setDimensionValue(int dimensionValue) {
this.dimensionValue = dimensionValue;
}
/**
* {@inheritDoc}
* @return
*/
@Override
public int getStartDocumentId() {
return startDocumentId;
}
/**
* {@inheritDoc}
* @param startDocumentId
*/
@Override
public void setStartDocumentId(int startDocumentId) {
this.startDocumentId = startDocumentId;
}
/**
* {@inheritDoc}
* @return
*/
@Override
public int getEndDocumentId() {
return endDocumentId;
}
/**
* {@inheritDoc}
* @param endDocumentId
*/
@Override
public void setEndDocumentId(int endDocumentId) {
this.endDocumentId = endDocumentId;
}
/**
* {@inheritDoc}
* @return
*/
@Override
public int getAggregatedDocumentId() {
return aggregatedDocumentId;
}
/**
* {@inheritDoc}
* @param aggregatedDocumentId
*/
@Override
public void setAggregatedDocumentId(int aggregatedDocumentId) {
this.aggregatedDocumentId = aggregatedDocumentId;
}
/**
* {@inheritDoc}
* @return
*/
@Override
public int getNumChildren() {
return (childrenStartIndex != INVALID_INDEX) ? (childrenEndIndex - childrenStartIndex + 1) : 0;
}
/**
* {@inheritDoc}
* @return
*/
@Override
public boolean isLeaf() {
return (childrenStartIndex == INVALID_INDEX);
}
/**
* {@inheritDoc}
* Performs binary search over children (that are sorted by dimension value)
* and returns child that matches the dimension value.
* Returns NULL if no child was found for the specified value.
*
* @param dimensionValue
* @return
*/
@Override
public StarTreeIndexNodeInterf getChildForDimensionValue(int dimensionValue) {
if (isLeaf()) {
return null;
}
int lo = childrenStartIndex;
int hi = childrenEndIndex;
while (lo <= hi) {
int mid = lo + ((hi - lo) >>> 1);
StarTreeIndexNodeOffHeap midNode = new StarTreeIndexNodeOffHeap(dataBuffer, mid);
int midValue = midNode.getDimensionValue();
if (midValue == dimensionValue) {
return midNode;
} else if (midValue < dimensionValue) {
lo = mid + 1;
} else {
hi = mid - 1;
}
}
return null;
}
/**
* {@inheritDoc}
* @return
*/
@Override
public Iterator<? extends StarTreeIndexNodeInterf> getChildrenIterator() {
return new ChildIterator();
}
/**
* {@inheritDoc}
* @return
*/
@Override
public int getChildDimensionName() {
long childDimensNameOffset = (childrenStartIndex * NODE_SERIALIZABLE_SIZE) + DIMENSION_NAME_OFFSET;
return (!isLeaf()) ? dataBuffer.getInt(childDimensNameOffset) : INVALID_INDEX;
}
/**
* Get the start index for children of this node.
* @return
*/
public int getChildrenStartIndex() {
return childrenStartIndex;
}
/**
* Set the start index for children of this node.
* @param childrenStartIndex
*/
public void setChildrenStartIndex(int childrenStartIndex) {
this.childrenStartIndex = childrenStartIndex;
}
/**
* Get the end index for children of this node.
* @return
*/
public int getChildrenEndIndex() {
return childrenEndIndex;
}
/**
* Get Set the end index for children of this node.
* @param childrenEndIndex
*/
public void setChildrenEndIndex(int childrenEndIndex) {
this.childrenEndIndex = childrenEndIndex;
}
/**
* Return the total size in bytes of fields that will be serialized.
* @return
*/
public static int getSerializableSize() {
return NODE_SERIALIZABLE_SIZE;
}
/**
* Iterator over children nodes.
*/
private class ChildIterator implements Iterator<StarTreeIndexNodeOffHeap> {
private int curChildId;
private int endChildId;
private StarTreeIndexNodeOffHeap child;
public ChildIterator() {
curChildId = getChildrenStartIndex();
endChildId = getChildrenEndIndex();
}
@Override
public boolean hasNext() {
return ((curChildId != INVALID_INDEX) && (curChildId <= endChildId));
}
@Override
public StarTreeIndexNodeOffHeap next() {
StarTreeIndexNodeOffHeap child = new StarTreeIndexNodeOffHeap(dataBuffer, curChildId);
curChildId++;
return child;
}
@Override
public void remove() {
throw new UnsupportedOperationException("Operation 'remove' not supported in class " + getClass().getName());
}
}
}