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 }