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