HBASE-1949 KeyValue expiration by Time-to-Live during major compaction is broken
git-svn-id: https://svn.apache.org/repos/asf/hadoop/hbase/trunk@833194 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
c25e5e20e1
commit
f76400f6e9
|
@ -94,6 +94,8 @@ Release 0.21.0 - Unreleased
|
||||||
when deleting a lot of values
|
when deleting a lot of values
|
||||||
HBASE-1781 Weird behavior of WildcardColumnTracker.checkColumn(),
|
HBASE-1781 Weird behavior of WildcardColumnTracker.checkColumn(),
|
||||||
looks like recursive loop
|
looks like recursive loop
|
||||||
|
HBASE-1949 KeyValue expiration by Time-to-Live during major compaction is
|
||||||
|
broken (Gary Helmling via Stack)
|
||||||
|
|
||||||
IMPROVEMENTS
|
IMPROVEMENTS
|
||||||
HBASE-1760 Cleanup TODOs in HTable
|
HBASE-1760 Cleanup TODOs in HTable
|
||||||
|
|
|
@ -231,8 +231,10 @@ public class QueryMatcher {
|
||||||
*/
|
*/
|
||||||
long timestamp = Bytes.toLong(bytes, offset);
|
long timestamp = Bytes.toLong(bytes, offset);
|
||||||
if(isExpired(timestamp)) {
|
if(isExpired(timestamp)) {
|
||||||
// reached the expired part, for scans, this indicates we're done.
|
/* KeyValue is expired, skip but don't early out since a non-expired
|
||||||
return MatchCode.NEXT; // done_row
|
* kv could come next.
|
||||||
|
*/
|
||||||
|
return MatchCode.SKIP; // go to next kv
|
||||||
}
|
}
|
||||||
offset += Bytes.SIZEOF_LONG;
|
offset += Bytes.SIZEOF_LONG;
|
||||||
|
|
||||||
|
|
|
@ -122,9 +122,8 @@ public class ScanQueryMatcher extends QueryMatcher {
|
||||||
|
|
||||||
long timestamp = kv.getTimestamp();
|
long timestamp = kv.getTimestamp();
|
||||||
if (isExpired(timestamp)) {
|
if (isExpired(timestamp)) {
|
||||||
// done, the rest wil also be expired as well.
|
// done, the rest of this column will also be expired as well.
|
||||||
stickyNextRow = true;
|
return MatchCode.SEEK_NEXT_COL;
|
||||||
return MatchCode.SEEK_NEXT_ROW;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
byte type = kv.getType();
|
byte type = kv.getType();
|
||||||
|
|
|
@ -27,6 +27,7 @@ import java.util.List;
|
||||||
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.KeyValueTestUtil;
|
||||||
import org.apache.hadoop.hbase.KeyValue.KeyComparator;
|
import org.apache.hadoop.hbase.KeyValue.KeyComparator;
|
||||||
import org.apache.hadoop.hbase.client.Get;
|
import org.apache.hadoop.hbase.client.Get;
|
||||||
import org.apache.hadoop.hbase.regionserver.QueryMatcher.MatchCode;
|
import org.apache.hadoop.hbase.regionserver.QueryMatcher.MatchCode;
|
||||||
|
@ -162,4 +163,103 @@ implements HConstants {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that {@link QueryMatcher} only skips expired KeyValue
|
||||||
|
* instances and does not exit early from the row (skipping
|
||||||
|
* later non-expired KeyValues). This version mimics a Get with
|
||||||
|
* explicitly specified column qualifiers.
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public void testMatch_ExpiredExplicit()
|
||||||
|
throws IOException {
|
||||||
|
|
||||||
|
long testTTL = 1000;
|
||||||
|
MatchCode [] expected = new MatchCode[] {
|
||||||
|
MatchCode.SKIP,
|
||||||
|
MatchCode.INCLUDE,
|
||||||
|
MatchCode.SKIP,
|
||||||
|
MatchCode.INCLUDE,
|
||||||
|
MatchCode.SKIP,
|
||||||
|
MatchCode.NEXT
|
||||||
|
};
|
||||||
|
|
||||||
|
QueryMatcher qm = new QueryMatcher(get, fam2,
|
||||||
|
get.getFamilyMap().get(fam2), testTTL, rowComparator, 1);
|
||||||
|
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
KeyValue [] kvs = new KeyValue[] {
|
||||||
|
new KeyValue(row1, fam2, col1, now-100, data),
|
||||||
|
new KeyValue(row1, fam2, col2, now-50, data),
|
||||||
|
new KeyValue(row1, fam2, col3, now-5000, data),
|
||||||
|
new KeyValue(row1, fam2, col4, now-500, data),
|
||||||
|
new KeyValue(row1, fam2, col5, now-10000, data),
|
||||||
|
new KeyValue(row2, fam1, col1, now-10, data)
|
||||||
|
};
|
||||||
|
|
||||||
|
List<MatchCode> actual = new ArrayList<MatchCode>(kvs.length);
|
||||||
|
for (KeyValue kv : kvs) {
|
||||||
|
actual.add( qm.match(kv) );
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(expected.length, actual.size());
|
||||||
|
for (int i=0; i<expected.length; i++) {
|
||||||
|
if(PRINT){
|
||||||
|
System.out.println("expected "+expected[i]+
|
||||||
|
", actual " +actual.get(i));
|
||||||
|
}
|
||||||
|
assertEquals(expected[i], actual.get(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that {@link QueryMatcher} only skips expired KeyValue
|
||||||
|
* instances and does not exit early from the row (skipping
|
||||||
|
* later non-expired KeyValues). This version mimics a Get with
|
||||||
|
* wildcard-inferred column qualifiers.
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public void testMatch_ExpiredWildcard()
|
||||||
|
throws IOException {
|
||||||
|
|
||||||
|
long testTTL = 1000;
|
||||||
|
MatchCode [] expected = new MatchCode[] {
|
||||||
|
MatchCode.INCLUDE,
|
||||||
|
MatchCode.INCLUDE,
|
||||||
|
MatchCode.SKIP,
|
||||||
|
MatchCode.INCLUDE,
|
||||||
|
MatchCode.SKIP,
|
||||||
|
MatchCode.NEXT
|
||||||
|
};
|
||||||
|
|
||||||
|
QueryMatcher qm = new QueryMatcher(get, fam2,
|
||||||
|
null, testTTL, rowComparator, 1);
|
||||||
|
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
KeyValue [] kvs = new KeyValue[] {
|
||||||
|
new KeyValue(row1, fam2, col1, now-100, data),
|
||||||
|
new KeyValue(row1, fam2, col2, now-50, data),
|
||||||
|
new KeyValue(row1, fam2, col3, now-5000, data),
|
||||||
|
new KeyValue(row1, fam2, col4, now-500, data),
|
||||||
|
new KeyValue(row1, fam2, col5, now-10000, data),
|
||||||
|
new KeyValue(row2, fam1, col1, now-10, data)
|
||||||
|
};
|
||||||
|
|
||||||
|
List<MatchCode> actual = new ArrayList<MatchCode>(kvs.length);
|
||||||
|
for (KeyValue kv : kvs) {
|
||||||
|
actual.add( qm.match(kv) );
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(expected.length, actual.size());
|
||||||
|
for (int i=0; i<expected.length; i++) {
|
||||||
|
if(PRINT){
|
||||||
|
System.out.println("expected "+expected[i]+
|
||||||
|
", actual " +actual.get(i));
|
||||||
|
}
|
||||||
|
assertEquals(expected[i], actual.get(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -354,4 +354,46 @@ public class TestStoreScanner extends TestCase {
|
||||||
results.clear();
|
results.clear();
|
||||||
assertEquals(false, scan.next(results));
|
assertEquals(false, scan.next(results));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test expiration of KeyValues in combination with a configured TTL for
|
||||||
|
* a column family (as should be triggered in a major compaction).
|
||||||
|
*/
|
||||||
|
public void testWildCardTtlScan() throws IOException {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
KeyValue [] kvs = new KeyValue[] {
|
||||||
|
KeyValueTestUtil.create("R1", "cf", "a", now-1000, KeyValue.Type.Put, "dont-care"),
|
||||||
|
KeyValueTestUtil.create("R1", "cf", "b", now-10, KeyValue.Type.Put, "dont-care"),
|
||||||
|
KeyValueTestUtil.create("R1", "cf", "c", now-200, KeyValue.Type.Put, "dont-care"),
|
||||||
|
KeyValueTestUtil.create("R1", "cf", "d", now-10000, KeyValue.Type.Put, "dont-care"),
|
||||||
|
KeyValueTestUtil.create("R2", "cf", "a", now, KeyValue.Type.Put, "dont-care"),
|
||||||
|
KeyValueTestUtil.create("R2", "cf", "b", now-10, KeyValue.Type.Put, "dont-care"),
|
||||||
|
KeyValueTestUtil.create("R2", "cf", "c", now-200, KeyValue.Type.Put, "dont-care"),
|
||||||
|
KeyValueTestUtil.create("R2", "cf", "c", now-1000, KeyValue.Type.Put, "dont-care")
|
||||||
|
};
|
||||||
|
KeyValueScanner [] scanners = new KeyValueScanner[] {
|
||||||
|
new KeyValueScanFixture(KeyValue.COMPARATOR, kvs)
|
||||||
|
};
|
||||||
|
Scan scan = new Scan();
|
||||||
|
scan.setMaxVersions(1);
|
||||||
|
StoreScanner scanner =
|
||||||
|
new StoreScanner(scan, CF, 500, KeyValue.COMPARATOR,
|
||||||
|
null, scanners);
|
||||||
|
|
||||||
|
List<KeyValue> results = new ArrayList<KeyValue>();
|
||||||
|
assertEquals(true, scanner.next(results));
|
||||||
|
assertEquals(2, results.size());
|
||||||
|
assertEquals(kvs[1], results.get(0));
|
||||||
|
assertEquals(kvs[2], results.get(1));
|
||||||
|
results.clear();
|
||||||
|
|
||||||
|
assertEquals(true, scanner.next(results));
|
||||||
|
assertEquals(3, results.size());
|
||||||
|
assertEquals(kvs[4], results.get(0));
|
||||||
|
assertEquals(kvs[5], results.get(1));
|
||||||
|
assertEquals(kvs[6], results.get(2));
|
||||||
|
results.clear();
|
||||||
|
|
||||||
|
assertEquals(false, scanner.next(results));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue