Package org.apache.hadoop.hdfs.server.namenode

Source Code of org.apache.hadoop.hdfs.server.namenode.RaidMissingBlocks$RaidMissingBlocksPerCodec

/**
* 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.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

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.namenode.BlocksMap.BlockInfo;
import org.apache.hadoop.hdfs.server.namenode.INodeRaidStorage.RaidBlockInfo;
import org.apache.hadoop.raid.RaidCodec;

/**
* This class manages the priority queues for each RaidCodec.
*
*/
class RaidMissingBlocks {
  static final Log LOG = LogFactory.getLog(RaidMissingBlocks.class);
  final HashMap<RaidCodec, RaidMissingBlocksPerCodec> queues
        = new HashMap<RaidCodec, RaidMissingBlocksPerCodec> ();
 
  RaidMissingBlocks() {
    for (RaidCodec codec : RaidCodec.getCodecs()) {
      queues.put(codec, new RaidMissingBlocksPerCodec(codec));
    }
  }
 
  /**
   * Empty the queues.
   */
  void clear() {
    for (RaidMissingBlocksPerCodec codecQueue : queues.values()) {
      codecQueue.clear();
    }
  }
 
  /**
   * Get the total count of the missing blocks
   */
  int getTotalCount() {
    int ret = 0;
    for (RaidMissingBlocksPerCodec queue : queues.values()) {
      ret += queue.getTotalCount();
    }
    return ret;
  }
 
  /**
   * Add a missing Raided block to its codec queue.
   */
  boolean add(BlockInfo blockInfo, RaidCodec codec) {
    if(queues.get(codec).add(blockInfo)) {
      if (NameNode.stateChangeLog.isDebugEnabled()) {
        NameNode.stateChangeLog.debug(
                                      "BLOCK* NameSystem.RaidMissingBlocks.add:"
                                      + blockInfo
                                      + " file "+ blockInfo.getINode()
                                      + " codec " + codec.id);
      }
      return true;
    }
    return false;
  }
 
  /**
   * Remove a missing Raided block from its codec queue.
   */
  boolean remove(BlockInfo blockInfo, RaidCodec codec) {
    if(queues.get(codec).remove(blockInfo)) {
      if (NameNode.stateChangeLog.isDebugEnabled()) {
        NameNode.stateChangeLog.debug(
                                      "BLOCK* NameSystem.RaidMissingBlocks.remove:"
                                      + blockInfo
                                      + " file "+ blockInfo.getINode()
                                      + " codec " + codec.id);
      }
      return true;
    }
    return false;
  }
 
  /**
   * This class maintains a priority queue for one RaidCodec.
   *
   * Not thread-safe.
   *
   * Each entity in the queue points to the missing blocks in a stripe,
   * we use the first parity block to represent the stripe and has a hashset
   * to store all the indexes of the missing blocks in the stripe.
   *
   * We prioritize the stripe according to number of missing blocks in the stripe.
   * We calculate the priorities like this:
   * num_missing_blocks       priorities
   *      1                       0
   *      2                       1
   *     ...                     ...
   *   numParityBlocks         numParityBlocks - 1
   *     more                  numParityBlocks(corruptLevel)
   *                            maxLevel
   * 
   */
  private static class RaidMissingBlocksPerCodec {
   
    private final RaidCodec codec;
    // the maxLevel, will be codec.numPrityBlock + 1
    private final int maxLevel;
   
    private final List<HashMap<RaidBlockInfo, HashSet<Integer>>> priorityQueues
          = new ArrayList<HashMap<RaidBlockInfo, HashSet<Integer>>> ();
   
    RaidMissingBlocksPerCodec(RaidCodec codec) {
      this.codec = codec;
      this.maxLevel = codec.numParityBlocks + 1;
     
      for (int i = 0; i < maxLevel; i++) {
        priorityQueues.add(new HashMap<RaidBlockInfo, HashSet<Integer>>());
      }
    }
   
    /**
     * Empty the queues.
     */
    void clear() {
      for(int i = 0; i < maxLevel; i++) {
        priorityQueues.get(i).clear();
      }
    }
   
