View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.apache.hadoop.hbase.regionserver;
20  
21  import java.util.Map;
22  import java.util.concurrent.atomic.AtomicBoolean;
23  import java.util.concurrent.locks.Lock;
24  import java.util.concurrent.locks.ReadWriteLock;
25  import java.util.concurrent.locks.ReentrantReadWriteLock;
26  
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.apache.commons.math.stat.descriptive.DescriptiveStatistics;
30  import org.apache.hadoop.hbase.classification.InterfaceAudience;
31  import org.apache.hadoop.metrics2.MetricsRecordBuilder;
32  import org.apache.hadoop.metrics2.impl.JmxCacheBuster;
33  import org.apache.hadoop.metrics2.lib.DynamicMetricsRegistry;
34  import org.apache.hadoop.metrics2.lib.Interns;
35  import org.apache.hadoop.metrics2.lib.MutableCounterLong;
36  import org.apache.hadoop.metrics2.lib.MutableHistogram;
37  
38  @InterfaceAudience.Private
39  public class MetricsRegionSourceImpl implements MetricsRegionSource {
40  
41    private static final Log LOG = LogFactory.getLog(MetricsRegionSourceImpl.class);
42  
43    private AtomicBoolean closed = new AtomicBoolean(false);
44  
45    // Non-final so that we can null out the wrapper
46    // This is just paranoia. We really really don't want to
47    // leak a whole region by way of keeping the
48    // regionWrapper around too long.
49    private MetricsRegionWrapper regionWrapper;
50  
51    private final MetricsRegionAggregateSourceImpl agg;
52    private final DynamicMetricsRegistry registry;
53  
54    private final String regionNamePrefix;
55    private final String regionPutKey;
56    private final String regionDeleteKey;
57    private final String regionGetKey;
58    private final String regionIncrementKey;
59    private final String regionAppendKey;
60    private final String regionScanNextKey;
61  
62    private final MutableCounterLong regionPut;
63    private final MutableCounterLong regionDelete;
64    private final MutableCounterLong regionIncrement;
65    private final MutableCounterLong regionAppend;
66    private final MutableHistogram regionGet;
67    private final MutableHistogram regionScanNext;
68  
69    public MetricsRegionSourceImpl(MetricsRegionWrapper regionWrapper,
70                                   MetricsRegionAggregateSourceImpl aggregate) {
71      this.regionWrapper = regionWrapper;
72      agg = aggregate;
73      agg.register(this);
74  
75      LOG.debug("Creating new MetricsRegionSourceImpl for table " +
76          regionWrapper.getTableName() + " " + regionWrapper.getRegionName());
77  
78      registry = agg.getMetricsRegistry();
79  
80      regionNamePrefix = "Namespace_" + regionWrapper.getNamespace() +
81          "_table_" + regionWrapper.getTableName() +
82          "_region_" + regionWrapper.getRegionName()  +
83          "_metric_";
84  
85      String suffix = "Count";
86  
87      regionPutKey = regionNamePrefix + MetricsRegionServerSource.MUTATE_KEY + suffix;
88      regionPut = registry.getLongCounter(regionPutKey, 0L);
89  
90      regionDeleteKey = regionNamePrefix + MetricsRegionServerSource.DELETE_KEY + suffix;
91      regionDelete = registry.getLongCounter(regionDeleteKey, 0L);
92  
93      regionIncrementKey = regionNamePrefix + MetricsRegionServerSource.INCREMENT_KEY + suffix;
94      regionIncrement = registry.getLongCounter(regionIncrementKey, 0L);
95  
96      regionAppendKey = regionNamePrefix + MetricsRegionServerSource.APPEND_KEY + suffix;
97      regionAppend = registry.getLongCounter(regionAppendKey, 0L);
98  
99      regionGetKey = regionNamePrefix + MetricsRegionServerSource.GET_KEY;
100     regionGet = registry.newHistogram(regionGetKey);
101 
102     regionScanNextKey = regionNamePrefix + MetricsRegionServerSource.SCAN_NEXT_KEY;
103     regionScanNext = registry.newHistogram(regionScanNextKey);
104   }
105 
106   @Override
107   public void close() {
108     boolean wasClosed = closed.getAndSet(true);
109 
110     // Has someone else already closed this for us?
111     if (wasClosed) {
112       return;
113     }
114 
115     // Before removing the metrics remove this region from the aggregate region bean.
116     // This should mean that it's unlikely that snapshot and close happen at the same time.
117     agg.deregister(this);
118 
119     // While it's un-likely that snapshot and close happen at the same time it's still possible.
120     // So grab the lock to ensure that all calls to snapshot are done before we remove the metrics
121     synchronized (this) {
122       if (LOG.isTraceEnabled()) {
123         LOG.trace("Removing region Metrics: " + regionWrapper.getRegionName());
124       }
125 
126       registry.removeMetric(regionPutKey);
127       registry.removeMetric(regionDeleteKey);
128       registry.removeMetric(regionIncrementKey);
129       registry.removeMetric(regionAppendKey);
130       registry.removeMetric(regionGetKey);
131       registry.removeMetric(regionScanNextKey);
132       registry.removeHistogramMetrics(regionGetKey);
133       registry.removeHistogramMetrics(regionScanNextKey);
134 
135       regionWrapper = null;
136     }
137   }
138 
139   @Override
140   public void updatePut() {
141     regionPut.incr();
142   }
143 
144   @Override
145   public void updateDelete() {
146     regionDelete.incr();
147   }
148 
149   @Override
150   public void updateGet(long getSize) {
151     regionGet.add(getSize);
152   }
153 
154   @Override
155   public void updateScan(long scanSize) {
156     regionScanNext.add(scanSize);
157   }
158 
159   @Override
160   public void updateIncrement() {
161     regionIncrement.incr();
162   }
163 
164   @Override
165   public void updateAppend() {
166     regionAppend.incr();
167   }
168 
169   @Override
170   public MetricsRegionAggregateSource getAggregateSource() {
171     return agg;
172   }
173 
174   @Override
175   public int compareTo(MetricsRegionSource source) {
176     if (!(source instanceof MetricsRegionSourceImpl))
177       return -1;
178 
179     MetricsRegionSourceImpl impl = (MetricsRegionSourceImpl) source;
180     return this.regionWrapper.getRegionName()
181         .compareTo(impl.regionWrapper.getRegionName());
182   }
183 
184   void snapshot(MetricsRecordBuilder mrb, boolean ignored) {
185 
186     // If there is a close that started be double extra sure
187     // that we're not getting any locks and not putting data
188     // into the metrics that should be removed. So early out
189     // before even getting the lock.
190     if (closed.get()) {
191       return;
192     }
193 
194     // Grab the read
195     // This ensures that removes of the metrics
196     // can't happen while we are putting them back in.
197     synchronized (this) {
198 
199       // It's possible that a close happened between checking
200       // the closed variable and getting the lock.
201       if (closed.get()) {
202         return;
203       }
204 
205       mrb.addGauge(
206           Interns.info(regionNamePrefix + MetricsRegionServerSource.STORE_COUNT,
207               MetricsRegionServerSource.STORE_COUNT_DESC),
208           this.regionWrapper.getNumStores());
209       mrb.addGauge(Interns.info(regionNamePrefix + MetricsRegionServerSource.STOREFILE_COUNT,
210               MetricsRegionServerSource.STOREFILE_COUNT_DESC),
211           this.regionWrapper.getNumStoreFiles());
212       mrb.addGauge(Interns.info(regionNamePrefix + MetricsRegionServerSource.MEMSTORE_SIZE,
213               MetricsRegionServerSource.MEMSTORE_SIZE_DESC),
214           this.regionWrapper.getMemstoreSize());
215       mrb.addGauge(Interns.info(regionNamePrefix + MetricsRegionServerSource.STOREFILE_SIZE,
216               MetricsRegionServerSource.STOREFILE_SIZE_DESC),
217           this.regionWrapper.getStoreFileSize());
218       mrb.addCounter(Interns.info(regionNamePrefix + MetricsRegionSource.COMPACTIONS_COMPLETED_COUNT,
219               MetricsRegionSource.COMPACTIONS_COMPLETED_DESC),
220           this.regionWrapper.getNumCompactionsCompleted());
221       mrb.addCounter(Interns.info(regionNamePrefix + MetricsRegionSource.NUM_BYTES_COMPACTED_COUNT,
222               MetricsRegionSource.NUM_BYTES_COMPACTED_DESC),
223           this.regionWrapper.getNumBytesCompacted());
224       mrb.addCounter(Interns.info(regionNamePrefix + MetricsRegionSource.NUM_FILES_COMPACTED_COUNT,
225               MetricsRegionSource.NUM_FILES_COMPACTED_DESC),
226           this.regionWrapper.getNumFilesCompacted());
227       mrb.addCounter(Interns.info(regionNamePrefix + MetricsRegionServerSource.READ_REQUEST_COUNT,
228               MetricsRegionServerSource.READ_REQUEST_COUNT_DESC),
229           this.regionWrapper.getReadRequestCount());
230       mrb.addCounter(Interns.info(regionNamePrefix + MetricsRegionServerSource.WRITE_REQUEST_COUNT,
231               MetricsRegionServerSource.WRITE_REQUEST_COUNT_DESC),
232           this.regionWrapper.getWriteRequestCount());
233 
234       for (Map.Entry<String, DescriptiveStatistics> entry : this.regionWrapper
235           .getCoprocessorExecutionStatistics()
236           .entrySet()) {
237         DescriptiveStatistics ds = entry.getValue();
238         mrb.addGauge(Interns.info(regionNamePrefix + " " + entry.getKey() + " "
239                     + MetricsRegionSource.COPROCESSOR_EXECUTION_STATISTICS,
240                 MetricsRegionSource.COPROCESSOR_EXECUTION_STATISTICS_DESC + "Min: "),
241             ds.getMin() / 1000);
242         mrb.addGauge(Interns.info(regionNamePrefix + " " + entry.getKey() + " "
243                     + MetricsRegionSource.COPROCESSOR_EXECUTION_STATISTICS,
244                 MetricsRegionSource.COPROCESSOR_EXECUTION_STATISTICS_DESC + "Mean: "),
245             ds.getMean() / 1000);
246         mrb.addGauge(Interns.info(regionNamePrefix + " " + entry.getKey() + " "
247                     + MetricsRegionSource.COPROCESSOR_EXECUTION_STATISTICS,
248                 MetricsRegionSource.COPROCESSOR_EXECUTION_STATISTICS_DESC + "Max: "),
249             ds.getMax() / 1000);
250         mrb.addGauge(Interns.info(regionNamePrefix + " " + entry.getKey() + " "
251                 + MetricsRegionSource.COPROCESSOR_EXECUTION_STATISTICS,
252             MetricsRegionSource.COPROCESSOR_EXECUTION_STATISTICS_DESC + "90th percentile: "), ds
253             .getPercentile(90d) / 1000);
254         mrb.addGauge(Interns.info(regionNamePrefix + " " + entry.getKey() + " "
255                 + MetricsRegionSource.COPROCESSOR_EXECUTION_STATISTICS,
256             MetricsRegionSource.COPROCESSOR_EXECUTION_STATISTICS_DESC + "95th percentile: "), ds
257             .getPercentile(95d) / 1000);
258         mrb.addGauge(Interns.info(regionNamePrefix + " " + entry.getKey() + " "
259                 + MetricsRegionSource.COPROCESSOR_EXECUTION_STATISTICS,
260             MetricsRegionSource.COPROCESSOR_EXECUTION_STATISTICS_DESC + "99th percentile: "), ds
261             .getPercentile(99d) / 1000);
262       }
263     }
264   }
265 
266   @Override
267   public int hashCode() {
268     return regionWrapper.getRegionHashCode();
269   }
270 
271   @Override
272   public boolean equals(Object obj) {
273     if (obj == this) return true;
274     return obj instanceof MetricsRegionSourceImpl && compareTo((MetricsRegionSourceImpl) obj) == 0;
275   }
276 }