/** * Converts a partially qualified KeyRange into a KeyRange with a inclusive lower bound and an * exclusive upper bound, widening as necessary. */ public static KeyRange convertToInclusiveExclusiveRange( KeyRange partialRange, RowKeySchema schema, ImmutableBytesWritable ptr) { // Ensure minMaxRange is lower inclusive and upper exclusive, as that's // what we need to intersect against for the HBase scan. byte[] lowerRange = partialRange.getLowerRange(); if (!partialRange.lowerUnbound()) { if (!partialRange.isLowerInclusive()) { lowerRange = ScanUtil.nextKey(lowerRange, schema, ptr); } } byte[] upperRange = partialRange.getUpperRange(); if (!partialRange.upperUnbound()) { if (partialRange.isUpperInclusive()) { upperRange = ScanUtil.nextKey(upperRange, schema, ptr); } } if (partialRange.getLowerRange() != lowerRange || partialRange.getUpperRange() != upperRange) { partialRange = KeyRange.getKeyRange(lowerRange, upperRange); } return partialRange; }
public static int getMaxKeyLength(RowKeySchema schema, List<List<KeyRange>> slots) { int maxKeyLength = getTerminatorCount(schema) * 2; for (List<KeyRange> slot : slots) { int maxSlotLength = 0; for (KeyRange range : slot) { int maxRangeLength = Math.max(range.getLowerRange().length, range.getUpperRange().length); if (maxSlotLength < maxRangeLength) { maxSlotLength = maxRangeLength; } } maxKeyLength += maxSlotLength; } return maxKeyLength; }
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); } }
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); }
public void initializeScan(Scan scan) { scan.setStartRow(scanRange.getLowerRange()); scan.setStopRow(scanRange.getUpperRange()); }
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); }