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.regionserver.wal;
20 
21 import java.io.DataInput;
22 import java.io.DataOutput;
23 import java.io.IOException;
24 
25 import org.apache.hadoop.hbase.classification.InterfaceAudience;
26 import org.apache.hadoop.hbase.KeyValue;
27 import org.apache.hadoop.hbase.util.Bytes;
28 import org.apache.hadoop.io.WritableUtils;
29 
30 /**
31  * DO NOT USE. This class is deprecated and should only be used in pre-PB WAL.
32  *
33  * Compression class for {@link KeyValue}s written to the WAL. This is not
34  * synchronized, so synchronization should be handled outside.
35  *
36  * Class only compresses and uncompresses row keys, family names, and the
37  * qualifier. More may be added depending on use patterns.
38  */
39 @Deprecated
40 @InterfaceAudience.Private
41 class KeyValueCompression {
42   /**
43    * Uncompresses a KeyValue from a DataInput and returns it.
44    *
45    * @param in the DataInput
46    * @param readContext the compressionContext to use.
47    * @return an uncompressed KeyValue
48    * @throws IOException
49    */
50 
readKV(DataInput in, CompressionContext readContext)51   public static KeyValue readKV(DataInput in, CompressionContext readContext)
52       throws IOException {
53     int keylength = WritableUtils.readVInt(in);
54     int vlength = WritableUtils.readVInt(in);
55     int tagsLength = WritableUtils.readVInt(in);
56     int length = (int) KeyValue.getKeyValueDataStructureSize(keylength, vlength, tagsLength);
57 
58     byte[] backingArray = new byte[length];
59     int pos = 0;
60     pos = Bytes.putInt(backingArray, pos, keylength);
61     pos = Bytes.putInt(backingArray, pos, vlength);
62 
63     // the row
64     int elemLen = Compressor.uncompressIntoArray(backingArray,
65         pos + Bytes.SIZEOF_SHORT, in, readContext.rowDict);
66     checkLength(elemLen, Short.MAX_VALUE);
67     pos = Bytes.putShort(backingArray, pos, (short)elemLen);
68     pos += elemLen;
69 
70     // family
71     elemLen = Compressor.uncompressIntoArray(backingArray,
72         pos + Bytes.SIZEOF_BYTE, in, readContext.familyDict);
73     checkLength(elemLen, Byte.MAX_VALUE);
74     pos = Bytes.putByte(backingArray, pos, (byte)elemLen);
75     pos += elemLen;
76 
77     // qualifier
78     elemLen = Compressor.uncompressIntoArray(backingArray, pos, in,
79         readContext.qualifierDict);
80     pos += elemLen;
81 
82     // the rest
83     in.readFully(backingArray, pos, length - pos);
84 
85     return new KeyValue(backingArray, 0, length);
86   }
87 
checkLength(int len, int max)88   private static void checkLength(int len, int max) throws IOException {
89     if (len < 0 || len > max) {
90       throw new IOException(
91           "Invalid length for compresesed portion of keyvalue: " + len);
92     }
93   }
94 
95   /**
96    * Compresses and writes ourKV to out, a DataOutput.
97    *
98    * @param out the DataOutput
99    * @param keyVal the KV to compress and write
100    * @param writeContext the compressionContext to use.
101    * @throws IOException
102    */
writeKV(final DataOutput out, KeyValue keyVal, CompressionContext writeContext)103   public static void writeKV(final DataOutput out, KeyValue keyVal,
104       CompressionContext writeContext) throws IOException {
105     byte[] backingArray = keyVal.getBuffer();
106     int offset = keyVal.getOffset();
107 
108     // we first write the KeyValue infrastructure as VInts.
109     WritableUtils.writeVInt(out, keyVal.getKeyLength());
110     WritableUtils.writeVInt(out, keyVal.getValueLength());
111     WritableUtils.writeVInt(out, keyVal.getTagsLength());
112 
113     // now we write the row key, as the row key is likely to be repeated
114     // We save space only if we attempt to compress elements with duplicates
115     Compressor.writeCompressed(keyVal.getBuffer(), keyVal.getRowOffset(),
116         keyVal.getRowLength(), out, writeContext.rowDict);
117 
118 
119     // now family, if it exists. if it doesn't, we write a 0 length array.
120     Compressor.writeCompressed(keyVal.getBuffer(), keyVal.getFamilyOffset(),
121         keyVal.getFamilyLength(), out, writeContext.familyDict);
122 
123     // qualifier next
124     Compressor.writeCompressed(keyVal.getBuffer(), keyVal.getQualifierOffset(),
125         keyVal.getQualifierLength(), out,
126         writeContext.qualifierDict);
127 
128     // now we write the rest uncompressed
129     int pos = keyVal.getTimestampOffset();
130     int remainingLength = keyVal.getLength() + offset - (pos);
131     out.write(backingArray, pos, remainingLength);
132   }
133 }
134