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.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.SimpleByteRange;
25  import org.apache.hadoop.hbase.util.vint.UFIntTool;
26  import org.apache.hadoop.hbase.util.vint.UVIntTool;
27  
28  /**
29   * Position one of these appropriately in the data block and you can call its methods to retrieve
30   * information necessary to decode the cells in the row.
31   */
32  @InterfaceAudience.Private
33  public class RowNodeReader {
34  
35    /************* fields ***********************************/
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    /******************* construct **************************/
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      // TODO : This code may not be needed now..As we always consider tags to be present
79      if(blockMeta.getTagsOffsetWidth() == 0) {
80        // Make both of them same so that we know that there are no tags
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    /******************** methods ****************************/
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    * for debugging
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     // TODO pass in reusable ByteRange
219     return new SimpleByteRange(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) {// found it, but need to adjust for position of fan in overall block
233       return fanIndexInBlock - fanOffset;
234     }
235     return fanIndexInBlock + fanOffset + 1;// 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:" + 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 }