Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.google.common.base.Preconditions;
import org.apache.hadoop.hdds.client.RatisReplicationConfig;
import org.apache.hadoop.hdds.conf.ConfigurationSource;
import org.apache.hadoop.hdds.conf.StorageUnit;
import org.apache.hadoop.hdds.protocol.DatanodeDetails;
import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
import org.apache.hadoop.hdds.protocol.proto.HddsProtos.ReplicationFactor;
Expand All @@ -45,9 +46,10 @@
* and network topology to supply pipeline creation.
* <p>
* 1. get a list of healthy nodes
* 2. filter out nodes that are not too heavily engaged in other pipelines
* 3. Choose an anchor node among the viable nodes.
* 4. Choose other nodes around the anchor node based on network topology
* 2. filter out nodes that have space less than container size.
* 3. filter out nodes that are not too heavily engaged in other pipelines
* 4. Choose an anchor node among the viable nodes.
* 5. Choose other nodes around the anchor node based on network topology
*/
public final class PipelinePlacementPolicy extends SCMCommonPlacementPolicy {
@VisibleForTesting
Expand Down Expand Up @@ -151,11 +153,30 @@ List<DatanodeDetails> filterViableNodes(
SCMException.ResultCodes.FAILED_TO_FIND_SUITABLE_NODE);
}

long sizeRequired = (long) conf.getStorageSize(
ScmConfigKeys.OZONE_SCM_CONTAINER_SIZE,
ScmConfigKeys.OZONE_SCM_CONTAINER_SIZE_DEFAULT,
StorageUnit.BYTES);

// filter nodes that don't even have space for one container
List<DatanodeDetails> canHoldList = healthyNodes.stream().filter(d ->
hasEnoughSpace(d, sizeRequired)).collect(Collectors.toList());

if (canHoldList.size() < nodesRequired) {
msg = String.format("Pipeline creation failed due to no sufficient" +
" healthy datanodes with enough space for even a single container." +
" Required %d. Found %d. Container size %d.",
nodesRequired, canHoldList.size(), sizeRequired);
LOG.warn(msg);
throw new SCMException(msg,
SCMException.ResultCodes.FAILED_TO_FIND_SUITABLE_NODE);
}

// filter nodes that meet the size and pipeline engagement criteria.
// Pipeline placement doesn't take node space left into account.
// Sort the DNs by pipeline load.
// TODO check if sorting could cause performance issue: HDDS-3466.
List<DatanodeDetails> healthyList = healthyNodes.stream()
List<DatanodeDetails> healthyList = canHoldList.stream()
.map(d ->
new DnWithPipelines(d, currentPipelineCount(d, nodesRequired)))
.filter(d ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
import org.apache.hadoop.hdds.server.events.EventPublisher;

import org.apache.hadoop.hdds.server.events.EventQueue;
import org.apache.hadoop.ozone.OzoneConsts;
import org.apache.hadoop.security.authentication.client
.AuthenticationException;
import org.apache.hadoop.test.GenericTestUtils;
Expand Down Expand Up @@ -131,7 +132,8 @@ public void testOnMessage() throws Exception {
.concat("/" + datanode1.getUuidString());

StorageReportProto storageOne = TestUtils.createStorageReport(
datanode1.getUuid(), storagePath, 100, 10, 90, null);
datanode1.getUuid(), storagePath, 100 * OzoneConsts.TB,
10 * OzoneConsts.TB, 90 * OzoneConsts.TB, null);

// Exit safemode, as otherwise the safemode precheck will prevent pipelines
// from getting created. Due to how this test is wired up, safemode will
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertTrue;
import static org.apache.hadoop.hdds.scm.ScmConfigKeys.OZONE_DATANODE_PIPELINE_LIMIT;
import static org.apache.hadoop.hdds.scm.ScmConfigKeys.OZONE_SCM_CONTAINER_SIZE;
import static org.apache.hadoop.hdds.scm.net.NetConstants.LEAF_SCHEMA;
import static org.apache.hadoop.hdds.scm.net.NetConstants.RACK_SCHEMA;
import static org.apache.hadoop.hdds.scm.net.NetConstants.ROOT_SCHEMA;
Expand Down Expand Up @@ -174,6 +175,30 @@ public void testChooseNodeWithSingleNodeRack() throws SCMException {
Assert.assertNotEquals(results.get(1).getNetworkLocation(),
results.get(2).getNetworkLocation());
}

@Test
public void testChooseNodeNotEnoughSpace() throws SCMException {
// A huge container size
conf.set(OZONE_SCM_CONTAINER_SIZE, "10TB");

// There is only one node on 3 racks altogether.
List<DatanodeDetails> datanodes = new ArrayList<>();
for (Node node : SINGLE_NODE_RACK) {
DatanodeDetails datanode = overwriteLocationInNode(
MockDatanodeDetails.randomDatanodeDetails(), node);
datanodes.add(datanode);
}
MockNodeManager localNodeManager = new MockNodeManager(initTopology(),
datanodes, false, datanodes.size());
PipelinePlacementPolicy localPlacementPolicy = new PipelinePlacementPolicy(
localNodeManager, new PipelineStateManager(), conf);
int nodesRequired = HddsProtos.ReplicationFactor.THREE.getNumber();

thrownExp.expect(SCMException.class);
thrownExp.expectMessage("enough space for even a single container");
localPlacementPolicy.chooseDatanodes(new ArrayList<>(datanodes.size()),
new ArrayList<>(datanodes.size()), nodesRequired, 0);
}

@Test
public void testPickLowestLoadAnchor() throws IOException{
Expand Down