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.encode.column;
20  
21  import java.io.IOException;
22  import java.io.OutputStream;
23  
24  import org.apache.hadoop.hbase.classification.InterfaceAudience;
25  import org.apache.hadoop.hbase.codec.prefixtree.PrefixTreeBlockMeta;
26  import org.apache.hadoop.hbase.codec.prefixtree.encode.other.ColumnNodeType;
27  import org.apache.hadoop.hbase.codec.prefixtree.encode.tokenize.TokenizerNode;
28  import org.apache.hadoop.hbase.util.ByteRange;
29  import org.apache.hadoop.hbase.util.Bytes;
30  import org.apache.hadoop.hbase.util.Strings;
31  import org.apache.hadoop.hbase.util.vint.UFIntTool;
32  import org.apache.hadoop.hbase.util.vint.UVIntTool;
33  
34  /**
35   * <p>
36   * Column nodes can be either family nodes or qualifier nodes, as both sections encode similarly.
37   * The family and qualifier sections of the data block are made of 1 or more of these nodes.
38   * </p>
39   * Each node is composed of 3 sections:<br>
40   * <ul>
41   * <li>tokenLength: UVInt (normally 1 byte) indicating the number of token bytes
42   * <li>token[]: the actual token bytes
43   * <li>parentStartPosition: the offset of the next node from the start of the family or qualifier
44   * section
45   * </ul>
46   */
47  @InterfaceAudience.Private
48  public class ColumnNodeWriter{
49  
50    /************* fields ****************************/
51  
52    protected TokenizerNode builderNode;
53    protected PrefixTreeBlockMeta blockMeta;
54  
55    protected int tokenLength;
56    protected byte[] token;
57    protected int parentStartPosition;
58    protected ColumnNodeType nodeType;
59  
60  
61    /*************** construct **************************/
62  
63    public ColumnNodeWriter(PrefixTreeBlockMeta blockMeta, TokenizerNode builderNode,
64        ColumnNodeType nodeType) {
65      this.blockMeta = blockMeta;
66      this.builderNode = builderNode;
67      this.nodeType = nodeType;
68      calculateTokenLength();
69    }
70  
71  
72    /************* methods *******************************/
73  
74    public boolean isRoot() {
75      return parentStartPosition == 0;
76    }
77  
78    private void calculateTokenLength() {
79      tokenLength = builderNode.getTokenLength();
80      token = new byte[tokenLength];
81    }
82  
83    /**
84     * This method is called before blockMeta.qualifierOffsetWidth is known, so we pass in a
85     * placeholder.
86     * @param offsetWidthPlaceholder the placeholder
87     * @return node width
88     */
89    public int getWidthUsingPlaceholderForOffsetWidth(int offsetWidthPlaceholder) {
90      int width = 0;
91      width += UVIntTool.numBytes(tokenLength);
92      width += token.length;
93      width += offsetWidthPlaceholder;
94      return width;
95    }
96  
97    public void writeBytes(OutputStream os) throws IOException {
98      int parentOffsetWidth;
99      if (this.nodeType == ColumnNodeType.FAMILY) {
100       parentOffsetWidth = blockMeta.getFamilyOffsetWidth();
101     } else if (this.nodeType == ColumnNodeType.QUALIFIER) {
102       parentOffsetWidth = blockMeta.getQualifierOffsetWidth();
103     } else {
104       parentOffsetWidth = blockMeta.getTagsOffsetWidth();
105     }
106     UVIntTool.writeBytes(tokenLength, os);
107     os.write(token);
108     UFIntTool.writeBytes(parentOffsetWidth, parentStartPosition, os);
109   }
110 
111   public void setTokenBytes(ByteRange source) {
112     source.deepCopySubRangeTo(0, tokenLength, token, 0);
113   }
114 
115 
116   /****************** standard methods ************************/
117 
118   @Override
119   public String toString() {
120     StringBuilder sb = new StringBuilder();
121     sb.append(Strings.padFront(builderNode.getOutputArrayOffset() + "", ' ', 3) + ",");
122     sb.append("[");
123     sb.append(Bytes.toString(token));
124     sb.append("]->");
125     sb.append(parentStartPosition);
126     return sb.toString();
127   }
128 
129 
130   /************************** get/set ***********************/
131 
132   public void setParentStartPosition(int parentStartPosition) {
133     this.parentStartPosition = parentStartPosition;
134   }
135 
136 }