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.cleaner; 019 020import java.io.IOException; 021import java.util.ArrayList; 022import java.util.List; 023import org.apache.hadoop.conf.Configuration; 024import org.apache.hadoop.hbase.HBaseClassTestRule; 025import org.apache.hadoop.hbase.HBaseTestingUtility; 026import org.apache.hadoop.hbase.Stoppable; 027import org.apache.hadoop.hbase.master.snapshot.SnapshotManager; 028import org.apache.hadoop.hbase.testclassification.MasterTests; 029import org.apache.hadoop.hbase.testclassification.SmallTests; 030import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 031import org.junit.ClassRule; 032import org.junit.Test; 033import org.junit.experimental.categories.Category; 034import org.mockito.Mockito; 035import org.slf4j.Logger; 036import org.slf4j.LoggerFactory; 037 038import org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos; 039 040/** 041 * Tests for SnapshotsCleanerChore 042 */ 043@Category({ MasterTests.class, SmallTests.class }) 044public class TestSnapshotCleanerChore { 045 046 @ClassRule 047 public static final HBaseClassTestRule CLASS_RULE = 048 HBaseClassTestRule.forClass(TestSnapshotCleanerChore.class); 049 050 private static final Logger LOG = LoggerFactory.getLogger(TestSnapshotCleanerChore.class); 051 052 private static final HBaseTestingUtility HBASE_TESTING_UTILITY = new HBaseTestingUtility(); 053 054 private SnapshotManager snapshotManager; 055 056 private Configuration getSnapshotCleanerConf() { 057 Configuration conf = HBASE_TESTING_UTILITY.getConfiguration(); 058 conf.setInt("hbase.master.cleaner.snapshot.interval", 100); 059 return conf; 060 } 061 062 @Test 063 public void testSnapshotCleanerWithoutAnyCompletedSnapshot() throws IOException { 064 snapshotManager = Mockito.mock(SnapshotManager.class); 065 Stoppable stopper = new StoppableImplementation(); 066 Configuration conf = getSnapshotCleanerConf(); 067 SnapshotCleanerChore snapshotCleanerChore = 068 new SnapshotCleanerChore(stopper, conf, snapshotManager); 069 try { 070 snapshotCleanerChore.chore(); 071 } finally { 072 stopper.stop("Stopping Test Stopper"); 073 } 074 Mockito.verify(snapshotManager, Mockito.times(0)).deleteSnapshot(Mockito.any()); 075 } 076 077 @Test 078 public void testSnapshotCleanerWithNoTtlExpired() throws IOException { 079 snapshotManager = Mockito.mock(SnapshotManager.class); 080 Stoppable stopper = new StoppableImplementation(); 081 Configuration conf = getSnapshotCleanerConf(); 082 SnapshotCleanerChore snapshotCleanerChore = 083 new SnapshotCleanerChore(stopper, conf, snapshotManager); 084 List<SnapshotProtos.SnapshotDescription> snapshotDescriptionList = new ArrayList<>(); 085 snapshotDescriptionList.add(getSnapshotDescription(-2, "snapshot01", "table01", 086 EnvironmentEdgeManager.currentTime() - 100000)); 087 snapshotDescriptionList.add( 088 getSnapshotDescription(10, "snapshot02", "table02", EnvironmentEdgeManager.currentTime())); 089 Mockito.when(snapshotManager.getCompletedSnapshots()).thenReturn(snapshotDescriptionList); 090 try { 091 LOG.info("2 Snapshots are completed but TTL is not expired for any of them"); 092 snapshotCleanerChore.chore(); 093 } finally { 094 stopper.stop("Stopping Test Stopper"); 095 } 096 Mockito.verify(snapshotManager, Mockito.times(0)).deleteSnapshot(Mockito.any()); 097 } 098 099 @Test 100 public void testSnapshotCleanerWithSomeTtlExpired() throws IOException { 101 snapshotManager = Mockito.mock(SnapshotManager.class); 102 Stoppable stopper = new StoppableImplementation(); 103 Configuration conf = getSnapshotCleanerConf(); 104 SnapshotCleanerChore snapshotCleanerChore = 105 new SnapshotCleanerChore(stopper, conf, snapshotManager); 106 List<SnapshotProtos.SnapshotDescription> snapshotDescriptionList = new ArrayList<>(); 107 snapshotDescriptionList.add(getSnapshotDescription(10, "snapshot01", "table01", 1)); 108 snapshotDescriptionList.add(getSnapshotDescription(5, "snapshot02", "table02", 2)); 109 snapshotDescriptionList.add( 110 getSnapshotDescription(30, "snapshot01", "table01", EnvironmentEdgeManager.currentTime())); 111 snapshotDescriptionList.add( 112 getSnapshotDescription(0, "snapshot02", "table02", EnvironmentEdgeManager.currentTime())); 113 snapshotDescriptionList.add( 114 getSnapshotDescription(40, "snapshot03", "table03", EnvironmentEdgeManager.currentTime())); 115 Mockito.when(snapshotManager.getCompletedSnapshots()).thenReturn(snapshotDescriptionList); 116 try { 117 LOG.info("5 Snapshots are completed. TTL is expired for 2 them. Going to delete them"); 118 snapshotCleanerChore.chore(); 119 } finally { 120 stopper.stop("Stopping Test Stopper"); 121 } 122 Mockito.verify(snapshotManager, Mockito.times(2)).deleteSnapshot(Mockito.any()); 123 } 124 125 @Test 126 public void testSnapshotCleanerWithReadIOE() throws IOException { 127 snapshotManager = Mockito.mock(SnapshotManager.class); 128 Stoppable stopper = new StoppableImplementation(); 129 Configuration conf = new HBaseTestingUtility().getConfiguration(); 130 SnapshotCleanerChore snapshotCleanerChore = 131 new SnapshotCleanerChore(stopper, conf, snapshotManager); 132 Mockito.when(snapshotManager.getCompletedSnapshots()).thenThrow(IOException.class); 133 try { 134 LOG.info("While getting completed Snapshots, IOException would occur. Hence, No Snapshot" 135 + " should be deleted"); 136 snapshotCleanerChore.chore(); 137 } finally { 138 stopper.stop("Stopping Test Stopper"); 139 } 140 Mockito.verify(snapshotManager, Mockito.times(0)).deleteSnapshot(Mockito.any()); 141 } 142 143 @Test 144 public void testSnapshotChoreWithTtlOutOfRange() throws IOException { 145 snapshotManager = Mockito.mock(SnapshotManager.class); 146 Stoppable stopper = new StoppableImplementation(); 147 Configuration conf = getSnapshotCleanerConf(); 148 List<SnapshotProtos.SnapshotDescription> snapshotDescriptionList = new ArrayList<>(); 149 snapshotDescriptionList.add(getSnapshotDescription(Long.MAX_VALUE, "snapshot01", "table01", 1)); 150 snapshotDescriptionList.add(getSnapshotDescription(5, "snapshot02", "table02", 2)); 151 Mockito.when(snapshotManager.getCompletedSnapshots()).thenReturn(snapshotDescriptionList); 152 SnapshotCleanerChore snapshotCleanerChore = 153 new SnapshotCleanerChore(stopper, conf, snapshotManager); 154 try { 155 LOG.info("Snapshot Chore is disabled. No cleanup performed for Expired Snapshots"); 156 snapshotCleanerChore.chore(); 157 } finally { 158 stopper.stop("Stopping Test Stopper"); 159 } 160 Mockito.verify(snapshotManager, Mockito.times(1)).getCompletedSnapshots(); 161 } 162 163 private SnapshotProtos.SnapshotDescription getSnapshotDescription(final long ttl, 164 final String snapshotName, final String tableName, final long snapshotCreationTime) { 165 SnapshotProtos.SnapshotDescription.Builder snapshotDescriptionBuilder = 166 SnapshotProtos.SnapshotDescription.newBuilder(); 167 snapshotDescriptionBuilder.setTtl(ttl); 168 snapshotDescriptionBuilder.setName(snapshotName); 169 snapshotDescriptionBuilder.setTable(tableName); 170 snapshotDescriptionBuilder.setType(SnapshotProtos.SnapshotDescription.Type.FLUSH); 171 snapshotDescriptionBuilder.setCreationTime(snapshotCreationTime); 172 return snapshotDescriptionBuilder.build(); 173 } 174 175 /** 176 * Simple helper class that just keeps track of whether or not its stopped. 177 */ 178 private static class StoppableImplementation implements Stoppable { 179 180 private volatile boolean stop = false; 181 182 @Override 183 public void stop(String why) { 184 this.stop = true; 185 } 186 187 @Override 188 public boolean isStopped() { 189 return this.stop; 190 } 191 192 } 193 194}