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.fs.Path; 028import org.apache.hadoop.hbase.HBaseClassTestRule; 029import org.apache.hadoop.hbase.TableName; 030import org.apache.hadoop.hbase.testclassification.MiscTests; 031import org.apache.hadoop.hbase.testclassification.SmallTests; 032import org.apache.hadoop.hbase.wal.WALKey; 033import org.apache.hadoop.hbase.wal.WALKeyImpl; 034import org.apache.hadoop.metrics2.lib.DynamicMetricsRegistry; 035import org.junit.ClassRule; 036import org.junit.Rule; 037import org.junit.Test; 038import org.junit.experimental.categories.Category; 039import org.junit.rules.TestName; 040 041@Category({ MiscTests.class, SmallTests.class }) 042public class TestMetricsWAL { 043 @Rule 044 public TestName name = new TestName(); 045 046 @ClassRule 047 public static final HBaseClassTestRule CLASS_RULE = 048 HBaseClassTestRule.forClass(TestMetricsWAL.class); 049 050 @Test 051 public void testLogRollRequested() throws Exception { 052 MetricsWALSource source = mock(MetricsWALSourceImpl.class); 053 MetricsWAL metricsWAL = new MetricsWAL(source); 054 metricsWAL.logRollRequested(WALActionsListener.RollRequestReason.ERROR); 055 metricsWAL.logRollRequested(WALActionsListener.RollRequestReason.LOW_REPLICATION); 056 metricsWAL.logRollRequested(WALActionsListener.RollRequestReason.SLOW_SYNC); 057 metricsWAL.logRollRequested(WALActionsListener.RollRequestReason.SIZE); 058 059 // Log roll was requested four times 060 verify(source, times(4)).incrementLogRollRequested(); 061 // One was because of an IO error. 062 verify(source, times(1)).incrementErrorLogRoll(); 063 // One was because of low replication on the hlog. 064 verify(source, times(1)).incrementLowReplicationLogRoll(); 065 // One was because of slow sync on the hlog. 066 verify(source, times(1)).incrementSlowSyncLogRoll(); 067 // One was because of hlog file length limit. 068 verify(source, times(1)).incrementSizeLogRoll(); 069 } 070 071 @Test 072 public void testPostSync() throws Exception { 073 long nanos = TimeUnit.MILLISECONDS.toNanos(145); 074 MetricsWALSource source = mock(MetricsWALSourceImpl.class); 075 MetricsWAL metricsWAL = new MetricsWAL(source); 076 metricsWAL.postSync(nanos, 1); 077 verify(source, times(1)).incrementSyncTime(145); 078 } 079 080 @Test 081 public void testSlowAppend() throws Exception { 082 String testName = name.getMethodName(); 083 MetricsWALSource source = new MetricsWALSourceImpl(testName, testName, testName, testName); 084 MetricsWAL metricsWAL = new MetricsWAL(source); 085 TableName tableName = TableName.valueOf("foo"); 086 WALKey walKey = new WALKeyImpl(null, tableName, -1); 087 // One not so slow append (< 1000) 088 metricsWAL.postAppend(1, 900, walKey, null); 089 // Two slow appends (> 1000) 090 metricsWAL.postAppend(1, 1010, walKey, null); 091 metricsWAL.postAppend(1, 2000, walKey, null); 092 assertEquals(2, source.getSlowAppendCount()); 093 } 094 095 @Test 096 public void testWalWrittenInBytes() throws Exception { 097 MetricsWALSource source = mock(MetricsWALSourceImpl.class); 098 MetricsWAL metricsWAL = new MetricsWAL(source); 099 TableName tableName = TableName.valueOf("foo"); 100 WALKey walKey = new WALKeyImpl(null, tableName, -1); 101 metricsWAL.postAppend(100, 900, walKey, null); 102 metricsWAL.postAppend(200, 2000, walKey, null); 103 verify(source, times(1)).incrementWrittenBytes(100); 104 verify(source, times(1)).incrementWrittenBytes(200); 105 } 106 107 @Test 108 public void testPerTableWALMetrics() throws Exception { 109 MetricsWALSourceImpl source = new MetricsWALSourceImpl("foo", "foo", "foo", "foo"); 110 final int numThreads = 10; 111 final int numIters = 10; 112 CountDownLatch latch = new CountDownLatch(numThreads); 113 for (int i = 0; i < numThreads; i++) { 114 final TableName tableName = TableName.valueOf("tab_" + i); 115 long size = i; 116 new Thread(() -> { 117 for (int j = 0; j < numIters; j++) { 118 source.incrementAppendCount(tableName); 119 source.incrementAppendSize(tableName, size); 120 } 121 latch.countDown(); 122 }).start(); 123 } 124 // Wait for threads to finish. 125 latch.await(); 126 DynamicMetricsRegistry registry = source.getMetricsRegistry(); 127 // Validate the metrics 128 for (int i = 0; i < numThreads; i++) { 129 TableName tableName = TableName.valueOf("tab_" + i); 130 long tableAppendCount = 131 registry.getCounter(tableName + "." + MetricsWALSource.APPEND_COUNT, -1).value(); 132 assertEquals(numIters, tableAppendCount); 133 long tableAppendSize = 134 registry.getCounter(tableName + "." + MetricsWALSource.APPEND_SIZE, -1).value(); 135 assertEquals(i * numIters, tableAppendSize); 136 } 137 } 138 139 @Test 140 public void testLogRolls() { 141 String testName = name.getMethodName(); 142 MetricsWALSource source = new MetricsWALSourceImpl(testName, testName, testName, testName); 143 MetricsWAL metricsWAL = new MetricsWAL(source); 144 Path path1 = new Path("path-1"); 145 int count = 1; 146 // oldPath is null but newPath is not null; 147 metricsWAL.postLogRoll(null, path1); 148 assertEquals(count, source.getSuccessfulLogRolls()); 149 150 // Simulating a case where AbstractFSWAL#replaceWriter fails 151 metricsWAL.postLogRoll(path1, path1); 152 assertEquals(count, source.getSuccessfulLogRolls()); 153 154 count++; 155 Path path2 = new Path("path-2"); 156 metricsWAL.postLogRoll(path1, path2); 157 assertEquals(count, source.getSuccessfulLogRolls()); 158 } 159}