/**
* 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.blockmanagement;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collection;
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.conf.Configuration;
import org.apache.hadoop.hdfs.StorageType;
import org.apache.hadoop.hdfs.protocol.Block;
import org.apache.hadoop.hdfs.protocol.BlockStoragePolicy;
import org.apache.hadoop.hdfs.protocol.DatanodeInfo;
import org.apache.hadoop.hdfs.protocol.LocatedBlock;
import org.apache.hadoop.hdfs.server.namenode.FSClusterStats;
import org.apache.hadoop.net.NetworkTopology;
import org.apache.hadoop.net.Node;
public class BlurBlockPlacementPolicyDefault extends BlockPlacementPolicyDefault {
public static final String BLUR_BLOCK_PLACEMENT_SERVER_LOOKUP = "blur.block.placement.server.lookup";
private static final Log LOG = LogFactory.getLog(BlurBlockPlacementPolicyDefault.class);
private static final ServerLookup DEFAULT = new ServerLookup(null, null) {
@Override
public boolean isPathSupported(String srcPath) {
return false;
}
@Override
public String getShardServer(String srcPath) {
throw new RuntimeException("Not implemented.");
}
@Override
public DatanodeDescriptor getDatanodeDescriptor(String shardServer) {
throw new RuntimeException("Not implemented.");
}
};
private ServerLookup _serverLookup;
private Random _random;
@Override
public void initialize(Configuration conf, FSClusterStats stats, NetworkTopology clusterMap,
Host2NodesMap host2datanodeMap) {
LOG.info("initialize");
super.initialize(conf, stats, clusterMap, host2datanodeMap);
_random = new Random();
Class<?> c = conf.getClass(BLUR_BLOCK_PLACEMENT_SERVER_LOOKUP, DefaultServerLookup.class);
if (host2datanodeMap == null) {
_serverLookup = DEFAULT;
} else {
try {
Constructor<?> constructor = c.getConstructor(new Class[] { Configuration.class, Host2NodesMap.class });
_serverLookup = (ServerLookup) constructor.newInstance(conf, host2datanodeMap);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@Override
public DatanodeStorageInfo[] chooseTarget(String srcPath, int numOfReplicas, Node writer,
List<DatanodeStorageInfo> chosenNodes, boolean returnChosenNodes, Set<Node> excludedNodes, long blocksize,
BlockStoragePolicy storagePolicy) {
LOG.info("chooseTarget");
if (_serverLookup.isPathSupported(srcPath)) {
String shardServer = _serverLookup.getShardServer(srcPath);
if (shardServer == null) {
return super.chooseTarget(srcPath, numOfReplicas, writer, chosenNodes, returnChosenNodes, excludedNodes,
blocksize, storagePolicy);
}
DatanodeDescriptor shardServerDatanodeDescriptor = _serverLookup.getDatanodeDescriptor(shardServer);
if (shardServerDatanodeDescriptor == null) {
return super.chooseTarget(srcPath, numOfReplicas, writer, chosenNodes, returnChosenNodes, excludedNodes,
blocksize, storagePolicy);
}
if (isAlreadyChosen(chosenNodes, shardServerDatanodeDescriptor)) {
return super.chooseTarget(srcPath, numOfReplicas, writer, chosenNodes, returnChosenNodes, excludedNodes,
blocksize, storagePolicy);
} else {
DatanodeStorageInfo[] shardServerStorageInfos = shardServerDatanodeDescriptor.getStorageInfos();
if (shardServerStorageInfos == null || shardServerStorageInfos.length == 0) {
return super.chooseTarget(srcPath, numOfReplicas, writer, chosenNodes, returnChosenNodes, excludedNodes,
blocksize, storagePolicy);
}
DatanodeStorageInfo shardServerStorageInfo = choseOne(shardServerStorageInfos);
if (numOfReplicas - 1 == 0) {
if (returnChosenNodes) {
List<DatanodeStorageInfo> copy = new ArrayList<DatanodeStorageInfo>(chosenNodes);
copy.add(shardServerStorageInfo);
return copy.toArray(new DatanodeStorageInfo[copy.size()]);
} else {
return new DatanodeStorageInfo[] { shardServerStorageInfo };
}
}
if (chosenNodes == null) {
chosenNodes = new ArrayList<DatanodeStorageInfo>();
}
chosenNodes.add(shardServerStorageInfo);
if (returnChosenNodes) {
return super.chooseTarget(srcPath, numOfReplicas - 1, writer, chosenNodes, returnChosenNodes, excludedNodes,
blocksize, storagePolicy);
} else {
DatanodeStorageInfo[] datanodeStorageInfos = super.chooseTarget(srcPath, numOfReplicas - 1, writer,
chosenNodes, returnChosenNodes, excludedNodes, blocksize, storagePolicy);
DatanodeStorageInfo[] result = new DatanodeStorageInfo[datanodeStorageInfos.length + 1];
System.arraycopy(datanodeStorageInfos, 0, result, 1, datanodeStorageInfos.length);
result[0] = shardServerStorageInfo;
return result;
}
}
} else {
return super.chooseTarget(srcPath, numOfReplicas, writer, chosenNodes, returnChosenNodes, excludedNodes,
blocksize, storagePolicy);
}
}
@Override
public BlockPlacementStatus verifyBlockPlacement(String srcPath, LocatedBlock lBlk, int numberOfReplicas) {
LOG.info("verifyBlockPlacement");
if (_serverLookup.isPathSupported(srcPath)) {
String shardServer = _serverLookup.getShardServer(srcPath);
if (shardServer != null) {
return super.verifyBlockPlacement(srcPath, lBlk, numberOfReplicas);
}
DatanodeDescriptor shardServerDatanodeDescriptor = _serverLookup.getDatanodeDescriptor(shardServer);
String shardServerDatanodeUuid = shardServerDatanodeDescriptor.getDatanodeUuid();
DatanodeInfo[] locations = lBlk.getLocations();
for (DatanodeInfo info : locations) {
String datanodeUuid = info.getDatanodeUuid();
if (shardServerDatanodeUuid.equals(datanodeUuid)) {
// then one of the locations is on the shard server.
return super.verifyBlockPlacement(srcPath, lBlk, numberOfReplicas);
}
}
// none of the replicas are on a shard server.
BlockPlacementStatus blockPlacementStatus = super.verifyBlockPlacement(srcPath, lBlk, numberOfReplicas);
if (blockPlacementStatus.isPlacementPolicySatisfied()) {
// default block placement is satisfied, but we are not.
return new BlurBlockPlacementStatusDefault(blockPlacementStatus, shardServer);
} else {
// both are unsatisfied
return new BlurBlockPlacementStatusDefault(blockPlacementStatus, shardServer);
}
} else {
return super.verifyBlockPlacement(srcPath, lBlk, numberOfReplicas);
}
}
@Override
public DatanodeStorageInfo chooseReplicaToDelete(BlockCollection bc, Block block, short replicationFactor,
Collection<DatanodeStorageInfo> first, Collection<DatanodeStorageInfo> second, List<StorageType> excessTypes) {
LOG.info("chooseReplicaToDelete rep [" + replicationFactor + "]");
String path = bc.getName();
String shardServer = _serverLookup.getShardServer(path);
if (shardServer == null) {
return super.chooseReplicaToDelete(bc, block, replicationFactor, first, second, excessTypes);
}
DatanodeDescriptor shardServerDatanodeDescriptor = _serverLookup.getDatanodeDescriptor(shardServer);
if (replicationFactor > 1) {
Collection<DatanodeStorageInfo> firstCopy = new ArrayList<DatanodeStorageInfo>();
for (DatanodeStorageInfo info : first) {
DatanodeDescriptor datanodeDescriptor = info.getDatanodeDescriptor();
if (!datanodeDescriptor.equals(shardServerDatanodeDescriptor)) {
firstCopy.add(info);
}
}
Collection<DatanodeStorageInfo> secondCopy = new ArrayList<DatanodeStorageInfo>();
for (DatanodeStorageInfo info : second) {
DatanodeDescriptor datanodeDescriptor = info.getDatanodeDescriptor();
if (!datanodeDescriptor.equals(shardServerDatanodeDescriptor)) {
secondCopy.add(info);
}
}
return super.chooseReplicaToDelete(bc, block, replicationFactor, firstCopy, secondCopy, excessTypes);
} else {
for (DatanodeStorageInfo info : first) {
DatanodeDescriptor datanodeDescriptor = info.getDatanodeDescriptor();
if (!datanodeDescriptor.equals(shardServerDatanodeDescriptor)) {
return info;
}
}
for (DatanodeStorageInfo info : second) {
DatanodeDescriptor datanodeDescriptor = info.getDatanodeDescriptor();
if (!datanodeDescriptor.equals(shardServerDatanodeDescriptor)) {
return info;
}
}
throw new RuntimeException("Should never happen!!!");
}
}
private DatanodeStorageInfo choseOne(DatanodeStorageInfo[] storageInfos) {
synchronized (_random) {
return storageInfos[_random.nextInt(storageInfos.length)];
}
}
private boolean isAlreadyChosen(List<DatanodeStorageInfo> chosenNodes, DatanodeDescriptor datanodeDescriptor) {
for (DatanodeStorageInfo info : chosenNodes) {
if (info.getDatanodeDescriptor().equals(datanodeDescriptor)) {
return true;
}
}
return false;
}
}