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  /**
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}