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