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 */ 019package org.apache.hadoop.hbase.filter; 020 021import java.io.IOException; 022import java.util.ArrayList; 023import java.util.Arrays; 024import java.util.Collections; 025import java.util.List; 026import java.util.Objects; 027 028import org.apache.hadoop.hbase.Cell; 029import org.apache.yetus.audience.InterfaceAudience; 030import org.apache.hadoop.hbase.exceptions.DeserializationException; 031 032import org.apache.hbase.thirdparty.com.google.protobuf.InvalidProtocolBufferException; 033import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 034import org.apache.hadoop.hbase.shaded.protobuf.generated.FilterProtos; 035 036/** 037 * Implementation of {@link Filter} that represents an ordered List of Filters which will be 038 * evaluated with a specified boolean operator {@link Operator#MUST_PASS_ALL} (<code>AND</code>) or 039 * {@link Operator#MUST_PASS_ONE} (<code>OR</code>). Since you can use Filter Lists as children of 040 * Filter Lists, you can create a hierarchy of filters to be evaluated. <br> 041 * {@link Operator#MUST_PASS_ALL} evaluates lazily: evaluation stops as soon as one filter does not 042 * include the Cell. <br> 043 * {@link Operator#MUST_PASS_ONE} evaluates non-lazily: all filters are always evaluated. <br> 044 * Defaults to {@link Operator#MUST_PASS_ALL}. 045 */ 046@InterfaceAudience.Public 047final public class FilterList extends FilterBase { 048 049 /** set operator */ 050 @InterfaceAudience.Public 051 public enum Operator { 052 /** !AND */ 053 MUST_PASS_ALL, 054 /** !OR */ 055 MUST_PASS_ONE 056 } 057 058 private Operator operator; 059 private FilterListBase filterListBase; 060 061 /** 062 * Constructor that takes a set of {@link Filter}s and an operator. 063 * @param operator Operator to process filter set with. 064 * @param filters Set of row filters. 065 */ 066 public FilterList(final Operator operator, final List<Filter> filters) { 067 if (operator == Operator.MUST_PASS_ALL) { 068 filterListBase = new FilterListWithAND(filters); 069 } else if (operator == Operator.MUST_PASS_ONE) { 070 filterListBase = new FilterListWithOR(filters); 071 } else { 072 throw new IllegalArgumentException("Invalid operator: " + operator); 073 } 074 this.operator = operator; 075 } 076 077 /** 078 * Constructor that takes a set of {@link Filter}s. The default operator MUST_PASS_ALL is assumed. 079 * All filters are cloned to internal list. 080 * @param filters list of filters 081 */ 082 public FilterList(final List<Filter> filters) { 083 this(Operator.MUST_PASS_ALL, filters); 084 } 085 086 /** 087 * Constructor that takes a var arg number of {@link Filter}s. The default operator MUST_PASS_ALL 088 * is assumed. 089 * @param filters 090 */ 091 public FilterList(final Filter... filters) { 092 this(Operator.MUST_PASS_ALL, Arrays.asList(filters)); 093 } 094 095 /** 096 * Constructor that takes an operator. 097 * @param operator Operator to process filter set with. 098 */ 099 public FilterList(final Operator operator) { 100 this(operator, new ArrayList<>()); 101 } 102 103 /** 104 * Constructor that takes a var arg number of {@link Filter}s and an operator. 105 * @param operator Operator to process filter set with. 106 * @param filters Filters to use 107 */ 108 public FilterList(final Operator operator, final Filter... filters) { 109 this(operator, Arrays.asList(filters)); 110 } 111 112 /** 113 * Get the operator. 114 * @return operator 115 */ 116 public Operator getOperator() { 117 return operator; 118 } 119 120 /** 121 * Get the filters. 122 * @return filters 123 */ 124 public List<Filter> getFilters() { 125 return filterListBase.getFilters(); 126 } 127 128 public int size() { 129 return filterListBase.size(); 130 } 131 132 public void addFilter(List<Filter> filters) { 133 filterListBase.addFilterLists(filters); 134 } 135 136 /** 137 * Add a filter. 138 * @param filter another filter 139 */ 140 public void addFilter(Filter filter) { 141 addFilter(Collections.singletonList(filter)); 142 } 143 144 @Override 145 public void reset() throws IOException { 146 filterListBase.reset(); 147 } 148 149 @Override 150 public boolean filterRowKey(byte[] rowKey, int offset, int length) throws IOException { 151 return filterListBase.filterRowKey(rowKey, offset, length); 152 } 153 154 @Override 155 public boolean filterRowKey(Cell firstRowCell) throws IOException { 156 return filterListBase.filterRowKey(firstRowCell); 157 } 158 159 @Override 160 public boolean filterAllRemaining() throws IOException { 161 return filterListBase.filterAllRemaining(); 162 } 163 164 @Override 165 public Cell transformCell(Cell c) throws IOException { 166 return filterListBase.transformCell(c); 167 } 168 169 @Override 170 @Deprecated 171 public ReturnCode filterKeyValue(final Cell c) throws IOException { 172 return filterCell(c); 173 } 174 175 @Override 176 public ReturnCode filterCell(final Cell c) throws IOException { 177 return filterListBase.filterCell(c); 178 } 179 180 /** 181 * Filters that never filter by modifying the returned List of Cells can inherit this 182 * implementation that does nothing. {@inheritDoc} 183 */ 184 @Override 185 public void filterRowCells(List<Cell> cells) throws IOException { 186 filterListBase.filterRowCells(cells); 187 } 188 189 @Override 190 public boolean hasFilterRow() { 191 return filterListBase.hasFilterRow(); 192 } 193 194 @Override 195 public boolean filterRow() throws IOException { 196 return filterListBase.filterRow(); 197 } 198 199 /** 200 * @return The filter serialized using pb 201 */ 202 @Override 203 public byte[] toByteArray() throws IOException { 204 FilterProtos.FilterList.Builder builder = FilterProtos.FilterList.newBuilder(); 205 builder.setOperator(FilterProtos.FilterList.Operator.valueOf(operator.name())); 206 ArrayList<Filter> filters = filterListBase.getFilters(); 207 for (int i = 0, n = filters.size(); i < n; i++) { 208 builder.addFilters(ProtobufUtil.toFilter(filters.get(i))); 209 } 210 return builder.build().toByteArray(); 211 } 212 213 /** 214 * @param pbBytes A pb serialized {@link FilterList} instance 215 * @return An instance of {@link FilterList} made from <code>bytes</code> 216 * @throws DeserializationException 217 * @see #toByteArray 218 */ 219 public static FilterList parseFrom(final byte[] pbBytes) throws DeserializationException { 220 FilterProtos.FilterList proto; 221 try { 222 proto = FilterProtos.FilterList.parseFrom(pbBytes); 223 } catch (InvalidProtocolBufferException e) { 224 throw new DeserializationException(e); 225 } 226 227 List<Filter> rowFilters = new ArrayList<>(proto.getFiltersCount()); 228 try { 229 List<FilterProtos.Filter> filtersList = proto.getFiltersList(); 230 for (int i = 0, n = filtersList.size(); i < n; i++) { 231 rowFilters.add(ProtobufUtil.toFilter(filtersList.get(i))); 232 } 233 } catch (IOException ioe) { 234 throw new DeserializationException(ioe); 235 } 236 return new FilterList(Operator.valueOf(proto.getOperator().name()), rowFilters); 237 } 238 239 /** 240 * @param other 241 * @return true if and only if the fields of the filter that are serialized are equal to the 242 * corresponding fields in other. Used for testing. 243 */ 244 @Override 245 boolean areSerializedFieldsEqual(Filter other) { 246 if (other == this) return true; 247 if (!(other instanceof FilterList)) return false; 248 249 FilterList o = (FilterList) other; 250 return this.getOperator().equals(o.getOperator()) 251 && ((this.getFilters() == o.getFilters()) || this.getFilters().equals(o.getFilters())); 252 } 253 254 @Override 255 public Cell getNextCellHint(Cell currentCell) throws IOException { 256 return this.filterListBase.getNextCellHint(currentCell); 257 } 258 259 @Override 260 public boolean isFamilyEssential(byte[] name) throws IOException { 261 return this.filterListBase.isFamilyEssential(name); 262 } 263 264 @Override 265 public void setReversed(boolean reversed) { 266 this.reversed = reversed; 267 this.filterListBase.setReversed(reversed); 268 } 269 270 @Override 271 public boolean isReversed() { 272 assert this.reversed == this.filterListBase.isReversed(); 273 return this.reversed; 274 } 275 276 @Override 277 public String toString() { 278 return this.filterListBase.toString(); 279 } 280 281 @Override 282 public boolean equals(Object obj) { 283 return obj instanceof Filter && areSerializedFieldsEqual((Filter) obj); 284 } 285 286 @Override 287 public int hashCode() { 288 return Objects.hash(getOperator(), getFilters()); 289 } 290}