1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.hadoop.hbase.regionserver;
21
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertFalse;
24 import static org.junit.Assert.assertNotNull;
25 import static org.junit.Assert.assertNull;
26 import static org.junit.Assert.assertTrue;
27
28 import java.io.IOException;
29 import java.net.URI;
30 import java.util.Collection;
31 import java.util.List;
32
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35 import org.apache.hadoop.conf.Configuration;
36 import org.apache.hadoop.fs.FSDataInputStream;
37 import org.apache.hadoop.fs.FSDataOutputStream;
38 import org.apache.hadoop.fs.FileStatus;
39 import org.apache.hadoop.fs.FileSystem;
40 import org.apache.hadoop.fs.Path;
41 import org.apache.hadoop.fs.permission.FsPermission;
42 import org.apache.hadoop.hbase.TableName;
43 import org.apache.hadoop.hbase.client.Admin;
44 import org.apache.hadoop.hbase.client.HTable;
45 import org.apache.hadoop.hbase.client.Put;
46 import org.apache.hadoop.hbase.fs.HFileSystem;
47 import org.apache.hadoop.hbase.HRegionInfo;
48 import org.apache.hadoop.hbase.HBaseTestingUtility;
49 import org.apache.hadoop.hbase.HColumnDescriptor;
50 import org.apache.hadoop.hbase.testclassification.SmallTests;
51 import org.apache.hadoop.hbase.util.Bytes;
52 import org.apache.hadoop.hbase.util.FSUtils;
53 import org.apache.hadoop.util.Progressable;
54
55 import org.junit.Test;
56 import org.junit.experimental.categories.Category;
57
58 @Category(SmallTests.class)
59 public class TestHRegionFileSystem {
60 private static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
61 private static final Log LOG = LogFactory.getLog(TestHRegionFileSystem.class);
62 private static final byte[] FAMILY_NAME = Bytes.toBytes("info");
63 private static final byte[][] FAMILIES = {
64 Bytes.add(FAMILY_NAME, Bytes.toBytes("-A")),
65 Bytes.add(FAMILY_NAME, Bytes.toBytes("-B"))
66 };
67 private static final TableName TABLE_NAME = TableName.valueOf("TestTable");
68
69 @Test
70 public void testBlockStoragePolicy() throws Exception {
71 TEST_UTIL = new HBaseTestingUtility();
72 Configuration conf = TEST_UTIL.getConfiguration();
73 TEST_UTIL.startMiniCluster();
74 HTable table = (HTable) TEST_UTIL.createTable(TABLE_NAME, FAMILIES);
75 assertEquals("Should start with empty table", 0, TEST_UTIL.countRows(table));
76 HRegionFileSystem regionFs = getHRegionFS(table, conf);
77
78 String spA = regionFs.getStoragePolicyName(Bytes.toString(FAMILIES[0]));
79 String spB = regionFs.getStoragePolicyName(Bytes.toString(FAMILIES[1]));
80 LOG.debug("Storage policy of cf 0: [" + spA + "].");
81 LOG.debug("Storage policy of cf 1: [" + spB + "].");
82 assertEquals("HOT", spA);
83 assertEquals("HOT", spB);
84
85
86 TEST_UTIL.shutdownMiniCluster();
87 TEST_UTIL.getConfiguration().set(HStore.BLOCK_STORAGE_POLICY_KEY, "WARM");
88 TEST_UTIL.startMiniCluster();
89 table = (HTable) TEST_UTIL.createTable(TABLE_NAME, FAMILIES);
90 regionFs = getHRegionFS(table, conf);
91
92 try (Admin admin = TEST_UTIL.getConnection().getAdmin()) {
93 spA = regionFs.getStoragePolicyName(Bytes.toString(FAMILIES[0]));
94 spB = regionFs.getStoragePolicyName(Bytes.toString(FAMILIES[1]));
95 LOG.debug("Storage policy of cf 0: [" + spA + "].");
96 LOG.debug("Storage policy of cf 1: [" + spB + "].");
97 assertEquals("WARM", spA);
98 assertEquals("WARM", spB);
99
100
101
102 HColumnDescriptor hcdA = new HColumnDescriptor(Bytes.toString(FAMILIES[0]));
103
104 hcdA.setValue(HStore.BLOCK_STORAGE_POLICY_KEY, "ONE_SSD");
105 admin.modifyColumn(TABLE_NAME, hcdA);
106 while (TEST_UTIL.getMiniHBaseCluster().getMaster().getAssignmentManager().getRegionStates()
107 .isRegionsInTransition()) {
108 Thread.sleep(200);
109 LOG.debug("Waiting on table to finish schema altering");
110 }
111
112 HColumnDescriptor hcdB = new HColumnDescriptor(Bytes.toString(FAMILIES[1]));
113 hcdB.setStoragePolicy("ALL_SSD");
114 admin.modifyColumn(TABLE_NAME, hcdB);
115 while (TEST_UTIL.getMiniHBaseCluster().getMaster().getAssignmentManager().getRegionStates()
116 .isRegionsInTransition()) {
117 Thread.sleep(200);
118 LOG.debug("Waiting on table to finish schema altering");
119 }
120 spA = regionFs.getStoragePolicyName(Bytes.toString(FAMILIES[0]));
121 spB = regionFs.getStoragePolicyName(Bytes.toString(FAMILIES[1]));
122 LOG.debug("Storage policy of cf 0: [" + spA + "].");
123 LOG.debug("Storage policy of cf 1: [" + spB + "].");
124 assertNotNull(spA);
125 assertEquals("ONE_SSD", spA);
126 assertNotNull(spB);
127 assertEquals("ALL_SSD", spB);
128
129
130 for (long i = 0; i < 3; i++) {
131 Put put = new Put(Bytes.toBytes(i));
132 put.addColumn(FAMILIES[0], Bytes.toBytes(i), Bytes.toBytes(i));
133 table.put(put);
134 admin.flush(TABLE_NAME);
135 }
136
137 FileSystem fs = TEST_UTIL.getDFSCluster().getFileSystem();
138 Path storePath = regionFs.getStoreDir(Bytes.toString(FAMILIES[0]));
139 FileStatus[] storeFiles = FSUtils.listStatus(fs, storePath);
140 assertNotNull(storeFiles);
141 assertEquals(3, storeFiles.length);
142
143 Path storeTempDir = new Path(regionFs.getTempDir(), Bytes.toString(FAMILIES[0]));
144 assertTrue(fs.exists(storeTempDir));
145 FileStatus[] tempFiles = FSUtils.listStatus(fs, storeTempDir);
146 assertNull(tempFiles);
147
148 assertEquals("ONE_SSD",
149 ((HFileSystem) regionFs.getFileSystem()).getStoragePolicyName(storeTempDir));
150 for (FileStatus status : storeFiles) {
151 assertEquals("ONE_SSD",
152 ((HFileSystem) regionFs.getFileSystem()).getStoragePolicyName(status.getPath()));
153 }
154
155
156 regionFs.setStoragePolicy(Bytes.toString(FAMILIES[0]), "ALL_SSD");
157 regionFs.setStoragePolicy(Bytes.toString(FAMILIES[1]), "ONE_SSD");
158 spA = regionFs.getStoragePolicyName(Bytes.toString(FAMILIES[0]));
159 spB = regionFs.getStoragePolicyName(Bytes.toString(FAMILIES[1]));
160 LOG.debug("Storage policy of cf 0: [" + spA + "].");
161 LOG.debug("Storage policy of cf 1: [" + spB + "].");
162 assertNotNull(spA);
163 assertEquals("ALL_SSD", spA);
164 assertNotNull(spB);
165 assertEquals("ONE_SSD", spB);
166 } finally {
167 table.close();
168 TEST_UTIL.deleteTable(TABLE_NAME);
169 TEST_UTIL.shutdownMiniCluster();
170 }
171 }
172
173 private HRegionFileSystem getHRegionFS(HTable table, Configuration conf) throws IOException {
174 FileSystem fs = TEST_UTIL.getDFSCluster().getFileSystem();
175 Path tableDir = FSUtils.getTableDir(TEST_UTIL.getDefaultRootDirPath(), table.getName());
176 List<Path> regionDirs = FSUtils.getRegionDirs(fs, tableDir);
177 assertEquals(1, regionDirs.size());
178 List<Path> familyDirs = FSUtils.getFamilyDirs(fs, regionDirs.get(0));
179 assertEquals(2, familyDirs.size());
180 HRegionInfo hri = table.getRegionLocator().getAllRegionLocations().get(0).getRegionInfo();
181 HRegionFileSystem regionFs = new HRegionFileSystem(conf, new HFileSystem(fs), tableDir, hri);
182 return regionFs;
183 }
184
185 @Test
186 public void testOnDiskRegionCreation() throws IOException {
187 Path rootDir = TEST_UTIL.getDataTestDirOnTestFS("testOnDiskRegionCreation");
188 FileSystem fs = TEST_UTIL.getTestFileSystem();
189 Configuration conf = TEST_UTIL.getConfiguration();
190
191
192 HRegionInfo hri = new HRegionInfo(TableName.valueOf("TestTable"));
193 HRegionFileSystem regionFs = HRegionFileSystem.createRegionOnFileSystem(conf, fs,
194 FSUtils.getTableDir(rootDir, hri.getTable()), hri);
195
196
197 Path regionDir = regionFs.getRegionDir();
198 assertTrue("The region folder should be created", fs.exists(regionDir));
199
200
201 HRegionInfo hriVerify = HRegionFileSystem.loadRegionInfoFileContent(fs, regionDir);
202 assertEquals(hri, hriVerify);
203
204
205 regionFs = HRegionFileSystem.openRegionFromFileSystem(conf, fs,
206 FSUtils.getTableDir(rootDir, hri.getTable()), hri, false);
207 assertEquals(regionDir, regionFs.getRegionDir());
208
209
210 HRegionFileSystem.deleteRegionFromFileSystem(conf, fs,
211 FSUtils.getTableDir(rootDir, hri.getTable()), hri);
212 assertFalse("The region folder should be removed", fs.exists(regionDir));
213
214 fs.delete(rootDir, true);
215 }
216
217 @Test
218 public void testNonIdempotentOpsWithRetries() throws IOException {
219 Path rootDir = TEST_UTIL.getDataTestDirOnTestFS("testOnDiskRegionCreation");
220 FileSystem fs = TEST_UTIL.getTestFileSystem();
221 Configuration conf = TEST_UTIL.getConfiguration();
222
223
224 HRegionInfo hri = new HRegionInfo(TableName.valueOf("TestTable"));
225 HRegionFileSystem regionFs = HRegionFileSystem.createRegionOnFileSystem(conf, fs, rootDir, hri);
226 assertTrue(fs.exists(regionFs.getRegionDir()));
227
228 regionFs = new HRegionFileSystem(conf, new MockFileSystemForCreate(),
229 null, null);
230
231
232 boolean result = regionFs.createDir(new Path("/foo/bar"));
233 assertTrue("Couldn't create the directory", result);
234
235
236 regionFs = new HRegionFileSystem(conf, new MockFileSystem(), null, null);
237 result = regionFs.rename(new Path("/foo/bar"), new Path("/foo/bar2"));
238 assertTrue("Couldn't rename the directory", result);
239
240 regionFs = new HRegionFileSystem(conf, new MockFileSystem(), null, null);
241 result = regionFs.deleteDir(new Path("/foo/bar"));
242 assertTrue("Couldn't delete the directory", result);
243 fs.delete(rootDir, true);
244 }
245
246 static class MockFileSystemForCreate extends MockFileSystem {
247 @Override
248 public boolean exists(Path path) {
249 return false;
250 }
251 }
252
253
254
255
256
257 static class MockFileSystem extends FileSystem {
258 int retryCount;
259 final static int successRetryCount = 3;
260
261 public MockFileSystem() {
262 retryCount = 0;
263 }
264
265 @Override
266 public FSDataOutputStream append(Path arg0, int arg1, Progressable arg2) throws IOException {
267 throw new IOException("");
268 }
269
270 @Override
271 public FSDataOutputStream create(Path arg0, FsPermission arg1, boolean arg2, int arg3,
272 short arg4, long arg5, Progressable arg6) throws IOException {
273 LOG.debug("Create, " + retryCount);
274 if (retryCount++ < successRetryCount) throw new IOException("Something bad happen");
275 return null;
276 }
277
278 @Override
279 public boolean delete(Path arg0) throws IOException {
280 if (retryCount++ < successRetryCount) throw new IOException("Something bad happen");
281 return true;
282 }
283
284 @Override
285 public boolean delete(Path arg0, boolean arg1) throws IOException {
286 if (retryCount++ < successRetryCount) throw new IOException("Something bad happen");
287 return true;
288 }
289
290 @Override
291 public FileStatus getFileStatus(Path arg0) throws IOException {
292 FileStatus fs = new FileStatus();
293 return fs;
294 }
295
296 @Override
297 public boolean exists(Path path) {
298 return true;
299 }
300
301 @Override
302 public URI getUri() {
303 throw new RuntimeException("Something bad happen");
304 }
305
306 @Override
307 public Path getWorkingDirectory() {
308 throw new RuntimeException("Something bad happen");
309 }
310
311 @Override
312 public FileStatus[] listStatus(Path arg0) throws IOException {
313 throw new IOException("Something bad happen");
314 }
315
316 @Override
317 public boolean mkdirs(Path arg0, FsPermission arg1) throws IOException {
318 LOG.debug("mkdirs, " + retryCount);
319 if (retryCount++ < successRetryCount) throw new IOException("Something bad happen");
320 return true;
321 }
322
323 @Override
324 public FSDataInputStream open(Path arg0, int arg1) throws IOException {
325 throw new IOException("Something bad happen");
326 }
327
328 @Override
329 public boolean rename(Path arg0, Path arg1) throws IOException {
330 LOG.debug("rename, " + retryCount);
331 if (retryCount++ < successRetryCount) throw new IOException("Something bad happen");
332 return true;
333 }
334
335 @Override
336 public void setWorkingDirectory(Path arg0) {
337 throw new RuntimeException("Something bad happen");
338 }
339 }
340
341 @Test
342 public void testTempAndCommit() throws IOException {
343 Path rootDir = TEST_UTIL.getDataTestDirOnTestFS("testTempAndCommit");
344 FileSystem fs = TEST_UTIL.getTestFileSystem();
345 Configuration conf = TEST_UTIL.getConfiguration();
346
347
348 String familyName = "cf";
349 HRegionInfo hri = new HRegionInfo(TableName.valueOf("TestTable"));
350 HRegionFileSystem regionFs = HRegionFileSystem.createRegionOnFileSystem(conf, fs, rootDir, hri);
351
352
353 Collection<StoreFileInfo> storeFiles = regionFs.getStoreFiles(familyName);
354 assertEquals(0, storeFiles != null ? storeFiles.size() : 0);
355
356
357 Path buildPath = regionFs.createTempName();
358 fs.createNewFile(buildPath);
359 storeFiles = regionFs.getStoreFiles(familyName);
360 assertEquals(0, storeFiles != null ? storeFiles.size() : 0);
361
362
363 Path dstPath = regionFs.commitStoreFile(familyName, buildPath);
364 storeFiles = regionFs.getStoreFiles(familyName);
365 assertEquals(0, storeFiles != null ? storeFiles.size() : 0);
366 assertFalse(fs.exists(buildPath));
367
368 fs.delete(rootDir, true);
369 }
370 }