/**
* Copyright 2016 Yahoo Inc.
*
* Licensed 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 com.yahoo.pulsar.broker.loadbalance.impl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.yahoo.pulsar.broker.loadbalance.LoadRanker;
import com.yahoo.pulsar.broker.loadbalance.ResourceDescription;
import com.yahoo.pulsar.common.policies.data.loadbalancer.ResourceUsage;
import java.util.Comparator;
import java.util.Map;
/**
*/
public class ResourceAvailabilityRanker implements LoadRanker, Comparator<ResourceDescription> {
private static final Logger log = LoggerFactory.getLogger(ResourceAvailabilityRanker.class);
/*
* Every resource's percentage availability is calculated and then added up to denote the total availability of a
* Resource Unit, if any available resource on a Resource unit is less than 5% we take it out, if only 20% of total
* resources are available then the rank would be halved for every resource that's less than 20% available
*
* Since this rank is based on ResourceAvailability Higher Number Rank means more availability, which is quite
* opposite of the word rank.
*/
@Override
public long getRank(ResourceDescription resourceDescription) {
int weight = 1;
int availabilityRank = 0;
int resourcesWithLowAvailability = 0;
// todo: need to re-think these numbers, keep it for now
// any resource with only 20% availability of total capacity will broker's probability to be selected
int minAvailableRequired = 20;
// any resource available only 5% will take this machine out of active
int absolutelyMinRequiredToFunction = 5;
boolean makeNonFunctional = false;
for (Map.Entry<String, ResourceUsage> entry : resourceDescription.getResourceUsage().entrySet()) {
int percentAvailable = 0;
if (entry.getValue().limit > 0 && entry.getValue().limit > entry.getValue().usage) {
Double temp = ((entry.getValue().limit - entry.getValue().usage) / entry.getValue().limit) * 100;
percentAvailable = temp.intValue();
}
log.debug("Resource [{}] in Percentage Available - [{}], Actual Usage is - [{}], Actual Limit is [{}]",
entry.getKey(), percentAvailable, entry.getValue().usage, entry.getValue().limit);
// give equal weight to each resource
int resourceWeight = weight * percentAvailable;
if (percentAvailable < minAvailableRequired) {
resourcesWithLowAvailability++;
}
availabilityRank += resourceWeight;
if (percentAvailable < absolutelyMinRequiredToFunction) {
makeNonFunctional = true;
}
}
if (resourcesWithLowAvailability > 0) {
availabilityRank = availabilityRank / (resourcesWithLowAvailability * 2);
log.debug("Total Resource with Low availability - [{}]", resourcesWithLowAvailability);
}
if (makeNonFunctional) {
// this will rarely be selected
availabilityRank = 0;
log.debug("ResourceUnit set to non-functional due to extremely low resources");
}
return availabilityRank;
}
public int compare(ResourceDescription rd1, ResourceDescription rd2) {
return ((Long) getRank(rd1)).compareTo(getRank(rd2));
}
}