|
@@ -0,0 +1,366 @@
|
|
|
|
+/**
|
|
|
|
+ * 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 org.apache.commons.logging.Log;
|
|
|
|
+import org.apache.commons.logging.LogFactory;
|
|
|
|
+import org.apache.hadoop.conf.Configuration;
|
|
|
|
+import org.apache.hadoop.fs.Path;
|
|
|
|
+import org.apache.hadoop.hdfs.protocol.ErasureCodingPolicy;
|
|
|
|
+import org.apache.hadoop.hdfs.protocol.HdfsConstants;
|
|
|
|
+import org.apache.hadoop.hdfs.server.namenode.ErasureCodingPolicyManager;
|
|
|
|
+import org.apache.hadoop.io.erasurecode.CodecUtil;
|
|
|
|
+import org.apache.hadoop.io.erasurecode.ErasureCodeNative;
|
|
|
|
+import org.apache.hadoop.io.erasurecode.rawcoder.NativeRSRawErasureCoderFactory;
|
|
|
|
+import org.junit.After;
|
|
|
|
+import org.junit.Before;
|
|
|
|
+import org.junit.Rule;
|
|
|
|
+import org.junit.Test;
|
|
|
|
+import org.junit.rules.Timeout;
|
|
|
|
+import org.junit.Assert;
|
|
|
|
+
|
|
|
|
+import java.io.FileNotFoundException;
|
|
|
|
+import java.io.IOException;
|
|
|
|
+
|
|
|
|
+import static org.apache.hadoop.test.GenericTestUtils.assertExceptionContains;
|
|
|
|
+import static org.junit.Assert.fail;
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * Test unset and change directory's erasure coding policy.
|
|
|
|
+ */
|
|
|
|
+public class TestUnsetAndChangeDirectoryEcPolicy {
|
|
|
|
+
|
|
|
|
+ public static final Log LOG =
|
|
|
|
+ LogFactory.getLog(TestUnsetAndChangeDirectoryEcPolicy.class);
|
|
|
|
+
|
|
|
|
+ private MiniDFSCluster cluster;
|
|
|
|
+ private Configuration conf = new Configuration();
|
|
|
|
+ private DistributedFileSystem fs;
|
|
|
|
+ private ErasureCodingPolicy ecPolicy = ErasureCodingPolicyManager
|
|
|
|
+ .getSystemDefaultPolicy();
|
|
|
|
+ private final short dataBlocks = (short) ecPolicy.getNumDataUnits();
|
|
|
|
+ private final short parityBlocks = (short) ecPolicy.getNumParityUnits();
|
|
|
|
+ private final int cellSize = ecPolicy.getCellSize();
|
|
|
|
+ private final int stripsPerBlock = 2;
|
|
|
|
+ private final int blockSize = stripsPerBlock * cellSize;
|
|
|
|
+ private final int blockGroupSize = dataBlocks * blockSize;
|
|
|
|
+
|
|
|
|
+ @Rule
|
|
|
|
+ public Timeout globalTimeout = new Timeout(300000);
|
|
|
|
+
|
|
|
|
+ @Before
|
|
|
|
+ public void setup() throws IOException {
|
|
|
|
+ conf.setLong(DFSConfigKeys.DFS_BLOCK_SIZE_KEY, blockSize);
|
|
|
|
+ conf.setInt(DFSConfigKeys.DFS_NAMENODE_REPLICATION_MAX_STREAMS_KEY, 0);
|
|
|
|
+ if (ErasureCodeNative.isNativeCodeLoaded()) {
|
|
|
|
+ conf.set(
|
|
|
|
+ CodecUtil.IO_ERASURECODE_CODEC_RS_DEFAULT_RAWCODER_KEY,
|
|
|
|
+ NativeRSRawErasureCoderFactory.class.getCanonicalName());
|
|
|
|
+ }
|
|
|
|
+ cluster = new MiniDFSCluster.Builder(conf).numDataNodes(
|
|
|
|
+ dataBlocks + parityBlocks).build();
|
|
|
|
+ cluster.waitActive();
|
|
|
|
+ fs = cluster.getFileSystem();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @After
|
|
|
|
+ public void tearDown() {
|
|
|
|
+ if (cluster != null) {
|
|
|
|
+ cluster.shutdown();
|
|
|
|
+ cluster = null;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Test unset EC policy on directory.
|
|
|
|
+ */
|
|
|
|
+ @Test
|
|
|
|
+ public void testUnsetEcPolicy() throws Exception {
|
|
|
|
+ final int numBlocks = 1;
|
|
|
|
+ final int fileLen = blockGroupSize * numBlocks;
|
|
|
|
+ final Path dirPath = new Path("/striped");
|
|
|
|
+ final Path ecFilePath = new Path(dirPath, "ec_file");
|
|
|
|
+ final Path replicateFilePath = new Path(dirPath, "3x_file");
|
|
|
|
+
|
|
|
|
+ fs.mkdirs(dirPath);
|
|
|
|
+ // Test unset a directory which has no EC policy
|
|
|
|
+ fs.unsetErasureCodingPolicy(dirPath);
|
|
|
|
+ // Set EC policy on directory
|
|
|
|
+ fs.setErasureCodingPolicy(dirPath, ecPolicy);
|
|
|
|
+
|
|
|
|
+ DFSTestUtil.createFile(fs, ecFilePath, fileLen, (short) 1, 0L);
|
|
|
|
+ fs.unsetErasureCodingPolicy(dirPath);
|
|
|
|
+ DFSTestUtil.createFile(fs, replicateFilePath, fileLen, (short) 1, 0L);
|
|
|
|
+
|
|
|
|
+ // ec_file should has EC policy
|
|
|
|
+ ErasureCodingPolicy tempEcPolicy =
|
|
|
|
+ fs.getErasureCodingPolicy(ecFilePath);
|
|
|
|
+ Assert.assertTrue("Erasure coding policy mismatch!",
|
|
|
|
+ tempEcPolicy.getName().equals(ecPolicy.getName()));
|
|
|
|
+
|
|
|
|
+ // rep_file should not have EC policy
|
|
|
|
+ tempEcPolicy = fs.getErasureCodingPolicy(replicateFilePath);
|
|
|
|
+ Assert.assertNull("Replicate file should not have erasure coding policy!",
|
|
|
|
+ tempEcPolicy);
|
|
|
|
+
|
|
|
|
+ // Directory should not return erasure coding policy
|
|
|
|
+ tempEcPolicy = fs.getErasureCodingPolicy(dirPath);
|
|
|
|
+ Assert.assertNull("Directory should no have erasure coding policy set!",
|
|
|
|
+ tempEcPolicy);
|
|
|
|
+
|
|
|
|
+ fs.delete(dirPath, true);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Test nested directory with different EC policy.
|
|
|
|
+ */
|
|
|
|
+ @Test
|
|
|
|
+ public void testNestedEcPolicy() throws Exception {
|
|
|
|
+ final int numBlocks = 1;
|
|
|
|
+ final int fileLen = blockGroupSize * numBlocks;
|
|
|
|
+ final Path parentDir = new Path("/ec-6-3");
|
|
|
|
+ final Path childDir = new Path("/ec-6-3/ec-3-2");
|
|
|
|
+ final Path ec63FilePath = new Path(childDir, "ec_6_3_file");
|
|
|
|
+ final Path ec32FilePath = new Path(childDir, "ec_3_2_file");
|
|
|
|
+ final Path ec63FilePath2 = new Path(childDir, "ec_6_3_file_2");
|
|
|
|
+ final ErasureCodingPolicy ec32Policy = ErasureCodingPolicyManager
|
|
|
|
+ .getPolicyByPolicyID(HdfsConstants.RS_3_2_POLICY_ID);
|
|
|
|
+
|
|
|
|
+ fs.mkdirs(parentDir);
|
|
|
|
+ fs.setErasureCodingPolicy(parentDir, ecPolicy);
|
|
|
|
+ fs.mkdirs(childDir);
|
|
|
|
+ // Create RS(6,3) EC policy file
|
|
|
|
+ DFSTestUtil.createFile(fs, ec63FilePath, fileLen, (short) 1, 0L);
|
|
|
|
+ // Set RS(3,2) EC policy on child directory
|
|
|
|
+ fs.setErasureCodingPolicy(childDir, ec32Policy);
|
|
|
|
+ // Create RS(3,2) EC policy file
|
|
|
|
+ DFSTestUtil.createFile(fs, ec32FilePath, fileLen, (short) 1, 0L);
|
|
|
|
+
|
|
|
|
+ // Start to check
|
|
|
|
+ // ec_6_3_file should has RS-6-3 EC policy
|
|
|
|
+ ErasureCodingPolicy tempEcPolicy =
|
|
|
|
+ fs.getErasureCodingPolicy(ec63FilePath);
|
|
|
|
+ Assert.assertTrue("Erasure coding policy mismatch!",
|
|
|
|
+ tempEcPolicy.getName().equals(ecPolicy.getName()));
|
|
|
|
+
|
|
|
|
+ // ec_3_2_file should have RS-3-2 policy
|
|
|
|
+ tempEcPolicy = fs.getErasureCodingPolicy(ec32FilePath);
|
|
|
|
+ Assert.assertTrue("Erasure coding policy mismatch!",
|
|
|
|
+ tempEcPolicy.getName().equals(ec32Policy.getName()));
|
|
|
|
+
|
|
|
|
+ // Child directory should have RS-3-2 policy
|
|
|
|
+ tempEcPolicy = fs.getErasureCodingPolicy(childDir);
|
|
|
|
+ Assert.assertTrue(
|
|
|
|
+ "Directory should have erasure coding policy set!",
|
|
|
|
+ tempEcPolicy.getName().equals(ec32Policy.getName()));
|
|
|
|
+
|
|
|
|
+ // Unset EC policy on child directory
|
|
|
|
+ fs.unsetErasureCodingPolicy(childDir);
|
|
|
|
+ DFSTestUtil.createFile(fs, ec63FilePath2, fileLen, (short) 1, 0L);
|
|
|
|
+
|
|
|
|
+ // ec_6_3_file_2 should have RS-6-3 policy
|
|
|
|
+ tempEcPolicy = fs.getErasureCodingPolicy(ec63FilePath2);
|
|
|
|
+ Assert.assertTrue("Erasure coding policy mismatch!",
|
|
|
|
+ tempEcPolicy.getName().equals(ecPolicy.getName()));
|
|
|
|
+
|
|
|
|
+ // Child directory should have RS-6-3 policy now
|
|
|
|
+ tempEcPolicy = fs.getErasureCodingPolicy(childDir);
|
|
|
|
+ Assert.assertTrue(
|
|
|
|
+ "Directory should have erasure coding policy set!",
|
|
|
|
+ tempEcPolicy.getName().equals(ecPolicy.getName()));
|
|
|
|
+
|
|
|
|
+ fs.delete(parentDir, true);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Test unset EC policy on root directory.
|
|
|
|
+ */
|
|
|
|
+ @Test
|
|
|
|
+ public void testUnsetRootDirEcPolicy() throws Exception {
|
|
|
|
+ final int numBlocks = 1;
|
|
|
|
+ final int fileLen = blockGroupSize * numBlocks;
|
|
|
|
+ final Path rootPath = new Path("/");
|
|
|
|
+ final Path ecFilePath = new Path(rootPath, "ec_file");
|
|
|
|
+ final Path replicateFilePath = new Path(rootPath, "rep_file");
|
|
|
|
+
|
|
|
|
+ // Test unset root path which has no EC policy
|
|
|
|
+ fs.unsetErasureCodingPolicy(rootPath);
|
|
|
|
+ // Set EC policy on root path
|
|
|
|
+ fs.setErasureCodingPolicy(rootPath, ecPolicy);
|
|
|
|
+ DFSTestUtil.createFile(fs, ecFilePath, fileLen, (short) 1, 0L);
|
|
|
|
+ fs.unsetErasureCodingPolicy(rootPath);
|
|
|
|
+ DFSTestUtil.createFile(fs, replicateFilePath, fileLen, (short) 1, 0L);
|
|
|
|
+
|
|
|
|
+ // ec_file should has EC policy set
|
|
|
|
+ ErasureCodingPolicy tempEcPolicy =
|
|
|
|
+ fs.getErasureCodingPolicy(ecFilePath);
|
|
|
|
+ Assert.assertTrue("Erasure coding policy mismatch!",
|
|
|
|
+ tempEcPolicy.getName().equals(ecPolicy.getName()));
|
|
|
|
+
|
|
|
|
+ // rep_file should not have EC policy set
|
|
|
|
+ tempEcPolicy = fs.getErasureCodingPolicy(replicateFilePath);
|
|
|
|
+ Assert.assertNull("Replicate file should not have erasure coding policy!",
|
|
|
|
+ tempEcPolicy);
|
|
|
|
+
|
|
|
|
+ // Directory should not return erasure coding policy
|
|
|
|
+ tempEcPolicy = fs.getErasureCodingPolicy(rootPath);
|
|
|
|
+ Assert.assertNull("Directory should not have erasure coding policy set!",
|
|
|
|
+ tempEcPolicy);
|
|
|
|
+
|
|
|
|
+ fs.delete(rootPath, true);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Test change EC policy on root directory.
|
|
|
|
+ */
|
|
|
|
+ @Test
|
|
|
|
+ public void testChangeRootDirEcPolicy() throws Exception {
|
|
|
|
+ final int numBlocks = 1;
|
|
|
|
+ final int fileLen = blockGroupSize * numBlocks;
|
|
|
|
+ final Path rootPath = new Path("/");
|
|
|
|
+ final Path ec63FilePath = new Path(rootPath, "ec_6_3_file");
|
|
|
|
+ final Path ec32FilePath = new Path(rootPath, "ec_3_2_file");
|
|
|
|
+ final ErasureCodingPolicy ec32Policy = ErasureCodingPolicyManager
|
|
|
|
+ .getPolicyByPolicyID(HdfsConstants.RS_3_2_POLICY_ID);
|
|
|
|
+
|
|
|
|
+ fs.unsetErasureCodingPolicy(rootPath);
|
|
|
|
+ fs.setErasureCodingPolicy(rootPath, ecPolicy);
|
|
|
|
+ // Create RS(6,3) EC policy file
|
|
|
|
+ DFSTestUtil.createFile(fs, ec63FilePath, fileLen, (short) 1, 0L);
|
|
|
|
+ // Change EC policy from RS(6,3) to RS(3,2)
|
|
|
|
+ fs.setErasureCodingPolicy(rootPath, ec32Policy);
|
|
|
|
+ DFSTestUtil.createFile(fs, ec32FilePath, fileLen, (short) 1, 0L);
|
|
|
|
+
|
|
|
|
+ // start to check
|
|
|
|
+ // ec_6_3_file should has RS-6-3 ec policy set
|
|
|
|
+ ErasureCodingPolicy tempEcPolicy =
|
|
|
|
+ fs.getErasureCodingPolicy(ec63FilePath);
|
|
|
|
+ Assert.assertTrue("Erasure coding policy mismatch!",
|
|
|
|
+ tempEcPolicy.getName().equals(ecPolicy.getName()));
|
|
|
|
+
|
|
|
|
+ // ec_3_2_file should have RS-3-2 policy
|
|
|
|
+ tempEcPolicy = fs.getErasureCodingPolicy(ec32FilePath);
|
|
|
|
+ Assert.assertTrue("Erasure coding policy mismatch!",
|
|
|
|
+ tempEcPolicy.getName().equals(ec32Policy.getName()));
|
|
|
|
+
|
|
|
|
+ // Root directory should have RS-3-2 policy
|
|
|
|
+ tempEcPolicy = fs.getErasureCodingPolicy(rootPath);
|
|
|
|
+ Assert.assertTrue(
|
|
|
|
+ "Directory should have erasure coding policy!",
|
|
|
|
+ tempEcPolicy.getName().equals(ec32Policy.getName()));
|
|
|
|
+
|
|
|
|
+ fs.delete(rootPath, true);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Test different replica factor files.
|
|
|
|
+ */
|
|
|
|
+ @Test
|
|
|
|
+ public void testDifferentReplicaFactor() throws Exception {
|
|
|
|
+ final int numBlocks = 1;
|
|
|
|
+ final int fileLen = blockGroupSize * numBlocks;
|
|
|
|
+ final Path ecDirPath = new Path("/striped");
|
|
|
|
+ final Path ecFilePath = new Path(ecDirPath, "ec_file");
|
|
|
|
+ final Path replicateFilePath = new Path(ecDirPath, "rep_file");
|
|
|
|
+ final Path replicateFilePath2 = new Path(ecDirPath, "rep_file2");
|
|
|
|
+
|
|
|
|
+ fs.mkdirs(ecDirPath);
|
|
|
|
+ fs.setErasureCodingPolicy(ecDirPath, ecPolicy);
|
|
|
|
+ DFSTestUtil.createFile(fs, ecFilePath, fileLen, (short) 1, 0L);
|
|
|
|
+ fs.unsetErasureCodingPolicy(ecDirPath);
|
|
|
|
+ DFSTestUtil.createFile(fs, replicateFilePath, fileLen, (short) 3, 0L);
|
|
|
|
+ DFSTestUtil.createFile(fs, replicateFilePath2, fileLen, (short) 2, 0L);
|
|
|
|
+
|
|
|
|
+ // ec_file should has EC policy set
|
|
|
|
+ ErasureCodingPolicy tempEcPolicy =
|
|
|
|
+ fs.getErasureCodingPolicy(ecFilePath);
|
|
|
|
+ Assert.assertTrue("Erasure coding policy mismatch!",
|
|
|
|
+ tempEcPolicy.getName().equals(ecPolicy.getName()));
|
|
|
|
+
|
|
|
|
+ // rep_file should not have EC policy set
|
|
|
|
+ tempEcPolicy = fs.getErasureCodingPolicy(replicateFilePath);
|
|
|
|
+ Assert.assertNull("Replicate file should not have erasure coding policy!",
|
|
|
|
+ tempEcPolicy);
|
|
|
|
+ tempEcPolicy = fs.getErasureCodingPolicy(replicateFilePath2);
|
|
|
|
+ Assert.assertNull("Replicate file should not have erasure coding policy!",
|
|
|
|
+ tempEcPolicy);
|
|
|
|
+
|
|
|
|
+ // Directory should not return erasure coding policy
|
|
|
|
+ tempEcPolicy = fs.getErasureCodingPolicy(ecDirPath);
|
|
|
|
+ Assert.assertNull("Directory should not have erasure coding policy set!",
|
|
|
|
+ tempEcPolicy);
|
|
|
|
+
|
|
|
|
+ fs.delete(ecDirPath, true);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Test set and unset EC policy on directory doesn't exist.
|
|
|
|
+ */
|
|
|
|
+ @Test
|
|
|
|
+ public void testNonExistentDir() throws Exception {
|
|
|
|
+ final Path dirPath = new Path("/striped");
|
|
|
|
+
|
|
|
|
+ // Unset EC policy on non-existent directory
|
|
|
|
+ try {
|
|
|
|
+ fs.unsetErasureCodingPolicy(dirPath);
|
|
|
|
+ fail("FileNotFoundException should be thrown for a non-existent"
|
|
|
|
+ + " file path");
|
|
|
|
+ } catch (FileNotFoundException e) {
|
|
|
|
+ assertExceptionContains("Path not found: " + dirPath, e);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Set EC policy on non-existent directory
|
|
|
|
+ try {
|
|
|
|
+ fs.setErasureCodingPolicy(dirPath, ecPolicy);
|
|
|
|
+ fail("FileNotFoundException should be thrown for a non-existent"
|
|
|
|
+ + " file path");
|
|
|
|
+ } catch (FileNotFoundException e) {
|
|
|
|
+ assertExceptionContains("Path not found: " + dirPath, e);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Test set and unset EC policy on file.
|
|
|
|
+ */
|
|
|
|
+ @Test
|
|
|
|
+ public void testEcPolicyOnFile() throws Exception {
|
|
|
|
+ final Path ecFilePath = new Path("/striped_file");
|
|
|
|
+ final int fileLen = blockGroupSize * 2;
|
|
|
|
+ DFSTestUtil.createFile(fs, ecFilePath, fileLen, (short) 1, 0L);
|
|
|
|
+
|
|
|
|
+ // Set EC policy on file
|
|
|
|
+ try {
|
|
|
|
+ fs.setErasureCodingPolicy(ecFilePath, ecPolicy);
|
|
|
|
+ fail("IOException should be thrown for setting EC policy on file");
|
|
|
|
+ } catch (IOException e) {
|
|
|
|
+ assertExceptionContains("Attempt to set an erasure coding policy " +
|
|
|
|
+ "for a file " + ecFilePath, e);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Unset EC policy on file
|
|
|
|
+ try {
|
|
|
|
+ fs.unsetErasureCodingPolicy(ecFilePath);
|
|
|
|
+ fail("IOException should be thrown for unsetting EC policy on file");
|
|
|
|
+ } catch (IOException e) {
|
|
|
|
+ assertExceptionContains("Cannot unset an erasure coding policy on a file "
|
|
|
|
+ + ecFilePath, e);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|