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.util.LinkedHashMap;
021import java.util.Map;
022import java.util.concurrent.ConcurrentHashMap;
023import org.apache.hadoop.hbase.metrics.Interns;
024import org.apache.hadoop.metrics2.MetricsCollector;
025import org.apache.hadoop.metrics2.MetricsRecordBuilder;
026import org.apache.yetus.audience.InterfaceAudience;
027
028@InterfaceAudience.Private
029public class MetricsStochasticBalancerSourceImpl extends MetricsBalancerSourceImpl
030  implements MetricsStochasticBalancerSource {
031  private static final String TABLE_FUNCTION_SEP = "_";
032
033  // Most Recently Used(MRU) cache
034  private static final float MRU_LOAD_FACTOR = 0.75f;
035  private int metricsSize = 1000;
036  private int mruCap = calcMruCap(metricsSize);
037
038  private final Map<String, Map<String, Double>> stochasticCosts =
039    new LinkedHashMap<String, Map<String, Double>>(mruCap, MRU_LOAD_FACTOR, true) {
040      private static final long serialVersionUID = 8204713453436906599L;
041
042      @Override
043      protected boolean removeEldestEntry(Map.Entry<String, Map<String, Double>> eldest) {
044        return size() > mruCap;
045      }
046    };
047  private Map<String, String> costFunctionDescs = new ConcurrentHashMap<>();
048
049  /**
050   * Calculates the mru cache capacity from the metrics size
051   */
052  private static int calcMruCap(int metricsSize) {
053    return (int) Math.ceil(metricsSize / MRU_LOAD_FACTOR) + 1;
054  }
055
056  @Override
057  public void updateMetricsSize(int size) {
058    if (size > 0) {
059      metricsSize = size;
060      mruCap = calcMruCap(size);
061    }
062  }
063
064  /**
065   * Reports stochastic load balancer costs to JMX
066   */
067  @Override
068  public void updateStochasticCost(String tableName, String costFunctionName, String functionDesc,
069    Double cost) {
070    if (tableName == null || costFunctionName == null || cost == null) {
071      return;
072    }
073    if (functionDesc != null) {
074      costFunctionDescs.put(costFunctionName, functionDesc);
075    }
076
077    synchronized (stochasticCosts) {
078      Map<String, Double> costs = stochasticCosts.get(tableName);
079      if (costs == null) {
080        costs = new ConcurrentHashMap<>();
081      }
082      costs.put(costFunctionName, cost);
083      stochasticCosts.put(tableName, costs);
084    }
085  }
086
087  @Override
088  public void getMetrics(MetricsCollector metricsCollector, boolean all) {
089    MetricsRecordBuilder metricsRecordBuilder = metricsCollector.addRecord(metricsName);
090
091    if (stochasticCosts != null) {
092      synchronized (stochasticCosts) {
093        for (Map.Entry<String, Map<String, Double>> tableEntry : stochasticCosts.entrySet()) {
094          for (Map.Entry<String, Double> costEntry : tableEntry.getValue().entrySet()) {
095            String attrName = tableEntry.getKey() + TABLE_FUNCTION_SEP + costEntry.getKey();
096            Double cost = costEntry.getValue();
097            String functionDesc = costFunctionDescs.get(costEntry.getKey());
098
099            if (functionDesc == null) {
100              functionDesc = costEntry.getKey();
101            }
102
103            metricsRecordBuilder.addGauge(Interns.info(attrName, functionDesc), cost);
104          }
105        }
106      }
107    }
108    metricsRegistry.snapshot(metricsRecordBuilder, all);
109  }
110}