示例#1
0
 private static byte[] getKey(
     RowKeySchema schema, List<List<KeyRange>> slots, int[] slotSpan, Bound bound) {
   if (slots.isEmpty()) {
     return KeyRange.UNBOUND;
   }
   int[] position = new int[slots.size()];
   int maxLength = 0;
   for (int i = 0; i < position.length; i++) {
     position[i] = bound == Bound.LOWER ? 0 : slots.get(i).size() - 1;
     KeyRange range = slots.get(i).get(position[i]);
     Field field = schema.getField(i + slotSpan[i]);
     int keyLength = range.getRange(bound).length;
     if (!field.getDataType().isFixedWidth()) {
       keyLength++;
       if (range.isUnbound(bound)
           && !range.isInclusive(bound)
           && field.getSortOrder() == SortOrder.DESC) {
         keyLength++;
       }
     }
     maxLength += keyLength;
   }
   byte[] key = new byte[maxLength];
   int length = setKey(schema, slots, slotSpan, position, bound, key, 0, 0, position.length);
   if (length == 0) {
     return KeyRange.UNBOUND;
   }
   if (length == maxLength) {
     return key;
   }
   byte[] keyCopy = new byte[length];
   System.arraycopy(key, 0, keyCopy, 0, length);
   return keyCopy;
 }
示例#2
0
 private static int getTerminatorCount(RowKeySchema schema) {
   int nTerminators = 0;
   for (int i = 0; i < schema.getFieldCount(); i++) {
     Field field = schema.getField(i);
     // We won't have a terminator on the last PK column
     // unless it is variable length and exclusive, but
     // having the extra byte irregardless won't hurt anything
     if (!field.getDataType().isFixedWidth()) {
       nTerminators++;
     }
   }
   return nTerminators;
 }
示例#3
0
 public static PName padTenantIdIfNecessary(
     RowKeySchema schema, boolean isSalted, PName tenantId) {
   int pkPos = isSalted ? 1 : 0;
   String tenantIdStr = tenantId.getString();
   Field field = schema.getField(pkPos);
   PDataType dataType = field.getDataType();
   boolean isFixedWidth = dataType.isFixedWidth();
   Integer maxLength = field.getMaxLength();
   if (isFixedWidth && maxLength != null) {
     if (tenantIdStr.length() < maxLength) {
       tenantIdStr = (String) dataType.pad(tenantIdStr, maxLength);
       return PNameFactory.newName(tenantIdStr);
     }
   }
   return tenantId;
 }
示例#4
0
 private static byte[] nextKey(byte[] key, RowKeySchema schema, ImmutableBytesWritable ptr) {
   int pos = 0;
   int maxOffset = schema.iterator(key, ptr);
   while (schema.next(ptr, pos, maxOffset) != null) {
     pos++;
   }
   Field field = schema.getField(pos - 1);
   if (!field.getDataType().isFixedWidth()) {
     byte[] newLowerRange = new byte[key.length + 1];
     System.arraycopy(key, 0, newLowerRange, 0, key.length);
     newLowerRange[key.length] =
         SchemaUtil.getSeparatorByte(schema.rowKeyOrderOptimizable(), key.length == 0, field);
     key = newLowerRange;
   } else {
     key = Arrays.copyOf(key, key.length);
   }
   ByteUtil.nextKey(key, key.length);
   return key;
 }
示例#5
0
  public static TimeRange getDescTimeRange(
      KeyRange lowestKeyRange, KeyRange highestKeyRange, Field f) throws IOException {
    boolean lowerUnbound = lowestKeyRange.lowerUnbound();
    boolean lowerInclusive = lowestKeyRange.isLowerInclusive();
    boolean upperUnbound = highestKeyRange.upperUnbound();
    boolean upperInclusive = highestKeyRange.isUpperInclusive();

    long low =
        lowerUnbound
            ? -1
            : f.getDataType()
                .getCodec()
                .decodeLong(lowestKeyRange.getLowerRange(), 0, SortOrder.DESC);
    long high =
        upperUnbound
            ? -1
            : f.getDataType()
                .getCodec()
                .decodeLong(highestKeyRange.getUpperRange(), 0, SortOrder.DESC);
    long newHigh;
    long newLow;
    if (!lowerUnbound && !upperUnbound) {
      newHigh = lowerInclusive ? safelyIncrement(low) : low;
      newLow = upperInclusive ? high : safelyIncrement(high);
      return new TimeRange(newLow, newHigh);
    } else if (!lowerUnbound && upperUnbound) {
      newHigh = lowerInclusive ? safelyIncrement(low) : low;
      newLow = 0;
      return new TimeRange(newLow, newHigh);
    } else if (lowerUnbound && !upperUnbound) {
      newLow = upperInclusive ? high : safelyIncrement(high);
      newHigh = HConstants.LATEST_TIMESTAMP;
      return new TimeRange(newLow, newHigh);
    } else {
      newLow = 0;
      newHigh = HConstants.LATEST_TIMESTAMP;
      return new TimeRange(newLow, newHigh);
    }
  }
