org.apache.hadoop.hdfs.server.namenode.TestBlocksMap.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.hdfs.server.namenode.TestBlocksMap.java

Source

/**
 * 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.server.namenode;

import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hdfs.protocol.Block;
import org.apache.hadoop.hdfs.server.common.GenerationStamp;
import org.apache.hadoop.hdfs.server.namenode.BlocksMap.BlockInfo;

import static org.junit.Assert.*;
import org.junit.BeforeClass;
import org.junit.Test;

import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;

public class TestBlocksMap {

    private class MyNamesystem extends FSNamesystem {
        @Override
        void decrementSafeBlockCountForBlockRemoval(Block b) {
        }
    }

    private static final Log LOG = LogFactory.getLog(TestBlocksMap.class.getName());

    INodeFile iNode;
    Set<Block> blockList;
    BlocksMap map;
    static Runtime runtime;

    @BeforeClass
    public static void setUpBeforeClass() {
        // simulate less memory to create fewer buckets for blocks map
        runtime = spy(Runtime.getRuntime());
        FSEditLog.setRuntimeForTesting(runtime);
    }

    private void insertBlocks(int numBlocks, boolean underConstruction) {
        Random r = new Random();
        map = new BlocksMap(1000, 0.75f, new MyNamesystem());
        Set<Long> ids = new HashSet<Long>(numBlocks);

        blockList = new HashSet<Block>(numBlocks);
        if (underConstruction) {
            INodeFile node = new INodeFile();
            iNode = new INodeFileUnderConstruction(node.getId(), node.getLocalNameBytes(), (short) 2,
                    node.getModificationTime(), 0, node.getPreferredBlockSize(), node.getBlocks(),
                    node.getPermissionStatus(), "", "", null);
        } else {
            iNode = new INodeFile();
        }
        int inserted = 0;

        while (inserted < numBlocks) {
            long id;
            while (ids.contains((id = r.nextLong())))
                ;
            ids.add(id);
            Block b = new Block(id, 0, GenerationStamp.FIRST_VALID_STAMP);
            blockList.add(b);
            BlockInfo info = map.addINode(b, iNode, iNode.getReplication());

            // create 2 datanode descriptors
            DatanodeDescriptor dd;

            dd = new DatanodeDescriptor();
            dd.addBlock(info);
            dd = new DatanodeDescriptor();
            dd.addBlock(info);

            inserted++;
        }
    }

    @Test
    public void testBlockInfoPlaceUpdate() throws IOException {
        insertBlocks(100, true);

        for (Block b : blockList) {
            BlockInfo oldBlock = map.getBlockInfo(b);

            // get current locations
            DatanodeDescriptor loc0 = oldBlock.getDatanode(0);
            DatanodeDescriptor loc1 = oldBlock.getDatanode(1);
            assertNotNull(loc0);
            assertNotNull(loc1);
            assertEquals(2, oldBlock.numNodes());

            // prepare new block with different size and GS
            long newGS = b.getGenerationStamp() + 1;
            b.setGenerationStamp(newGS);
            b.setNumBytes(b.getNumBytes() + 10);
            BlockInfo newBlock = new BlockInfo(b, iNode.getReplication());

            LOG.info("Updating block: " + oldBlock + " to: " + newBlock);
            // do update
            newBlock = map.updateINode(oldBlock, newBlock, iNode, iNode.getReplication(), false);
            // preserved new generation stamp
            assertEquals(map.getStoredBlockWithoutMatchingGS(newBlock).getGenerationStamp(), newGS);
            // check locations
            assertEquals(0, newBlock.numNodes());

            // when id is mismatched, the block should not be updated
            newBlock.setBlockId(newBlock.getBlockId() + 1);
            try {
                map.updateINode(oldBlock, newBlock, iNode, iNode.getReplication(), false);
                fail("Should fail here");
            } catch (IOException e) {
                LOG.info("Can't update " + oldBlock + " to: " + newBlock + " " + e.getMessage());
            }
        }
    }

    @Test
    public void testFullIteratorWithEmptyBuckets() {
        // number of buckets is more than blocks
        testFullIterator(5000, 10 * 1024 * 1024);
    }

    @Test
    public void testFullIteratorWithNoEmptyBuckets() {
        // number of buckets is much lower than blocks
        // little chances that there will be empty buckets
        testFullIterator(100000, 1 * 1024 * 1024);
    }

    @Test
    public void testShardedIteratorWithEmptyBuckets() {
        // number of buckets is more than blocks
        testShardedIterator(5000, 10 * 1024 * 1024);
    }

    @Test
    public void testShardedIteratorWithNoEmptyBuckets() {
        // number of buckets is much lower than blocks
        // little chances that there will be empty buckets
        testShardedIterator(100000, 1 * 1024 * 1024);
    }

    @SuppressWarnings("unused")
    @Test
    public void testEmpty() {
        // test correct behaviour when the map is empty

        doReturn(new Long(1 * 1024 * 1024)).when(runtime).maxMemory();
        insertBlocks(0, false);

        for (Block b : map.getBlocks()) {
            fail("There should be no blocks in the map");
        }

        // get sharded iterators
        List<Iterator<BlockInfo>> iterators = map.getBlocksIterarors(16);
        assertEquals(16, iterators.size());
        for (Iterator<BlockInfo> iterator : iterators) {
            LOG.info("Next sharded iterator");
            while (iterator.hasNext()) {
                fail("There should be no block in any iterator");
            }
        }

    }

    private void testFullIterator(int numBlocks, long memSize) {

        // make the map have very few buckets
        doReturn(new Long(memSize)).when(runtime).maxMemory();

        insertBlocks(numBlocks, false);
        assertEquals(map.size(), numBlocks);
        assertEquals(blockList.size(), numBlocks);

        LOG.info("Starting iteration...");
        long start = System.currentTimeMillis();
        Set<Block> iteratedBlocks = new HashSet<Block>();
        for (Block b : map.getBlocks()) {
            // no block should be seen more than once
            assertFalse(iteratedBlocks.contains(b));
            iteratedBlocks.add(b);
        }
        long stop = System.currentTimeMillis();

        // each block should be seen once
        assertEquals(blockList, iteratedBlocks);
        LOG.info("Iterated : " + numBlocks + " in: " + (stop - start));
    }

    private void testShardedIterator(int numBlocks, long memSize) {

        // make the map have very few buckets
        doReturn(new Long(memSize)).when(runtime).maxMemory();

        insertBlocks(numBlocks, false);
        assertEquals(map.size(), numBlocks);
        assertEquals(blockList.size(), numBlocks);

        LOG.info("Starting iteration...");
        long start = System.currentTimeMillis();
        Set<Block> iteratedBlocks = new HashSet<Block>();

        // get sharded iterators
        List<Iterator<BlockInfo>> iterators = map.getBlocksIterarors(16);
        assertEquals(16, iterators.size());
        for (Iterator<BlockInfo> iterator : iterators) {
            LOG.info("Next sharded iterator");
            while (iterator.hasNext()) {
                Block b = new Block(iterator.next());
                // no block should be seen more than once
                assertFalse(iteratedBlocks.contains(b));
                iteratedBlocks.add(b);
            }
        }

        long stop = System.currentTimeMillis();

        // each block should be seen once
        assertEquals(blockList, iteratedBlocks);
        LOG.info("Iterated : " + numBlocks + " in: " + (stop - start));
    }
}