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