1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.util;
20
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertFalse;
23 import static org.junit.Assert.assertNotEquals;
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.DataOutputStream;
29 import java.io.File;
30 import java.io.IOException;
31 import java.util.Random;
32 import java.util.UUID;
33
34 import org.apache.hadoop.conf.Configuration;
35 import org.apache.hadoop.fs.FSDataInputStream;
36 import org.apache.hadoop.fs.FSDataOutputStream;
37 import org.apache.hadoop.fs.FileStatus;
38 import org.apache.hadoop.fs.FileSystem;
39 import org.apache.hadoop.fs.Path;
40 import org.apache.hadoop.fs.permission.FsPermission;
41 import org.apache.hadoop.hbase.HBaseConfiguration;
42 import org.apache.hadoop.hbase.HBaseTestingUtility;
43 import org.apache.hadoop.hbase.HConstants;
44 import org.apache.hadoop.hbase.HDFSBlocksDistribution;
45 import org.apache.hadoop.hbase.testclassification.MediumTests;
46 import org.apache.hadoop.hbase.exceptions.DeserializationException;
47 import org.apache.hadoop.hdfs.DFSConfigKeys;
48 import org.apache.hadoop.hdfs.DFSHedgedReadMetrics;
49 import org.apache.hadoop.hdfs.DFSTestUtil;
50 import org.apache.hadoop.hdfs.MiniDFSCluster;
51 import org.junit.Test;
52 import org.junit.experimental.categories.Category;
53
54
55
56
57 @Category(MediumTests.class)
58 public class TestFSUtils {
59
60
61
62
63 @Test
64 public void testMatchingTail() throws IOException {
65 HBaseTestingUtility htu = new HBaseTestingUtility();
66 final FileSystem fs = htu.getTestFileSystem();
67 Path rootdir = htu.getDataTestDir();
68 assertTrue(rootdir.depth() > 1);
69 Path partPath = new Path("a", "b");
70 Path fullPath = new Path(rootdir, partPath);
71 Path fullyQualifiedPath = fs.makeQualified(fullPath);
72 assertFalse(FSUtils.isMatchingTail(fullPath, partPath));
73 assertFalse(FSUtils.isMatchingTail(fullPath, partPath.toString()));
74 assertTrue(FSUtils.isStartingWithPath(rootdir, fullPath.toString()));
75 assertTrue(FSUtils.isStartingWithPath(fullyQualifiedPath, fullPath.toString()));
76 assertFalse(FSUtils.isStartingWithPath(rootdir, partPath.toString()));
77 assertFalse(FSUtils.isMatchingTail(fullyQualifiedPath, partPath));
78 assertTrue(FSUtils.isMatchingTail(fullyQualifiedPath, fullPath));
79 assertTrue(FSUtils.isMatchingTail(fullyQualifiedPath, fullPath.toString()));
80 assertTrue(FSUtils.isMatchingTail(fullyQualifiedPath, fs.makeQualified(fullPath)));
81 assertTrue(FSUtils.isStartingWithPath(rootdir, fullyQualifiedPath.toString()));
82 assertFalse(FSUtils.isMatchingTail(fullPath, new Path("x")));
83 assertFalse(FSUtils.isMatchingTail(new Path("x"), fullPath));
84 }
85
86 @Test
87 public void testVersion() throws DeserializationException, IOException {
88 HBaseTestingUtility htu = new HBaseTestingUtility();
89 final FileSystem fs = htu.getTestFileSystem();
90 final Path rootdir = htu.getDataTestDir();
91 assertNull(FSUtils.getVersion(fs, rootdir));
92
93 Path versionFile = new Path(rootdir, HConstants.VERSION_FILE_NAME);
94 FSDataOutputStream s = fs.create(versionFile);
95 final String version = HConstants.FILE_SYSTEM_VERSION;
96 s.writeUTF(version);
97 s.close();
98 assertTrue(fs.exists(versionFile));
99 FileStatus [] status = fs.listStatus(versionFile);
100 assertNotNull(status);
101 assertTrue(status.length > 0);
102 String newVersion = FSUtils.getVersion(fs, rootdir);
103 assertEquals(version.length(), newVersion.length());
104 assertEquals(version, newVersion);
105
106 assertEquals(version, FSUtils.getVersion(fs, rootdir));
107 FSUtils.checkVersion(fs, rootdir, true);
108 }
109
110 @Test public void testIsHDFS() throws Exception {
111 HBaseTestingUtility htu = new HBaseTestingUtility();
112 htu.getConfiguration().setBoolean("dfs.support.append", false);
113 assertFalse(FSUtils.isHDFS(htu.getConfiguration()));
114 htu.getConfiguration().setBoolean("dfs.support.append", true);
115 MiniDFSCluster cluster = null;
116 try {
117 cluster = htu.startMiniDFSCluster(1);
118 assertTrue(FSUtils.isHDFS(htu.getConfiguration()));
119 assertTrue(FSUtils.isAppendSupported(htu.getConfiguration()));
120 } finally {
121 if (cluster != null) cluster.shutdown();
122 }
123 }
124
125 private void WriteDataToHDFS(FileSystem fs, Path file, int dataSize)
126 throws Exception {
127 FSDataOutputStream out = fs.create(file);
128 byte [] data = new byte[dataSize];
129 out.write(data, 0, dataSize);
130 out.close();
131 }
132
133 @Test public void testcomputeHDFSBlocksDistribution() throws Exception {
134 HBaseTestingUtility htu = new HBaseTestingUtility();
135 final int DEFAULT_BLOCK_SIZE = 1024;
136 htu.getConfiguration().setLong("dfs.blocksize", DEFAULT_BLOCK_SIZE);
137 MiniDFSCluster cluster = null;
138 Path testFile = null;
139
140 try {
141
142 String hosts[] = new String[] { "host1", "host2", "host3" };
143 cluster = htu.startMiniDFSCluster(hosts);
144 cluster.waitActive();
145 FileSystem fs = cluster.getFileSystem();
146
147
148 testFile = new Path("/test1.txt");
149 WriteDataToHDFS(fs, testFile, 2*DEFAULT_BLOCK_SIZE);
150
151
152
153
154 final long maxTime = System.currentTimeMillis() + 2000;
155 boolean ok;
156 do {
157 ok = true;
158 FileStatus status = fs.getFileStatus(testFile);
159 HDFSBlocksDistribution blocksDistribution =
160 FSUtils.computeHDFSBlocksDistribution(fs, status, 0, status.getLen());
161 long uniqueBlocksTotalWeight =
162 blocksDistribution.getUniqueBlocksTotalWeight();
163 for (String host : hosts) {
164 long weight = blocksDistribution.getWeight(host);
165 ok = (ok && uniqueBlocksTotalWeight == weight);
166 }
167 } while (!ok && System.currentTimeMillis() < maxTime);
168 assertTrue(ok);
169 } finally {
170 htu.shutdownMiniDFSCluster();
171 }
172
173
174 try {
175
176 String hosts[] = new String[] { "host1", "host2", "host3", "host4" };
177 cluster = htu.startMiniDFSCluster(hosts);
178 cluster.waitActive();
179 FileSystem fs = cluster.getFileSystem();
180
181
182 testFile = new Path("/test2.txt");
183 WriteDataToHDFS(fs, testFile, 3*DEFAULT_BLOCK_SIZE);
184
185
186
187
188 final long maxTime = System.currentTimeMillis() + 2000;
189 long weight;
190 long uniqueBlocksTotalWeight;
191 do {
192 FileStatus status = fs.getFileStatus(testFile);
193 HDFSBlocksDistribution blocksDistribution =
194 FSUtils.computeHDFSBlocksDistribution(fs, status, 0, status.getLen());
195 uniqueBlocksTotalWeight = blocksDistribution.getUniqueBlocksTotalWeight();
196
197 String tophost = blocksDistribution.getTopHosts().get(0);
198 weight = blocksDistribution.getWeight(tophost);
199
200
201 } while (uniqueBlocksTotalWeight != weight && System.currentTimeMillis() < maxTime);
202 assertTrue(uniqueBlocksTotalWeight == weight);
203
204 } finally {
205 htu.shutdownMiniDFSCluster();
206 }
207
208
209 try {
210
211 String hosts[] = new String[] { "host1", "host2", "host3", "host4" };
212 cluster = htu.startMiniDFSCluster(hosts);
213 cluster.waitActive();
214 FileSystem fs = cluster.getFileSystem();
215
216
217 testFile = new Path("/test3.txt");
218 WriteDataToHDFS(fs, testFile, DEFAULT_BLOCK_SIZE);
219
220
221
222 final long maxTime = System.currentTimeMillis() + 2000;
223 HDFSBlocksDistribution blocksDistribution;
224 do {
225 FileStatus status = fs.getFileStatus(testFile);
226 blocksDistribution = FSUtils.computeHDFSBlocksDistribution(fs, status, 0, status.getLen());
227
228 }
229 while (blocksDistribution.getTopHosts().size() != 3 && System.currentTimeMillis() < maxTime);
230 assertEquals("Wrong number of hosts distributing blocks.", 3,
231 blocksDistribution.getTopHosts().size());
232 } finally {
233 htu.shutdownMiniDFSCluster();
234 }
235 }
236
237 @Test
238 public void testPermMask() throws Exception {
239
240 Configuration conf = HBaseConfiguration.create();
241 FileSystem fs = FileSystem.get(conf);
242
243
244 FsPermission defaultFsPerm = FSUtils.getFilePermissions(fs, conf,
245 HConstants.DATA_FILE_UMASK_KEY);
246
247 assertEquals(FsPermission.getFileDefault(), defaultFsPerm);
248
249 conf.setBoolean(HConstants.ENABLE_DATA_FILE_UMASK, true);
250
251 FsPermission defaultStartPerm = FSUtils.getFilePermissions(fs, conf,
252 HConstants.DATA_FILE_UMASK_KEY);
253
254
255
256
257 assertEquals(new FsPermission(FSUtils.FULL_RWX_PERMISSIONS), defaultStartPerm);
258
259 conf.setStrings(HConstants.DATA_FILE_UMASK_KEY, "077");
260
261 FsPermission filePerm = FSUtils.getFilePermissions(fs, conf,
262 HConstants.DATA_FILE_UMASK_KEY);
263 assertEquals(new FsPermission("700"), filePerm);
264
265
266 Path p = new Path("target" + File.separator + UUID.randomUUID().toString());
267 try {
268 FSDataOutputStream out = FSUtils.create(conf, fs, p, filePerm, null);
269 out.close();
270 FileStatus stat = fs.getFileStatus(p);
271 assertEquals(new FsPermission("700"), stat.getPermission());
272
273 } finally {
274 fs.delete(p, true);
275 }
276 }
277
278 @Test
279 public void testDeleteAndExists() throws Exception {
280 HBaseTestingUtility htu = new HBaseTestingUtility();
281 Configuration conf = htu.getConfiguration();
282 conf.setBoolean(HConstants.ENABLE_DATA_FILE_UMASK, true);
283 FileSystem fs = FileSystem.get(conf);
284 FsPermission perms = FSUtils.getFilePermissions(fs, conf, HConstants.DATA_FILE_UMASK_KEY);
285
286 String file = UUID.randomUUID().toString();
287 Path p = new Path(htu.getDataTestDir(), "temptarget" + File.separator + file);
288 Path p1 = new Path(htu.getDataTestDir(), "temppath" + File.separator + file);
289 try {
290 FSDataOutputStream out = FSUtils.create(conf, fs, p, perms, null);
291 out.close();
292 assertTrue("The created file should be present", FSUtils.isExists(fs, p));
293
294 FSUtils.delete(fs, p, false);
295
296 FSDataOutputStream out1 = FSUtils.create(conf, fs, p1, perms, null);
297 out1.close();
298
299 FSUtils.delete(fs, p1, true);
300 assertFalse("The created file should be present", FSUtils.isExists(fs, p1));
301
302 } finally {
303 FSUtils.delete(fs, p, true);
304 FSUtils.delete(fs, p1, true);
305 }
306 }
307
308 @Test
309 public void testRenameAndSetModifyTime() throws Exception {
310 HBaseTestingUtility htu = new HBaseTestingUtility();
311 Configuration conf = htu.getConfiguration();
312
313 MiniDFSCluster cluster = htu.startMiniDFSCluster(1);
314 assertTrue(FSUtils.isHDFS(conf));
315
316 FileSystem fs = FileSystem.get(conf);
317 Path testDir = htu.getDataTestDirOnTestFS("testArchiveFile");
318
319 String file = UUID.randomUUID().toString();
320 Path p = new Path(testDir, file);
321
322 FSDataOutputStream out = fs.create(p);
323 out.close();
324 assertTrue("The created file should be present", FSUtils.isExists(fs, p));
325
326 long expect = System.currentTimeMillis() + 1000;
327 assertNotEquals(expect, fs.getFileStatus(p).getModificationTime());
328
329 ManualEnvironmentEdge mockEnv = new ManualEnvironmentEdge();
330 mockEnv.setValue(expect);
331 EnvironmentEdgeManager.injectEdge(mockEnv);
332 try {
333 String dstFile = UUID.randomUUID().toString();
334 Path dst = new Path(testDir , dstFile);
335
336 assertTrue(FSUtils.renameAndSetModifyTime(fs, p, dst));
337 assertFalse("The moved file should not be present", FSUtils.isExists(fs, p));
338 assertTrue("The dst file should be present", FSUtils.isExists(fs, dst));
339
340 assertEquals(expect, fs.getFileStatus(dst).getModificationTime());
341 cluster.shutdown();
342 } finally {
343 EnvironmentEdgeManager.reset();
344 }
345 }
346
347 private void verifyFileInDirWithStoragePolicy(final String policy) throws Exception {
348 HBaseTestingUtility htu = new HBaseTestingUtility();
349 Configuration conf = htu.getConfiguration();
350 conf.set(HConstants.WAL_STORAGE_POLICY, policy);
351
352 MiniDFSCluster cluster = htu.startMiniDFSCluster(1);
353 try {
354 assertTrue(FSUtils.isHDFS(conf));
355
356 FileSystem fs = FileSystem.get(conf);
357 Path testDir = htu.getDataTestDirOnTestFS("testArchiveFile");
358 fs.mkdirs(testDir);
359
360 FSUtils.setStoragePolicy(fs, conf, testDir, HConstants.WAL_STORAGE_POLICY,
361 HConstants.DEFAULT_WAL_STORAGE_POLICY);
362
363 String file = UUID.randomUUID().toString();
364 Path p = new Path(testDir, file);
365 WriteDataToHDFS(fs, p, 4096);
366
367 cleanupFile(fs, testDir);
368 } finally {
369 cluster.shutdown();
370 }
371 }
372
373 @Test
374 public void testSetStoragePolicyDefault() throws Exception {
375 verifyFileInDirWithStoragePolicy(HConstants.DEFAULT_WAL_STORAGE_POLICY);
376 }
377
378
379 @Test
380 public void testSetStoragePolicyValidButMaybeNotPresent() throws Exception {
381 verifyFileInDirWithStoragePolicy("ALL_SSD");
382 }
383
384
385 @Test
386 public void testSetStoragePolicyInvalid() throws Exception {
387 verifyFileInDirWithStoragePolicy("1772");
388 }
389
390 private void cleanupFile(FileSystem fileSys, Path name) throws IOException {
391 assertTrue(fileSys.exists(name));
392 assertTrue(fileSys.delete(name, true));
393 assertTrue(!fileSys.exists(name));
394 }
395
396
397
398
399
400
401 @Test public void testDFSHedgedReadMetrics() throws Exception {
402 HBaseTestingUtility htu = new HBaseTestingUtility();
403
404
405 Configuration conf = htu.getConfiguration();
406 conf.setInt(DFSConfigKeys.DFS_DFSCLIENT_HEDGED_READ_THREADPOOL_SIZE, 5);
407 conf.setLong(DFSConfigKeys.DFS_DFSCLIENT_HEDGED_READ_THRESHOLD_MILLIS, 0);
408 conf.setLong(DFSConfigKeys.DFS_BLOCK_SIZE_KEY, 4096);
409 conf.setLong(DFSConfigKeys.DFS_CLIENT_READ_PREFETCH_SIZE_KEY, 4096);
410
411 conf.setInt(DFSConfigKeys.DFS_CLIENT_RETRY_WINDOW_BASE, 0);
412 conf.setBoolean("dfs.datanode.transferTo.allowed", false);
413 MiniDFSCluster cluster = new MiniDFSCluster.Builder(conf).numDataNodes(3).build();
414
415 DFSHedgedReadMetrics metrics = FSUtils.getDFSHedgedReadMetrics(conf);
416 assertEquals(0, metrics.getHedgedReadOps());
417 FileSystem fileSys = cluster.getFileSystem();
418 try {
419 Path p = new Path("preadtest.dat");
420
421 DFSTestUtil.createFile(fileSys, p, 12 * blockSize, 12 * blockSize,
422 blockSize, (short) 3, seed);
423 pReadFile(fileSys, p);
424 cleanupFile(fileSys, p);
425 assertTrue(metrics.getHedgedReadOps() > 0);
426 } finally {
427 fileSys.close();
428 cluster.shutdown();
429 }
430 }
431
432
433 static final int blockSize = 4096;
434 static final long seed = 0xDEADBEEFL;
435
436 private void pReadFile(FileSystem fileSys, Path name) throws IOException {
437 FSDataInputStream stm = fileSys.open(name);
438 byte[] expected = new byte[12 * blockSize];
439 Random rand = new Random(seed);
440 rand.nextBytes(expected);
441
442 byte[] actual = new byte[4096];
443 stm.readFully(actual);
444 checkAndEraseData(actual, 0, expected, "Read Sanity Test");
445
446 actual = new byte[8192];
447 doPread(stm, 0L, actual, 0, 8192);
448 checkAndEraseData(actual, 0, expected, "Pread Test 1");
449
450 actual = new byte[4096];
451 stm.readFully(actual);
452 checkAndEraseData(actual, 4096, expected, "Pread Test 2");
453
454
455 stm.readFully(blockSize - 2048, actual, 0, 4096);
456 checkAndEraseData(actual, (blockSize - 2048), expected, "Pread Test 3");
457
458
459 actual = new byte[blockSize + 4096];
460 stm.readFully(blockSize - 2048, actual);
461 checkAndEraseData(actual, (blockSize - 2048), expected, "Pread Test 4");
462
463
464 actual = new byte[blockSize + 4096];
465 stm.readFully(10 * blockSize - 2048, actual);
466 checkAndEraseData(actual, (10 * blockSize - 2048), expected, "Pread Test 5");
467
468
469 actual = new byte[4096];
470 stm.readFully(actual);
471 checkAndEraseData(actual, 8192, expected, "Pread Test 6");
472
473 stm.close();
474
475 stm = fileSys.open(name);
476 stm.readFully(1, actual, 0, 4096);
477 stm.readFully(4*blockSize, actual, 0, 4096);
478 stm.readFully(7*blockSize, actual, 0, 4096);
479 actual = new byte[3*4096];
480 stm.readFully(0*blockSize, actual, 0, 3*4096);
481 checkAndEraseData(actual, 0, expected, "Pread Test 7");
482 actual = new byte[8*4096];
483 stm.readFully(3*blockSize, actual, 0, 8*4096);
484 checkAndEraseData(actual, 3*blockSize, expected, "Pread Test 8");
485
486 stm.readFully(11*blockSize+blockSize/2, actual, 0, blockSize/2);
487 IOException res = null;
488 try {
489 stm.readFully(11*blockSize+blockSize/2, actual, 0, blockSize);
490 } catch (IOException e) {
491
492 res = e;
493 }
494 assertTrue("Error reading beyond file boundary.", res != null);
495
496 stm.close();
497 }
498
499 private void checkAndEraseData(byte[] actual, int from, byte[] expected, String message) {
500 for (int idx = 0; idx < actual.length; idx++) {
501 assertEquals(message+" byte "+(from+idx)+" differs. expected "+
502 expected[from+idx]+" actual "+actual[idx],
503 actual[idx], expected[from+idx]);
504 actual[idx] = 0;
505 }
506 }
507
508 private void doPread(FSDataInputStream stm, long position, byte[] buffer,
509 int offset, int length) throws IOException {
510 int nread = 0;
511
512
513
514
515
516
517
518
519
520 while (nread < length) {
521 int nbytes =
522 stm.read(position + nread, buffer, offset + nread, length - nread);
523 assertTrue("Error in pread", nbytes > 0);
524 nread += nbytes;
525 }
526
527
528
529
530
531
532
533
534
535
536
537 }
538 }