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