View Javadoc

1   /*
2    * Copyright The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one or more
5    * contributor license agreements. See the NOTICE file distributed with this
6    * work for additional information regarding copyright ownership. The ASF
7    * licenses this file to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   *
11   * http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16   * License for the specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.hadoop.hbase.regionserver.metrics;
20  
21  import java.util.Set;
22  
23  import org.apache.hadoop.conf.Configuration;
24  import org.apache.hadoop.hbase.HRegionInfo;
25  import org.apache.hadoop.hbase.client.Append;
26  import org.apache.hadoop.hbase.client.Delete;
27  import org.apache.hadoop.hbase.client.Get;
28  import org.apache.hadoop.hbase.client.HTable;
29  import org.apache.hadoop.hbase.client.Increment;
30  import org.apache.hadoop.hbase.client.Put;
31  import org.apache.hadoop.hbase.util.Bytes;
32  
33  /**
34   * This class provides a simplified interface to expose time varying metrics
35   * about GET/DELETE/PUT/ICV operations on a region and on Column Families. All
36   * metrics are stored in {@link RegionMetricsStorage} and exposed to hadoop
37   * metrics through {@link RegionServerDynamicMetrics}.
38   */
39  public class OperationMetrics {
40  
41    private static final String DELETE_KEY = "delete_";
42    private static final String PUT_KEY = "put_";
43    private static final String GET_KEY = "get_";
44    private static final String ICV_KEY = "incrementColumnValue_";
45    private static final String INCREMENT_KEY = "increment_";
46    private static final String MULTIPUT_KEY = "multiput_";
47    private static final String MULTIDELETE_KEY = "multidelete_";
48    private static final String APPEND_KEY = "append_";
49    private static final String READREQUESTCOUNT_KEY = "readrequestcount";
50    private static final String WRITEREQUESTCOUNT_KEY = "writerequestcount";
51    
52    /** Conf key controlling whether we should expose metrics.*/
53    private static final String CONF_KEY =
54        "hbase.metrics.exposeOperationTimes";
55  
56    private final String tableName;
57    private final String regionName;
58    private final String regionMetrixPrefix;
59    private final Configuration conf;
60    private final boolean exposeTimes;
61  
62  
63    /**
64     * Create a new OperationMetrics
65     * @param conf The Configuration of the HRegion reporting operations coming in.
66     * @param regionInfo The region info
67     */
68    public OperationMetrics(Configuration conf, HRegionInfo regionInfo) { 
69      // Configure SchemaMetrics before trying to create a RegionOperationMetrics instance as
70      // RegionOperationMetrics relies on SchemaMetrics to do naming.
71      if (conf != null) {
72        SchemaMetrics.configureGlobally(conf);
73        
74        this.conf = conf;
75        if (regionInfo != null) {
76          this.tableName = regionInfo.getTableNameAsString();
77          this.regionName = regionInfo.getEncodedName();
78        } else {
79          this.tableName = SchemaMetrics.UNKNOWN;
80          this.regionName = SchemaMetrics.UNKNOWN;
81        }
82        this.regionMetrixPrefix =
83            SchemaMetrics.generateRegionMetricsPrefix(this.tableName, this.regionName);
84        this.exposeTimes = this.conf.getBoolean(CONF_KEY, true);
85      } else {
86        //Make all the final values happy.
87        this.conf = null;
88        this.tableName = null;
89        this.regionName = null;
90        this.regionMetrixPrefix = null;
91        this.exposeTimes = false;
92      }
93    }
94    
95    /**
96     * This is used in creating a testing HRegion where the regionInfo is unknown
97     * @param conf
98     */
99    public OperationMetrics() {
100     this(null, null);
101   }
102 
103     /*
104      * This is used in set the read request count that is going to be exposed to 
105      * hadoop metric framework.
106      * @param value absolute value of read account
107      */
108     public void setReadRequestCountMetrics(long value) {
109       doSetNumericPersistentMetrics(READREQUESTCOUNT_KEY, value);
110     }
111 
112     /*
113      * This is used in set the read request count that is going to be exposed to 
114      * hadoop metric framework.
115      * @param value absolute value of write account
116      */
117     public void setWriteRequestCountMetrics(long value) {
118       doSetNumericPersistentMetrics(WRITEREQUESTCOUNT_KEY, value);
119     }
120     
121     private void doSetNumericPersistentMetrics(String key, long value) {      
122        RegionMetricsStorage.setNumericPersistentMetric(this.regionMetrixPrefix+key, value); 
123     }    
124 
125   /**
126    * Update the stats associated with {@link HTable#put(java.util.List)}.
127    * 
128    * @param columnFamilies Set of CF's this multiput is associated with
129    * @param value the time
130    */
131   public void updateMultiPutMetrics(Set<byte[]> columnFamilies, long value) {
132     doUpdateTimeVarying(columnFamilies, MULTIPUT_KEY, value);
133   }
134 
135   /**
136    * Update the stats associated with {@link HTable#delete(java.util.List)}.
137    *
138    * @param columnFamilies Set of CF's this multidelete is associated with
139    * @param value the time
140    */
141   public void updateMultiDeleteMetrics(Set<byte[]> columnFamilies, long value) {
142     doUpdateTimeVarying(columnFamilies, MULTIDELETE_KEY, value);
143   }
144   
145   /**
146    * Update the metrics associated with a {@link Get}
147    * 
148    * @param columnFamilies
149    *          Set of Column Families in this get.
150    * @param value
151    *          the time
152    */
153   public void updateGetMetrics(Set<byte[]> columnFamilies, long value) {
154     doUpdateTimeVarying(columnFamilies, GET_KEY, value);
155   }
156   
157   /**
158    * Update metrics associated with an {@link Increment}
159    * @param columnFamilies
160    * @param value
161    */
162   public void updateIncrementMetrics(Set<byte[]> columnFamilies, long value) {
163     doUpdateTimeVarying(columnFamilies, INCREMENT_KEY, value);
164   }
165   
166   
167   /**
168    * Update the metrics associated with an {@link Append}
169    * @param columnFamilies
170    * @param value
171    */
172   public void updateAppendMetrics(Set<byte[]> columnFamilies, long value) {
173     doUpdateTimeVarying(columnFamilies, APPEND_KEY, value);
174   }
175 
176 
177   /**
178    * Update the metrics associated with
179    * {@link HTable#incrementColumnValue(byte[], byte[], byte[], long)}
180    * 
181    * @param columnFamily
182    *          The single column family associated with an ICV
183    * @param value
184    *          the time
185    */
186   public void updateIncrementColumnValueMetrics(byte[] columnFamily, long value) {
187     String cfMetricPrefix =
188         SchemaMetrics.generateSchemaMetricsPrefix(this.tableName, Bytes.toString(columnFamily));
189     doSafeIncTimeVarying(cfMetricPrefix, ICV_KEY, value);
190     doSafeIncTimeVarying(this.regionMetrixPrefix, ICV_KEY, value);
191   }
192 
193   /**
194    * update metrics associated with a {@link Put}
195    * 
196    * @param columnFamilies
197    *          Set of column families involved.
198    * @param value
199    *          the time.
200    */
201   public void updatePutMetrics(Set<byte[]> columnFamilies, long value) {
202     doUpdateTimeVarying(columnFamilies, PUT_KEY, value);
203   }
204 
205   /**
206    * update metrics associated with a {@link Delete}
207    * 
208    * @param columnFamilies
209    * @param value
210    *          the time.
211    */
212   public void updateDeleteMetrics(Set<byte[]> columnFamilies, long value) {
213     doUpdateTimeVarying(columnFamilies, DELETE_KEY, value);
214   }
215   
216 
217 
218   /**
219    * This deletes all old non-persistent metrics this instance has ever created or updated.
220    * for persistent metrics, only delete for the region to be closed
221    * @param regionEncodedName the region that is to be closed
222    */
223   public void closeMetrics(String regionEncodedName) {
224     RegionMetricsStorage.clear(regionEncodedName);
225   }
226 
227   /**
228    * Method to send updates for cf and region metrics. This is the normal method
229    * used if the naming of stats and CF's are in line with put/delete/multiput.
230    * 
231    * @param columnFamilies
232    *          the set of column families involved.
233    * @param key
234    *          the metric name.
235    * @param value
236    *          the time.
237    */
238   private void doUpdateTimeVarying(Set<byte[]> columnFamilies, String key, long value) {
239     String cfPrefix = null;
240     if (columnFamilies != null) {
241       cfPrefix = SchemaMetrics.generateSchemaMetricsPrefix(tableName, columnFamilies);
242     } else {
243       cfPrefix = SchemaMetrics.generateSchemaMetricsPrefix(tableName, SchemaMetrics.UNKNOWN);
244     }
245 
246     doSafeIncTimeVarying(cfPrefix, key, value);
247     doSafeIncTimeVarying(this.regionMetrixPrefix, key, value);
248   }
249 
250   private void doSafeIncTimeVarying(String prefix, String key, long value) {
251     if (exposeTimes) {
252       if (prefix != null && !prefix.isEmpty() && key != null && !key.isEmpty()) {
253         String m = prefix + key;
254         RegionMetricsStorage.incrTimeVaryingMetric(m, value);
255       }
256     }
257   }
258 
259 }