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.mapreduce; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertFalse; 022import static org.junit.Assert.assertThrows; 023import static org.junit.Assert.assertTrue; 024import static org.junit.Assert.fail; 025 026import java.io.ByteArrayOutputStream; 027import java.io.IOException; 028import java.io.PrintStream; 029import java.util.HashMap; 030import java.util.Map; 031import org.apache.hadoop.hbase.HBaseClassTestRule; 032import org.apache.hadoop.hbase.HBaseTestingUtil; 033import org.apache.hadoop.hbase.TableName; 034import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor; 035import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; 036import org.apache.hadoop.hbase.client.SnapshotDescription; 037import org.apache.hadoop.hbase.client.SnapshotType; 038import org.apache.hadoop.hbase.client.Table; 039import org.apache.hadoop.hbase.client.TableDescriptor; 040import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 041import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils; 042import org.apache.hadoop.hbase.snapshot.SnapshotTTLExpiredException; 043import org.apache.hadoop.hbase.testclassification.LargeTests; 044import org.apache.hadoop.hbase.testclassification.MapReduceTests; 045import org.apache.hadoop.hbase.util.Bytes; 046import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 047import org.apache.hadoop.hbase.util.LauncherSecurityManager; 048import org.junit.AfterClass; 049import org.junit.BeforeClass; 050import org.junit.ClassRule; 051import org.junit.Rule; 052import org.junit.Test; 053import org.junit.experimental.categories.Category; 054import org.junit.rules.TestName; 055 056/** 057 * Basic test for the CopyTable M/R tool 058 */ 059@Category({ MapReduceTests.class, LargeTests.class }) 060public class TestCopyTable extends CopyTableTestBase { 061 062 @ClassRule 063 public static final HBaseClassTestRule CLASS_RULE = 064 HBaseClassTestRule.forClass(TestCopyTable.class); 065 066 private static final HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil(); 067 068 @Rule 069 public TestName name = new TestName(); 070 071 @BeforeClass 072 public static void beforeClass() throws Exception { 073 TEST_UTIL.startMiniCluster(3); 074 } 075 076 @AfterClass 077 public static void afterClass() throws Exception { 078 TEST_UTIL.shutdownMiniCluster(); 079 } 080 081 @Override 082 protected Table createSourceTable(TableDescriptor desc) throws Exception { 083 return TEST_UTIL.createTable(desc, null); 084 } 085 086 @Override 087 protected Table createTargetTable(TableDescriptor desc) throws Exception { 088 return TEST_UTIL.createTable(desc, null); 089 } 090 091 @Override 092 protected void dropSourceTable(TableName tableName) throws Exception { 093 TEST_UTIL.deleteTable(tableName); 094 } 095 096 @Override 097 protected void dropTargetTable(TableName tableName) throws Exception { 098 TEST_UTIL.deleteTable(tableName); 099 } 100 101 @Override 102 protected String[] getPeerClusterOptions() throws Exception { 103 return new String[0]; 104 } 105 106 /** 107 * Simple end-to-end test 108 */ 109 @Test 110 public void testCopyTable() throws Exception { 111 doCopyTableTest(TEST_UTIL.getConfiguration(), false); 112 } 113 114 /** 115 * Simple end-to-end test with bulkload. 116 */ 117 @Test 118 public void testCopyTableWithBulkload() throws Exception { 119 doCopyTableTest(TEST_UTIL.getConfiguration(), true); 120 } 121 122 /** 123 * Simple end-to-end test on table with MOB 124 */ 125 @Test 126 public void testCopyTableWithMob() throws Exception { 127 doCopyTableTestWithMob(TEST_UTIL.getConfiguration(), false); 128 } 129 130 /** 131 * Simple end-to-end test with bulkload on table with MOB. 132 */ 133 @Test 134 public void testCopyTableWithBulkloadWithMob() throws Exception { 135 doCopyTableTestWithMob(TEST_UTIL.getConfiguration(), true); 136 } 137 138 @Test 139 public void testStartStopRow() throws Exception { 140 testStartStopRow(TEST_UTIL.getConfiguration()); 141 } 142 143 /** 144 * Test copy of table from sourceTable to targetTable all rows from family a 145 */ 146 @Test 147 public void testRenameFamily() throws Exception { 148 testRenameFamily(TEST_UTIL.getConfiguration()); 149 } 150 151 /** 152 * Test main method of CopyTable. 153 */ 154 @Test 155 public void testMainMethod() throws Exception { 156 String[] emptyArgs = { "-h" }; 157 PrintStream oldWriter = System.err; 158 ByteArrayOutputStream data = new ByteArrayOutputStream(); 159 PrintStream writer = new PrintStream(data); 160 System.setErr(writer); 161 SecurityManager SECURITY_MANAGER = System.getSecurityManager(); 162 LauncherSecurityManager newSecurityManager = new LauncherSecurityManager(); 163 System.setSecurityManager(newSecurityManager); 164 try { 165 CopyTable.main(emptyArgs); 166 fail("should be exit"); 167 } catch (SecurityException e) { 168 assertEquals(1, newSecurityManager.getExitCode()); 169 } finally { 170 System.setErr(oldWriter); 171 System.setSecurityManager(SECURITY_MANAGER); 172 } 173 assertTrue(data.toString().contains("rs.class")); 174 // should print usage information 175 assertTrue(data.toString().contains("Usage:")); 176 } 177 178 private Table createTable(TableName tableName, byte[] family, boolean isMob) throws IOException { 179 if (isMob) { 180 ColumnFamilyDescriptor cfd = ColumnFamilyDescriptorBuilder.newBuilder(family) 181 .setMobEnabled(true).setMobThreshold(1).build(); 182 TableDescriptor desc = 183 TableDescriptorBuilder.newBuilder(tableName).setColumnFamily(cfd).build(); 184 return TEST_UTIL.createTable(desc, null); 185 } else { 186 return TEST_UTIL.createTable(tableName, family); 187 } 188 } 189 190 private void testCopyTableBySnapshot(String tablePrefix, boolean bulkLoad, boolean isMob) 191 throws Exception { 192 TableName table1 = TableName.valueOf(tablePrefix + 1); 193 TableName table2 = TableName.valueOf(tablePrefix + 2); 194 String snapshot = tablePrefix + "_snapshot"; 195 try (Table t1 = createTable(table1, FAMILY_A, isMob); 196 Table t2 = createTable(table2, FAMILY_A, isMob)) { 197 loadData(t1, FAMILY_A, Bytes.toBytes("qualifier")); 198 TEST_UTIL.getAdmin().snapshot(snapshot, table1); 199 boolean success; 200 if (bulkLoad) { 201 success = runCopy(TEST_UTIL.getConfiguration(), 202 new String[] { "--snapshot", "--new.name=" + table2, "--bulkload", snapshot }); 203 } else { 204 success = runCopy(TEST_UTIL.getConfiguration(), 205 new String[] { "--snapshot", "--new.name=" + table2, snapshot }); 206 } 207 assertTrue(success); 208 verifyRows(t2, FAMILY_A, Bytes.toBytes("qualifier")); 209 } finally { 210 TEST_UTIL.getAdmin().deleteSnapshot(snapshot); 211 TEST_UTIL.deleteTable(table1); 212 TEST_UTIL.deleteTable(table2); 213 } 214 } 215 216 @Test 217 public void testLoadingSnapshotToTable() throws Exception { 218 testCopyTableBySnapshot("testLoadingSnapshotToTable", false, false); 219 } 220 221 @Test 222 public void testLoadingTtlExpiredSnapshotToTable() throws Exception { 223 String tablePrefix = "testLoadingExpiredSnapshotToTable"; 224 TableName table1 = TableName.valueOf(tablePrefix + 1); 225 TableName table2 = TableName.valueOf(tablePrefix + 2); 226 Table t1 = createTable(table1, FAMILY_A, false); 227 createTable(table2, FAMILY_A, false); 228 loadData(t1, FAMILY_A, Bytes.toBytes("qualifier")); 229 String snapshot = tablePrefix + "_snapshot"; 230 Map<String, Object> properties = new HashMap<>(); 231 properties.put("TTL", 10); 232 SnapshotDescription snapshotDescription = new SnapshotDescription(snapshot, table1, 233 SnapshotType.FLUSH, null, EnvironmentEdgeManager.currentTime(), -1, properties); 234 TEST_UTIL.getAdmin().snapshot(snapshotDescription); 235 boolean isExist = 236 TEST_UTIL.getAdmin().listSnapshots().stream().anyMatch(ele -> snapshot.equals(ele.getName())); 237 assertTrue(isExist); 238 int retry = 6; 239 while ( 240 !SnapshotDescriptionUtils.isExpiredSnapshot(snapshotDescription.getTtl(), 241 snapshotDescription.getCreationTime(), EnvironmentEdgeManager.currentTime()) && retry > 0 242 ) { 243 retry--; 244 Thread.sleep(10 * 1000); 245 } 246 boolean isExpiredSnapshot = 247 SnapshotDescriptionUtils.isExpiredSnapshot(snapshotDescription.getTtl(), 248 snapshotDescription.getCreationTime(), EnvironmentEdgeManager.currentTime()); 249 assertTrue(isExpiredSnapshot); 250 String[] args = new String[] { "--snapshot", "--new.name=" + table2, "--bulkload", snapshot }; 251 assertThrows(SnapshotTTLExpiredException.class, 252 () -> runCopy(TEST_UTIL.getConfiguration(), args)); 253 } 254 255 @Test 256 public void tsetLoadingSnapshotToMobTable() throws Exception { 257 testCopyTableBySnapshot("testLoadingSnapshotToMobTable", false, true); 258 } 259 260 @Test 261 public void testLoadingSnapshotAndBulkLoadToTable() throws Exception { 262 testCopyTableBySnapshot("testLoadingSnapshotAndBulkLoadToTable", true, false); 263 } 264 265 @Test 266 public void testLoadingSnapshotAndBulkLoadToMobTable() throws Exception { 267 testCopyTableBySnapshot("testLoadingSnapshotAndBulkLoadToMobTable", true, true); 268 } 269 270 @Test 271 public void testLoadingSnapshotWithoutSnapshotName() throws Exception { 272 assertFalse(runCopy(TEST_UTIL.getConfiguration(), new String[] { "--snapshot" })); 273 } 274 275 @Test 276 public void testLoadingSnapshotWithoutDestTable() throws Exception { 277 assertFalse( 278 runCopy(TEST_UTIL.getConfiguration(), new String[] { "--snapshot", "sourceSnapshotName" })); 279 } 280 281}