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; 021import static org.junit.Assert.assertFalse; 022import static org.junit.Assert.assertTrue; 023import static org.junit.Assert.fail; 024 025import java.util.Optional; 026import java.util.Set; 027import org.apache.hadoop.fs.Path; 028import org.apache.hadoop.hbase.HBaseClassTestRule; 029import org.apache.hadoop.hbase.TableName; 030import org.apache.hadoop.hbase.master.MasterFileSystem; 031import org.apache.hadoop.hbase.testclassification.ClientTests; 032import org.apache.hadoop.hbase.testclassification.LargeTests; 033import org.apache.hadoop.hbase.util.Bytes; 034import org.apache.hadoop.hbase.util.CommonFSUtils; 035import org.apache.hadoop.hbase.util.FSTableDescriptors; 036import org.junit.Assert; 037import org.junit.ClassRule; 038import org.junit.Test; 039import org.junit.experimental.categories.Category; 040import org.junit.runner.RunWith; 041import org.junit.runners.Parameterized; 042 043/** 044 * Class to test asynchronous table admin operations 045 * @see TestAsyncTableAdminApi This test and it used to be joined it was taking longer than our 046 * ten minute timeout so they were split. 047 */ 048@RunWith(Parameterized.class) 049@Category({ LargeTests.class, ClientTests.class }) 050public class TestAsyncTableAdminApi2 extends TestAsyncAdminBase { 051 052 @ClassRule 053 public static final HBaseClassTestRule CLASS_RULE = 054 HBaseClassTestRule.forClass(TestAsyncTableAdminApi2.class); 055 056 @Test 057 public void testDisableCatalogTable() throws Exception { 058 try { 059 this.admin.disableTable(TableName.META_TABLE_NAME).join(); 060 fail("Expected to throw ConstraintException"); 061 } catch (Exception e) { 062 } 063 // Before the fix for HBASE-6146, the below table creation was failing as the hbase:meta table 064 // actually getting disabled by the disableTable() call. 065 createTableWithDefaultConf(tableName); 066 } 067 068 @Test 069 public void testAddColumnFamily() throws Exception { 070 // Create a table with two families 071 TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(tableName); 072 builder.setColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILY_0)); 073 admin.createTable(builder.build()).join(); 074 admin.disableTable(tableName).join(); 075 // Verify the table descriptor 076 verifyTableDescriptor(tableName, FAMILY_0); 077 078 // Modify the table removing one family and verify the descriptor 079 admin.addColumnFamily(tableName, ColumnFamilyDescriptorBuilder.of(FAMILY_1)).join(); 080 verifyTableDescriptor(tableName, FAMILY_0, FAMILY_1); 081 } 082 083 @Test 084 public void testAddSameColumnFamilyTwice() throws Exception { 085 // Create a table with one families 086 TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(tableName); 087 builder.setColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILY_0)); 088 admin.createTable(builder.build()).join(); 089 admin.disableTable(tableName).join(); 090 // Verify the table descriptor 091 verifyTableDescriptor(tableName, FAMILY_0); 092 093 // Modify the table removing one family and verify the descriptor 094 admin.addColumnFamily(tableName, ColumnFamilyDescriptorBuilder.of(FAMILY_1)).join(); 095 verifyTableDescriptor(tableName, FAMILY_0, FAMILY_1); 096 097 try { 098 // Add same column family again - expect failure 099 this.admin.addColumnFamily(tableName, ColumnFamilyDescriptorBuilder.of(FAMILY_1)).join(); 100 Assert.fail("Delete a non-exist column family should fail"); 101 } catch (Exception e) { 102 // Expected. 103 } 104 } 105 106 @Test 107 public void testModifyColumnFamily() throws Exception { 108 TableDescriptorBuilder tdBuilder = TableDescriptorBuilder.newBuilder(tableName); 109 ColumnFamilyDescriptor cfd = ColumnFamilyDescriptorBuilder.of(FAMILY_0); 110 int blockSize = cfd.getBlocksize(); 111 admin.createTable(tdBuilder.setColumnFamily(cfd).build()).join(); 112 admin.disableTable(tableName).join(); 113 // Verify the table descriptor 114 verifyTableDescriptor(tableName, FAMILY_0); 115 116 int newBlockSize = 2 * blockSize; 117 cfd = ColumnFamilyDescriptorBuilder.newBuilder(FAMILY_0).setBlocksize(newBlockSize).build(); 118 // Modify colymn family 119 admin.modifyColumnFamily(tableName, cfd).join(); 120 121 TableDescriptor htd = admin.getDescriptor(tableName).get(); 122 ColumnFamilyDescriptor hcfd = htd.getColumnFamily(FAMILY_0); 123 assertTrue(hcfd.getBlocksize() == newBlockSize); 124 } 125 126 @Test 127 public void testModifyNonExistingColumnFamily() throws Exception { 128 TableDescriptorBuilder tdBuilder = TableDescriptorBuilder.newBuilder(tableName); 129 ColumnFamilyDescriptor cfd = ColumnFamilyDescriptorBuilder.of(FAMILY_0); 130 int blockSize = cfd.getBlocksize(); 131 admin.createTable(tdBuilder.setColumnFamily(cfd).build()).join(); 132 admin.disableTable(tableName).join(); 133 // Verify the table descriptor 134 verifyTableDescriptor(tableName, FAMILY_0); 135 136 int newBlockSize = 2 * blockSize; 137 cfd = ColumnFamilyDescriptorBuilder.newBuilder(FAMILY_1).setBlocksize(newBlockSize).build(); 138 139 // Modify a column family that is not in the table. 140 try { 141 admin.modifyColumnFamily(tableName, cfd).join(); 142 Assert.fail("Modify a non-exist column family should fail"); 143 } catch (Exception e) { 144 // Expected. 145 } 146 } 147 148 @Test 149 public void testDeleteColumnFamily() throws Exception { 150 // Create a table with two families 151 TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(tableName); 152 builder.setColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILY_0)) 153 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILY_1)); 154 admin.createTable(builder.build()).join(); 155 admin.disableTable(tableName).join(); 156 // Verify the table descriptor 157 verifyTableDescriptor(tableName, FAMILY_0, FAMILY_1); 158 159 // Modify the table removing one family and verify the descriptor 160 admin.deleteColumnFamily(tableName, FAMILY_1).join(); 161 verifyTableDescriptor(tableName, FAMILY_0); 162 } 163 164 @Test 165 public void testDeleteSameColumnFamilyTwice() throws Exception { 166 // Create a table with two families 167 TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(tableName); 168 builder.setColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILY_0)) 169 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILY_1)); 170 admin.createTable(builder.build()).join(); 171 admin.disableTable(tableName).join(); 172 // Verify the table descriptor 173 verifyTableDescriptor(tableName, FAMILY_0, FAMILY_1); 174 175 // Modify the table removing one family and verify the descriptor 176 admin.deleteColumnFamily(tableName, FAMILY_1).join(); 177 verifyTableDescriptor(tableName, FAMILY_0); 178 179 try { 180 // Delete again - expect failure 181 admin.deleteColumnFamily(tableName, FAMILY_1).join(); 182 Assert.fail("Delete a non-exist column family should fail"); 183 } catch (Exception e) { 184 // Expected. 185 } 186 } 187 188 private void verifyTableDescriptor(final TableName tableName, final byte[]... families) 189 throws Exception { 190 // Verify descriptor from master 191 TableDescriptor htd = admin.getDescriptor(tableName).get(); 192 verifyTableDescriptor(htd, tableName, families); 193 194 // Verify descriptor from HDFS 195 MasterFileSystem mfs = TEST_UTIL.getMiniHBaseCluster().getMaster().getMasterFileSystem(); 196 Path tableDir = CommonFSUtils.getTableDir(mfs.getRootDir(), tableName); 197 TableDescriptor td = FSTableDescriptors.getTableDescriptorFromFs(mfs.getFileSystem(), tableDir); 198 verifyTableDescriptor(td, tableName, families); 199 } 200 201 private void verifyTableDescriptor(final TableDescriptor htd, final TableName tableName, 202 final byte[]... families) { 203 Set<byte[]> htdFamilies = htd.getColumnFamilyNames(); 204 assertEquals(tableName, htd.getTableName()); 205 assertEquals(families.length, htdFamilies.size()); 206 for (byte[] familyName : families) { 207 assertTrue("Expected family " + Bytes.toString(familyName), htdFamilies.contains(familyName)); 208 } 209 } 210 211 212 @Test 213 public void testTableAvailableWithRandomSplitKeys() throws Exception { 214 createTableWithDefaultConf(tableName); 215 byte[][] splitKeys = new byte[1][]; 216 splitKeys = new byte[][] { new byte[] { 1, 1, 1 }, new byte[] { 2, 2, 2 } }; 217 boolean tableAvailable = admin.isTableAvailable(tableName, splitKeys).get(); 218 assertFalse("Table should be created with 1 row in META", tableAvailable); 219 } 220 221 @Test 222 public void testCompactionTimestamps() throws Exception { 223 createTableWithDefaultConf(tableName); 224 AsyncTable<?> table = ASYNC_CONN.getTable(tableName); 225 Optional<Long> ts = admin.getLastMajorCompactionTimestamp(tableName).get(); 226 assertFalse(ts.isPresent()); 227 Put p = new Put(Bytes.toBytes("row1")); 228 p.addColumn(FAMILY, Bytes.toBytes("q"), Bytes.toBytes("v")); 229 table.put(p).join(); 230 ts = admin.getLastMajorCompactionTimestamp(tableName).get(); 231 // no files written -> no data 232 assertFalse(ts.isPresent()); 233 234 admin.flush(tableName).join(); 235 ts = admin.getLastMajorCompactionTimestamp(tableName).get(); 236 // still 0, we flushed a file, but no major compaction happened 237 assertFalse(ts.isPresent()); 238 239 byte[] regionName = ASYNC_CONN.getRegionLocator(tableName) 240 .getRegionLocation(Bytes.toBytes("row1")).get().getRegion().getRegionName(); 241 Optional<Long> ts1 = admin.getLastMajorCompactionTimestampForRegion(regionName).get(); 242 assertFalse(ts1.isPresent()); 243 p = new Put(Bytes.toBytes("row2")); 244 p.addColumn(FAMILY, Bytes.toBytes("q"), Bytes.toBytes("v")); 245 table.put(p).join(); 246 admin.flush(tableName).join(); 247 ts1 = admin.getLastMajorCompactionTimestamp(tableName).get(); 248 // make sure the region API returns the same value, as the old file is still around 249 assertFalse(ts1.isPresent()); 250 251 for (int i = 0; i < 3; i++) { 252 table.put(p).join(); 253 admin.flush(tableName).join(); 254 } 255 admin.majorCompact(tableName).join(); 256 long curt = System.currentTimeMillis(); 257 long waitTime = 10000; 258 long endt = curt + waitTime; 259 CompactionState state = admin.getCompactionState(tableName).get(); 260 LOG.info("Current compaction state 1 is " + state); 261 while (state == CompactionState.NONE && curt < endt) { 262 Thread.sleep(100); 263 state = admin.getCompactionState(tableName).get(); 264 curt = System.currentTimeMillis(); 265 LOG.info("Current compaction state 2 is " + state); 266 } 267 // Now, should have the right compaction state, let's wait until the compaction is done 268 if (state == CompactionState.MAJOR) { 269 state = admin.getCompactionState(tableName).get(); 270 LOG.info("Current compaction state 3 is " + state); 271 while (state != CompactionState.NONE && curt < endt) { 272 Thread.sleep(10); 273 state = admin.getCompactionState(tableName).get(); 274 LOG.info("Current compaction state 4 is " + state); 275 } 276 } 277 // Sleep to wait region server report 278 Thread 279 .sleep(TEST_UTIL.getConfiguration().getInt("hbase.regionserver.msginterval", 3 * 1000) * 2); 280 281 ts = admin.getLastMajorCompactionTimestamp(tableName).get(); 282 // after a compaction our earliest timestamp will have progressed forward 283 assertTrue(ts.isPresent()); 284 assertTrue(ts.get() > 0); 285 // region api still the same 286 ts1 = admin.getLastMajorCompactionTimestampForRegion(regionName).get(); 287 assertTrue(ts1.isPresent()); 288 assertEquals(ts.get(), ts1.get()); 289 table.put(p).join(); 290 admin.flush(tableName).join(); 291 ts = admin.getLastMajorCompactionTimestamp(tableName).join(); 292 assertTrue(ts.isPresent()); 293 assertEquals(ts.get(), ts1.get()); 294 ts1 = admin.getLastMajorCompactionTimestampForRegion(regionName).get(); 295 assertTrue(ts1.isPresent()); 296 assertEquals(ts.get(), ts1.get()); 297 } 298}