Index: hbase-server/src/main/java/org/apache/hadoop/hbase/client/Scan.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/client/Scan.java (revision 1436486) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/client/Scan.java (working copy) @@ -92,6 +92,7 @@ private int storeLimit = -1; private int storeOffset = 0; + private boolean getScan; // If application wants to collect scan metrics, it needs to // call scan.setAttribute(SCAN_ATTRIBUTES_ENABLE, Bytes.toBytes(Boolean.TRUE)) @@ -141,6 +142,8 @@ public Scan(byte [] startRow, byte [] stopRow) { this.startRow = startRow; this.stopRow = stopRow; + // if the startRow and stopRow both are empty, it is not a Get + this.getScan = isStartRowAndEqualsStopRow(); } /** @@ -159,6 +162,7 @@ caching = scan.getCaching(); maxResultSize = scan.getMaxResultSize(); cacheBlocks = scan.getCacheBlocks(); + getScan = scan.isGetScan(); filter = scan.getFilter(); // clone? loadColumnFamiliesOnDemand = scan.getLoadColumnFamiliesOnDemandValue(); TimeRange ctr = scan.getTimeRange(); @@ -194,9 +198,14 @@ this.storeOffset = get.getRowOffsetPerColumnFamily(); this.tr = get.getTimeRange(); this.familyMap = get.getFamilyMap(); + this.getScan = true; } public boolean isGetScan() { + return this.getScan || isStartRowAndEqualsStopRow(); + } + + private boolean isStartRowAndEqualsStopRow() { return this.startRow != null && this.startRow.length > 0 && Bytes.equals(this.startRow, this.stopRow); } @@ -620,15 +629,15 @@ colCount += entry.getValue().size(); if (maxCols <= 0) { continue; - } + } for (byte [] column : entry.getValue()) { if (--maxCols <= 0) { continue; } columns.add(Bytes.toStringBinary(column)); } - } - } + } + } map.put("totalColumns", colCount); if (this.filter != null) { map.put("filter", this.filter.toString()); @@ -666,10 +675,10 @@ * Set the isolation level for this scan. If the * isolation level is set to READ_UNCOMMITTED, then * this scan will return data from committed and - * uncommitted transactions. If the isolation level - * is set to READ_COMMITTED, then this scan will return + * uncommitted transactions. If the isolation level + * is set to READ_COMMITTED, then this scan will return * data from committed transactions only. If a isolation - * level is not explicitly set on a Scan, then it + * level is not explicitly set on a Scan, then it * is assumed to be READ_COMMITTED. * @param level IsolationLevel for this scan */ @@ -678,7 +687,7 @@ } /* * @return The isolation level of this scan. - * If no isolation level was set for this scan object, + * If no isolation level was set for this scan object, * then it returns READ_COMMITTED. * @return The IsolationLevel for this scan */ Index: hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java (revision 1436486) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java (working copy) @@ -3402,7 +3402,7 @@ } this.batch = scan.getBatch(); - if (Bytes.equals(scan.getStopRow(), HConstants.EMPTY_END_ROW)) { + if (Bytes.equals(scan.getStopRow(), HConstants.EMPTY_END_ROW) && !scan.isGetScan()) { this.stopRow = null; } else { this.stopRow = scan.getStopRow(); Index: hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestGetEmptyRowKey.java =================================================================== --- hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestGetEmptyRowKey.java (revision 0) +++ hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestGetEmptyRowKey.java (working copy) @@ -0,0 +1,88 @@ +/** + * + * 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.hadoop.hbase.regionserver; + +import static org.junit.Assert.*; + +import java.util.Arrays; + +import org.apache.hadoop.hbase.HBaseTestingUtility; +import org.apache.hadoop.hbase.HColumnDescriptor; +import org.apache.hadoop.hbase.HTableDescriptor; +import org.apache.hadoop.hbase.client.Get; +import org.apache.hadoop.hbase.client.HBaseAdmin; +import org.apache.hadoop.hbase.client.HTable; +import org.apache.hadoop.hbase.client.Put; +import org.apache.hadoop.hbase.client.Result; +import org.apache.hadoop.hbase.util.Bytes; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.apache.hadoop.hbase.MediumTests; + +@Category(MediumTests.class) +public class TestGetEmptyRowKey { + private final static HBaseTestingUtility UTIL = new HBaseTestingUtility(); + private final static byte[] FAMILY = Bytes.toBytes("f1"); + private final static byte[] COL_QUAL = Bytes.toBytes("f1"); + private final static byte[] VAL_BYTES = Bytes.toBytes("v1"); + private final static byte[] ROW_BYTES = Bytes.toBytes("r1"); + @BeforeClass + public static void beforeClass() throws Exception { + UTIL.startMiniCluster(); + } + + @AfterClass + public static void afterClass() throws Exception { + UTIL.shutdownMiniCluster(); + } + + @Test + public void test() throws Exception { + //Create a table and put in 1 row + HBaseAdmin admin = UTIL.getHBaseAdmin(); + HTableDescriptor desc = new HTableDescriptor(Bytes.toBytes("test")); + desc.addFamily(new HColumnDescriptor(FAMILY)); + admin.createTable(desc); + HTable table = new HTable(UTIL.getConfiguration(), "test"); + + Put put = new Put(ROW_BYTES); + put.add(FAMILY, COL_QUAL, VAL_BYTES); + table.put(put); + table.flushCommits(); + + //Try getting the row with an empty row key + Result res = table.get(new Get(new byte[0])); + assertTrue(res.isEmpty() == true); + res = table.get(new Get(Bytes.toBytes("r1-not-exist"))); + assertTrue(res.isEmpty() == true); + res = table.get(new Get(ROW_BYTES)); + assertTrue(Arrays.equals(res.getValue(FAMILY, COL_QUAL), VAL_BYTES)); + + //Now actually put in a row with an empty row key + put = new Put(new byte[0]); + put.add(FAMILY, COL_QUAL, VAL_BYTES); + table.put(put); + table.flushCommits(); + res = table.get(new Get(new byte[0])); + assertTrue(Arrays.equals(res.getValue(FAMILY, COL_QUAL), VAL_BYTES)); + } +}