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 java.io.IOException; 021import org.apache.hadoop.conf.Configuration; 022import org.apache.hadoop.hbase.HBaseClassTestRule; 023import org.apache.hadoop.hbase.HBaseTestingUtility; 024import org.apache.hadoop.hbase.HConstants; 025import org.apache.hadoop.hbase.TableName; 026import org.apache.hadoop.hbase.client.Admin; 027import org.apache.hadoop.hbase.client.SnapshotType; 028import org.apache.hadoop.hbase.client.Table; 029import org.apache.hadoop.hbase.master.snapshot.SnapshotManager; 030import org.apache.hadoop.hbase.regionserver.snapshot.RegionServerSnapshotManager; 031import org.apache.hadoop.hbase.testclassification.LargeTests; 032import org.apache.hadoop.hbase.testclassification.RegionServerTests; 033import org.apache.hadoop.hbase.util.Bytes; 034import org.junit.After; 035import org.junit.AfterClass; 036import org.junit.Before; 037import org.junit.BeforeClass; 038import org.junit.ClassRule; 039import org.junit.Test; 040import org.junit.experimental.categories.Category; 041import org.slf4j.Logger; 042import org.slf4j.LoggerFactory; 043 044/** 045 * Test clone/restore snapshots from the client 046 * 047 * TODO This is essentially a clone of TestRestoreSnapshotFromClient. This is worth refactoring 048 * this because there will be a few more flavors of snapshots that need to run these tests. 049 */ 050@Category({RegionServerTests.class, LargeTests.class}) 051public class TestRestoreFlushSnapshotFromClient { 052 053 @ClassRule 054 public static final HBaseClassTestRule CLASS_RULE = 055 HBaseClassTestRule.forClass(TestRestoreFlushSnapshotFromClient.class); 056 057 private static final Logger LOG = 058 LoggerFactory.getLogger(TestRestoreFlushSnapshotFromClient.class); 059 060 protected final static HBaseTestingUtility UTIL = new HBaseTestingUtility(); 061 062 protected final byte[] FAMILY = Bytes.toBytes("cf"); 063 064 protected byte[] snapshotName0; 065 protected byte[] snapshotName1; 066 protected byte[] snapshotName2; 067 protected int snapshot0Rows; 068 protected int snapshot1Rows; 069 protected TableName tableName; 070 protected Admin admin; 071 072 @BeforeClass 073 public static void setupCluster() throws Exception { 074 setupConf(UTIL.getConfiguration()); 075 UTIL.startMiniCluster(3); 076 } 077 078 protected static void setupConf(Configuration conf) { 079 UTIL.getConfiguration().setInt("hbase.regionserver.msginterval", 100); 080 UTIL.getConfiguration().setInt("hbase.client.pause", 250); 081 UTIL.getConfiguration().setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 6); 082 UTIL.getConfiguration().setBoolean( 083 "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 @AfterClass 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 102 * and two snapshots (snapshotName0, snapshotName1) of different states. 103 * The tableName, snapshotNames and the number of rows in the snapshot are initialized. 104 */ 105 @Before 106 public void setup() throws Exception { 107 this.admin = UTIL.getAdmin(); 108 109 long tid = System.currentTimeMillis(); 110 tableName = TableName.valueOf("testtb-" + tid); 111 snapshotName0 = Bytes.toBytes("snaptb0-" + tid); 112 snapshotName1 = Bytes.toBytes("snaptb1-" + tid); 113 snapshotName2 = Bytes.toBytes("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(Bytes.toString(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(Bytes.toString(snapshotName1), tableName, SnapshotType.FLUSH); 137 LOG.info("=== after snapshot with 1000 rows"); 138 logFSTree(); 139 table.close(); 140 } 141 142 @After 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(expected=SnapshotDoesNotExistException.class) 174 public void testCloneNonExistentSnapshot() throws IOException, InterruptedException { 175 String snapshotName = "random-snapshot-" + System.currentTimeMillis(); 176 TableName tableName = TableName.valueOf("random-table-" + System.currentTimeMillis()); 177 admin.cloneSnapshot(snapshotName, tableName); 178 } 179 180 @Test 181 public void testCloneSnapshot() throws IOException, InterruptedException { 182 TableName clonedTableName = TableName.valueOf("clonedtb-" + System.currentTimeMillis()); 183 testCloneSnapshot(clonedTableName, snapshotName0, snapshot0Rows); 184 testCloneSnapshot(clonedTableName, snapshotName1, snapshot1Rows); 185 } 186 187 private void testCloneSnapshot(final TableName tableName, final byte[] snapshotName, 188 int snapshotRows) throws IOException, InterruptedException { 189 // create a new table from snapshot 190 admin.cloneSnapshot(snapshotName, tableName); 191 verifyRowCount(UTIL, tableName, snapshotRows); 192 193 UTIL.deleteTable(tableName); 194 } 195 196 @Test 197 public void testRestoreSnapshotOfCloned() throws IOException, InterruptedException { 198 TableName clonedTableName = TableName.valueOf("clonedtb-" + System.currentTimeMillis()); 199 admin.cloneSnapshot(snapshotName0, clonedTableName); 200 verifyRowCount(UTIL, clonedTableName, snapshot0Rows); 201 admin.snapshot(Bytes.toString(snapshotName2), clonedTableName, SnapshotType.FLUSH); 202 UTIL.deleteTable(clonedTableName); 203 204 admin.cloneSnapshot(snapshotName2, clonedTableName); 205 verifyRowCount(UTIL, clonedTableName, snapshot0Rows); 206 UTIL.deleteTable(clonedTableName); 207 } 208 209 // ========================================================================== 210 // Helpers 211 // ========================================================================== 212 private void logFSTree() throws IOException { 213 UTIL.getMiniHBaseCluster().getMaster().getMasterFileSystem().logFileSystemState(LOG); 214 } 215 216 protected void verifyRowCount(final HBaseTestingUtility util, final TableName tableName, 217 long expectedRows) throws IOException { 218 SnapshotTestingUtils.verifyRowCount(util, tableName, expectedRows); 219 } 220 221 protected int countRows(final Table table, final byte[]... families) throws IOException { 222 return UTIL.countRows(table, families); 223 } 224}