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.snapshot; 019 020import static org.junit.jupiter.api.Assertions.assertThrows; 021 022import java.io.IOException; 023import org.apache.hadoop.conf.Configuration; 024import org.apache.hadoop.hbase.HBaseTestingUtil; 025import org.apache.hadoop.hbase.HConstants; 026import org.apache.hadoop.hbase.TableName; 027import org.apache.hadoop.hbase.client.Admin; 028import org.apache.hadoop.hbase.client.SnapshotType; 029import org.apache.hadoop.hbase.client.Table; 030import org.apache.hadoop.hbase.master.snapshot.SnapshotManager; 031import org.apache.hadoop.hbase.regionserver.snapshot.RegionServerSnapshotManager; 032import org.apache.hadoop.hbase.testclassification.LargeTests; 033import org.apache.hadoop.hbase.testclassification.RegionServerTests; 034import org.apache.hadoop.hbase.util.Bytes; 035import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 036import org.junit.jupiter.api.AfterAll; 037import org.junit.jupiter.api.AfterEach; 038import org.junit.jupiter.api.BeforeAll; 039import org.junit.jupiter.api.BeforeEach; 040import org.junit.jupiter.api.Tag; 041import org.junit.jupiter.api.Test; 042import org.junit.jupiter.api.TestInfo; 043import org.slf4j.Logger; 044import org.slf4j.LoggerFactory; 045 046/** 047 * Test clone/restore snapshots from the client TODO This is essentially a clone of 048 * TestRestoreSnapshotFromClient. This is worth refactoring this because there will be a few more 049 * flavors of snapshots that need to run these tests. 050 */ 051@Tag(RegionServerTests.TAG) 052@Tag(LargeTests.TAG) 053public class TestRestoreFlushSnapshotFromClient { 054 055 private static final Logger LOG = 056 LoggerFactory.getLogger(TestRestoreFlushSnapshotFromClient.class); 057 058 protected final static HBaseTestingUtil UTIL = new HBaseTestingUtil(); 059 060 protected final byte[] FAMILY = Bytes.toBytes("cf"); 061 062 protected String snapshotName0; 063 protected String snapshotName1; 064 protected String snapshotName2; 065 protected int snapshot0Rows; 066 protected int snapshot1Rows; 067 protected TableName tableName; 068 protected Admin admin; 069 070 @BeforeAll 071 public static void setupCluster(TestInfo testInfo) throws Exception { 072 if (testInfo.getTestClass().orElse(null) != TestRestoreFlushSnapshotFromClient.class) { 073 return; 074 } 075 setupConf(UTIL.getConfiguration()); 076 UTIL.startMiniCluster(3); 077 } 078 079 protected static void setupConf(Configuration conf) { 080 UTIL.getConfiguration().setInt("hbase.regionserver.msginterval", 100); 081 UTIL.getConfiguration().setInt("hbase.client.pause", 250); 082 UTIL.getConfiguration().setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 6); 083 UTIL.getConfiguration().setBoolean("hbase.master.enabletable.roundrobin", true); 084 085 // Enable snapshot 086 UTIL.getConfiguration().setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, true); 087 UTIL.getConfiguration().setLong(RegionServerSnapshotManager.SNAPSHOT_TIMEOUT_MILLIS_KEY, 088 RegionServerSnapshotManager.SNAPSHOT_TIMEOUT_MILLIS_DEFAULT * 2); 089 } 090 091 @AfterAll 092 public static void tearDownAfterClass() throws Exception { 093 UTIL.shutdownMiniCluster(); 094 } 095 096 protected void createTable() throws Exception { 097 SnapshotTestingUtils.createTable(UTIL, tableName, FAMILY); 098 } 099 100 /** 101 * Initialize the tests with a table filled with some data and two snapshots (snapshotName0, 102 * snapshotName1) of different states. The tableName, snapshotNames and the number of rows in the 103 * snapshot are initialized. 104 */ 105 @BeforeEach 106 public void setup() throws Exception { 107 this.admin = UTIL.getAdmin(); 108 109 long tid = EnvironmentEdgeManager.currentTime(); 110 tableName = TableName.valueOf("testtb-" + tid); 111 snapshotName0 = "snaptb0-" + tid; 112 snapshotName1 = "snaptb1-" + tid; 113 snapshotName2 = "snaptb2-" + tid; 114 115 // create Table and disable it 116 createTable(); 117 SnapshotTestingUtils.loadData(UTIL, tableName, 500, FAMILY); 118 Table table = UTIL.getConnection().getTable(tableName); 119 snapshot0Rows = countRows(table); 120 LOG.info("=== before snapshot with 500 rows"); 121 logFSTree(); 122 123 // take a snapshot 124 admin.snapshot(snapshotName0, tableName, SnapshotType.FLUSH); 125 126 LOG.info("=== after snapshot with 500 rows"); 127 logFSTree(); 128 129 // insert more data 130 SnapshotTestingUtils.loadData(UTIL, tableName, 500, FAMILY); 131 snapshot1Rows = countRows(table); 132 LOG.info("=== before snapshot with 1000 rows"); 133 logFSTree(); 134 135 // take a snapshot of the updated table 136 admin.snapshot(snapshotName1, tableName, SnapshotType.FLUSH); 137 LOG.info("=== after snapshot with 1000 rows"); 138 logFSTree(); 139 table.close(); 140 } 141 142 @AfterEach 143 public void tearDown() throws Exception { 144 SnapshotTestingUtils.deleteAllSnapshots(UTIL.getAdmin()); 145 SnapshotTestingUtils.deleteArchiveDirectory(UTIL); 146 } 147 148 @Test 149 public void testTakeFlushSnapshot() throws IOException { 150 // taking happens in setup. 151 } 152 153 @Test 154 public void testRestoreSnapshot() throws IOException { 155 verifyRowCount(UTIL, tableName, snapshot1Rows); 156 157 // Restore from snapshot-0 158 admin.disableTable(tableName); 159 admin.restoreSnapshot(snapshotName0); 160 logFSTree(); 161 admin.enableTable(tableName); 162 LOG.info("=== after restore with 500 row snapshot"); 163 logFSTree(); 164 verifyRowCount(UTIL, tableName, snapshot0Rows); 165 166 // Restore from snapshot-1 167 admin.disableTable(tableName); 168 admin.restoreSnapshot(snapshotName1); 169 admin.enableTable(tableName); 170 verifyRowCount(UTIL, tableName, snapshot1Rows); 171 } 172 173 @Test 174 public void testCloneNonExistentSnapshot() throws IOException, InterruptedException { 175 String snapshotName = "random-snapshot-" + EnvironmentEdgeManager.currentTime(); 176 TableName tableName = TableName.valueOf("random-table-" + EnvironmentEdgeManager.currentTime()); 177 assertThrows(SnapshotDoesNotExistException.class, 178 () -> admin.cloneSnapshot(snapshotName, tableName)); 179 } 180 181 @Test 182 public void testCloneSnapshot() throws IOException, InterruptedException { 183 TableName clonedTableName = 184 TableName.valueOf("clonedtb-" + EnvironmentEdgeManager.currentTime()); 185 testCloneSnapshot(clonedTableName, snapshotName0, snapshot0Rows); 186 testCloneSnapshot(clonedTableName, snapshotName1, snapshot1Rows); 187 } 188 189 private void testCloneSnapshot(final TableName tableName, final String snapshotName, 190 int snapshotRows) throws IOException, InterruptedException { 191 // create a new table from snapshot 192 admin.cloneSnapshot(snapshotName, tableName); 193 verifyRowCount(UTIL, tableName, snapshotRows); 194 195 UTIL.deleteTable(tableName); 196 } 197 198 @Test 199 public void testRestoreSnapshotOfCloned() throws IOException, InterruptedException { 200 TableName clonedTableName = 201 TableName.valueOf("clonedtb-" + EnvironmentEdgeManager.currentTime()); 202 admin.cloneSnapshot(snapshotName0, clonedTableName); 203 verifyRowCount(UTIL, clonedTableName, snapshot0Rows); 204 admin.snapshot(snapshotName2, clonedTableName, SnapshotType.FLUSH); 205 UTIL.deleteTable(clonedTableName); 206 207 admin.cloneSnapshot(snapshotName2, clonedTableName); 208 verifyRowCount(UTIL, clonedTableName, snapshot0Rows); 209 UTIL.deleteTable(clonedTableName); 210 } 211 212 // ========================================================================== 213 // Helpers 214 // ========================================================================== 215 private void logFSTree() throws IOException { 216 UTIL.getMiniHBaseCluster().getMaster().getMasterFileSystem().logFileSystemState(LOG); 217 } 218 219 protected void verifyRowCount(final HBaseTestingUtil util, final TableName tableName, 220 long expectedRows) throws IOException { 221 SnapshotTestingUtils.verifyRowCount(util, tableName, expectedRows); 222 } 223 224 protected int countRows(final Table table, final byte[]... families) throws IOException { 225 return UTIL.countRows(table, families); 226 } 227}