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.List; 025 026import org.apache.hadoop.hbase.Cell; 027import org.apache.hadoop.hbase.CellComparator; 028import org.apache.yetus.audience.InterfaceAudience; 029 030/** 031 * Base class for FilterList. Currently, we have two sub-classes to extend this class: 032 * {@link FilterListWithOR}, {@link FilterListWithAND}. 033 */ 034@InterfaceAudience.Private 035public abstract class FilterListBase extends FilterBase { 036 private static final int MAX_LOG_FILTERS = 5; 037 protected final ArrayList<Filter> filters; 038 /** 039 * For each sub-filter in filter list, we save a boolean flag to indicate that whether the return 040 * code of filterCell(c) for sub-filter is INCLUDE* (INCLUDE, INCLUDE_AND_NEXT_COL, 041 * INCLUDE_AND_SEEK_NEXT_ROW) case. if true, we need to transform cell for the sub-filter. 042 */ 043 protected ArrayList<Boolean> subFiltersIncludedCell; 044 045 public FilterListBase(List<Filter> filters) { 046 reversed = checkAndGetReversed(filters, reversed); 047 this.filters = new ArrayList<>(filters); 048 } 049 050 protected static boolean isInReturnCodes(ReturnCode testRC, ReturnCode... returnCodes) { 051 for (ReturnCode rc : returnCodes) { 052 if (testRC == rc) { 053 return true; 054 } 055 } 056 return false; 057 } 058 059 protected static boolean checkAndGetReversed(List<Filter> rowFilters, boolean defaultValue) { 060 if (rowFilters.isEmpty()) { 061 return defaultValue; 062 } 063 boolean retValue = rowFilters.get(0).isReversed(); 064 for (int i = 1, n = rowFilters.size(); i < n; i++) { 065 if (rowFilters.get(i).isReversed() != retValue) { 066 throw new IllegalArgumentException("Filters in the list must have the same reversed flag"); 067 } 068 } 069 return retValue; 070 } 071 072 public abstract void addFilterLists(List<Filter> filters); 073 074 public int size() { 075 return this.filters.size(); 076 } 077 078 public boolean isEmpty() { 079 return this.filters.isEmpty(); 080 } 081 082 public ArrayList<Filter> getFilters() { 083 return this.filters; 084 } 085 086 protected int compareCell(Cell a, Cell b) { 087 int cmp = CellComparator.getInstance().compare(a, b); 088 return reversed ? -1 * cmp : cmp; 089 } 090 091 /** 092 * For FilterList, we can consider a filter list as a node in a tree. sub-filters of the filter 093 * list are children of the relative node. The logic of transforming cell of a filter list, well, 094 * we can consider it as the process of post-order tree traverse. For a node , before we traverse 095 * the current child, we should set the traverse result (transformed cell) of previous node(s) as 096 * the initial value. (HBASE-18879). 097 * @param c The cell in question. 098 * @return the transformed cell. 099 * @throws IOException 100 */ 101 @Override 102 public Cell transformCell(Cell c) throws IOException { 103 if (isEmpty()) { 104 return super.transformCell(c); 105 } 106 Cell transformed = c; 107 for (int i = 0, n = filters.size(); i < n; i++) { 108 if (subFiltersIncludedCell.get(i)) { 109 transformed = filters.get(i).transformCell(transformed); 110 } 111 } 112 return transformed; 113 } 114 115 @Override 116 public ReturnCode filterKeyValue(final Cell c) throws IOException { 117 return filterCell(c); 118 } 119 120 /** 121 * Filters that never filter by modifying the returned List of Cells can inherit this 122 * implementation that does nothing. {@inheritDoc} 123 */ 124 @Override 125 public void filterRowCells(List<Cell> cells) throws IOException { 126 for (int i = 0, n = filters.size(); i < n; i++) { 127 filters.get(i).filterRowCells(cells); 128 } 129 } 130 131 @Override 132 public boolean hasFilterRow() { 133 for (int i = 0, n = filters.size(); i < n; i++) { 134 if (filters.get(i).hasFilterRow()) { 135 return true; 136 } 137 } 138 return false; 139 } 140 141 @Override 142 public boolean isFamilyEssential(byte[] name) throws IOException { 143 if (this.filters.isEmpty()) { 144 return super.isFamilyEssential(name); 145 } 146 for (int i = 0, n = filters.size(); i < n; i++) { 147 if (filters.get(i).isFamilyEssential(name)) { 148 return true; 149 } 150 } 151 return false; 152 } 153 154 @Override 155 public void setReversed(boolean reversed) { 156 for (int i = 0, n = filters.size(); i < n; i++) { 157 filters.get(i).setReversed(reversed); 158 } 159 this.reversed = reversed; 160 } 161 162 @Override 163 public String toString() { 164 int endIndex = this.size() < MAX_LOG_FILTERS ? this.size() : MAX_LOG_FILTERS; 165 return formatLogFilters(filters.subList(0, endIndex)); 166 } 167 168 protected abstract String formatLogFilters(List<Filter> logFilters); 169}