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-4606 Remove spam in HCM and fix a list.size == 0
|
||||
HBASE-3581 hbase rpc should send size of response
|
||||
HBASE-4585 Avoid seek operation when current kv is deleted(Liyin Tang)
|
||||
|
||||
|
||||
TASKS
|
||||
|
|
|
@ -51,9 +51,9 @@ public interface DeleteTracker {
|
|||
* @param qualifierOffset column qualifier offset
|
||||
* @param qualifierLength column qualifier length
|
||||
* @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);
|
||||
|
||||
/**
|
||||
|
@ -94,4 +94,17 @@ public interface DeleteTracker {
|
|||
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;
|
||||
|
||||
import org.apache.hadoop.hbase.KeyValue;
|
||||
import org.apache.hadoop.hbase.regionserver.DeleteTracker.DeleteResult;
|
||||
import org.apache.hadoop.hbase.util.Bytes;
|
||||
|
||||
/**
|
||||
|
@ -99,13 +100,13 @@ public class ScanDeleteTracker implements DeleteTracker {
|
|||
* @param qualifierOffset column qualifier offset
|
||||
* @param qualifierLength column qualifier length
|
||||
* @param timestamp timestamp
|
||||
* @return true is the specified KeyValue is deleted, false if not
|
||||
* @return deleteResult
|
||||
*/
|
||||
@Override
|
||||
public boolean isDeleted(byte [] buffer, int qualifierOffset,
|
||||
public DeleteResult isDeleted(byte [] buffer, int qualifierOffset,
|
||||
int qualifierLength, long timestamp) {
|
||||
if (timestamp <= familyStamp) {
|
||||
return true;
|
||||
return DeleteResult.FAMILY_DELETED;
|
||||
}
|
||||
|
||||
if (deleteBuffer != null) {
|
||||
|
@ -114,12 +115,12 @@ public class ScanDeleteTracker implements DeleteTracker {
|
|||
|
||||
if (ret == 0) {
|
||||
if (deleteType == KeyValue.Type.DeleteColumn.getCode()) {
|
||||
return true;
|
||||
return DeleteResult.COLUMN_DELETED;
|
||||
}
|
||||
// Delete (aka DeleteVersion)
|
||||
// If the timestamp is the same, keep this one
|
||||
if (timestamp == deleteTimestamp) {
|
||||
return true;
|
||||
return DeleteResult.VERSION_DELETED;
|
||||
}
|
||||
// use assert or not?
|
||||
assert timestamp < deleteTimestamp;
|
||||
|
@ -138,7 +139,7 @@ public class ScanDeleteTracker implements DeleteTracker {
|
|||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return DeleteResult.NOT_DELETED;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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.ReturnCode;
|
||||
import org.apache.hadoop.hbase.io.TimeRange;
|
||||
import org.apache.hadoop.hbase.regionserver.DeleteTracker.DeleteResult;
|
||||
import org.apache.hadoop.hbase.util.Bytes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -184,15 +185,20 @@ public class ScanQueryMatcher {
|
|||
}
|
||||
}
|
||||
|
||||
if (!this.deletes.isEmpty() &&
|
||||
deletes.isDeleted(bytes, offset, qualLength, timestamp)) {
|
||||
|
||||
// May be able to optimize the SKIP here, if we matched
|
||||
// due to a DelFam, we can skip to next row
|
||||
// due to a DelCol, we can skip to next col
|
||||
// But it requires more info out of isDelete().
|
||||
// needful -> million column challenge.
|
||||
if (!this.deletes.isEmpty()) {
|
||||
DeleteResult deleteResult = deletes.isDeleted(bytes, offset, qualLength,
|
||||
timestamp);
|
||||
switch (deleteResult) {
|
||||
case FAMILY_DELETED:
|
||||
case COLUMN_DELETED:
|
||||
return columns.getNextRowOrNextColumn(bytes, offset, qualLength);
|
||||
case VERSION_DELETED:
|
||||
return MatchCode.SKIP;
|
||||
case NOT_DELETED:
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("UNEXPECTED");
|
||||
}
|
||||
}
|
||||
|
||||
int timestampComparison = tr.compare(timestamp);
|
||||
|
|
|
@ -283,14 +283,14 @@ public class TestBlocksRead extends HBaseTestCase {
|
|||
deleteFamily(FAMILY, "row", 6);
|
||||
region.flushcache();
|
||||
|
||||
// Baseline expected blocks read: 6.
|
||||
kvs = getData(FAMILY, "row", "col1", 6);
|
||||
// Baseline expected blocks read: 4. [HBASE-4585]
|
||||
kvs = getData(FAMILY, "row", "col1", 4);
|
||||
assertEquals(0, kvs.length);
|
||||
kvs = getData(FAMILY, "row", "col2", 6);
|
||||
kvs = getData(FAMILY, "row", "col2", 5);
|
||||
assertEquals(0, kvs.length);
|
||||
kvs = getData(FAMILY, "row", "col3", 6);
|
||||
kvs = getData(FAMILY, "row", "col3", 4);
|
||||
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);
|
||||
|
||||
// File 5: Delete
|
||||
|
@ -304,8 +304,8 @@ public class TestBlocksRead extends HBaseTestCase {
|
|||
putData(FAMILY, "row", "col3", 9);
|
||||
region.flushcache();
|
||||
|
||||
// Baseline expected blocks read: 10
|
||||
kvs = getData(FAMILY, "row", Arrays.asList("col1", "col2", "col3"), 10);
|
||||
// Baseline expected blocks read: 8. [HBASE-4585]
|
||||
kvs = getData(FAMILY, "row", Arrays.asList("col1", "col2", "col3"), 8);
|
||||
assertEquals(0, kvs.length);
|
||||
|
||||
// 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.HConstants;
|
||||
import org.apache.hadoop.hbase.KeyValue;
|
||||
import org.apache.hadoop.hbase.regionserver.DeleteTracker.DeleteResult;
|
||||
import org.apache.hadoop.hbase.util.Bytes;
|
||||
|
||||
|
||||
|
@ -42,8 +43,8 @@ public class TestScanDeleteTracker extends HBaseTestCase {
|
|||
deleteType = KeyValue.Type.Delete.getCode();
|
||||
|
||||
sdt.add(qualifier, 0, qualifier.length, timestamp, deleteType);
|
||||
boolean ret = sdt.isDeleted(qualifier, 0, qualifier.length, timestamp);
|
||||
assertEquals(true, ret);
|
||||
DeleteResult ret = sdt.isDeleted(qualifier, 0, qualifier.length, timestamp);
|
||||
assertEquals(DeleteResult.VERSION_DELETED, ret);
|
||||
}
|
||||
|
||||
public void testDeletedBy_DeleteColumn() {
|
||||
|
@ -52,8 +53,8 @@ public class TestScanDeleteTracker extends HBaseTestCase {
|
|||
|
||||
sdt.add(qualifier, 0, qualifier.length, timestamp, deleteType);
|
||||
timestamp -= 5;
|
||||
boolean ret = sdt.isDeleted(qualifier, 0, qualifier.length, timestamp);
|
||||
assertEquals(true, ret);
|
||||
DeleteResult ret = sdt.isDeleted(qualifier, 0, qualifier.length, timestamp);
|
||||
assertEquals(DeleteResult.COLUMN_DELETED, ret);
|
||||
}
|
||||
|
||||
public void testDeletedBy_DeleteFamily() {
|
||||
|
@ -63,8 +64,8 @@ public class TestScanDeleteTracker extends HBaseTestCase {
|
|||
sdt.add(qualifier, 0, qualifier.length, timestamp, deleteType);
|
||||
|
||||
timestamp -= 5;
|
||||
boolean ret = sdt.isDeleted(qualifier, 0, qualifier.length, timestamp);
|
||||
assertEquals(true, ret);
|
||||
DeleteResult ret = sdt.isDeleted(qualifier, 0, qualifier.length, timestamp);
|
||||
assertEquals(DeleteResult.FAMILY_DELETED, ret);
|
||||
}
|
||||
|
||||
public void testDelete_DeleteColumn() {
|
||||
|
@ -78,8 +79,8 @@ public class TestScanDeleteTracker extends HBaseTestCase {
|
|||
sdt.add(qualifier, 0, qualifier.length, timestamp, deleteType);
|
||||
|
||||
timestamp -= 5;
|
||||
boolean ret = sdt.isDeleted(qualifier, 0, qualifier.length, timestamp);
|
||||
assertEquals(true, ret);
|
||||
DeleteResult ret = sdt.isDeleted(qualifier, 0, qualifier.length, timestamp);
|
||||
assertEquals(DeleteResult.COLUMN_DELETED, ret);
|
||||
}
|
||||
|
||||
|
||||
|
@ -93,8 +94,8 @@ public class TestScanDeleteTracker extends HBaseTestCase {
|
|||
deleteType = KeyValue.Type.Delete.getCode();
|
||||
sdt.add(qualifier, 0, qualifier.length, timestamp, deleteType);
|
||||
|
||||
boolean ret = sdt.isDeleted(qualifier, 0, qualifier.length, timestamp);
|
||||
assertEquals(true, ret);
|
||||
DeleteResult ret = sdt.isDeleted(qualifier, 0, qualifier.length, timestamp);
|
||||
assertEquals( DeleteResult.VERSION_DELETED, ret);
|
||||
}
|
||||
|
||||
//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());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue