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