示例#6
0
 /**
  * Perform a binary lookup on the list of KeyRange for the tightest slot such that the slotBound
  * of the current slot is higher or equal than the slotBound of our range.
  *
  * @return the index of the slot whose slot bound equals or are the tightest one that is smaller
  *     than rangeBound of range, or slots.length if no bound can be found.
  */
 public static int searchClosestKeyRangeWithUpperHigherThanPtr(
     List<KeyRange> slots, ImmutableBytesWritable ptr, int lower, Field field) {
   int upper = slots.size() - 1;
   int mid;
   BytesComparator comparator =
       ScanUtil.getComparator(field.getDataType().isFixedWidth(), field.getSortOrder());
   while (lower <= upper) {
     mid = (lower + upper) / 2;
     int cmp = slots.get(mid).compareUpperToLowerBound(ptr, true, comparator);
     if (cmp < 0) {
       lower = mid + 1;
     } else if (cmp > 0) {
       upper = mid - 1;
     } else {
       return mid;
     }
   }
   mid = (lower + upper) / 2;
   if (mid == 0 && slots.get(mid).compareUpperToLowerBound(ptr, true, comparator) > 0) {
     return mid;
   } else {
     return ++mid;
   }
 }
示例#7
0
 private static TimeRange getAscTimeRange(KeyRange lowestRange, KeyRange highestRange, Field f)
     throws IOException {
   long low;
   long high;
   if (lowestRange.lowerUnbound()) {
     low = 0;
   } else {
     long lowerRange =
         f.getDataType().getCodec().decodeLong(lowestRange.getLowerRange(), 0, SortOrder.ASC);
     low = lowestRange.isLowerInclusive() ? lowerRange : safelyIncrement(lowerRange);
   }
   if (highestRange.upperUnbound()) {
     high = HConstants.LATEST_TIMESTAMP;
   } else {
     long upperRange =
         f.getDataType().getCodec().decodeLong(highestRange.getUpperRange(), 0, SortOrder.ASC);
     if (highestRange.isUpperInclusive()) {
       high = safelyIncrement(upperRange);
     } else {
       high = upperRange;
     }
   }
   return new TimeRange(low, high);
 }
示例#8
0
 private static TimeRange getRowTimestampColumnRange(
     List<List<KeyRange>> ranges, RowKeySchema schema, int rowTimestampColPos) {
   try {
     if (rowTimestampColPos != -1) {
       if (ranges != null && ranges.size() > rowTimestampColPos) {
         List<KeyRange> rowTimestampColRange = ranges.get(rowTimestampColPos);
         List<KeyRange> sortedRange = new ArrayList<>(rowTimestampColRange);
         Collections.sort(sortedRange, KeyRange.COMPARATOR);
         // ranges.set(rowTimestampColPos, sortedRange); //TODO: do I really need to do this?
         Field f = schema.getField(rowTimestampColPos);
         SortOrder order = f.getSortOrder();
         KeyRange lowestRange = rowTimestampColRange.get(0);
         KeyRange highestRange = rowTimestampColRange.get(rowTimestampColRange.size() - 1);
         if (order == SortOrder.DESC) {
           return getDescTimeRange(lowestRange, highestRange, f);
         }
         return getAscTimeRange(lowestRange, highestRange, f);
       }
     }
   } catch (IOException e) {
     Throwables.propagate(e);
   }
   return null;
 }
示例#9
0
 public static BytesComparator getComparator(Field field) {
   return getComparator(field.getDataType().isFixedWidth(), field.getSortOrder());
 }
