All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.druid.frame.read.columnar.LongFrameColumnReader Maven / Gradle / Ivy

There is a newer version: 31.0.0
Show newest version
/*
 * 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.
 */

package org.apache.druid.frame.read.columnar;

import org.apache.datasketches.memory.Memory;
import org.apache.druid.common.config.NullHandling;
import org.apache.druid.frame.Frame;
import org.apache.druid.frame.write.columnar.FrameColumnWriters;
import org.apache.druid.frame.write.columnar.LongFrameMaker;
import org.apache.druid.java.util.common.ISE;
import org.apache.druid.query.monomorphicprocessing.RuntimeShapeInspector;
import org.apache.druid.query.rowsandcols.column.Column;
import org.apache.druid.query.rowsandcols.column.ColumnAccessorBasedColumn;
import org.apache.druid.query.rowsandcols.column.accessor.LongColumnAccessorBase;
import org.apache.druid.segment.ColumnValueSelector;
import org.apache.druid.segment.LongColumnSelector;
import org.apache.druid.segment.column.ColumnCapabilitiesImpl;
import org.apache.druid.segment.column.NumericColumn;
import org.apache.druid.segment.data.ReadableOffset;
import org.apache.druid.segment.vector.BaseLongVectorValueSelector;
import org.apache.druid.segment.vector.ReadableVectorInspector;
import org.apache.druid.segment.vector.ReadableVectorOffset;
import org.apache.druid.segment.vector.VectorValueSelector;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

public class LongFrameColumnReader implements FrameColumnReader
{
  private final int columnNumber;

  LongFrameColumnReader(final int columnNumber)
  {
    this.columnNumber = columnNumber;
  }

  @Override
  public Column readRACColumn(Frame frame)
  {
    final LongFrameColumn frameCol = makeLongFrameColumn(frame);

    return new ColumnAccessorBasedColumn(frameCol);

  }

  @Override
  public ColumnPlus readColumn(final Frame frame)
  {
    final LongFrameColumn frameCol = makeLongFrameColumn(frame);

    return new ColumnPlus(
        frameCol,
        ColumnCapabilitiesImpl.createSimpleNumericColumnCapabilities(frameCol.getType())
                              .setHasNulls(NullHandling.sqlCompatible() && frameCol.hasNulls),
        frame.numRows()
    );
  }

  @Nonnull
  private LongFrameColumn makeLongFrameColumn(Frame frame)
  {
    final Memory memory = frame.region(columnNumber);
    validate(memory, frame.numRows());

    final boolean hasNulls = getHasNulls(memory);
    return new LongFrameColumn(frame, hasNulls, memory);
  }

  private void validate(final Memory region, final int numRows)
  {
    // Check if column is big enough for a header
    if (region.getCapacity() < LongFrameMaker.DATA_OFFSET) {
      throw new ISE("Column is not big enough for a header");
    }

    final byte typeCode = region.getByte(0);
    if (typeCode != FrameColumnWriters.TYPE_LONG) {
      throw new ISE("Column does not have the correct type code");
    }

    final boolean hasNulls = getHasNulls(region);
    final int sz = LongFrameMaker.valueSize(hasNulls);

    // Check column length again, now that we know exactly how long it should be.
    if (region.getCapacity() != LongFrameMaker.DATA_OFFSET + (long) sz * numRows) {
      throw new ISE("Column does not have the correct length");
    }
  }

  private static boolean getHasNulls(final Memory memoryRange)
  {
    return memoryRange.getByte(Byte.BYTES) != 0;
  }

  private static class LongFrameColumn extends LongColumnAccessorBase implements NumericColumn
  {
    private final Frame frame;
    private final boolean hasNulls;
    private final int sz;
    private final Memory memory;
    private final long memoryPosition;

    private LongFrameColumn(
        final Frame frame,
        final boolean hasNulls,
        final Memory memory
    )
    {
      this.frame = frame;
      this.hasNulls = hasNulls;
      this.sz = LongFrameMaker.valueSize(hasNulls);
      this.memory = memory;
      this.memoryPosition = LongFrameMaker.DATA_OFFSET;
    }

