1 /** 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 package org.apache.hadoop.hdfs.server.blockmanagement; 19 20 import static org.hamcrest.core.Is.is; 21 import static org.junit.Assert.assertEquals; 22 import static org.junit.Assert.assertNotNull; 23 24 import java.util.ArrayList; 25 import java.util.Iterator; 26 import java.util.Random; 27 28 import org.apache.commons.logging.Log; 29 import org.apache.commons.logging.LogFactory; 30 import org.apache.hadoop.hdfs.DFSTestUtil; 31 import org.apache.hadoop.hdfs.protocol.Block; 32 import org.apache.hadoop.hdfs.server.blockmanagement.DatanodeStorageInfo.AddBlockResult; 33 import org.apache.hadoop.hdfs.server.common.GenerationStamp; 34 import org.apache.hadoop.hdfs.server.protocol.DatanodeStorage; 35 import org.junit.Assert; 36 import org.junit.Test; 37 38 /** 39 * This class provides tests for BlockInfo class, which is used in BlocksMap. 40 * The test covers BlockList.listMoveToHead, used for faster block report 41 * processing in DatanodeDescriptor.reportDiff. 42 */ 43 44 public class TestBlockInfo { 45 46 private static final Log LOG = LogFactory 47 .getLog("org.apache.hadoop.hdfs.TestBlockInfo"); 48 49 50 @Test testAddStorage()51 public void testAddStorage() throws Exception { 52 BlockInfoContiguous blockInfo = new BlockInfoContiguous((short) 3); 53 54 final DatanodeStorageInfo storage = DFSTestUtil.createDatanodeStorageInfo("storageID", "127.0.0.1"); 55 56 boolean added = blockInfo.addStorage(storage); 57 58 Assert.assertTrue(added); 59 Assert.assertEquals(storage, blockInfo.getStorageInfo(0)); 60 } 61 62 63 @Test testReplaceStorage()64 public void testReplaceStorage() throws Exception { 65 66 // Create two dummy storages. 67 final DatanodeStorageInfo storage1 = DFSTestUtil.createDatanodeStorageInfo("storageID1", "127.0.0.1"); 68 final DatanodeStorageInfo storage2 = new DatanodeStorageInfo(storage1.getDatanodeDescriptor(), new DatanodeStorage("storageID2")); 69 final int NUM_BLOCKS = 10; 70 BlockInfoContiguous[] blockInfos = new BlockInfoContiguous[NUM_BLOCKS]; 71 72 // Create a few dummy blocks and add them to the first storage. 73 for (int i = 0; i < NUM_BLOCKS; ++i) { 74 blockInfos[i] = new BlockInfoContiguous((short) 3); 75 storage1.addBlock(blockInfos[i]); 76 } 77 78 // Try to move one of the blocks to a different storage. 79 boolean added = 80 storage2.addBlock(blockInfos[NUM_BLOCKS / 2]) == AddBlockResult.ADDED; 81 Assert.assertThat(added, is(false)); 82 Assert.assertThat(blockInfos[NUM_BLOCKS/2].getStorageInfo(0), is(storage2)); 83 } 84 85 @Test testBlockListMoveToHead()86 public void testBlockListMoveToHead() throws Exception { 87 LOG.info("BlockInfo moveToHead tests..."); 88 89 final int MAX_BLOCKS = 10; 90 91 DatanodeStorageInfo dd = DFSTestUtil.createDatanodeStorageInfo("s1", "1.1.1.1"); 92 ArrayList<Block> blockList = new ArrayList<Block>(MAX_BLOCKS); 93 ArrayList<BlockInfoContiguous> blockInfoList = new ArrayList<BlockInfoContiguous>(); 94 int headIndex; 95 int curIndex; 96 97 LOG.info("Building block list..."); 98 for (int i = 0; i < MAX_BLOCKS; i++) { 99 blockList.add(new Block(i, 0, GenerationStamp.LAST_RESERVED_STAMP)); 100 blockInfoList.add(new BlockInfoContiguous(blockList.get(i), (short) 3)); 101 dd.addBlock(blockInfoList.get(i)); 102 103 // index of the datanode should be 0 104 assertEquals("Find datanode should be 0", 0, blockInfoList.get(i) 105 .findStorageInfo(dd)); 106 } 107 108 // list length should be equal to the number of blocks we inserted 109 LOG.info("Checking list length..."); 110 assertEquals("Length should be MAX_BLOCK", MAX_BLOCKS, dd.numBlocks()); 111 Iterator<BlockInfoContiguous> it = dd.getBlockIterator(); 112 int len = 0; 113 while (it.hasNext()) { 114 it.next(); 115 len++; 116 } 117 assertEquals("There should be MAX_BLOCK blockInfo's", MAX_BLOCKS, len); 118 119 headIndex = dd.getBlockListHeadForTesting().findStorageInfo(dd); 120 121 LOG.info("Moving each block to the head of the list..."); 122 for (int i = 0; i < MAX_BLOCKS; i++) { 123 curIndex = blockInfoList.get(i).findStorageInfo(dd); 124 headIndex = dd.moveBlockToHead(blockInfoList.get(i), curIndex, headIndex); 125 // the moved element must be at the head of the list 126 assertEquals("Block should be at the head of the list now.", 127 blockInfoList.get(i), dd.getBlockListHeadForTesting()); 128 } 129 130 // move head of the list to the head - this should not change the list 131 LOG.info("Moving head to the head..."); 132 133 BlockInfoContiguous temp = dd.getBlockListHeadForTesting(); 134 curIndex = 0; 135 headIndex = 0; 136 dd.moveBlockToHead(temp, curIndex, headIndex); 137 assertEquals( 138 "Moving head to the head of the list shopuld not change the list", 139 temp, dd.getBlockListHeadForTesting()); 140 141 // check all elements of the list against the original blockInfoList 142 LOG.info("Checking elements of the list..."); 143 temp = dd.getBlockListHeadForTesting(); 144 assertNotNull("Head should not be null", temp); 145 int c = MAX_BLOCKS - 1; 146 while (temp != null) { 147 assertEquals("Expected element is not on the list", 148 blockInfoList.get(c--), temp); 149 temp = temp.getNext(0); 150 } 151 152 LOG.info("Moving random blocks to the head of the list..."); 153 headIndex = dd.getBlockListHeadForTesting().findStorageInfo(dd); 154 Random rand = new Random(); 155 for (int i = 0; i < MAX_BLOCKS; i++) { 156 int j = rand.nextInt(MAX_BLOCKS); 157 curIndex = blockInfoList.get(j).findStorageInfo(dd); 158 headIndex = dd.moveBlockToHead(blockInfoList.get(j), curIndex, headIndex); 159 // the moved element must be at the head of the list 160 assertEquals("Block should be at the head of the list now.", 161 blockInfoList.get(j), dd.getBlockListHeadForTesting()); 162 } 163 } 164 }