1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.codec.prefixtree.decode;
20
21 import org.apache.hadoop.hbase.classification.InterfaceAudience;
22 import org.apache.hadoop.hbase.Cell;
23 import org.apache.hadoop.hbase.CellComparator;
24 import org.apache.hadoop.hbase.CellScanner;
25 import org.apache.hadoop.hbase.codec.prefixtree.PrefixTreeBlockMeta;
26 import org.apache.hadoop.hbase.codec.prefixtree.decode.column.ColumnReader;
27 import org.apache.hadoop.hbase.codec.prefixtree.decode.row.RowNodeReader;
28 import org.apache.hadoop.hbase.codec.prefixtree.decode.timestamp.MvccVersionDecoder;
29 import org.apache.hadoop.hbase.codec.prefixtree.decode.timestamp.TimestampDecoder;
30 import org.apache.hadoop.hbase.codec.prefixtree.encode.other.ColumnNodeType;
31
32
33
34
35
36
37
38
39
40
41 @InterfaceAudience.Private
42 public class PrefixTreeArrayScanner extends PrefixTreeCell implements CellScanner {
43
44
45
46 protected PrefixTreeBlockMeta blockMeta;
47
48 protected boolean beforeFirst;
49 protected boolean afterLast;
50
51 protected RowNodeReader[] rowNodes;
52 protected int rowNodeStackIndex;
53
54 protected RowNodeReader currentRowNode;
55 protected ColumnReader familyReader;
56 protected ColumnReader qualifierReader;
57 protected ColumnReader tagsReader;
58 protected TimestampDecoder timestampDecoder;
59 protected MvccVersionDecoder mvccVersionDecoder;
60
61 protected boolean nubCellsRemain;
62 protected int currentCellIndex;
63
64
65
66
67
68 public PrefixTreeArrayScanner(PrefixTreeBlockMeta blockMeta, int rowTreeDepth,
69 int rowBufferLength, int qualifierBufferLength, int tagsBufferLength) {
70 this.rowNodes = new RowNodeReader[rowTreeDepth];
71 for (int i = 0; i < rowNodes.length; ++i) {
72 rowNodes[i] = new RowNodeReader();
73 }
74 this.rowBuffer = new byte[rowBufferLength];
75 this.familyBuffer = new byte[PrefixTreeBlockMeta.MAX_FAMILY_LENGTH];
76 this.familyReader = new ColumnReader(familyBuffer, ColumnNodeType.FAMILY);
77 this.qualifierBuffer = new byte[qualifierBufferLength];
78 this.tagsBuffer = new byte[tagsBufferLength];
79 this.qualifierReader = new ColumnReader(qualifierBuffer, ColumnNodeType.QUALIFIER);
80 this.tagsReader = new ColumnReader(tagsBuffer, ColumnNodeType.TAGS);
81 this.timestampDecoder = new TimestampDecoder();
82 this.mvccVersionDecoder = new MvccVersionDecoder();
83 }
84
85
86
87
88
89
90
91
92 public boolean areBuffersBigEnough() {
93 if (rowNodes.length < blockMeta.getRowTreeDepth()) {
94 return false;
95 }
96 if (rowBuffer.length < blockMeta.getMaxRowLength()) {
97 return false;
98 }
99 if (qualifierBuffer.length < blockMeta.getMaxQualifierLength()) {
100 return false;
101 }
102 if(tagsBuffer.length < blockMeta.getMaxTagsLength()) {
103 return false;
104 }
105 return true;
106 }
107
108 public void initOnBlock(PrefixTreeBlockMeta blockMeta, byte[] block,
109 boolean includeMvccVersion) {
110 this.block = block;
111 this.blockMeta = blockMeta;
112 this.familyOffset = familyBuffer.length;
113 this.familyReader.initOnBlock(blockMeta, block);
114 this.qualifierOffset = qualifierBuffer.length;
115 this.qualifierReader.initOnBlock(blockMeta, block);
116 this.tagsOffset = tagsBuffer.length;
117 this.tagsReader.initOnBlock(blockMeta, block);
118 this.timestampDecoder.initOnBlock(blockMeta, block);
119 this.mvccVersionDecoder.initOnBlock(blockMeta, block);
120 this.includeMvccVersion = includeMvccVersion;
121 resetToBeforeFirstEntry();
122 }
123
124
125 public void resetToBeforeFirstEntry() {
126 beforeFirst = true;
127 afterLast = false;
128 rowNodeStackIndex = -1;
129 currentRowNode = null;
130 rowLength = 0;
131 familyOffset = familyBuffer.length;
132 familyLength = 0;
133 qualifierOffset = blockMeta.getMaxQualifierLength();
134 qualifierLength = 0;
135 nubCellsRemain = false;
136 currentCellIndex = -1;
137 timestamp = -1L;
138 type = DEFAULT_TYPE;
139 absoluteValueOffset = 0;
140 valueLength = 0;
141 tagsOffset = blockMeta.getMaxTagsLength();
142 tagsLength = 0;
143 }
144
145
146
147
148
149 public void releaseBlockReference(){
150 block = null;
151 }
152
153
154
155
156 @Override
157 public Cell current() {
158 if(isOutOfBounds()){
159 return null;
160 }
161 return (Cell)this;
162 }
163
164
165
166 @Override
167 public boolean equals(Object obj) {
168
169 return super.equals(obj);
170 }
171
172 @Override
173 public int hashCode() {
174 return super.hashCode();
175 }
176
177
178
179
180 @Override
181 public String toString() {
182 Cell currentCell = current();
183 if(currentCell==null){
184 return "null";
185 }
186 return ((PrefixTreeCell)currentCell).getKeyValueString();
187 }
188
189
190
191
192 public boolean positionAtFirstCell() {
193 reInitFirstNode();
194 return advance();
195 }
196
197 @Override
198 public boolean advance() {
199 if (afterLast) {
200 return false;
201 }
202 if (!hasOccurrences()) {
203 resetToBeforeFirstEntry();
204 }
205 if (beforeFirst || isLastCellInRow()) {
206 nextRow();
207 if (afterLast) {
208 return false;
209 }
210 } else {
211 ++currentCellIndex;
212 }
213
214 populateNonRowFields(currentCellIndex);
215 return true;
216 }
217
218
219 public boolean nextRow() {
220 nextRowInternal();
221 if (afterLast) {
222 return false;
223 }
224 populateNonRowFields(currentCellIndex);
225 return true;
226 }
227
228
229
230
231
232
233
234 protected boolean nextRowInternal() {
235 if (afterLast) {
236 return false;
237 }
238 if (beforeFirst) {
239 initFirstNode();
240 if (currentRowNode.hasOccurrences()) {
241 if (currentRowNode.isNub()) {
242 nubCellsRemain = true;
243 }
244 currentCellIndex = 0;
245 return true;
246 }
247 }
248 if (currentRowNode.isLeaf()) {
249 discardCurrentRowNode(true);
250 }
251 while (!afterLast) {
252 if (nubCellsRemain) {
253 nubCellsRemain = false;
254 }
255 if (currentRowNode.hasMoreFanNodes()) {
256 followNextFan();
257 if (currentRowNode.hasOccurrences()) {
258
259 currentCellIndex = 0;
260 return true;
261 }
262 } else {
263 discardCurrentRowNode(true);
264 }
265 }
266 return false;
267 }
268
269
270
271
272 protected void reInitFirstNode() {
273 resetToBeforeFirstEntry();
274 initFirstNode();
275 }
276
277 protected void initFirstNode() {
278 int offsetIntoUnderlyingStructure = blockMeta.getAbsoluteRowOffset();
279 rowNodeStackIndex = 0;
280 currentRowNode = rowNodes[0];
281 currentRowNode.initOnBlock(blockMeta, block, offsetIntoUnderlyingStructure);
282 appendCurrentTokenToRowBuffer();
283 beforeFirst = false;
284 }
285
286 protected void followFirstFan() {
287 followFan(0);
288 }
289
290 protected void followPreviousFan() {
291 int nextFanPosition = currentRowNode.getFanIndex() - 1;
292 followFan(nextFanPosition);
293 }
294
295 protected void followCurrentFan() {
296 int currentFanPosition = currentRowNode.getFanIndex();
297 followFan(currentFanPosition);
298 }
299
300 protected void followNextFan() {
301 int nextFanPosition = currentRowNode.getFanIndex() + 1;
302 followFan(nextFanPosition);
303 }
304
305 protected void followLastFan() {
306 followFan(currentRowNode.getLastFanIndex());
307 }
308
309 protected void followFan(int fanIndex) {
310 currentRowNode.setFanIndex(fanIndex);
311 appendToRowBuffer(currentRowNode.getFanByte(fanIndex));
312
313 int nextOffsetIntoUnderlyingStructure = currentRowNode.getOffset()
314 + currentRowNode.getNextNodeOffset(fanIndex, blockMeta);
315 ++rowNodeStackIndex;
316
317 currentRowNode = rowNodes[rowNodeStackIndex];
318 currentRowNode.initOnBlock(blockMeta, block, nextOffsetIntoUnderlyingStructure);
319
320
321 appendCurrentTokenToRowBuffer();
322 if (currentRowNode.isNub()) {
323 nubCellsRemain = true;
324 }
325 currentCellIndex = 0;
326 }
327
328
329
330
331 protected void discardCurrentRowNode(boolean forwards) {
332 RowNodeReader rowNodeBeingPopped = currentRowNode;
333 --rowNodeStackIndex;
334 if (rowNodeStackIndex < 0) {
335 currentRowNode = null;
336 if (forwards) {
337 markAfterLast();
338 } else {
339 markBeforeFirst();
340 }
341 return;
342 }
343 popFromRowBuffer(rowNodeBeingPopped);
344 currentRowNode = rowNodes[rowNodeStackIndex];
345 }
346
347 protected void markBeforeFirst() {
348 beforeFirst = true;
349 afterLast = false;
350 currentRowNode = null;
351 }
352
353 protected void markAfterLast() {
354 beforeFirst = false;
355 afterLast = true;
356 currentRowNode = null;
357 }
358
359
360
361
362 protected void appendCurrentTokenToRowBuffer() {
363 System.arraycopy(block, currentRowNode.getTokenArrayOffset(), rowBuffer, rowLength,
364 currentRowNode.getTokenLength());
365 rowLength += currentRowNode.getTokenLength();
366 }
367
368 protected void appendToRowBuffer(byte b) {
369 rowBuffer[rowLength] = b;
370 ++rowLength;
371 }
372
373 protected void popFromRowBuffer(RowNodeReader rowNodeBeingPopped) {
374 rowLength -= rowNodeBeingPopped.getTokenLength();
375 --rowLength;
376 }
377
378 protected boolean hasOccurrences() {
379 return currentRowNode != null && currentRowNode.hasOccurrences();
380 }
381
382 protected boolean isBranch() {
383 return currentRowNode != null && !currentRowNode.hasOccurrences()
384 && currentRowNode.hasChildren();
385 }
386
387 protected boolean isNub() {
388 return currentRowNode != null && currentRowNode.hasOccurrences()
389 && currentRowNode.hasChildren();
390 }
391
392 protected boolean isLeaf() {
393 return currentRowNode != null && currentRowNode.hasOccurrences()
394 && !currentRowNode.hasChildren();
395 }
396
397
398 public boolean isBeforeFirst(){
399 return beforeFirst;
400 }
401
402 public boolean isAfterLast(){
403 return afterLast;
404 }
405
406 protected boolean isOutOfBounds(){
407 return beforeFirst || afterLast;
408 }
409
410 protected boolean isFirstCellInRow() {
411 return currentCellIndex == 0;
412 }
413
414 protected boolean isLastCellInRow() {
415 return currentCellIndex == currentRowNode.getLastCellIndex();
416 }
417
418
419
420
421 protected int populateNonRowFieldsAndCompareTo(int cellNum, Cell key) {
422 populateNonRowFields(cellNum);
423 return CellComparator.compare(this, key, true);
424 }
425
426 protected void populateFirstNonRowFields() {
427 populateNonRowFields(0);
428 }
429
430 protected void populatePreviousNonRowFields() {
431 populateNonRowFields(currentCellIndex - 1);
432 }
433
434 protected void populateLastNonRowFields() {
435 populateNonRowFields(currentRowNode.getLastCellIndex());
436 }
437
438 protected void populateNonRowFields(int cellIndex) {
439 currentCellIndex = cellIndex;
440 populateFamily();
441 populateQualifier();
442
443 if(blockMeta.getNumTagsBytes() != 0) {
444 populateTag();
445 }
446 populateTimestamp();
447 populateMvccVersion();
448 populateType();
449 populateValueOffsets();
450 }
451
452 protected void populateFamily() {
453 int familyTreeIndex = currentRowNode.getFamilyOffset(currentCellIndex, blockMeta);
454 familyOffset = familyReader.populateBuffer(familyTreeIndex).getColumnOffset();
455 familyLength = familyReader.getColumnLength();
456 }
457
458 protected void populateQualifier() {
459 int qualifierTreeIndex = currentRowNode.getColumnOffset(currentCellIndex, blockMeta);
460 qualifierOffset = qualifierReader.populateBuffer(qualifierTreeIndex).getColumnOffset();
461 qualifierLength = qualifierReader.getColumnLength();
462 }
463
464 protected void populateTag() {
465 int tagTreeIndex = currentRowNode.getTagOffset(currentCellIndex, blockMeta);
466 tagsOffset = tagsReader.populateBuffer(tagTreeIndex).getColumnOffset();
467 tagsLength = tagsReader.getColumnLength();
468 }
469
470 protected void populateTimestamp() {
471 if (blockMeta.isAllSameTimestamp()) {
472 timestamp = blockMeta.getMinTimestamp();
473 } else {
474 int timestampIndex = currentRowNode.getTimestampIndex(currentCellIndex, blockMeta);
475 timestamp = timestampDecoder.getLong(timestampIndex);
476 }
477 }
478
479 protected void populateMvccVersion() {
480 if (blockMeta.isAllSameMvccVersion()) {
481 mvccVersion = blockMeta.getMinMvccVersion();
482 } else {
483 int mvccVersionIndex = currentRowNode.getMvccVersionIndex(currentCellIndex,
484 blockMeta);
485 mvccVersion = mvccVersionDecoder.getMvccVersion(mvccVersionIndex);
486 }
487 }
488
489 protected void populateType() {
490 int typeInt;
491 if (blockMeta.isAllSameType()) {
492 typeInt = blockMeta.getAllTypes();
493 } else {
494 typeInt = currentRowNode.getType(currentCellIndex, blockMeta);
495 }
496 type = PrefixTreeCell.TYPES[typeInt];
497 }
498
499 protected void populateValueOffsets() {
500 int offsetIntoValueSection = currentRowNode.getValueOffset(currentCellIndex, blockMeta);
501 absoluteValueOffset = blockMeta.getAbsoluteValueOffset() + offsetIntoValueSection;
502 valueLength = currentRowNode.getValueLength(currentCellIndex, blockMeta);
503 }
504
505
506
507 public byte[] getTreeBytes() {
508 return block;
509 }
510
511 public PrefixTreeBlockMeta getBlockMeta() {
512 return blockMeta;
513 }
514
515 public int getMaxRowTreeStackNodes() {
516 return rowNodes.length;
517 }
518
519 public int getRowBufferLength() {
520 return rowBuffer.length;
521 }
522
523 public int getQualifierBufferLength() {
524 return qualifierBuffer.length;
525 }
526
527 public int getTagBufferLength() {
528 return tagsBuffer.length;
529 }
530 }