    @Override
    public ColumnValueSelector makeColumnValueSelector(final ReadableOffset offset)
    {
      return new LongColumnSelector()
      {
        @Override
        public long getLong()
        {
          assert NullHandling.replaceWithDefault() || !isNull();
          return LongFrameColumn.this.getLongPhysical(frame.physicalRow(offset.getOffset()));
        }

        @Override
        public boolean isNull()
        {
          return LongFrameColumn.this.isNullPhysical(frame.physicalRow(offset.getOffset()));
        }

        @Override
        public void inspectRuntimeShape(RuntimeShapeInspector inspector)
        {
          // Do nothing.
        }
      };
    }

    @Override
    public VectorValueSelector makeVectorValueSelector(final ReadableVectorOffset theOffset)
    {
      class LongFrameColumnVectorValueSelector extends BaseLongVectorValueSelector
      {
        private final long[] longVector;
        private final boolean[] nullVector;

        private int id = ReadableVectorInspector.NULL_ID;

        private LongFrameColumnVectorValueSelector()
        {
          super(theOffset);
          this.longVector = new long[offset.getMaxVectorSize()];
          this.nullVector = hasNulls ? new boolean[offset.getMaxVectorSize()] : null;
        }

        @Nullable
        @Override
        public boolean[] getNullVector()
        {
          computeVectorsIfNeeded();
          return nullVector;
        }

        @Override
        public long[] getLongVector()
        {
          computeVectorsIfNeeded();
          return longVector;
        }

        private void computeVectorsIfNeeded()
        {
          if (id == offset.getId()) {
            return;
          }

          if (offset.isContiguous()) {
            final int start = offset.getStartOffset();

            for (int i = 0; i < offset.getCurrentVectorSize(); i++) {
              final int physicalRow = frame.physicalRow(i + start);
              longVector[i] = getLongPhysical(physicalRow);

              if (hasNulls) {
                nullVector[i] = isNullPhysical(physicalRow);
              }
            }
          } else {
            final int[] offsets = offset.getOffsets();

            for (int i = 0; i < offset.getCurrentVectorSize(); i++) {
              final int physicalRow = frame.physicalRow(offsets[i]);
              longVector[i] = getLongPhysical(physicalRow);

              if (hasNulls) {
                nullVector[i] = isNullPhysical(physicalRow);
              }
            }
          }

          id = offset.getId();
        }
      }

      return new LongFrameColumnVectorValueSelector();
    }

    @Override
    public int length()
    {
      return frame.numRows();
    }

    @Override
    public long getLongSingleValueRow(final int rowNum)
    {
      // Need bounds checking, since getLong(physicalRow) doesn't do it.
      if (rowNum < 0 || rowNum >= frame.numRows()) {
        throw new ISE("Row [%d] out of bounds", rowNum);
      }

      return getLongPhysical(frame.physicalRow(rowNum));
    }

    @Override
    public void close()
    {
      // Do nothing.
    }

    @Override
    public void inspectRuntimeShape(final RuntimeShapeInspector inspector)
    {
      // Do nothing.
    }

    @Override
    public int numRows()
    {
      return length();
    }

    @Override
    public boolean isNull(int rowNum)
    {
      return isNullPhysical(frame.physicalRow(rowNum));
    }

    @Override
    public long getLong(int rowNum)
    {
      return getLongPhysical(frame.physicalRow(rowNum));
    }

    private boolean isNullPhysical(final int physicalRow)
    {
      if (hasNulls) {
        final long rowPosition = memoryPosition + (long) sz * physicalRow;
        return memory.getByte(rowPosition) != 0;
      } else {
        return false;
      }
    }

    private long getLongPhysical(final int physicalRow)
    {
      final long rowPosition = memoryPosition + (long) sz * physicalRow;

      if (hasNulls) {
        return memory.getLong(rowPosition + 1);
      } else {
        return memory.getLong(rowPosition);
      }
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy