1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.hadoop.hbase.io.encoding;
18
19 import java.io.DataInputStream;
20 import java.io.DataOutputStream;
21 import java.io.IOException;
22 import java.nio.ByteBuffer;
23
24 import org.apache.hadoop.classification.InterfaceAudience;
25 import org.apache.hadoop.hbase.KeyValue;
26 import org.apache.hadoop.hbase.KeyValue.KVComparator;
27 import org.apache.hadoop.hbase.util.ByteBufferUtils;
28 import org.apache.hadoop.hbase.util.Bytes;
29 import org.apache.hadoop.io.RawComparator;
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 @InterfaceAudience.Private
46 public class PrefixKeyDeltaEncoder extends BufferedDataBlockEncoder {
47
48 private int addKV(int prevKeyOffset, DataOutputStream out,
49 ByteBuffer in, int prevKeyLength) throws IOException {
50 int keyLength = in.getInt();
51 int valueLength = in.getInt();
52
53 if (prevKeyOffset == -1) {
54
55 ByteBufferUtils.putCompressedInt(out, keyLength);
56 ByteBufferUtils.putCompressedInt(out, valueLength);
57 ByteBufferUtils.putCompressedInt(out, 0);
58 ByteBufferUtils.moveBufferToStream(out, in, keyLength + valueLength);
59 } else {
60
61 int common = ByteBufferUtils.findCommonPrefix(
62 in, prevKeyOffset + KeyValue.ROW_OFFSET,
63 in.position(),
64 Math.min(prevKeyLength, keyLength));
65
66 ByteBufferUtils.putCompressedInt(out, keyLength - common);
67 ByteBufferUtils.putCompressedInt(out, valueLength);
68 ByteBufferUtils.putCompressedInt(out, common);
69
70 ByteBufferUtils.skip(in, common);
71 ByteBufferUtils.moveBufferToStream(out, in, keyLength - common
72 + valueLength);
73 }
74
75 return keyLength;
76 }
77
78 @Override
79 public void internalEncodeKeyValues(DataOutputStream writeHere,
80 ByteBuffer in, boolean includesMemstoreTS) throws IOException {
81 in.rewind();
82 ByteBufferUtils.putInt(writeHere, in.limit());
83 int prevOffset = -1;
84 int offset = 0;
85 int keyLength = 0;
86 while (in.hasRemaining()) {
87 offset = in.position();
88 keyLength = addKV(prevOffset, writeHere, in, keyLength);
89 afterEncodingKeyValue(in, writeHere, includesMemstoreTS);
90 prevOffset = offset;
91 }
92 }
93
94 @Override
95 public ByteBuffer decodeKeyValues(DataInputStream source,
96 int allocHeaderLength, int skipLastBytes, boolean includesMemstoreTS)
97 throws IOException {
98 int decompressedSize = source.readInt();
99 ByteBuffer buffer = ByteBuffer.allocate(decompressedSize +
100 allocHeaderLength);
101 buffer.position(allocHeaderLength);
102 int prevKeyOffset = 0;
103
104 while (source.available() > skipLastBytes) {
105 prevKeyOffset = decodeKeyValue(source, buffer, prevKeyOffset);
106 afterDecodingKeyValue(source, buffer, includesMemstoreTS);
107 }
108
109 if (source.available() != skipLastBytes) {
110 throw new IllegalStateException("Read too many bytes.");
111 }
112
113 buffer.limit(buffer.position());
114 return buffer;
115 }
116
117 private int decodeKeyValue(DataInputStream source, ByteBuffer buffer,
118 int prevKeyOffset)
119 throws IOException, EncoderBufferTooSmallException {
120 int keyLength = ByteBufferUtils.readCompressedInt(source);
121 int valueLength = ByteBufferUtils.readCompressedInt(source);
122 int commonLength = ByteBufferUtils.readCompressedInt(source);
123 int keyOffset;
124 keyLength += commonLength;
125
126 ensureSpace(buffer, keyLength + valueLength + KeyValue.ROW_OFFSET);
127
128 buffer.putInt(keyLength);
129 buffer.putInt(valueLength);
130
131
132 if (commonLength > 0) {
133 keyOffset = buffer.position();
134 ByteBufferUtils.copyFromBufferToBuffer(buffer, buffer, prevKeyOffset,
135 commonLength);
136 } else {
137 keyOffset = buffer.position();
138 }
139
140
141 int len = keyLength - commonLength + valueLength;
142 ByteBufferUtils.copyFromStreamToBuffer(buffer, source, len);
143 return keyOffset;
144 }
145
146 @Override
147 public ByteBuffer getFirstKeyInBlock(ByteBuffer block) {
148 block.mark();
149 block.position(Bytes.SIZEOF_INT);
150 int keyLength = ByteBufferUtils.readCompressedInt(block);
151 ByteBufferUtils.readCompressedInt(block);
152 int commonLength = ByteBufferUtils.readCompressedInt(block);
153 if (commonLength != 0) {
154 throw new AssertionError("Nonzero common length in the first key in "
155 + "block: " + commonLength);
156 }
157 int pos = block.position();
158 block.reset();
159 return ByteBuffer.wrap(block.array(), pos, keyLength).slice();
160 }
161
162 @Override
163 public String toString() {
164 return PrefixKeyDeltaEncoder.class.getSimpleName();
165 }
166
167 @Override
168 public EncodedSeeker createSeeker(KVComparator comparator,
169 final boolean includesMemstoreTS) {
170 return new BufferedEncodedSeeker<SeekerState>(comparator) {
171 @Override
172 protected void decodeNext() {
173 current.keyLength = ByteBufferUtils.readCompressedInt(currentBuffer);
174 current.valueLength = ByteBufferUtils.readCompressedInt(currentBuffer);
175 current.lastCommonPrefix =
176 ByteBufferUtils.readCompressedInt(currentBuffer);
177 current.keyLength += current.lastCommonPrefix;
178 current.ensureSpaceForKey();
179 currentBuffer.get(current.keyBuffer, current.lastCommonPrefix,
180 current.keyLength - current.lastCommonPrefix);
181 current.valueOffset = currentBuffer.position();
182 ByteBufferUtils.skip(currentBuffer, current.valueLength);
183 if (includesMemstoreTS) {
184 current.memstoreTS = ByteBufferUtils.readVLong(currentBuffer);
185 } else {
186 current.memstoreTS = 0;
187 }
188 current.nextKvOffset = currentBuffer.position();
189 }
190
191 @Override
192 protected void decodeFirst() {
193 ByteBufferUtils.skip(currentBuffer, Bytes.SIZEOF_INT);
194 decodeNext();
195 }
196 };
197 }
198 }