public Scan intersectScan()

in phoenix-core-client/src/main/java/org/apache/phoenix/compile/ScanRanges.java [328:486]


    public Scan intersectScan(Scan scan, final byte[] originalStartKey, final byte[] originalStopKey, final int keyOffset, boolean crossesRegionBoundary) {
        byte[] startKey = originalStartKey;
        byte[] stopKey = originalStopKey;
        if (stopKey.length > 0 && Bytes.compareTo(startKey, stopKey) >= 0) { 
            return null; 
        }
        // Keep the keys as they are if we have a point lookup, as we've already resolved the
        // salt bytes in that case.
        final int scanKeyOffset = this.isSalted && !this.isPointLookup ? SaltingUtil.NUM_SALTING_BYTES : 0;
        assert (scanKeyOffset == 0 || keyOffset == 0);
        // Total offset for startKey/stopKey. Either 1 for salted tables or the prefix length
        // of the current region for local indexes. We'll never have a case where a table is
        // both salted and local.
        final int totalKeyOffset = scanKeyOffset + keyOffset;
        byte[] prefixBytes = ByteUtil.EMPTY_BYTE_ARRAY;
        if (totalKeyOffset > 0) {
            prefixBytes = ScanUtil.getPrefix(startKey, totalKeyOffset);
            /*
             * If our startKey to stopKey crosses a region boundary consider everything after the startKey as our scan
             * is always done within a single region. This prevents us from having to prefix the key prior to knowing
             * whether or not there may be an intersection. We can't calculate whether or not we've crossed a region
             * boundary for local indexes, because we don't know the key offset of the next region, but only for the
             * current one (which is the one passed in). If the next prefix happened to be a subset of the previous
             * prefix, then this wouldn't detect that we crossed a region boundary.
             */
            if (crossesRegionBoundary) {
                stopKey = ByteUtil.EMPTY_BYTE_ARRAY;
            }
        }
        int scanStartKeyOffset = scanKeyOffset;
        byte[] scanStartKey = scan == null ? this.scanRange.getLowerRange() : scan.getStartRow();
        // Compare ignoring key prefix and salt byte
        if (scanStartKey.length - scanKeyOffset > 0) {
            if (startKey.length - totalKeyOffset > 0) {
                if (Bytes.compareTo(scanStartKey, scanKeyOffset, scanStartKey.length - scanKeyOffset, startKey, totalKeyOffset, startKey.length - totalKeyOffset) < 0) {
                    scanStartKey = startKey;
                    scanStartKeyOffset = totalKeyOffset;
                }
            }
        } else {
            scanStartKey = startKey;
            scanStartKeyOffset = totalKeyOffset;
        }
        int scanStopKeyOffset = scanKeyOffset;
        byte[] scanStopKey = scan == null ? this.scanRange.getUpperRange() : scan.getStopRow();
        if (scanStopKey.length - scanKeyOffset > 0) {
            if (stopKey.length - totalKeyOffset > 0) {
                if (Bytes.compareTo(scanStopKey, scanKeyOffset, scanStopKey.length - scanKeyOffset, stopKey, totalKeyOffset, stopKey.length - totalKeyOffset) > 0) {
                    scanStopKey = stopKey;
                    scanStopKeyOffset = totalKeyOffset;
                }
            }
        } else {
            scanStopKey = stopKey;
            scanStopKeyOffset = totalKeyOffset;
        }
        
        // If not scanning anything, return null
        if (scanStopKey.length - scanStopKeyOffset > 0 && 
            Bytes.compareTo(scanStartKey, scanStartKeyOffset, scanStartKey.length - scanStartKeyOffset, 
                            scanStopKey, scanStopKeyOffset, scanStopKey.length - scanStopKeyOffset) >= 0) {
            return null;
        }
        if (originalStopKey.length != 0 && scanStopKey.length == 0) {
            scanStopKey = originalStopKey;
        }
        Filter newFilter = null;
        // Only if the scan is using skip scan filter, intersect and replace the filter.
        // For example, we may be forcing a range scan, in which case we do not want to
        // intersect the start/stop with the filter. Instead, we rely only on the scan
        // start/stop or the scanRanges start/stop.
        if (this.useSkipScanFilter()) {
            byte[] skipScanStartKey = scanStartKey;
            byte[] skipScanStopKey = scanStopKey;
            // If we have a keyOffset and we've used the startKey/stopKey that
            // were passed in (which have the prefix) for the above range check,
            // we need to remove the prefix before running our intersect method.
            if (scanKeyOffset > 0) {
                if (skipScanStartKey != originalStartKey) { // original already has correct salt byte
                    skipScanStartKey = replaceSaltByte(skipScanStartKey, prefixBytes);
                }
                if (skipScanStopKey != originalStopKey) {
                    skipScanStopKey = replaceSaltByte(skipScanStopKey, prefixBytes);
                }
            } else if (keyOffset > 0) {
                if (skipScanStartKey == originalStartKey) {
                    skipScanStartKey = stripPrefix(skipScanStartKey, keyOffset);
                }
                if (skipScanStopKey == originalStopKey) {
                    skipScanStopKey = stripPrefix(skipScanStopKey, keyOffset);
                }
            }
            if (scan == null) {
                return filter.hasIntersect(skipScanStartKey, skipScanStopKey) ? HAS_INTERSECTION : null;
            }
            Filter filter = scan.getFilter();
            SkipScanFilter newSkipScanFilter = null;
            if (filter instanceof SkipScanFilter) {
                SkipScanFilter oldSkipScanFilter = (SkipScanFilter)filter;
                newFilter = newSkipScanFilter = oldSkipScanFilter.intersect(skipScanStartKey, skipScanStopKey);
                if (newFilter == null) {
                    return null;
                }
            } else if (filter instanceof FilterList) {
                FilterList oldList = (FilterList)filter;
                FilterList newList = new FilterList(FilterList.Operator.MUST_PASS_ALL);
                newFilter = newList;
                for (Filter f : oldList.getFilters()) {
                    if (f instanceof SkipScanFilter) {
                        newSkipScanFilter = ((SkipScanFilter)f).intersect(skipScanStartKey, skipScanStopKey);
                        if (newSkipScanFilter == null) {
                            return null;
                        }
                        newList.addFilter(newSkipScanFilter);
                    } else {
                        newList.addFilter(f);
                    }
                }
            }
            // TODO: it seems that our SkipScanFilter or HBase runs into problems if we don't
            // have an enclosing range when we do a point lookup.
            if (isPointLookup) {
                scanStartKey = ScanUtil.getMinKey(schema, newSkipScanFilter.getSlots(), slotSpan);
                scanStopKey = ScanUtil.getMaxKey(schema, newSkipScanFilter.getSlots(), slotSpan);
            }
        }
        // If we've got this far, we know we have an intersection
        if (scan == null) {
            return HAS_INTERSECTION;
        }
        if (newFilter == null) {
            newFilter = scan.getFilter();
        }
        Scan newScan = ScanUtil.newScan(scan);
        newScan.setFilter(newFilter);
        // If we have an offset (salted table or local index), we need to make sure to
        // prefix our scan start/stop row by the prefix of the startKey or stopKey that
        // were passed in. Our scan either doesn't have the prefix or has a placeholder
        // for it.
        if (totalKeyOffset > 0) {
            if (scanStartKey != originalStartKey) {
                scanStartKey = prefixKey(scanStartKey, scanKeyOffset, prefixBytes, keyOffset);
            }
            if (scanStopKey != originalStopKey) {
                scanStopKey = prefixKey(scanStopKey, scanKeyOffset, prefixBytes, keyOffset);
            }
        }
        // Don't let the stopRow of the scan go beyond the originalStopKey
        if (originalStopKey.length > 0 && Bytes.compareTo(scanStopKey, originalStopKey) > 0) {
            scanStopKey = originalStopKey;
        }
        if (scanStopKey.length > 0 && Bytes.compareTo(scanStartKey, scanStopKey) >= 0) { 
            return null; 
        }
        newScan.setAttribute(SCAN_ACTUAL_START_ROW, scanStartKey);
        newScan.withStartRow(scanStartKey);
        newScan.withStopRow(scanStopKey);
        return newScan;
    }