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.CellUtil;
24 import org.apache.hadoop.hbase.classification.InterfaceAudience;
25
26 import java.io.IOException;
27 import java.util.ArrayList;
28 import java.util.Collections;
29 import java.util.List;
30 import java.util.Objects;
31
32
33
34
35
36 @InterfaceAudience.Private
37 public class FilterListWithOR extends FilterListBase {
38
39
40
41
42
43
44 private List<ReturnCode> prevFilterRCList = null;
45 private List<Cell> prevCellList = null;
46
47 public FilterListWithOR(List<Filter> filters) {
48 super(filters);
49 prevFilterRCList =
50 new ArrayList<ReturnCode>(Collections.nCopies(filters.size(), (ReturnCode) null));
51 prevCellList = new ArrayList<Cell>(Collections.nCopies(filters.size(), (Cell) null));
52 subFiltersIncludedCell = new ArrayList<Boolean>(Collections.nCopies(filters.size(), false));
53 }
54
55 @Override
56 public void addFilterLists(List<Filter> filters) {
57 if (checkAndGetReversed(filters, isReversed()) != isReversed()) {
58 throw new IllegalArgumentException("Filters in the list must have the same reversed flag");
59 }
60 this.filters.addAll(filters);
61 this.subFiltersIncludedCell.addAll(Collections.nCopies(filters.size(), false));
62 this.prevFilterRCList.addAll(Collections.nCopies(filters.size(), (ReturnCode) null));
63 this.prevCellList.addAll(Collections.nCopies(filters.size(), (Cell) null));
64 }
65
66 @Override
67 protected String formatLogFilters(List<Filter> logFilters) {
68 return String.format("FilterList OR (%d/%d): %s", logFilters.size(), this.size(),
69 logFilters.toString());
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 private ReturnCode calculateReturnCodeByPrevCellAndRC(Filter subFilter, Cell currentCell,
97 Cell prevCell, ReturnCode prevCode) throws IOException {
98 if (prevCell == null || prevCode == null) {
99 return null;
100 }
101 switch (prevCode) {
102 case INCLUDE:
103 case SKIP:
104 return null;
105 case SEEK_NEXT_USING_HINT:
106 Cell nextHintCell = subFilter.getNextCellHint(prevCell);
107 return nextHintCell != null && compareCell(currentCell, nextHintCell) < 0
108 ? ReturnCode.SEEK_NEXT_USING_HINT : null;
109 case NEXT_COL:
110 case INCLUDE_AND_NEXT_COL:
111
112
113 return CellUtil.matchingColumn(prevCell, currentCell) ? ReturnCode.NEXT_COL : null;
114 case NEXT_ROW:
115 case INCLUDE_AND_SEEK_NEXT_ROW:
116
117 return CellUtil.matchingFamily(prevCell, currentCell) ? ReturnCode.NEXT_ROW : null;
118 default:
119 throw new IllegalStateException("Received code is not valid.");
120 }
121 }
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157 private ReturnCode mergeReturnCode(ReturnCode rc, ReturnCode localRC) {
158 if (rc == null) return localRC;
159 switch (localRC) {
160 case INCLUDE:
161 return ReturnCode.INCLUDE;
162 case INCLUDE_AND_NEXT_COL:
163 if (isInReturnCodes(rc, ReturnCode.INCLUDE, ReturnCode.SKIP,
164 ReturnCode.SEEK_NEXT_USING_HINT)) {
165 return ReturnCode.INCLUDE;
166 }
167 if (isInReturnCodes(rc, ReturnCode.INCLUDE_AND_NEXT_COL, ReturnCode.INCLUDE_AND_SEEK_NEXT_ROW,
168 ReturnCode.NEXT_COL, ReturnCode.NEXT_ROW)) {
169 return ReturnCode.INCLUDE_AND_NEXT_COL;
170 }
171 break;
172 case INCLUDE_AND_SEEK_NEXT_ROW:
173 if (isInReturnCodes(rc, ReturnCode.INCLUDE, ReturnCode.SKIP,
174 ReturnCode.SEEK_NEXT_USING_HINT)) {
175 return ReturnCode.INCLUDE;
176 }
177 if (isInReturnCodes(rc, ReturnCode.INCLUDE_AND_NEXT_COL, ReturnCode.NEXT_COL)) {
178 return ReturnCode.INCLUDE_AND_NEXT_COL;
179 }
180 if (isInReturnCodes(rc, ReturnCode.INCLUDE_AND_SEEK_NEXT_ROW, ReturnCode.NEXT_ROW)) {
181 return ReturnCode.INCLUDE_AND_SEEK_NEXT_ROW;
182 }
183 break;
184 case SKIP:
185 if (isInReturnCodes(rc, ReturnCode.INCLUDE, ReturnCode.INCLUDE_AND_NEXT_COL,
186 ReturnCode.INCLUDE_AND_SEEK_NEXT_ROW)) {
187 return ReturnCode.INCLUDE;
188 }
189 if (isInReturnCodes(rc, ReturnCode.SKIP, ReturnCode.NEXT_COL, ReturnCode.NEXT_ROW,
190 ReturnCode.SEEK_NEXT_USING_HINT)) {
191 return ReturnCode.SKIP;
192 }
193 break;
194 case NEXT_COL:
195 if (isInReturnCodes(rc, ReturnCode.INCLUDE)) {
196 return ReturnCode.INCLUDE;
197 }
198 if (isInReturnCodes(rc, ReturnCode.NEXT_COL, ReturnCode.NEXT_ROW)) {
199 return ReturnCode.NEXT_COL;
200 }
201 if (isInReturnCodes(rc, ReturnCode.INCLUDE_AND_NEXT_COL,
202 ReturnCode.INCLUDE_AND_SEEK_NEXT_ROW)) {
203 return ReturnCode.INCLUDE_AND_NEXT_COL;
204 }
205 if (isInReturnCodes(rc, ReturnCode.SKIP, ReturnCode.SEEK_NEXT_USING_HINT)) {
206 return ReturnCode.SKIP;
207 }
208 break;
209 case NEXT_ROW:
210 if (isInReturnCodes(rc, ReturnCode.INCLUDE)) {
211 return ReturnCode.INCLUDE;
212 }
213 if (isInReturnCodes(rc, ReturnCode.INCLUDE_AND_NEXT_COL)) {
214 return ReturnCode.INCLUDE_AND_NEXT_COL;
215 }
216 if (isInReturnCodes(rc, ReturnCode.INCLUDE_AND_SEEK_NEXT_ROW)) {
217 return ReturnCode.INCLUDE_AND_SEEK_NEXT_ROW;
218 }
219 if (isInReturnCodes(rc, ReturnCode.SKIP, ReturnCode.SEEK_NEXT_USING_HINT)) {
220 return ReturnCode.SKIP;
221 }
222 if (isInReturnCodes(rc, ReturnCode.NEXT_COL)) {
223 return ReturnCode.NEXT_COL;
224 }
225 if (isInReturnCodes(rc, ReturnCode.NEXT_ROW)) {
226 return ReturnCode.NEXT_ROW;
227 }
228 break;
229 case SEEK_NEXT_USING_HINT:
230 if (isInReturnCodes(rc, ReturnCode.INCLUDE, ReturnCode.INCLUDE_AND_NEXT_COL,
231 ReturnCode.INCLUDE_AND_SEEK_NEXT_ROW)) {
232 return ReturnCode.INCLUDE;
233 }
234 if (isInReturnCodes(rc, ReturnCode.SKIP, ReturnCode.NEXT_COL, ReturnCode.NEXT_ROW)) {
235 return ReturnCode.SKIP;
236 }
237 if (isInReturnCodes(rc, ReturnCode.SEEK_NEXT_USING_HINT)) {
238 return ReturnCode.SEEK_NEXT_USING_HINT;
239 }
240 break;
241 }
242 throw new IllegalStateException(
243 "Received code is not valid. rc: " + rc + ", localRC: " + localRC);
244 }
245
246 private void updatePrevFilterRCList(int index, ReturnCode currentRC) {
247 prevFilterRCList.set(index, currentRC);
248 }
249
250 private void updatePrevCellList(int index, Cell currentCell, ReturnCode currentRC) {
251 if (currentCell == null || currentRC == ReturnCode.INCLUDE || currentRC == ReturnCode.SKIP) {
252
253
254
255 prevCellList.set(index, null);
256 } else {
257 prevCellList.set(index, currentCell);
258 }
259 }
260
261 @Override
262 public ReturnCode filterKeyValue(Cell c) throws IOException {
263 if (isEmpty()) {
264 return ReturnCode.INCLUDE;
265 }
266 ReturnCode rc = null;
267 for (int i = 0, n = filters.size(); i < n; i++) {
268 Filter filter = filters.get(i);
269 subFiltersIncludedCell.set(i, false);
270
271 Cell prevCell = this.prevCellList.get(i);
272 ReturnCode prevCode = this.prevFilterRCList.get(i);
273 if (filter.filterAllRemaining()) {
274 continue;
275 }
276
277 ReturnCode localRC = calculateReturnCodeByPrevCellAndRC(filter, c, prevCell, prevCode);
278 if (localRC == null) {
279
280
281
282 localRC = filter.filterKeyValue(c);
283 }
284
285
286 updatePrevFilterRCList(i, localRC);
287 updatePrevCellList(i, c, localRC);
288
289 rc = mergeReturnCode(rc, localRC);
290
291
292 if (isInReturnCodes(localRC, ReturnCode.INCLUDE, ReturnCode.INCLUDE_AND_NEXT_COL,
293 ReturnCode.INCLUDE_AND_SEEK_NEXT_ROW)) {
294 subFiltersIncludedCell.set(i, true);
295 }
296 }
297
298
299 return rc == null ? ReturnCode.SKIP : rc;
300 }
301
302 @Override
303 public void reset() throws IOException {
304 for (int i = 0, n = filters.size(); i < n; i++) {
305 filters.get(i).reset();
306 subFiltersIncludedCell.set(i, false);
307 prevFilterRCList.set(i, null);
308 prevCellList.set(i, null);
309 }
310 }
311
312 @Override
313 public boolean filterRowKey(byte[] rowKey, int offset, int length) throws IOException {
314 if (isEmpty()) {
315 return super.filterRowKey(rowKey, offset, length);
316 }
317 boolean retVal = true;
318 for (int i = 0, n = filters.size(); i < n; i++) {
319 Filter filter = filters.get(i);
320 if (!filter.filterAllRemaining() && !filter.filterRowKey(rowKey, offset, length)) {
321 retVal = false;
322 }
323 }
324 return retVal;
325 }
326
327 @Override
328 public boolean filterAllRemaining() throws IOException {
329 if (isEmpty()) {
330 return super.filterAllRemaining();
331 }
332 for (int i = 0, n = filters.size(); i < n; i++) {
333 if (!filters.get(i).filterAllRemaining()) {
334 return false;
335 }
336 }
337 return true;
338 }
339
340 @Override
341 public boolean filterRow() throws IOException {
342 if (isEmpty()) {
343 return super.filterRow();
344 }
345 for (int i = 0, n = filters.size(); i < n; i++) {
346 Filter filter = filters.get(i);
347 if (!filter.filterRow()) {
348 return false;
349 }
350 }
351 return true;
352 }
353
354 @Override
355 public Cell getNextCellHint(Cell currentCell) throws IOException {
356 if (isEmpty()) {
357 return super.getNextCellHint(currentCell);
358 }
359 Cell minKeyHint = null;
360
361 for (int i = 0, n = filters.size(); i < n; i++) {
362 if (filters.get(i).filterAllRemaining()) {
363 continue;
364 }
365 Cell curKeyHint = filters.get(i).getNextCellHint(currentCell);
366 if (curKeyHint == null) {
367
368 return null;
369 }
370
371 if (minKeyHint == null) {
372 minKeyHint = curKeyHint;
373 continue;
374 }
375 if (this.compareCell(minKeyHint, curKeyHint) > 0) {
376 minKeyHint = curKeyHint;
377 }
378 }
379 return minKeyHint;
380 }
381
382
383 @Override
384 public boolean equals(Object obj) {
385 if (obj == null || (!(obj instanceof FilterListWithOR))) {
386 return false;
387 }
388 if (this == obj) {
389 return true;
390 }
391 FilterListWithOR f = (FilterListWithOR) obj;
392 return this.filters.equals(f.getFilters()) &&
393 this.prevFilterRCList.equals(f.prevFilterRCList) &&
394 this.prevCellList.equals(f.prevCellList);
395 }
396
397 @Override
398 public int hashCode() {
399 return Objects.hash(this.prevFilterRCList, this.prevCellList, this.filters);
400 }
401 }