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 public class TestCompactionArchiveConcurrentClose {
60 public HBaseTestingUtility testUtil;
61
62 private Path testDir;
63 private AtomicBoolean archived = new AtomicBoolean();
64
65 @Before
66 public void setup() throws Exception {
67 testUtil = HBaseTestingUtility.createLocalHTU();
68 testDir = testUtil.getDataTestDir("TestStoreFileRefresherChore");
69 FSUtils.setRootDir(testUtil.getConfiguration(), testDir);
70 }
71
72 @After
73 public void tearDown() throws Exception {
74 testUtil.cleanupTestDir();
75 }
76
77 @Test
78 public void testStoreCloseAndDischargeRunningInParallel() throws Exception {
79 byte[] fam = Bytes.toBytes("f");
80 byte[] col = Bytes.toBytes("c");
81 byte[] val = Bytes.toBytes("val");
82
83 TableName tableName = TableName.valueOf(getClass().getSimpleName());
84 HTableDescriptor htd = new HTableDescriptor(tableName);
85 htd.addFamily(new HColumnDescriptor(fam));
86 HRegionInfo info = new HRegionInfo(tableName, null, null, false);
87 final Region region = initHRegion(htd, info);
88 RegionServerServices rss = mock(RegionServerServices.class);
89 List<Region> regions = new ArrayList<Region>();
90 regions.add(region);
91 when(rss.getOnlineRegions()).thenReturn(regions);
92
93
94 final CompactedHFilesDischarger cleaner =
95 new CompactedHFilesDischarger(1000, (Stoppable) null, rss, false);
96
97 int batchSize = 10;
98 int fileCount = 10;
99 for (int f = 0; f < fileCount; f++) {
100 int start = f * batchSize;
101 for (int i = start; i < start + batchSize; i++) {
102 Put p = new Put(Bytes.toBytes("row" + i));
103 p.addColumn(fam, col, val);
104 region.put(p);
105 }
106
107 region.flush(true);
108 }
109
110 Store store = region.getStore(fam);
111 assertEquals(fileCount, store.getStorefilesCount());
112
113 Collection<StoreFile> storefiles = store.getStorefiles();
114
115 for (StoreFile file : storefiles) {
116 assertFalse(file.isCompactedAway());
117 }
118
119 region.compact(true);
120
121
122 Thread cleanerThread = new Thread() {
123 public void run() {
124 cleaner.chore();
125 }
126 };
127 cleanerThread.start();
128
129 synchronized (archived) {
130 if (!archived.get()) {
131 archived.wait();
132 }
133 }
134 final AtomicReference<Exception> closeException = new AtomicReference<>();
135 Thread closeThread = new Thread() {
136 public void run() {
137
138 try {
139 ((HRegion) region).close();
140 } catch (IOException e) {
141 closeException.set(e);
142 }
143 }
144 };
145 closeThread.start();
146
147 closeThread.join();
148 cleanerThread.join();
149
150 if (closeException.get() != null) {
151 throw closeException.get();
152 }
153 }
154
155 private Region initHRegion(HTableDescriptor htd, HRegionInfo info)
156 throws IOException {
157 Configuration conf = testUtil.getConfiguration();
158 Path tableDir = FSUtils.getTableDir(testDir, htd.getTableName());
159
160 HRegionFileSystem fs = new WaitingHRegionFileSystem(conf, tableDir.getFileSystem(conf),
161 tableDir, info);
162 final Configuration walConf = new Configuration(conf);
163 FSUtils.setRootDir(walConf, tableDir);
164 final WALFactory wals = new WALFactory(walConf, null, "log_" + info.getEncodedName());
165 HRegion region =
166 new HRegion(fs, wals.getWAL(info.getEncodedNameAsBytes(), info.getTable().getNamespace()),
167 conf, htd, null);
168
169 region.initialize();
170
171 return region;
172 }
173
174 private class WaitingHRegionFileSystem extends HRegionFileSystem {
175
176 public WaitingHRegionFileSystem(final Configuration conf, final FileSystem fs,
177 final Path tableDir, final HRegionInfo regionInfo) {
178 super(conf, fs, tableDir, regionInfo);
179 }
180
181 @Override
182 public void removeStoreFiles(String familyName, Collection<StoreFile> storeFiles)
183 throws IOException {
184 super.removeStoreFiles(familyName, storeFiles);
185 archived.set(true);
186 synchronized (archived) {
187 archived.notifyAll();
188 }
189 try {
190
191
192 Thread.sleep(100);
193 } catch (InterruptedException ie) {
194 throw new InterruptedIOException("Interrupted waiting for latch");
195 }
196 }
197 }
198 }