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