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

org.apache.druid.frame.read.FrameReaderUtils 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;

import com.google.common.primitives.Ints;
import org.apache.datasketches.memory.Memory;
import org.apache.druid.frame.allocation.MemoryRange;
import org.apache.druid.frame.field.ComplexFieldReader;
import org.apache.druid.frame.segment.row.FrameColumnSelectorFactory;
import org.apache.druid.segment.ColumnSelectorFactory;
import org.apache.druid.segment.ColumnValueSelector;
import org.apache.druid.segment.column.ColumnCapabilities;
import org.apache.druid.segment.column.ColumnType;
import org.apache.druid.segment.column.RowSignature;
import org.apache.druid.segment.column.ValueType;
import org.apache.druid.segment.serde.ComplexMetricSerde;

import javax.annotation.Nullable;
import java.nio.ByteBuffer;
import java.util.function.Supplier;

/**
 * Utility methods used by various entities that read data from {@link org.apache.druid.frame.Frame} objects.
 */
public class FrameReaderUtils
{
  /**
   * Returns a ByteBuffer containing data from the provided {@link Memory}. The ByteBuffer is always newly
   * created, so it is OK to change its position, limit, etc. However, it may point directly to the backing memory
   * of the {@link Memory} object, so it is not OK to write to its contents.
   */
  public static ByteBuffer readByteBuffer(final Memory memory, final long dataStart, final int dataLength)
  {
    if (memory.hasByteBuffer()) {
      // Avoid data copy
      final ByteBuffer byteBuffer = memory.getByteBuffer().duplicate();
      byteBuffer.limit(Ints.checkedCast(memory.getRegionOffset(dataStart + dataLength)));
      byteBuffer.position(Ints.checkedCast(memory.getRegionOffset(dataStart)));
      return byteBuffer;
    } else {
      final byte[] stringData = new byte[dataLength];
      memory.getByteArray(dataStart, stringData, 0, stringData.length);
      return ByteBuffer.wrap(stringData);
    }
  }

  /**
   * Returns a direct row memory supplier if {@link #mayBeAbleToSelectRowMemory}, otherwise returns null.
   *
   * Note that even if the returned supplier is nonnull, it is still possible for the supplied {@link MemoryRange}
   * to be null. Callers must check for this.
   *
   * @param columnSelectorFactory frame column selector factory
   * @param expectedSignature     expected signature of the target frame
   */
  @Nullable
  public static Supplier> makeRowMemorySupplier(
      final ColumnSelectorFactory columnSelectorFactory,
      final RowSignature expectedSignature
  )
  {
    if (mayBeAbleToSelectRowMemory(columnSelectorFactory)) {
      final ColumnValueSelector signatureSelector =
          columnSelectorFactory.makeColumnValueSelector(FrameColumnSelectorFactory.ROW_SIGNATURE_COLUMN);

      final ColumnValueSelector memorySelector =
          columnSelectorFactory.makeColumnValueSelector(FrameColumnSelectorFactory.ROW_MEMORY_COLUMN);

      return new Supplier>()
      {
        private RowSignature lastSignature = null;
        private boolean lastSignatureOk = false;

        @Override
        public MemoryRange get()
        {
          final RowSignature selectedSignature = (RowSignature) signatureSelector.getObject();

          //noinspection ObjectEquality: checking reference equality on purpose
          if (selectedSignature != lastSignature) {
            lastSignature = selectedSignature;
            lastSignatureOk = expectedSignature.equals(selectedSignature);
          }

          if (lastSignatureOk) {
            //noinspection unchecked
            return (MemoryRange) memorySelector.getObject();
          } else {
            return null;
          }
        }
      };
    } else {
      return null;
    }
  }

  /**
   * Compares two Memory ranges using unsigned byte ordering.
   *
   * Different from {@link Memory#compareTo}, which uses signed ordering.
   */
  public static int compareMemoryUnsigned(
      final Memory memory1,
      final long position1,
      final int length1,
      final Memory memory2,
      final long position2,
      final int length2
  )
  {
    final int commonLength = Math.min(length1, length2);

    for (int i = 0; i < commonLength; i += Long.BYTES) {
      final int remaining = commonLength - i;
      final long r1 = readComparableLong(memory1, position1 + i, remaining);
      final long r2 = readComparableLong(memory2, position2 + i, remaining);
      final int cmp = Long.compare(r1, r2);
      if (cmp != 0) {
        return cmp;
      }
    }

    return Integer.compare(length1, length2);
  }

