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 * <p> 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * <p> 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 java.io.IOException; 021import java.util.List; 022 023import org.apache.hadoop.conf.Configuration; 024import org.apache.hadoop.fs.FileStatus; 025import org.apache.hadoop.fs.FileSystem; 026import org.apache.hadoop.fs.Path; 027import org.apache.hadoop.hbase.FailedCloseWALAfterInitializedErrorException; 028import org.apache.hadoop.hbase.HBaseClassTestRule; 029import org.apache.hadoop.hbase.HBaseTestingUtility; 030import org.apache.hadoop.hbase.HRegionInfo; 031import org.apache.hadoop.hbase.ServerName; 032import org.apache.hadoop.hbase.testclassification.MediumTests; 033import org.apache.hadoop.hbase.testclassification.RegionServerTests; 034import org.apache.hadoop.hbase.util.CommonFSUtils; 035import org.apache.hadoop.hbase.wal.FSHLogProvider; 036import org.apache.hadoop.hbase.wal.WALFactory; 037import org.apache.hadoop.hdfs.MiniDFSCluster; 038 039import org.junit.After; 040import org.junit.AfterClass; 041import org.junit.Assert; 042import org.junit.Before; 043import org.junit.BeforeClass; 044import org.junit.ClassRule; 045import org.junit.Rule; 046import org.junit.Test; 047import org.junit.experimental.categories.Category; 048import org.junit.rules.TestName; 049import org.slf4j.Logger; 050import org.slf4j.LoggerFactory; 051 052/** 053 * Test WAL Init ERROR 054 */ 055@Category({RegionServerTests.class, MediumTests.class}) 056public class TestWALOpenError { 057 058 @ClassRule 059 public static final HBaseClassTestRule CLASS_RULE = 060 HBaseClassTestRule.forClass(TestWALOpenError.class); 061 062 private static final Logger LOG = LoggerFactory.getLogger(TestWALOpenError.class); 063 064 protected static Configuration conf; 065 private static MiniDFSCluster cluster; 066 protected final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); 067 protected static Path hbaseDir; 068 protected static Path hbaseWALDir; 069 070 protected FileSystem fs; 071 protected Path dir; 072 protected WALFactory wals; 073 private ServerName currentServername; 074 075 @Rule 076 public final TestName currentTest = new TestName(); 077 078 @Before 079 public void setUp() throws Exception { 080 fs = cluster.getFileSystem(); 081 dir = new Path(hbaseDir, currentTest.getMethodName()); 082 this.currentServername = ServerName.valueOf(currentTest.getMethodName(), 16010, 1); 083 wals = new WALFactory(conf, this.currentServername.toString()); 084 } 085 086 @After 087 public void tearDown() throws Exception { 088 // testAppendClose closes the FileSystem, which will prevent us from closing cleanly here. 089 try { 090 wals.close(); 091 } catch (IOException exception) { 092 LOG.warn("Encountered exception while closing wal factory. If you have other errors, this" + 093 " may be the cause. Message: " + exception); 094 LOG.debug("Exception details for failure to close wal factory.", exception); 095 } 096 FileStatus[] entries = fs.listStatus(new Path("/")); 097 for (FileStatus dir : entries) { 098 fs.delete(dir.getPath(), true); 099 } 100 } 101 102 @BeforeClass 103 public static void setUpBeforeClass() throws Exception { 104 TEST_UTIL.startMiniDFSCluster(3); 105 conf = TEST_UTIL.getConfiguration(); 106 conf.set(WALFactory.WAL_PROVIDER, MyFSWalProvider.class.getName()); 107 conf.set(WALFactory.META_WAL_PROVIDER, MyFSWalProvider.class.getName()); 108 cluster = TEST_UTIL.getDFSCluster(); 109 110 hbaseDir = TEST_UTIL.createRootDir(); 111 hbaseWALDir = TEST_UTIL.createWALRootDir(); 112 } 113 114 @AfterClass 115 public static void tearDownAfterClass() throws Exception { 116 TEST_UTIL.shutdownMiniCluster(); 117 } 118 119 120 private static MyFSLog myFSLogCreated; 121 private static boolean throwExceptionWhenCloseFSLogClose = false; 122 123 @Test 124 public void testWALClosedIfOpenError() throws IOException { 125 126 throwExceptionWhenCloseFSLogClose = false; 127 128 boolean hasFakeInitException = false; 129 try { 130 wals.getWAL(HRegionInfo.FIRST_META_REGIONINFO); 131 } catch (IOException ex) { 132 hasFakeInitException = ex.getMessage().contains("Fake init exception"); 133 } 134 Assert.assertTrue(hasFakeInitException); 135 Assert.assertTrue(myFSLogCreated.closed); 136 137 FileStatus[] fileStatuses = CommonFSUtils.listStatus(fs, myFSLogCreated.walDir); 138 Assert.assertTrue(fileStatuses == null || fileStatuses.length == 0); 139 } 140 141 @Test 142 public void testThrowFailedCloseWalException() throws IOException { 143 throwExceptionWhenCloseFSLogClose = true; 144 boolean failedCloseWalException = false; 145 try { 146 wals.getWAL(HRegionInfo.FIRST_META_REGIONINFO); 147 } catch (FailedCloseWALAfterInitializedErrorException ex) { 148 failedCloseWalException = true; 149 } 150 Assert.assertTrue(failedCloseWalException); 151 } 152 153 154 public static class MyFSWalProvider extends FSHLogProvider { 155 156 @Override 157 protected MyFSLog createWAL() throws IOException { 158 MyFSLog myFSLog = new MyFSLog(CommonFSUtils.getWALFileSystem(conf), 159 CommonFSUtils.getWALRootDir(conf), getWALDirectoryName(factory.getFactoryId()), 160 getWALArchiveDirectoryName(conf, factory.getFactoryId()), conf, listeners, true, logPrefix, 161 META_WAL_PROVIDER_ID.equals(providerId) ? META_WAL_PROVIDER_ID : null); 162 163 myFSLogCreated = myFSLog; 164 165 return myFSLog; 166 } 167 } 168 169 public static class MyFSLog extends FSHLog { 170 public MyFSLog(final FileSystem fs, final Path rootDir, final String logDir, 171 final String archiveDir, final Configuration conf, final List<WALActionsListener> listeners, 172 final boolean failIfWALExists, final String prefix, final String suffix) throws IOException { 173 super(fs, rootDir, logDir, archiveDir, conf, listeners, failIfWALExists, prefix, suffix); 174 } 175 176 @Override 177 public void init() throws IOException { 178 super.init(); 179 throw new IOException("Fake init exception"); 180 } 181 182 @Override 183 public void close() throws IOException { 184 if (throwExceptionWhenCloseFSLogClose) { 185 throw new IOException("Fake close exception"); 186 } 187 super.close(); 188 } 189 } 190}