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.assertTrue; 021import static org.junit.Assert.fail; 022 023import java.io.IOException; 024import java.util.List; 025import org.apache.hadoop.conf.Configuration; 026import org.apache.hadoop.fs.FileSystem; 027import org.apache.hadoop.fs.Path; 028import org.apache.hadoop.hbase.Abortable; 029import org.apache.hadoop.hbase.HBaseClassTestRule; 030import org.apache.hadoop.hbase.HBaseTestingUtility; 031import org.apache.hadoop.hbase.HConstants; 032import org.apache.hadoop.hbase.StartMiniClusterOption; 033import org.apache.hadoop.hbase.TableName; 034import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; 035import org.apache.hadoop.hbase.client.Put; 036import org.apache.hadoop.hbase.client.RegionInfo; 037import org.apache.hadoop.hbase.client.TableDescriptor; 038import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 039import org.apache.hadoop.hbase.io.asyncfs.monitor.StreamSlowMonitor; 040import org.apache.hadoop.hbase.regionserver.HRegion; 041import org.apache.hadoop.hbase.regionserver.HRegionFileSystem; 042import org.apache.hadoop.hbase.regionserver.HRegionServer; 043import org.apache.hadoop.hbase.regionserver.RegionServerServices; 044import org.apache.hadoop.hbase.testclassification.LargeTests; 045import org.apache.hadoop.hbase.testclassification.RegionServerTests; 046import org.apache.hadoop.hbase.util.Bytes; 047import org.apache.hadoop.hbase.util.CommonFSUtils; 048import org.apache.hadoop.hbase.wal.AsyncFSWALProvider; 049import org.apache.hadoop.hbase.wal.WAL; 050import org.apache.hadoop.hbase.wal.WALFactory; 051import org.apache.hadoop.hbase.wal.WALProvider; 052import org.junit.AfterClass; 053import org.junit.BeforeClass; 054import org.junit.ClassRule; 055import org.junit.Test; 056import org.junit.experimental.categories.Category; 057 058import org.apache.hbase.thirdparty.io.netty.channel.Channel; 059import org.apache.hbase.thirdparty.io.netty.channel.EventLoopGroup; 060 061@Category({ RegionServerTests.class, LargeTests.class }) 062public class TestWALSyncTimeoutException { 063 064 @ClassRule 065 public static final HBaseClassTestRule CLASS_RULE = 066 HBaseClassTestRule.forClass(TestWALSyncTimeoutException.class); 067 068 private static final byte[] FAMILY = Bytes.toBytes("family_test"); 069 070 private static final byte[] QUAL = Bytes.toBytes("qualifier_test"); 071 072 private static final HBaseTestingUtility HTU = new HBaseTestingUtility(); 073 074 private static TableName tableName = TableName.valueOf("TestWALSyncTimeoutException"); 075 private static volatile boolean testWALTimout = false; 076 private static final long timeoutMIlliseconds = 3000; 077 private static final String USER_THREAD_NAME = tableName.getNameAsString(); 078 079 @BeforeClass 080 public static void setUp() throws Exception { 081 Configuration conf = HTU.getConfiguration(); 082 conf.setClass(HConstants.REGION_IMPL, HRegionForTest.class, HRegion.class); 083 conf.setClass(WALFactory.WAL_PROVIDER, SlowAsyncFSWALProvider.class, WALProvider.class); 084 conf.setLong(AbstractFSWAL.WAL_SYNC_TIMEOUT_MS, timeoutMIlliseconds); 085 HTU.startMiniCluster(StartMiniClusterOption.builder().numRegionServers(1).build()); 086 087 } 088 089 @AfterClass 090 public static void tearDown() throws Exception { 091 HTU.shutdownMiniCluster(); 092 } 093 094 /** 095 * This test is for HBASE-27230. When {@link WAL#sync} timeout, it would throws 096 * {@link WALSyncTimeoutIOException},and when {@link HRegion#doWALAppend} catches this exception 097 * it aborts the RegionServer. 098 */ 099 @Test 100 public void testWALSyncWriteException() throws Exception { 101 final HRegionForTest region = this.createTable(); 102 103 String oldThreadName = Thread.currentThread().getName(); 104 Thread.currentThread().setName(USER_THREAD_NAME); 105 try { 106 byte[] rowKey1 = Bytes.toBytes(1); 107 byte[] value1 = Bytes.toBytes(3); 108 Thread.sleep(2000); 109 testWALTimout = true; 110 111 /** 112 * The {@link WAL#sync} would timeout and throws {@link WALSyncTimeoutIOException},when 113 * {@link HRegion#doWALAppend} catches this exception it aborts the RegionServer. 114 */ 115 try { 116 region.put(new Put(rowKey1).addColumn(FAMILY, QUAL, value1)); 117 fail(); 118 } catch (WALSyncTimeoutIOException e) { 119 assertTrue(e != null); 120 } 121 assertTrue(region.getRSServices().isAborted()); 122 } finally { 123 Thread.currentThread().setName(oldThreadName); 124 testWALTimout = false; 125 } 126 } 127 128 private HRegionForTest createTable() throws Exception { 129 TableDescriptor tableDescriptor = TableDescriptorBuilder.newBuilder(tableName) 130 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILY)).build(); 131 HTU.getAdmin().createTable(tableDescriptor); 132 HRegionServer rs = HTU.getMiniHBaseCluster().getRegionServer(0); 133 return (HRegionForTest) rs.getRegions(tableName).get(0); 134 } 135 136 public static final class HRegionForTest extends HRegion { 137 138 public HRegionForTest(HRegionFileSystem fs, WAL wal, Configuration confParam, 139 TableDescriptor htd, RegionServerServices rsServices) { 140 super(fs, wal, confParam, htd, rsServices); 141 } 142 143 @SuppressWarnings("deprecation") 144 public HRegionForTest(Path tableDir, WAL wal, FileSystem fs, Configuration confParam, 145 RegionInfo regionInfo, TableDescriptor htd, RegionServerServices rsServices) { 146 super(tableDir, wal, fs, confParam, regionInfo, htd, rsServices); 147 } 148 149 public RegionServerServices getRSServices() { 150 return this.rsServices; 151 } 152 153 } 154 155 public static class SlowAsyncFSWAL extends AsyncFSWAL { 156 157 public SlowAsyncFSWAL(FileSystem fs, Abortable abortable, Path rootDir, String logDir, 158 String archiveDir, Configuration conf, List<WALActionsListener> listeners, 159 boolean failIfWALExists, String prefix, String suffix, EventLoopGroup eventLoopGroup, 160 Class<? extends Channel> channelClass, StreamSlowMonitor monitor) 161 throws FailedLogCloseException, IOException { 162 super(fs, abortable, rootDir, logDir, archiveDir, conf, listeners, failIfWALExists, prefix, 163 suffix, eventLoopGroup, channelClass, monitor); 164 165 } 166 167 public SlowAsyncFSWAL(FileSystem fs, Path rootDir, String logDir, String archiveDir, 168 Configuration conf, List<WALActionsListener> listeners, boolean failIfWALExists, 169 String prefix, String suffix, EventLoopGroup eventLoopGroup, 170 Class<? extends Channel> channelClass) throws FailedLogCloseException, IOException { 171 super(fs, rootDir, logDir, archiveDir, conf, listeners, failIfWALExists, prefix, suffix, 172 eventLoopGroup, channelClass); 173 174 } 175 176 @Override 177 protected void atHeadOfRingBufferEventHandlerAppend() { 178 if (testWALTimout) { 179 try { 180 Thread.sleep(timeoutMIlliseconds + 1000); 181 } catch (InterruptedException e) { 182 throw new RuntimeException(e); 183 } 184 } 185 super.atHeadOfRingBufferEventHandlerAppend(); 186 } 187 188 } 189 190 public static class SlowAsyncFSWALProvider extends AsyncFSWALProvider { 191 192 @Override 193 protected AsyncFSWAL createWAL() throws IOException { 194 return new SlowAsyncFSWAL(CommonFSUtils.getWALFileSystem(conf), this.abortable, 195 CommonFSUtils.getWALRootDir(conf), getWALDirectoryName(factory.getFactoryId()), 196 getWALArchiveDirectoryName(conf, factory.getFactoryId()), conf, listeners, true, logPrefix, 197 META_WAL_PROVIDER_ID.equals(providerId) ? META_WAL_PROVIDER_ID : null, eventLoopGroup, 198 channelClass, factory.getExcludeDatanodeManager().getStreamSlowMonitor(providerId)); 199 } 200 201 } 202}