Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,11 @@ public StoreScanner(HStore store, ScanInfo scanInfo, Scan scan, NavigableSet<byt
// Always check bloom filter to optimize the top row seek for delete
// family marker.

seekScanners(scanners, matcher.getStartKey(), explicitColumnQuery && lazySeekEnabledGlobally,
parallelSeekEnabled);
// Filters must only see real Cells. A lazy seek can expose a synthetic Cell
// for the scan start row, so disable it for non-Get filters.
boolean useLazySeek = explicitColumnQuery && lazySeekEnabledGlobally
&& !(scan.hasFilter() && !scan.isGetScan());
seekScanners(scanners, matcher.getStartKey(), useLazySeek, parallelSeekEnabled);

// set storeLimit
this.storeLimit = scan.getMaxResultsPerColumnFamily();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,11 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.NavigableSet;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.CompareOperator;
import org.apache.hadoop.hbase.ExtendedCell;
import org.apache.hadoop.hbase.HBaseTestingUtil;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.HTestConst;
Expand All @@ -48,9 +51,11 @@
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.client.TableDescriptor;
import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
import org.apache.hadoop.hbase.filter.ByteArrayComparable;
import org.apache.hadoop.hbase.filter.Filter;
import org.apache.hadoop.hbase.filter.InclusiveStopFilter;
import org.apache.hadoop.hbase.filter.PrefixFilter;
import org.apache.hadoop.hbase.filter.RowFilter;
import org.apache.hadoop.hbase.filter.WhileMatchFilter;
import org.apache.hadoop.hbase.testclassification.MediumTests;
import org.apache.hadoop.hbase.testclassification.RegionServerTests;
Expand Down Expand Up @@ -95,6 +100,10 @@ public class TestScanner {

private static final long START_CODE = Long.MAX_VALUE;

private static final byte[] LAZY_SEEK_FAMILY = Bytes.toBytes("family");
private static final byte[] LAZY_SEEK_QUALIFIER = Bytes.toBytes("qualifier");
private static final byte[] LAZY_SEEK_ROW = Bytes.toBytes("row");

private HRegion region;

private byte[] firstRowBytes, secondRowBytes, thirdRowBytes;
Expand All @@ -113,6 +122,146 @@ public TestScanner() {
col1 = Bytes.toBytes("column1");
}

private static final class RecordingStoreScanner extends StoreScanner {
private boolean initialSeekWasLazy;

RecordingStoreScanner(HStore store, Scan scan, NavigableSet<byte[]> columns)
throws IOException {
super(store, store.getScanInfo(), scan, columns, Long.MAX_VALUE);
}

@Override
protected void seekScanners(List<? extends KeyValueScanner> scanners, ExtendedCell seekKey,
boolean isLazy, boolean isParallelSeek) throws IOException {
initialSeekWasLazy = isLazy;
super.seekScanners(scanners, seekKey, isLazy, isParallelSeek);
}
}

private static final class TrackingRowComparator extends ByteArrayComparable {
private final List<byte[]> comparedRows = new ArrayList<>();

TrackingRowComparator(byte[] value) {
super(value);
}

@Override
public int compareTo(byte[] value, int offset, int length) {
comparedRows.add(Bytes.copy(value, offset, length));
return Bytes.compareTo(getValue(), 0, getValue().length, value, offset, length);
}

@Override
public byte[] toByteArray() {
return getValue();
}
}

@Test
public void testFilterComparatorOnlySeesActualRows() throws Exception {
byte[] family = Bytes.toBytes("family");
byte[] qualifier = Bytes.toBytes("qualifier");
byte[] regionStartKey = new byte[] { 1 };
byte[] row = new byte[] { 1, 0, 1 };
TableDescriptor tableDescriptor = TableDescriptorBuilder
.newBuilder(TableName.valueOf("testFilterComparatorOnlySeesActualRows"))
.setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(family)
.setBloomFilterType(BloomType.ROWCOL).build())
.build();
TrackingRowComparator comparator = new TrackingRowComparator(row);

StoreScanner.enableLazySeekGlobally(true);
try {
this.region = TEST_UTIL.createLocalHRegion(tableDescriptor, regionStartKey, null);
Put put = new Put(row);
put.addColumn(family, qualifier, Bytes.toBytes("value"));
region.put(put);
region.flush(true);

Scan scan = new Scan().withStartRow(regionStartKey);
scan.addColumn(family, qualifier);
scan.setFilter(new RowFilter(CompareOperator.EQUAL, comparator));
List<Cell> results = new ArrayList<>();
try (InternalScanner scanner = region.getScanner(scan)) {
assertFalse(scanner.next(results));
}

assertEquals(1, results.size());
assertTrue(CellUtil.matchingRows(results.get(0), row));
assertEquals(1, comparator.comparedRows.size());
assertTrue(Bytes.equals(row, comparator.comparedRows.get(0)));
} finally {
StoreScanner.enableLazySeekGlobally(StoreScanner.LAZY_SEEK_ENABLED_BY_DEFAULT);
HBaseTestingUtil.closeRegionAndWAL(this.region);
}
}

@Test
public void testInitialLazySeekForUnfilteredExplicitColumnScan() throws Exception {
Scan scan = new Scan().withStartRow(LAZY_SEEK_ROW);
scan.addColumn(LAZY_SEEK_FAMILY, LAZY_SEEK_QUALIFIER);
assertInitialLazySeek(scan, true, true);
}

@Test
public void testInitialLazySeekForFilteredGet() throws Exception {
Get get = new Get(LAZY_SEEK_ROW);
get.addColumn(LAZY_SEEK_FAMILY, LAZY_SEEK_QUALIFIER);
get.setFilter(new PrefixFilter(LAZY_SEEK_ROW));
assertInitialLazySeek(new Scan(get), true, true);
}

@Test
public void testInitialLazySeekForFilteredNonGetScan() throws Exception {
Scan scan = new Scan().withStartRow(LAZY_SEEK_ROW);
scan.addColumn(LAZY_SEEK_FAMILY, LAZY_SEEK_QUALIFIER);
scan.setFilter(new PrefixFilter(LAZY_SEEK_ROW));
assertInitialLazySeek(scan, true, false);
}

@Test
public void testInitialLazySeekForAllColumnScan() throws Exception {
assertInitialLazySeek(new Scan().withStartRow(LAZY_SEEK_ROW), true, false);
}

@Test
public void testInitialLazySeekWhenDisabledGlobally() throws Exception {
Scan scan = new Scan().withStartRow(LAZY_SEEK_ROW);
scan.addColumn(LAZY_SEEK_FAMILY, LAZY_SEEK_QUALIFIER);
assertInitialLazySeek(scan, false, false);
}

private void assertInitialLazySeek(Scan scan, boolean lazySeekEnabled, boolean expected)
throws IOException {
StoreScanner.enableLazySeekGlobally(lazySeekEnabled);
try {
HStore store = createLazySeekTestStore();
try (
RecordingStoreScanner scanner =
new RecordingStoreScanner(store, scan, scan.getFamilyMap().get(LAZY_SEEK_FAMILY))) {
assertEquals(expected, scanner.initialSeekWasLazy);
}
} finally {
StoreScanner.enableLazySeekGlobally(StoreScanner.LAZY_SEEK_ENABLED_BY_DEFAULT);
if (this.region != null) {
HBaseTestingUtil.closeRegionAndWAL(this.region);
this.region = null;
}
}
}

private HStore createLazySeekTestStore() throws IOException {
TableDescriptor tableDescriptor = TableDescriptorBuilder
.newBuilder(TableName.valueOf("testInitialLazySeek"))
.setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(LAZY_SEEK_FAMILY).build()).build();
this.region = TEST_UTIL.createLocalHRegion(tableDescriptor, null, null);
Put put = new Put(LAZY_SEEK_ROW);
put.addColumn(LAZY_SEEK_FAMILY, LAZY_SEEK_QUALIFIER, Bytes.toBytes("value"));
region.put(put);
region.flush(true);
return region.getStore(LAZY_SEEK_FAMILY);
}

/**
* Test basic stop row filter works.
*/
Expand Down