HBASE-4585 Avoid seek operation when current kv is deleted(Liyin Tang)
git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1185771 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
712bf529b8
commit
9e071332b2
|
@ -625,6 +625,7 @@ Release 0.92.0 - Unreleased
|
||||||
HBASE-4568 Make zk dump jsp response faster
|
HBASE-4568 Make zk dump jsp response faster
|
||||||
HBASE-4606 Remove spam in HCM and fix a list.size == 0
|
HBASE-4606 Remove spam in HCM and fix a list.size == 0
|
||||||
HBASE-3581 hbase rpc should send size of response
|
HBASE-3581 hbase rpc should send size of response
|
||||||
|
HBASE-4585 Avoid seek operation when current kv is deleted(Liyin Tang)
|
||||||
|
|
||||||
|
|
||||||
TASKS
|
TASKS
|
||||||
|
|
|
@ -51,9 +51,9 @@ public interface DeleteTracker {
|
||||||
* @param qualifierOffset column qualifier offset
|
* @param qualifierOffset column qualifier offset
|
||||||
* @param qualifierLength column qualifier length
|
* @param qualifierLength column qualifier length
|
||||||
* @param timestamp timestamp
|
* @param timestamp timestamp
|
||||||
* @return true is the specified KeyValue is deleted, false if not
|
* @return deleteResult The result tells whether the KeyValue is deleted and why
|
||||||
*/
|
*/
|
||||||
public boolean isDeleted(byte [] buffer, int qualifierOffset,
|
public DeleteResult isDeleted(byte [] buffer, int qualifierOffset,
|
||||||
int qualifierLength, long timestamp);
|
int qualifierLength, long timestamp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -94,4 +94,17 @@ public interface DeleteTracker {
|
||||||
NEXT_NEW
|
NEXT_NEW
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns codes for delete result.
|
||||||
|
* The codes tell the ScanQueryMatcher whether the kv is deleted and why.
|
||||||
|
* Based on the delete result, the ScanQueryMatcher will decide the next
|
||||||
|
* operation
|
||||||
|
*/
|
||||||
|
public static enum DeleteResult {
|
||||||
|
FAMILY_DELETED, // The KeyValue is deleted by a delete family.
|
||||||
|
COLUMN_DELETED, // The KeyValue is deleted by a delete column.
|
||||||
|
VERSION_DELETED, // The KeyValue is deleted by a version delete.
|
||||||
|
NOT_DELETED
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
package org.apache.hadoop.hbase.regionserver;
|
package org.apache.hadoop.hbase.regionserver;
|
||||||
|
|
||||||
import org.apache.hadoop.hbase.KeyValue;
|
import org.apache.hadoop.hbase.KeyValue;
|
||||||
|
import org.apache.hadoop.hbase.regionserver.DeleteTracker.DeleteResult;
|
||||||
import org.apache.hadoop.hbase.util.Bytes;
|
import org.apache.hadoop.hbase.util.Bytes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -99,13 +100,13 @@ public class ScanDeleteTracker implements DeleteTracker {
|
||||||
* @param qualifierOffset column qualifier offset
|
* @param qualifierOffset column qualifier offset
|
||||||
* @param qualifierLength column qualifier length
|
* @param qualifierLength column qualifier length
|
||||||
* @param timestamp timestamp
|
* @param timestamp timestamp
|
||||||
* @return true is the specified KeyValue is deleted, false if not
|
* @return deleteResult
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean isDeleted(byte [] buffer, int qualifierOffset,
|
public DeleteResult isDeleted(byte [] buffer, int qualifierOffset,
|
||||||
int qualifierLength, long timestamp) {
|
int qualifierLength, long timestamp) {
|
||||||
if (timestamp <= familyStamp) {
|
if (timestamp <= familyStamp) {
|
||||||
return true;
|
return DeleteResult.FAMILY_DELETED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deleteBuffer != null) {
|
if (deleteBuffer != null) {
|
||||||
|
@ -114,12 +115,12 @@ public class ScanDeleteTracker implements DeleteTracker {
|
||||||
|
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
if (deleteType == KeyValue.Type.DeleteColumn.getCode()) {
|
if (deleteType == KeyValue.Type.DeleteColumn.getCode()) {
|
||||||
return true;
|
return DeleteResult.COLUMN_DELETED;
|
||||||
}
|
}
|
||||||
// Delete (aka DeleteVersion)
|
// Delete (aka DeleteVersion)
|
||||||
// If the timestamp is the same, keep this one
|
// If the timestamp is the same, keep this one
|
||||||
if (timestamp == deleteTimestamp) {
|
if (timestamp == deleteTimestamp) {
|
||||||
return true;
|
return DeleteResult.VERSION_DELETED;
|
||||||
}
|
}
|
||||||
// use assert or not?
|
// use assert or not?
|
||||||
assert timestamp < deleteTimestamp;
|
assert timestamp < deleteTimestamp;
|
||||||
|
@ -138,7 +139,7 @@ public class ScanDeleteTracker implements DeleteTracker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return DeleteResult.NOT_DELETED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -158,4 +159,4 @@ public class ScanDeleteTracker implements DeleteTracker {
|
||||||
public void update() {
|
public void update() {
|
||||||
this.reset();
|
this.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import org.apache.hadoop.hbase.client.Scan;
|
||||||
import org.apache.hadoop.hbase.filter.Filter;
|
import org.apache.hadoop.hbase.filter.Filter;
|
||||||
import org.apache.hadoop.hbase.filter.Filter.ReturnCode;
|
import org.apache.hadoop.hbase.filter.Filter.ReturnCode;
|
||||||
import org.apache.hadoop.hbase.io.TimeRange;
|
import org.apache.hadoop.hbase.io.TimeRange;
|
||||||
|
import org.apache.hadoop.hbase.regionserver.DeleteTracker.DeleteResult;
|
||||||
import org.apache.hadoop.hbase.util.Bytes;
|
import org.apache.hadoop.hbase.util.Bytes;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -184,15 +185,20 @@ public class ScanQueryMatcher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.deletes.isEmpty() &&
|
if (!this.deletes.isEmpty()) {
|
||||||
deletes.isDeleted(bytes, offset, qualLength, timestamp)) {
|
DeleteResult deleteResult = deletes.isDeleted(bytes, offset, qualLength,
|
||||||
|
timestamp);
|
||||||
// May be able to optimize the SKIP here, if we matched
|
switch (deleteResult) {
|
||||||
// due to a DelFam, we can skip to next row
|
case FAMILY_DELETED:
|
||||||
// due to a DelCol, we can skip to next col
|
case COLUMN_DELETED:
|
||||||
// But it requires more info out of isDelete().
|
return columns.getNextRowOrNextColumn(bytes, offset, qualLength);
|
||||||
// needful -> million column challenge.
|
case VERSION_DELETED:
|
||||||
return MatchCode.SKIP;
|
return MatchCode.SKIP;
|
||||||
|
case NOT_DELETED:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new RuntimeException("UNEXPECTED");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int timestampComparison = tr.compare(timestamp);
|
int timestampComparison = tr.compare(timestamp);
|
||||||
|
|
|
@ -283,14 +283,14 @@ public class TestBlocksRead extends HBaseTestCase {
|
||||||
deleteFamily(FAMILY, "row", 6);
|
deleteFamily(FAMILY, "row", 6);
|
||||||
region.flushcache();
|
region.flushcache();
|
||||||
|
|
||||||
// Baseline expected blocks read: 6.
|
// Baseline expected blocks read: 4. [HBASE-4585]
|
||||||
kvs = getData(FAMILY, "row", "col1", 6);
|
kvs = getData(FAMILY, "row", "col1", 4);
|
||||||
assertEquals(0, kvs.length);
|
assertEquals(0, kvs.length);
|
||||||
kvs = getData(FAMILY, "row", "col2", 6);
|
kvs = getData(FAMILY, "row", "col2", 5);
|
||||||
assertEquals(0, kvs.length);
|
assertEquals(0, kvs.length);
|
||||||
kvs = getData(FAMILY, "row", "col3", 6);
|
kvs = getData(FAMILY, "row", "col3", 4);
|
||||||
assertEquals(0, kvs.length);
|
assertEquals(0, kvs.length);
|
||||||
kvs = getData(FAMILY, "row", Arrays.asList("col1", "col2", "col3"), 6);
|
kvs = getData(FAMILY, "row", Arrays.asList("col1", "col2", "col3"), 5);
|
||||||
assertEquals(0, kvs.length);
|
assertEquals(0, kvs.length);
|
||||||
|
|
||||||
// File 5: Delete
|
// File 5: Delete
|
||||||
|
@ -304,8 +304,8 @@ public class TestBlocksRead extends HBaseTestCase {
|
||||||
putData(FAMILY, "row", "col3", 9);
|
putData(FAMILY, "row", "col3", 9);
|
||||||
region.flushcache();
|
region.flushcache();
|
||||||
|
|
||||||
// Baseline expected blocks read: 10
|
// Baseline expected blocks read: 8. [HBASE-4585]
|
||||||
kvs = getData(FAMILY, "row", Arrays.asList("col1", "col2", "col3"), 10);
|
kvs = getData(FAMILY, "row", Arrays.asList("col1", "col2", "col3"), 8);
|
||||||
assertEquals(0, kvs.length);
|
assertEquals(0, kvs.length);
|
||||||
|
|
||||||
// File 7: Put back new data
|
// File 7: Put back new data
|
||||||
|
|
|
@ -23,6 +23,7 @@ package org.apache.hadoop.hbase.regionserver;
|
||||||
import org.apache.hadoop.hbase.HBaseTestCase;
|
import org.apache.hadoop.hbase.HBaseTestCase;
|
||||||
import org.apache.hadoop.hbase.HConstants;
|
import org.apache.hadoop.hbase.HConstants;
|
||||||
import org.apache.hadoop.hbase.KeyValue;
|
import org.apache.hadoop.hbase.KeyValue;
|
||||||
|
import org.apache.hadoop.hbase.regionserver.DeleteTracker.DeleteResult;
|
||||||
import org.apache.hadoop.hbase.util.Bytes;
|
import org.apache.hadoop.hbase.util.Bytes;
|
||||||
|
|
||||||
|
|
||||||
|
@ -42,8 +43,8 @@ public class TestScanDeleteTracker extends HBaseTestCase {
|
||||||
deleteType = KeyValue.Type.Delete.getCode();
|
deleteType = KeyValue.Type.Delete.getCode();
|
||||||
|
|
||||||
sdt.add(qualifier, 0, qualifier.length, timestamp, deleteType);
|
sdt.add(qualifier, 0, qualifier.length, timestamp, deleteType);
|
||||||
boolean ret = sdt.isDeleted(qualifier, 0, qualifier.length, timestamp);
|
DeleteResult ret = sdt.isDeleted(qualifier, 0, qualifier.length, timestamp);
|
||||||
assertEquals(true, ret);
|
assertEquals(DeleteResult.VERSION_DELETED, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testDeletedBy_DeleteColumn() {
|
public void testDeletedBy_DeleteColumn() {
|
||||||
|
@ -52,8 +53,8 @@ public class TestScanDeleteTracker extends HBaseTestCase {
|
||||||
|
|
||||||
sdt.add(qualifier, 0, qualifier.length, timestamp, deleteType);
|
sdt.add(qualifier, 0, qualifier.length, timestamp, deleteType);
|
||||||
timestamp -= 5;
|
timestamp -= 5;
|
||||||
boolean ret = sdt.isDeleted(qualifier, 0, qualifier.length, timestamp);
|
DeleteResult ret = sdt.isDeleted(qualifier, 0, qualifier.length, timestamp);
|
||||||
assertEquals(true, ret);
|
assertEquals(DeleteResult.COLUMN_DELETED, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testDeletedBy_DeleteFamily() {
|
public void testDeletedBy_DeleteFamily() {
|
||||||
|
@ -63,8 +64,8 @@ public class TestScanDeleteTracker extends HBaseTestCase {
|
||||||
sdt.add(qualifier, 0, qualifier.length, timestamp, deleteType);
|
sdt.add(qualifier, 0, qualifier.length, timestamp, deleteType);
|
||||||
|
|
||||||
timestamp -= 5;
|
timestamp -= 5;
|
||||||
boolean ret = sdt.isDeleted(qualifier, 0, qualifier.length, timestamp);
|
DeleteResult ret = sdt.isDeleted(qualifier, 0, qualifier.length, timestamp);
|
||||||
assertEquals(true, ret);
|
assertEquals(DeleteResult.FAMILY_DELETED, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testDelete_DeleteColumn() {
|
public void testDelete_DeleteColumn() {
|
||||||
|
@ -78,8 +79,8 @@ public class TestScanDeleteTracker extends HBaseTestCase {
|
||||||
sdt.add(qualifier, 0, qualifier.length, timestamp, deleteType);
|
sdt.add(qualifier, 0, qualifier.length, timestamp, deleteType);
|
||||||
|
|
||||||
timestamp -= 5;
|
timestamp -= 5;
|
||||||
boolean ret = sdt.isDeleted(qualifier, 0, qualifier.length, timestamp);
|
DeleteResult ret = sdt.isDeleted(qualifier, 0, qualifier.length, timestamp);
|
||||||
assertEquals(true, ret);
|
assertEquals(DeleteResult.COLUMN_DELETED, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -93,8 +94,8 @@ public class TestScanDeleteTracker extends HBaseTestCase {
|
||||||
deleteType = KeyValue.Type.Delete.getCode();
|
deleteType = KeyValue.Type.Delete.getCode();
|
||||||
sdt.add(qualifier, 0, qualifier.length, timestamp, deleteType);
|
sdt.add(qualifier, 0, qualifier.length, timestamp, deleteType);
|
||||||
|
|
||||||
boolean ret = sdt.isDeleted(qualifier, 0, qualifier.length, timestamp);
|
DeleteResult ret = sdt.isDeleted(qualifier, 0, qualifier.length, timestamp);
|
||||||
assertEquals(true, ret);
|
assertEquals( DeleteResult.VERSION_DELETED, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Testing new way where we save the Delete in case of a Delete for specific
|
//Testing new way where we save the Delete in case of a Delete for specific
|
||||||
|
@ -109,5 +110,4 @@ public class TestScanDeleteTracker extends HBaseTestCase {
|
||||||
assertEquals(false ,sdt.isEmpty());
|
assertEquals(false ,sdt.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue