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;
20  
21  import java.nio.ByteBuffer;
22  
23  import org.apache.hadoop.classification.InterfaceAudience;
24  import org.apache.hadoop.classification.InterfaceStability;
25  import org.apache.hadoop.hbase.util.ByteBufferUtils;
26  import org.apache.hadoop.hbase.util.ByteRange;
27  import org.apache.hadoop.hbase.util.Bytes;
28  import org.apache.hadoop.hbase.util.IterableUtils;
29  import org.apache.hadoop.io.WritableUtils;
30  import org.apache.hbase.Cell;
31  import org.apache.hbase.cell.CellTool;
32  
33  /**
34   * static convenience methods for dealing with KeyValues and collections of KeyValues
35   */
36  @InterfaceAudience.Private
37  public class KeyValueTool {
38  
39    /**************** length *********************/
40  
41    public static int length(final Cell cell) {
42      return (int)KeyValue.getKeyValueDataStructureSize(cell.getRowLength(), cell.getFamilyLength(),
43        cell.getQualifierLength(), cell.getValueLength());
44    }
45  
46    protected static int keyLength(final Cell cell) {
47      return (int)KeyValue.getKeyDataStructureSize(cell.getRowLength(), cell.getFamilyLength(),
48        cell.getQualifierLength());
49    }
50  
51    public static int lengthWithMvccVersion(final KeyValue kv, final boolean includeMvccVersion) {
52      int length = kv.getLength();
53      if (includeMvccVersion) {
54        length += WritableUtils.getVIntSize(kv.getMvccVersion());
55      }
56      return length;
57    }
58  
59    public static int totalLengthWithMvccVersion(final Iterable<? extends KeyValue> kvs,
60        final boolean includeMvccVersion) {
61      int length = 0;
62      for (KeyValue kv : IterableUtils.nullSafe(kvs)) {
63        length += lengthWithMvccVersion(kv, includeMvccVersion);
64      }
65      return length;
66    }
67  
68  
69    /**************** copy key only *********************/
70  
71    public static KeyValue copyToNewKeyValue(final Cell cell) {
72      KeyValue kvCell = new KeyValue(copyToNewByteArray(cell));
73      kvCell.setMvccVersion(cell.getMvccVersion());
74      return kvCell;
75    }
76  
77    public static ByteBuffer copyKeyToNewByteBuffer(final Cell cell) {
78      byte[] bytes = new byte[keyLength(cell)];
79      appendKeyToByteArrayWithoutValue(cell, bytes, 0);
80      ByteBuffer buffer = ByteBuffer.wrap(bytes);
81      buffer.position(buffer.limit());//make it look as if each field were appended
82      return buffer;
83    }
84  
85    public static byte[] copyToNewByteArray(final Cell cell) {
86      int v1Length = length(cell);
87      byte[] backingBytes = new byte[v1Length];
88      appendToByteArray(cell, backingBytes, 0);
89      return backingBytes;
90    }
91  
92    protected static int appendKeyToByteArrayWithoutValue(final Cell cell, final byte[] output,
93        final int offset) {
94      int nextOffset = offset;
95      nextOffset = Bytes.putShort(output, nextOffset, cell.getRowLength());
96      nextOffset = CellTool.copyRowTo(cell, output, nextOffset);
97      nextOffset = Bytes.putByte(output, nextOffset, cell.getFamilyLength());
98      nextOffset = CellTool.copyFamilyTo(cell, output, nextOffset);
99      nextOffset = CellTool.copyQualifierTo(cell, output, nextOffset);
100     nextOffset = Bytes.putLong(output, nextOffset, cell.getTimestamp());
101     nextOffset = Bytes.putByte(output, nextOffset, cell.getTypeByte());
102     return nextOffset;
103   }
104 
105 
106   /**************** copy key and value *********************/
107 
108   public static int appendToByteArray(final Cell cell, final byte[] output, final int offset) {
109     int pos = offset;
110     pos = Bytes.putInt(output, pos, keyLength(cell));
111     pos = Bytes.putInt(output, pos, cell.getValueLength());
112     pos = appendKeyToByteArrayWithoutValue(cell, output, pos);
113     CellTool.copyValueTo(cell, output, pos);
114     return pos + cell.getValueLength();
115   }
116 
117   public static ByteBuffer copyToNewByteBuffer(final Cell cell) {
118     byte[] bytes = new byte[length(cell)];
119     appendToByteArray(cell, bytes, 0);
120     ByteBuffer buffer = ByteBuffer.wrap(bytes);
121     buffer.position(buffer.limit());//make it look as if each field were appended
122     return buffer;
123   }
124 
125   public static void appendToByteBuffer(final ByteBuffer bb, final KeyValue kv,
126       final boolean includeMvccVersion) {
127     // keep pushing the limit out. assume enough capacity
128     bb.limit(bb.position() + kv.getLength());
129     bb.put(kv.getBuffer(), kv.getOffset(), kv.getLength());
130     if (includeMvccVersion) {
131       int numMvccVersionBytes = WritableUtils.getVIntSize(kv.getMvccVersion());
132       ByteBufferUtils.extendLimit(bb, numMvccVersionBytes);
133       ByteBufferUtils.writeVLong(bb, kv.getMvccVersion());
134     }
135   }
136 
137 
138   /**************** iterating *******************************/
139 
140   /**
141    * Creates a new KeyValue object positioned in the supplied ByteBuffer and sets the ByteBuffer's
142    * position to the start of the next KeyValue. Does not allocate a new array or copy data.
143    */
144   public static KeyValue nextShallowCopy(final ByteBuffer bb, final boolean includesMvccVersion) {
145     if (bb.isDirect()) {
146       throw new IllegalArgumentException("only supports heap buffers");
147     }
148     if (bb.remaining() < 1) {
149       return null;
150     }
151     int underlyingArrayOffset = bb.arrayOffset() + bb.position();
152     int keyLength = bb.getInt();
153     int valueLength = bb.getInt();
154     int kvLength = KeyValue.KEYVALUE_INFRASTRUCTURE_SIZE + keyLength + valueLength;
155     KeyValue keyValue = new KeyValue(bb.array(), underlyingArrayOffset, kvLength);
156     ByteBufferUtils.skip(bb, keyLength + valueLength);
157     if (includesMvccVersion) {
158       long mvccVersion = ByteBufferUtils.readVLong(bb);
159       keyValue.setMvccVersion(mvccVersion);
160     }
161     return keyValue;
162   }
163 
164 
165   /*************** next/previous **********************************/
166 
167   /**
168    * Append single byte 0x00 to the end of the input row key
169    */
170   public static KeyValue createFirstKeyInNextRow(final Cell in){
171     byte[] nextRow = new byte[in.getRowLength() + 1];
172     System.arraycopy(in.getRowArray(), in.getRowOffset(), nextRow, 0, in.getRowLength());
173     nextRow[nextRow.length - 1] = 0;//maybe not necessary
174     return KeyValue.createFirstOnRow(nextRow);
175   }
176 
177   /**
178    * Increment the row bytes and clear the other fields
179    */
180   public static KeyValue createFirstKeyInIncrementedRow(final Cell in){
181     byte[] thisRow = new ByteRange(in.getRowArray(), in.getRowOffset(), in.getRowLength())
182         .deepCopyToNewArray();
183     byte[] nextRow = Bytes.unsignedCopyAndIncrement(thisRow);
184     return KeyValue.createFirstOnRow(nextRow);
185   }
186 
187   /**
188    * Decrement the timestamp.  For tests (currently wasteful)
189    *
190    * Remember timestamps are sorted reverse chronologically.
191    * @param in
192    * @return previous key
193    */
194   public static KeyValue previousKey(final KeyValue in) {
195     return KeyValue.createFirstOnRow(CellTool.getRowArray(in), CellTool.getFamilyArray(in),
196       CellTool.getQualifierArray(in), in.getTimestamp() - 1);
197   }
198 }