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.Assert.assertEquals; 021import static org.junit.Assert.assertFalse; 022import static org.junit.Assert.assertNotNull; 023import static org.junit.Assert.assertNull; 024import static org.junit.Assert.assertTrue; 025 026import org.apache.hadoop.hbase.Cell; 027import org.apache.hadoop.hbase.HBaseClassTestRule; 028import org.apache.hadoop.hbase.KeyValue; 029import org.apache.hadoop.hbase.KeyValueUtil; 030import org.apache.hadoop.hbase.testclassification.FilterTests; 031import org.apache.hadoop.hbase.testclassification.SmallTests; 032import org.apache.hadoop.hbase.util.Bytes; 033import org.junit.Before; 034import org.junit.ClassRule; 035import org.junit.Test; 036import org.junit.experimental.categories.Category; 037 038@Category({ FilterTests.class, SmallTests.class }) 039public class TestPrefixFilter { 040 041 @ClassRule 042 public static final HBaseClassTestRule CLASS_RULE = 043 HBaseClassTestRule.forClass(TestPrefixFilter.class); 044 045 Filter mainFilter; 046 static final char FIRST_CHAR = 'a'; 047 static final char LAST_CHAR = 'e'; 048 static final String HOST_PREFIX = "org.apache.site-"; 049 050 @Before 051 public void setUp() throws Exception { 052 this.mainFilter = new PrefixFilter(Bytes.toBytes(HOST_PREFIX)); 053 } 054 055 @Test 056 public void testPrefixOnRow() throws Exception { 057 prefixRowTests(mainFilter); 058 } 059 060 @Test 061 public void testPrefixOnRowInsideWhileMatchRow() throws Exception { 062 prefixRowTests(new WhileMatchFilter(this.mainFilter), true); 063 } 064 065 @Test 066 public void testSerialization() throws Exception { 067 // Decompose mainFilter to bytes. 068 byte[] buffer = mainFilter.toByteArray(); 069 070 // Recompose filter. 071 Filter newFilter = PrefixFilter.parseFrom(buffer); 072 073 // Ensure the serialization preserved the filter by running all test. 074 prefixRowTests(newFilter); 075 } 076 077 private void prefixRowTests(Filter filter) throws Exception { 078 prefixRowTests(filter, false); 079 } 080 081 private void prefixRowTests(Filter filter, boolean lastFilterAllRemaining) throws Exception { 082 for (char c = FIRST_CHAR; c <= LAST_CHAR; c++) { 083 byte[] t = createRow(c); 084 assertFalse("Failed with character " + c, 085 filter.filterRowKey(KeyValueUtil.createFirstOnRow(t))); 086 assertFalse(filter.filterAllRemaining()); 087 } 088 String yahooSite = "com.yahoo.www"; 089 byte[] yahooSiteBytes = Bytes.toBytes(yahooSite); 090 KeyValue yahooSiteCell = KeyValueUtil.createFirstOnRow(yahooSiteBytes); 091 assertFalse("Failed with character " + yahooSite, filter.filterRowKey(yahooSiteCell)); 092 assertEquals(Filter.ReturnCode.SEEK_NEXT_USING_HINT, filter.filterCell(yahooSiteCell)); 093 assertEquals(lastFilterAllRemaining, filter.filterAllRemaining()); 094 } 095 096 private byte[] createRow(final char c) { 097 return Bytes.toBytes(HOST_PREFIX + Character.toString(c)); 098 } 099 100 @Test 101 public void shouldProvideHintWhenKeyBefore() { 102 byte[] prefix = Bytes.toBytes("gg"); 103 PrefixFilter filter = new PrefixFilter(prefix); 104 105 KeyValue cell = KeyValueUtil.createFirstOnRow(Bytes.toBytes("aa")); 106 107 // Should include this row so that filterCell() will be invoked. 108 assertFalse(filter.filterRowKey(cell)); 109 assertEquals(Filter.ReturnCode.SEEK_NEXT_USING_HINT, filter.filterCell(cell)); 110 Cell actualCellHint = filter.getNextCellHint(cell); 111 assertNotNull(actualCellHint); 112 Cell expectedCellHint = KeyValueUtil.createFirstOnRow(prefix); 113 assertEquals(expectedCellHint, actualCellHint); 114 assertFalse(filter.filterAllRemaining()); 115 assertTrue(filter.filterRow()); 116 } 117 118 @Test 119 public void shouldProvideHintWhenKeyBeforeAndShorter() { 120 byte[] prefix = Bytes.toBytes("gggg"); 121 PrefixFilter filter = new PrefixFilter(prefix); 122 123 KeyValue cell = KeyValueUtil.createFirstOnRow(Bytes.toBytes("aa")); 124 125 // Should include this row so that filterCell() will be invoked. 126 assertFalse(filter.filterRowKey(cell)); 127 assertEquals(Filter.ReturnCode.SEEK_NEXT_USING_HINT, filter.filterCell(cell)); 128 Cell actualCellHint = filter.getNextCellHint(cell); 129 assertNotNull(actualCellHint); 130 Cell expectedCellHint = KeyValueUtil.createFirstOnRow(prefix); 131 assertEquals(expectedCellHint, actualCellHint); 132 assertFalse(filter.filterAllRemaining()); 133 assertTrue(filter.filterRow()); 134 } 135 136 @Test 137 public void shouldIncludeWhenKeyMatches() { 138 PrefixFilter filter = new PrefixFilter(Bytes.toBytes("gg")); 139 140 KeyValue matchingCell = KeyValueUtil.createFirstOnRow(Bytes.toBytes("gg")); 141 142 assertFalse(filter.filterRowKey(matchingCell)); 143 assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(matchingCell)); 144 assertFalse(filter.filterAllRemaining()); 145 assertFalse(filter.filterRow()); 146 } 147 148 @Test 149 public void shouldReturnNextRowWhenKeyAfter() { 150 PrefixFilter filter = new PrefixFilter(Bytes.toBytes("gg")); 151 152 KeyValue afterCell = KeyValueUtil.createFirstOnRow(Bytes.toBytes("pp")); 153 154 assertTrue(filter.filterRowKey(afterCell)); 155 assertEquals(Filter.ReturnCode.NEXT_ROW, filter.filterCell(afterCell)); 156 assertTrue(filter.filterAllRemaining()); 157 assertTrue(filter.filterRow()); 158 } 159 160 @Test 161 public void shouldProvideHintWhenKeyBeforeReversed() { 162 PrefixFilter filter = new PrefixFilter(Bytes.toBytes("aa")); 163 filter.setReversed(true); 164 165 KeyValue cell = KeyValueUtil.createFirstOnRow(Bytes.toBytes("x")); 166 167 // Should include this row so that filterCell() will be invoked. 168 assertFalse(filter.filterRowKey(cell)); 169 assertEquals(Filter.ReturnCode.SEEK_NEXT_USING_HINT, filter.filterCell(cell)); 170 Cell actualCellHint = filter.getNextCellHint(cell); 171 assertNotNull(actualCellHint); 172 Cell expectedCellHint = KeyValueUtil.createFirstOnRow(Bytes.toBytes("ab")); 173 assertEquals(expectedCellHint, actualCellHint); 174 assertFalse(filter.filterAllRemaining()); 175 assertTrue(filter.filterRow()); 176 } 177 178 @Test 179 public void hintShouldIncreaseLastNonMaxByteWhenReversed() { 180 PrefixFilter filter = new PrefixFilter(new byte[] { 'a', 'a', Byte.MAX_VALUE }); 181 filter.setReversed(true); 182 183 KeyValue cell = KeyValueUtil.createFirstOnRow(Bytes.toBytes("x")); 184 185 // Should include this row so that filterCell() will be invoked. 186 assertFalse(filter.filterRowKey(cell)); 187 assertEquals(Filter.ReturnCode.SEEK_NEXT_USING_HINT, filter.filterCell(cell)); 188 Cell actualCellHint = filter.getNextCellHint(cell); 189 assertNotNull(actualCellHint); 190 Cell expectedCellHint = KeyValueUtil.createFirstOnRow(new byte[] { 'a', 'b', Byte.MAX_VALUE }); 191 assertEquals(expectedCellHint, actualCellHint); 192 assertFalse(filter.filterAllRemaining()); 193 assertTrue(filter.filterRow()); 194 } 195 196 @Test 197 public void shouldIncludeWhenKeyMatchesReversed() { 198 PrefixFilter filter = new PrefixFilter(Bytes.toBytes("aa")); 199 filter.setReversed(true); 200 201 KeyValue matchingCell = KeyValueUtil.createFirstOnRow(Bytes.toBytes("aa")); 202 203 assertFalse(filter.filterRowKey(matchingCell)); 204 assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(matchingCell)); 205 assertFalse(filter.filterAllRemaining()); 206 assertFalse(filter.filterRow()); 207 } 208 209 @Test 210 public void shouldReturnNextRowWhenKeyAfterReversed() { 211 PrefixFilter filter = new PrefixFilter(Bytes.toBytes("dd")); 212 filter.setReversed(true); 213 214 KeyValue cell = KeyValueUtil.createFirstOnRow(Bytes.toBytes("aa")); 215 216 assertTrue(filter.filterRowKey(cell)); 217 assertEquals(Filter.ReturnCode.NEXT_ROW, filter.filterCell(cell)); 218 assertTrue(filter.filterAllRemaining()); 219 assertTrue(filter.filterRow()); 220 } 221 222 @Test 223 public void hintShouldNotIncreaseMaxBytesWhenReversed() { 224 PrefixFilter filter = 225 new PrefixFilter(new byte[] { Byte.MAX_VALUE, Byte.MAX_VALUE, Byte.MAX_VALUE }); 226 filter.setReversed(true); 227 228 KeyValue cell = KeyValueUtil.createFirstOnRow(Bytes.toBytes("x")); 229 230 assertTrue(filter.filterRowKey(cell)); 231 assertEquals(Filter.ReturnCode.NEXT_ROW, filter.filterCell(cell)); 232 Cell actualCellHint = filter.getNextCellHint(cell); 233 assertNotNull(actualCellHint); 234 Cell expectedCellHint = 235 KeyValueUtil.createFirstOnRow(new byte[] { Byte.MAX_VALUE, Byte.MAX_VALUE, Byte.MAX_VALUE }); 236 assertEquals(expectedCellHint, actualCellHint); 237 assertTrue(filter.filterAllRemaining()); 238 assertTrue(filter.filterRow()); 239 } 240 241 @Test 242 public void shouldNotThrowWhenCreatedWithNullPrefix() { 243 PrefixFilter filter = new PrefixFilter(null); 244 KeyValue cell = KeyValueUtil.createFirstOnRow(Bytes.toBytes("doesNotMatter")); 245 246 assertNull(filter.getNextCellHint(cell)); 247 filter.setReversed(true); 248 assertNull(filter.getNextCellHint(cell)); 249 } 250 251 @Test 252 public void shouldNotThrowWhenCreatedWithEmptyByteArrayPrefix() { 253 byte[] emptyPrefix = {}; 254 KeyValue emptyPrefixCell = KeyValueUtil.createFirstOnRow(emptyPrefix); 255 KeyValue cell = KeyValueUtil.createFirstOnRow(Bytes.toBytes("doesNotMatter")); 256 257 PrefixFilter filter = new PrefixFilter(emptyPrefix); 258 259 Cell forwardNextCellHint = filter.getNextCellHint(cell); 260 assertNotNull(forwardNextCellHint); 261 assertEquals(emptyPrefixCell, forwardNextCellHint); 262 263 filter.setReversed(true); 264 Cell reverseNextCellHint = filter.getNextCellHint(cell); 265 assertNotNull(reverseNextCellHint); 266 assertEquals(emptyPrefixCell, reverseNextCellHint); 267 } 268}