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