/*
* Copyright 2013-2014 eXascale Infolab, University of Fribourg. All rights reserved.
*/
package org.apache.hadoop.hadaps;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.hdfs.DistributedFileSystem;
import org.apache.hadoop.hdfs.StorageType;
import org.apache.hadoop.hdfs.protocol.*;
import org.apache.hadoop.hdfs.server.blockmanagement.*;
import org.apache.hadoop.hdfs.server.namenode.FSClusterStats;
import org.apache.hadoop.net.NetworkTopology;
import org.apache.hadoop.net.Node;
import java.io.IOException;
import java.net.InetAddress;
import java.util.*;
public class HadapsBlockPlacementPolicy extends BlockPlacementPolicy {
private FSClusterStats stats = null;
private NetworkTopology clusterMap = null;
private final Map<String, ParameterGeneration> generationMap = new HashMap<String, ParameterGeneration>();
private DistributedFileSystem fileSystem = null;
private BalancerNameNode nameNode = null;
protected HadapsBlockPlacementPolicy() {
}
protected HadapsBlockPlacementPolicy(Configuration conf, FSClusterStats stats, NetworkTopology clusterMap) {
initialize(conf, stats, clusterMap);
}
@Override
protected void initialize(Configuration conf, FSClusterStats stats, NetworkTopology clusterMap) {
this.stats = stats;
this.clusterMap = clusterMap;
try {
// Get generations
List<ParameterGeneration> generations = HadapsConfiguration.parseGenerations(conf);
for (ParameterGeneration generation : generations) {
for (InetAddress host : generation.getHosts()) {
generationMap.put(host.getHostAddress(), generation);
}
}
// Get distributed filesystem
FileSystem fs = FileSystem.get(conf);
if (!(fs instanceof DistributedFileSystem)) {
throw new IllegalStateException("Filesystem " + fs.getUri() + " is not an HDFS filesystem");
}
fileSystem = (DistributedFileSystem) fs;
// Create name node
nameNode = new BalancerNameNode(fileSystem);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public synchronized Map<ExtendedBlock, List<DatanodeInfo>> chooseTarget(FileStatus fileStatus) throws IOException {
if (fileStatus == null) throw new IllegalArgumentException();
// Populate extended block list
List<ExtendedBlock> extendedBlocks = new ArrayList<ExtendedBlock>();
for (LocatedBlock block : nameNode.getLocatedBlocks(fileStatus).getLocatedBlocks()) {
extendedBlocks.add(block.getBlock());
}
// Populate data node list
List<BalancerDataNode> dataNodes = new ArrayList<BalancerDataNode>();
for (DatanodeInfo node : fileSystem.getDataNodeStats(HdfsConstants.DatanodeReportType.LIVE)) {
if (node.isDecommissioned() || node.isDecommissionInProgress()) {
continue;
}
ParameterGeneration generation = generationMap.get(node.getIpAddr());
if (generation != null) {
dataNodes.add(new BalancerDataNode(node, generation.getWeight()));
}
}
Collections.sort(dataNodes);
// Initialize weight factors
float totalWeight = 0.0f;
for (BalancerDataNode node : dataNodes) {
totalWeight += node.getWeight();
}
float baseWeight = extendedBlocks.size() / totalWeight;
for (BalancerDataNode node : dataNodes) {
node.setWeight((float) Math.ceil(node.getWeight() * baseWeight));
}
// Initialize node map
Map<BalancerDataNode, List<ExtendedBlock>> nodeMap = new HashMap<BalancerDataNode, List<ExtendedBlock>>();
for (BalancerDataNode node : dataNodes) {
nodeMap.put(node, new ArrayList<ExtendedBlock>());
}
// Iterate over replication factor
for (int replication = 0; replication < fileStatus.getReplication(); ++replication) {
List<BalancerDataNode> nodes = new ArrayList<BalancerDataNode>(dataNodes);
List<ExtendedBlock> blocks = new ArrayList<ExtendedBlock>(extendedBlocks);
Map<BalancerDataNode, Float> weightMap = new HashMap<BalancerDataNode, Float>();
for (BalancerDataNode node : dataNodes) {
weightMap.put(node, node.getWeight());
}
// Iterate over all blocks
Iterator<ExtendedBlock> blockIter = blocks.iterator();
while (!blocks.isEmpty()) {
if (!blockIter.hasNext()) {
blockIter = blocks.iterator();
nodes = new ArrayList<BalancerDataNode>(dataNodes);
}
ExtendedBlock block = blockIter.next();
// Populate our node list with all data nodes
if (nodes.isEmpty()) {
for (BalancerDataNode node : dataNodes) {
if (weightMap.get(node) > 0) {
nodes.add(node);
}
}
}
// Loop over remaining nodes
for (BalancerDataNode node : nodes) {
List<ExtendedBlock> list = nodeMap.get(node);
if (!list.contains(block)) {
// We've found a valid node
list.add(block);
nodes.remove(node);
blocks.remove(block);
weightMap.put(node, weightMap.get(node) - 1);
blockIter = blocks.iterator();
break;
}
}
}
}
// Generate block map
Map<ExtendedBlock, List<DatanodeInfo>> blockMap = new HashMap<ExtendedBlock, List<DatanodeInfo>>();
for (Map.Entry<BalancerDataNode, List<ExtendedBlock>> entry : nodeMap.entrySet()) {
for (ExtendedBlock block : entry.getValue()) {
List<DatanodeInfo> nodes = blockMap.get(block);
if (nodes == null) {
nodes = new ArrayList<DatanodeInfo>();
blockMap.put(block, nodes);
}
nodes.add(entry.getKey().getDataNode());
}
}
return blockMap;
}
@Override
public DatanodeStorageInfo[] chooseTarget(String srcPath,
int numOfReplicas,
Node writer,
List<DatanodeStorageInfo> chosen,
boolean returnChosenNodes,
Set<Node> excludedNodes,
long blocksize,
StorageType storageType) {
// TODO
return new DatanodeStorageInfo[0];
}
@Override
public BlockPlacementStatus verifyBlockPlacement(String srcPath,
LocatedBlock lBlk,
int numOfReplicas) {
// TODO
return null;
}
@Override
public DatanodeDescriptor chooseReplicaToDelete(BlockCollection srcBC,
Block block,
short replicationFactor,
Collection<DatanodeDescriptor> existingReplicas,
Collection<DatanodeDescriptor> moreExistingReplicas) {
// TODO
return null;
}
}