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.Assert.assertEquals; 021 022import java.io.IOException; 023import java.io.InterruptedIOException; 024import java.util.Optional; 025import org.apache.hadoop.hbase.HBaseClassTestRule; 026import org.apache.hadoop.hbase.HBaseTestingUtility; 027import org.apache.hadoop.hbase.HColumnDescriptor; 028import org.apache.hadoop.hbase.HConstants; 029import org.apache.hadoop.hbase.HTableDescriptor; 030import org.apache.hadoop.hbase.TableName; 031import org.apache.hadoop.hbase.coprocessor.ObserverContext; 032import org.apache.hadoop.hbase.coprocessor.RegionCoprocessor; 033import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment; 034import org.apache.hadoop.hbase.coprocessor.RegionObserver; 035import org.apache.hadoop.hbase.master.cleaner.TimeToLiveHFileCleaner; 036import org.apache.hadoop.hbase.mob.MobConstants; 037import org.apache.hadoop.hbase.regionserver.FlushLifeCycleTracker; 038import org.apache.hadoop.hbase.snapshot.MobSnapshotTestingUtils; 039import org.apache.hadoop.hbase.snapshot.SnapshotTestingUtils; 040import org.apache.hadoop.hbase.testclassification.ClientTests; 041import org.apache.hadoop.hbase.testclassification.LargeTests; 042import org.apache.hadoop.hbase.util.Bytes; 043import org.junit.BeforeClass; 044import org.junit.ClassRule; 045import org.junit.Rule; 046import org.junit.Test; 047import org.junit.experimental.categories.Category; 048import org.junit.rules.TestName; 049 050/** 051 * Test clone snapshots from the client 052 */ 053@Category({LargeTests.class, ClientTests.class}) 054public class TestMobCloneSnapshotFromClient extends TestCloneSnapshotFromClient { 055 056 @ClassRule 057 public static final HBaseClassTestRule CLASS_RULE = 058 HBaseClassTestRule.forClass(TestMobCloneSnapshotFromClient.class); 059 060 private static boolean delayFlush = false; 061 062 @Rule 063 public TestName name = new TestName(); 064 065 protected static void setupConfiguration() { 066 TestCloneSnapshotFromClient.setupConfiguration(); 067 TEST_UTIL.getConfiguration().setLong(TimeToLiveHFileCleaner.TTL_CONF_KEY, 0); 068 TEST_UTIL.getConfiguration().setInt(MobConstants.MOB_FILE_CACHE_SIZE_KEY, 0); 069 } 070 071 @BeforeClass 072 public static void setUpBeforeClass() throws Exception { 073 setupConfiguration(); 074 TEST_UTIL.startMiniCluster(3); 075 } 076 077 @Override 078 protected void createTableAndSnapshots() throws Exception { 079 // create Table and disable it 080 createMobTable(TEST_UTIL, tableName, SnapshotTestingUtils.getSplitKeys(), getNumReplicas(), 081 FAMILY); 082 delayFlush = false; 083 admin.disableTable(tableName); 084 085 // take an empty snapshot 086 admin.snapshot(emptySnapshot, tableName); 087 088 Connection c = ConnectionFactory.createConnection(TEST_UTIL.getConfiguration()); 089 Table table = c.getTable(tableName); 090 try { 091 // enable table and insert data 092 admin.enableTable(tableName); 093 SnapshotTestingUtils.loadData(TEST_UTIL, tableName, 20, FAMILY); 094 snapshot0Rows = MobSnapshotTestingUtils.countMobRows(table); 095 admin.disableTable(tableName); 096 097 // take a snapshot 098 admin.snapshot(snapshotName0, tableName); 099 100 // enable table and insert more data 101 admin.enableTable(tableName); 102 SnapshotTestingUtils.loadData(TEST_UTIL, tableName, 20, FAMILY); 103 snapshot1Rows = MobSnapshotTestingUtils.countMobRows(table); 104 admin.disableTable(tableName); 105 106 // take a snapshot of the updated table 107 admin.snapshot(snapshotName1, tableName); 108 109 // re-enable table 110 admin.enableTable(tableName); 111 } finally { 112 table.close(); 113 } 114 } 115 116 @Test 117 @Override 118 public void testCloneLinksAfterDelete() throws IOException, InterruptedException { 119 // delay the flush to make sure 120 delayFlush = true; 121 SnapshotTestingUtils.loadData(TEST_UTIL, tableName, 20, FAMILY); 122 long tid = System.currentTimeMillis(); 123 byte[] snapshotName3 = Bytes.toBytes("snaptb3-" + tid); 124 TableName clonedTableName3 = TableName.valueOf(name.getMethodName() + System.currentTimeMillis()); 125 admin.snapshot(snapshotName3, tableName); 126 delayFlush = false; 127 int snapshot3Rows = -1; 128 try (Table table = TEST_UTIL.getConnection().getTable(tableName)) { 129 snapshot3Rows = TEST_UTIL.countRows(table); 130 } 131 admin.cloneSnapshot(snapshotName3, clonedTableName3); 132 admin.deleteSnapshot(snapshotName3); 133 super.testCloneLinksAfterDelete(); 134 verifyRowCount(TEST_UTIL, clonedTableName3, snapshot3Rows); 135 admin.disableTable(clonedTableName3); 136 admin.deleteTable(clonedTableName3); 137 } 138 139 @Override 140 protected void verifyRowCount(final HBaseTestingUtility util, final TableName tableName, 141 long expectedRows) throws IOException { 142 MobSnapshotTestingUtils.verifyMobRowCount(util, tableName, expectedRows); 143 } 144 145 /** 146 * This coprocessor is used to delay the flush. 147 */ 148 public static class DelayFlushCoprocessor implements RegionCoprocessor, RegionObserver { 149 150 @Override 151 public Optional<RegionObserver> getRegionObserver() { 152 return Optional.of(this); 153 } 154 155 @Override 156 public void preFlush(ObserverContext<RegionCoprocessorEnvironment> e, 157 FlushLifeCycleTracker tracker) throws IOException { 158 if (delayFlush) { 159 try { 160 if (Bytes.compareTo(e.getEnvironment().getRegionInfo().getStartKey(), 161 HConstants.EMPTY_START_ROW) != 0) { 162 Thread.sleep(100); 163 } 164 } catch (InterruptedException e1) { 165 throw new InterruptedIOException(e1.getMessage()); 166 } 167 } 168 } 169 } 170 171 private void createMobTable(final HBaseTestingUtility util, final TableName tableName, 172 final byte[][] splitKeys, int regionReplication, final byte[]... families) throws IOException, 173 InterruptedException { 174 HTableDescriptor htd = new HTableDescriptor(tableName); 175 htd.setRegionReplication(regionReplication); 176 htd.addCoprocessor(DelayFlushCoprocessor.class.getName()); 177 for (byte[] family : families) { 178 HColumnDescriptor hcd = new HColumnDescriptor(family); 179 hcd.setMobEnabled(true); 180 hcd.setMobThreshold(0L); 181 htd.addFamily(hcd); 182 } 183 util.getAdmin().createTable(htd, splitKeys); 184 SnapshotTestingUtils.waitForTableToBeOnline(util, tableName); 185 assertEquals((splitKeys.length + 1) * regionReplication, 186 util.getAdmin().getTableRegions(tableName).size()); 187 } 188}