You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by st...@apache.org on 2017/08/22 16:02:53 UTC
[06/21] hbase git commit: HBASE-18471 The DeleteFamily cell is
skipped when StoreScanner seeks to next column
HBASE-18471 The DeleteFamily cell is skipped when StoreScanner seeks to next column
Project: http://git-wip-us.apache.org/repos/asf/hbase/repo
Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/56f9e1a6
Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/56f9e1a6
Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/56f9e1a6
Branch: refs/heads/HBASE-14070.HLC
Commit: 56f9e1a60af224f8f3b0453932155ca46d44cf71
Parents: e9bafeb
Author: Chia-Ping Tsai <ch...@gmail.com>
Authored: Sat Aug 19 02:15:12 2017 +0800
Committer: Chia-Ping Tsai <ch...@gmail.com>
Committed: Sat Aug 19 02:15:12 2017 +0800
----------------------------------------------------------------------
.../java/org/apache/hadoop/hbase/CellUtil.java | 53 ++++++++++
.../querymatcher/ScanQueryMatcher.java | 13 +++
.../hbase/client/TestFromClientSide3.java | 101 +++++++++++++++++++
3 files changed, 167 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/hbase/blob/56f9e1a6/hbase-common/src/main/java/org/apache/hadoop/hbase/CellUtil.java
----------------------------------------------------------------------
diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/CellUtil.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/CellUtil.java
index 1146de4..03d8b70 100644
--- a/hbase-common/src/main/java/org/apache/hadoop/hbase/CellUtil.java
+++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/CellUtil.java
@@ -3135,4 +3135,57 @@ public final class CellUtil {
return Type.DeleteFamily.getCode();
}
}
+
+ /**
+ * @return An new cell is located following input cell. If both of type and timestamp are
+ * minimum, the input cell will be returned directly.
+ */
+ @InterfaceAudience.Private
+ public static Cell createNextOnRowCol(Cell cell) {
+ long ts = cell.getTimestamp();
+ byte type = cell.getTypeByte();
+ if (type != Type.Minimum.getCode()) {
+ type = KeyValue.Type.values()[KeyValue.Type.codeToType(type).ordinal() - 1].getCode();
+ } else if (ts != HConstants.OLDEST_TIMESTAMP) {
+ ts = ts - 1;
+ type = Type.Maximum.getCode();
+ } else {
+ return cell;
+ }
+ return createNextOnRowCol(cell, ts, type);
+ }
+
+ private static Cell createNextOnRowCol(Cell cell, long ts, byte type) {
+ if (cell instanceof ByteBufferCell) {
+ return new LastOnRowColByteBufferCell(((ByteBufferCell) cell).getRowByteBuffer(),
+ ((ByteBufferCell) cell).getRowPosition(), cell.getRowLength(),
+ ((ByteBufferCell) cell).getFamilyByteBuffer(),
+ ((ByteBufferCell) cell).getFamilyPosition(), cell.getFamilyLength(),
+ ((ByteBufferCell) cell).getQualifierByteBuffer(),
+ ((ByteBufferCell) cell).getQualifierPosition(), cell.getQualifierLength()) {
+ @Override
+ public long getTimestamp() {
+ return ts;
+ }
+
+ @Override
+ public byte getTypeByte() {
+ return type;
+ }
+ };
+ }
+ return new LastOnRowColCell(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength(),
+ cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength(),
+ cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength()) {
+ @Override
+ public long getTimestamp() {
+ return ts;
+ }
+
+ @Override
+ public byte getTypeByte() {
+ return type;
+ }
+ };
+ }
}
http://git-wip-us.apache.org/repos/asf/hbase/blob/56f9e1a6/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/querymatcher/ScanQueryMatcher.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/querymatcher/ScanQueryMatcher.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/querymatcher/ScanQueryMatcher.java
index 524d3f7..f00a400 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/querymatcher/ScanQueryMatcher.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/querymatcher/ScanQueryMatcher.java
@@ -290,6 +290,19 @@ public abstract class ScanQueryMatcher implements ShipperListener {
public abstract boolean moreRowsMayExistAfter(Cell cell);
public Cell getKeyForNextColumn(Cell cell) {
+ // We aren't sure whether any DeleteFamily cells exist, so we can't skip to next column.
+ // TODO: Current way disable us to seek to next column quickly. Is there any better solution?
+ // see HBASE-18471 for more details
+ // see TestFromClientSide3#testScanAfterDeletingSpecifiedRow
+ // see TestFromClientSide3#testScanAfterDeletingSpecifiedRowV2
+ if (cell.getQualifierLength() == 0) {
+ Cell nextKey = CellUtil.createNextOnRowCol(cell);
+ if (nextKey != cell) {
+ return nextKey;
+ }
+ // The cell is at the end of row/family/qualifier, so it is impossible to find any DeleteFamily cells.
+ // Let us seek to next column.
+ }
ColumnCount nextColumn = columns.getColumnHint();
if (nextColumn == null) {
return CellUtil.createLastOnRowCol(cell);
http://git-wip-us.apache.org/repos/asf/hbase/blob/56f9e1a6/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide3.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide3.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide3.java
index f20c050..7b6c9a8 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide3.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide3.java
@@ -34,6 +34,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Cell;
+import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.Coprocessor;
import org.apache.hadoop.hbase.coprocessor.ObserverContext;
import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
@@ -159,6 +160,106 @@ public class TestFromClientSide3 {
}
}
+ private static List<Cell> toList(ResultScanner scanner) {
+ try {
+ List<Cell> cells = new ArrayList<>();
+ for (Result r : scanner) {
+ cells.addAll(r.listCells());
+ }
+ return cells;
+ } finally {
+ scanner.close();
+ }
+ }
+
+ @Test
+ public void testScanAfterDeletingSpecifiedRow() throws IOException {
+ TableName tableName = TableName.valueOf(name.getMethodName());
+ TableDescriptor desc = TableDescriptorBuilder.newBuilder(tableName)
+ .addColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILY))
+ .build();
+ TEST_UTIL.getAdmin().createTable(desc);
+ byte[] row = Bytes.toBytes("SpecifiedRow");
+ byte[] value0 = Bytes.toBytes("value_0");
+ byte[] value1 = Bytes.toBytes("value_1");
+ try (Table t = TEST_UTIL.getConnection().getTable(tableName)) {
+ Put put = new Put(row);
+ put.addColumn(FAMILY, QUALIFIER, VALUE);
+ t.put(put);
+ Delete d = new Delete(row);
+ t.delete(d);
+ put = new Put(row);
+ put.addColumn(FAMILY, null, value0);
+ t.put(put);
+ put = new Put(row);
+ put.addColumn(FAMILY, null, value1);
+ t.put(put);
+ List<Cell> cells = toList(t.getScanner(new Scan()));
+ assertEquals(1, cells.size());
+ assertEquals("value_1", Bytes.toString(CellUtil.cloneValue(cells.get(0))));
+
+ cells = toList(t.getScanner(new Scan().addFamily(FAMILY)));
+ assertEquals(1, cells.size());
+ assertEquals("value_1", Bytes.toString(CellUtil.cloneValue(cells.get(0))));
+
+ cells = toList(t.getScanner(new Scan().addColumn(FAMILY, QUALIFIER)));
+ assertEquals(0, cells.size());
+
+ TEST_UTIL.getAdmin().flush(tableName);
+ cells = toList(t.getScanner(new Scan()));
+ assertEquals(1, cells.size());
+ assertEquals("value_1", Bytes.toString(CellUtil.cloneValue(cells.get(0))));
+
+ cells = toList(t.getScanner(new Scan().addFamily(FAMILY)));
+ assertEquals(1, cells.size());
+ assertEquals("value_1", Bytes.toString(CellUtil.cloneValue(cells.get(0))));
+
+ cells = toList(t.getScanner(new Scan().addColumn(FAMILY, QUALIFIER)));
+ assertEquals(0, cells.size());
+ }
+ }
+
+ @Test
+ public void testScanAfterDeletingSpecifiedRowV2() throws IOException {
+ TableName tableName = TableName.valueOf(name.getMethodName());
+ TableDescriptor desc = TableDescriptorBuilder.newBuilder(tableName)
+ .addColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILY))
+ .build();
+ TEST_UTIL.getAdmin().createTable(desc);
+ byte[] row = Bytes.toBytes("SpecifiedRow");
+ byte[] qual0 = Bytes.toBytes("qual0");
+ byte[] qual1 = Bytes.toBytes("qual1");
+ try (Table t = TEST_UTIL.getConnection().getTable(tableName)) {
+ Delete d = new Delete(row);
+ t.delete(d);
+
+ Put put = new Put(row);
+ put.addColumn(FAMILY, null, VALUE);
+ t.put(put);
+
+ put = new Put(row);
+ put.addColumn(FAMILY, qual1, qual1);
+ t.put(put);
+
+ put = new Put(row);
+ put.addColumn(FAMILY, qual0, qual0);
+ t.put(put);
+
+ Result r = t.get(new Get(row));
+ assertEquals(3, r.size());
+ assertEquals("testValue", Bytes.toString(CellUtil.cloneValue(r.rawCells()[0])));
+ assertEquals("qual0", Bytes.toString(CellUtil.cloneValue(r.rawCells()[1])));
+ assertEquals("qual1", Bytes.toString(CellUtil.cloneValue(r.rawCells()[2])));
+
+ TEST_UTIL.getAdmin().flush(tableName);
+ r = t.get(new Get(row));
+ assertEquals(3, r.size());
+ assertEquals("testValue", Bytes.toString(CellUtil.cloneValue(r.rawCells()[0])));
+ assertEquals("qual0", Bytes.toString(CellUtil.cloneValue(r.rawCells()[1])));
+ assertEquals("qual1", Bytes.toString(CellUtil.cloneValue(r.rawCells()[2])));
+ }
+ }
+
// override the config settings at the CF level and ensure priority
@Test(timeout = 60000)
public void testAdvancedConfigOverride() throws Exception {