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