001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.filter; 019 020import static org.junit.jupiter.api.Assertions.assertEquals; 021 022import java.io.IOException; 023import java.util.ArrayList; 024import java.util.List; 025import org.apache.hadoop.hbase.Cell; 026import org.apache.hadoop.hbase.HBaseTestingUtil; 027import org.apache.hadoop.hbase.TableName; 028import org.apache.hadoop.hbase.client.Durability; 029import org.apache.hadoop.hbase.client.Put; 030import org.apache.hadoop.hbase.client.Result; 031import org.apache.hadoop.hbase.client.ResultScanner; 032import org.apache.hadoop.hbase.client.Scan; 033import org.apache.hadoop.hbase.client.Table; 034import org.apache.hadoop.hbase.filter.MultiRowRangeFilter.RowRange; 035import org.apache.hadoop.hbase.io.hfile.HFile; 036import org.apache.hadoop.hbase.testclassification.MediumTests; 037import org.apache.hadoop.hbase.util.Bytes; 038import org.junit.jupiter.api.AfterAll; 039import org.junit.jupiter.api.BeforeAll; 040import org.junit.jupiter.api.Tag; 041import org.junit.jupiter.api.Test; 042import org.junit.jupiter.api.TestInfo; 043import org.slf4j.Logger; 044import org.slf4j.LoggerFactory; 045 046/* 047 * This test is for the optimization added in HBASE-15243. 048 * FilterList with two MultiRowRangeFilter's is constructed using Operator.MUST_PASS_ONE. 049 */ 050@Tag(MediumTests.TAG) 051public class TestFilterListOrOperatorWithBlkCnt { 052 053 private final static HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil(); 054 private static final Logger LOG = 055 LoggerFactory.getLogger(TestFilterListOrOperatorWithBlkCnt.class); 056 private byte[] family = Bytes.toBytes("family"); 057 private byte[] qf = Bytes.toBytes("qf"); 058 private byte[] value = Bytes.toBytes("val"); 059 private TableName tableName; 060 private int numRows = 10000; 061 062 @BeforeAll 063 public static void setUpBeforeClass() throws Exception { 064 long blkSize = 4096; 065 /* 066 * dfs block size is adjusted so that the specified number of rows would result in multiple 067 * blocks (8 for this test). Later in the test, assertion is made on the number of blocks read. 068 */ 069 TEST_UTIL.getConfiguration().setLong("dfs.blocksize", blkSize); 070 TEST_UTIL.getConfiguration().setLong("dfs.bytes-per-checksum", blkSize); 071 TEST_UTIL.startMiniCluster(); 072 } 073 074 @AfterAll 075 public static void tearDownAfterClass() throws Exception { 076 TEST_UTIL.shutdownMiniCluster(); 077 } 078 079 private static long getBlkAccessCount() { 080 return HFile.DATABLOCK_READ_COUNT.sum(); 081 } 082 083 @Test 084 public void testMultiRowRangeWithFilterListOrOperatorWithBlkCnt(TestInfo testInfo) 085 throws IOException { 086 tableName = TableName.valueOf(testInfo.getTestMethod().get().getName()); 087 Table ht = TEST_UTIL.createTable(tableName, family, Integer.MAX_VALUE); 088 generateRows(numRows, ht, family, qf, value); 089 090 Scan scan = new Scan(); 091 scan.readAllVersions(); 092 long blocksStart = getBlkAccessCount(); 093 094 List<RowRange> ranges1 = new ArrayList<>(); 095 ranges1.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(15), false)); 096 ranges1.add(new RowRange(Bytes.toBytes(9980), true, Bytes.toBytes(9985), false)); 097 098 MultiRowRangeFilter filter1 = new MultiRowRangeFilter(ranges1); 099 100 List<RowRange> ranges2 = new ArrayList<>(); 101 ranges2.add(new RowRange(Bytes.toBytes(15), true, Bytes.toBytes(20), false)); 102 ranges2.add(new RowRange(Bytes.toBytes(9985), true, Bytes.toBytes(9990), false)); 103 104 MultiRowRangeFilter filter2 = new MultiRowRangeFilter(ranges2); 105 106 FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ONE); 107 filterList.addFilter(filter1); 108 filterList.addFilter(filter2); 109 scan.setFilter(filterList); 110 int resultsSize = getResultsSize(ht, scan); 111 LOG.info("found " + resultsSize + " results"); 112 List<Cell> results1 = getScanResult(Bytes.toBytes(10), Bytes.toBytes(20), ht); 113 List<Cell> results2 = getScanResult(Bytes.toBytes(9980), Bytes.toBytes(9990), ht); 114 115 assertEquals(results1.size() + results2.size(), resultsSize); 116 long blocksEnd = getBlkAccessCount(); 117 long diff = blocksEnd - blocksStart; 118 LOG.info("Diff in number of blocks " + diff); 119 /* 120 * Verify that we don't read all the blocks (8 in total). 121 */ 122 assertEquals(4, diff); 123 124 ht.close(); 125 } 126 127 private void generateRows(int numberOfRows, Table ht, byte[] family, byte[] qf, byte[] value) 128 throws IOException { 129 for (int i = 0; i < numberOfRows; i++) { 130 byte[] row = Bytes.toBytes(i); 131 Put p = new Put(row); 132 p.addColumn(family, qf, value); 133 p.setDurability(Durability.SKIP_WAL); 134 ht.put(p); 135 } 136 TEST_UTIL.flush(); 137 } 138 139 private List<Cell> getScanResult(byte[] startRow, byte[] stopRow, Table ht) throws IOException { 140 Scan scan = new Scan(); 141 scan.readAllVersions(); 142 if (!Bytes.toString(startRow).isEmpty()) { 143 scan.withStartRow(startRow); 144 } 145 if (!Bytes.toString(stopRow).isEmpty()) { 146 scan.withStopRow(stopRow); 147 } 148 ResultScanner scanner = ht.getScanner(scan); 149 List<Cell> kvList = new ArrayList<>(); 150 Result r; 151 while ((r = scanner.next()) != null) { 152 for (Cell kv : r.listCells()) { 153 kvList.add(kv); 154 } 155 } 156 return kvList; 157 } 158 159 private int getResultsSize(Table ht, Scan scan) throws IOException { 160 ResultScanner scanner = ht.getScanner(scan); 161 List<Cell> results = new ArrayList<>(); 162 Result r; 163 while ((r = scanner.next()) != null) { 164 for (Cell kv : r.listCells()) { 165 results.add(kv); 166 } 167 } 168 return results.size(); 169 } 170}