PHOENIX-2900 Unable to find hash cache once a salted table 's first region has 
split (chenglei)


Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo
Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/0b39a520
Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/0b39a520
Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/0b39a520

Branch: refs/heads/encodecolumns
Commit: 0b39a520970cbba36560e814ba2ae7ea8719b655
Parents: 925d3ee
Author: James Taylor <[email protected]>
Authored: Sat Jul 23 09:49:33 2016 -0700
Committer: James Taylor <[email protected]>
Committed: Sat Jul 23 12:55:29 2016 -0700

----------------------------------------------------------------------
 .../end2end/BaseTenantSpecificViewIndexIT.java  |   2 +-
 .../org/apache/phoenix/end2end/BaseViewIT.java  |   4 +-
 .../phoenix/end2end/index/SaltedIndexIT.java    |   4 +-
 .../apache/phoenix/cache/ServerCacheClient.java |   5 +-
 .../org/apache/phoenix/compile/ScanRanges.java  |  88 +++----
 .../phoenix/compile/SaltedScanRangesTest.java   | 231 +++++++++++++++++++
 .../apache/phoenix/compile/ScanRangesTest.java  |   8 +-
 .../org/apache/phoenix/query/QueryPlanTest.java |   4 +-
 8 files changed, 291 insertions(+), 55 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/phoenix/blob/0b39a520/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseTenantSpecificViewIndexIT.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseTenantSpecificViewIndexIT.java
 
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseTenantSpecificViewIndexIT.java
index 11a33da..04f4268 100644
--- 
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseTenantSpecificViewIndexIT.java
+++ 
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseTenantSpecificViewIndexIT.java
@@ -142,7 +142,7 @@ public class BaseTenantSpecificViewIndexIT extends 
BaseHBaseManagedTimeIT {
             String expected = saltBuckets == null ? 
                     "CLIENT PARALLEL 1-WAY RANGE SCAN OVER _IDX_T [-32768,'" + 
tenantId + "','" + valuePrefix + "v2-1']\n"
                             + "    SERVER FILTER BY FIRST KEY ONLY" :
-                    "CLIENT PARALLEL 3-WAY RANGE SCAN OVER _IDX_T [0,-32768,'" 
+ tenantId + "','" + valuePrefix + "v2-1']\n"
+                    "CLIENT PARALLEL 3-WAY RANGE SCAN OVER _IDX_T [0,-32768,'" 
+ tenantId + "','" + valuePrefix + "v2-1'] - 
["+(saltBuckets.intValue()-1)+",-32768,'" + tenantId + "','" + valuePrefix + 
"v2-1']\n"
                   + "    SERVER FILTER BY FIRST KEY ONLY\n"
                   + "CLIENT MERGE SORT";
             assertEquals(expected, QueryUtil.getExplainPlan(rs));

http://git-wip-us.apache.org/repos/asf/phoenix/blob/0b39a520/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseViewIT.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseViewIT.java 
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseViewIT.java
index 6d8d889..d9a59a9 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseViewIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseViewIT.java
@@ -210,7 +210,7 @@ public abstract class BaseViewIT extends 
BaseOwnClusterHBaseManagedTimeIT {
         } else {
             assertEquals(saltBuckets == null
                     ? "CLIENT PARALLEL 1-WAY RANGE SCAN OVER _IDX_" + 
tableName +" [" + Short.MIN_VALUE + ",51]"
-                            : "CLIENT PARALLEL " + saltBuckets + "-WAY RANGE 
SCAN OVER _IDX_T" + (transactional ? "_TXN" : "") + " [0," + Short.MIN_VALUE + 
",51]\nCLIENT MERGE SORT",
+                            : "CLIENT PARALLEL " + saltBuckets + "-WAY RANGE 
SCAN OVER _IDX_T" + (transactional ? "_TXN" : "") + " [0," + Short.MIN_VALUE + 
",51] - ["+(saltBuckets.intValue()-1)+"," + Short.MIN_VALUE + ",51]\nCLIENT 
MERGE SORT",
                             queryPlan);
         }
 
@@ -251,7 +251,7 @@ public abstract class BaseViewIT extends 
BaseOwnClusterHBaseManagedTimeIT {
             assertEquals(saltBuckets == null
                     ? "CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + htableName +" 
[" + (Short.MIN_VALUE+1) + ",'foo']\n"
                             + "    SERVER FILTER BY FIRST KEY ONLY"
-                            : "CLIENT PARALLEL " + saltBuckets + "-WAY RANGE 
SCAN OVER " + htableName + " [0," + (Short.MIN_VALUE+1) + ",'foo']\n"
+                            : "CLIENT PARALLEL " + saltBuckets + "-WAY RANGE 
SCAN OVER " + htableName + " [0," + (Short.MIN_VALUE+1) + ",'foo'] - 
["+(saltBuckets.intValue()-1)+"," + (Short.MIN_VALUE+1) + ",'foo']\n"
                                     + "    SERVER FILTER BY FIRST KEY ONLY\n"
                                     + "CLIENT MERGE SORT",
                             QueryUtil.getExplainPlan(rs));

http://git-wip-us.apache.org/repos/asf/phoenix/blob/0b39a520/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/SaltedIndexIT.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/SaltedIndexIT.java 
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/SaltedIndexIT.java
index b5c8477..5b2b15a 100644
--- 
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/SaltedIndexIT.java
+++ 
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/SaltedIndexIT.java
@@ -143,7 +143,7 @@ public class SaltedIndexIT extends BaseHBaseManagedTimeIT {
         expectedPlan = indexSaltBuckets == null ? 
              "CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + 
TestUtil.DEFAULT_INDEX_TABLE_FULL_NAME + " [~'y']\n" + 
              "    SERVER FILTER BY FIRST KEY ONLY" : 
-            ("CLIENT PARALLEL 4-WAY RANGE SCAN OVER " + 
TestUtil.DEFAULT_INDEX_TABLE_FULL_NAME + " [0,~'y']\n" + 
+            ("CLIENT PARALLEL 4-WAY RANGE SCAN OVER " + 
TestUtil.DEFAULT_INDEX_TABLE_FULL_NAME + " [0,~'y'] - 
["+(indexSaltBuckets.intValue()-1)+",~'y']\n" + 
              "    SERVER FILTER BY FIRST KEY ONLY\n" +
              "CLIENT MERGE SORT");
         assertEquals(expectedPlan,QueryUtil.getExplainPlan(rs));
@@ -164,7 +164,7 @@ public class SaltedIndexIT extends BaseHBaseManagedTimeIT {
         expectedPlan = indexSaltBuckets == null ? 
             "CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + 
TestUtil.DEFAULT_INDEX_TABLE_FULL_NAME + " [*] - [~'x']\n"
           + "    SERVER FILTER BY FIRST KEY ONLY" :
-            ("CLIENT PARALLEL 4-WAY RANGE SCAN OVER " + 
TestUtil.DEFAULT_INDEX_TABLE_FULL_NAME + " [0,*] - [0,~'x']\n"
+            ("CLIENT PARALLEL 4-WAY RANGE SCAN OVER " + 
TestUtil.DEFAULT_INDEX_TABLE_FULL_NAME + " [0,*] - 
["+(indexSaltBuckets.intValue()-1)+",~'x']\n"
            + "    SERVER FILTER BY FIRST KEY ONLY\n" + 
              "CLIENT MERGE SORT");
         assertEquals(expectedPlan,QueryUtil.getExplainPlan(rs));

http://git-wip-us.apache.org/repos/asf/phoenix/blob/0b39a520/phoenix-core/src/main/java/org/apache/phoenix/cache/ServerCacheClient.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/cache/ServerCacheClient.java 
b/phoenix-core/src/main/java/org/apache/phoenix/cache/ServerCacheClient.java
index d88b094..67fc410 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/cache/ServerCacheClient.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/cache/ServerCacheClient.java
@@ -172,9 +172,8 @@ public class ServerCacheClient {
                 byte[] regionStartKey = entry.getRegionInfo().getStartKey();
                 byte[] regionEndKey = entry.getRegionInfo().getEndKey();
                 if ( ! servers.contains(entry) && 
-                        keyRanges.intersects(regionStartKey, regionEndKey,
-                                cacheUsingTable.getIndexType() == 
IndexType.LOCAL ? 
-                                    ScanUtil.getRowKeyOffset(regionStartKey, 
regionEndKey) : 0, true)) {  
+                        keyRanges.intersectRegion(regionStartKey, regionEndKey,
+                                cacheUsingTable.getIndexType() == 
IndexType.LOCAL)) {  
                     // Call RPC once per server
                     servers.add(entry);
                     if (LOG.isDebugEnabled()) 
{LOG.debug(addCustomAnnotations("Adding cache entry to be sent for " + entry, 
connection));}

http://git-wip-us.apache.org/repos/asf/phoenix/blob/0b39a520/phoenix-core/src/main/java/org/apache/phoenix/compile/ScanRanges.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/compile/ScanRanges.java 
b/phoenix-core/src/main/java/org/apache/phoenix/compile/ScanRanges.java
index 6f0adb0..f3d5bba 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/ScanRanges.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/ScanRanges.java
@@ -68,6 +68,11 @@ public class ScanRanges {
         return create(schema, ranges, 
ScanUtil.getDefaultSlotSpans(ranges.size()), KeyRange.EVERYTHING_RANGE, null, 
true, -1);
     }
     
+    // For testing
+    public static ScanRanges createSingleSpan(RowKeySchema schema, 
List<List<KeyRange>> ranges, Integer nBuckets, boolean useSkipSan) {
+        return create(schema, ranges, 
ScanUtil.getDefaultSlotSpans(ranges.size()), KeyRange.EVERYTHING_RANGE, 
nBuckets, useSkipSan, -1);
+    }
+
     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();
@@ -170,12 +175,8 @@ public class ScanRanges {
         this.minMaxRange = minMaxRange;
         this.rowTimestampRange = rowTimestampRange;
         
-        // Only blow out the bucket values if we're using the skip scan. We 
need all the
-        // bucket values in this case because we use intersect against a key 
that may have
-        // any of the possible bucket values. Otherwise, we can pretty easily 
ignore the
-        // bucket values.
-        if (useSkipScanFilter && isSalted && !isPointLookup) {
-               ranges.set(0, SaltingUtil.generateAllSaltingRanges(bucketNum));
+        if (isSalted && !isPointLookup) {
+            ranges.set(0, SaltingUtil.generateAllSaltingRanges(bucketNum));
         }
         this.ranges = ImmutableList.copyOf(ranges);
         this.slotSpan = slotSpan;
@@ -243,7 +244,6 @@ public class ScanRanges {
         if (stopKey.length > 0 && Bytes.compareTo(startKey, stopKey) >= 0) { 
             return null; 
         }
-        boolean mayHaveRows = false;
         // 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;
@@ -268,49 +268,53 @@ public class ScanRanges {
             }
         }
         int scanStartKeyOffset = scanKeyOffset;
-        byte[] scanStartKey = scan == null ? ByteUtil.EMPTY_BYTE_ARRAY : 
scan.getStartRow();
+        byte[] scanStartKey = scan == null ? this.scanRange.getLowerRange() : 
scan.getStartRow();
         // Compare ignoring key prefix and salt byte
-        if (scanStartKey.length > 0) {
-            if (startKey.length > 0 && Bytes.compareTo(scanStartKey, 
scanKeyOffset, scanStartKey.length - scanKeyOffset, startKey, totalKeyOffset, 
startKey.length - totalKeyOffset) < 0) {
-                scanStartKey = startKey;
-                scanStartKeyOffset = totalKeyOffset;
+        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;
+            scanStartKey = startKey;
             scanStartKeyOffset = totalKeyOffset;
-            mayHaveRows = true;
         }
         int scanStopKeyOffset = scanKeyOffset;
-        byte[] scanStopKey = scan == null ? ByteUtil.EMPTY_BYTE_ARRAY : 
scan.getStopRow();
-        if (scanStopKey.length > 0) {
-            if (stopKey.length > 0 && Bytes.compareTo(scanStopKey, 
scanKeyOffset, scanStopKey.length - scanKeyOffset, stopKey, totalKeyOffset, 
stopKey.length - totalKeyOffset) > 0) {
-                scanStopKey = stopKey;
-                scanStopKeyOffset = totalKeyOffset;
+        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;
+            scanStopKey = stopKey;
             scanStopKeyOffset = totalKeyOffset;
-            mayHaveRows = true;
         }
-        mayHaveRows = mayHaveRows || Bytes.compareTo(scanStartKey, 
scanStartKeyOffset, scanStartKey.length - scanStartKeyOffset, scanStopKey, 
scanStopKeyOffset, scanStopKey.length - scanStopKeyOffset) < 0;
         
-        if (!mayHaveRows) {
+        // 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;
-        // If the scan is using skip scan filter, intersect and replace the 
filter.
-        if (scan == null || this.useSkipScanFilter()) {
+        // 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.
-            // TODO: we could use skipScanFilter.setOffset(keyOffset) if both
-            // the startKey and stopKey were used above *and* our intersect
-            // method honored the skipScanFilter.offset variable.
             if (scanKeyOffset > 0) {
                 if (skipScanStartKey != originalStartKey) { // original 
already has correct salt byte
                     skipScanStartKey = replaceSaltByte(skipScanStartKey, 
prefixBytes);
@@ -360,6 +364,10 @@ public class ScanRanges {
                 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();
         }
@@ -391,29 +399,27 @@ public class ScanRanges {
     }
 
     /**
-     * Return true if the range formed by the lowerInclusiveKey and 
upperExclusiveKey
-     * intersects with the scan ranges and false otherwise. We cannot pass in
-     * a KeyRange here, because the underlying compare functions expect lower 
inclusive
-     * and upper exclusive keys. We cannot get their next key because the key 
must
-     * conform to the row key schema and if a null byte is added to a lower 
inclusive
-     * key, it's no longer a valid, real key.
-     * @param lowerInclusiveKey lower inclusive key
-     * @param upperExclusiveKey upper exclusive key
-     * @param crossesRegionBoundary whether or not the upperExclusiveKey spans 
upto
-     * or after the next region.
+     * Return true if the region with the start and end key
+     * intersects with the scan ranges and false otherwise. 
+     * @param regionStartKey lower inclusive key
+     * @param regionEndKey upper exclusive key
+     * @param isLocalIndex true if the table being scanned is a local index
      * @return true if the scan range intersects with the specified 
lower/upper key
      * range
      */
-    public boolean intersects(byte[] lowerInclusiveKey, byte[] 
upperExclusiveKey, int keyOffset, boolean crossesRegionBoundary) {
+    public boolean intersectRegion(byte[] regionStartKey, byte[] regionEndKey, 
boolean isLocalIndex) {
         if (isEverything()) {
             return true;
         }
         if (isDegenerate()) {
             return false;
         }
+        // Every range intersects all regions of a local index table 
+        if (isLocalIndex) {
+            return true;
+        }
         
-        //return filter.hasIntersect(lowerInclusiveKey, upperExclusiveKey);
-        return intersectScan(null, lowerInclusiveKey, upperExclusiveKey, 
keyOffset, crossesRegionBoundary) == HAS_INTERSECTION;
+        return intersectScan(null, regionStartKey, regionEndKey, 0, false) == 
HAS_INTERSECTION;
     }
     
     public SkipScanFilter getSkipScanFilter() {

http://git-wip-us.apache.org/repos/asf/phoenix/blob/0b39a520/phoenix-core/src/test/java/org/apache/phoenix/compile/SaltedScanRangesTest.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/test/java/org/apache/phoenix/compile/SaltedScanRangesTest.java
 
b/phoenix-core/src/test/java/org/apache/phoenix/compile/SaltedScanRangesTest.java
new file mode 100644
index 0000000..f8eb3a0
--- /dev/null
+++ 
b/phoenix-core/src/test/java/org/apache/phoenix/compile/SaltedScanRangesTest.java
@@ -0,0 +1,231 @@
+/*
+ * 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.phoenix.compile;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.phoenix.query.KeyRange;
+import org.apache.phoenix.schema.PDatum;
+import org.apache.phoenix.schema.RowKeySchema.RowKeySchemaBuilder;
+import org.apache.phoenix.schema.SaltingUtil;
+import org.apache.phoenix.schema.SortOrder;
+import org.apache.phoenix.schema.types.PChar;
+import org.apache.phoenix.schema.types.PDataType;
+import org.apache.phoenix.schema.types.PVarchar;
+import org.apache.phoenix.util.ByteUtil;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+
+
+/**
+ * Test for intersect method in {@link ScanRanges} over salted data
+ */
+@RunWith(Parameterized.class)
+public class SaltedScanRangesTest {
+
+    private static Integer nBuckets = 3;
+    private final ScanRanges scanRanges;
+    private final KeyRange keyRange;
+    private final boolean expectedResult;
+
+    public SaltedScanRangesTest(ScanRanges scanRanges, int[] widths,
+            KeyRange keyRange, boolean expectedResult) {
+        this.keyRange = keyRange;
+        this.scanRanges = scanRanges;
+        this.expectedResult = expectedResult;
+    }
+
+    @Test
+    public void test() {
+        byte[] lowerInclusiveKey = keyRange.getLowerRange();
+        if (!keyRange.isLowerInclusive() && !Bytes.equals(lowerInclusiveKey, 
KeyRange.UNBOUND)) {
+            // This assumes the last key is fixed length, otherwise the 
results may be incorrect
+            // since there's no terminating 0 byte for a variable length key 
and thus we may be
+            // incrementing the key too much.
+            lowerInclusiveKey = ByteUtil.nextKey(lowerInclusiveKey);
+        }
+        byte[] upperExclusiveKey = keyRange.getUpperRange();
+        if (keyRange.isUpperInclusive()) {
+            // This assumes the last key is fixed length, otherwise the 
results may be incorrect
+            // since there's no terminating 0 byte for a variable length key 
and thus we may be
+            // incrementing the key too much.
+            upperExclusiveKey = ByteUtil.nextKey(upperExclusiveKey);
+        }
+        assertEquals(expectedResult, 
scanRanges.intersectRegion(lowerInclusiveKey,upperExclusiveKey,false));
+    }
+
+    @Parameters(name="{0} {2}")
+    public static Collection<Object> data() {
+        List<Object> testCases = Lists.newArrayList();
+        testCases.addAll(
+                foreach(new KeyRange[][]{{
+                        PVarchar.INSTANCE.getKeyRange(Bytes.toBytes("c"), 
true, Bytes.toBytes("e"), false),
+                    }},
+                    new int[] {0},
+                    KeyRange.getKeyRange(KeyRange.UNBOUND, new byte[]{1}),
+                    false,
+                    true));
+        testCases.addAll(
+                foreach(new KeyRange[][]{{
+                        PVarchar.INSTANCE.getKeyRange(Bytes.toBytes("c"), 
true, Bytes.toBytes("e"), false),
+                    }},
+                    new int[] {0},
+                    KeyRange.getKeyRange(new byte[]{1},new byte[]{2}),
+                    false,
+                    true));
+        testCases.addAll(
+                foreach(new KeyRange[][]{{
+                        PVarchar.INSTANCE.getKeyRange(Bytes.toBytes("c"), 
true, Bytes.toBytes("e"), false),
+                    }},
+                    new int[] {0},
+                    KeyRange.getKeyRange(new byte[]{2},KeyRange.UNBOUND),
+                    false,
+                    true));
+        testCases.addAll(
+                foreach(new KeyRange[][]{{
+                        PVarchar.INSTANCE.getKeyRange(Bytes.toBytes("c"), 
true, Bytes.toBytes("e"), false),
+                    }},
+                    new int[] {0},
+                    KeyRange.getKeyRange(new byte[]{1},ByteUtil.concat(new 
byte[]{1}, Bytes.toBytes("c"))),
+                    false,
+                    false));
+        testCases.addAll(
+                foreach(new KeyRange[][]{{
+                        PVarchar.INSTANCE.getKeyRange(Bytes.toBytes("c"), 
true, Bytes.toBytes("e"), false),
+                    }},
+                    new int[] {0},
+                    KeyRange.getKeyRange(ByteUtil.concat(new byte[]{1}, 
Bytes.toBytes("e")), new byte[]{2}),
+                    false,
+                    false));
+        testCases.addAll(
+                foreach(new KeyRange[][]{{
+                        PVarchar.INSTANCE.getKeyRange(Bytes.toBytes("c"), 
true, Bytes.toBytes("e"), false),
+                    }},
+                    new int[] {0},
+                    KeyRange.getKeyRange(ByteUtil.concat(new byte[]{1}, 
Bytes.toBytes("d")), new byte[]{2}),
+                    false,
+                    true));
+        testCases.addAll(
+                foreach(new KeyRange[][]{{
+                        PVarchar.INSTANCE.getKeyRange(Bytes.toBytes("c"), 
true, Bytes.toBytes("e"), false),
+                        PVarchar.INSTANCE.getKeyRange(Bytes.toBytes("h"), 
true, Bytes.toBytes("i"), false),
+                        PVarchar.INSTANCE.getKeyRange(Bytes.toBytes("m"), 
true, Bytes.toBytes("p"), false),
+                    }},
+                    new int[] {0},
+                    KeyRange.getKeyRange(ByteUtil.concat(new byte[]{1}, 
Bytes.toBytes("f")), ByteUtil.concat(new byte[]{1}, Bytes.toBytes("g"))),
+                    false,
+                    true));
+        testCases.addAll(
+                foreach(new KeyRange[][]{{
+                        PVarchar.INSTANCE.getKeyRange(Bytes.toBytes("c"), 
true, Bytes.toBytes("e"), false),
+                        PVarchar.INSTANCE.getKeyRange(Bytes.toBytes("h"), 
true, Bytes.toBytes("i"), false),
+                        PVarchar.INSTANCE.getKeyRange(Bytes.toBytes("m"), 
true, Bytes.toBytes("p"), false),
+                    }},
+                    new int[] {0},
+                    KeyRange.getKeyRange(ByteUtil.concat(new byte[]{1}, 
Bytes.toBytes("f")), ByteUtil.concat(new byte[]{1}, Bytes.toBytes("g"))),
+                    true,
+                    false));
+        return testCases;
+    }
+
+    private static Collection<?> foreach(ScanRanges ranges, int[] widths, 
KeyRange keyRange,
+            boolean expectedResult) {
+        List<Object> ret = Lists.newArrayList();
+        ret.add(new Object[] {ranges, widths, keyRange, expectedResult});
+        return ret;
+    }
+
+    private static Collection<?> foreach(KeyRange[][] ranges, int[] widths, 
KeyRange keyRange, boolean useSkipScan,
+            boolean expectedResult) {
+        List<List<KeyRange>> slots = 
Lists.transform(Lists.newArrayList(ranges), ARRAY_TO_LIST);
+        slots = new ArrayList<>(slots);
+        slots.add(0, Collections.singletonList(KeyRange.getKeyRange(new 
byte[]{0})));
+        RowKeySchemaBuilder builder = new RowKeySchemaBuilder(10);
+        builder.addField(SaltingUtil.SALTING_COLUMN, false, 
SortOrder.getDefault());
+        for (final int width : widths) {
+            if (width > 0) {
+                builder.addField(new PDatum() {
+                    @Override
+                    public boolean isNullable() {
+                        return false;
+                    }
+                    @Override
+                    public PDataType getDataType() {
+                        return PChar.INSTANCE;
+                    }
+                    @Override
+                    public Integer getMaxLength() {
+                        return width;
+                    }
+                    @Override
+                    public Integer getScale() {
+                        return null;
+                    }
+                    @Override
+                    public SortOrder getSortOrder() {
+                        return SortOrder.getDefault();
+                    }
+                }, false, SortOrder.getDefault());
+            } else {
+                builder.addField(new PDatum() {
+                    @Override
+                    public boolean isNullable() {
+                        return false;
+                    }
+                    @Override
+                    public PDataType getDataType() {
+                        return PVarchar.INSTANCE;
+                    }
+                    @Override
+                    public Integer getMaxLength() {
+                        return width;
+                    }
+                    @Override
+                    public Integer getScale() {
+                        return null;
+                    }
+                    @Override
+                    public SortOrder getSortOrder() {
+                        return SortOrder.getDefault();
+                    }
+                }, false, SortOrder.getDefault());
+            }
+        }
+        ScanRanges scanRanges = ScanRanges.createSingleSpan(builder.build(), 
slots, nBuckets , useSkipScan);
+        return foreach(scanRanges, widths, keyRange, expectedResult);
+    }
+
+    private static final Function<KeyRange[], List<KeyRange>> ARRAY_TO_LIST = 
+            new Function<KeyRange[], List<KeyRange>>() {
+                @Override 
+                public List<KeyRange> apply(KeyRange[] input) {
+                    return Lists.newArrayList(input);
+                }
+    };
+}

http://git-wip-us.apache.org/repos/asf/phoenix/blob/0b39a520/phoenix-core/src/test/java/org/apache/phoenix/compile/ScanRangesTest.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/test/java/org/apache/phoenix/compile/ScanRangesTest.java 
b/phoenix-core/src/test/java/org/apache/phoenix/compile/ScanRangesTest.java
index 0292244..44aac4d 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/compile/ScanRangesTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/compile/ScanRangesTest.java
@@ -24,12 +24,12 @@ import java.util.List;
 
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.phoenix.query.KeyRange;
-import org.apache.phoenix.schema.types.PChar;
-import org.apache.phoenix.schema.types.PDataType;
 import org.apache.phoenix.schema.PDatum;
-import org.apache.phoenix.schema.types.PVarchar;
 import org.apache.phoenix.schema.RowKeySchema.RowKeySchemaBuilder;
 import org.apache.phoenix.schema.SortOrder;
+import org.apache.phoenix.schema.types.PChar;
+import org.apache.phoenix.schema.types.PDataType;
+import org.apache.phoenix.schema.types.PVarchar;
 import org.apache.phoenix.util.ByteUtil;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -73,7 +73,7 @@ public class ScanRangesTest {
             // incrementing the key too much.
             upperExclusiveKey = ByteUtil.nextKey(upperExclusiveKey);
         }
-        assertEquals(expectedResult, 
scanRanges.intersects(lowerInclusiveKey,upperExclusiveKey,0, true));
+        assertEquals(expectedResult, 
scanRanges.intersectRegion(lowerInclusiveKey,upperExclusiveKey,false));
     }
 
     @Parameters(name="{0} {2}")

http://git-wip-us.apache.org/repos/asf/phoenix/blob/0b39a520/phoenix-core/src/test/java/org/apache/phoenix/query/QueryPlanTest.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/test/java/org/apache/phoenix/query/QueryPlanTest.java 
b/phoenix-core/src/test/java/org/apache/phoenix/query/QueryPlanTest.java
index 8af832b..37010b3 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/query/QueryPlanTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/query/QueryPlanTest.java
@@ -245,7 +245,7 @@ public class QueryPlanTest extends 
BaseConnectionlessQueryTest {
             ResultSet rs = conn.createStatement().executeQuery("EXPLAIN " + 
query);
             String queryPlan = QueryUtil.getExplainPlan(rs);
             assertEquals(
-                    "CLIENT PARALLEL 20-WAY RANGE SCAN OVER FOO 
[0,'a',~'2016-01-28 23:59:59.999'] - [0,'a',~'2016-01-28 00:00:00.000']\n" + 
+                    "CLIENT PARALLEL 20-WAY RANGE SCAN OVER FOO 
[0,'a',~'2016-01-28 23:59:59.999'] - [19,'a',~'2016-01-28 00:00:00.000']\n" + 
                     "    SERVER FILTER BY FIRST KEY ONLY\n" + 
                     "CLIENT MERGE SORT", queryPlan);
         } finally {
@@ -271,7 +271,7 @@ public class QueryPlanTest extends 
BaseConnectionlessQueryTest {
             ResultSet rs = conn.createStatement().executeQuery("EXPLAIN " + 
query);
             String queryPlan = QueryUtil.getExplainPlan(rs);
             assertEquals(
-                    "CLIENT PARALLEL 20-WAY ROUND ROBIN RANGE SCAN OVER " + 
tableName + " [0,'a',~'2016-01-28 23:59:59.999'] - [0,'a',~'2016-01-28 
00:00:00.000']\n" + 
+                    "CLIENT PARALLEL 20-WAY ROUND ROBIN RANGE SCAN OVER " + 
tableName + " [0,'a',~'2016-01-28 23:59:59.999'] - [19,'a',~'2016-01-28 
00:00:00.000']\n" + 
                     "    SERVER FILTER BY FIRST KEY ONLY", queryPlan);
         } finally {
             conn.close();

Reply via email to