    /** Return the number of Raid missing blocks of priority */
    int size(int priority) {
      if (priority < 0 || priority >= maxLevel) {
        throw new IllegalArgumentException("Unsupported priority: " + priority);
      }
     
      if (priority < maxLevel - 1) {
        return priorityQueues.get(priority).size() * (priority + 1);
      } else {
        int ret = 0;
        for (HashSet<Integer> missingBlocks : priorityQueues.get(priority).values()) {
          ret += missingBlocks.size();
        }
        return ret;
      }
    }
   
    /**
     * get total count of the missing blocks in this queue.
     */
    int getTotalCount() {
      int ret = 0;
      for (int priority = 0; priority < maxLevel; priority ++) {
        ret += size(priority);
      }
      return ret;
    }
   
    private int getBlockIndex(BlockInfo blockInfo)
                      throws IOException {
      if (blockInfo instanceof RaidBlockInfo) {
        return ((RaidBlockInfo) blockInfo).getIndex();
      } else {
        return blockInfo.getINode().getBlockIndex(blockInfo, blockInfo.getINode().toString());
      }
    }
   
    /**
     * Add a missing block to the queue.
     *
     */
    boolean add(BlockInfo blockInfo) {
      INodeFile fileINode = blockInfo.getINode();
      try {
        int blockIndex = getBlockIndex(blockInfo);
        RaidBlockInfo firstBlock = fileINode.getFirstBlockInStripe(blockInfo, blockIndex);
        HashSet<Integer> missingBlkIdxs = null;
        int i = 0;
        for (; i < maxLevel; i++) {
          HashMap<RaidBlockInfo, HashSet<Integer>> queue = priorityQueues.get(i);
          if (queue.containsKey(firstBlock)) {
            missingBlkIdxs = queue.get(firstBlock);
            if (missingBlkIdxs.contains(blockIndex)) {
              return false;
            }
           
            if (i == maxLevel - 1) {
              missingBlkIdxs.add(blockIndex);
              return true;
            }
            queue.remove(firstBlock);
            break;
          }
        }
       
        if (missingBlkIdxs == null) {
          // no other missing blocks in this stripe
          missingBlkIdxs = new HashSet<Integer>(1);
          missingBlkIdxs.add(blockIndex);
          priorityQueues.get(0).put(firstBlock, missingBlkIdxs);
        } else {
          // there are other missing blocks in this stripe
          missingBlkIdxs.add(blockIndex);
          priorityQueues.get(i + 1).put(firstBlock, missingBlkIdxs);
        }
       
        return true;
      } catch (IOException ex) {
        LOG.warn("Failed to add block into Raid missing blocks queue: " +
                                "block: " + blockInfo +
                                "file: " + fileINode +
                                "codec: " + codec.id,
                                ex);
        return false;
      }
    }
   
    /**
     * remove a missing block from the queue.
     */
    boolean remove(BlockInfo blockInfo) {
      INodeFile fileINode = blockInfo.getINode();
      try {
        int blockIndex = getBlockIndex(blockInfo);
        RaidBlockInfo firstBlock = fileINode.getFirstBlockInStripe(blockInfo, blockIndex);
        HashSet<Integer> missingBlkIdxs = null;
        int i = 0;
        for (; i < maxLevel; i++) {
          HashMap<RaidBlockInfo, HashSet<Integer>> queue = priorityQueues.get(i);
          if (queue.containsKey(firstBlock)) {
            missingBlkIdxs = queue.get(firstBlock);
            if (!missingBlkIdxs.contains(blockIndex)) {
              return false;
            }
            break;
          }
        }

        if (missingBlkIdxs == null) {
          // can not find any missing blocks in this stripe
          return false;
        } else {
          missingBlkIdxs.remove(blockIndex);
          if (missingBlkIdxs.size() == 0) {
            priorityQueues.get(i).remove(firstBlock);
          } else if (missingBlkIdxs.size() < (i + 1)) {
            priorityQueues.get(i).remove(firstBlock);
            priorityQueues.get(i - 1).put(firstBlock, missingBlkIdxs);
          }
        }
        return true;
      } catch (Exception ex) {
        LOG.warn("Failed to remove block from Raid missing blocks queue: " +
                                    "block: " + blockInfo +
                                    "file: " + fileINode +
                                    "codec: " + codec.id,
                                    ex);
        return false;
      }
    }
  }
}
TOP

Related Classes of org.apache.hadoop.hdfs.server.namenode.RaidMissingBlocks$RaidMissingBlocksPerCodec

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.