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.io.IOException; 026import java.util.List; 027import java.util.regex.Pattern; 028import org.apache.hadoop.hbase.HBaseClassTestRule; 029import org.apache.hadoop.hbase.HConstants; 030import org.apache.hadoop.hbase.HRegionLocation; 031import org.apache.hadoop.hbase.InvalidFamilyOperationException; 032import org.apache.hadoop.hbase.MetaTableAccessor; 033import org.apache.hadoop.hbase.TableName; 034import org.apache.hadoop.hbase.TableNotDisabledException; 035import org.apache.hadoop.hbase.TableNotEnabledException; 036import org.apache.hadoop.hbase.TableNotFoundException; 037import org.apache.hadoop.hbase.testclassification.ClientTests; 038import org.apache.hadoop.hbase.testclassification.LargeTests; 039import org.apache.hadoop.hbase.util.Bytes; 040import org.junit.ClassRule; 041import org.junit.Test; 042import org.junit.experimental.categories.Category; 043import org.slf4j.Logger; 044import org.slf4j.LoggerFactory; 045 046@Category({ LargeTests.class, ClientTests.class }) 047public class TestAdmin3 extends TestAdminBase { 048 049 @ClassRule 050 public static final HBaseClassTestRule CLASS_RULE = HBaseClassTestRule.forClass(TestAdmin3.class); 051 052 private static final Logger LOG = LoggerFactory.getLogger(TestAdmin3.class); 053 054 @Test 055 public void testDisableAndEnableTable() throws IOException { 056 final byte[] row = Bytes.toBytes("row"); 057 final byte[] qualifier = Bytes.toBytes("qualifier"); 058 final byte[] value = Bytes.toBytes("value"); 059 final TableName table = TableName.valueOf(name.getMethodName()); 060 Table ht = TEST_UTIL.createTable(table, HConstants.CATALOG_FAMILY); 061 Put put = new Put(row); 062 put.addColumn(HConstants.CATALOG_FAMILY, qualifier, value); 063 ht.put(put); 064 Get get = new Get(row); 065 get.addColumn(HConstants.CATALOG_FAMILY, qualifier); 066 ht.get(get); 067 068 ADMIN.disableTable(ht.getName()); 069 assertTrue("Table must be disabled.", TEST_UTIL.getHBaseCluster().getMaster() 070 .getTableStateManager().isTableState(ht.getName(), TableState.State.DISABLED)); 071 assertEquals(TableState.State.DISABLED, getStateFromMeta(table)); 072 073 // Test that table is disabled 074 get = new Get(row); 075 get.addColumn(HConstants.CATALOG_FAMILY, qualifier); 076 boolean ok = false; 077 try { 078 ht.get(get); 079 } catch (TableNotEnabledException e) { 080 ok = true; 081 } 082 ok = false; 083 // verify that scan encounters correct exception 084 Scan scan = new Scan(); 085 try { 086 ResultScanner scanner = ht.getScanner(scan); 087 Result res = null; 088 do { 089 res = scanner.next(); 090 } while (res != null); 091 } catch (TableNotEnabledException e) { 092 ok = true; 093 } 094 assertTrue(ok); 095 ADMIN.enableTable(table); 096 assertTrue("Table must be enabled.", TEST_UTIL.getHBaseCluster().getMaster() 097 .getTableStateManager().isTableState(ht.getName(), TableState.State.ENABLED)); 098 assertEquals(TableState.State.ENABLED, getStateFromMeta(table)); 099 100 // Test that table is enabled 101 try { 102 ht.get(get); 103 } catch (RetriesExhaustedException e) { 104 ok = false; 105 } 106 assertTrue(ok); 107 ht.close(); 108 } 109 110 @Test 111 public void testDisableAndEnableTables() throws IOException { 112 final byte[] row = Bytes.toBytes("row"); 113 final byte[] qualifier = Bytes.toBytes("qualifier"); 114 final byte[] value = Bytes.toBytes("value"); 115 final TableName table1 = TableName.valueOf(name.getMethodName() + "1"); 116 final TableName table2 = TableName.valueOf(name.getMethodName() + "2"); 117 Table ht1 = TEST_UTIL.createTable(table1, HConstants.CATALOG_FAMILY); 118 Table ht2 = TEST_UTIL.createTable(table2, HConstants.CATALOG_FAMILY); 119 Put put = new Put(row); 120 put.addColumn(HConstants.CATALOG_FAMILY, qualifier, value); 121 ht1.put(put); 122 ht2.put(put); 123 Get get = new Get(row); 124 get.addColumn(HConstants.CATALOG_FAMILY, qualifier); 125 ht1.get(get); 126 ht2.get(get); 127 128 TableName[] tableNames = ADMIN.listTableNames(Pattern.compile("testDisableAndEnableTable.*")); 129 for (TableName tableName : tableNames) { 130 ADMIN.disableTable(tableName); 131 } 132 133 // Test that tables are disabled 134 get = new Get(row); 135 get.addColumn(HConstants.CATALOG_FAMILY, qualifier); 136 boolean ok = false; 137 try { 138 ht1.get(get); 139 ht2.get(get); 140 } catch (org.apache.hadoop.hbase.DoNotRetryIOException e) { 141 ok = true; 142 } 143 144 assertEquals(TableState.State.DISABLED, getStateFromMeta(table1)); 145 assertEquals(TableState.State.DISABLED, getStateFromMeta(table2)); 146 147 assertTrue(ok); 148 for (TableName tableName : tableNames) { 149 ADMIN.enableTable(tableName); 150 } 151 152 // Test that tables are enabled 153 try { 154 ht1.get(get); 155 } catch (IOException e) { 156 ok = false; 157 } 158 try { 159 ht2.get(get); 160 } catch (IOException e) { 161 ok = false; 162 } 163 assertTrue(ok); 164 165 ht1.close(); 166 ht2.close(); 167 168 assertEquals(TableState.State.ENABLED, getStateFromMeta(table1)); 169 assertEquals(TableState.State.ENABLED, getStateFromMeta(table2)); 170 } 171 172 /** 173 * Test retain assignment on enableTable. 174 */ 175 @Test 176 public void testEnableTableRetainAssignment() throws IOException { 177 final TableName tableName = TableName.valueOf(name.getMethodName()); 178 byte[][] splitKeys = { new byte[] { 1, 1, 1 }, new byte[] { 2, 2, 2 }, new byte[] { 3, 3, 3 }, 179 new byte[] { 4, 4, 4 }, new byte[] { 5, 5, 5 }, new byte[] { 6, 6, 6 }, 180 new byte[] { 7, 7, 7 }, new byte[] { 8, 8, 8 }, new byte[] { 9, 9, 9 } }; 181 int expectedRegions = splitKeys.length + 1; 182 TableDescriptor desc = TableDescriptorBuilder.newBuilder(tableName) 183 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(HConstants.CATALOG_FAMILY)).build(); 184 ADMIN.createTable(desc, splitKeys); 185 186 try (RegionLocator l = TEST_UTIL.getConnection().getRegionLocator(tableName)) { 187 List<HRegionLocation> regions = l.getAllRegionLocations(); 188 189 assertEquals( 190 "Tried to create " + expectedRegions + " regions " + "but only found " + regions.size(), 191 expectedRegions, regions.size()); 192 // Disable table. 193 ADMIN.disableTable(tableName); 194 // Enable table, use retain assignment to assign regions. 195 ADMIN.enableTable(tableName); 196 List<HRegionLocation> regions2 = l.getAllRegionLocations(); 197 198 // Check the assignment. 199 assertEquals(regions.size(), regions2.size()); 200 assertTrue(regions2.containsAll(regions)); 201 } 202 } 203 204 @Test 205 public void testEnableDisableAddColumnDeleteColumn() throws Exception { 206 final TableName tableName = TableName.valueOf(name.getMethodName()); 207 TEST_UTIL.createTable(tableName, HConstants.CATALOG_FAMILY).close(); 208 while (!ADMIN.isTableEnabled(TableName.valueOf(name.getMethodName()))) { 209 Thread.sleep(10); 210 } 211 ADMIN.disableTable(tableName); 212 try { 213 TEST_UTIL.getConnection().getTable(tableName); 214 } catch (org.apache.hadoop.hbase.DoNotRetryIOException e) { 215 // expected 216 } 217 218 ADMIN.addColumnFamily(tableName, ColumnFamilyDescriptorBuilder.of("col2")); 219 ADMIN.enableTable(tableName); 220 try { 221 ADMIN.deleteColumnFamily(tableName, Bytes.toBytes("col2")); 222 } catch (TableNotDisabledException e) { 223 LOG.info(e.toString(), e); 224 } 225 ADMIN.disableTable(tableName); 226 ADMIN.deleteTable(tableName); 227 } 228 229 @Test 230 public void testGetTableDescriptor() throws IOException { 231 TableDescriptor htd = TableDescriptorBuilder.newBuilder(TableName.valueOf(name.getMethodName())) 232 .setColumnFamily(ColumnFamilyDescriptorBuilder.of("fam1")) 233 .setColumnFamily(ColumnFamilyDescriptorBuilder.of("fam2")) 234 .setColumnFamily(ColumnFamilyDescriptorBuilder.of("fam3")).build(); 235 ADMIN.createTable(htd); 236 Table table = TEST_UTIL.getConnection().getTable(htd.getTableName()); 237 TableDescriptor confirmedHtd = table.getDescriptor(); 238 assertEquals(0, TableDescriptor.COMPARATOR.compare(htd, confirmedHtd)); 239 MetaTableAccessor.fullScanMetaAndPrint(TEST_UTIL.getConnection()); 240 table.close(); 241 } 242 243 /** 244 * Verify schema change for read only table 245 */ 246 @Test 247 public void testReadOnlyTableModify() throws IOException, InterruptedException { 248 final TableName tableName = TableName.valueOf(name.getMethodName()); 249 TEST_UTIL.createTable(tableName, HConstants.CATALOG_FAMILY).close(); 250 251 // Make table read only 252 TableDescriptor htd = 253 TableDescriptorBuilder.newBuilder(ADMIN.getDescriptor(tableName)).setReadOnly(true).build(); 254 ADMIN.modifyTable(htd); 255 256 // try to modify the read only table now 257 htd = TableDescriptorBuilder.newBuilder(ADMIN.getDescriptor(tableName)) 258 .setCompactionEnabled(false).build(); 259 ADMIN.modifyTable(htd); 260 // Delete the table 261 ADMIN.disableTable(tableName); 262 ADMIN.deleteTable(tableName); 263 assertFalse(ADMIN.tableExists(tableName)); 264 } 265 266 @Test(expected = TableNotDisabledException.class) 267 public void testModifyRegionReplicasEnabledTable() throws Exception { 268 final TableName tableName = TableName.valueOf(name.getMethodName()); 269 TEST_UTIL.createTable(tableName, HConstants.CATALOG_FAMILY).close(); 270 271 // Modify region replication count 272 TableDescriptor htd = TableDescriptorBuilder.newBuilder(ADMIN.getDescriptor(tableName)) 273 .setRegionReplication(3).build(); 274 try { 275 // try to modify the region replication count without disabling the table 276 ADMIN.modifyTable(htd); 277 fail("Expected an exception"); 278 } finally { 279 // Delete the table 280 ADMIN.disableTable(tableName); 281 ADMIN.deleteTable(tableName); 282 assertFalse(ADMIN.tableExists(tableName)); 283 } 284 } 285 286 @Test 287 public void testDeleteLastColumnFamily() throws Exception { 288 final TableName tableName = TableName.valueOf(name.getMethodName()); 289 TEST_UTIL.createTable(tableName, HConstants.CATALOG_FAMILY).close(); 290 while (!ADMIN.isTableEnabled(TableName.valueOf(name.getMethodName()))) { 291 Thread.sleep(10); 292 } 293 294 // test for enabled table 295 try { 296 ADMIN.deleteColumnFamily(tableName, HConstants.CATALOG_FAMILY); 297 fail("Should have failed to delete the only column family of a table"); 298 } catch (InvalidFamilyOperationException ex) { 299 // expected 300 } 301 302 // test for disabled table 303 ADMIN.disableTable(tableName); 304 305 try { 306 ADMIN.deleteColumnFamily(tableName, HConstants.CATALOG_FAMILY); 307 fail("Should have failed to delete the only column family of a table"); 308 } catch (InvalidFamilyOperationException ex) { 309 // expected 310 } 311 312 ADMIN.deleteTable(tableName); 313 } 314 315 @Test 316 public void testDeleteEditUnknownColumnFamilyAndOrTable() throws IOException { 317 // Test we get exception if we try to 318 final TableName nonexistentTable = TableName.valueOf("nonexistent"); 319 final byte[] nonexistentColumn = Bytes.toBytes("nonexistent"); 320 ColumnFamilyDescriptor nonexistentHcd = ColumnFamilyDescriptorBuilder.of(nonexistentColumn); 321 Exception exception = null; 322 try { 323 ADMIN.addColumnFamily(nonexistentTable, nonexistentHcd); 324 } catch (IOException e) { 325 exception = e; 326 } 327 assertTrue(exception instanceof TableNotFoundException); 328 329 exception = null; 330 try { 331 ADMIN.deleteTable(nonexistentTable); 332 } catch (IOException e) { 333 exception = e; 334 } 335 assertTrue(exception instanceof TableNotFoundException); 336 337 exception = null; 338 try { 339 ADMIN.deleteColumnFamily(nonexistentTable, nonexistentColumn); 340 } catch (IOException e) { 341 exception = e; 342 } 343 assertTrue(exception instanceof TableNotFoundException); 344 345 exception = null; 346 try { 347 ADMIN.disableTable(nonexistentTable); 348 } catch (IOException e) { 349 exception = e; 350 } 351 assertTrue(exception instanceof TableNotFoundException); 352 353 exception = null; 354 try { 355 ADMIN.enableTable(nonexistentTable); 356 } catch (IOException e) { 357 exception = e; 358 } 359 assertTrue(exception instanceof TableNotFoundException); 360 361 exception = null; 362 try { 363 ADMIN.modifyColumnFamily(nonexistentTable, nonexistentHcd); 364 } catch (IOException e) { 365 exception = e; 366 } 367 assertTrue(exception instanceof TableNotFoundException); 368 369 exception = null; 370 try { 371 TableDescriptor htd = TableDescriptorBuilder.newBuilder(nonexistentTable) 372 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(HConstants.CATALOG_FAMILY)).build(); 373 ADMIN.modifyTable(htd); 374 } catch (IOException e) { 375 exception = e; 376 } 377 assertTrue(exception instanceof TableNotFoundException); 378 379 // Now make it so at least the table exists and then do tests against a 380 // nonexistent column family -- see if we get right exceptions. 381 final TableName tableName = 382 TableName.valueOf(name.getMethodName() + System.currentTimeMillis()); 383 TableDescriptor htd = TableDescriptorBuilder.newBuilder(tableName) 384 .setColumnFamily(ColumnFamilyDescriptorBuilder.of("cf")).build(); 385 ADMIN.createTable(htd); 386 try { 387 exception = null; 388 try { 389 ADMIN.deleteColumnFamily(htd.getTableName(), nonexistentHcd.getName()); 390 } catch (IOException e) { 391 exception = e; 392 } 393 assertTrue("found=" + exception.getClass().getName(), 394 exception instanceof InvalidFamilyOperationException); 395 396 exception = null; 397 try { 398 ADMIN.modifyColumnFamily(htd.getTableName(), nonexistentHcd); 399 } catch (IOException e) { 400 exception = e; 401 } 402 assertTrue("found=" + exception.getClass().getName(), 403 exception instanceof InvalidFamilyOperationException); 404 } finally { 405 ADMIN.disableTable(tableName); 406 ADMIN.deleteTable(tableName); 407 } 408 } 409}