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