1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.regionserver.compactions;
19
20 import static org.apache.hadoop.hbase.regionserver.StripeStoreFileManager.OPEN_KEY;
21 import static org.apache.hadoop.hbase.regionserver.compactions.TestCompactor.createDummyRequest;
22 import static org.junit.Assert.assertEquals;
23 import static org.mockito.Matchers.any;
24 import static org.mockito.Matchers.anyBoolean;
25 import static org.mockito.Matchers.anyLong;
26 import static org.mockito.Mockito.mock;
27 import static org.mockito.Mockito.when;
28
29 import java.io.IOException;
30 import java.util.ArrayList;
31 import java.util.Arrays;
32 import java.util.List;
33
34 import org.apache.hadoop.conf.Configuration;
35 import org.apache.hadoop.fs.FileSystem;
36 import org.apache.hadoop.fs.Path;
37 import org.apache.hadoop.hbase.CellUtil;
38 import org.apache.hadoop.hbase.HBaseConfiguration;
39 import org.apache.hadoop.hbase.HColumnDescriptor;
40 import org.apache.hadoop.hbase.HRegionInfo;
41 import org.apache.hadoop.hbase.KeyValue;
42 import org.apache.hadoop.hbase.KeyValue.KVComparator;
43 import org.apache.hadoop.hbase.TableName;
44 import org.apache.hadoop.hbase.io.compress.Compression;
45 import org.apache.hadoop.hbase.regionserver.InternalScanner;
46 import org.apache.hadoop.hbase.regionserver.ScanInfo;
47 import org.apache.hadoop.hbase.regionserver.ScanType;
48 import org.apache.hadoop.hbase.regionserver.Store;
49 import org.apache.hadoop.hbase.regionserver.StoreFileScanner;
50 import org.apache.hadoop.hbase.regionserver.compactions.TestCompactor.Scanner;
51 import org.apache.hadoop.hbase.regionserver.compactions.TestCompactor.StoreFileWritersCapture;
52 import org.apache.hadoop.hbase.regionserver.throttle.NoLimitThroughputController;
53 import org.apache.hadoop.hbase.testclassification.RegionServerTests;
54 import org.apache.hadoop.hbase.testclassification.SmallTests;
55 import org.apache.hadoop.hbase.util.Bytes;
56 import org.junit.Test;
57 import org.junit.experimental.categories.Category;
58 import org.junit.runner.RunWith;
59 import org.junit.runners.Parameterized;
60 import org.junit.runners.Parameterized.Parameter;
61 import org.junit.runners.Parameterized.Parameters;
62
63 @RunWith(Parameterized.class)
64 @Category({ RegionServerTests.class, SmallTests.class })
65 public class TestStripeCompactor {
66 private static final byte[] NAME_OF_THINGS = Bytes.toBytes("foo");
67 private static final TableName TABLE_NAME = TableName.valueOf(NAME_OF_THINGS, NAME_OF_THINGS);
68
69 private static final byte[] KEY_B = Bytes.toBytes("bbb");
70 private static final byte[] KEY_C = Bytes.toBytes("ccc");
71 private static final byte[] KEY_D = Bytes.toBytes("ddd");
72
73 private static final KeyValue KV_A = kvAfter(Bytes.toBytes("aaa"));
74 private static final KeyValue KV_B = kvAfter(KEY_B);
75 private static final KeyValue KV_C = kvAfter(KEY_C);
76 private static final KeyValue KV_D = kvAfter(KEY_D);
77
78 @Parameters(name = "{index}: usePrivateReaders={0}")
79 public static Iterable<Object[]> data() {
80 return Arrays.asList(new Object[] { true }, new Object[] { false });
81 }
82
83 @Parameter
84 public boolean usePrivateReaders;
85
86 private static KeyValue kvAfter(byte[] key) {
87 return new KeyValue(Arrays.copyOf(key, key.length + 1), 0L);
88 }
89
90 @SuppressWarnings("unchecked")
91 private static <T> T[] a(T... a) {
92 return a;
93 }
94
95 private static KeyValue[] e() {
96 return TestStripeCompactor.<KeyValue> a();
97 }
98
99 @Test
100 public void testBoundaryCompactions() throws Exception {
101
102 verifyBoundaryCompaction(a(KV_A, KV_A, KV_B, KV_B, KV_C, KV_D),
103 a(OPEN_KEY, KEY_B, KEY_D, OPEN_KEY), a(a(KV_A, KV_A), a(KV_B, KV_B, KV_C), a(KV_D)));
104 verifyBoundaryCompaction(a(KV_B, KV_C), a(KEY_B, KEY_C, KEY_D), a(a(KV_B), a(KV_C)));
105 verifyBoundaryCompaction(a(KV_B, KV_C), a(KEY_B, KEY_D), new KeyValue[][] { a(KV_B, KV_C) });
106 }
107
108 @Test
109 public void testBoundaryCompactionEmptyFiles() throws Exception {
110
111 verifyBoundaryCompaction(a(KV_B), a(KEY_B, KEY_C, KEY_D, OPEN_KEY), a(a(KV_B), null, null),
112 null, null, false);
113 verifyBoundaryCompaction(a(KV_A, KV_C), a(OPEN_KEY, KEY_B, KEY_C, KEY_D),
114 a(a(KV_A), null, a(KV_C)), null, null, false);
115
116 verifyBoundaryCompaction(e(), a(OPEN_KEY, KEY_B, KEY_C, OPEN_KEY), a(null, null, e()), null,
117 null, false);
118
119 verifyBoundaryCompaction(e(), a(OPEN_KEY, KEY_B, KEY_C, OPEN_KEY), a(null, e(), null), KEY_B,
120 KEY_C, false);
121 verifyBoundaryCompaction(e(), a(OPEN_KEY, KEY_B, KEY_C, OPEN_KEY), a(e(), e(), null), OPEN_KEY,
122 KEY_C, false);
123
124 verifyBoundaryCompaction(a(KV_A), a(OPEN_KEY, KEY_B, KEY_C, KEY_D, OPEN_KEY),
125 a(a(KV_A), e(), e(), null), KEY_B, KEY_D, false);
126 verifyBoundaryCompaction(a(KV_C), a(OPEN_KEY, KEY_B, KEY_C, KEY_D, OPEN_KEY),
127 a(null, null, a(KV_C), e()), KEY_C, OPEN_KEY, false);
128
129 }
130
131 private void verifyBoundaryCompaction(KeyValue[] input, byte[][] boundaries, KeyValue[][] output)
132 throws Exception {
133 verifyBoundaryCompaction(input, boundaries, output, null, null, true);
134 }
135
136 private void verifyBoundaryCompaction(KeyValue[] input, byte[][] boundaries, KeyValue[][] output,
137 byte[] majorFrom, byte[] majorTo, boolean allFiles) throws Exception {
138 StoreFileWritersCapture writers = new StoreFileWritersCapture();
139 StripeCompactor sc = createCompactor(writers, input);
140 List<Path> paths = sc.compact(createDummyRequest(), Arrays.asList(boundaries), majorFrom,
141 majorTo, NoLimitThroughputController.INSTANCE, null);
142 writers.verifyKvs(output, allFiles, true);
143 if (allFiles) {
144 assertEquals(output.length, paths.size());
145 writers.verifyBoundaries(boundaries);
146 }
147 }
148
149 @Test
150 public void testSizeCompactions() throws Exception {
151
152 verifySizeCompaction(a(KV_A, KV_A, KV_B, KV_C, KV_D), 3, 2, OPEN_KEY, OPEN_KEY,
153 a(a(KV_A, KV_A), a(KV_B, KV_C), a(KV_D)));
154 verifySizeCompaction(a(KV_A, KV_B, KV_C, KV_D), 4, 1, OPEN_KEY, OPEN_KEY,
155 a(a(KV_A), a(KV_B), a(KV_C), a(KV_D)));
156 verifySizeCompaction(a(KV_B, KV_C), 2, 1, KEY_B, KEY_D, a(a(KV_B), a(KV_C)));
157
158 verifySizeCompaction(a(KV_A, KV_A, KV_A, KV_C, KV_D), 3, 2, OPEN_KEY, OPEN_KEY,
159 a(a(KV_A, KV_A, KV_A), a(KV_C, KV_D)));
160 verifySizeCompaction(a(KV_A, KV_B, KV_B, KV_C), 3, 1, OPEN_KEY, OPEN_KEY,
161 a(a(KV_A), a(KV_B, KV_B), a(KV_C)));
162
163 verifySizeCompaction(a(KV_A, KV_B, KV_C, KV_D), 2, 1, OPEN_KEY, OPEN_KEY,
164 a(a(KV_A), a(KV_B, KV_C, KV_D)));
165 verifySizeCompaction(a(KV_A, KV_B, KV_C), 1, Long.MAX_VALUE, OPEN_KEY, KEY_D,
166 new KeyValue[][] { a(KV_A, KV_B, KV_C) });
167
168 verifySizeCompaction(a(KV_A, KV_B, KV_C, KV_D), Integer.MAX_VALUE, 2, OPEN_KEY, OPEN_KEY,
169 a(a(KV_A, KV_B), a(KV_C, KV_D)));
170 }
171
172 private void verifySizeCompaction(KeyValue[] input, int targetCount, long targetSize, byte[] left,
173 byte[] right, KeyValue[][] output) throws Exception {
174 StoreFileWritersCapture writers = new StoreFileWritersCapture();
175 StripeCompactor sc = createCompactor(writers, input);
176 List<Path> paths = sc.compact(createDummyRequest(), targetCount, targetSize, left, right, null,
177 null, NoLimitThroughputController.INSTANCE, null);
178 assertEquals(output.length, paths.size());
179 writers.verifyKvs(output, true, true);
180 List<byte[]> boundaries = new ArrayList<byte[]>();
181 boundaries.add(left);
182 for (int i = 1; i < output.length; ++i) {
183 boundaries.add(CellUtil.cloneRow(output[i][0]));
184 }
185 boundaries.add(right);
186 writers.verifyBoundaries(boundaries.toArray(new byte[][] {}));
187 }
188
189 private StripeCompactor createCompactor(StoreFileWritersCapture writers, KeyValue[] input)
190 throws Exception {
191 Configuration conf = HBaseConfiguration.create();
192 conf.setBoolean("hbase.regionserver.compaction.private.readers", usePrivateReaders);
193 final Scanner scanner = new Scanner(input);
194
195
196 HColumnDescriptor col = new HColumnDescriptor(NAME_OF_THINGS);
197 ScanInfo si = new ScanInfo(conf, col, Long.MAX_VALUE, 0, new KVComparator());
198 Store store = mock(Store.class);
199 when(store.getFamily()).thenReturn(col);
200 when(store.getScanInfo()).thenReturn(si);
201 when(store.areWritesEnabled()).thenReturn(true);
202 when(store.getFileSystem()).thenReturn(mock(FileSystem.class));
203 when(store.getRegionInfo()).thenReturn(new HRegionInfo(TABLE_NAME));
204 when(store.createWriterInTmp(anyLong(), any(Compression.Algorithm.class), anyBoolean(),
205 anyBoolean(), anyBoolean(), anyBoolean(), anyLong())).thenAnswer(writers);
206 when(store.getComparator()).thenReturn(new KVComparator());
207
208 return new StripeCompactor(conf, store) {
209 @Override
210 protected InternalScanner createScanner(Store store, List<StoreFileScanner> scanners,
211 long smallestReadPoint, long earliestPutTs, byte[] dropDeletesFromRow,
212 byte[] dropDeletesToRow) throws IOException {
213 return scanner;
214 }
215
216 @Override
217 protected InternalScanner createScanner(Store store, List<StoreFileScanner> scanners,
218 ScanType scanType, long smallestReadPoint, long earliestPutTs) throws IOException {
219 return scanner;
220 }
221 };
222 }
223 }