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.wal;
019
020import static org.junit.Assert.assertEquals;
021import static org.mockito.Mockito.mock;
022import static org.mockito.Mockito.times;
023import static org.mockito.Mockito.verify;
024
025import java.util.concurrent.CountDownLatch;
026import java.util.concurrent.TimeUnit;
027import org.apache.hadoop.hbase.HBaseClassTestRule;
028import org.apache.hadoop.hbase.TableName;
029import org.apache.hadoop.hbase.testclassification.MiscTests;
030import org.apache.hadoop.hbase.testclassification.SmallTests;
031import org.apache.hadoop.hbase.wal.WALKey;
032import org.apache.hadoop.hbase.wal.WALKeyImpl;
033import org.apache.hadoop.metrics2.lib.DynamicMetricsRegistry;
034import org.junit.ClassRule;
035import org.junit.Test;
036import org.junit.experimental.categories.Category;
037
038@Category({MiscTests.class, SmallTests.class})
039public class TestMetricsWAL {
040
041  @ClassRule
042  public static final HBaseClassTestRule CLASS_RULE =
043      HBaseClassTestRule.forClass(TestMetricsWAL.class);
044
045  @Test
046  public void testLogRollRequested() throws Exception {
047    MetricsWALSource source = mock(MetricsWALSourceImpl.class);
048    MetricsWAL metricsWAL = new MetricsWAL(source);
049    metricsWAL.logRollRequested(WALActionsListener.RollRequestReason.ERROR);
050    metricsWAL.logRollRequested(WALActionsListener.RollRequestReason.LOW_REPLICATION);
051    metricsWAL.logRollRequested(WALActionsListener.RollRequestReason.SLOW_SYNC);
052    metricsWAL.logRollRequested(WALActionsListener.RollRequestReason.SIZE);
053
054    // Log roll was requested four times
055    verify(source, times(4)).incrementLogRollRequested();
056    // One was because of an IO error.
057    verify(source, times(1)).incrementErrorLogRoll();
058    // One was because of low replication on the hlog.
059    verify(source, times(1)).incrementLowReplicationLogRoll();
060    // One was because of slow sync on the hlog.
061    verify(source, times(1)).incrementSlowSyncLogRoll();
062    // One was because of hlog file length limit.
063    verify(source, times(1)).incrementSizeLogRoll();
064  }
065
066  @Test
067  public void testPostSync() throws Exception {
068    long nanos = TimeUnit.MILLISECONDS.toNanos(145);
069    MetricsWALSource source = mock(MetricsWALSourceImpl.class);
070    MetricsWAL metricsWAL = new MetricsWAL(source);
071    metricsWAL.postSync(nanos, 1);
072    verify(source, times(1)).incrementSyncTime(145);
073  }
074
075  @Test
076  public void testSlowAppend() throws Exception {
077    MetricsWALSource source = new MetricsWALSourceImpl();
078    MetricsWAL metricsWAL = new MetricsWAL(source);
079    TableName tableName = TableName.valueOf("foo");
080    WALKey walKey = new WALKeyImpl(null, tableName, -1);
081    // One not so slow append (< 1000)
082    metricsWAL.postAppend(1, 900, walKey, null);
083    // Two slow appends (> 1000)
084    metricsWAL.postAppend(1, 1010, walKey, null);
085    metricsWAL.postAppend(1, 2000, walKey, null);
086    assertEquals(2, source.getSlowAppendCount());
087  }
088
089  @Test
090  public void testWalWrittenInBytes() throws Exception {
091    MetricsWALSource source = mock(MetricsWALSourceImpl.class);
092    MetricsWAL metricsWAL = new MetricsWAL(source);
093    TableName tableName = TableName.valueOf("foo");
094    WALKey walKey = new WALKeyImpl(null, tableName, -1);
095    metricsWAL.postAppend(100, 900, walKey, null);
096    metricsWAL.postAppend(200, 2000, walKey, null);
097    verify(source, times(1)).incrementWrittenBytes(100);
098    verify(source, times(1)).incrementWrittenBytes(200);
099  }
100
101  @Test
102  public void testPerTableWALMetrics() throws Exception {
103    MetricsWALSourceImpl source = new MetricsWALSourceImpl("foo", "foo", "foo", "foo");
104    final int numThreads = 10;
105    final int numIters = 10;
106    CountDownLatch latch = new CountDownLatch(numThreads);
107    for (int i = 0; i < numThreads; i++) {
108      final TableName tableName = TableName.valueOf("tab_" + i);
109      long size = i;
110      new Thread(() -> {
111        for (int j = 0; j < numIters; j++) {
112          source.incrementAppendCount(tableName);
113          source.incrementAppendSize(tableName, size);
114        }
115        latch.countDown();
116      }).start();
117    }
118    // Wait for threads to finish.
119    latch.await();
120    DynamicMetricsRegistry registry = source.getMetricsRegistry();
121    // Validate the metrics
122    for (int i = 0; i < numThreads; i++) {
123      TableName tableName = TableName.valueOf("tab_" + i);
124      long tableAppendCount =
125          registry.getCounter(tableName + "." + MetricsWALSource.APPEND_COUNT, -1).value();
126      assertEquals(numIters, tableAppendCount);
127      long tableAppendSize =
128          registry.getCounter(tableName + "." + MetricsWALSource.APPEND_SIZE, -1).value();
129      assertEquals(i * numIters, tableAppendSize);
130    }
131  }
132}