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.client; 019 020import static org.junit.jupiter.api.Assertions.assertEquals; 021import static org.junit.jupiter.api.Assertions.assertFalse; 022import static org.junit.jupiter.api.Assertions.assertTrue; 023import static org.junit.jupiter.api.Assertions.fail; 024 025import java.io.IOException; 026import java.util.HashMap; 027import java.util.List; 028import java.util.Map; 029import org.apache.hadoop.conf.Configuration; 030import org.apache.hadoop.hbase.HBaseTestingUtil; 031import org.apache.hadoop.hbase.TableName; 032import org.apache.hadoop.hbase.master.snapshot.SnapshotManager; 033import org.apache.hadoop.hbase.snapshot.SnapshotTTLExpiredException; 034import org.apache.hadoop.hbase.snapshot.SnapshotTestingUtils; 035import org.apache.hadoop.hbase.testclassification.ClientTests; 036import org.apache.hadoop.hbase.testclassification.LargeTests; 037import org.apache.hadoop.hbase.util.Bytes; 038import org.apache.hadoop.hbase.util.Threads; 039import org.junit.jupiter.api.AfterAll; 040import org.junit.jupiter.api.AfterEach; 041import org.junit.jupiter.api.BeforeAll; 042import org.junit.jupiter.api.BeforeEach; 043import org.junit.jupiter.api.Tag; 044import org.junit.jupiter.api.Test; 045import org.slf4j.Logger; 046import org.slf4j.LoggerFactory; 047 048/** 049 * Test restore/clone snapshots with TTL from the client 050 */ 051@Tag(LargeTests.TAG) 052@Tag(ClientTests.TAG) 053public class TestSnapshotWithTTLFromClient { 054 055 private static final Logger LOG = LoggerFactory.getLogger(TestSnapshotWithTTLFromClient.class); 056 057 private static final HBaseTestingUtil UTIL = new HBaseTestingUtil(); 058 private static final int NUM_RS = 2; 059 private static final String STRING_TABLE_NAME = "test"; 060 private static final byte[] TEST_FAM = Bytes.toBytes("fam"); 061 private static final TableName TABLE_NAME = TableName.valueOf(STRING_TABLE_NAME); 062 private static final TableName CLONED_TABLE_NAME = TableName.valueOf("clonedTable"); 063 private static final String TTL_KEY = "TTL"; 064 private static final int CHORE_INTERVAL_SECS = 30; 065 066 /** 067 * Setup the config for the cluster 068 * @throws Exception on failure 069 */ 070 @BeforeAll 071 public static void setupCluster() throws Exception { 072 setupConf(UTIL.getConfiguration()); 073 UTIL.startMiniCluster(NUM_RS); 074 } 075 076 protected static void setupConf(Configuration conf) { 077 // Enable snapshot 078 conf.setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, true); 079 080 // Set this to high value so that cleaner chore is not triggered 081 conf.setInt("hbase.master.cleaner.snapshot.interval", CHORE_INTERVAL_SECS * 60 * 1000); 082 } 083 084 @BeforeEach 085 public void setup() throws Exception { 086 createTable(); 087 } 088 089 protected void createTable() throws Exception { 090 UTIL.createTable(TABLE_NAME, new byte[][] { TEST_FAM }); 091 } 092 093 @AfterEach 094 public void tearDown() throws Exception { 095 UTIL.deleteTableIfAny(TABLE_NAME); 096 UTIL.deleteTableIfAny(CLONED_TABLE_NAME); 097 SnapshotTestingUtils.deleteAllSnapshots(UTIL.getAdmin()); 098 SnapshotTestingUtils.deleteArchiveDirectory(UTIL); 099 } 100 101 @AfterAll 102 public static void cleanupTest() throws Exception { 103 try { 104 UTIL.shutdownMiniCluster(); 105 } catch (Exception e) { 106 LOG.warn("failure shutting down cluster", e); 107 } 108 } 109 110 @Test 111 public void testRestoreSnapshotWithTTLSuccess() throws Exception { 112 String snapshotName = "nonExpiredTTLRestoreSnapshotTest"; 113 114 // table should exist 115 assertTrue(UTIL.getAdmin().tableExists(TABLE_NAME)); 116 117 // create snapshot fo given table with specified ttl 118 createSnapshotWithTTL(TABLE_NAME, snapshotName, CHORE_INTERVAL_SECS * 2); 119 Admin admin = UTIL.getAdmin(); 120 121 // Disable and drop table 122 admin.disableTable(TABLE_NAME); 123 admin.deleteTable(TABLE_NAME); 124 assertFalse(UTIL.getAdmin().tableExists(TABLE_NAME)); 125 126 // restore snapshot 127 admin.restoreSnapshot(snapshotName); 128 129 // table should be created 130 assertTrue(UTIL.getAdmin().tableExists(TABLE_NAME)); 131 } 132 133 @Test 134 public void testRestoreSnapshotFailsDueToTTLExpired() throws Exception { 135 String snapshotName = "expiredTTLRestoreSnapshotTest"; 136 137 // table should exist 138 assertTrue(UTIL.getAdmin().tableExists(TABLE_NAME)); 139 140 // create snapshot fo given table with specified ttl 141 createSnapshotWithTTL(TABLE_NAME, snapshotName, 5); 142 Admin admin = UTIL.getAdmin(); 143 144 // Disable and drop table 145 admin.disableTable(TABLE_NAME); 146 admin.deleteTable(TABLE_NAME); 147 assertFalse(UTIL.getAdmin().tableExists(TABLE_NAME)); 148 149 // Sleep so that TTL may expire 150 Threads.sleep(10000); 151 152 // restore snapshot which has expired 153 try { 154 admin.restoreSnapshot(snapshotName); 155 fail("Restore snapshot succeeded even though TTL has expired."); 156 } catch (SnapshotTTLExpiredException e) { 157 LOG.info("Correctly failed to restore a TTL expired snapshot table:" + e.getMessage()); 158 } 159 160 // table should not be created 161 assertFalse(UTIL.getAdmin().tableExists(TABLE_NAME)); 162 } 163 164 @Test 165 public void testCloneSnapshotWithTTLSuccess() throws Exception { 166 String snapshotName = "nonExpiredTTLCloneSnapshotTest"; 167 168 // table should exist 169 assertTrue(UTIL.getAdmin().tableExists(TABLE_NAME)); 170 171 // create snapshot fo given table with specified ttl 172 createSnapshotWithTTL(TABLE_NAME, snapshotName, CHORE_INTERVAL_SECS * 2); 173 Admin admin = UTIL.getAdmin(); 174 175 // restore snapshot 176 admin.cloneSnapshot(snapshotName, CLONED_TABLE_NAME); 177 178 // table should be created 179 assertTrue(UTIL.getAdmin().tableExists(CLONED_TABLE_NAME)); 180 } 181 182 @Test 183 public void testCloneSnapshotFailsDueToTTLExpired() throws Exception { 184 String snapshotName = "expiredTTLCloneSnapshotTest"; 185 186 // table should exist 187 assertTrue(UTIL.getAdmin().tableExists(TABLE_NAME)); 188 189 // create snapshot fo given table with specified ttl 190 createSnapshotWithTTL(TABLE_NAME, snapshotName, 5); 191 Admin admin = UTIL.getAdmin(); 192 193 assertTrue(UTIL.getAdmin().tableExists(TABLE_NAME)); 194 195 // Sleep so that TTL may expire 196 Threads.sleep(10000); 197 198 // clone snapshot which has expired 199 try { 200 admin.cloneSnapshot(snapshotName, CLONED_TABLE_NAME); 201 fail("Clone snapshot succeeded even though TTL has expired."); 202 } catch (SnapshotTTLExpiredException e) { 203 LOG.info("Correctly failed to clone a TTL expired snapshot table:" + e.getMessage()); 204 } 205 206 // table should not be created 207 assertFalse(UTIL.getAdmin().tableExists(CLONED_TABLE_NAME)); 208 } 209 210 private void createSnapshotWithTTL(TableName tableName, final String snapshotName, 211 final int snapshotTTL) throws IOException { 212 Admin admin = UTIL.getAdmin(); 213 214 // make sure we don't fail on listing snapshots 215 SnapshotTestingUtils.assertNoSnapshots(admin); 216 217 // put some stuff in the table 218 Table table = UTIL.getConnection().getTable(tableName); 219 UTIL.loadTable(table, TEST_FAM); 220 221 Map<String, Object> props = new HashMap<>(); 222 props.put(TTL_KEY, snapshotTTL); 223 224 // take a snapshot of the table 225 SnapshotTestingUtils.snapshot(UTIL.getAdmin(), snapshotName, tableName, SnapshotType.FLUSH, 3, 226 props); 227 LOG.debug("Snapshot completed."); 228 229 // make sure we have the snapshot with expectd TTL 230 List<SnapshotDescription> snapshots = 231 SnapshotTestingUtils.assertOneSnapshotThatMatches(admin, snapshotName, tableName); 232 assertEquals(1, snapshots.size()); 233 assertEquals(snapshotTTL, snapshots.get(0).getTtl()); 234 } 235}