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.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 * 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 initOnBlock(PrefixTreeBlockMeta blockMeta, byte[] block, int offset)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 isLeaf()98 public boolean isLeaf() { 99 return fanOut == 0; 100 } 101 isNub()102 public boolean isNub() { 103 return fanOut > 0 && numCells > 0; 104 } 105 isBranch()106 public boolean isBranch() { 107 return fanOut > 0 && numCells == 0; 108 } 109 hasOccurrences()110 public boolean hasOccurrences() { 111 return numCells > 0; 112 } 113 getTokenArrayOffset()114 public int getTokenArrayOffset(){ 115 return tokenOffset; 116 } 117 getTokenLength()118 public int getTokenLength() { 119 return tokenLength; 120 } 121 getFanByte(int i)122 public byte getFanByte(int i) { 123 return block[fanOffset + i]; 124 } 125 126 /** 127 * for debugging 128 */ getFanByteReadable(int i)129 protected String getFanByteReadable(int i){ 130 return Bytes.toStringBinary(block, fanOffset + i, 1); 131 } 132 getFamilyOffset(int index, PrefixTreeBlockMeta blockMeta)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 getColumnOffset(int index, PrefixTreeBlockMeta blockMeta)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 getTagOffset(int index, PrefixTreeBlockMeta blockMeta)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 getTimestampIndex(int index, PrefixTreeBlockMeta blockMeta)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 getMvccVersionIndex(int index, PrefixTreeBlockMeta blockMeta)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 getType(int index, PrefixTreeBlockMeta blockMeta)163 public int getType(int index, PrefixTreeBlockMeta blockMeta) { 164 if (blockMeta.isAllSameType()) { 165 return blockMeta.getAllTypes(); 166 } 167 return block[operationTypesOffset + index]; 168 } 169 getValueOffset(int index, PrefixTreeBlockMeta blockMeta)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 getValueLength(int index, PrefixTreeBlockMeta blockMeta)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 getNextNodeOffset(int index, PrefixTreeBlockMeta blockMeta)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 getBranchNubLeafIndicator()190 public String getBranchNubLeafIndicator() { 191 if (isNub()) { 192 return "N"; 193 } 194 return isBranch() ? "B" : "L"; 195 } 196 hasChildren()197 public boolean hasChildren() { 198 return fanOut > 0; 199 } 200 getLastFanIndex()201 public int getLastFanIndex() { 202 return fanOut - 1; 203 } 204 getLastCellIndex()205 public int getLastCellIndex() { 206 return numCells - 1; 207 } 208 getNumCells()209 public int getNumCells() { 210 return numCells; 211 } 212 getFanOut()213 public int getFanOut() { 214 return fanOut; 215 } 216 getToken()217 public byte[] getToken() { 218 // TODO pass in reusable ByteRange 219 return new SimpleMutableByteRange(block, tokenOffset, tokenLength).deepCopyToNewArray(); 220 } 221 getOffset()222 public int getOffset() { 223 return offset; 224 } 225 whichFanNode(byte searchForByte)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;// didn't find it, so compensate in reverse 236 } 237 resetFanIndex()238 public void resetFanIndex() { 239 fanIndex = -1;// just the way the logic currently works 240 } 241 getFanIndex()242 public int getFanIndex() { 243 return fanIndex; 244 } 245 setFanIndex(int fanIndex)246 public void setFanIndex(int fanIndex) { 247 this.fanIndex = fanIndex; 248 } 249 hasFan()250 public boolean hasFan(){ 251 return fanOut > 0; 252 } 253 hasPreviousFanNodes()254 public boolean hasPreviousFanNodes() { 255 return fanOut > 0 && fanIndex > 0; 256 } 257 hasMoreFanNodes()258 public boolean hasMoreFanNodes() { 259 return fanIndex < getLastFanIndex(); 260 } 261 isOnLastFanNode()262 public boolean isOnLastFanNode() { 263 return !hasMoreFanNodes(); 264 } 265 266 267 /*************** standard methods **************************/ 268 269 @Override toString()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 } 282