/* * Copyright The Apache Software Foundation * * 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.regionserver.metrics; import java.util.Set; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.client.Append; import org.apache.hadoop.hbase.client.Delete; import org.apache.hadoop.hbase.client.Get; import org.apache.hadoop.hbase.client.HTable; import org.apache.hadoop.hbase.client.Increment; import org.apache.hadoop.hbase.client.Put; import org.apache.hadoop.hbase.util.Bytes; /** * This class provides a simplified interface to expose time varying metrics * about GET/DELETE/PUT/ICV operations on a region and on Column Families. All * metrics are stored in {@link RegionMetricsStorage} and exposed to hadoop * metrics through {@link RegionServerDynamicMetrics}. */ public class OperationMetrics { private static final String DELETE_KEY = "delete_"; private static final String PUT_KEY = "put_"; private static final String GET_KEY = "get_"; private static final String ICV_KEY = "incrementColumnValue_"; private static final String INCREMENT_KEY = "increment_"; private static final String MULTIPUT_KEY = "multiput_"; private static final String MULTIDELETE_KEY = "multidelete_"; private static final String APPEND_KEY = "append_"; private static final String READREQUESTCOUNT_KEY = "readrequestcount"; private static final String WRITEREQUESTCOUNT_KEY = "writerequestcount"; /** Conf key controlling whether we should expose metrics.*/ private static final String CONF_KEY = "hbase.metrics.exposeOperationTimes"; private final String tableName; private final String regionName; private final String regionMetrixPrefix; private final Configuration conf; private final boolean exposeTimes; /** * Create a new OperationMetrics * @param conf The Configuration of the HRegion reporting operations coming in. * @param regionInfo The region info */ public OperationMetrics(Configuration conf, HRegionInfo regionInfo) { // Configure SchemaMetrics before trying to create a RegionOperationMetrics instance as // RegionOperationMetrics relies on SchemaMetrics to do naming. if (conf != null) { SchemaMetrics.configureGlobally(conf); this.conf = conf; if (regionInfo != null) { this.tableName = regionInfo.getTableNameAsString(); this.regionName = regionInfo.getEncodedName(); } else { this.tableName = SchemaMetrics.UNKNOWN; this.regionName = SchemaMetrics.UNKNOWN; } this.regionMetrixPrefix = SchemaMetrics.generateRegionMetricsPrefix(this.tableName, this.regionName); this.exposeTimes = this.conf.getBoolean(CONF_KEY, true); } else { //Make all the final values happy. this.conf = null; this.tableName = null; this.regionName = null; this.regionMetrixPrefix = null; this.exposeTimes = false; } } /** * This is used in creating a testing HRegion where the regionInfo is unknown * @param conf */ public OperationMetrics() { this(null, null); } /* * This is used in set the read request count that is going to be exposed to * hadoop metric framework. * @param value absolute value of read account */ public void setReadRequestCountMetrics(long value) { doSetNumericPersistentMetrics(READREQUESTCOUNT_KEY, value); } /* * This is used in set the read request count that is going to be exposed to * hadoop metric framework. * @param value absolute value of write account */ public void setWriteRequestCountMetrics(long value) { doSetNumericPersistentMetrics(WRITEREQUESTCOUNT_KEY, value); } private void doSetNumericPersistentMetrics(String key, long value) { RegionMetricsStorage.setNumericPersistentMetric(this.regionMetrixPrefix+key, value); } /** * Update the stats associated with {@link HTable#put(java.util.List)}. * * @param columnFamilies Set of CF's this multiput is associated with * @param value the time */ public void updateMultiPutMetrics(Set<byte[]> columnFamilies, long value) { doUpdateTimeVarying(columnFamilies, MULTIPUT_KEY, value); } /** * Update the stats associated with {@link HTable#delete(java.util.List)}. * * @param columnFamilies Set of CF's this multidelete is associated with * @param value the time */ public void updateMultiDeleteMetrics(Set<byte[]> columnFamilies, long value) { doUpdateTimeVarying(columnFamilies, MULTIDELETE_KEY, value); } /** * Update the metrics associated with a {@link Get} * * @param columnFamilies * Set of Column Families in this get. * @param value * the time */ public void updateGetMetrics(Set<byte[]> columnFamilies, long value) { doUpdateTimeVarying(columnFamilies, GET_KEY, value); } /** * Update metrics associated with an {@link Increment} * @param columnFamilies * @param value */ public void updateIncrementMetrics(Set<byte[]> columnFamilies, long value) { doUpdateTimeVarying(columnFamilies, INCREMENT_KEY, value); } /** * Update the metrics associated with an {@link Append} * @param columnFamilies * @param value */ public void updateAppendMetrics(Set<byte[]> columnFamilies, long value) { doUpdateTimeVarying(columnFamilies, APPEND_KEY, value); } /** * Update the metrics associated with * {@link HTable#incrementColumnValue(byte[], byte[], byte[], long)} * * @param columnFamily * The single column family associated with an ICV * @param value * the time */ public void updateIncrementColumnValueMetrics(byte[] columnFamily, long value) { String cfMetricPrefix = SchemaMetrics.generateSchemaMetricsPrefix(this.tableName, Bytes.toString(columnFamily)); doSafeIncTimeVarying(cfMetricPrefix, ICV_KEY, value); doSafeIncTimeVarying(this.regionMetrixPrefix, ICV_KEY, value); } /** * update metrics associated with a {@link Put} * * @param columnFamilies * Set of column families involved. * @param value * the time. */ public void updatePutMetrics(Set<byte[]> columnFamilies, long value) { doUpdateTimeVarying(columnFamilies, PUT_KEY, value); } /** * update metrics associated with a {@link Delete} * * @param columnFamilies * @param value * the time. */ public void updateDeleteMetrics(Set<byte[]> columnFamilies, long value) { doUpdateTimeVarying(columnFamilies, DELETE_KEY, value); } /** * This deletes all old non-persistent metrics this instance has ever created or updated. * for persistent metrics, only delete for the region to be closed * @param regionEncodedName the region that is to be closed */ public void closeMetrics(String regionEncodedName) { RegionMetricsStorage.clear(regionEncodedName); } /** * Method to send updates for cf and region metrics. This is the normal method * used if the naming of stats and CF's are in line with put/delete/multiput. * * @param columnFamilies * the set of column families involved. * @param key * the metric name. * @param value * the time. */ private void doUpdateTimeVarying(Set<byte[]> columnFamilies, String key, long value) { String cfPrefix = null; if (columnFamilies != null) { cfPrefix = SchemaMetrics.generateSchemaMetricsPrefix(tableName, columnFamilies); } else { cfPrefix = SchemaMetrics.generateSchemaMetricsPrefix(tableName, SchemaMetrics.UNKNOWN); } doSafeIncTimeVarying(cfPrefix, key, value); doSafeIncTimeVarying(this.regionMetrixPrefix, key, value); } private void doSafeIncTimeVarying(String prefix, String key, long value) { if (exposeTimes) { if (prefix != null && !prefix.isEmpty() && key != null && !key.isEmpty()) { String m = prefix + key; RegionMetricsStorage.incrTimeVaryingMetric(m, value); } } } }