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.concurrent.atomic.AtomicBoolean;
22  
23  import org.apache.commons.logging.Log;
24  import org.apache.commons.logging.LogFactory;
25  import org.apache.hadoop.hbase.classification.InterfaceAudience;
26  import org.apache.hadoop.hbase.metrics.Interns;
27  import org.apache.hadoop.metrics2.MetricsRecordBuilder;
28  import org.apache.hadoop.metrics2.lib.DynamicMetricsRegistry;
29  import org.apache.hadoop.metrics2.lib.MutableFastCounter;
30  
31  @InterfaceAudience.Private
32  public class MetricsRegionSourceImpl implements MetricsRegionSource {
33  
34    private static final Log LOG = LogFactory.getLog(MetricsRegionSourceImpl.class);
35  
36    private AtomicBoolean closed = new AtomicBoolean(false);
37  
38    // Non-final so that we can null out the wrapper
39    // This is just paranoia. We really really don't want to
40    // leak a whole region by way of keeping the
41    // regionWrapper around too long.
42    private MetricsRegionWrapper regionWrapper;
43  
44    private final MetricsRegionAggregateSourceImpl agg;
45    private final DynamicMetricsRegistry registry;
46  
47    private final String regionNamePrefix;
48    private final String regionPutKey;
49    private final String regionDeleteKey;
50    private final String regionGetKey;
51    private final String regionIncrementKey;
52    private final String regionAppendKey;
53    private final String regionScanKey;
54  
55    /*
56     * Implementation note: Do not put histograms per region. With hundreds of regions in a server
57     * histograms allocate too many counters. See HBASE-17016.
58     */
59    private final MutableFastCounter regionPut;
60    private final MutableFastCounter regionDelete;
61    private final MutableFastCounter regionIncrement;
62    private final MutableFastCounter regionAppend;
63    private final MutableFastCounter regionGet;
64    private final MutableFastCounter regionScan;
65  
66    private final int hashCode;
67  
68    public MetricsRegionSourceImpl(MetricsRegionWrapper regionWrapper,
69                                   MetricsRegionAggregateSourceImpl aggregate) {
70      this.regionWrapper = regionWrapper;
71      agg = aggregate;
72      agg.register(this);
73  
74      LOG.debug("Creating new MetricsRegionSourceImpl for table " +
75          regionWrapper.getTableName() + " " + regionWrapper.getRegionName());
76  
77      registry = agg.getMetricsRegistry();
78  
79      regionNamePrefix = "Namespace_" + regionWrapper.getNamespace() +
80          "_table_" + regionWrapper.getTableName() +
81          "_region_" + regionWrapper.getRegionName()  +
82          "_metric_";
83  
84      String suffix = "Count";
85  
86      regionPutKey = regionNamePrefix + MetricsRegionServerSource.MUTATE_KEY + suffix;
87      regionPut = registry.getCounter(regionPutKey, 0L);
88  
89      regionDeleteKey = regionNamePrefix + MetricsRegionServerSource.DELETE_KEY + suffix;
90      regionDelete = registry.getCounter(regionDeleteKey, 0L);
91  
92      regionIncrementKey = regionNamePrefix + MetricsRegionServerSource.INCREMENT_KEY + suffix;
93      regionIncrement = registry.getCounter(regionIncrementKey, 0L);
94  
95      regionAppendKey = regionNamePrefix + MetricsRegionServerSource.APPEND_KEY + suffix;
96      regionAppend = registry.getCounter(regionAppendKey, 0L);
97  
98      regionGetKey = regionNamePrefix + MetricsRegionServerSource.GET_KEY + suffix;
99      regionGet = registry.getCounter(regionGetKey, 0L);
100 
101     regionScanKey = regionNamePrefix + MetricsRegionServerSource.SCAN_KEY + suffix;
102     regionScan = registry.getCounter(regionScanKey, 0L);
103 
104     hashCode = regionWrapper.getRegionHashCode();
105   }
106 
107   @Override
108   public void close() {
109     boolean wasClosed = closed.getAndSet(true);
110 
111     // Has someone else already closed this for us?
112     if (wasClosed) {
113       return;
114     }
115 
116     // Before removing the metrics remove this region from the aggregate region bean.
117     // This should mean that it's unlikely that snapshot and close happen at the same time.
118     agg.deregister(this);
119 
120     // While it's un-likely that snapshot and close happen at the same time it's still possible.
121     // So grab the lock to ensure that all calls to snapshot are done before we remove the metrics
122     synchronized (this) {
123       if (LOG.isTraceEnabled()) {
124         LOG.trace("Removing region Metrics: " + regionWrapper.getRegionName());
125       }
126 
127       registry.removeMetric(regionPutKey);
128       registry.removeMetric(regionDeleteKey);
129       registry.removeMetric(regionIncrementKey);
130       registry.removeMetric(regionAppendKey);
131       registry.removeMetric(regionGetKey);
132       registry.removeMetric(regionScanKey);
133 
134       regionWrapper = null;
135     }
136   }
137 
138   @Override
139   public void updatePut() {
140     regionPut.incr();
141   }
142 
143   @Override
144   public void updateDelete() {
145     regionDelete.incr();
146   }
147 
148   @Override
149   public void updateGet(long mills) {
150     regionGet.incr();
151   }
152 
153   @Override
154   public void updateScanTime(long mills) {
155     regionScan.incr();
156   }
157 
158   @Override
159   public void updateIncrement() {
160     regionIncrement.incr();
161   }
162 
163   @Override
164   public void updateAppend() {
165     regionAppend.incr();
166   }
167 
168   @Override
169   public MetricsRegionAggregateSource getAggregateSource() {
170     return agg;
171   }
172 
173   @Override
174   public int compareTo(MetricsRegionSource source) {
175     if (!(source instanceof MetricsRegionSourceImpl)) {
176       return -1;
177     }
178 
179     MetricsRegionSourceImpl impl = (MetricsRegionSourceImpl) source;
180     if (impl == null) {
181       return -1;
182     }
183 
184     return Long.compare(hashCode, impl.hashCode);
185   }
186 
187   void snapshot(MetricsRecordBuilder mrb, boolean ignored) {
188 
189     // If there is a close that started be double extra sure
190     // that we're not getting any locks and not putting data
191     // into the metrics that should be removed. So early out
192     // before even getting the lock.
193     if (closed.get()) {
194       return;
195     }
196 
197     // Grab the read
198     // This ensures that removes of the metrics
199     // can't happen while we are putting them back in.
200     synchronized (this) {
201 
202       // It's possible that a close happened between checking
203       // the closed variable and getting the lock.
204       if (closed.get()) {
205         return;
206       }
207 
208       mrb.addGauge(
209           Interns.info(
210               regionNamePrefix + MetricsRegionServerSource.STORE_COUNT,
211               MetricsRegionServerSource.STORE_COUNT_DESC),
212           this.regionWrapper.getNumStores());
213       mrb.addGauge(Interns.info(
214               regionNamePrefix + MetricsRegionServerSource.STOREFILE_COUNT,
215               MetricsRegionServerSource.STOREFILE_COUNT_DESC),
216           this.regionWrapper.getNumStoreFiles());
217       mrb.addGauge(Interns.info(
218               regionNamePrefix + MetricsRegionServerSource.MEMSTORE_SIZE,
219               MetricsRegionServerSource.MEMSTORE_SIZE_DESC),
220           this.regionWrapper.getMemstoreSize());
221       mrb.addGauge(Interns.info(
222         regionNamePrefix + MetricsRegionServerSource.MAX_STORE_FILE_AGE,
223         MetricsRegionServerSource.MAX_STORE_FILE_AGE_DESC),
224         this.regionWrapper.getMaxStoreFileAge());
225       mrb.addGauge(Interns.info(
226         regionNamePrefix + MetricsRegionServerSource.MIN_STORE_FILE_AGE,
227         MetricsRegionServerSource.MIN_STORE_FILE_AGE_DESC),
228         this.regionWrapper.getMinStoreFileAge());
229       mrb.addGauge(Interns.info(
230         regionNamePrefix + MetricsRegionServerSource.AVG_STORE_FILE_AGE,
231         MetricsRegionServerSource.AVG_STORE_FILE_AGE_DESC),
232         this.regionWrapper.getAvgStoreFileAge());
233       mrb.addGauge(Interns.info(
234         regionNamePrefix + MetricsRegionServerSource.NUM_REFERENCE_FILES,
235         MetricsRegionServerSource.NUM_REFERENCE_FILES_DESC),
236         this.regionWrapper.getNumReferenceFiles());
237       mrb.addGauge(Interns.info(
238               regionNamePrefix + MetricsRegionServerSource.STOREFILE_SIZE,
239               MetricsRegionServerSource.STOREFILE_SIZE_DESC),
240           this.regionWrapper.getStoreFileSize());
241       mrb.addCounter(Interns.info(
242               regionNamePrefix + MetricsRegionSource.COMPACTIONS_COMPLETED_COUNT,
243               MetricsRegionSource.COMPACTIONS_COMPLETED_DESC),
244           this.regionWrapper.getNumCompactionsCompleted());
245       mrb.addCounter(Interns.info(
246           regionNamePrefix + MetricsRegionSource.COMPACTIONS_FAILED_COUNT,
247           MetricsRegionSource.COMPACTIONS_FAILED_DESC),
248           this.regionWrapper.getNumCompactionsFailed());
249       mrb.addCounter(Interns.info(
250               regionNamePrefix + MetricsRegionSource.LAST_MAJOR_COMPACTION_AGE,
251               MetricsRegionSource.LAST_MAJOR_COMPACTION_DESC),
252           this.regionWrapper.getLastMajorCompactionAge());
253       mrb.addCounter(Interns.info(
254               regionNamePrefix + MetricsRegionSource.NUM_BYTES_COMPACTED_COUNT,
255               MetricsRegionSource.NUM_BYTES_COMPACTED_DESC),
256           this.regionWrapper.getNumBytesCompacted());
257       mrb.addCounter(Interns.info(
258               regionNamePrefix + MetricsRegionSource.NUM_FILES_COMPACTED_COUNT,
259               MetricsRegionSource.NUM_FILES_COMPACTED_DESC),
260           this.regionWrapper.getNumFilesCompacted());
261       mrb.addCounter(Interns.info(
262               regionNamePrefix + MetricsRegionServerSource.READ_REQUEST_COUNT,
263               MetricsRegionServerSource.READ_REQUEST_COUNT_DESC),
264           this.regionWrapper.getReadRequestCount());
265       mrb.addCounter(Interns.info(
266               regionNamePrefix + MetricsRegionServerSource.WRITE_REQUEST_COUNT,
267               MetricsRegionServerSource.WRITE_REQUEST_COUNT_DESC),
268           this.regionWrapper.getWriteRequestCount());
269       mrb.addCounter(Interns.info(regionNamePrefix + MetricsRegionSource.REPLICA_ID,
270               MetricsRegionSource.REPLICA_ID_DESC),
271           this.regionWrapper.getReplicaId());
272     }
273   }
274 
275   @Override
276   public int hashCode() {
277     return hashCode;
278   }
279 
280   @Override
281   public boolean equals(Object obj) {
282     return obj == this ||
283         (obj instanceof MetricsRegionSourceImpl && compareTo((MetricsRegionSourceImpl) obj) == 0);
284   }
285 }