Exemple #1
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;
   }
 }
Exemple #2
0
  public static ScanRanges create(
      RowKeySchema schema,
      List<List<KeyRange>> ranges,
      int[] slotSpan,
      KeyRange minMaxRange,
      Integer nBuckets,
      boolean useSkipScan,
      int rowTimestampColIndex) {
    int offset = nBuckets == null ? 0 : SaltingUtil.NUM_SALTING_BYTES;
    int nSlots = ranges.size();
    if (nSlots == offset && minMaxRange == KeyRange.EVERYTHING_RANGE) {
      return EVERYTHING;
    } else if (minMaxRange == KeyRange.EMPTY_RANGE
        || (nSlots == 1 + offset
            && ranges.get(offset).size() == 1
            && ranges.get(offset).get(0) == KeyRange.EMPTY_RANGE)) {
      return NOTHING;
    }
    TimeRange rowTimestampRange = getRowTimestampColumnRange(ranges, schema, rowTimestampColIndex);
    boolean isPointLookup = isPointLookup(schema, ranges, slotSpan, useSkipScan);
    if (isPointLookup) {
      // TODO: consider keeping original to use for serialization as it would be smaller?
      List<byte[]> keys = ScanRanges.getPointKeys(ranges, slotSpan, schema, nBuckets);
      List<KeyRange> keyRanges = Lists.newArrayListWithExpectedSize(keys.size());
      KeyRange unsaltedMinMaxRange = minMaxRange;
      if (nBuckets != null && minMaxRange != KeyRange.EVERYTHING_RANGE) {
        unsaltedMinMaxRange =
            KeyRange.getKeyRange(
                stripPrefix(minMaxRange.getLowerRange(), offset),
                minMaxRange.lowerUnbound(),
                stripPrefix(minMaxRange.getUpperRange(), offset),
                minMaxRange.upperUnbound());
      }
      // We have full keys here, so use field from our varbinary schema
      BytesComparator comparator = ScanUtil.getComparator(SchemaUtil.VAR_BINARY_SCHEMA.getField(0));
      for (byte[] key : keys) {
        // Filter now based on unsalted minMaxRange and ignore the point key salt byte
        if (unsaltedMinMaxRange.compareLowerToUpperBound(
                    key, offset, key.length - offset, true, comparator)
                <= 0
            && unsaltedMinMaxRange.compareUpperToLowerBound(
                    key, offset, key.length - offset, true, comparator)
                >= 0) {
          keyRanges.add(KeyRange.getKeyRange(key));
        }
      }
      ranges = Collections.singletonList(keyRanges);
      useSkipScan = keyRanges.size() > 1;
      // Treat as binary if descending because we've got a separator byte at the end
      // which is not part of the value.
      if (keys.size() > 1
          || SchemaUtil.getSeparatorByte(schema.rowKeyOrderOptimizable(), false, schema.getField(0))
              == QueryConstants.DESC_SEPARATOR_BYTE) {
        schema = SchemaUtil.VAR_BINARY_SCHEMA;
        slotSpan = ScanUtil.SINGLE_COLUMN_SLOT_SPAN;
      } else {
        // Keep original schema and don't use skip scan as it's not necessary
        // when there's a single key.
        slotSpan = new int[] {schema.getMaxFields() - 1};
      }
    }
    List<List<KeyRange>> sortedRanges = Lists.newArrayListWithExpectedSize(ranges.size());
    for (int i = 0; i < ranges.size(); i++) {
      List<KeyRange> sorted = Lists.newArrayList(ranges.get(i));
      Collections.sort(sorted, KeyRange.COMPARATOR);
      sortedRanges.add(ImmutableList.copyOf(sorted));
    }

    // Don't set minMaxRange for point lookup because it causes issues during intersect
    // by going across region boundaries
    KeyRange scanRange = KeyRange.EVERYTHING_RANGE;
    // if (!isPointLookup && (nBuckets == null || !useSkipScanFilter)) {
    // if (! ( isPointLookup || (nBuckets != null && useSkipScanFilter) ) ) {
    // if (nBuckets == null || (nBuckets != null && (!isPointLookup || !useSkipScanFilter))) {
    if (nBuckets == null || !isPointLookup || !useSkipScan) {
      byte[] minKey = ScanUtil.getMinKey(schema, sortedRanges, slotSpan);
      byte[] maxKey = ScanUtil.getMaxKey(schema, sortedRanges, slotSpan);
      // If the maxKey has crossed the salt byte boundary, then we do not
      // have anything to filter at the upper end of the range
      if (ScanUtil.crossesPrefixBoundary(maxKey, ScanUtil.getPrefix(minKey, offset), offset)) {
        maxKey = KeyRange.UNBOUND;
      }
      // We won't filter anything at the low end of the range if we just have the salt byte
      if (minKey.length <= offset) {
        minKey = KeyRange.UNBOUND;
      }
      scanRange = KeyRange.getKeyRange(minKey, maxKey);
    }
    if (minMaxRange != KeyRange.EVERYTHING_RANGE) {
      minMaxRange =
          ScanUtil.convertToInclusiveExclusiveRange(
              minMaxRange, schema, new ImmutableBytesWritable());
      scanRange = scanRange.intersect(minMaxRange);
    }

    if (scanRange == KeyRange.EMPTY_RANGE) {
      return NOTHING;
    }
    return new ScanRanges(
        schema,
        slotSpan,
        sortedRanges,
        scanRange,
        minMaxRange,
        useSkipScan,
        isPointLookup,
        nBuckets,
        rowTimestampRange);
  }