1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.hadoop.hbase.filter;
21
22 import org.apache.hadoop.hbase.Cell;
23 import org.apache.hadoop.hbase.classification.InterfaceAudience;
24
25 import java.io.IOException;
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.List;
29
30
31
32
33
34 @InterfaceAudience.Private
35 public class FilterListWithAND extends FilterListBase {
36
37 private List<Filter> seekHintFilters = new ArrayList<>();
38
39 public FilterListWithAND(List<Filter> filters) {
40 super(filters);
41
42
43
44 subFiltersIncludedCell = new ArrayList<>(Collections.nCopies(filters.size(), true));
45 }
46
47 @Override
48 public void addFilterLists(List<Filter> filters) {
49 if (checkAndGetReversed(filters, isReversed()) != isReversed()) {
50 throw new IllegalArgumentException("Filters in the list must have the same reversed flag");
51 }
52 this.filters.addAll(filters);
53 this.subFiltersIncludedCell.addAll(Collections.nCopies(filters.size(), true));
54 }
55
56 @Override
57 protected String formatLogFilters(List<Filter> logFilters) {
58 return String.format("FilterList AND (%d/%d): %s", logFilters.size(), this.size(),
59 logFilters.toString());
60 }
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98 private ReturnCode mergeReturnCode(ReturnCode rc, ReturnCode localRC) {
99 if (rc == ReturnCode.SEEK_NEXT_USING_HINT) {
100 return ReturnCode.SEEK_NEXT_USING_HINT;
101 }
102 switch (localRC) {
103 case SEEK_NEXT_USING_HINT:
104 return ReturnCode.SEEK_NEXT_USING_HINT;
105 case INCLUDE:
106 return rc;
107 case INCLUDE_AND_NEXT_COL:
108 if (isInReturnCodes(rc, ReturnCode.INCLUDE, ReturnCode.INCLUDE_AND_NEXT_COL)) {
109 return ReturnCode.INCLUDE_AND_NEXT_COL;
110 }
111 if (isInReturnCodes(rc, ReturnCode.INCLUDE_AND_SEEK_NEXT_ROW)) {
112 return ReturnCode.INCLUDE_AND_SEEK_NEXT_ROW;
113 }
114 if (isInReturnCodes(rc, ReturnCode.SKIP, ReturnCode.NEXT_COL)) {
115 return ReturnCode.NEXT_COL;
116 }
117 if (isInReturnCodes(rc, ReturnCode.NEXT_ROW)) {
118 return ReturnCode.NEXT_ROW;
119 }
120 break;
121 case INCLUDE_AND_SEEK_NEXT_ROW:
122 if (isInReturnCodes(rc, ReturnCode.INCLUDE, ReturnCode.INCLUDE_AND_NEXT_COL,
123 ReturnCode.INCLUDE_AND_SEEK_NEXT_ROW)) {
124 return ReturnCode.INCLUDE_AND_SEEK_NEXT_ROW;
125 }
126 if (isInReturnCodes(rc, ReturnCode.SKIP, ReturnCode.NEXT_COL, ReturnCode.NEXT_ROW)) {
127 return ReturnCode.NEXT_ROW;
128 }
129 break;
130 case SKIP:
131 if (isInReturnCodes(rc, ReturnCode.INCLUDE, ReturnCode.SKIP)) {
132 return ReturnCode.SKIP;
133 }
134 if (isInReturnCodes(rc, ReturnCode.INCLUDE_AND_NEXT_COL, ReturnCode.NEXT_COL)) {
135 return ReturnCode.NEXT_COL;
136 }
137 if (isInReturnCodes(rc, ReturnCode.INCLUDE_AND_SEEK_NEXT_ROW, ReturnCode.NEXT_ROW)) {
138 return ReturnCode.NEXT_ROW;
139 }
140 break;
141 case NEXT_COL:
142 if (isInReturnCodes(rc, ReturnCode.INCLUDE, ReturnCode.INCLUDE_AND_NEXT_COL, ReturnCode.SKIP,
143 ReturnCode.NEXT_COL)) {
144 return ReturnCode.NEXT_COL;
145 }
146 if (isInReturnCodes(rc, ReturnCode.INCLUDE_AND_SEEK_NEXT_ROW, ReturnCode.NEXT_ROW)) {
147 return ReturnCode.NEXT_ROW;
148 }
149 break;
150 case NEXT_ROW:
151 return ReturnCode.NEXT_ROW;
152 }
153 throw new IllegalStateException(
154 "Received code is not valid. rc: " + rc + ", localRC: " + localRC);
155 }
156
157 private boolean isIncludeRelatedReturnCode(ReturnCode rc) {
158 return isInReturnCodes(rc, ReturnCode.INCLUDE, ReturnCode.INCLUDE_AND_NEXT_COL,
159 ReturnCode.INCLUDE_AND_SEEK_NEXT_ROW);
160 }
161
162 @Override
163 public ReturnCode filterKeyValue(Cell c) throws IOException {
164 if (isEmpty()) {
165 return ReturnCode.INCLUDE;
166 }
167 ReturnCode rc = ReturnCode.INCLUDE;
168 this.seekHintFilters.clear();
169 for (int i = 0, n = filters.size(); i < n; i++) {
170 Filter filter = filters.get(i);
171 if (filter.filterAllRemaining()) {
172 return ReturnCode.NEXT_ROW;
173 }
174 ReturnCode localRC = filter.filterKeyValue(c);
175 if (localRC == ReturnCode.SEEK_NEXT_USING_HINT) {
176 seekHintFilters.add(filter);
177 }
178 rc = mergeReturnCode(rc, localRC);
179
180
181
182 if (!isIncludeRelatedReturnCode(rc)) {
183 return rc;
184 }
185 }
186 if (!seekHintFilters.isEmpty()) {
187 return ReturnCode.SEEK_NEXT_USING_HINT;
188 }
189 return rc;
190 }
191
192 @Override
193 public void reset() throws IOException {
194 for (int i = 0, n = filters.size(); i < n; i++) {
195 filters.get(i).reset();
196 }
197 seekHintFilters.clear();
198 }
199
200 @Override
201 public boolean filterRowKey(byte[] rowKey, int offset, int length) throws IOException {
202 if (isEmpty()) {
203 return super.filterRowKey(rowKey, offset, length);
204 }
205 boolean retVal = false;
206 for (int i = 0, n = filters.size(); i < n; i++) {
207 Filter filter = filters.get(i);
208 if (filter.filterAllRemaining() || filter.filterRowKey(rowKey, offset, length)) {
209 retVal = true;
210 }
211 }
212 return retVal;
213 }
214
215 @Override
216 public boolean filterAllRemaining() throws IOException {
217 if (isEmpty()) {
218 return super.filterAllRemaining();
219 }
220 for (int i = 0, n = filters.size(); i < n; i++) {
221 if (filters.get(i).filterAllRemaining()) {
222 return true;
223 }
224 }
225 return false;
226 }
227
228 @Override
229 public boolean filterRow() throws IOException {
230 if (isEmpty()) {
231 return super.filterRow();
232 }
233 for (int i = 0, n = filters.size(); i < n; i++) {
234 Filter filter = filters.get(i);
235 if (filter.filterRow()) {
236 return true;
237 }
238 }
239 return false;
240 }
241
242 @Override
243 public Cell getNextCellHint(Cell currentCell) throws IOException {
244 if (isEmpty()) {
245 return super.getNextCellHint(currentCell);
246 }
247 Cell maxHint = null;
248 for (Filter filter : seekHintFilters) {
249 if (filter.filterAllRemaining()) {
250 continue;
251 }
252 Cell curKeyHint = filter.getNextCellHint(currentCell);
253 if (maxHint == null) {
254 maxHint = curKeyHint;
255 continue;
256 }
257 if (this.compareCell(maxHint, curKeyHint) < 0) {
258 maxHint = curKeyHint;
259 }
260 }
261 return maxHint;
262 }
263 }