1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.regionserver;
20
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertFalse;
23 import static org.mockito.Mockito.mock;
24 import static org.mockito.Mockito.when;
25
26 import org.apache.hadoop.conf.Configuration;
27 import org.apache.hadoop.fs.FileSystem;
28 import org.apache.hadoop.fs.Path;
29 import org.apache.hadoop.hbase.HBaseTestingUtility;
30 import org.apache.hadoop.hbase.HColumnDescriptor;
31 import org.apache.hadoop.hbase.HRegionInfo;
32 import org.apache.hadoop.hbase.HTableDescriptor;
33 import org.apache.hadoop.hbase.Stoppable;
34 import org.apache.hadoop.hbase.TableName;
35 import org.apache.hadoop.hbase.client.Put;
36 import org.apache.hadoop.hbase.testclassification.MediumTests;
37 import org.apache.hadoop.hbase.testclassification.RegionServerTests;
38 import org.apache.hadoop.hbase.util.Bytes;
39 import org.apache.hadoop.hbase.util.FSUtils;
40 import org.apache.hadoop.hbase.wal.WALFactory;
41 import org.junit.After;
42 import org.junit.Before;
43 import org.junit.Test;
44 import org.junit.experimental.categories.Category;
45
46 import java.io.IOException;
47 import java.io.InterruptedIOException;
48 import java.util.ArrayList;
49 import java.util.Collection;
50 import java.util.List;
51 import java.util.concurrent.atomic.AtomicBoolean;
52 import java.util.concurrent.atomic.AtomicReference;
53
54
55
56
57
58 @Category({RegionServerTests.class, MediumTests.class})
59 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="JLM_JSR166_UTILCONCURRENT_MONITORENTER",
60 justification="Use of an atomic type both as monitor and condition variable is intended")
61 public class TestCompactionArchiveConcurrentClose {
62 public HBaseTestingUtility testUtil;
63
64 private Path testDir;
65 private AtomicBoolean archived = new AtomicBoolean();
66
67 @Before
68 public void setup() throws Exception {
69 testUtil = HBaseTestingUtility.createLocalHTU();
70 testDir = testUtil.getDataTestDir("TestStoreFileRefresherChore");
71 FSUtils.setRootDir(testUtil.getConfiguration(), testDir);
72 }
73
74 @After
75 public void tearDown() throws Exception {
76 testUtil.cleanupTestDir();
77 }
78
79 @Test
80 public void testStoreCloseAndDischargeRunningInParallel() throws Exception {
81 byte[] fam = Bytes.toBytes("f");
82 byte[] col = Bytes.toBytes("c");
83 byte[] val = Bytes.toBytes("val");
84
85 TableName tableName = TableName.valueOf(getClass().getSimpleName());
86 HTableDescriptor htd = new HTableDescriptor(tableName);
87 htd.addFamily(new HColumnDescriptor(fam));
88 HRegionInfo info = new HRegionInfo(tableName, null, null, false);
89 final Region region = initHRegion(htd, info);
90 RegionServerServices rss = mock(RegionServerServices.class);
91 List<Region> regions = new ArrayList<Region>();
92 regions.add(region);
93 when(rss.getOnlineRegions()).thenReturn(regions);
94
95
96 final CompactedHFilesDischarger cleaner =
97 new CompactedHFilesDischarger(1000, (Stoppable) null, rss, false);
98
99 int batchSize = 10;
100 int fileCount = 10;
101 for (int f = 0; f < fileCount; f++) {
102 int start = f * batchSize;
103 for (int i = start; i < start + batchSize; i++) {
104 Put p = new Put(Bytes.toBytes("row" + i));
105 p.addColumn(fam, col, val);
106 region.put(p);
107 }
108
109 region.flush(true);
110 }
111
112 Store store = region.getStore(fam);
113 assertEquals(fileCount, store.getStorefilesCount());
114
115 Collection<StoreFile> storefiles = store.getStorefiles();
116
117 for (StoreFile file : storefiles) {
118 assertFalse(file.isCompactedAway());
119 }
120
121 region.compact(true);
122
123
124 Thread cleanerThread = new Thread() {
125 public void run() {
126 cleaner.chore();
127 }
128 };
129 cleanerThread.start();
130
131 synchronized (archived) {
132 if (!archived.get()) {
133 archived.wait();
134 }
135 }
136 final AtomicReference<Exception> closeException = new AtomicReference<>();
137 Thread closeThread = new Thread() {
138 public void run() {
139
140 try {
141 ((HRegion) region).close();
142 } catch (IOException e) {
143 closeException.set(e);
144 }
145 }
146 };
147 closeThread.start();
148
149 closeThread.join();
150 cleanerThread.join();
151
152 if (closeException.get() != null) {
153 throw closeException.get();
154 }
155 }
156
157 private Region initHRegion(HTableDescriptor htd, HRegionInfo info)
158 throws IOException {
159 Configuration conf = testUtil.getConfiguration();
160 Path tableDir = FSUtils.getTableDir(testDir, htd.getTableName());
161
162 HRegionFileSystem fs = new WaitingHRegionFileSystem(conf, tableDir.getFileSystem(conf),
163 tableDir, info);
164 final Configuration walConf = new Configuration(conf);
165 FSUtils.setRootDir(walConf, tableDir);
166 final WALFactory wals = new WALFactory(walConf, null, "log_" + info.getEncodedName());
167 HRegion region =
168 new HRegion(fs, wals.getWAL(info.getEncodedNameAsBytes(), info.getTable().getNamespace()),
169 conf, htd, null);
170
171 region.initialize();
172
173 return region;
174 }
175
176 private class WaitingHRegionFileSystem extends HRegionFileSystem {
177
178 public WaitingHRegionFileSystem(final Configuration conf, final FileSystem fs,
179 final Path tableDir, final HRegionInfo regionInfo) {
180 super(conf, fs, tableDir, regionInfo);
181 }
182
183 @Override
184 public void removeStoreFiles(String familyName, Collection<StoreFile> storeFiles)
185 throws IOException {
186 super.removeStoreFiles(familyName, storeFiles);
187 archived.set(true);
188 synchronized (archived) {
189 archived.notifyAll();
190 }
191 try {
192
193
194 Thread.sleep(100);
195 } catch (InterruptedException ie) {
196 throw new InterruptedIOException("Interrupted waiting for latch");
197 }
198 }
199 }
200 }