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 267 public void testDeleteLastColumnFamily() throws Exception { 268 final TableName tableName = TableName.valueOf(name.getMethodName()); 269 TEST_UTIL.createTable(tableName, HConstants.CATALOG_FAMILY).close(); 270 while (!ADMIN.isTableEnabled(TableName.valueOf(name.getMethodName()))) { 271 Thread.sleep(10); 272 } 273 274 // test for enabled table 275 try { 276 ADMIN.deleteColumnFamily(tableName, HConstants.CATALOG_FAMILY); 277 fail("Should have failed to delete the only column family of a table"); 278 } catch (InvalidFamilyOperationException ex) { 279 // expected 280 } 281 282 // test for disabled table 283 ADMIN.disableTable(tableName); 284 285 try { 286 ADMIN.deleteColumnFamily(tableName, HConstants.CATALOG_FAMILY); 287 fail("Should have failed to delete the only column family of a table"); 288 } catch (InvalidFamilyOperationException ex) { 289 // expected 290 } 291 292 ADMIN.deleteTable(tableName); 293 } 294 295 @Test 296 public void testDeleteEditUnknownColumnFamilyAndOrTable() throws IOException { 297 // Test we get exception if we try to 298 final TableName nonexistentTable = TableName.valueOf("nonexistent"); 299 final byte[] nonexistentColumn = Bytes.toBytes("nonexistent"); 300 ColumnFamilyDescriptor nonexistentHcd = ColumnFamilyDescriptorBuilder.of(nonexistentColumn); 301 Exception exception = null; 302 try { 303 ADMIN.addColumnFamily(nonexistentTable, nonexistentHcd); 304 } catch (IOException e) { 305 exception = e; 306 } 307 assertTrue(exception instanceof TableNotFoundException); 308 309 exception = null; 310 try { 311 ADMIN.deleteTable(nonexistentTable); 312 } catch (IOException e) { 313 exception = e; 314 } 315 assertTrue(exception instanceof TableNotFoundException); 316 317 exception = null; 318 try { 319 ADMIN.deleteColumnFamily(nonexistentTable, nonexistentColumn); 320 } catch (IOException e) { 321 exception = e; 322 } 323 assertTrue(exception instanceof TableNotFoundException); 324 325 exception = null; 326 try { 327 ADMIN.disableTable(nonexistentTable); 328 } catch (IOException e) { 329 exception = e; 330 } 331 assertTrue(exception instanceof TableNotFoundException); 332 333 exception = null; 334 try { 335 ADMIN.enableTable(nonexistentTable); 336 } catch (IOException e) { 337 exception = e; 338 } 339 assertTrue(exception instanceof TableNotFoundException); 340 341 exception = null; 342 try { 343 ADMIN.modifyColumnFamily(nonexistentTable, nonexistentHcd); 344 } catch (IOException e) { 345 exception = e; 346 } 347 assertTrue(exception instanceof TableNotFoundException); 348 349 exception = null; 350 try { 351 TableDescriptor htd = TableDescriptorBuilder.newBuilder(nonexistentTable) 352 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(HConstants.CATALOG_FAMILY)).build(); 353 ADMIN.modifyTable(htd); 354 } catch (IOException e) { 355 exception = e; 356 } 357 assertTrue(exception instanceof TableNotFoundException); 358 359 // Now make it so at least the table exists and then do tests against a 360 // nonexistent column family -- see if we get right exceptions. 361 final TableName tableName = 362 TableName.valueOf(name.getMethodName() + System.currentTimeMillis()); 363 TableDescriptor htd = TableDescriptorBuilder.newBuilder(tableName) 364 .setColumnFamily(ColumnFamilyDescriptorBuilder.of("cf")).build(); 365 ADMIN.createTable(htd); 366 try { 367 exception = null; 368 try { 369 ADMIN.deleteColumnFamily(htd.getTableName(), nonexistentHcd.getName()); 370 } catch (IOException e) { 371 exception = e; 372 } 373 assertTrue("found=" + exception.getClass().getName(), 374 exception instanceof InvalidFamilyOperationException); 375 376 exception = null; 377 try { 378 ADMIN.modifyColumnFamily(htd.getTableName(), nonexistentHcd); 379 } catch (IOException e) { 380 exception = e; 381 } 382 assertTrue("found=" + exception.getClass().getName(), 383 exception instanceof InvalidFamilyOperationException); 384 } finally { 385 ADMIN.disableTable(tableName); 386 ADMIN.deleteTable(tableName); 387 } 388 } 389}