blob: c16e9f7f2f5141792e838939efe991a5072bb1d2 [file] [log] [blame]
/**
* 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.ozone.container.common.volume;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.ozone.container.common.interfaces.VolumeChoosingPolicy;
import org.apache.hadoop.util.DiskChecker.DiskOutOfSpaceException;
import java.io.IOException;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
/**
* Volume choosing policy that randomly choose volume with remaining
* space to satisfy the size constraints.
* <p>
* The Algorithm is as follows, Pick 2 random volumes from a given pool of
* volumeSet and then pick the volume with lower utilization. This leads to a
* higher probability of volume with lower utilization to be picked.
* <p>
* Same algorithm as the SCMContainerPlacementCapacity.
*/
public class CapacityVolumeChoosingPolicy implements VolumeChoosingPolicy {
public static final Log LOG = LogFactory.getLog(
CapacityVolumeChoosingPolicy.class);
// Stores the index of the next volume to be returned.
private final Random random = new Random();
@Override
public HddsVolume chooseVolume(List<HddsVolume> volumes,
long maxContainerSize) throws IOException {
// No volumes available to choose from
if (volumes.size() < 1) {
throw new DiskOutOfSpaceException("No more available volumes");
}
List<HddsVolume> filtered = volumes.stream()
.filter(v ->
v.getAvailable() - v.getCommittedBytes() > maxContainerSize)
.collect(Collectors.toList());
if (filtered.size() < 1) {
throw new DiskOutOfSpaceException("Out of space: "
+ "All volumes are less than the container size (=" + maxContainerSize
+ " B).");
} else if (filtered.size() == 1) {
return filtered.get(0);
} else {
// Even we don't have too many volumes in filtered for choosing, this
// algorithm will still help us choose the volume with larger
// available space than other volumes.
// Say we have vol1 with larger available space than vol2, for two choices
// , the distribution of possibility is as follows;
// 1. vol1 + vol2: 25%, result is vol1
// 2. vol1 + vol1: 25%, result is vol1
// 3. vol2 + vol1: 25%, result is vol1
// 4. vol2 + vol2: 25%, result is vol2
// So we have a total of 75% chances to choose vol1, which meets our
// expectation.
int firstIndex = random.nextInt(filtered.size());
int secondIndex = random.nextInt(filtered.size());
HddsVolume firstVolume = filtered.get(firstIndex);
HddsVolume secondVolume = filtered.get(secondIndex);
long firstAvailable = firstVolume.getAvailable()
- firstVolume.getCommittedBytes();
long secondAvailable = secondVolume.getAvailable()
- secondVolume.getCommittedBytes();
return firstAvailable < secondAvailable ? secondVolume : firstVolume;
}
}
}