001/** 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 */ 019 020package org.apache.hadoop.hbase.filter; 021 022import java.io.IOException; 023import java.util.ArrayList; 024import java.util.Arrays; 025import java.util.List; 026 027import org.apache.hadoop.hbase.Cell; 028import org.apache.hadoop.hbase.CellComparator; 029import org.apache.yetus.audience.InterfaceAudience; 030 031/** 032 * Base class for FilterList. Currently, we have two sub-classes to extend this class: 033 * {@link FilterListWithOR}, {@link FilterListWithAND}. 034 */ 035@InterfaceAudience.Private 036public abstract class FilterListBase extends FilterBase { 037 private static final int MAX_LOG_FILTERS = 5; 038 protected final ArrayList<Filter> filters; 039 /** 040 * For each sub-filter in filter list, we save a boolean flag to indicate that whether the return 041 * code of filterCell(c) for sub-filter is INCLUDE* (INCLUDE, INCLUDE_AND_NEXT_COL, 042 * INCLUDE_AND_SEEK_NEXT_ROW) case. if true, we need to transform cell for the sub-filter. 043 */ 044 protected ArrayList<Boolean> subFiltersIncludedCell; 045 046 public FilterListBase(List<Filter> filters) { 047 reversed = checkAndGetReversed(filters, reversed); 048 this.filters = new ArrayList<>(filters); 049 } 050 051 protected static boolean isInReturnCodes(ReturnCode testRC, ReturnCode... returnCodes) { 052 return Arrays.stream(returnCodes).anyMatch(testRC::equals); 053 } 054 055 protected static boolean checkAndGetReversed(List<Filter> rowFilters, boolean defaultValue) { 056 if (rowFilters.isEmpty()) { 057 return defaultValue; 058 } 059 boolean retValue = rowFilters.get(0).isReversed(); 060 boolean allEqual = rowFilters.stream().allMatch(f -> f.isReversed() == retValue); 061 if (!allEqual) { 062 throw new IllegalArgumentException("Filters in the list must have the same reversed flag"); 063 } 064 return retValue; 065 } 066 067 public abstract void addFilterLists(List<Filter> filters); 068 069 public int size() { 070 return this.filters.size(); 071 } 072 073 public boolean isEmpty() { 074 return this.filters.isEmpty(); 075 } 076 077 public ArrayList<Filter> getFilters() { 078 return this.filters; 079 } 080 081 protected int compareCell(Cell a, Cell b) { 082 int cmp = CellComparator.getInstance().compare(a, b); 083 return reversed ? -1 * cmp : cmp; 084 } 085 086 /** 087 * For FilterList, we can consider a filter list as a node in a tree. sub-filters of the filter 088 * list are children of the relative node. The logic of transforming cell of a filter list, well, 089 * we can consider it as the process of post-order tree traverse. For a node , before we traverse 090 * the current child, we should set the traverse result (transformed cell) of previous node(s) as 091 * the initial value. (HBASE-18879). 092 * @param c The cell in question. 093 * @return the transformed cell. 094 * @throws IOException 095 */ 096 @Override 097 public Cell transformCell(Cell c) throws IOException { 098 if (isEmpty()) { 099 return super.transformCell(c); 100 } 101 Cell transformed = c; 102 for (int i = 0, n = filters.size(); i < n; i++) { 103 if (subFiltersIncludedCell.get(i)) { 104 transformed = filters.get(i).transformCell(transformed); 105 } 106 } 107 return transformed; 108 } 109 110 @Override 111 public ReturnCode filterKeyValue(final Cell c) throws IOException { 112 return filterCell(c); 113 } 114 115 /** 116 * Filters that never filter by modifying the returned List of Cells can inherit this 117 * implementation that does nothing. {@inheritDoc} 118 */ 119 @Override 120 public void filterRowCells(List<Cell> cells) throws IOException { 121 for (int i = 0, n = filters.size(); i < n; i++) { 122 filters.get(i).filterRowCells(cells); 123 } 124 } 125 126 @Override 127 public boolean hasFilterRow() { 128 for (int i = 0, n = filters.size(); i < n; i++) { 129 if (filters.get(i).hasFilterRow()) { 130 return true; 131 } 132 } 133 return false; 134 } 135 136 @Override 137 public boolean isFamilyEssential(byte[] name) throws IOException { 138 if (this.filters.isEmpty()) { 139 return super.isFamilyEssential(name); 140 } 141 for (int i = 0, n = filters.size(); i < n; i++) { 142 if (filters.get(i).isFamilyEssential(name)) { 143 return true; 144 } 145 } 146 return false; 147 } 148 149 @Override 150 public void setReversed(boolean reversed) { 151 for (int i = 0, n = filters.size(); i < n; i++) { 152 filters.get(i).setReversed(reversed); 153 } 154 this.reversed = reversed; 155 } 156 157 @Override 158 public String toString() { 159 int endIndex = this.size() < MAX_LOG_FILTERS ? this.size() : MAX_LOG_FILTERS; 160 return formatLogFilters(filters.subList(0, endIndex)); 161 } 162 163 protected abstract String formatLogFilters(List<Filter> logFilters); 164}