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.master.snapshot; 019 020import static org.junit.Assert.assertFalse; 021import static org.junit.Assert.assertTrue; 022import static org.junit.Assert.fail; 023 024import java.io.IOException; 025import org.apache.hadoop.conf.Configuration; 026import org.apache.hadoop.fs.FileSystem; 027import org.apache.hadoop.fs.Path; 028import org.apache.hadoop.hbase.HBaseClassTestRule; 029import org.apache.hadoop.hbase.HBaseTestingUtility; 030import org.apache.hadoop.hbase.TableName; 031import org.apache.hadoop.hbase.executor.ExecutorService; 032import org.apache.hadoop.hbase.master.MasterFileSystem; 033import org.apache.hadoop.hbase.master.MasterServices; 034import org.apache.hadoop.hbase.master.cleaner.HFileCleaner; 035import org.apache.hadoop.hbase.master.cleaner.HFileLinkCleaner; 036import org.apache.hadoop.hbase.procedure.ProcedureCoordinator; 037import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils; 038import org.apache.hadoop.hbase.testclassification.MasterTests; 039import org.apache.hadoop.hbase.testclassification.SmallTests; 040import org.apache.zookeeper.KeeperException; 041import org.junit.ClassRule; 042import org.junit.Rule; 043import org.junit.Test; 044import org.junit.experimental.categories.Category; 045import org.junit.rules.TestName; 046import org.mockito.Mockito; 047 048/** 049 * Test basic snapshot manager functionality 050 */ 051@Category({MasterTests.class, SmallTests.class}) 052public class TestSnapshotManager { 053 054 @ClassRule 055 public static final HBaseClassTestRule CLASS_RULE = 056 HBaseClassTestRule.forClass(TestSnapshotManager.class); 057 058 private static final HBaseTestingUtility UTIL = new HBaseTestingUtility(); 059 060 @Rule 061 public TestName name = new TestName(); 062 063 MasterServices services = Mockito.mock(MasterServices.class); 064 ProcedureCoordinator coordinator = Mockito.mock(ProcedureCoordinator.class); 065 ExecutorService pool = Mockito.mock(ExecutorService.class); 066 MasterFileSystem mfs = Mockito.mock(MasterFileSystem.class); 067 FileSystem fs; 068 { 069 try { 070 fs = UTIL.getTestFileSystem(); 071 } catch (IOException e) { 072 throw new RuntimeException("Couldn't get test filesystem", e); 073 } 074 } 075 076 private SnapshotManager getNewManager() throws IOException, KeeperException { 077 return getNewManager(UTIL.getConfiguration()); 078 } 079 080 private SnapshotManager getNewManager(Configuration conf) throws IOException, KeeperException { 081 return getNewManager(conf, 1); 082 } 083 084 private SnapshotManager getNewManager(Configuration conf, int intervalSeconds) 085 throws IOException, KeeperException { 086 Mockito.reset(services); 087 Mockito.when(services.getConfiguration()).thenReturn(conf); 088 Mockito.when(services.getMasterFileSystem()).thenReturn(mfs); 089 Mockito.when(mfs.getFileSystem()).thenReturn(fs); 090 Mockito.when(mfs.getRootDir()).thenReturn(UTIL.getDataTestDir()); 091 return new SnapshotManager(services, coordinator, pool, intervalSeconds); 092 } 093 094 @Test 095 public void testCleanFinishedHandler() throws Exception { 096 TableName tableName = TableName.valueOf(name.getMethodName()); 097 Configuration conf = UTIL.getConfiguration(); 098 try { 099 conf.setLong(SnapshotManager.HBASE_SNAPSHOT_SENTINELS_CLEANUP_TIMEOUT_MILLIS, 5 * 1000L); 100 SnapshotManager manager = getNewManager(conf, 1); 101 TakeSnapshotHandler handler = Mockito.mock(TakeSnapshotHandler.class); 102 assertFalse("Manager is in process when there is no current handler", 103 manager.isTakingSnapshot(tableName)); 104 manager.setSnapshotHandlerForTesting(tableName, handler); 105 Mockito.when(handler.isFinished()).thenReturn(false); 106 assertTrue(manager.isTakingAnySnapshot()); 107 assertTrue("Manager isn't in process when handler is running", 108 manager.isTakingSnapshot(tableName)); 109 Mockito.when(handler.isFinished()).thenReturn(true); 110 assertFalse("Manager is process when handler isn't running", 111 manager.isTakingSnapshot(tableName)); 112 assertTrue(manager.isTakingAnySnapshot()); 113 Thread.sleep(6 * 1000); 114 assertFalse(manager.isTakingAnySnapshot()); 115 } finally { 116 conf.unset(SnapshotManager.HBASE_SNAPSHOT_SENTINELS_CLEANUP_TIMEOUT_MILLIS); 117 } 118 } 119 120 @Test 121 public void testInProcess() throws KeeperException, IOException { 122 final TableName tableName = TableName.valueOf(name.getMethodName()); 123 SnapshotManager manager = getNewManager(); 124 TakeSnapshotHandler handler = Mockito.mock(TakeSnapshotHandler.class); 125 assertFalse("Manager is in process when there is no current handler", 126 manager.isTakingSnapshot(tableName)); 127 manager.setSnapshotHandlerForTesting(tableName, handler); 128 Mockito.when(handler.isFinished()).thenReturn(false); 129 assertTrue("Manager isn't in process when handler is running", 130 manager.isTakingSnapshot(tableName)); 131 Mockito.when(handler.isFinished()).thenReturn(true); 132 assertFalse("Manager is process when handler isn't running", 133 manager.isTakingSnapshot(tableName)); 134 } 135 136 /** 137 * Verify the snapshot support based on the configuration. 138 */ 139 @Test 140 public void testSnapshotSupportConfiguration() throws Exception { 141 // No configuration (no cleaners, not enabled): snapshot feature disabled 142 Configuration conf = new Configuration(); 143 SnapshotManager manager = getNewManager(conf); 144 assertFalse("Snapshot should be disabled with no configuration", isSnapshotSupported(manager)); 145 146 // force snapshot feature to be enabled 147 conf = new Configuration(); 148 conf.setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, true); 149 manager = getNewManager(conf); 150 assertTrue("Snapshot should be enabled", isSnapshotSupported(manager)); 151 152 // force snapshot feature to be disabled 153 conf = new Configuration(); 154 conf.setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, false); 155 manager = getNewManager(conf); 156 assertFalse("Snapshot should be disabled", isSnapshotSupported(manager)); 157 158 // force snapshot feature to be disabled, even if cleaners are present 159 conf = new Configuration(); 160 conf.setStrings(HFileCleaner.MASTER_HFILE_CLEANER_PLUGINS, 161 SnapshotHFileCleaner.class.getName(), HFileLinkCleaner.class.getName()); 162 conf.setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, false); 163 manager = getNewManager(conf); 164 assertFalse("Snapshot should be disabled", isSnapshotSupported(manager)); 165 166 // cleaners are present, but missing snapshot enabled property 167 conf = new Configuration(); 168 conf.setStrings(HFileCleaner.MASTER_HFILE_CLEANER_PLUGINS, 169 SnapshotHFileCleaner.class.getName(), HFileLinkCleaner.class.getName()); 170 manager = getNewManager(conf); 171 assertTrue("Snapshot should be enabled, because cleaners are present", 172 isSnapshotSupported(manager)); 173 174 // Create a "test snapshot" 175 Path rootDir = UTIL.getDataTestDir(); 176 Path testSnapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir( 177 "testSnapshotSupportConfiguration", rootDir); 178 fs.mkdirs(testSnapshotDir); 179 try { 180 // force snapshot feature to be disabled, but snapshots are present 181 conf = new Configuration(); 182 conf.setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, false); 183 manager = getNewManager(conf); 184 fail("Master should not start when snapshot is disabled, but snapshots are present"); 185 } catch (UnsupportedOperationException e) { 186 // expected 187 } finally { 188 fs.delete(testSnapshotDir, true); 189 } 190 } 191 192 private boolean isSnapshotSupported(final SnapshotManager manager) { 193 try { 194 manager.checkSnapshotSupport(); 195 return true; 196 } catch (UnsupportedOperationException e) { 197 return false; 198 } 199 } 200}