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 java.io.IOException;
21
22 import org.apache.hadoop.hbase.Cell;
23 import org.apache.hadoop.hbase.HConstants;
24 import org.apache.hadoop.hbase.KeyValue;
25 import org.apache.hadoop.hbase.KeyValue.KVComparator;
26 import org.apache.hadoop.hbase.KeyValue.Type;
27 import org.apache.hadoop.hbase.KeyValueUtil;
28 import org.apache.hadoop.hbase.classification.InterfaceAudience;
29 import org.apache.hadoop.hbase.filter.Filter;
30 import org.apache.hadoop.hbase.regionserver.DeleteTracker;
31 import org.apache.hadoop.hbase.regionserver.DeleteTracker.DeleteResult;
32 import org.apache.hadoop.hbase.regionserver.HStore;
33 import org.apache.hadoop.hbase.regionserver.RegionCoprocessorHost;
34 import org.apache.hadoop.hbase.regionserver.ScanInfo;
35
36
37
38
39 @InterfaceAudience.Private
40 public abstract class ScanQueryMatcher {
41
42
43
44
45
46
47
48
49 public static enum MatchCode {
50
51
52
53 INCLUDE,
54
55
56
57
58 SKIP,
59
60
61
62
63 NEXT,
64
65
66
67
68 DONE,
69
70
71
72
73
74
75
76
77 SEEK_NEXT_ROW,
78
79
80
81
82 SEEK_NEXT_COL,
83
84
85
86
87 DONE_SCAN,
88
89
90
91
92 SEEK_NEXT_USING_HINT,
93
94
95
96
97 INCLUDE_AND_SEEK_NEXT_COL,
98
99
100
101
102 INCLUDE_AND_SEEK_NEXT_ROW,
103 }
104
105
106 protected final KVComparator rowComparator;
107
108
109 protected final Cell startKey;
110
111
112 protected final ColumnTracker columns;
113
114
115 protected final long oldestUnexpiredTS;
116
117 protected final long now;
118
119
120 protected Cell currentRow;
121
122 protected ScanQueryMatcher(Cell startKey, ScanInfo scanInfo, ColumnTracker columns,
123 long oldestUnexpiredTS, long now) {
124 this.rowComparator = scanInfo.getComparator();
125 this.startKey = startKey;
126 this.oldestUnexpiredTS = oldestUnexpiredTS;
127 this.now = now;
128 this.columns = columns;
129 }
130
131 protected static Cell createStartKeyFromRow(byte[] startRow, ScanInfo scanInfo) {
132 return KeyValueUtil.createFirstDeleteFamilyOnRow(startRow, scanInfo.getFamily());
133 }
134
135
136
137
138
139 protected final MatchCode preCheck(Cell cell) {
140 if (currentRow == null) {
141
142
143 return MatchCode.DONE;
144 }
145
146 if (rowComparator.compareRows(currentRow, cell) != 0) {
147 return MatchCode.DONE;
148 }
149
150 if (this.columns.done()) {
151 return MatchCode.SEEK_NEXT_ROW;
152 }
153
154 long timestamp = cell.getTimestamp();
155
156
157
158 if (timestamp == HConstants.OLDEST_TIMESTAMP || columns.isDone(timestamp)) {
159 return columns.getNextRowOrNextColumn(cell.getQualifierArray(), cell.getQualifierOffset(),
160 cell.getQualifierLength());
161 }
162
163 if (HStore.isCellTTLExpired(cell, this.oldestUnexpiredTS, this.now)) {
164 return MatchCode.SKIP;
165 }
166 return null;
167 }
168
169 protected final MatchCode checkDeleted(DeleteTracker deletes, Cell cell) {
170 if (deletes.isEmpty()) {
171 return null;
172 }
173 DeleteResult deleteResult = deletes.isDeleted(cell);
174 switch (deleteResult) {
175 case FAMILY_DELETED:
176 case COLUMN_DELETED:
177 return columns.getNextRowOrNextColumn(cell.getQualifierArray(), cell.getQualifierOffset(),
178 cell.getQualifierLength());
179 case VERSION_DELETED:
180 case FAMILY_VERSION_DELETED:
181 return MatchCode.SKIP;
182 case NOT_DELETED:
183 return null;
184 default:
185 throw new RuntimeException("Unexpected delete result: " + deleteResult);
186 }
187 }
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203 public abstract MatchCode match(Cell cell) throws IOException;
204
205
206
207
208 public Cell getStartKey() {
209 return startKey;
210 }
211
212
213
214
215 public abstract boolean hasNullColumnInQuery();
216
217
218
219
220 public Cell currentRow() {
221 return currentRow;
222 }
223
224
225
226
227 public void clearCurrentRow() {
228 currentRow = null;
229 }
230
231 protected abstract void reset();
232
233
234
235
236
237 public void setToNewRow(Cell currentRow) {
238 this.currentRow = currentRow;
239 columns.reset();
240 reset();
241 }
242
243 public abstract boolean isUserScan();
244
245
246
247
248
249
250 public abstract boolean moreRowsMayExistAfter(Cell cell);
251
252 public Cell getKeyForNextColumn(Cell cell) {
253
254
255
256
257
258 if (cell.getQualifierLength() == 0) {
259 Cell nextKey = createNextOnRowCol(cell);
260 if (nextKey != cell) {
261 return nextKey;
262 }
263
264
265 }
266 ColumnCount nextColumn = columns.getColumnHint();
267 if (nextColumn == null) {
268 return KeyValueUtil.createLastOnRow(cell.getRowArray(), cell.getRowOffset(),
269 cell.getRowLength(), cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength(),
270 cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength());
271 } else {
272 return KeyValueUtil.createFirstOnRow(cell.getRowArray(), cell.getRowOffset(),
273 cell.getRowLength(), cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength(),
274 nextColumn.getBuffer(), nextColumn.getOffset(), nextColumn.getLength());
275 }
276 }
277
278
279
280
281
282
283 public int compareKeyForNextRow(Cell nextIndexed, Cell currentCell) {
284 return rowComparator.compareKey(nextIndexed, currentCell.getRowArray(),
285 currentCell.getRowOffset(), currentCell.getRowLength(), null, 0, 0, null, 0, 0,
286 HConstants.OLDEST_TIMESTAMP, Type.Minimum.getCode());
287 }
288
289
290
291
292
293
294 public int compareKeyForNextColumn(Cell nextIndexed, Cell currentCell) {
295 ColumnCount nextColumn = columns.getColumnHint();
296 if (nextColumn == null) {
297 return rowComparator.compareKey(nextIndexed, currentCell.getRowArray(),
298 currentCell.getRowOffset(), currentCell.getRowLength(), currentCell.getFamilyArray(),
299 currentCell.getFamilyOffset(), currentCell.getFamilyLength(),
300 currentCell.getQualifierArray(), currentCell.getQualifierOffset(),
301 currentCell.getQualifierLength(), HConstants.OLDEST_TIMESTAMP, Type.Minimum.getCode());
302 } else {
303 return rowComparator.compareKey(nextIndexed, currentCell.getRowArray(),
304 currentCell.getRowOffset(), currentCell.getRowLength(), currentCell.getFamilyArray(),
305 currentCell.getFamilyOffset(), currentCell.getFamilyLength(), nextColumn.getBuffer(),
306 nextColumn.getOffset(), nextColumn.getLength(), HConstants.LATEST_TIMESTAMP,
307 Type.Maximum.getCode());
308 }
309 }
310
311
312
313
314 public abstract Filter getFilter();
315
316
317
318
319 public abstract Cell getNextKeyHint(Cell cell) throws IOException;
320
321 protected static DeleteTracker instantiateDeleteTracker(RegionCoprocessorHost host)
322 throws IOException {
323 DeleteTracker tracker = new ScanDeleteTracker();
324 if (host != null) {
325 tracker = host.postInstantiateDeleteTracker(tracker);
326 }
327 return tracker;
328 }
329
330
331 static MatchCode checkColumn(ColumnTracker columnTracker, byte[] bytes, int offset, int length,
332 long ttl, byte type, boolean ignoreCount) throws IOException {
333 MatchCode matchCode = columnTracker.checkColumn(bytes, offset, length, type);
334 if (matchCode == MatchCode.INCLUDE) {
335 return columnTracker.checkVersions(bytes, offset, length, ttl, type, ignoreCount);
336 }
337 return matchCode;
338 }
339
340
341
342
343
344 private static Cell createNextOnRowCol(Cell cell) {
345 long ts = cell.getTimestamp();
346 byte type = cell.getTypeByte();
347 if (type != Type.Minimum.getCode()) {
348 type = KeyValue.Type.values()[KeyValue.Type.codeToType(type).ordinal() - 1].getCode();
349 } else if (ts != HConstants.OLDEST_TIMESTAMP) {
350 ts = ts - 1;
351 type = Type.Maximum.getCode();
352 } else {
353 return cell;
354 }
355 return createNextOnRowCol(cell, ts, type);
356 }
357
358 private static Cell createNextOnRowCol(final Cell cell, final long ts, final byte type) {
359 return new Cell() {
360 @Override
361 public byte[] getRowArray() { return cell.getRowArray(); }
362
363 @Override
364 public int getRowOffset() { return cell.getRowOffset(); }
365
366 @Override
367 public short getRowLength() { return cell.getRowLength(); }
368
369 @Override
370 public byte[] getFamilyArray() { return cell.getFamilyArray(); }
371
372 @Override
373 public int getFamilyOffset() { return cell.getFamilyOffset(); }
374
375 @Override
376 public byte getFamilyLength() { return cell.getFamilyLength(); }
377
378 @Override
379 public byte[] getQualifierArray() { return cell.getQualifierArray(); }
380
381 @Override
382 public int getQualifierOffset() { return cell.getQualifierOffset(); }
383
384 @Override
385 public int getQualifierLength() { return cell.getQualifierLength(); }
386
387 @Override
388 public long getTimestamp() { return ts; }
389
390 @Override
391 public byte getTypeByte() {return type; }
392
393 @Override
394 public long getMvccVersion() { return cell.getMvccVersion(); }
395
396 @Override
397 public long getSequenceId() { return cell.getSequenceId(); }
398
399 @Override
400 public byte[] getValueArray() { return cell.getValueArray(); }
401
402 @Override
403 public int getValueOffset() { return cell.getValueOffset(); }
404
405 @Override
406 public int getValueLength() { return cell.getValueLength(); }
407
408 @Override
409 public byte[] getTagsArray() { return cell.getTagsArray(); }
410
411 @Override
412 public int getTagsOffset() { return cell.getTagsOffset(); }
413
414 @Override
415 public int getTagsLength() { return cell.getTagsLength(); }
416
417 @Override
418 public byte[] getValue() { return cell.getValue(); }
419
420 @Override
421 public byte[] getFamily() { return cell.getFamily(); }
422
423 @Override
424 public byte[] getQualifier() { return cell.getQualifier(); }
425
426 @Override
427 public byte[] getRow() {return cell.getRow(); }
428 };
429 }
430 }