001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.master.balancer; 019 020import java.time.Duration; 021import java.util.List; 022import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 023import org.apache.yetus.audience.InterfaceAudience; 024import org.apache.yetus.audience.InterfaceStability; 025import org.slf4j.Logger; 026import org.slf4j.LoggerFactory; 027 028@InterfaceAudience.Private 029@InterfaceStability.Evolving 030public abstract class RegionPlanConditionalCandidateGenerator extends CandidateGenerator { 031 032 private static final Logger LOG = 033 LoggerFactory.getLogger(RegionPlanConditionalCandidateGenerator.class); 034 035 private static final Duration WEIGHT_CACHE_TTL = Duration.ofMinutes(1); 036 private long lastWeighedAt = -1; 037 private double lastWeight = 0.0; 038 039 private final BalancerConditionals balancerConditionals; 040 041 RegionPlanConditionalCandidateGenerator(BalancerConditionals balancerConditionals) { 042 this.balancerConditionals = balancerConditionals; 043 } 044 045 BalancerConditionals getBalancerConditionals() { 046 return this.balancerConditionals; 047 } 048 049 /** 050 * Generates a balancing action to appease the conditional. 051 * @param cluster Current state of the cluster. 052 * @param isWeighing Flag indicating if the generator is being used for weighing. 053 * @return A BalanceAction, or NULL_ACTION if no action is needed. 054 */ 055 abstract BalanceAction generateCandidate(BalancerClusterState cluster, boolean isWeighing); 056 057 @Override 058 BalanceAction generate(BalancerClusterState cluster) { 059 BalanceAction balanceAction = generateCandidate(cluster, false); 060 if (!willBeAccepted(cluster, balanceAction)) { 061 LOG.debug("Generated action is not widely accepted by all conditionals. " 062 + "Likely we are finding our way out of a deadlock. balanceAction={}", balanceAction); 063 } 064 return balanceAction; 065 } 066 067 BalanceAction batchMovesAndResetClusterState(BalancerClusterState cluster, 068 List<MoveRegionAction> moves) { 069 if (moves.isEmpty()) { 070 return BalanceAction.NULL_ACTION; 071 } 072 MoveBatchAction batchAction = new MoveBatchAction(moves); 073 undoBatchAction(cluster, batchAction); 074 return batchAction; 075 } 076 077 boolean willBeAccepted(BalancerClusterState cluster, BalanceAction action) { 078 BalancerConditionals balancerConditionals = getBalancerConditionals(); 079 if (balancerConditionals == null) { 080 return true; 081 } 082 return !balancerConditionals.isViolating(cluster, action); 083 } 084 085 void undoBatchAction(BalancerClusterState cluster, MoveBatchAction batchAction) { 086 for (int i = batchAction.getMoveActions().size() - 1; i >= 0; i--) { 087 MoveRegionAction action = batchAction.getMoveActions().get(i); 088 cluster.doAction(action.undoAction()); 089 } 090 } 091 092 void clearWeightCache() { 093 lastWeighedAt = -1; 094 } 095 096 double getWeight(BalancerClusterState cluster) { 097 boolean hasCandidate = false; 098 099 // Candidate generation is expensive, so for re-weighing generators we will cache 100 // the value for a bit 101 if (EnvironmentEdgeManager.currentTime() - lastWeighedAt < WEIGHT_CACHE_TTL.toMillis()) { 102 return lastWeight; 103 } else { 104 hasCandidate = generateCandidate(cluster, true) != BalanceAction.NULL_ACTION; 105 lastWeighedAt = EnvironmentEdgeManager.currentTime(); 106 } 107 108 if (hasCandidate) { 109 // If this generator has something to do, then it's important 110 lastWeight = CandidateGenerator.MAX_WEIGHT; 111 } else { 112 lastWeight = 0; 113 } 114 return lastWeight; 115 } 116}