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.row;
20
21 import org.apache.hadoop.hbase.classification.InterfaceAudience;
22 import org.apache.hadoop.hbase.codec.prefixtree.PrefixTreeBlockMeta;
23 import org.apache.hadoop.hbase.util.Bytes;
24 import org.apache.hadoop.hbase.util.SimpleMutableByteRange;
25 import org.apache.hadoop.hbase.util.vint.UFIntTool;
26 import org.apache.hadoop.hbase.util.vint.UVIntTool;
27
28
29
30
31
32 @InterfaceAudience.Private
33 public class RowNodeReader {
34
35
36
37 protected byte[] block;
38 protected int offset;
39 protected int fanIndex;
40
41 protected int numCells;
42
43 protected int tokenOffset;
44 protected int tokenLength;
45 protected int fanOffset;
46 protected int fanOut;
47
48 protected int familyOffsetsOffset;
49 protected int qualifierOffsetsOffset;
50 protected int timestampIndexesOffset;
51 protected int mvccVersionIndexesOffset;
52 protected int operationTypesOffset;
53 protected int valueOffsetsOffset;
54 protected int valueLengthsOffset;
55 protected int tagOffsetsOffset;
56 protected int nextNodeOffsetsOffset;
57
58
59
60
61 public void initOnBlock(PrefixTreeBlockMeta blockMeta, byte[] block, int offset) {
62 this.block = block;
63
64 this.offset = offset;
65 resetFanIndex();
66
67 this.tokenLength = UVIntTool.getInt(block, offset);
68 this.tokenOffset = offset + UVIntTool.numBytes(tokenLength);
69
70 this.fanOut = UVIntTool.getInt(block, tokenOffset + tokenLength);
71 this.fanOffset = tokenOffset + tokenLength + UVIntTool.numBytes(fanOut);
72
73 this.numCells = UVIntTool.getInt(block, fanOffset + fanOut);
74
75 this.familyOffsetsOffset = fanOffset + fanOut + UVIntTool.numBytes(numCells);
76 this.qualifierOffsetsOffset = familyOffsetsOffset + numCells * blockMeta.getFamilyOffsetWidth();
77 this.tagOffsetsOffset = this.qualifierOffsetsOffset + numCells * blockMeta.getQualifierOffsetWidth();
78
79 if(blockMeta.getTagsOffsetWidth() == 0) {
80
81 this.tagOffsetsOffset = this.qualifierOffsetsOffset;
82 this.timestampIndexesOffset = qualifierOffsetsOffset + numCells * blockMeta.getQualifierOffsetWidth();
83 } else {
84 this.timestampIndexesOffset = tagOffsetsOffset + numCells * blockMeta.getTagsOffsetWidth();
85 }
86 this.mvccVersionIndexesOffset = timestampIndexesOffset + numCells
87 * blockMeta.getTimestampIndexWidth();
88 this.operationTypesOffset = mvccVersionIndexesOffset + numCells
89 * blockMeta.getMvccVersionIndexWidth();
90 this.valueOffsetsOffset = operationTypesOffset + numCells * blockMeta.getKeyValueTypeWidth();
91 this.valueLengthsOffset = valueOffsetsOffset + numCells * blockMeta.getValueOffsetWidth();
92 this.nextNodeOffsetsOffset = valueLengthsOffset + numCells * blockMeta.getValueLengthWidth();
93 }
94
95
96
97
98 public boolean isLeaf() {
99 return fanOut == 0;
100 }
101
102 public boolean isNub() {
103 return fanOut > 0 && numCells > 0;
104 }
105
106 public boolean isBranch() {
107 return fanOut > 0 && numCells == 0;
108 }
109
110 public boolean hasOccurrences() {
111 return numCells > 0;
112 }
113
114 public int getTokenArrayOffset(){
115 return tokenOffset;
116 }
117
118 public int getTokenLength() {
119 return tokenLength;
120 }
121
122 public byte getFanByte(int i) {
123 return block[fanOffset + i];
124 }
125
126
127
128
129 protected String getFanByteReadable(int i){
130 return Bytes.toStringBinary(block, fanOffset + i, 1);
131 }
132
133 public int getFamilyOffset(int index, PrefixTreeBlockMeta blockMeta) {
134 int fIntWidth = blockMeta.getFamilyOffsetWidth();
135 int startIndex = familyOffsetsOffset + fIntWidth * index;
136 return (int) UFIntTool.fromBytes(block, startIndex, fIntWidth);
137 }
138
139 public int getColumnOffset(int index, PrefixTreeBlockMeta blockMeta) {
140 int fIntWidth = blockMeta.getQualifierOffsetWidth();
141 int startIndex = qualifierOffsetsOffset + fIntWidth * index;
142 return (int) UFIntTool.fromBytes(block, startIndex, fIntWidth);
143 }
144
145 public int getTagOffset(int index, PrefixTreeBlockMeta blockMeta) {
146 int fIntWidth = blockMeta.getTagsOffsetWidth();
147 int startIndex = tagOffsetsOffset + fIntWidth * index;
148 return (int) UFIntTool.fromBytes(block, startIndex, fIntWidth);
149 }
150
151 public int getTimestampIndex(int index, PrefixTreeBlockMeta blockMeta) {
152 int fIntWidth = blockMeta.getTimestampIndexWidth();
153 int startIndex = timestampIndexesOffset + fIntWidth * index;
154 return (int) UFIntTool.fromBytes(block, startIndex, fIntWidth);
155 }
156
157 public int getMvccVersionIndex(int index, PrefixTreeBlockMeta blockMeta) {
158 int fIntWidth = blockMeta.getMvccVersionIndexWidth();
159 int startIndex = mvccVersionIndexesOffset + fIntWidth * index;
160 return (int) UFIntTool.fromBytes(block, startIndex, fIntWidth);
161 }
162
163 public int getType(int index, PrefixTreeBlockMeta blockMeta) {
164 if (blockMeta.isAllSameType()) {
165 return blockMeta.getAllTypes();
166 }
167 return block[operationTypesOffset + index];
168 }
169
170 public int getValueOffset(int index, PrefixTreeBlockMeta blockMeta) {
171 int fIntWidth = blockMeta.getValueOffsetWidth();
172 int startIndex = valueOffsetsOffset + fIntWidth * index;
173 int offset = (int) UFIntTool.fromBytes(block, startIndex, fIntWidth);
174 return offset;
175 }
176
177 public int getValueLength(int index, PrefixTreeBlockMeta blockMeta) {
178 int fIntWidth = blockMeta.getValueLengthWidth();
179 int startIndex = valueLengthsOffset + fIntWidth * index;
180 int length = (int) UFIntTool.fromBytes(block, startIndex, fIntWidth);
181 return length;
182 }
183
184 public int getNextNodeOffset(int index, PrefixTreeBlockMeta blockMeta) {
185 int fIntWidth = blockMeta.getNextNodeOffsetWidth();
186 int startIndex = nextNodeOffsetsOffset + fIntWidth * index;
187 return (int) UFIntTool.fromBytes(block, startIndex, fIntWidth);
188 }
189
190 public String getBranchNubLeafIndicator() {
191 if (isNub()) {
192 return "N";
193 }
194 return isBranch() ? "B" : "L";
195 }
196
197 public boolean hasChildren() {
198 return fanOut > 0;
199 }
200
201 public int getLastFanIndex() {
202 return fanOut - 1;
203 }
204
205 public int getLastCellIndex() {
206 return numCells - 1;
207 }
208
209 public int getNumCells() {
210 return numCells;
211 }
212
213 public int getFanOut() {
214 return fanOut;
215 }
216
217 public byte[] getToken() {
218
219 return new SimpleMutableByteRange(block, tokenOffset, tokenLength).deepCopyToNewArray();
220 }
221
222 public int getOffset() {
223 return offset;
224 }
225
226 public int whichFanNode(byte searchForByte) {
227 if( ! hasFan()){
228 throw new IllegalStateException("This row node has no fan, so can't search it");
229 }
230 int fanIndexInBlock = Bytes.unsignedBinarySearch(block, fanOffset, fanOffset + fanOut,
231 searchForByte);
232 if (fanIndexInBlock >= 0) {
233 return fanIndexInBlock - fanOffset;
234 }
235 return fanIndexInBlock + fanOffset;
236 }
237
238 public void resetFanIndex() {
239 fanIndex = -1;
240 }
241
242 public int getFanIndex() {
243 return fanIndex;
244 }
245
246 public void setFanIndex(int fanIndex) {
247 this.fanIndex = fanIndex;
248 }
249
250 public boolean hasFan(){
251 return fanOut > 0;
252 }
253
254 public boolean hasPreviousFanNodes() {
255 return fanOut > 0 && fanIndex > 0;
256 }
257
258 public boolean hasMoreFanNodes() {
259 return fanIndex < getLastFanIndex();
260 }
261
262 public boolean isOnLastFanNode() {
263 return !hasMoreFanNodes();
264 }
265
266
267
268
269 @Override
270 public String toString() {
271 StringBuilder sb = new StringBuilder();
272 sb.append("fan:" + Bytes.toStringBinary(block, fanOffset, fanOut));
273 sb.append(",token:" + Bytes.toStringBinary(block, tokenOffset, tokenLength));
274 sb.append(",numCells:" + numCells);
275 sb.append(",fanIndex:"+fanIndex);
276 if(fanIndex>=0){
277 sb.append("("+getFanByteReadable(fanIndex)+")");
278 }
279 return sb.toString();
280 }
281 }