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 java.io.IOException; 021import java.util.List; 022import org.apache.hadoop.hbase.Cell; 023import org.apache.hadoop.hbase.exceptions.DeserializationException; 024import org.apache.yetus.audience.InterfaceAudience; 025 026/** 027 * Interface for row and column filters directly applied within the regionserver. A filter can 028 * expect the following call sequence: 029 * <ul> 030 * <li>{@link #reset()} : reset the filter state before filtering a new row.</li> 031 * <li>{@link #filterAllRemaining()}: true means row scan is over; false means keep going.</li> 032 * <li>{@link #filterRowKey(Cell)}: true means drop this row; false means include.</li> 033 * <li>{@link #getHintForRejectedRow(Cell)}: if {@code filterRowKey} returned true, optionally 034 * provide a seek hint to skip past the rejected row efficiently.</li> 035 * <li>{@link #getSkipHint(Cell)}: when a cell is structurally skipped (time-range, column, or 036 * version gate) before {@code filterCell} is reached, optionally provide a seek hint.</li> 037 * <li>{@link #filterCell(Cell)}: decides whether to include or exclude this Cell. See 038 * {@link ReturnCode}.</li> 039 * <li>{@link #transformCell(Cell)}: if the Cell is included, let the filter transform the Cell. 040 * </li> 041 * <li>{@link #filterRowCells(List)}: allows direct modification of the final list to be submitted 042 * <li>{@link #filterRow()}: last chance to drop entire row based on the sequence of filter calls. 043 * Eg: filter a row if it doesn't contain a specified column.</li> 044 * </ul> 045 * Filter instances are created one per region/scan. This abstract class replaces the old 046 * RowFilterInterface. When implementing your own filters, consider inheriting {@link FilterBase} to 047 * help you reduce boilerplate. 048 * @see FilterBase 049 */ 050@InterfaceAudience.Public 051public abstract class Filter { 052 protected transient boolean reversed; 053 054 /** 055 * Reset the state of the filter between rows. Concrete implementers can signal a failure 056 * condition in their code by throwing an {@link IOException}. 057 * @throws IOException in case an I/O or an filter specific failure needs to be signaled. 058 */ 059 abstract public void reset() throws IOException; 060 061 /** 062 * Filters a row based on the row key. If this returns true, the entire row will be excluded. If 063 * false, each KeyValue in the row will be passed to {@link #filterCell(Cell)} below. If 064 * {@link #filterAllRemaining()} returns true, then {@link #filterRowKey(Cell)} should also return 065 * true. Concrete implementers can signal a failure condition in their code by throwing an 066 * {@link IOException}. 067 * @param firstRowCell The first cell coming in the new row 068 * @return true, remove entire row, false, include the row (maybe). 069 * @throws IOException in case an I/O or an filter specific failure needs to be signaled. 070 */ 071 abstract public boolean filterRowKey(Cell firstRowCell) throws IOException; 072 073 /** 074 * If this returns true, the scan will terminate. Concrete implementers can signal a failure 075 * condition in their code by throwing an {@link IOException}. 076 * @return true to end scan, false to continue. 077 * @throws IOException in case an I/O or an filter specific failure needs to be signaled. 078 */ 079 abstract public boolean filterAllRemaining() throws IOException; 080 081 /** 082 * A way to filter based on the column family, column qualifier and/or the column value. Return 083 * code is described below. This allows filters to filter only certain number of columns, then 084 * terminate without matching ever column. If filterRowKey returns true, filterCell needs to be 085 * consistent with it. filterCell can assume that filterRowKey has already been called for the 086 * row. If your filter returns <code>ReturnCode.NEXT_ROW</code>, it should return 087 * <code>ReturnCode.NEXT_ROW</code> until {@link #reset()} is called just in case the caller calls 088 * for the next row. Concrete implementers can signal a failure condition in their code by 089 * throwing an {@link IOException}. 090 * @param c the Cell in question 091 * @return code as described below 092 * @throws IOException in case an I/O or an filter specific failure needs to be signaled. 093 * @see Filter.ReturnCode 094 */ 095 public ReturnCode filterCell(final Cell c) throws IOException { 096 return ReturnCode.INCLUDE; 097 } 098 099 /** 100 * Give the filter a chance to transform the passed Cell. If the Cell is changed a new Cell object 101 * must be returned. 102 * <p/> 103 * <strong>NOTICE:</strong> Filter will be evaluate at server side so the returned {@link Cell} 104 * must be an {@link org.apache.hadoop.hbase.ExtendedCell}, although it is marked as IA.Private. 105 * @see org.apache.hadoop.hbase.KeyValue#shallowCopy() The transformed KeyValue is what is 106 * eventually returned to the client. Most filters will return the passed KeyValue unchanged. 107 * @see org.apache.hadoop.hbase.filter.KeyOnlyFilter#transformCell(Cell) for an example of a 108 * transformation. Concrete implementers can signal a failure condition in their code by 109 * throwing an {@link IOException}. 110 * @param v the Cell in question 111 * @return the changed Cell 112 * @throws IOException in case an I/O or an filter specific failure needs to be signaled. 113 */ 114 abstract public Cell transformCell(final Cell v) throws IOException; 115 116 /** 117 * Return codes for filterValue(). 118 */ 119 @InterfaceAudience.Public 120 public enum ReturnCode { 121 /** 122 * Include the Cell 123 */ 124 INCLUDE, 125 /** 126 * Include the Cell and seek to the next column skipping older versions. 127 */ 128 INCLUDE_AND_NEXT_COL, 129 /** 130 * Skip this Cell 131 */ 132 SKIP, 133 /** 134 * Skip this column. Go to the next column in this row. 135 */ 136 NEXT_COL, 137 /** 138 * Seek to next row in current family. It may still pass a cell whose family is different but 139 * row is the same as previous cell to {@link #filterCell(Cell)} , even if we get a NEXT_ROW 140 * returned for previous cell. For more details see HBASE-18368. <br> 141 * Once reset() method was invoked, then we switch to the next row for all family, and you can 142 * catch the event by invoking CellUtils.matchingRows(previousCell, currentCell). <br> 143 * Note that filterRow() will still be called. <br> 144 */ 145 NEXT_ROW, 146 /** 147 * Seek to next key which is given as hint by the filter. 148 */ 149 SEEK_NEXT_USING_HINT, 150 /** 151 * Include KeyValue and done with row, seek to next. See NEXT_ROW. 152 */ 153 INCLUDE_AND_SEEK_NEXT_ROW, 154 } 155 156 /** 157 * Chance to alter the list of Cells to be submitted. Modifications to the list will carry on 158 * Concrete implementers can signal a failure condition in their code by throwing an 159 * {@link IOException}. 160 * @param kvs the list of Cells to be filtered 161 * @throws IOException in case an I/O or an filter specific failure needs to be signaled. 162 */ 163 abstract public void filterRowCells(List<Cell> kvs) throws IOException; 164 165 /** 166 * Primarily used to check for conflicts with scans(such as scans that do not read a full row at a 167 * time). 168 * @return True if this filter actively uses filterRowCells(List) or filterRow(). 169 */ 170 abstract public boolean hasFilterRow(); 171 172 /** 173 * Last chance to veto row based on previous {@link #filterCell(Cell)} calls. The filter needs to 174 * retain state then return a particular value for this call if they wish to exclude a row if a 175 * certain column is missing (for example). Concrete implementers can signal a failure condition 176 * in their code by throwing an {@link IOException}. 177 * @return true to exclude row, false to include row. 178 * @throws IOException in case an I/O or an filter specific failure needs to be signaled. 179 */ 180 abstract public boolean filterRow() throws IOException; 181 182 /** 183 * If the filter returns the match code SEEK_NEXT_USING_HINT, then it should also tell which is 184 * the next key it must seek to. After receiving the match code SEEK_NEXT_USING_HINT, the 185 * QueryMatcher would call this function to find out which key it must next seek to. Concrete 186 * implementers can signal a failure condition in their code by throwing an {@link IOException}. 187 * <strong>NOTICE:</strong> Filter will be evaluate at server side so the returned {@link Cell} 188 * must be an {@link org.apache.hadoop.hbase.ExtendedCell}, although it is marked as IA.Private. 189 * @return KeyValue which must be next seeked. return null if the filter is not sure which key to 190 * seek to next. 191 * @throws IOException in case an I/O or an filter specific failure needs to be signaled. 192 */ 193 abstract public Cell getNextCellHint(final Cell currentCell) throws IOException; 194 195 /** 196 * Provides a seek hint to bypass row-by-row scanning after {@link #filterRowKey(Cell)} rejects a 197 * row. When {@code filterRowKey} returns {@code true} the scan pipeline would normally iterate 198 * through every remaining cell in the rejected row one-by-one (via {@code nextRow()}) before 199 * moving on. If the filter can determine a better forward position — for example, the next range 200 * boundary in a {@code MultiRowRangeFilter} — it should return that target cell here, allowing 201 * the scanner to seek directly past the unwanted rows. 202 * <p> 203 * Contract: 204 * <ul> 205 * <li>Only called after {@link #filterRowKey(Cell)} has returned {@code true} for the same 206 * {@code firstRowCell}.</li> 207 * <li>Implementations may use state that was set during {@link #filterRowKey(Cell)} (e.g. an 208 * updated range pointer), but <strong>must not</strong> invoke {@link #filterCell(Cell)} logic — 209 * the caller guarantees that {@code filterCell} has not been called for this row.</li> 210 * <li>The returned {@link Cell}, if non-null, must be an 211 * {@link org.apache.hadoop.hbase.ExtendedCell} because filters are evaluated on the server 212 * side.</li> 213 * <li>Returning {@code null} (the default) falls through to the existing {@code nextRow()} 214 * behaviour, preserving full backward compatibility.</li> 215 * <li>For reversed scans ({@link org.apache.hadoop.hbase.client.Scan#isReversed()}), the hint 216 * must point to a <em>smaller</em> row key (earlier in reverse-scan direction). The scanner 217 * validates hint direction and falls back to {@code nextRow()} if the hint does not advance in 218 * the scan direction.</li> 219 * <li><strong>Composite filter support:</strong> {@code FilterList} (both {@code MUST_PASS_ALL} 220 * and {@code MUST_PASS_ONE}), {@code SkipFilter}, and {@code WhileMatchFilter} delegate this 221 * method to their sub-filters and merge the results. For AND ({@code MUST_PASS_ALL}), only 222 * sub-filters whose {@code filterRowKey} individually returned {@code true} are consulted, and 223 * the farthest (maximal-step) hint among them is returned. For OR ({@code MUST_PASS_ONE}), the 224 * nearest hint is returned only when every non-terminated sub-filter provides one — any null 225 * collapses the OR result to null.</li> 226 * </ul> 227 * @param firstRowCell the first cell encountered in the rejected row; contains the row key that 228 * was passed to {@code filterRowKey} 229 * @return a {@link Cell} representing the earliest position the scanner should seek to, or 230 * {@code null} if this filter cannot provide a better position than a sequential skip 231 * @throws IOException in case an I/O or filter-specific failure needs to be signaled 232 * @see #filterRowKey(Cell) 233 */ 234 public Cell getHintForRejectedRow(final Cell firstRowCell) throws IOException { 235 return null; 236 } 237 238 /** 239 * Provides a seek hint for cells that are structurally skipped by the scan pipeline 240 * <em>before</em> {@link #filterCell(Cell)} is ever reached. The pipeline short-circuits on 241 * several criteria — time-range mismatch, column-set exclusion, and version-limit exhaustion — 242 * and in each case the filter is bypassed entirely. When an implementation can compute a 243 * meaningful forward position purely from the cell's coordinates (without needing the 244 * {@code filterCell} call sequence), it should return that position here so the scanner can seek 245 * ahead instead of advancing one cell at a time. 246 * <p> 247 * Contract: 248 * <ul> 249 * <li>May be called for cells that have <strong>never</strong> been passed to 250 * {@link #filterCell(Cell)}.</li> 251 * <li>Implementations <strong>must not</strong> modify any filter state; this method is treated 252 * as logically stateless. Only filters whose hint computation is based solely on immutable 253 * configuration (e.g. a fixed column range or a fuzzy-row pattern) should override this.</li> 254 * <li>The returned {@link Cell}, if non-null, must be an 255 * {@link org.apache.hadoop.hbase.ExtendedCell} because filters are evaluated on the server 256 * side.</li> 257 * <li>Returning {@code null} (the default) falls through to the existing structural skip/seek 258 * behaviour, preserving full backward compatibility.</li> 259 * <li>For reversed scans, the returned cell must have a <em>smaller</em> row key (i.e., earlier 260 * in reverse-scan direction) than the {@code skippedCell}. Hints that do not advance in the scan 261 * direction are silently ignored.</li> 262 * <li><strong>Composite filter support:</strong> {@code FilterList} (both {@code MUST_PASS_ALL} 263 * and {@code MUST_PASS_ONE}), {@code SkipFilter}, and {@code WhileMatchFilter} delegate this 264 * method to their sub-filters and merge the results (maximal step for AND; for OR, the nearest 265 * hint is returned only when every non-terminated sub-filter provides one — any null collapses 266 * the OR result to null).</li> 267 * </ul> 268 * @param skippedCell the cell that was rejected by the time-range, column, or version gate before 269 * {@code filterCell} could be consulted 270 * @return a {@link Cell} representing the earliest position the scanner should seek to, or 271 * {@code null} if this filter cannot provide a better position than the structural hint 272 * @throws IOException in case an I/O or filter-specific failure needs to be signaled 273 * @see #filterCell(Cell) 274 * @see #getNextCellHint(Cell) 275 */ 276 public Cell getSkipHint(final Cell skippedCell) throws IOException { 277 return null; 278 } 279 280 /** 281 * Check that given column family is essential for filter to check row. Most filters always return 282 * true here. But some could have more sophisticated logic which could significantly reduce 283 * scanning process by not even touching columns until we are 100% sure that it's data is needed 284 * in result. Concrete implementers can signal a failure condition in their code by throwing an 285 * {@link IOException}. 286 * @throws IOException in case an I/O or an filter specific failure needs to be signaled. 287 */ 288 abstract public boolean isFamilyEssential(byte[] name) throws IOException; 289 290 /** 291 * TODO: JAVADOC Concrete implementers can signal a failure condition in their code by throwing an 292 * {@link IOException}. 293 * @return The filter serialized using pb 294 * @throws IOException in case an I/O or an filter specific failure needs to be signaled. 295 */ 296 abstract public byte[] toByteArray() throws IOException; 297 298 /** 299 * Concrete implementers can signal a failure condition in their code by throwing an 300 * {@link IOException}. 301 * @param pbBytes A pb serialized {@link Filter} instance 302 * @return An instance of {@link Filter} made from <code>bytes</code> 303 * @throws DeserializationException if an error occurred 304 * @see #toByteArray 305 */ 306 public static Filter parseFrom(final byte[] pbBytes) throws DeserializationException { 307 throw new DeserializationException( 308 "parseFrom called on base Filter, but should be called on derived type"); 309 } 310 311 /** 312 * Concrete implementers can signal a failure condition in their code by throwing an 313 * {@link IOException}. 314 * @return true if and only if the fields of the filter that are serialized are equal to the 315 * corresponding fields in other. Used for testing. 316 */ 317 abstract boolean areSerializedFieldsEqual(Filter other); 318 319 /** 320 * alter the reversed scan flag 321 * @param reversed flag 322 */ 323 public void setReversed(boolean reversed) { 324 this.reversed = reversed; 325 } 326 327 public boolean isReversed() { 328 return this.reversed; 329 } 330}