  public static long readComparableLong(final Memory memory, final long position, final int length)
  {
    long retVal = 0;
    switch (length) {
      case 7:
        retVal |= (memory.getByte(position + 6) & 0xFFL) << 8;
      case 6:
        retVal |= (memory.getByte(position + 5) & 0xFFL) << 16;
      case 5:
        retVal |= (memory.getByte(position + 4) & 0xFFL) << 24;
      case 4:
        retVal |= (memory.getByte(position + 3) & 0xFFL) << 32;
      case 3:
        retVal |= (memory.getByte(position + 2) & 0xFFL) << 40;
      case 2:
        retVal |= (memory.getByte(position + 1) & 0xFFL) << 48;
      case 1:
        retVal |= (memory.getByte(position) & 0xFFL) << 56;
        break;
      default:
        retVal = Long.reverseBytes(memory.getLong(position));
    }

    return retVal + Long.MIN_VALUE;
  }

  /**
   * Compares Memory with a byte array using unsigned byte ordering.
   */
  public static int compareMemoryToByteArrayUnsigned(
      final Memory memory,
      final long position1,
      final long length1,
      final byte[] array,
      final int position2,
      final int length2
  )
  {
    final int commonLength = (int) Math.min(length1, length2);

    for (int i = 0; i < commonLength; i++) {
      final byte byte1 = memory.getByte(position1 + i);
      final byte byte2 = array[position2 + i];
      final int cmp = (byte1 & 0xFF) - (byte2 & 0xFF); // Unsigned comparison
      if (cmp != 0) {
        return cmp;
      }
    }

    return Long.compare(length1, length2);
  }

  /**
   * Compares two byte arrays using unsigned byte ordering.
   */
  public static int compareByteArraysUnsigned(
      final byte[] array1,
      final int position1,
      final int length1,
      final byte[] array2,
      final int position2,
      final int length2
  )
  {
    final int commonLength = Math.min(length1, length2);

    for (int i = 0; i < commonLength; i++) {
      final byte byte1 = array1[position1 + i];
      final byte byte2 = array2[position2 + i];
      final int cmp = (byte1 & 0xFF) - (byte2 & 0xFF); // Unsigned comparison
      if (cmp != 0) {
        return cmp;
      }
    }

    return Integer.compare(length1, length2);
  }

  public static int compareComplexTypes(
      final byte[] array1,
      final int position1,
      final byte[] array2,
      final int position2,
      final ColumnType columnType,
      final ComplexMetricSerde complexMetricSerde
  )
  {
    return columnType.getNullableStrategy().compare(
        ComplexFieldReader.readFieldFromByteArray(complexMetricSerde, array1, position1),
        ComplexFieldReader.readFieldFromByteArray(complexMetricSerde, array2, position2)
    );
  }

  public static int compareComplexTypes(
      final Memory memory,
      final long position1,
      final byte[] array,
      final int position2,
      final ColumnType columnType,
      final ComplexMetricSerde complexMetricSerde
  )
  {
    return columnType.getNullableStrategy().compare(
        ComplexFieldReader.readFieldFromMemory(complexMetricSerde, memory, position1),
        ComplexFieldReader.readFieldFromByteArray(complexMetricSerde, array, position2)
    );
  }

  public static int compareComplexTypes(
      final Memory memory1,
      final long position1,
      final Memory memory2,
      final long position2,
      final ColumnType columnType,
      final ComplexMetricSerde complexMetricSerde
  )
  {
    return columnType.getNullableStrategy().compare(
        ComplexFieldReader.readFieldFromMemory(complexMetricSerde, memory1, position1),
        ComplexFieldReader.readFieldFromMemory(complexMetricSerde, memory2, position2)
    );
  }


  /**
   * Returns whether a {@link ColumnSelectorFactory} may be able to provide a {@link MemoryRange}. This enables
   * efficient copying without needing to deal with each field individually.
   *
   * Note that if this method returns true, it may still not be possible to do direct row-memory copying.
   * Therefore, {@link #makeRowMemorySupplier} verifies the signature of each row.
   */
  private static boolean mayBeAbleToSelectRowMemory(final ColumnSelectorFactory columnSelectorFactory)
  {
    final ColumnCapabilities rowSignatureCapabilities =
        columnSelectorFactory.getColumnCapabilities(FrameColumnSelectorFactory.ROW_SIGNATURE_COLUMN);

    if (rowSignatureCapabilities == null || rowSignatureCapabilities.getType() != ValueType.COMPLEX) {
      return false;
    }

    final ColumnCapabilities rowMemoryCapabilities =
        columnSelectorFactory.getColumnCapabilities(FrameColumnSelectorFactory.ROW_MEMORY_COLUMN);

    if (rowMemoryCapabilities == null || rowMemoryCapabilities.getType() != ValueType.COMPLEX) {
      return false;
    }

    return true;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy