blob: bfaf0a3d1178731c3fcf5751e2b1b2ec1783b609 [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.hbase.master.balancer;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.master.balancer.BalancerClusterState.LocalityType;
import org.apache.yetus.audience.InterfaceAudience;
/**
* Compute a cost of a potential cluster configuration based upon where
* {@link org.apache.hadoop.hbase.regionserver.HStoreFile}s are located.
*/
@InterfaceAudience.Private
abstract class LocalityBasedCostFunction extends CostFunction {
private final LocalityType type;
private double bestLocality; // best case locality across cluster weighted by local data size
private double locality; // current locality across cluster weighted by local data size
LocalityBasedCostFunction(Configuration conf, LocalityType type, String localityCostKey,
float defaultLocalityCost) {
this.type = type;
this.setMultiplier(conf.getFloat(localityCostKey, defaultLocalityCost));
this.locality = 0.0;
this.bestLocality = 0.0;
}
/**
* Maps region to the current entity (server or rack) on which it is stored
*/
abstract int regionIndexToEntityIndex(int region);
@Override
void init(BalancerClusterState cluster) {
super.init(cluster);
locality = 0.0;
bestLocality = 0.0;
for (int region = 0; region < cluster.numRegions; region++) {
locality += getWeightedLocality(region, regionIndexToEntityIndex(region));
bestLocality += getWeightedLocality(region, getMostLocalEntityForRegion(region));
}
// We normalize locality to be a score between 0 and 1.0 representing how good it
// is compared to how good it could be. If bestLocality is 0, assume locality is 100
// (and the cost is 0)
locality = bestLocality == 0 ? 1.0 : locality / bestLocality;
}
@Override
protected void regionMoved(int region, int oldServer, int newServer) {
int oldEntity =
type == LocalityType.SERVER ? oldServer : cluster.serverIndexToRackIndex[oldServer];
int newEntity =
type == LocalityType.SERVER ? newServer : cluster.serverIndexToRackIndex[newServer];
double localityDelta =
getWeightedLocality(region, newEntity) - getWeightedLocality(region, oldEntity);
double normalizedDelta = bestLocality == 0 ? 0.0 : localityDelta / bestLocality;
locality += normalizedDelta;
}
@Override
protected final double cost() {
return 1 - locality;
}
private int getMostLocalEntityForRegion(int region) {
return cluster.getOrComputeRegionsToMostLocalEntities(type)[region];
}
private double getWeightedLocality(int region, int entity) {
return cluster.getOrComputeWeightedLocality(region, entity, type);
}
}