From e69954d22cc97eb3818c8ee7c3f623a5d0497b54 Mon Sep 17 00:00:00 2001 From: Jing Zhao Date: Thu, 21 Aug 2014 23:42:33 +0000 Subject: [PATCH] HDFS-6906. Archival Storage: Add more tests for BlockStoragePolicy. Contributed by Tsz Wo Nicholas Sze. git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/HDFS-6584@1619628 13f79535-47bb-0310-9956-ffa450edef68 --- .../hadoop/hdfs/BlockStoragePolicy.java | 56 +- .../BlockPlacementPolicyDefault.java | 35 +- .../hadoop/hdfs/TestBlockStoragePolicy.java | 580 +++++++++++++++++- 3 files changed, 635 insertions(+), 36 deletions(-) diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/BlockStoragePolicy.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/BlockStoragePolicy.java index a0935258870..6e90cf19d0c 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/BlockStoragePolicy.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/BlockStoragePolicy.java @@ -134,11 +134,65 @@ public class BlockStoragePolicy { */ public List chooseStorageTypes(final short replication, final Iterable chosen) { + return chooseStorageTypes(replication, chosen, null); + } + + private List chooseStorageTypes(final short replication, + final Iterable chosen, final List excess) { final List types = chooseStorageTypes(replication); - diff(types, chosen, null); + diff(types, chosen, excess); return types; } + /** + * Choose the storage types for storing the remaining replicas, given the + * replication number, the storage types of the chosen replicas and + * the unavailable storage types. It uses fallback storage in case that + * the desired storage type is unavailable. + * + * @param replication the replication number. + * @param chosen the storage types of the chosen replicas. + * @param unavailables the unavailable storage types. + * @param isNewBlock Is it for new block creation? + * @return a list of {@link StorageType}s for storing the replicas of a block. + */ + public List chooseStorageTypes(final short replication, + final Iterable chosen, + final EnumSet unavailables, + final boolean isNewBlock) { + final List excess = new LinkedList(); + final List storageTypes = chooseStorageTypes( + replication, chosen, excess); + final int expectedSize = storageTypes.size() - excess.size(); + final List removed = new LinkedList(); + for(int i = storageTypes.size() - 1; i >= 0; i--) { + // replace/remove unavailable storage types. + final StorageType t = storageTypes.get(i); + if (unavailables.contains(t)) { + final StorageType fallback = isNewBlock? + getCreationFallback(unavailables) + : getReplicationFallback(unavailables); + if (fallback == null) { + removed.add(storageTypes.remove(i)); + } else { + storageTypes.set(i, fallback); + } + } + } + // remove excess storage types after fallback replacement. + diff(storageTypes, excess, null); + if (storageTypes.size() < expectedSize) { + LOG.warn("Failed to place enough replicas: expected size is " + expectedSize + + " but only " + storageTypes.size() + " storage types can be selected " + + "(replication=" + replication + + ", selected=" + storageTypes + + ", unavailable=" + unavailables + + ", removed=" + removed + + ", policy=" + this + ")"); + } + return storageTypes; + } + /** * Compute the list difference t = t - c. * Further, if e is not null, set e = e + c - t; diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/blockmanagement/BlockPlacementPolicyDefault.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/blockmanagement/BlockPlacementPolicyDefault.java index b049a462bfe..392e3509c05 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/blockmanagement/BlockPlacementPolicyDefault.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/blockmanagement/BlockPlacementPolicyDefault.java @@ -241,39 +241,6 @@ public class BlockPlacementPolicyDefault extends BlockPlacementPolicy { return new int[] {numOfReplicas, maxNodesPerRack}; } - private static List selectStorageTypes( - final BlockStoragePolicy storagePolicy, - final short replication, - final Iterable chosen, - final EnumSet unavailableStorages, - final boolean isNewBlock) { - final List storageTypes = storagePolicy.chooseStorageTypes( - replication, chosen); - final List removed = new ArrayList(); - for(int i = storageTypes.size() - 1; i >= 0; i--) { - // replace/remove unavailable storage types. - final StorageType t = storageTypes.get(i); - if (unavailableStorages.contains(t)) { - final StorageType fallback = isNewBlock? - storagePolicy.getCreationFallback(unavailableStorages) - : storagePolicy.getReplicationFallback(unavailableStorages); - if (fallback == null) { - removed.add(storageTypes.remove(i)); - } else { - storageTypes.set(i, fallback); - } - } - } - if (storageTypes.size() < replication) { - LOG.warn("Failed to place enough replicas: replication is " + replication - + " but only " + storageTypes.size() + " storage types can be selected " - + "(selected=" + storageTypes - + ", unavailable=" + unavailableStorages - + ", removed=" + removed - + ", policy=" + storagePolicy + ")"); - } - return storageTypes; - } /** * choose numOfReplicas from all data nodes * @param numOfReplicas additional number of replicas wanted @@ -309,7 +276,7 @@ public class BlockPlacementPolicyDefault extends BlockPlacementPolicy { new HashSet(excludedNodes) : null; // choose storage types; use fallbacks for unavailable storages - final List storageTypes = selectStorageTypes(storagePolicy, + final List storageTypes = storagePolicy.chooseStorageTypes( (short)totalReplicasExpected, DatanodeStorageInfo.toStorageTypes(results), unavailableStorages, newBlock); diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/TestBlockStoragePolicy.java b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/TestBlockStoragePolicy.java index e6c25a955e4..f2c9fb1a370 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/TestBlockStoragePolicy.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/TestBlockStoragePolicy.java @@ -20,6 +20,8 @@ package org.apache.hadoop.hdfs; import static org.apache.hadoop.hdfs.BlockStoragePolicy.ID_UNSPECIFIED; import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.Arrays; import java.util.EnumSet; import java.util.HashMap; import java.util.List; @@ -60,8 +62,22 @@ public class TestBlockStoragePolicy { static final byte WARM = (byte) 8; static final byte HOT = (byte) 12; + static final List> chosens = new ArrayList>(); + static { + chosens.add(Arrays.asList()); + chosens.add(Arrays.asList(StorageType.DISK)); + chosens.add(Arrays.asList(StorageType.ARCHIVE)); + chosens.add(Arrays.asList(StorageType.DISK, StorageType.DISK)); + chosens.add(Arrays.asList(StorageType.DISK, StorageType.ARCHIVE)); + chosens.add(Arrays.asList(StorageType.ARCHIVE, StorageType.ARCHIVE)); + chosens.add(Arrays.asList(StorageType.DISK, StorageType.DISK, StorageType.DISK)); + chosens.add(Arrays.asList(StorageType.DISK, StorageType.DISK, StorageType.ARCHIVE)); + chosens.add(Arrays.asList(StorageType.DISK, StorageType.ARCHIVE, StorageType.ARCHIVE)); + chosens.add(Arrays.asList(StorageType.ARCHIVE, StorageType.ARCHIVE, StorageType.ARCHIVE)); + } + @Test - public void testDefaultPolicies() throws Exception { + public void testDefaultPolicies() { final Map expectedPolicyStrings = new HashMap(); expectedPolicyStrings.put(COLD, "BlockStoragePolicy{COLD:4, storageTypes=[ARCHIVE], creationFallbacks=[], replicationFallbacks=[]"); @@ -136,6 +152,568 @@ public class TestBlockStoragePolicy { Assert.assertEquals(null, policy.getReplicationFallback(both)); } + private static interface CheckChooseStorageTypes { + public void checkChooseStorageTypes(BlockStoragePolicy p, short replication, + List chosen, StorageType... expected); + + /** Basic case: pass only replication and chosen */ + static final CheckChooseStorageTypes Basic = new CheckChooseStorageTypes() { + @Override + public void checkChooseStorageTypes(BlockStoragePolicy p, short replication, + List chosen, StorageType... expected) { + final List types = p.chooseStorageTypes(replication, chosen); + assertStorageTypes(types, expected); + } + }; + + /** With empty unavailables and isNewBlock=true */ + static final CheckChooseStorageTypes EmptyUnavailablesAndNewBlock + = new CheckChooseStorageTypes() { + @Override + public void checkChooseStorageTypes(BlockStoragePolicy p, + short replication, List chosen, StorageType... expected) { + final List types = p.chooseStorageTypes(replication, + chosen, none, true); + assertStorageTypes(types, expected); + } + }; + + /** With empty unavailables and isNewBlock=false */ + static final CheckChooseStorageTypes EmptyUnavailablesAndNonNewBlock + = new CheckChooseStorageTypes() { + @Override + public void checkChooseStorageTypes(BlockStoragePolicy p, + short replication, List chosen, StorageType... expected) { + final List types = p.chooseStorageTypes(replication, + chosen, none, false); + assertStorageTypes(types, expected); + } + }; + + /** With both DISK and ARCHIVE unavailables and isNewBlock=true */ + static final CheckChooseStorageTypes BothUnavailableAndNewBlock + = new CheckChooseStorageTypes() { + @Override + public void checkChooseStorageTypes(BlockStoragePolicy p, + short replication, List chosen, StorageType... expected) { + final List types = p.chooseStorageTypes(replication, + chosen, both, true); + assertStorageTypes(types, expected); + } + }; + + /** With both DISK and ARCHIVE unavailable and isNewBlock=false */ + static final CheckChooseStorageTypes BothUnavailableAndNonNewBlock + = new CheckChooseStorageTypes() { + @Override + public void checkChooseStorageTypes(BlockStoragePolicy p, + short replication, List chosen, StorageType... expected) { + final List types = p.chooseStorageTypes(replication, + chosen, both, false); + assertStorageTypes(types, expected); + } + }; + + /** With ARCHIVE unavailable and isNewBlock=true */ + static final CheckChooseStorageTypes ArchivalUnavailableAndNewBlock + = new CheckChooseStorageTypes() { + @Override + public void checkChooseStorageTypes(BlockStoragePolicy p, + short replication, List chosen, StorageType... expected) { + final List types = p.chooseStorageTypes(replication, + chosen, archive, true); + assertStorageTypes(types, expected); + } + }; + + /** With ARCHIVE unavailable and isNewBlock=true */ + static final CheckChooseStorageTypes ArchivalUnavailableAndNonNewBlock + = new CheckChooseStorageTypes() { + @Override + public void checkChooseStorageTypes(BlockStoragePolicy p, + short replication, List chosen, StorageType... expected) { + final List types = p.chooseStorageTypes(replication, + chosen, archive, false); + assertStorageTypes(types, expected); + } + }; + } + + @Test + public void testChooseStorageTypes() { + run(CheckChooseStorageTypes.Basic); + run(CheckChooseStorageTypes.EmptyUnavailablesAndNewBlock); + run(CheckChooseStorageTypes.EmptyUnavailablesAndNonNewBlock); + } + + private static void run(CheckChooseStorageTypes method) { + final BlockStoragePolicy hot = POLICY_SUITE.getPolicy(HOT); + final BlockStoragePolicy warm = POLICY_SUITE.getPolicy(WARM); + final BlockStoragePolicy cold = POLICY_SUITE.getPolicy(COLD); + + final short replication = 3; + { + final List chosen = Arrays.asList(); + method.checkChooseStorageTypes(hot, replication, chosen, + StorageType.DISK, StorageType.DISK, StorageType.DISK); + method.checkChooseStorageTypes(warm, replication, chosen, + StorageType.DISK, StorageType.ARCHIVE, StorageType.ARCHIVE); + method.checkChooseStorageTypes(cold, replication, chosen, + StorageType.ARCHIVE, StorageType.ARCHIVE, StorageType.ARCHIVE); + } + + { + final List chosen = Arrays.asList(StorageType.DISK); + method.checkChooseStorageTypes(hot, replication, chosen, + StorageType.DISK, StorageType.DISK); + method.checkChooseStorageTypes(warm, replication, chosen, + StorageType.ARCHIVE, StorageType.ARCHIVE); + method.checkChooseStorageTypes(cold, replication, chosen, + StorageType.ARCHIVE, StorageType.ARCHIVE, StorageType.ARCHIVE); + } + + { + final List chosen = Arrays.asList(StorageType.ARCHIVE); + method.checkChooseStorageTypes(hot, replication, chosen, + StorageType.DISK, StorageType.DISK, StorageType.DISK); + method.checkChooseStorageTypes(warm, replication, chosen, + StorageType.DISK, StorageType.ARCHIVE); + method.checkChooseStorageTypes(cold, replication, chosen, + StorageType.ARCHIVE, StorageType.ARCHIVE); + } + + { + final List chosen = Arrays.asList( + StorageType.DISK, StorageType.DISK); + method.checkChooseStorageTypes(hot, replication, chosen, + StorageType.DISK); + method.checkChooseStorageTypes(warm, replication, chosen, + StorageType.ARCHIVE, StorageType.ARCHIVE); + method.checkChooseStorageTypes(cold, replication, chosen, + StorageType.ARCHIVE, StorageType.ARCHIVE, StorageType.ARCHIVE); + } + + { + final List chosen = Arrays.asList( + StorageType.DISK, StorageType.ARCHIVE); + method.checkChooseStorageTypes(hot, replication, chosen, + StorageType.DISK, StorageType.DISK); + method.checkChooseStorageTypes(warm, replication, chosen, + StorageType.ARCHIVE); + method.checkChooseStorageTypes(cold, replication, chosen, + StorageType.ARCHIVE, StorageType.ARCHIVE); + } + + { + final List chosen = Arrays.asList( + StorageType.ARCHIVE, StorageType.ARCHIVE); + method.checkChooseStorageTypes(hot, replication, chosen, + StorageType.DISK, StorageType.DISK, StorageType.DISK); + method.checkChooseStorageTypes(warm, replication, chosen, + StorageType.DISK); + method.checkChooseStorageTypes(cold, replication, chosen, + StorageType.ARCHIVE); + } + + { + final List chosen = Arrays.asList( + StorageType.DISK, StorageType.DISK, StorageType.DISK); + method.checkChooseStorageTypes(hot, replication, chosen); + method.checkChooseStorageTypes(warm, replication, chosen, + StorageType.ARCHIVE, StorageType.ARCHIVE); + method.checkChooseStorageTypes(cold, replication, chosen, + StorageType.ARCHIVE, StorageType.ARCHIVE, StorageType.ARCHIVE); + } + + { + final List chosen = Arrays.asList( + StorageType.DISK, StorageType.DISK, StorageType.ARCHIVE); + method.checkChooseStorageTypes(hot, replication, chosen, + StorageType.DISK); + method.checkChooseStorageTypes(warm, replication, chosen, + StorageType.ARCHIVE); + method.checkChooseStorageTypes(cold, replication, chosen, + StorageType.ARCHIVE, StorageType.ARCHIVE); + } + + { + final List chosen = Arrays.asList( + StorageType.DISK, StorageType.ARCHIVE, StorageType.ARCHIVE); + method.checkChooseStorageTypes(hot, replication, chosen, + StorageType.DISK, StorageType.DISK); + method.checkChooseStorageTypes(warm, replication, chosen); + method.checkChooseStorageTypes(cold, replication, chosen, + StorageType.ARCHIVE); + } + + { + final List chosen = Arrays.asList( + StorageType.ARCHIVE, StorageType.ARCHIVE, StorageType.ARCHIVE); + method.checkChooseStorageTypes(hot, replication, chosen, + StorageType.DISK, StorageType.DISK, StorageType.DISK); + method.checkChooseStorageTypes(warm, replication, chosen, + StorageType.DISK); + method.checkChooseStorageTypes(cold, replication, chosen); + } + } + + @Test + public void testChooseStorageTypesWithBothUnavailable() { + runWithBothUnavailable(CheckChooseStorageTypes.BothUnavailableAndNewBlock); + runWithBothUnavailable(CheckChooseStorageTypes.BothUnavailableAndNonNewBlock); + } + + private static void runWithBothUnavailable(CheckChooseStorageTypes method) { + final BlockStoragePolicy hot = POLICY_SUITE.getPolicy(HOT); + final BlockStoragePolicy warm = POLICY_SUITE.getPolicy(WARM); + final BlockStoragePolicy cold = POLICY_SUITE.getPolicy(COLD); + + final short replication = 3; + for(List c : chosens) { + method.checkChooseStorageTypes(hot, replication, c); + method.checkChooseStorageTypes(warm, replication, c); + method.checkChooseStorageTypes(cold, replication, c); + } + } + + @Test + public void testChooseStorageTypesWithDiskUnavailableAndNewBlock() { + final BlockStoragePolicy hot = POLICY_SUITE.getPolicy(HOT); + final BlockStoragePolicy warm = POLICY_SUITE.getPolicy(WARM); + final BlockStoragePolicy cold = POLICY_SUITE.getPolicy(COLD); + + final short replication = 3; + final EnumSet unavailables = disk; + final boolean isNewBlock = true; + { + final List chosen = Arrays.asList(); + checkChooseStorageTypes(hot, replication, chosen, unavailables, isNewBlock); + checkChooseStorageTypes(warm, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE, StorageType.ARCHIVE, StorageType.ARCHIVE); + checkChooseStorageTypes(cold, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE, StorageType.ARCHIVE, StorageType.ARCHIVE); + } + + { + final List chosen = Arrays.asList(StorageType.DISK); + checkChooseStorageTypes(hot, replication, chosen, unavailables, isNewBlock); + checkChooseStorageTypes(warm, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE, StorageType.ARCHIVE); + checkChooseStorageTypes(cold, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE, StorageType.ARCHIVE, StorageType.ARCHIVE); + } + + { + final List chosen = Arrays.asList(StorageType.ARCHIVE); + checkChooseStorageTypes(hot, replication, chosen, unavailables, isNewBlock); + checkChooseStorageTypes(warm, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE, StorageType.ARCHIVE); + checkChooseStorageTypes(cold, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE, StorageType.ARCHIVE); + } + + { + final List chosen = Arrays.asList( + StorageType.DISK, StorageType.DISK); + checkChooseStorageTypes(hot, replication, chosen, unavailables, isNewBlock); + checkChooseStorageTypes(warm, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE, StorageType.ARCHIVE); + checkChooseStorageTypes(cold, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE, StorageType.ARCHIVE, StorageType.ARCHIVE); + } + + { + final List chosen = Arrays.asList( + StorageType.DISK, StorageType.ARCHIVE); + checkChooseStorageTypes(hot, replication, chosen, unavailables, isNewBlock); + checkChooseStorageTypes(warm, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE); + checkChooseStorageTypes(cold, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE, StorageType.ARCHIVE); + } + + { + final List chosen = Arrays.asList( + StorageType.ARCHIVE, StorageType.ARCHIVE); + checkChooseStorageTypes(hot, replication, chosen, unavailables, isNewBlock); + checkChooseStorageTypes(warm, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE); + checkChooseStorageTypes(cold, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE); + } + + { + final List chosen = Arrays.asList( + StorageType.DISK, StorageType.DISK, StorageType.DISK); + checkChooseStorageTypes(hot, replication, chosen, unavailables, isNewBlock); + checkChooseStorageTypes(warm, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE, StorageType.ARCHIVE); + checkChooseStorageTypes(cold, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE, StorageType.ARCHIVE, StorageType.ARCHIVE); + } + + { + final List chosen = Arrays.asList( + StorageType.DISK, StorageType.DISK, StorageType.ARCHIVE); + checkChooseStorageTypes(hot, replication, chosen, unavailables, isNewBlock); + checkChooseStorageTypes(warm, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE); + checkChooseStorageTypes(cold, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE, StorageType.ARCHIVE); + } + + { + final List chosen = Arrays.asList( + StorageType.DISK, StorageType.ARCHIVE, StorageType.ARCHIVE); + checkChooseStorageTypes(hot, replication, chosen, unavailables, isNewBlock); + checkChooseStorageTypes(warm, replication, chosen, unavailables, isNewBlock); + checkChooseStorageTypes(cold, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE); + } + + { + final List chosen = Arrays.asList( + StorageType.ARCHIVE, StorageType.ARCHIVE, StorageType.ARCHIVE); + checkChooseStorageTypes(hot, replication, chosen, unavailables, isNewBlock); + checkChooseStorageTypes(warm, replication, chosen, unavailables, isNewBlock); + checkChooseStorageTypes(cold, replication, chosen, unavailables, isNewBlock); + } + } + + @Test + public void testChooseStorageTypesWithArchiveUnavailable() { + runWithArchiveUnavailable(CheckChooseStorageTypes.ArchivalUnavailableAndNewBlock); + runWithArchiveUnavailable(CheckChooseStorageTypes.ArchivalUnavailableAndNonNewBlock); + } + + private static void runWithArchiveUnavailable(CheckChooseStorageTypes method) { + final BlockStoragePolicy hot = POLICY_SUITE.getPolicy(HOT); + final BlockStoragePolicy warm = POLICY_SUITE.getPolicy(WARM); + final BlockStoragePolicy cold = POLICY_SUITE.getPolicy(COLD); + + final short replication = 3; + { + final List chosen = Arrays.asList(); + method.checkChooseStorageTypes(hot, replication, chosen, + StorageType.DISK, StorageType.DISK, StorageType.DISK); + method.checkChooseStorageTypes(warm, replication, chosen, + StorageType.DISK, StorageType.DISK, StorageType.DISK); + method.checkChooseStorageTypes(cold, replication, chosen); + } + + { + final List chosen = Arrays.asList(StorageType.DISK); + method.checkChooseStorageTypes(hot, replication, chosen, + StorageType.DISK, StorageType.DISK); + method.checkChooseStorageTypes(warm, replication, chosen, + StorageType.DISK, StorageType.DISK); + method.checkChooseStorageTypes(cold, replication, chosen); + } + + { + final List chosen = Arrays.asList(StorageType.ARCHIVE); + method.checkChooseStorageTypes(hot, replication, chosen, + StorageType.DISK, StorageType.DISK, StorageType.DISK); + method.checkChooseStorageTypes(warm, replication, chosen, + StorageType.DISK, StorageType.DISK); + method.checkChooseStorageTypes(cold, replication, chosen); + } + + { + final List chosen = Arrays.asList( + StorageType.DISK, StorageType.DISK); + method.checkChooseStorageTypes(hot, replication, chosen, + StorageType.DISK); + method.checkChooseStorageTypes(warm, replication, chosen, + StorageType.DISK); + method.checkChooseStorageTypes(cold, replication, chosen); + } + + { + final List chosen = Arrays.asList( + StorageType.DISK, StorageType.ARCHIVE); + method.checkChooseStorageTypes(hot, replication, chosen, + StorageType.DISK, StorageType.DISK); + method.checkChooseStorageTypes(warm, replication, chosen, + StorageType.DISK); + method.checkChooseStorageTypes(cold, replication, chosen); + } + + { + final List chosen = Arrays.asList( + StorageType.ARCHIVE, StorageType.ARCHIVE); + method.checkChooseStorageTypes(hot, replication, chosen, + StorageType.DISK, StorageType.DISK, StorageType.DISK); + method.checkChooseStorageTypes(warm, replication, chosen, + StorageType.DISK); + method.checkChooseStorageTypes(cold, replication, chosen); + } + + { + final List chosen = Arrays.asList( + StorageType.DISK, StorageType.DISK, StorageType.DISK); + method.checkChooseStorageTypes(hot, replication, chosen); + method.checkChooseStorageTypes(warm, replication, chosen); + method.checkChooseStorageTypes(cold, replication, chosen); + } + + { + final List chosen = Arrays.asList( + StorageType.DISK, StorageType.DISK, StorageType.ARCHIVE); + method.checkChooseStorageTypes(hot, replication, chosen, + StorageType.DISK); + method.checkChooseStorageTypes(warm, replication, chosen); + method.checkChooseStorageTypes(cold, replication, chosen); + } + + { + final List chosen = Arrays.asList( + StorageType.DISK, StorageType.ARCHIVE, StorageType.ARCHIVE); + method.checkChooseStorageTypes(hot, replication, chosen, + StorageType.DISK, StorageType.DISK); + method.checkChooseStorageTypes(warm, replication, chosen); + method.checkChooseStorageTypes(cold, replication, chosen); + } + + { + final List chosen = Arrays.asList( + StorageType.ARCHIVE, StorageType.ARCHIVE, StorageType.ARCHIVE); + method.checkChooseStorageTypes(hot, replication, chosen, + StorageType.DISK, StorageType.DISK, StorageType.DISK); + method.checkChooseStorageTypes(warm, replication, chosen, + StorageType.DISK); + method.checkChooseStorageTypes(cold, replication, chosen); + } + } + + @Test + public void testChooseStorageTypesWithDiskUnavailableAndNonNewBlock() { + final BlockStoragePolicy hot = POLICY_SUITE.getPolicy(HOT); + final BlockStoragePolicy warm = POLICY_SUITE.getPolicy(WARM); + final BlockStoragePolicy cold = POLICY_SUITE.getPolicy(COLD); + + final short replication = 3; + final EnumSet unavailables = disk; + final boolean isNewBlock = false; + { + final List chosen = Arrays.asList(); + checkChooseStorageTypes(hot, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE, StorageType.ARCHIVE, StorageType.ARCHIVE); + checkChooseStorageTypes(warm, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE, StorageType.ARCHIVE, StorageType.ARCHIVE); + checkChooseStorageTypes(cold, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE, StorageType.ARCHIVE, StorageType.ARCHIVE); + } + + { + final List chosen = Arrays.asList(StorageType.DISK); + checkChooseStorageTypes(hot, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE, StorageType.ARCHIVE); + checkChooseStorageTypes(warm, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE, StorageType.ARCHIVE); + checkChooseStorageTypes(cold, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE, StorageType.ARCHIVE, StorageType.ARCHIVE); + } + + { + final List chosen = Arrays.asList(StorageType.ARCHIVE); + checkChooseStorageTypes(hot, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE, StorageType.ARCHIVE); + checkChooseStorageTypes(warm, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE, StorageType.ARCHIVE); + checkChooseStorageTypes(cold, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE, StorageType.ARCHIVE); + } + + { + final List chosen = Arrays.asList( + StorageType.DISK, StorageType.DISK); + checkChooseStorageTypes(hot, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE); + checkChooseStorageTypes(warm, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE, StorageType.ARCHIVE); + checkChooseStorageTypes(cold, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE, StorageType.ARCHIVE, StorageType.ARCHIVE); + } + + { + final List chosen = Arrays.asList( + StorageType.DISK, StorageType.ARCHIVE); + checkChooseStorageTypes(hot, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE); + checkChooseStorageTypes(warm, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE); + checkChooseStorageTypes(cold, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE, StorageType.ARCHIVE); + } + + { + final List chosen = Arrays.asList( + StorageType.ARCHIVE, StorageType.ARCHIVE); + checkChooseStorageTypes(hot, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE); + checkChooseStorageTypes(warm, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE); + checkChooseStorageTypes(cold, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE); + } + + { + final List chosen = Arrays.asList( + StorageType.DISK, StorageType.DISK, StorageType.DISK); + checkChooseStorageTypes(hot, replication, chosen, unavailables, isNewBlock); + checkChooseStorageTypes(warm, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE, StorageType.ARCHIVE); + checkChooseStorageTypes(cold, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE, StorageType.ARCHIVE, StorageType.ARCHIVE); + } + + { + final List chosen = Arrays.asList( + StorageType.DISK, StorageType.DISK, StorageType.ARCHIVE); + checkChooseStorageTypes(hot, replication, chosen, unavailables, isNewBlock); + checkChooseStorageTypes(warm, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE); + checkChooseStorageTypes(cold, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE, StorageType.ARCHIVE); + } + + { + final List chosen = Arrays.asList( + StorageType.DISK, StorageType.ARCHIVE, StorageType.ARCHIVE); + checkChooseStorageTypes(hot, replication, chosen, unavailables, isNewBlock); + checkChooseStorageTypes(warm, replication, chosen, unavailables, isNewBlock); + checkChooseStorageTypes(cold, replication, chosen, unavailables, isNewBlock, + StorageType.ARCHIVE); + } + + { + final List chosen = Arrays.asList( + StorageType.ARCHIVE, StorageType.ARCHIVE, StorageType.ARCHIVE); + checkChooseStorageTypes(hot, replication, chosen, unavailables, isNewBlock); + checkChooseStorageTypes(warm, replication, chosen, unavailables, isNewBlock); + checkChooseStorageTypes(cold, replication, chosen, unavailables, isNewBlock); + } + } + + static void checkChooseStorageTypes(BlockStoragePolicy p, short replication, + List chosen, EnumSet unavailables, + boolean isNewBlock, StorageType... expected) { + final List types = p.chooseStorageTypes(replication, chosen, + unavailables, isNewBlock); + assertStorageTypes(types, expected); + } + + static void assertStorageTypes(List computed, StorageType... expected) { + assertStorageTypes(computed.toArray(StorageType.EMPTY_ARRAY), expected); + } + + static void assertStorageTypes(StorageType[] computed, StorageType... expected) { + Arrays.sort(expected); + Arrays.sort(computed); + Assert.assertArrayEquals(expected, computed); + } + private void checkDirectoryListing(HdfsFileStatus[] stats, byte... policies) { Assert.assertEquals(stats.length, policies.length); for (int i = 0; i < stats.length; i++) {