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.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertFalse;
22 import static org.junit.Assert.assertTrue;
23 import static org.mockito.Mockito.mock;
24 import static org.mockito.Mockito.when;
25
26 import java.io.IOException;
27 import java.util.ArrayList;
28 import java.util.Collection;
29 import java.util.List;
30 import java.util.concurrent.CountDownLatch;
31 import java.util.concurrent.atomic.AtomicInteger;
32
33 import org.apache.hadoop.fs.Path;
34 import org.apache.hadoop.hbase.Cell;
35 import org.apache.hadoop.hbase.CellUtil;
36 import org.apache.hadoop.hbase.HBaseTestingUtility;
37 import org.apache.hadoop.hbase.HColumnDescriptor;
38 import org.apache.hadoop.hbase.HRegionInfo;
39 import org.apache.hadoop.hbase.HTableDescriptor;
40 import org.apache.hadoop.hbase.Stoppable;
41 import org.apache.hadoop.hbase.TableName;
42 import org.apache.hadoop.hbase.client.Put;
43 import org.apache.hadoop.hbase.client.Scan;
44 import org.apache.hadoop.hbase.regionserver.CompactedHFilesDischarger;
45 import org.apache.hadoop.hbase.regionserver.HRegion;
46 import org.apache.hadoop.hbase.regionserver.HStore;
47 import org.apache.hadoop.hbase.regionserver.Region;
48 import org.apache.hadoop.hbase.regionserver.RegionScanner;
49 import org.apache.hadoop.hbase.regionserver.RegionServerServices;
50 import org.apache.hadoop.hbase.regionserver.Store;
51 import org.apache.hadoop.hbase.regionserver.StoreFile;
52 import org.apache.hadoop.hbase.testclassification.MediumTests;
53 import org.apache.hadoop.hbase.testclassification.RegionServerTests;
54 import org.apache.hadoop.hbase.util.Bytes;
55 import org.junit.After;
56 import org.junit.Before;
57 import org.junit.Test;
58 import org.junit.experimental.categories.Category;
59
60 @Category({ MediumTests.class, RegionServerTests.class })
61 public class TestCompactedHFilesDischarger {
62 private final HBaseTestingUtility testUtil = new HBaseTestingUtility();
63 private Region region;
64 private final static byte[] fam = Bytes.toBytes("cf_1");
65 private final static byte[] qual1 = Bytes.toBytes("qf_1");
66 private final static byte[] val = Bytes.toBytes("val");
67 private static CountDownLatch latch = new CountDownLatch(3);
68 private static AtomicInteger counter = new AtomicInteger(0);
69 private static AtomicInteger scanCompletedCounter = new AtomicInteger(0);
70 private RegionServerServices rss;
71
72 @Before
73 public void setUp() throws Exception {
74 TableName tableName = TableName.valueOf(getClass().getSimpleName());
75 HTableDescriptor htd = new HTableDescriptor(tableName);
76 htd.addFamily(new HColumnDescriptor(fam));
77 HRegionInfo info = new HRegionInfo(tableName, null, null, false);
78 Path path = testUtil.getDataTestDir(getClass().getSimpleName());
79 region = HBaseTestingUtility.createRegionAndWAL(info, path, path, testUtil.getConfiguration(), htd);
80 rss = mock(RegionServerServices.class);
81 List<Region> regions = new ArrayList<Region>();
82 regions.add(region);
83 when(rss.getOnlineRegions()).thenReturn(regions);
84 }
85
86 @After
87 public void tearDown() throws IOException {
88 counter.set(0);
89 scanCompletedCounter.set(0);
90 latch = new CountDownLatch(3);
91 HBaseTestingUtility.closeRegionAndWAL(region);
92 testUtil.cleanupTestDir();
93 }
94
95 @Test
96 public void testCompactedHFilesCleaner() throws Exception {
97
98 CompactedHFilesDischarger cleaner =
99 new CompactedHFilesDischarger(1000, (Stoppable) null, rss, false);
100
101 for (int i = 1; i < 10; i++) {
102 Put p = new Put(Bytes.toBytes("row" + i));
103 p.addColumn(fam, qual1, val);
104 region.put(p);
105 }
106
107 region.flush(true);
108 for (int i = 11; i < 20; i++) {
109 Put p = new Put(Bytes.toBytes("row" + i));
110 p.addColumn(fam, qual1, val);
111 region.put(p);
112 }
113
114 region.flush(true);
115 for (int i = 21; i < 30; i++) {
116 Put p = new Put(Bytes.toBytes("row" + i));
117 p.addColumn(fam, qual1, val);
118 region.put(p);
119 }
120
121 region.flush(true);
122
123 Store store = region.getStore(fam);
124 assertEquals(3, store.getStorefilesCount());
125
126 Collection<StoreFile> storefiles = store.getStorefiles();
127 Collection<StoreFile> compactedfiles =
128 ((HStore) store).getStoreEngine().getStoreFileManager().getCompactedfiles();
129
130 for (StoreFile file : storefiles) {
131 assertFalse(file.isCompactedAway());
132 }
133
134 cleaner.chore();
135 storefiles = store.getStorefiles();
136
137 for (StoreFile file : storefiles) {
138 assertFalse(file.isCompactedAway());
139 }
140
141 region.compact(true);
142
143
144 assertEquals(1, store.getStorefilesCount());
145 assertEquals(3,
146 ((HStore) store).getStoreEngine().getStoreFileManager().getCompactedfiles().size());
147
148
149 cleaner.chore();
150 assertEquals(1, store.getStorefilesCount());
151 storefiles = store.getStorefiles();
152 for (StoreFile file : storefiles) {
153
154 assertFalse(file.isCompactedAway());
155 }
156 compactedfiles = ((HStore) store).getStoreEngine().getStoreFileManager().getCompactedfiles();
157 assertTrue(compactedfiles.size() == 0);
158
159 }
160
161 @Test
162 public void testCleanerWithParallelScannersAfterCompaction() throws Exception {
163
164 CompactedHFilesDischarger cleaner =
165 new CompactedHFilesDischarger(1000, (Stoppable) null, rss, false);
166
167 for (int i = 1; i < 10; i++) {
168 Put p = new Put(Bytes.toBytes("row" + i));
169 p.addColumn(fam, qual1, val);
170 region.put(p);
171 }
172
173 region.flush(true);
174 for (int i = 11; i < 20; i++) {
175 Put p = new Put(Bytes.toBytes("row" + i));
176 p.addColumn(fam, qual1, val);
177 region.put(p);
178 }
179
180 region.flush(true);
181 for (int i = 21; i < 30; i++) {
182 Put p = new Put(Bytes.toBytes("row" + i));
183 p.addColumn(fam, qual1, val);
184 region.put(p);
185 }
186
187 region.flush(true);
188
189 Store store = region.getStore(fam);
190 assertEquals(3, store.getStorefilesCount());
191
192 Collection<StoreFile> storefiles = store.getStorefiles();
193 Collection<StoreFile> compactedfiles =
194 ((HStore) store).getStoreEngine().getStoreFileManager().getCompactedfiles();
195
196 for (StoreFile file : storefiles) {
197 assertFalse(file.isCompactedAway());
198 }
199
200 region.compact(true);
201 startScannerThreads();
202
203 storefiles = store.getStorefiles();
204 int usedReaderCount = 0;
205 int unusedReaderCount = 0;
206 for (StoreFile file : storefiles) {
207 if (file.getRefCount() == 3) {
208 usedReaderCount++;
209 }
210 }
211 compactedfiles = ((HStore) store).getStoreEngine().getStoreFileManager().getCompactedfiles();
212 for(StoreFile file : compactedfiles) {
213 assertEquals("Refcount should be 3", 0, file.getRefCount());
214 unusedReaderCount++;
215 }
216
217 assertEquals("unused reader count should be 3", 3, unusedReaderCount);
218 assertEquals("used reader count should be 1", 1, usedReaderCount);
219
220 cleaner.chore();
221 countDown();
222 assertEquals(1, store.getStorefilesCount());
223 storefiles = store.getStorefiles();
224 for (StoreFile file : storefiles) {
225
226 assertFalse(file.isCompactedAway());
227 }
228 compactedfiles = ((HStore) store).getStoreEngine().getStoreFileManager().getCompactedfiles();
229 assertTrue(compactedfiles.size() == 0);
230 }
231
232 @Test
233 public void testCleanerWithParallelScanners() throws Exception {
234
235 CompactedHFilesDischarger cleaner =
236 new CompactedHFilesDischarger(1000, (Stoppable) null, rss, false);
237
238 for (int i = 1; i < 10; i++) {
239 Put p = new Put(Bytes.toBytes("row" + i));
240 p.addColumn(fam, qual1, val);
241 region.put(p);
242 }
243
244 region.flush(true);
245 for (int i = 11; i < 20; i++) {
246 Put p = new Put(Bytes.toBytes("row" + i));
247 p.addColumn(fam, qual1, val);
248 region.put(p);
249 }
250
251 region.flush(true);
252 for (int i = 21; i < 30; i++) {
253 Put p = new Put(Bytes.toBytes("row" + i));
254 p.addColumn(fam, qual1, val);
255 region.put(p);
256 }
257
258 region.flush(true);
259
260 Store store = region.getStore(fam);
261 assertEquals(3, store.getStorefilesCount());
262
263 Collection<StoreFile> storefiles = store.getStorefiles();
264 Collection<StoreFile> compactedfiles =
265 ((HStore) store).getStoreEngine().getStoreFileManager().getCompactedfiles();
266
267 for (StoreFile file : storefiles) {
268 assertFalse(file.isCompactedAway());
269 }
270 startScannerThreads();
271
272 region.compact(true);
273
274 storefiles = store.getStorefiles();
275 int usedReaderCount = 0;
276 int unusedReaderCount = 0;
277 for (StoreFile file : storefiles) {
278 if (file.getRefCount() == 0) {
279 unusedReaderCount++;
280 }
281 }
282 compactedfiles =
283 ((HStore) store).getStoreEngine().getStoreFileManager().getCompactedfiles();
284 for(StoreFile file : compactedfiles) {
285 assertEquals("Refcount should be 3", 3, file.getRefCount());
286 usedReaderCount++;
287 }
288
289 assertEquals("unused reader count should be 1", 1, unusedReaderCount);
290 assertEquals("used reader count should be 3", 3, usedReaderCount);
291
292 cleaner.chore();
293 countDown();
294
295 assertEquals(1, store.getStorefilesCount());
296 assertEquals(3,
297 ((HStore) store).getStoreEngine().getStoreFileManager().getCompactedfiles().size());
298 while (scanCompletedCounter.get() != 3) {
299 Thread.sleep(100);
300 }
301
302 latch = new CountDownLatch(3);
303 scanCompletedCounter.set(0);
304 counter.set(0);
305
306 startScannerThreads();
307 storefiles = store.getStorefiles();
308 usedReaderCount = 0;
309 unusedReaderCount = 0;
310 for (StoreFile file : storefiles) {
311 if (file.getRefCount() == 3) {
312 usedReaderCount++;
313 }
314 }
315 compactedfiles = ((HStore) store).getStoreEngine().getStoreFileManager().getCompactedfiles();
316 for(StoreFile file : compactedfiles) {
317 assertEquals("Refcount should be 0", 0, file.getRefCount());
318 unusedReaderCount++;
319 }
320
321 assertEquals("unused reader count should be 3", 3, unusedReaderCount);
322 assertEquals("used reader count should be 1", 1, usedReaderCount);
323 countDown();
324 while (scanCompletedCounter.get() != 3) {
325 Thread.sleep(100);
326 }
327
328 cleaner.chore();
329
330 assertEquals(1, store.getStorefilesCount());
331 storefiles = store.getStorefiles();
332 for (StoreFile file : storefiles) {
333
334 assertFalse(file.isCompactedAway());
335 }
336 compactedfiles = ((HStore) store).getStoreEngine().getStoreFileManager().getCompactedfiles();
337 assertTrue(compactedfiles.size() == 0);
338 }
339
340 @Test
341 public void testStoreFileMissing() throws Exception {
342
343 write("row1");
344 region.flush(true);
345 write("row2");
346 region.flush(true);
347 write("row3");
348 region.flush(true);
349
350 Scan scan = new Scan();
351 scan.setCaching(1);
352 RegionScanner scanner = region.getScanner(scan);
353 List<Cell> res = new ArrayList<Cell>();
354
355 scanner.next(res);
356 assertEquals("row1", Bytes.toString(CellUtil.cloneRow(res.get(0))));
357 res.clear();
358
359 write("row4");
360 region.flush(true);
361
362
363 region.compact(true);
364
365
366 CompactedHFilesDischarger cleaner =
367 new CompactedHFilesDischarger(1000, (Stoppable) null, rss, false);
368 cleaner.chore();
369
370 scanner.next(res);
371 assertEquals("row2", Bytes.toString(CellUtil.cloneRow(res.get(0))));
372
373 scanner.close();
374 }
375
376 private void write(String row1) throws IOException {
377 byte[] row = Bytes.toBytes(row1);
378 Put put = new Put(row);
379 put.addColumn(fam, qual1, row);
380 region.put(put);
381 }
382
383 protected void countDown() {
384
385 latch.countDown();
386 latch.countDown();
387 latch.countDown();
388 }
389
390 protected void startScannerThreads() throws InterruptedException {
391
392 ScanThread[] scanThreads = new ScanThread[3];
393 for (int i = 0; i < 3; i++) {
394 scanThreads[i] = new ScanThread((HRegion) region);
395 }
396 for (ScanThread thread : scanThreads) {
397 thread.start();
398 }
399 while (counter.get() != 3) {
400 Thread.sleep(100);
401 }
402 }
403
404 private static class ScanThread extends Thread {
405 private final HRegion region;
406
407 public ScanThread(HRegion region) {
408 this.region = region;
409 }
410
411 @Override
412 public void run() {
413 try {
414 initiateScan(region);
415 } catch (IOException e) {
416 e.printStackTrace();
417 }
418 }
419
420 private void initiateScan(HRegion region) throws IOException {
421 Scan scan = new Scan();
422 scan.setCaching(1);
423 RegionScanner resScanner = null;
424 try {
425 resScanner = region.getScanner(scan);
426 List<Cell> results = new ArrayList<Cell>();
427 boolean next = resScanner.next(results);
428 try {
429 counter.incrementAndGet();
430 latch.await();
431 } catch (InterruptedException e) {
432 }
433 while (next) {
434 next = resScanner.next(results);
435 }
436 } finally {
437 scanCompletedCounter.incrementAndGet();
438 if (resScanner != null) {
439 resScanner.close();
440 }
441 }
442 }
443 }
444 }