/** * 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; import java.io.*; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.hdfs.protocol.FSConstants; import org.apache.hadoop.hdfs.protocol.QuotaExceededException; public class TestDFSRename extends junit.framework.TestCase { static Configuration CONF = new Configuration(); static MiniDFSCluster cluster = null; static int countLease(MiniDFSCluster cluster) { return cluster.getNameNode().namesystem.leaseManager.countLease(); } final Path dir = new Path("/test/rename/"); @Override protected void setUp() throws Exception { cluster = new MiniDFSCluster(CONF, 2, true, null); } private void restartCluster() throws IOException { if (cluster != null) { cluster.shutdown(); cluster = null; } cluster = new MiniDFSCluster(CONF, 1, false, null); cluster.waitClusterUp(); } @Override protected void tearDown() throws Exception { if (cluster != null) {cluster.shutdown();} } void list(FileSystem fs, String name) throws IOException { FileSystem.LOG.info("\n\n" + name); for(FileStatus s : fs.listStatus(dir)) { FileSystem.LOG.info("" + s.getPath()); } } static void createFile(FileSystem fs, Path f) throws IOException { DataOutputStream a_out = fs.create(f); a_out.writeBytes("something"); a_out.close(); } public void testRename() throws Exception { FileSystem fs = cluster.getFileSystem(); assertTrue(fs.mkdirs(dir)); { //test lease Path a = new Path(dir, "a"); Path aa = new Path(dir, "aa"); Path b = new Path(dir, "b"); createFile(fs, a); //should not have any lease assertEquals(0, countLease(cluster)); createFile(fs, aa); DataOutputStream aa_out = fs.create(aa); aa_out.writeBytes("something"); //should have 1 lease assertEquals(1, countLease(cluster)); list(fs, "rename0"); fs.rename(a, b); list(fs, "rename1"); aa_out.writeBytes(" more"); aa_out.close(); list(fs, "rename2"); //should not have any lease assertEquals(0, countLease(cluster)); } { // test non-existent destination Path dstPath = new Path("/c/d"); assertFalse(fs.exists(dstPath)); assertFalse(fs.rename(dir, dstPath)); } { // dst cannot be a file or directory under src // test rename /a/b/foo to /a/b/c Path src = new Path("/a/b"); Path dst = new Path("/a/b/c"); createFile(fs, new Path(src, "foo")); // dst cannot be a file under src assertFalse(fs.rename(src, dst)); // dst cannot be a directory under src assertFalse(fs.rename(src.getParent(), dst.getParent())); } { // dst can start with src, if it is not a directory or file under src // test rename /test /testfile Path src = new Path("/testPrefix"); Path dst = new Path("/testPrefixfile"); createFile(fs, src); assertTrue(fs.rename(src, dst)); } { // dst should not be same as src test rename /a/b/c to /a/b/c Path src = new Path("/a/b/c"); createFile(fs, src); assertTrue(fs.rename(src, src)); assertFalse(fs.rename(new Path("/a/b"), new Path("/a/b/"))); assertTrue(fs.rename(src, new Path("/a/b/c/"))); } fs.delete(dir, true); } public void testRenameWithQuota() throws Exception { DistributedFileSystem fs = (DistributedFileSystem) cluster.getFileSystem(); Path src1 = new Path(dir, "testRenameWithQuota/srcdir/src1"); Path src2 = new Path(dir, "testRenameWithQuota/srcdir/src2"); Path dst1 = new Path(dir, "testRenameWithQuota/dstdir/dst1"); Path dst2 = new Path(dir, "testRenameWithQuota/dstdir/dst2"); createFile(fs, src1); createFile(fs, src2); fs.setQuota(src1.getParent(), FSConstants.QUOTA_DONT_SET, FSConstants.QUOTA_DONT_SET); fs.mkdirs(dst1.getParent()); fs.setQuota(dst1.getParent(), FSConstants.QUOTA_DONT_SET, FSConstants.QUOTA_DONT_SET); // Test1: src does not exceed quota and dst has quota to accommodate rename rename(src1, dst1, true, false); // Test2: src does not exceed quota and dst has *no* quota to accommodate // rename fs.setQuota(dst1.getParent(), 1, FSConstants.QUOTA_DONT_SET); rename(src2, dst2, false, true); // Test3: src exceeds quota and dst has *no* quota to accommodate rename fs.setQuota(src1.getParent(), 1, FSConstants.QUOTA_DONT_SET); rename(dst1, src1, false, true); } /** * Perform operations such as setting quota, deletion of files, rename and * ensure system can apply edits log during startup. */ public void testEditsLog() throws Exception { DistributedFileSystem fs = (DistributedFileSystem) cluster.getFileSystem(); Path src1 = new Path(dir, "testEditsLog/srcdir/src1"); Path dst1 = new Path(dir, "testEditsLog/dstdir/dst1"); createFile(fs, src1); fs.mkdirs(dst1.getParent()); createFile(fs, dst1); // Set quota so that dst1 parent cannot allow under it new files/directories fs.setQuota(dst1.getParent(), 2, FSConstants.QUOTA_DONT_SET); // Free up quota for a subsequent rename fs.delete(dst1, true); rename(src1, dst1, true, false); // Restart the cluster and ensure the above operations can be // loaded from the edits log restartCluster(); fs = (DistributedFileSystem)cluster.getFileSystem(); assertFalse(fs.exists(src1)); // ensure src1 is already renamed assertTrue(fs.exists(dst1)); // ensure rename dst exists } private void rename(Path src, Path dst, boolean renameSucceeds, boolean quotaException) throws Exception { DistributedFileSystem fs = (DistributedFileSystem) cluster.getFileSystem(); try { assertEquals(renameSucceeds, fs.rename(src, dst)); } catch (QuotaExceededException ex) { assertTrue(quotaException); } assertEquals(renameSucceeds, !fs.exists(src)); assertEquals(renameSucceeds, fs.exists(dst)); } }