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 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
075    if (functionDesc != null) {
076      costFunctionDescs.put(costFunctionName, functionDesc);
077    }
078
079    synchronized (stochasticCosts) {
080      Map<String, Double> costs = stochasticCosts.get(tableName);
081      if (costs == null) {
082        costs = new ConcurrentHashMap<>();
083      }
084
085      costs.put(costFunctionName, cost);
086      stochasticCosts.put(tableName, costs);
087    }
088  }
089
090  @Override
091  public void getMetrics(MetricsCollector metricsCollector, boolean all) {
092    MetricsRecordBuilder metricsRecordBuilder = metricsCollector.addRecord(metricsName);
093
094    if (stochasticCosts != null) {
095      synchronized (stochasticCosts) {
096        for (Map.Entry<String, Map<String, Double>> tableEntry : stochasticCosts.entrySet()) {
097          for (Map.Entry<String, Double> costEntry : tableEntry.getValue().entrySet()) {
098            String attrName = tableEntry.getKey() + TABLE_FUNCTION_SEP + costEntry.getKey();
099            Double cost = costEntry.getValue();
100            String functionDesc = costFunctionDescs.get(costEntry.getKey());
101
102            if (functionDesc == null) {
103              functionDesc = costEntry.getKey();
104            }
105
106            metricsRecordBuilder.addGauge(Interns.info(attrName, functionDesc), cost);
107          }
108        }
109      }
110    }
111    metricsRegistry.snapshot(metricsRecordBuilder, all);
112  }
113}