1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.codec.prefixtree;
20
21 import java.io.DataInputStream;
22 import java.io.DataOutputStream;
23 import java.io.IOException;
24 import java.nio.ByteBuffer;
25
26 import org.apache.hadoop.classification.InterfaceAudience;
27 import org.apache.hadoop.hbase.KeyValue;
28 import org.apache.hadoop.hbase.KeyValue.KeyComparator;
29 import org.apache.hadoop.hbase.KeyValue.MetaKeyComparator;
30 import org.apache.hadoop.hbase.KeyValue.RootKeyComparator;
31 import org.apache.hadoop.hbase.KeyValueUtil;
32 import org.apache.hadoop.hbase.codec.prefixtree.decode.DecoderFactory;
33 import org.apache.hadoop.hbase.codec.prefixtree.decode.PrefixTreeArraySearcher;
34 import org.apache.hadoop.hbase.codec.prefixtree.encode.EncoderFactory;
35 import org.apache.hadoop.hbase.codec.prefixtree.encode.PrefixTreeEncoder;
36 import org.apache.hadoop.hbase.codec.prefixtree.scanner.CellSearcher;
37 import org.apache.hadoop.hbase.io.compress.Compression.Algorithm;
38 import org.apache.hadoop.hbase.io.encoding.DataBlockEncoder;
39 import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding;
40 import org.apache.hadoop.hbase.io.encoding.HFileBlockDecodingContext;
41 import org.apache.hadoop.hbase.io.encoding.HFileBlockDefaultDecodingContext;
42 import org.apache.hadoop.hbase.io.encoding.HFileBlockDefaultEncodingContext;
43 import org.apache.hadoop.hbase.io.encoding.HFileBlockEncodingContext;
44 import org.apache.hadoop.hbase.io.hfile.BlockType;
45 import org.apache.hadoop.hbase.util.ByteBufferUtils;
46 import org.apache.hadoop.io.RawComparator;
47
48
49
50
51
52
53
54
55
56
57
58 @InterfaceAudience.Private
59 public class PrefixTreeCodec implements DataBlockEncoder{
60
61
62
63
64 public PrefixTreeCodec() {
65 }
66
67
68
69
70
71 @Override
72 public void encodeKeyValues(ByteBuffer in, boolean includesMvccVersion,
73 HFileBlockEncodingContext blkEncodingCtx) throws IOException {
74 if (blkEncodingCtx.getClass() != HFileBlockDefaultEncodingContext.class) {
75 throw new IOException(this.getClass().getName() + " only accepts "
76 + HFileBlockDefaultEncodingContext.class.getName() + " as the " + "encoding context.");
77 }
78
79 HFileBlockDefaultEncodingContext encodingCtx
80 = (HFileBlockDefaultEncodingContext) blkEncodingCtx;
81 encodingCtx.prepareEncoding();
82 DataOutputStream dataOut = encodingCtx.getOutputStreamForEncoder();
83 internalEncodeKeyValues(dataOut, in, includesMvccVersion);
84
85
86 if (encodingCtx.getDataBlockEncoding() != DataBlockEncoding.NONE) {
87 encodingCtx.postEncoding(BlockType.ENCODED_DATA);
88 } else {
89 encodingCtx.postEncoding(BlockType.DATA);
90 }
91 }
92
93 private void internalEncodeKeyValues(DataOutputStream encodedOutputStream,
94 ByteBuffer rawKeyValues, boolean includesMvccVersion) throws IOException {
95 rawKeyValues.rewind();
96 PrefixTreeEncoder builder = EncoderFactory.checkOut(encodedOutputStream, includesMvccVersion);
97
98 try{
99 KeyValue kv;
100 while ((kv = KeyValueUtil.nextShallowCopy(rawKeyValues, includesMvccVersion)) != null) {
101 builder.write(kv);
102 }
103 builder.flush();
104 }finally{
105 EncoderFactory.checkIn(builder);
106 }
107 }
108
109
110 @Override
111 public ByteBuffer decodeKeyValues(DataInputStream source, boolean includesMvccVersion)
112 throws IOException {
113 return decodeKeyValues(source, 0, 0, includesMvccVersion);
114 }
115
116
117
118
119
120
121 @Override
122 public ByteBuffer decodeKeyValues(DataInputStream source, int allocateHeaderLength,
123 int skipLastBytes, boolean includesMvccVersion) throws IOException {
124 ByteBuffer sourceAsBuffer = ByteBufferUtils.drainInputStreamToBuffer(source);
125 sourceAsBuffer.mark();
126 PrefixTreeBlockMeta blockMeta = new PrefixTreeBlockMeta(sourceAsBuffer);
127 sourceAsBuffer.rewind();
128 int numV1BytesWithHeader = allocateHeaderLength + blockMeta.getNumKeyValueBytes();
129 byte[] keyValueBytesWithHeader = new byte[numV1BytesWithHeader];
130 ByteBuffer result = ByteBuffer.wrap(keyValueBytesWithHeader);
131 result.rewind();
132 CellSearcher searcher = null;
133 try {
134 searcher = DecoderFactory.checkOut(sourceAsBuffer, includesMvccVersion);
135 while (searcher.advance()) {
136 KeyValue currentCell = KeyValueUtil.copyToNewKeyValue(searcher.current());
137
138
139 int offset = result.arrayOffset() + result.position();
140 KeyValueUtil.appendToByteArray(currentCell, result.array(), offset);
141 int keyValueLength = KeyValueUtil.length(currentCell);
142 ByteBufferUtils.skip(result, keyValueLength);
143 offset += keyValueLength;
144 if (includesMvccVersion) {
145 ByteBufferUtils.writeVLong(result, currentCell.getMvccVersion());
146 }
147 }
148 result.position(result.limit());
149 return result;
150 } finally {
151 DecoderFactory.checkIn(searcher);
152 }
153 }
154
155
156 @Override
157 public ByteBuffer getFirstKeyInBlock(ByteBuffer block) {
158 block.rewind();
159 PrefixTreeArraySearcher searcher = null;
160 try {
161
162 searcher = DecoderFactory.checkOut(block, true);
163 if (!searcher.positionAtFirstCell()) {
164 return null;
165 }
166 return KeyValueUtil.copyKeyToNewByteBuffer(searcher.current());
167 } finally {
168 DecoderFactory.checkIn(searcher);
169 }
170 }
171
172 @Override
173 public HFileBlockEncodingContext newDataBlockEncodingContext(Algorithm compressionAlgorithm,
174 DataBlockEncoding encoding, byte[] header) {
175 if(DataBlockEncoding.PREFIX_TREE != encoding){
176
177
178 throw new IllegalArgumentException("only DataBlockEncoding.PREFIX_TREE supported");
179 }
180 return new HFileBlockDefaultEncodingContext(compressionAlgorithm, encoding, header);
181 }
182
183 @Override
184 public HFileBlockDecodingContext newDataBlockDecodingContext(Algorithm compressionAlgorithm) {
185 return new HFileBlockDefaultDecodingContext(compressionAlgorithm);
186 }
187
188
189
190
191
192 @Override
193 public EncodedSeeker createSeeker(RawComparator<byte[]> comparator, boolean includesMvccVersion) {
194 if(! (comparator instanceof KeyComparator)){
195 throw new IllegalArgumentException("comparator must be KeyValue.KeyComparator");
196 }
197 if(comparator instanceof MetaKeyComparator){
198 throw new IllegalArgumentException("DataBlockEncoding.PREFIX_TREE not compatible with META "
199 +"table");
200 }
201 if(comparator instanceof RootKeyComparator){
202 throw new IllegalArgumentException("DataBlockEncoding.PREFIX_TREE not compatible with ROOT "
203 +"table");
204 }
205
206 return new PrefixTreeSeeker(includesMvccVersion);
207 }
208
209 }