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.ByteRange;
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   * 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 nextNodeOffsetsOffset;
56  
57  
58    /******************* construct **************************/
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    /******************** methods ****************************/
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    * for debugging
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     // TODO pass in reusable ByteRange
205     return new ByteRange(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) {// found it, but need to adjust for position of fan in overall block
219       return fanIndexInBlock - fanOffset;
220     }
221     return fanIndexInBlock + fanOffset + 1;// didn't find it, so compensate in reverse
222   }
223 
224   public void resetFanIndex() {
225     fanIndex = -1;// just the way the logic currently works
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   /*************** standard methods **************************/
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 }