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