phoenix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jamestay...@apache.org
Subject phoenix git commit: PHOENIX-2900 Unable to find hash cache once a salted table 's first region has split (chenglei)
Date Sat, 23 Jul 2016 19:53:54 GMT
Repository: phoenix
Updated Branches:
  refs/heads/4.x-HBase-1.1 1078209bf -> dc818cbf7


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/dc818cbf
Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/dc818cbf
Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/dc818cbf

Branch: refs/heads/4.x-HBase-1.1
Commit: dc818cbf717ebf2b5964a4565584adecb9806cfa
Parents: 1078209
Author: James Taylor <jamestaylor@apache.org>
Authored: Sat Jul 23 09:49:33 2016 -0700
Committer: James Taylor <jamestaylor@apache.org>
Committed: Sat Jul 23 12:53:00 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/dc818cbf/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/dc818cbf/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/dc818cbf/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/dc818cbf/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/dc818cbf/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/dc818cbf/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/dc818cbf/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/dc818cbf/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();


Mime
View raw message