示例#10
0
  public static int setKey(
      RowKeySchema schema,
      List<List<KeyRange>> slots,
      int[] slotSpan,
      int[] position,
      Bound bound,
      byte[] key,
      int byteOffset,
      int slotStartIndex,
      int slotEndIndex,
      int schemaStartIndex) {
    int offset = byteOffset;
    boolean lastInclusiveUpperSingleKey = false;
    boolean anyInclusiveUpperRangeKey = false;
    // The index used for slots should be incremented by 1,
    // but the index for the field it represents in the schema
    // should be incremented by 1 + value in the current slotSpan index
    // slotSpan stores the number of columns beyond one that the range spans
    Field field = null;
    int i = slotStartIndex, fieldIndex = ScanUtil.getRowKeyPosition(slotSpan, slotStartIndex);
    for (i = slotStartIndex; i < slotEndIndex; i++) {
      // Build up the key by appending the bound of each key range
      // from the current position of each slot.
      KeyRange range = slots.get(i).get(position[i]);
      // Use last slot in a multi-span column to determine if fixed width
      field = schema.getField(fieldIndex + slotSpan[i]);
      boolean isFixedWidth = field.getDataType().isFixedWidth();
      fieldIndex += slotSpan[i] + 1;
      /*
       * If the current slot is unbound then stop if:
       * 1) setting the upper bound. There's no value in
       *    continuing because nothing will be filtered.
       * 2) setting the lower bound when the type is fixed length
       *    for the same reason. However, if the type is variable width
       *    continue building the key because null values will be filtered
       *    since our separator byte will be appended and incremented.
       */
      if (range.isUnbound(bound) && (bound == Bound.UPPER || isFixedWidth)) {
        break;
      }
      byte[] bytes = range.getRange(bound);
      System.arraycopy(bytes, 0, key, offset, bytes.length);
      offset += bytes.length;
      /*
       * We must add a terminator to a variable length key even for the last PK column if
       * the lower key is non inclusive or the upper key is inclusive. Otherwise, we'd be
       * incrementing the key value itself, and thus bumping it up too much.
       */
      boolean inclusiveUpper = range.isInclusive(bound) && bound == Bound.UPPER;
      boolean exclusiveLower = !range.isInclusive(bound) && bound == Bound.LOWER;
      // If we are setting the upper bound of using inclusive single key, we remember
      // to increment the key if we exit the loop after this iteration.
      //
      // We remember to increment the last slot if we are setting the upper bound with an
      // inclusive range key.
      //
      // We cannot combine the two flags together in case for single-inclusive key followed
      // by the range-exclusive key. In that case, we do not need to increment the end at the
      // end. But if we combine the two flag, the single inclusive key in the middle of the
      // key slots would cause the flag to become true.
      lastInclusiveUpperSingleKey = range.isSingleKey() && inclusiveUpper;
      anyInclusiveUpperRangeKey |= !range.isSingleKey() && inclusiveUpper;
      // A null or empty byte array is always represented as a zero byte
      byte sepByte =
          SchemaUtil.getSeparatorByte(schema.rowKeyOrderOptimizable(), bytes.length == 0, field);

      if (!isFixedWidth
          && (fieldIndex < schema.getMaxFields()
              || inclusiveUpper
              || exclusiveLower
              || sepByte == QueryConstants.DESC_SEPARATOR_BYTE)) {
        key[offset++] = sepByte;
        // Set lastInclusiveUpperSingleKey back to false if this is the last pk column
        // as we don't want to increment the null byte in this case
        lastInclusiveUpperSingleKey &= i < schema.getMaxFields() - 1;
      }
      // If we are setting the lower bound with an exclusive range key, we need to bump the
      // slot up for each key part. For an upper bound, we bump up an inclusive key, but
      // only after the last key part.
      if (exclusiveLower) {
        if (!ByteUtil.nextKey(key, offset)) {
          // Special case for not being able to increment.
          // In this case we return a negative byteOffset to
          // remove this part from the key being formed. Since the
          // key has overflowed, this means that we should not
          // have an end key specified.
          return -byteOffset;
        }
        // We're filtering on values being non null here, but we still need the 0xFF
        // terminator, since DESC keys ignore the last byte as it's expected to be
        // the terminator. Without this, we'd ignore the separator byte that was
        // just added and incremented.
        if (!isFixedWidth
            && bytes.length == 0
            && SchemaUtil.getSeparatorByte(schema.rowKeyOrderOptimizable(), false, field)
                == QueryConstants.DESC_SEPARATOR_BYTE) {
          key[offset++] = QueryConstants.DESC_SEPARATOR_BYTE;
        }
      }
    }
    if (lastInclusiveUpperSingleKey || anyInclusiveUpperRangeKey) {
      if (!ByteUtil.nextKey(key, offset)) {
        // Special case for not being able to increment.
        // In this case we return a negative byteOffset to
        // remove this part from the key being formed. Since the
        // key has overflowed, this means that we should not
        // have an end key specified.
        return -byteOffset;
      }
    }
    // Remove trailing separator bytes, since the columns may have been added
    // after the table has data, in which case there won't be a separator
    // byte.
    if (bound == Bound.LOWER) {
      while (--i >= schemaStartIndex
          && offset > byteOffset
          && !(field = schema.getField(--fieldIndex)).getDataType().isFixedWidth()
          && field.getSortOrder() == SortOrder.ASC
          && key[offset - 1] == QueryConstants.SEPARATOR_BYTE) {
        offset--;
        fieldIndex -= slotSpan[i];
      }
    }
    return offset - byteOffset;
  }
示例#11
0
 public static byte getSeparatorByte(
     boolean rowKeyOrderOptimizable, boolean isNullValue, Field f) {
   return getSeparatorByte(rowKeyOrderOptimizable, isNullValue, f.getSortOrder());
 }