/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.hadoop.hdfs.server.namenode; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.io.File; import java.io.IOException; import java.util.EnumSet; import org.junit.Assert; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FSDataOutputStream; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.FileUtil; import org.apache.hadoop.fs.Path; import org.apache.hadoop.hdfs.DFSConfigKeys; import org.apache.hadoop.hdfs.DFSOutputStream; import org.apache.hadoop.hdfs.DistributedFileSystem; import org.apache.hadoop.hdfs.HdfsConfiguration; import org.apache.hadoop.hdfs.MiniDFSCluster; import org.apache.hadoop.hdfs.client.HdfsDataOutputStream.SyncFlag; import org.apache.hadoop.hdfs.protocol.HdfsConstants; import org.apache.hadoop.hdfs.protocol.HdfsConstants.SafeModeAction; import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfoContiguous; import org.apache.hadoop.hdfs.server.common.HdfsServerConstants.BlockUCState; import org.apache.hadoop.hdfs.server.common.HdfsServerConstants.StartupOption; import org.apache.hadoop.hdfs.server.namenode.LeaseManager.Lease; import org.apache.hadoop.hdfs.util.MD5FileUtils; import org.apache.hadoop.test.GenericTestUtils; import org.apache.hadoop.test.PathUtils; import org.junit.Test; public class TestFSImage { private static final String HADOOP_2_7_ZER0_BLOCK_SIZE_TGZ = "image-with-zero-block-size.tar.gz"; @Test public void testPersist() throws IOException { Configuration conf = new Configuration(); testPersistHelper(conf); } @Test public void testCompression() throws IOException { Configuration conf = new Configuration(); conf.setBoolean(DFSConfigKeys.DFS_IMAGE_COMPRESS_KEY, true); setCompressCodec(conf, "org.apache.hadoop.io.compress.DefaultCodec"); setCompressCodec(conf, "org.apache.hadoop.io.compress.GzipCodec"); setCompressCodec(conf, "org.apache.hadoop.io.compress.BZip2Codec"); setCompressCodec(conf, "org.apache.hadoop.io.compress.Lz4Codec"); } private void setCompressCodec(Configuration conf, String compressCodec) throws IOException { conf.set(DFSConfigKeys.DFS_IMAGE_COMPRESSION_CODEC_KEY, compressCodec); testPersistHelper(conf); } private void testPersistHelper(Configuration conf) throws IOException { MiniDFSCluster cluster = null; try { cluster = new MiniDFSCluster.Builder(conf).build(); cluster.waitActive(); FSNamesystem fsn = cluster.getNamesystem(); DistributedFileSystem fs = cluster.getFileSystem(); final Path dir = new Path("/abc/def"); final Path file1 = new Path(dir, "f1"); final Path file2 = new Path(dir, "f2"); // create an empty file f1 fs.create(file1).close(); // create an under-construction file f2 FSDataOutputStream out = fs.create(file2); out.writeBytes("hello"); ((DFSOutputStream) out.getWrappedStream()).hsync(EnumSet .of(SyncFlag.UPDATE_LENGTH)); // checkpoint fs.setSafeMode(SafeModeAction.SAFEMODE_ENTER); fs.saveNamespace(); fs.setSafeMode(SafeModeAction.SAFEMODE_LEAVE); cluster.restartNameNode(); cluster.waitActive(); fs = cluster.getFileSystem(); assertTrue(fs.isDirectory(dir)); assertTrue(fs.exists(file1)); assertTrue(fs.exists(file2)); // check internals of file2 INodeFile file2Node = fsn.dir.getINode4Write(file2.toString()).asFile(); assertEquals("hello".length(), file2Node.computeFileSize()); assertTrue(file2Node.isUnderConstruction()); BlockInfoContiguous[] blks = file2Node.getBlocks(); assertEquals(1, blks.length); assertEquals(BlockUCState.UNDER_CONSTRUCTION, blks[0].getBlockUCState()); // check lease manager Lease lease = fsn.leaseManager.getLeaseByPath(file2.toString()); Assert.assertNotNull(lease); } finally { if (cluster != null) { cluster.shutdown(); } } } /** * Ensure that the digest written by the saver equals to the digest of the * file. */ @Test public void testDigest() throws IOException { Configuration conf = new Configuration(); MiniDFSCluster cluster = null; try { cluster = new MiniDFSCluster.Builder(conf).numDataNodes(0).build(); DistributedFileSystem fs = cluster.getFileSystem(); fs.setSafeMode(SafeModeAction.SAFEMODE_ENTER); fs.saveNamespace(); fs.setSafeMode(SafeModeAction.SAFEMODE_LEAVE); File currentDir = FSImageTestUtil.getNameNodeCurrentDirs(cluster, 0).get( 0); File fsimage = FSImageTestUtil.findNewestImageFile(currentDir .getAbsolutePath()); assertEquals(MD5FileUtils.readStoredMd5ForFile(fsimage), MD5FileUtils.computeMd5ForFile(fsimage)); } finally { if (cluster != null) { cluster.shutdown(); } } } /** * Ensure mtime and atime can be loaded from fsimage. */ @Test(timeout=60000) public void testLoadMtimeAtime() throws Exception { Configuration conf = new Configuration(); MiniDFSCluster cluster = null; try { cluster = new MiniDFSCluster.Builder(conf).numDataNodes(1).build(); cluster.waitActive(); DistributedFileSystem hdfs = cluster.getFileSystem(); String userDir = hdfs.getHomeDirectory().toUri().getPath().toString(); Path file = new Path(userDir, "file"); Path dir = new Path(userDir, "/dir"); Path link = new Path(userDir, "/link"); hdfs.createNewFile(file); hdfs.mkdirs(dir); hdfs.createSymlink(file, link, false); long mtimeFile = hdfs.getFileStatus(file).getModificationTime(); long atimeFile = hdfs.getFileStatus(file).getAccessTime(); long mtimeDir = hdfs.getFileStatus(dir).getModificationTime(); long mtimeLink = hdfs.getFileLinkStatus(link).getModificationTime(); long atimeLink = hdfs.getFileLinkStatus(link).getAccessTime(); // save namespace and restart cluster hdfs.setSafeMode(HdfsConstants.SafeModeAction.SAFEMODE_ENTER); hdfs.saveNamespace(); hdfs.setSafeMode(HdfsConstants.SafeModeAction.SAFEMODE_LEAVE); cluster.shutdown(); cluster = new MiniDFSCluster.Builder(conf).format(false) .numDataNodes(1).build(); cluster.waitActive(); hdfs = cluster.getFileSystem(); assertEquals(mtimeFile, hdfs.getFileStatus(file).getModificationTime()); assertEquals(atimeFile, hdfs.getFileStatus(file).getAccessTime()); assertEquals(mtimeDir, hdfs.getFileStatus(dir).getModificationTime()); assertEquals(mtimeLink, hdfs.getFileLinkStatus(link).getModificationTime()); assertEquals(atimeLink, hdfs.getFileLinkStatus(link).getAccessTime()); } finally { if (cluster != null) { cluster.shutdown(); } } } /** * In this test case, I have created an image with a file having * preferredblockSize = 0. We are trying to read this image (since file with * preferredblockSize = 0 was allowed pre 2.1.0-beta version. The namenode * after 2.6 version will not be able to read this particular file. * See HDFS-7788 for more information. * @throws Exception */ @Test public void testZeroBlockSize() throws Exception { final Configuration conf = new HdfsConfiguration(); String tarFile = System.getProperty("test.cache.data", "build/test/cache") + "/" + HADOOP_2_7_ZER0_BLOCK_SIZE_TGZ; String testDir = PathUtils.getTestDirName(getClass()); File dfsDir = new File(testDir, "image-with-zero-block-size"); if (dfsDir.exists() && !FileUtil.fullyDelete(dfsDir)) { throw new IOException("Could not delete dfs directory '" + dfsDir + "'"); } FileUtil.unTar(new File(tarFile), new File(testDir)); File nameDir = new File(dfsDir, "name"); GenericTestUtils.assertExists(nameDir); conf.set(DFSConfigKeys.DFS_NAMENODE_NAME_DIR_KEY, nameDir.getAbsolutePath()); MiniDFSCluster cluster = new MiniDFSCluster.Builder(conf).numDataNodes(1) .format(false) .manageDataDfsDirs(false) .manageNameDfsDirs(false) .waitSafeMode(false) .startupOption(StartupOption.UPGRADE) .build(); try { FileSystem fs = cluster.getFileSystem(); Path testPath = new Path("/tmp/zeroBlockFile"); assertTrue("File /tmp/zeroBlockFile doesn't exist ", fs.exists(testPath)); assertTrue("Name node didn't come up", cluster.isNameNodeUp(0)); } finally { cluster.shutdown(); //Clean up FileUtil.fullyDelete(dfsDir); } } }