View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.omid.transaction;
19  
20  import org.apache.hadoop.hbase.Cell;
21  import org.apache.hadoop.hbase.CellUtil;
22  import org.apache.hadoop.hbase.KeyValue;
23  import org.apache.hadoop.hbase.KeyValueUtil;
24  import org.apache.hadoop.hbase.filter.Filter;
25  import org.apache.omid.OmidFilterBase;
26  
27  import java.io.IOException;
28  import java.util.List;
29  
30  /**
31   * {@link Filter} that encapsulates another {@link Filter}. It remembers the last {@link KeyValue}
32   * for which the underlying filter returned the {@link ReturnCode#NEXT_COL} or {@link ReturnCode#INCLUDE_AND_NEXT_COL},
33   * so that when {@link #filterKeyValue} is called again for the same {@link KeyValue} with different
34   * version, it returns {@link ReturnCode#NEXT_COL} directly without consulting the underlying {@link Filter}.
35   * Please see TEPHRA-169 for more details.
36   */
37  
38  public class CellSkipFilterBase extends OmidFilterBase {
39      private final Filter filter;
40      // remember the previous keyvalue processed by filter when the return code was NEXT_COL or INCLUDE_AND_NEXT_COL
41      private KeyValue skipColumn = null;
42  
43      public CellSkipFilterBase(Filter filter) {
44          this.filter = filter;
45      }
46  
47      /**
48       * Determines whether the current cell should be skipped. The cell will be skipped
49       * if the previous keyvalue had the same key as the current cell. This means filter already responded
50       * for the previous keyvalue with ReturnCode.NEXT_COL or ReturnCode.INCLUDE_AND_NEXT_COL.
51       * @param cell the {@link Cell} to be tested for skipping
52       * @return true is current cell should be skipped, false otherwise
53       */
54      private boolean skipCellVersion(Cell cell) {
55          return skipColumn != null
56          && CellUtil.matchingRow(cell, skipColumn.getRowArray(), skipColumn.getRowOffset(),
57                  skipColumn.getRowLength())
58                  && CellUtil.matchingFamily(cell, skipColumn.getFamilyArray(), skipColumn.getFamilyOffset(),
59                  skipColumn.getFamilyLength())
60                  && CellUtil.matchingQualifier(cell, skipColumn.getQualifierArray(), skipColumn.getQualifierOffset(),
61                  skipColumn.getQualifierLength());
62      }
63  
64      @Override
65      public ReturnCode filterKeyValue(Cell cell) throws IOException {
66          if (skipCellVersion(cell)) {
67              return ReturnCode.NEXT_COL;
68          }
69  
70          ReturnCode code = filter.filterKeyValue(cell);
71          if (code == ReturnCode.NEXT_COL || code == ReturnCode.INCLUDE_AND_NEXT_COL) {
72              // only store the reference to the keyvalue if we are returning NEXT_COL or INCLUDE_AND_NEXT_COL
73              skipColumn = KeyValueUtil.createFirstOnRow(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength(),
74                      cell.getFamilyArray(), cell.getFamilyOffset(),
75                      cell.getFamilyLength(), cell.getQualifierArray(),
76                      cell.getQualifierOffset(), cell.getQualifierLength());
77          } else {
78              skipColumn = null;
79          }
80          return code;
81      }
82  
83      @Override
84      public boolean filterRow() throws IOException {
85          return filter.filterRow();
86      }
87  
88      @Override
89      public Cell transformCell(Cell cell) throws IOException {
90          return filter.transformCell(cell);
91      }
92  
93      @Override
94      public void reset() throws IOException {
95          filter.reset();
96      }
97  
98      @Override
99      public boolean filterRowKey(byte[] buffer, int offset, int length) throws IOException {
100         return filter.filterRowKey(buffer, offset, length);
101     }
102 
103     @Override
104     public boolean filterAllRemaining() throws IOException {
105         return filter.filterAllRemaining();
106     }
107 
108     @Override
109     public void filterRowCells(List<Cell> kvs) throws IOException {
110         filter.filterRowCells(kvs);
111     }
112 
113     @Override
114     public boolean hasFilterRow() {
115         return filter.hasFilterRow();
116     }
117 
118     @Override
119     public Cell getNextCellHint(Cell currentKV) throws IOException {
120         return filter.getNextCellHint(currentKV);
121     }
122 
123     @Override
124     public boolean isFamilyEssential(byte[] name) throws IOException {
125         return filter.isFamilyEssential(name);
126     }
127 
128     @Override
129     public byte[] toByteArray() throws IOException {
130         return filter.toByteArray();
131     }
132 
133     public Filter getInnerFilter() {
134         return filter;
135     }
136 }