1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.regionserver.querymatcher;
19
20 import com.google.common.base.Preconditions;
21
22 import java.io.IOException;
23 import java.util.Arrays;
24 import java.util.NavigableSet;
25
26 import org.apache.hadoop.hbase.Cell;
27 import org.apache.hadoop.hbase.CellUtil;
28 import org.apache.hadoop.hbase.HConstants;
29 import org.apache.hadoop.hbase.KeepDeletedCells;
30 import org.apache.hadoop.hbase.classification.InterfaceAudience;
31 import org.apache.hadoop.hbase.client.Scan;
32 import org.apache.hadoop.hbase.filter.Filter;
33 import org.apache.hadoop.hbase.filter.Filter.ReturnCode;
34 import org.apache.hadoop.hbase.io.TimeRange;
35 import org.apache.hadoop.hbase.regionserver.DeleteTracker;
36 import org.apache.hadoop.hbase.regionserver.DeleteTracker.DeleteResult;
37 import org.apache.hadoop.hbase.regionserver.RegionCoprocessorHost;
38 import org.apache.hadoop.hbase.regionserver.ScanInfo;
39 import org.apache.hadoop.hbase.regionserver.ScanType;
40 import org.apache.hadoop.hbase.util.Bytes;
41 import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
42
43
44
45
46
47
48 @Deprecated
49 @InterfaceAudience.Private
50 public class LegacyScanQueryMatcher extends ScanQueryMatcher {
51
52 private final TimeRange tr;
53
54 private final Filter filter;
55
56
57 private final DeleteTracker deletes;
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73 private boolean retainDeletesInOutput;
74
75
76 private final KeepDeletedCells keepDeletedCells;
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95 private final long timeToPurgeDeletes;
96
97
98
99
100
101
102 private final boolean hasNullColumn;
103
104
105 private final long maxReadPointToTrackVersions;
106
107
108
109
110
111 protected final long earliestPutTs;
112
113 private final byte[] stopRow;
114
115 private byte[] dropDeletesFromRow = null, dropDeletesToRow = null;
116
117 private LegacyScanQueryMatcher(Scan scan, ScanInfo scanInfo, ColumnTracker columns,
118 boolean hasNullColumn, DeleteTracker deletes, ScanType scanType, long readPointToUse,
119 long earliestPutTs, long oldestUnexpiredTS, long now) {
120 super(createStartKeyFromRow(scan.getStartRow(), scanInfo), scanInfo, columns, oldestUnexpiredTS,
121 now);
122 TimeRange timeRange = scan.getColumnFamilyTimeRange().get(scanInfo.getFamily());
123 if (timeRange == null) {
124 this.tr = scan.getTimeRange();
125 } else {
126 this.tr = timeRange;
127 }
128 this.hasNullColumn = hasNullColumn;
129 this.deletes = deletes;
130 this.filter = scan.getFilter();
131 this.maxReadPointToTrackVersions = readPointToUse;
132 this.timeToPurgeDeletes = scanInfo.getTimeToPurgeDeletes();
133 this.earliestPutTs = earliestPutTs;
134
135
136 this.keepDeletedCells = scanInfo.getKeepDeletedCells();
137 this.retainDeletesInOutput = scanType == ScanType.COMPACT_RETAIN_DELETES;
138 this.stopRow = scan.getStopRow();
139 }
140
141 private LegacyScanQueryMatcher(Scan scan, ScanInfo scanInfo, ColumnTracker columns,
142 boolean hasNullColumn, DeleteTracker deletes, ScanType scanType, long readPointToUse,
143 long earliestPutTs, long oldestUnexpiredTS, long now, byte[] dropDeletesFromRow,
144 byte[] dropDeletesToRow) {
145 this(scan, scanInfo, columns, hasNullColumn, deletes, scanType, readPointToUse, earliestPutTs,
146 oldestUnexpiredTS, now);
147 this.dropDeletesFromRow = Preconditions.checkNotNull(dropDeletesFromRow);
148 this.dropDeletesToRow = Preconditions.checkNotNull(dropDeletesToRow);
149 }
150
151 @Override
152 public MatchCode match(Cell cell) throws IOException {
153 if (filter != null && filter.filterAllRemaining()) {
154 return MatchCode.DONE_SCAN;
155 }
156 MatchCode returnCode = preCheck(cell);
157 if (returnCode != null) {
158 return returnCode;
159 }
160
161
162
163
164
165
166
167
168
169
170
171
172
173 long timestamp = cell.getTimestamp();
174 byte typeByte = cell.getTypeByte();
175 long mvccVersion = cell.getSequenceId();
176 int qualifierOffset = cell.getQualifierOffset();
177 int qualifierLength = cell.getQualifierLength();
178 if (CellUtil.isDelete(typeByte)) {
179 if (keepDeletedCells == KeepDeletedCells.FALSE
180 || (keepDeletedCells == KeepDeletedCells.TTL && timestamp < oldestUnexpiredTS)) {
181
182
183
184
185
186
187 boolean includeDeleteMarker = tr.withinOrAfterTimeRange(timestamp);
188 if (includeDeleteMarker && mvccVersion <= maxReadPointToTrackVersions) {
189 this.deletes.add(cell);
190 }
191
192 }
193
194 if (timeToPurgeDeletes > 0
195 && (EnvironmentEdgeManager.currentTime() - timestamp) <= timeToPurgeDeletes) {
196 return MatchCode.INCLUDE;
197 } else if (retainDeletesInOutput || mvccVersion > maxReadPointToTrackVersions) {
198
199
200
201
202 return MatchCode.INCLUDE;
203 } else if (keepDeletedCells == KeepDeletedCells.TRUE
204 || (keepDeletedCells == KeepDeletedCells.TTL && timestamp >= oldestUnexpiredTS)) {
205 if (timestamp < earliestPutTs) {
206
207
208 return columns.getNextRowOrNextColumn(cell.getQualifierArray(), qualifierOffset,
209 qualifierLength);
210 }
211
212
213 } else {
214 return MatchCode.SKIP;
215 }
216
217
218 } else if (!this.deletes.isEmpty()) {
219 DeleteResult deleteResult = deletes.isDeleted(cell);
220 switch (deleteResult) {
221 case FAMILY_DELETED:
222 case COLUMN_DELETED:
223 return columns.getNextRowOrNextColumn(cell.getQualifierArray(), qualifierOffset,
224 qualifierLength);
225 case VERSION_DELETED:
226 case FAMILY_VERSION_DELETED:
227 return MatchCode.SKIP;
228 case NOT_DELETED:
229 break;
230 default:
231 throw new RuntimeException("UNEXPECTED");
232 }
233 }
234
235 int timestampComparison = tr.compare(timestamp);
236 if (timestampComparison >= 1) {
237 return MatchCode.SKIP;
238 } else if (timestampComparison <= -1) {
239 return columns.getNextRowOrNextColumn(cell.getQualifierArray(), qualifierOffset,
240 qualifierLength);
241 }
242
243
244 MatchCode colChecker = columns.checkColumn(cell.getQualifierArray(),
245 qualifierOffset, qualifierLength, typeByte);
246 if (colChecker == MatchCode.INCLUDE) {
247 ReturnCode filterResponse = ReturnCode.SKIP;
248
249 if (filter != null) {
250
251 filterResponse = filter.filterKeyValue(cell);
252 switch (filterResponse) {
253 case SKIP:
254 return MatchCode.SKIP;
255 case NEXT_COL:
256 return columns.getNextRowOrNextColumn(cell.getQualifierArray(),
257 qualifierOffset, qualifierLength);
258 case NEXT_ROW:
259 return MatchCode.SEEK_NEXT_ROW;
260 case SEEK_NEXT_USING_HINT:
261 return MatchCode.SEEK_NEXT_USING_HINT;
262 default:
263
264 break;
265 }
266 }
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286 colChecker =
287 columns.checkVersions(cell.getQualifierArray(), qualifierOffset,
288 qualifierLength, timestamp, typeByte,
289 mvccVersion > maxReadPointToTrackVersions);
290 return (filterResponse == ReturnCode.INCLUDE_AND_NEXT_COL &&
291 colChecker == MatchCode.INCLUDE) ? MatchCode.INCLUDE_AND_SEEK_NEXT_COL
292 : colChecker;
293 }
294 return colChecker;
295 }
296
297 @Override
298 public boolean hasNullColumnInQuery() {
299 return hasNullColumn;
300 }
301
302
303
304
305
306
307 private void checkPartialDropDeleteRange(Cell curCell) {
308 byte[] rowArray = curCell.getRowArray();
309 int rowOffset = curCell.getRowOffset();
310 short rowLength = curCell.getRowLength();
311
312
313
314
315 if ((dropDeletesFromRow != null)
316 && (Arrays.equals(dropDeletesFromRow, HConstants.EMPTY_START_ROW)
317 || (Bytes.compareTo(rowArray, rowOffset, rowLength, dropDeletesFromRow, 0,
318 dropDeletesFromRow.length) >= 0))) {
319 retainDeletesInOutput = false;
320 dropDeletesFromRow = null;
321 }
322
323
324
325 if ((dropDeletesFromRow == null) && (dropDeletesToRow != null)
326 && !Arrays.equals(dropDeletesToRow, HConstants.EMPTY_END_ROW) && (Bytes.compareTo(rowArray,
327 rowOffset, rowLength, dropDeletesToRow, 0, dropDeletesToRow.length) >= 0)) {
328 retainDeletesInOutput = true;
329 dropDeletesToRow = null;
330 }
331 }
332
333 @Override
334 protected void reset() {
335 checkPartialDropDeleteRange(currentRow);
336 }
337
338 @Override
339 public boolean isUserScan() {
340 return false;
341 }
342
343 @Override
344 public boolean moreRowsMayExistAfter(Cell cell) {
345 if (this.stopRow == null || this.stopRow.length == 0) {
346 return true;
347 }
348 return rowComparator.compareRows(cell, stopRow, 0, stopRow.length) < 0;
349 }
350
351 @Override
352 public Filter getFilter() {
353 return filter;
354 }
355
356 @Override
357 public Cell getNextKeyHint(Cell cell) throws IOException {
358 if (filter == null) {
359 return null;
360 } else {
361 return filter.getNextCellHint(cell);
362 }
363 }
364
365 public static LegacyScanQueryMatcher create(Scan scan, ScanInfo scanInfo,
366 NavigableSet<byte[]> columns, ScanType scanType, long readPointToUse, long earliestPutTs,
367 long oldestUnexpiredTS, long now, byte[] dropDeletesFromRow, byte[] dropDeletesToRow,
368 RegionCoprocessorHost regionCoprocessorHost) throws IOException {
369 int maxVersions = Math.min(scan.getMaxVersions(), scanInfo.getMaxVersions());
370 boolean hasNullColumn;
371 ColumnTracker columnTracker;
372 if (columns == null || columns.size() == 0) {
373
374 hasNullColumn = true;
375
376 columnTracker = new ScanWildcardColumnTracker(scanInfo.getMinVersions(), maxVersions,
377 oldestUnexpiredTS);
378 } else {
379
380
381
382 hasNullColumn = columns.first().length == 0;
383 columnTracker = new ExplicitColumnTracker(columns, scanInfo.getMinVersions(), maxVersions,
384 oldestUnexpiredTS);
385 }
386 DeleteTracker deletes = instantiateDeleteTracker(regionCoprocessorHost);
387 if (dropDeletesFromRow == null) {
388 return new LegacyScanQueryMatcher(scan, scanInfo, columnTracker, hasNullColumn, deletes,
389 scanType, readPointToUse, earliestPutTs, oldestUnexpiredTS, now);
390 } else {
391 return new LegacyScanQueryMatcher(scan, scanInfo, columnTracker, hasNullColumn, deletes,
392 scanType, readPointToUse, earliestPutTs, oldestUnexpiredTS, now, dropDeletesFromRow,
393 dropDeletesToRow);
394 }
395 }
396 }