View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.apache.hadoop.hbase.replication.regionserver;
20  
21  import java.util.HashMap;
22  import java.util.List;
23  import java.util.Map;
24  import java.util.concurrent.ConcurrentHashMap;
25  import org.apache.hadoop.hbase.CompatibilitySingletonFactory;
26  import org.apache.hadoop.hbase.HBaseInterfaceAudience;
27  import org.apache.hadoop.hbase.classification.InterfaceAudience;
28  import org.apache.hadoop.hbase.metrics.BaseSource;
29  import org.apache.hadoop.hbase.metrics.MetricRegistryInfo;
30  import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
31  import org.apache.hadoop.hbase.util.Pair;
32  import org.apache.hadoop.hbase.wal.WAL.Entry;
33  
34  /**
35   * This class is for maintaining the various replication statistics for a source and publishing them
36   * through the metrics interfaces.
37   */
38  @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.REPLICATION)
39  public class MetricsSource implements BaseSource {
40  
41    // tracks last shipped timestamp for each wal group
42    private Map<String, Long> lastTimestamps = new HashMap<>();
43    private Map<String, Long> ageOfLastShippedOp = new HashMap<>();
44    private long lastHFileRefsQueueSize = 0;
45    private String id;
46  
47    private final MetricsReplicationSourceSource singleSourceSource;
48    private final MetricsReplicationSourceSource globalSourceSource;
49    private Map<String, MetricsReplicationTableSource> singleSourceSourceByTable;
50  
51    /**
52     * Constructor used to register the metrics
53     *
54     * @param id Name of the source this class is monitoring
55     */
56    public MetricsSource(String id) {
57      this.id = id;
58      singleSourceSource =
59          CompatibilitySingletonFactory.getInstance(MetricsReplicationSourceFactory.class)
60              .getSource(id);
61      globalSourceSource = CompatibilitySingletonFactory
62          .getInstance(MetricsReplicationSourceFactory.class).getGlobalSource();
63      singleSourceSourceByTable = new ConcurrentHashMap<>();
64    }
65  
66    /**
67     * Constructor for injecting custom (or test) MetricsReplicationSourceSources
68     * @param id Name of the source this class is monitoring
69     * @param singleSourceSource Class to monitor id-scoped metrics
70     * @param globalSourceSource Class to monitor global-scoped metrics
71     */
72    public MetricsSource(String id, MetricsReplicationSourceSource singleSourceSource,
73                         MetricsReplicationSourceSource globalSourceSource,
74                         Map<String, MetricsReplicationTableSource> singleSourceSourceByTable) {
75      this.id = id;
76      this.singleSourceSource = singleSourceSource;
77      this.globalSourceSource = globalSourceSource;
78      this.singleSourceSourceByTable = singleSourceSourceByTable;
79    }
80  
81    private MetricsReplicationTableSource getSourceForTable(String tableName) {
82      MetricsReplicationTableSource tableSource = singleSourceSourceByTable.get(tableName);
83      if (tableSource == null) {
84        // Not quite Map#computeIfAbsent but we are restricted to what is available in Java 7
85        // for branch-1
86        tableSource = CompatibilitySingletonFactory.getInstance(MetricsReplicationSourceFactory.class)
87            .getTableSource(tableName);
88        MetricsReplicationTableSource otherTableSource =
89          ((ConcurrentHashMap<String, MetricsReplicationTableSource>)singleSourceSourceByTable)
90            .putIfAbsent(tableName, tableSource);
91        if (otherTableSource != null) {
92          tableSource = otherTableSource;
93        }
94      }
95      return tableSource;
96    }
97  
98    /**
99     * Update the table level replication metrics per table
100    *
101    * @param walEntries List of pairs of WAL entry and it's size
102    */
103   public void updateTableLevelMetrics(List<Pair<Entry, Long>> walEntries) {
104     for (Pair<Entry, Long> walEntryWithSize : walEntries) {
105       Entry entry = walEntryWithSize.getFirst();
106       long entrySize = walEntryWithSize.getSecond();
107       String tableName = entry.getKey().getTablename().getNameAsString();
108       long writeTime = entry.getKey().getWriteTime();
109       long age = EnvironmentEdgeManager.currentTime() - writeTime;
110       // get the replication metrics source for table at the run time
111       MetricsReplicationTableSource tableSource = getSourceForTable(tableName);
112       tableSource.setLastShippedAge(age);
113       tableSource.incrShippedBytes(entrySize);
114     }
115   }
116 
117   /**
118    * Set the age of the last edit that was shipped
119    * @param timestamp write time of the edit
120    * @param walGroup which group we are setting
121    */
122   public void setAgeOfLastShippedOp(long timestamp, String walGroup) {
123     long age = EnvironmentEdgeManager.currentTime() - timestamp;
124     singleSourceSource.setLastShippedAge(age);
125     globalSourceSource.setLastShippedAge(age);
126     this.ageOfLastShippedOp.put(walGroup, age);
127     this.lastTimestamps.put(walGroup, timestamp);
128   }
129 
130   /**
131    * Set the age of the last edit that was shipped group by table
132    * @param timestamp write time of the edit
133    * @param tableName String as group and tableName
134    */
135   public void setAgeOfLastShippedOpByTable(long timestamp, String tableName) {
136     getSourceForTable(tableName)
137       .setLastShippedAge(EnvironmentEdgeManager.currentTime() - timestamp);
138   }
139 
140   /**
141    * get the last timestamp of given wal group. If the walGroup is null, return 0.
142    * @param walGroup which group we are getting
143    * @return timeStamp
144    */
145   public long getLastTimeStampOfWalGroup(String walGroup) {
146     return this.lastTimestamps.get(walGroup) == null ? 0 : lastTimestamps.get(walGroup);
147   }
148 
149   /**
150    * get age of last shipped op of given wal group. If the walGroup is null, return 0
151    * @param walGroup which group we are getting
152    * @return age
153    */
154   public long getAgeOfLastShippedOp(String walGroup) {
155     return this.ageOfLastShippedOp.get(walGroup) == null ? 0 : ageOfLastShippedOp.get(walGroup);
156   }
157 
158   /**
159    * Convenience method to use the last given timestamp to refresh the age of the last edit. Used
160    * when replication fails and need to keep that metric accurate.
161    * @param walGroupId id of the group to update
162    */
163   public void refreshAgeOfLastShippedOp(String walGroupId) {
164     Long lastTimestamp = this.lastTimestamps.get(walGroupId);
165     if (lastTimestamp == null) {
166       this.lastTimestamps.put(walGroupId, 0L);
167       lastTimestamp = 0L;
168     }
169     if (lastTimestamp > 0) {
170       setAgeOfLastShippedOp(lastTimestamp, walGroupId);
171     }
172   }
173 
174   /**
175    * Increment size of the log queue.
176    */
177   public void incrSizeOfLogQueue() {
178     singleSourceSource.incrSizeOfLogQueue(1);
179     globalSourceSource.incrSizeOfLogQueue(1);
180   }
181 
182   public void decrSizeOfLogQueue() {
183     singleSourceSource.decrSizeOfLogQueue(1);
184     globalSourceSource.decrSizeOfLogQueue(1);
185   }
186 
187   /**
188    * Increment the count for initializing sources
189    */
190   public void incrSourceInitializing() {
191     singleSourceSource.incrSourceInitializing();
192     globalSourceSource.incrSourceInitializing();
193   }
194 
195   /**
196    * Decrement the count for initializing sources
197    */
198   public void decrSourceInitializing() {
199     singleSourceSource.decrSourceInitializing();
200     globalSourceSource.decrSourceInitializing();
201   }
202 
203   /**
204    * Add on the the number of log edits read
205    *
206    * @param delta the number of log edits read.
207    */
208   private void incrLogEditsRead(long delta) {
209     singleSourceSource.incrLogReadInEdits(delta);
210     globalSourceSource.incrLogReadInEdits(delta);
211   }
212 
213   /** Increment the number of log edits read by one. */
214   public void incrLogEditsRead() {
215     incrLogEditsRead(1);
216   }
217 
218   /**
219    * Add on the number of log edits filtered
220    *
221    * @param delta the number filtered.
222    */
223   public void incrLogEditsFiltered(long delta) {
224     singleSourceSource.incrLogEditsFiltered(delta);
225     globalSourceSource.incrLogEditsFiltered(delta);
226   }
227 
228   /** The number of log edits filtered out. */
229   public void incrLogEditsFiltered() {
230     incrLogEditsFiltered(1);
231   }
232 
233   /**
234    * Convience method to apply changes to metrics do to shipping a batch of logs.
235    *
236    * @param batchSize the size of the batch that was shipped to sinks.
237    */
238   public void shipBatch(long batchSize, int sizeInBytes) {
239     singleSourceSource.incrBatchesShipped(1);
240     globalSourceSource.incrBatchesShipped(1);
241 
242     singleSourceSource.incrOpsShipped(batchSize);
243     globalSourceSource.incrOpsShipped(batchSize);
244 
245     singleSourceSource.incrShippedBytes(sizeInBytes);
246     globalSourceSource.incrShippedBytes(sizeInBytes);
247   }
248 
249   /**
250    * Convience method to apply changes to metrics do to shipping a batch of logs.
251    *
252    * @param batchSize the size of the batch that was shipped to sinks.
253    * @param hfiles total number of hfiles shipped to sinks.
254    */
255   public void shipBatch(long batchSize, int sizeInBytes, long hfiles) {
256     shipBatch(batchSize, sizeInBytes);
257     singleSourceSource.incrHFilesShipped(hfiles);
258     globalSourceSource.incrHFilesShipped(hfiles);
259   }
260 
261   /** increase the byte number read by source from log file */
262   public void incrLogReadInBytes(long readInBytes) {
263     singleSourceSource.incrLogReadInBytes(readInBytes);
264     globalSourceSource.incrLogReadInBytes(readInBytes);
265   }
266 
267   /** Removes all metrics about this Source. */
268   public void clear() {
269     int lastQueueSize = singleSourceSource.getSizeOfLogQueue();
270     globalSourceSource.decrSizeOfLogQueue(lastQueueSize);
271     singleSourceSource.decrSizeOfLogQueue(lastQueueSize);
272     singleSourceSource.clear();
273     globalSourceSource.decrSizeOfHFileRefsQueue(lastHFileRefsQueueSize);
274     lastTimestamps.clear();
275     ageOfLastShippedOp.clear();
276     lastHFileRefsQueueSize = 0;
277   }
278 
279   /**
280    * Get AgeOfLastShippedOp
281    * @return AgeOfLastShippedOp
282    */
283   public Long getAgeOfLastShippedOp() {
284     return singleSourceSource.getLastShippedAge();
285   }
286 
287   /**
288    * Get the sizeOfLogQueue
289    * @return sizeOfLogQueue
290    */
291   public int getSizeOfLogQueue() {
292     return singleSourceSource.getSizeOfLogQueue();
293   }
294 
295   /**
296    * Get the timeStampsOfLastShippedOp, if there are multiple groups, return the latest one
297    * @return lastTimestampForAge
298    */
299   public long getTimeStampOfLastShippedOp() {
300     long lastTimestamp = 0L;
301     for (long ts : lastTimestamps.values()) {
302       if (ts > lastTimestamp) {
303         lastTimestamp = ts;
304       }
305     }
306     return lastTimestamp;
307   }
308 
309 
310   /**
311    * Get the value of uncleanlyClosedWAL counter
312    * @return uncleanlyClosedWAL
313    */
314   public long getUncleanlyClosedWALs() {
315     return singleSourceSource.getUncleanlyClosedWALs();
316   }
317 
318   /**
319    * Get the source initializing counts
320    * @return number of replication sources getting initialized
321    */
322   public int getSourceInitializing() {
323     return singleSourceSource.getSourceInitializing();
324   }
325 
326   /**
327    * Get the slave peer ID
328    * @return peerID
329    */
330   public String getPeerID() {
331     return id;
332   }
333 
334   public void incrSizeOfHFileRefsQueue(long size) {
335     singleSourceSource.incrSizeOfHFileRefsQueue(size);
336     globalSourceSource.incrSizeOfHFileRefsQueue(size);
337     lastHFileRefsQueueSize = size;
338   }
339 
340   public void decrSizeOfHFileRefsQueue(int size) {
341     singleSourceSource.decrSizeOfHFileRefsQueue(size);
342     globalSourceSource.decrSizeOfHFileRefsQueue(size);
343     lastHFileRefsQueueSize -= size;
344     if (lastHFileRefsQueueSize < 0) {
345       lastHFileRefsQueueSize = 0;
346     }
347   }
348 
349   public void incrUnknownFileLengthForClosedWAL() {
350     singleSourceSource.incrUnknownFileLengthForClosedWAL();
351     globalSourceSource.incrUnknownFileLengthForClosedWAL();
352   }
353 
354   public void incrUncleanlyClosedWALs() {
355     singleSourceSource.incrUncleanlyClosedWALs();
356     globalSourceSource.incrUncleanlyClosedWALs();
357   }
358 
359   public void incrBytesSkippedInUncleanlyClosedWALs(final long bytes) {
360     singleSourceSource.incrBytesSkippedInUncleanlyClosedWALs(bytes);
361     globalSourceSource.incrBytesSkippedInUncleanlyClosedWALs(bytes);
362   }
363 
364   public void incrRestartedWALReading() {
365     singleSourceSource.incrRestartedWALReading();
366     globalSourceSource.incrRestartedWALReading();
367   }
368 
369   public void incrRepeatedFileBytes(final long bytes) {
370     singleSourceSource.incrRepeatedFileBytes(bytes);
371     globalSourceSource.incrRepeatedFileBytes(bytes);
372   }
373 
374   public void incrCompletedWAL() {
375     singleSourceSource.incrCompletedWAL();
376     globalSourceSource.incrCompletedWAL();
377   }
378 
379   public void incrCompletedRecoveryQueue() {
380     singleSourceSource.incrCompletedRecoveryQueue();
381     globalSourceSource.incrCompletedRecoveryQueue();
382   }
383 
384   public void incrFailedRecoveryQueue() {
385     globalSourceSource.incrFailedRecoveryQueue();
386   }
387 
388 
389   @Override
390   public void init() {
391     singleSourceSource.init();
392     globalSourceSource.init();
393   }
394 
395   @Override
396   public void setGauge(String gaugeName, long value) {
397     singleSourceSource.setGauge(gaugeName, value);
398     globalSourceSource.setGauge(gaugeName, value);
399   }
400 
401   @Override
402   public void incGauge(String gaugeName, long delta) {
403     singleSourceSource.incGauge(gaugeName, delta);
404     globalSourceSource.incGauge(gaugeName, delta);
405   }
406 
407   @Override
408   public void decGauge(String gaugeName, long delta) {
409     singleSourceSource.decGauge(gaugeName, delta);
410     globalSourceSource.decGauge(gaugeName, delta);
411   }
412 
413   @Override
414   public void removeMetric(String key) {
415     singleSourceSource.removeMetric(key);
416     globalSourceSource.removeMetric(key);
417   }
418 
419   @Override
420   public void incCounters(String counterName, long delta) {
421     singleSourceSource.incCounters(counterName, delta);
422     globalSourceSource.incCounters(counterName, delta);
423   }
424 
425   @Override
426   public void updateHistogram(String name, long value) {
427     singleSourceSource.updateHistogram(name, value);
428     globalSourceSource.updateHistogram(name, value);
429   }
430 
431   /*
432    Sets the age of oldest log file just for source.
433   */
434   public void setOldestWalAge(long age) {
435     singleSourceSource.setOldestWalAge(age);
436   }
437 
438   public long getOldestWalAge() {
439     return singleSourceSource.getOldestWalAge();
440   }
441 
442   @Override
443   public String getMetricsContext() {
444     return globalSourceSource.getMetricsContext();
445   }
446 
447   @Override
448   public String getMetricsDescription() {
449     return globalSourceSource.getMetricsDescription();
450   }
451 
452   @Override
453   public String getMetricsJmxContext() {
454     return globalSourceSource.getMetricsJmxContext();
455   }
456 
457   @Override
458   public String getMetricsName() {
459     return globalSourceSource.getMetricsName();
460   }
461 
462   public Map<String, MetricsReplicationTableSource> getSingleSourceSourceByTable() {
463     return singleSourceSourceByTable;
464   }
465 
466   @Override
467   public MetricRegistryInfo getMetricRegistryInfo() {
468     return new MetricRegistryInfo(getMetricsName(), getMetricsDescription(),
469       getMetricsContext(), getMetricsJmxContext(), true);
470   }
471 }