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 */
018package org.apache.hadoop.hbase.regionserver;
019
020import java.io.Closeable;
021import java.io.IOException;
022import java.util.HashMap;
023import java.util.Map;
024import java.util.OptionalDouble;
025import java.util.OptionalLong;
026import java.util.concurrent.ScheduledExecutorService;
027import java.util.concurrent.ScheduledFuture;
028import java.util.concurrent.TimeUnit;
029import org.apache.commons.lang3.mutable.MutableLong;
030import org.apache.hadoop.hbase.CompatibilitySingletonFactory;
031import org.apache.hadoop.hbase.client.RegionInfo;
032import org.apache.hadoop.hbase.client.TableDescriptor;
033import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
034import org.apache.hadoop.metrics2.MetricsExecutor;
035import org.apache.yetus.audience.InterfaceAudience;
036import org.slf4j.Logger;
037import org.slf4j.LoggerFactory;
038
039@InterfaceAudience.Private
040public class MetricsRegionWrapperImpl implements MetricsRegionWrapper, Closeable {
041
042  private static final Logger LOG = LoggerFactory.getLogger(MetricsRegionWrapperImpl.class);
043
044  public static final int PERIOD = 45;
045  public static final String UNKNOWN = "unknown";
046
047  private final HRegion region;
048  private ScheduledExecutorService executor;
049  private Runnable runnable;
050  private long numStoreFiles;
051  private long storeRefCount;
052  private long maxCompactedStoreFileRefCount;
053  private long memstoreSize;
054  private long storeFileSize;
055  private long maxStoreFileAge;
056  private long minStoreFileAge;
057  private long avgStoreFileAge;
058  private long numReferenceFiles;
059  private long maxFlushQueueSize;
060  private long maxCompactionQueueSize;
061  private Map<String, Long> readsOnlyFromMemstore;
062  private Map<String, Long> mixedReadsOnStore;
063
064  private ScheduledFuture<?> regionMetricsUpdateTask;
065
066  private float currentRegionCacheRatio;
067
068  public MetricsRegionWrapperImpl(HRegion region) {
069    this.region = region;
070    this.executor = CompatibilitySingletonFactory.getInstance(MetricsExecutor.class).getExecutor();
071    this.runnable = new HRegionMetricsWrapperRunnable();
072    this.regionMetricsUpdateTask =
073      this.executor.scheduleWithFixedDelay(this.runnable, PERIOD, PERIOD, TimeUnit.SECONDS);
074  }
075
076  @Override
077  public String getTableName() {
078    TableDescriptor tableDesc = this.region.getTableDescriptor();
079    if (tableDesc == null) {
080      return UNKNOWN;
081    }
082    return tableDesc.getTableName().getQualifierAsString();
083  }
084
085  @Override
086  public String getNamespace() {
087    TableDescriptor tableDesc = this.region.getTableDescriptor();
088    if (tableDesc == null) {
089      return UNKNOWN;
090    }
091    return tableDesc.getTableName().getNamespaceAsString();
092  }
093
094  @Override
095  public String getRegionName() {
096    RegionInfo regionInfo = this.region.getRegionInfo();
097    if (regionInfo == null) {
098      return UNKNOWN;
099    }
100    return regionInfo.getEncodedName();
101  }
102
103  @Override
104  public long getNumStores() {
105    Map<byte[], HStore> stores = this.region.stores;
106    if (stores == null) {
107      return 0;
108    }
109    return stores.size();
110  }
111
112  @Override
113  public long getNumStoreFiles() {
114    return numStoreFiles;
115  }
116
117  @Override
118  public long getMemStoreSize() {
119    return memstoreSize;
120  }
121
122  @Override
123  public long getStoreFileSize() {
124    return storeFileSize;
125  }
126
127  public float getCurrentRegionCacheRatio() {
128    return currentRegionCacheRatio;
129  }
130
131  @Override
132  public long getStoreRefCount() {
133    return storeRefCount;
134  }
135
136  @Override
137  public long getMaxCompactedStoreFileRefCount() {
138    return maxCompactedStoreFileRefCount;
139  }
140
141  @Override
142  public long getReadRequestCount() {
143    return this.region.getReadRequestsCount();
144  }
145
146  @Override
147  public long getCpRequestCount() {
148    return this.region.getCpRequestsCount();
149  }
150
151  @Override
152  public long getFilteredReadRequestCount() {
153    return this.region.getFilteredReadRequestsCount();
154  }
155
156  @Override
157  public long getWriteRequestCount() {
158    return this.region.getWriteRequestsCount();
159  }
160
161  @Override
162  public long getNumFilesCompacted() {
163    return this.region.compactionNumFilesCompacted.sum();
164  }
165
166  @Override
167  public long getNumBytesCompacted() {
168    return this.region.compactionNumBytesCompacted.sum();
169  }
170
171  @Override
172  public long getNumCompactionsCompleted() {
173    return this.region.compactionsFinished.sum();
174  }
175
176  @Override
177  public long getLastMajorCompactionAge() {
178    long lastMajorCompactionTs = 0L;
179    try {
180      lastMajorCompactionTs = this.region.getOldestHfileTs(true);
181    } catch (IOException ioe) {
182      LOG.error("Could not load HFile info ", ioe);
183    }
184    long now = EnvironmentEdgeManager.currentTime();
185    return now - lastMajorCompactionTs;
186  }
187
188  @Override
189  public long getTotalRequestCount() {
190    return getReadRequestCount() + getWriteRequestCount();
191  }
192
193  @Override
194  public long getNumCompactionsFailed() {
195    return this.region.compactionsFailed.sum();
196  }
197
198  @Override
199  public long getNumCompactionsQueued() {
200    return this.region.compactionsQueued.sum();
201  }
202
203  @Override
204  public long getNumFlushesQueued() {
205    return this.region.flushesQueued.sum();
206  }
207
208  @Override
209  public long getMaxCompactionQueueSize() {
210    return maxCompactionQueueSize;
211  }
212
213  @Override
214  public long getMaxFlushQueueSize() {
215    return maxFlushQueueSize;
216  }
217
218  @Override
219  public long getMaxStoreFileAge() {
220    return maxStoreFileAge;
221  }
222
223  @Override
224  public long getMinStoreFileAge() {
225    return minStoreFileAge;
226  }
227
228  @Override
229  public long getAvgStoreFileAge() {
230    return avgStoreFileAge;
231  }
232
233  @Override
234  public long getNumReferenceFiles() {
235    return numReferenceFiles;
236  }
237
238  @Override
239  public int getRegionHashCode() {
240    return this.region.hashCode();
241  }
242
243  @Override
244  public Map<String, Long> getMemstoreOnlyRowReadsCount() {
245    return readsOnlyFromMemstore;
246  }
247
248  @Override
249  public Map<String, Long> getMixedRowReadsCount() {
250    return mixedReadsOnStore;
251  }
252
253  public class HRegionMetricsWrapperRunnable implements Runnable {
254
255    @Override
256    public void run() {
257      long tempNumStoreFiles = 0;
258      int tempStoreRefCount = 0;
259      int tempMaxCompactedStoreFileRefCount = 0;
260      long tempMemstoreSize = 0;
261      long tempStoreFileSize = 0;
262      long tempMaxStoreFileAge = 0;
263      long tempMinStoreFileAge = Long.MAX_VALUE;
264      long tempNumReferenceFiles = 0;
265      long tempMaxCompactionQueueSize = 0;
266      long tempMaxFlushQueueSize = 0;
267      long avgAgeNumerator = 0;
268      long numHFiles = 0;
269      if (region.stores != null) {
270        for (HStore store : region.stores.values()) {
271          tempNumStoreFiles += store.getStorefilesCount();
272          int currentStoreRefCount = store.getStoreRefCount();
273          tempStoreRefCount += currentStoreRefCount;
274          int currentMaxCompactedStoreFileRefCount = store.getMaxCompactedStoreFileRefCount();
275          tempMaxCompactedStoreFileRefCount =
276            Math.max(tempMaxCompactedStoreFileRefCount, currentMaxCompactedStoreFileRefCount);
277          tempMemstoreSize += store.getMemStoreSize().getDataSize();
278          tempStoreFileSize += store.getStorefilesSize();
279          OptionalLong storeMaxStoreFileAge = store.getMaxStoreFileAge();
280          if (
281            storeMaxStoreFileAge.isPresent()
282              && storeMaxStoreFileAge.getAsLong() > tempMaxStoreFileAge
283          ) {
284            tempMaxStoreFileAge = storeMaxStoreFileAge.getAsLong();
285          }
286
287          OptionalLong storeMinStoreFileAge = store.getMinStoreFileAge();
288          if (
289            storeMinStoreFileAge.isPresent()
290              && storeMinStoreFileAge.getAsLong() < tempMinStoreFileAge
291          ) {
292            tempMinStoreFileAge = storeMinStoreFileAge.getAsLong();
293          }
294
295          long storeHFiles = store.getNumHFiles();
296          numHFiles += storeHFiles;
297          tempNumReferenceFiles += store.getNumReferenceFiles();
298
299          OptionalDouble storeAvgStoreFileAge = store.getAvgStoreFileAge();
300          if (storeAvgStoreFileAge.isPresent()) {
301            avgAgeNumerator += (long) storeAvgStoreFileAge.getAsDouble() * storeHFiles;
302          }
303          if (mixedReadsOnStore == null) {
304            mixedReadsOnStore = new HashMap<String, Long>();
305          }
306          Long tempVal = mixedReadsOnStore.get(store.getColumnFamilyName());
307          if (tempVal == null) {
308            tempVal = 0L;
309          } else {
310            tempVal += store.getMixedRowReadsCount();
311          }
312          mixedReadsOnStore.put(store.getColumnFamilyName(), tempVal);
313          if (readsOnlyFromMemstore == null) {
314            readsOnlyFromMemstore = new HashMap<String, Long>();
315          }
316          tempVal = readsOnlyFromMemstore.get(store.getColumnFamilyName());
317          if (tempVal == null) {
318            tempVal = 0L;
319          } else {
320            tempVal += store.getMemstoreOnlyRowReadsCount();
321          }
322          readsOnlyFromMemstore.put(store.getColumnFamilyName(), tempVal);
323        }
324      }
325      MutableLong regionCachedAmount = new MutableLong(0);
326      region.getBlockCache().getRegionCachedInfo().ifPresent(regionCacheRatio -> regionCachedAmount
327        .addAndGet(regionCacheRatio.getOrDefault(region.getRegionInfo().getEncodedName(), 0L)));
328      if (tempStoreFileSize > 0) {
329        LOG.debug("Region {}, had cached {} bytes from a total of {}",
330          region.getRegionInfo().getEncodedName(), regionCachedAmount.getValue(),
331          tempStoreFileSize);
332        currentRegionCacheRatio = regionCachedAmount.floatValue() / tempStoreFileSize;
333      }
334      numStoreFiles = tempNumStoreFiles;
335      storeRefCount = tempStoreRefCount;
336      maxCompactedStoreFileRefCount = tempMaxCompactedStoreFileRefCount;
337      memstoreSize = tempMemstoreSize;
338      storeFileSize = tempStoreFileSize;
339      maxStoreFileAge = tempMaxStoreFileAge;
340      if (tempMinStoreFileAge != Long.MAX_VALUE) {
341        minStoreFileAge = tempMinStoreFileAge;
342      }
343
344      if (numHFiles != 0) {
345        avgStoreFileAge = avgAgeNumerator / numHFiles;
346      }
347
348      numReferenceFiles = tempNumReferenceFiles;
349      tempMaxCompactionQueueSize = getNumCompactionsQueued();
350      tempMaxFlushQueueSize = getNumFlushesQueued();
351      if (tempMaxCompactionQueueSize > maxCompactionQueueSize) {
352        maxCompactionQueueSize = tempMaxCompactionQueueSize;
353      }
354      if (tempMaxFlushQueueSize > maxFlushQueueSize) {
355        maxFlushQueueSize = tempMaxFlushQueueSize;
356      }
357    }
358  }
359
360  @Override
361  public void close() throws IOException {
362    regionMetricsUpdateTask.cancel(true);
363  }
364
365  /**
366   * Get the replica id of this region.
367   */
368  @Override
369  public int getReplicaId() {
370    return region.getRegionInfo().getReplicaId();
371  }
372
373}