diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/HalfStoreFileReader.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/HalfStoreFileReader.java index 5ce6c74..e7ed6d4 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/HalfStoreFileReader.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/HalfStoreFileReader.java @@ -294,6 +294,11 @@ public class HalfStoreFileReader extends StoreFile.Reader { public boolean isSeeked() { return this.delegate.isSeeked(); } + + @Override + public byte[] getNextIndexedKey() { + return null; + } }; } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/HFileReaderV2.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/HFileReaderV2.java index 1c7c02b..816822b 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/HFileReaderV2.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/HFileReaderV2.java @@ -512,6 +512,10 @@ public class HFileReaderV2 extends AbstractHFileReader { super(r, cacheBlocks, pread, isCompaction); } + @Override + public byte[] getNextIndexedKey() { + return nextIndexedKey; + } /** * An internal API function. Seek to the given key, optionally rewinding to * the first key of the block before doing the seek. diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/HFileScanner.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/HFileScanner.java index c0b2047..60cd80a 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/HFileScanner.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/HFileScanner.java @@ -144,4 +144,5 @@ public interface HFileScanner { * Otherwise returns false. */ boolean isSeeked(); + byte[] getNextIndexedKey(); } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/KeyValueHeap.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/KeyValueHeap.java index f8cc5b4..6bffe50 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/KeyValueHeap.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/KeyValueHeap.java @@ -396,4 +396,8 @@ public class KeyValueHeap extends NonReversedNonLazyKeyValueScanner KeyValueScanner getCurrentForTesting() { return current; } + @Override + public byte[] getNextIndexedKey() { + return current == null ? null : current.getNextIndexedKey(); + } } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/KeyValueScanner.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/KeyValueScanner.java index babb216..9dc9c8e 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/KeyValueScanner.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/KeyValueScanner.java @@ -156,4 +156,5 @@ public interface KeyValueScanner { * @throws IOException */ public boolean seekToLastRow() throws IOException; + byte[] getNextIndexedKey(); } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/NonLazyKeyValueScanner.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/NonLazyKeyValueScanner.java index a892637..5e7cecb 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/NonLazyKeyValueScanner.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/NonLazyKeyValueScanner.java @@ -67,4 +67,8 @@ public abstract class NonLazyKeyValueScanner implements KeyValueScanner { // Not a file by default. return false; } + @Override + public byte[] getNextIndexedKey() { + return null; + } } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFileScanner.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFileScanner.java index e528770..ac3d12f 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFileScanner.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFileScanner.java @@ -475,4 +475,9 @@ public class StoreFileScanner implements KeyValueScanner { } return true; } + + @Override + public byte[] getNextIndexedKey() { + return hfs.getNextIndexedKey(); + } } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StoreScanner.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StoreScanner.java index 853e1bf..b86839c 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StoreScanner.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StoreScanner.java @@ -41,6 +41,7 @@ import org.apache.hadoop.hbase.client.IsolationLevel; import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.executor.ExecutorService; import org.apache.hadoop.hbase.filter.Filter; +import org.apache.hadoop.hbase.regionserver.ScanQueryMatcher.MatchCode; import org.apache.hadoop.hbase.regionserver.handler.ParallelSeekHandler; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; @@ -478,6 +479,7 @@ public class StoreScanner extends NonReversedNonLazyKeyValueScanner prevKV = kv; ScanQueryMatcher.MatchCode qcode = matcher.match(kv); + qcode = optimize(qcode, kv); switch(qcode) { case INCLUDE: case INCLUDE_AND_SEEK_NEXT_ROW: @@ -575,6 +577,44 @@ public class StoreScanner extends NonReversedNonLazyKeyValueScanner } } + private ScanQueryMatcher.MatchCode optimize(ScanQueryMatcher.MatchCode qcode, KeyValue kv) { + byte[] nextIndexedKey = getNextIndexedKey(); + if (nextIndexedKey == null || nextIndexedKey == HConstants.NO_NEXT_INDEXED_KEY || store == null) { + return qcode; + } + switch(qcode) { + case INCLUDE_AND_SEEK_NEXT_COL: + case SEEK_NEXT_COL: + { + KeyValue key = matcher.getKeyForNextColumn(kv); + byte[] keyBuf = key.getBuffer(); + int keyOff = key.getKeyOffset(); + int keyLen = key.getKeyLength(); + if (store.getComparator().compareFlatKey(keyBuf, keyOff, keyLen, + nextIndexedKey, 0, nextIndexedKey.length) < 0) { + return qcode == MatchCode.SEEK_NEXT_COL ? MatchCode.SKIP : MatchCode.INCLUDE; + } + break; + } + case INCLUDE_AND_SEEK_NEXT_ROW: + case SEEK_NEXT_ROW: + { + KeyValue key = matcher.getKeyForNextRow(kv); + byte[] keyBuf = key.getBuffer(); + int keyOff = key.getKeyOffset(); + int keyLen = key.getKeyLength(); + if (store.getComparator().compareFlatKey(keyBuf, keyOff, keyLen, + nextIndexedKey, 0, nextIndexedKey.length) < 0) { + return qcode == MatchCode.SEEK_NEXT_ROW ? MatchCode.SKIP : MatchCode.INCLUDE; + } + break; + } + default: + break; + } + return qcode; + } + @Override public boolean next(List outResult) throws IOException { return next(outResult, -1); @@ -778,5 +818,10 @@ public class StoreScanner extends NonReversedNonLazyKeyValueScanner public long getEstimatedNumberOfKvsScanned() { return this.kvsScanned; } + + @Override + public byte[] getNextIndexedKey() { + return this.heap.getNextIndexedKey(); + } }