View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
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.nio.ByteBuff;
24  import org.apache.hadoop.hbase.util.vint.UFIntTool;
25  import org.apache.hadoop.hbase.util.vint.UVIntTool;
26  
27  /**
28   * Position one of these appropriately in the data block and you can call its methods to retrieve
29   * information necessary to decode the cells in the row.
30   */
31  @InterfaceAudience.Private
32  public class RowNodeReader {
33  
34    /************* fields ***********************************/
35  
36    protected ByteBuff block;
37    protected int offset;
38    protected int fanIndex;
39  
40    protected int numCells;
41  
42    protected int tokenOffset;
43    protected int tokenLength;
44    protected int fanOffset;
45    protected int fanOut;
46  
47    protected int familyOffsetsOffset;
48    protected int qualifierOffsetsOffset;
49    protected int timestampIndexesOffset;
50    protected int mvccVersionIndexesOffset;
51    protected int operationTypesOffset;
52    protected int valueOffsetsOffset;
53    protected int valueLengthsOffset;
54    protected int tagOffsetsOffset;
55    protected int nextNodeOffsetsOffset;
56  
57  
58    /******************* construct **************************/
59  
60    public void initOnBlock(PrefixTreeBlockMeta blockMeta, ByteBuff 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.tagOffsetsOffset = this.qualifierOffsetsOffset + numCells * blockMeta.getQualifierOffsetWidth();
77      // TODO : This code may not be needed now..As we always consider tags to be present
78      if(blockMeta.getTagsOffsetWidth() == 0) {
79        // Make both of them same so that we know that there are no tags
80        this.tagOffsetsOffset = this.qualifierOffsetsOffset;
81        this.timestampIndexesOffset = qualifierOffsetsOffset + numCells * blockMeta.getQualifierOffsetWidth();
82      } else {
83        this.timestampIndexesOffset = tagOffsetsOffset + numCells * blockMeta.getTagsOffsetWidth();
84      }
85      this.mvccVersionIndexesOffset = timestampIndexesOffset + numCells
86          * blockMeta.getTimestampIndexWidth();
87      this.operationTypesOffset = mvccVersionIndexesOffset + numCells
88          * blockMeta.getMvccVersionIndexWidth();
89      this.valueOffsetsOffset = operationTypesOffset + numCells * blockMeta.getKeyValueTypeWidth();
90      this.valueLengthsOffset = valueOffsetsOffset + numCells * blockMeta.getValueOffsetWidth();
91      this.nextNodeOffsetsOffset = valueLengthsOffset + numCells * blockMeta.getValueLengthWidth();
92    }
93  
94  
95    /******************** methods ****************************/
96  
97    public boolean isLeaf() {
98      return fanOut == 0;
99    }
100 
101   public boolean isNub() {
102     return fanOut > 0 && numCells > 0;
103   }
104 
105   public boolean isBranch() {
106     return fanOut > 0 && numCells == 0;
107   }
108 
109   public boolean hasOccurrences() {
110     return numCells > 0;
111   }
112 
113   public int getTokenArrayOffset(){
114     return tokenOffset;
115   }
116 
117   public int getTokenLength() {
118     return tokenLength;
119   }
120 
121   public byte getFanByte(int i) {
122     return block.get(fanOffset + i);
123   }
124   
125   /**
126    * for debugging
127    */
128   protected String getFanByteReadable(int i){
129     return ByteBuff.toStringBinary(block, fanOffset + i, 1);
130   }
131 
132   public int getFamilyOffset(int index, PrefixTreeBlockMeta blockMeta) {
133     int fIntWidth = blockMeta.getFamilyOffsetWidth();
134     int startIndex = familyOffsetsOffset + fIntWidth * index;
135     return (int) UFIntTool.fromBytes(block, startIndex, fIntWidth);
136   }
137 
138   public int getColumnOffset(int index, PrefixTreeBlockMeta blockMeta) {
139     int fIntWidth = blockMeta.getQualifierOffsetWidth();
140     int startIndex = qualifierOffsetsOffset + fIntWidth * index;
141     return (int) UFIntTool.fromBytes(block, startIndex, fIntWidth);
142   }
143 
144   public int getTagOffset(int index, PrefixTreeBlockMeta blockMeta) {
145     int fIntWidth = blockMeta.getTagsOffsetWidth();
146     int startIndex = tagOffsetsOffset + fIntWidth * index;
147     return (int) UFIntTool.fromBytes(block, startIndex, fIntWidth);
148   }
149 
150   public int getTimestampIndex(int index, PrefixTreeBlockMeta blockMeta) {
151     int fIntWidth = blockMeta.getTimestampIndexWidth();
152     int startIndex = timestampIndexesOffset + fIntWidth * index;
153     return (int) UFIntTool.fromBytes(block, startIndex, fIntWidth);
154   }
155 
156   public int getMvccVersionIndex(int index, PrefixTreeBlockMeta blockMeta) {
157     int fIntWidth = blockMeta.getMvccVersionIndexWidth();
158     int startIndex = mvccVersionIndexesOffset + fIntWidth * index;
159     return (int) UFIntTool.fromBytes(block, startIndex, fIntWidth);
160   }
161 
162   public int getType(int index, PrefixTreeBlockMeta blockMeta) {
163     if (blockMeta.isAllSameType()) {
164       return blockMeta.getAllTypes();
165     }
166     return block.get(operationTypesOffset + index);
167   }
168 
169   public int getValueOffset(int index, PrefixTreeBlockMeta blockMeta) {
170     int fIntWidth = blockMeta.getValueOffsetWidth();
171     int startIndex = valueOffsetsOffset + fIntWidth * index;
172     int offset = (int) UFIntTool.fromBytes(block, startIndex, fIntWidth);
173     return offset;
174   }
175 
176   public int getValueLength(int index, PrefixTreeBlockMeta blockMeta) {
177     int fIntWidth = blockMeta.getValueLengthWidth();
178     int startIndex = valueLengthsOffset + fIntWidth * index;
179     int length = (int) UFIntTool.fromBytes(block, startIndex, fIntWidth);
180     return length;
181   }
182 
183   public int getNextNodeOffset(int index, PrefixTreeBlockMeta blockMeta) {
184     int fIntWidth = blockMeta.getNextNodeOffsetWidth();
185     int startIndex = nextNodeOffsetsOffset + fIntWidth * index;
186     return (int) UFIntTool.fromBytes(block, startIndex, fIntWidth);
187   }
188 
189   public String getBranchNubLeafIndicator() {
190     if (isNub()) {
191       return "N";
192     }
193     return isBranch() ? "B" : "L";
194   }
195 
196   public boolean hasChildren() {
197     return fanOut > 0;
198   }
199 
200   public int getLastFanIndex() {
201     return fanOut - 1;
202   }
203 
204   public int getLastCellIndex() {
205     return numCells - 1;
206   }
207 
208   public int getNumCells() {
209     return numCells;
210   }
211 
212   public int getFanOut() {
213     return fanOut;
214   }
215 
216   public byte[] getToken() {
217     byte[] newToken = new byte[tokenLength];
218     block.get(tokenOffset, newToken, 0, tokenLength);
219     return newToken;
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 = ByteBuff.unsignedBinarySearch(block, fanOffset, fanOffset + fanOut,
231       searchForByte);
232     if (fanIndexInBlock >= 0) {// found it, but need to adjust for position of fan in overall block
233       return fanIndexInBlock - fanOffset;
234     }
235     return fanIndexInBlock + fanOffset;// didn't find it, so compensate in reverse
236   }
237 
238   public void resetFanIndex() {
239     fanIndex = -1;// just the way the logic currently works
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   /*************** standard methods **************************/
268 
269   @Override
270   public String toString() {
271     StringBuilder sb = new StringBuilder();
272     sb.append("fan:" + ByteBuff.toStringBinary(block, fanOffset, fanOut));
273     sb.append(",token:" + ByteBuff.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 }