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.master.procedure; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertFalse; 022import static org.junit.Assert.assertTrue; 023 024import java.io.IOException; 025import org.apache.hadoop.hbase.ConcurrentTableModificationException; 026import org.apache.hadoop.hbase.DoNotRetryIOException; 027import org.apache.hadoop.hbase.HBaseClassTestRule; 028import org.apache.hadoop.hbase.InvalidFamilyOperationException; 029import org.apache.hadoop.hbase.TableName; 030import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor; 031import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; 032import org.apache.hadoop.hbase.client.PerClientRandomNonceGenerator; 033import org.apache.hadoop.hbase.client.RegionInfo; 034import org.apache.hadoop.hbase.client.TableDescriptor; 035import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 036import org.apache.hadoop.hbase.master.procedure.MasterProcedureTestingUtility.StepHook; 037import org.apache.hadoop.hbase.procedure2.Procedure; 038import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; 039import org.apache.hadoop.hbase.procedure2.ProcedureTestingUtility; 040import org.apache.hadoop.hbase.testclassification.LargeTests; 041import org.apache.hadoop.hbase.testclassification.MasterTests; 042import org.apache.hadoop.hbase.util.Bytes; 043import org.apache.hadoop.hbase.util.NonceKey; 044import org.apache.hadoop.hbase.util.TableDescriptorChecker; 045import org.junit.Assert; 046import org.junit.ClassRule; 047import org.junit.Rule; 048import org.junit.Test; 049import org.junit.experimental.categories.Category; 050import org.junit.rules.TestName; 051 052@Category({ MasterTests.class, LargeTests.class }) 053public class TestModifyTableProcedure extends TestTableDDLProcedureBase { 054 055 @ClassRule 056 public static final HBaseClassTestRule CLASS_RULE = 057 HBaseClassTestRule.forClass(TestModifyTableProcedure.class); 058 059 @Rule 060 public TestName name = new TestName(); 061 062 private static final String column_Family1 = "cf1"; 063 private static final String column_Family2 = "cf2"; 064 private static final String column_Family3 = "cf3"; 065 066 @Test 067 public void testModifyTable() throws Exception { 068 final TableName tableName = TableName.valueOf(name.getMethodName()); 069 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor(); 070 071 MasterProcedureTestingUtility.createTable(procExec, tableName, null, "cf"); 072 UTIL.getAdmin().disableTable(tableName); 073 074 // Modify the table descriptor 075 TableDescriptor htd = UTIL.getAdmin().getDescriptor(tableName); 076 077 // Test 1: Modify 1 property 078 long newMaxFileSize = htd.getMaxFileSize() * 2; 079 htd = TableDescriptorBuilder.newBuilder(htd).setMaxFileSize(newMaxFileSize) 080 .setRegionReplication(3).build(); 081 082 long procId1 = ProcedureTestingUtility.submitAndWait(procExec, 083 new ModifyTableProcedure(procExec.getEnvironment(), htd)); 084 ProcedureTestingUtility.assertProcNotFailed(procExec.getResult(procId1)); 085 086 TableDescriptor currentHtd = UTIL.getAdmin().getDescriptor(tableName); 087 assertEquals(newMaxFileSize, currentHtd.getMaxFileSize()); 088 089 // Test 2: Modify multiple properties 090 boolean newReadOnlyOption = htd.isReadOnly() ? false : true; 091 long newMemStoreFlushSize = htd.getMemStoreFlushSize() * 2; 092 htd = TableDescriptorBuilder.newBuilder(htd).setReadOnly(newReadOnlyOption) 093 .setMemStoreFlushSize(newMemStoreFlushSize).build(); 094 095 long procId2 = ProcedureTestingUtility.submitAndWait(procExec, 096 new ModifyTableProcedure(procExec.getEnvironment(), htd)); 097 ProcedureTestingUtility.assertProcNotFailed(procExec.getResult(procId2)); 098 099 currentHtd = UTIL.getAdmin().getDescriptor(tableName); 100 assertEquals(newReadOnlyOption, currentHtd.isReadOnly()); 101 assertEquals(newMemStoreFlushSize, currentHtd.getMemStoreFlushSize()); 102 } 103 104 @Test 105 public void testModifyTableAddCF() throws Exception { 106 final TableName tableName = TableName.valueOf(name.getMethodName()); 107 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor(); 108 109 MasterProcedureTestingUtility.createTable(procExec, tableName, null, "cf1"); 110 TableDescriptor currentHtd = UTIL.getAdmin().getDescriptor(tableName); 111 assertEquals(1, currentHtd.getColumnFamilyNames().size()); 112 113 // Test 1: Modify the table descriptor online 114 String cf2 = "cf2"; 115 TableDescriptorBuilder tableDescriptorBuilder = 116 TableDescriptorBuilder.newBuilder(UTIL.getAdmin().getDescriptor(tableName)); 117 ColumnFamilyDescriptor columnFamilyDescriptor = 118 ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(cf2)).build(); 119 tableDescriptorBuilder.setColumnFamily(columnFamilyDescriptor); 120 121 long procId = ProcedureTestingUtility.submitAndWait(procExec, 122 new ModifyTableProcedure(procExec.getEnvironment(), tableDescriptorBuilder.build())); 123 ProcedureTestingUtility.assertProcNotFailed(procExec.getResult(procId)); 124 125 currentHtd = UTIL.getAdmin().getDescriptor(tableName); 126 assertEquals(2, currentHtd.getColumnFamilyNames().size()); 127 assertTrue(currentHtd.hasColumnFamily(Bytes.toBytes(cf2))); 128 129 // Test 2: Modify the table descriptor offline 130 UTIL.getAdmin().disableTable(tableName); 131 ProcedureTestingUtility.waitNoProcedureRunning(procExec); 132 String cf3 = "cf3"; 133 tableDescriptorBuilder = 134 TableDescriptorBuilder.newBuilder(UTIL.getAdmin().getDescriptor(tableName)); 135 columnFamilyDescriptor = ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(cf3)).build(); 136 tableDescriptorBuilder.setColumnFamily(columnFamilyDescriptor); 137 138 long procId2 = ProcedureTestingUtility.submitAndWait(procExec, 139 new ModifyTableProcedure(procExec.getEnvironment(), tableDescriptorBuilder.build())); 140 ProcedureTestingUtility.assertProcNotFailed(procExec.getResult(procId2)); 141 142 currentHtd = UTIL.getAdmin().getDescriptor(tableName); 143 assertTrue(currentHtd.hasColumnFamily(Bytes.toBytes(cf3))); 144 assertEquals(3, currentHtd.getColumnFamilyNames().size()); 145 } 146 147 @Test 148 public void testModifyTableDeleteCF() throws Exception { 149 final TableName tableName = TableName.valueOf(name.getMethodName()); 150 final String cf1 = "cf1"; 151 final String cf2 = "cf2"; 152 final String cf3 = "cf3"; 153 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor(); 154 155 MasterProcedureTestingUtility.createTable(procExec, tableName, null, cf1, cf2, cf3); 156 TableDescriptor currentHtd = UTIL.getAdmin().getDescriptor(tableName); 157 assertEquals(3, currentHtd.getColumnFamilyNames().size()); 158 159 // Test 1: Modify the table descriptor 160 TableDescriptor htd = UTIL.getAdmin().getDescriptor(tableName); 161 htd = TableDescriptorBuilder.newBuilder(htd).removeColumnFamily(Bytes.toBytes(cf2)).build(); 162 163 long procId = ProcedureTestingUtility.submitAndWait(procExec, 164 new ModifyTableProcedure(procExec.getEnvironment(), htd)); 165 ProcedureTestingUtility.assertProcNotFailed(procExec.getResult(procId)); 166 167 currentHtd = UTIL.getAdmin().getDescriptor(tableName); 168 assertEquals(2, currentHtd.getColumnFamilyNames().size()); 169 assertFalse(currentHtd.hasColumnFamily(Bytes.toBytes(cf2))); 170 171 // Test 2: Modify the table descriptor offline 172 UTIL.getAdmin().disableTable(tableName); 173 ProcedureTestingUtility.waitNoProcedureRunning(procExec); 174 175 TableDescriptor htd2 = UTIL.getAdmin().getDescriptor(tableName); 176 // Disable Sanity check 177 htd2 = TableDescriptorBuilder.newBuilder(htd2).removeColumnFamily(Bytes.toBytes(cf3)) 178 .setValue(TableDescriptorChecker.TABLE_SANITY_CHECKS, Boolean.FALSE.toString()).build(); 179 180 long procId2 = ProcedureTestingUtility.submitAndWait(procExec, 181 new ModifyTableProcedure(procExec.getEnvironment(), htd2)); 182 ProcedureTestingUtility.assertProcNotFailed(procExec.getResult(procId2)); 183 184 currentHtd = UTIL.getAdmin().getDescriptor(tableName); 185 assertEquals(1, currentHtd.getColumnFamilyNames().size()); 186 assertFalse(currentHtd.hasColumnFamily(Bytes.toBytes(cf3))); 187 188 // Removing the last family will fail 189 TableDescriptor htd3 = UTIL.getAdmin().getDescriptor(tableName); 190 htd3 = TableDescriptorBuilder.newBuilder(htd3).removeColumnFamily(Bytes.toBytes(cf1)).build(); 191 long procId3 = ProcedureTestingUtility.submitAndWait(procExec, 192 new ModifyTableProcedure(procExec.getEnvironment(), htd3)); 193 final Procedure<?> result = procExec.getResult(procId3); 194 assertEquals(true, result.isFailed()); 195 Throwable cause = ProcedureTestingUtility.getExceptionCause(result); 196 assertTrue("expected DoNotRetryIOException, got " + cause, 197 cause instanceof DoNotRetryIOException); 198 assertEquals(1, currentHtd.getColumnFamilyNames().size()); 199 assertTrue(currentHtd.hasColumnFamily(Bytes.toBytes(cf1))); 200 } 201 202 @Test 203 public void testRecoveryAndDoubleExecutionOffline() throws Exception { 204 final TableName tableName = TableName.valueOf(name.getMethodName()); 205 final String cf2 = "cf2"; 206 final String cf3 = "cf3"; 207 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor(); 208 209 // create the table 210 RegionInfo[] regions = 211 MasterProcedureTestingUtility.createTable(procExec, tableName, null, "cf1", cf3); 212 UTIL.getAdmin().disableTable(tableName); 213 214 ProcedureTestingUtility.waitNoProcedureRunning(procExec); 215 ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true); 216 217 // Modify multiple properties of the table. 218 TableDescriptor oldDescriptor = UTIL.getAdmin().getDescriptor(tableName); 219 TableDescriptor newDescriptor = TableDescriptorBuilder.newBuilder(oldDescriptor) 220 .setCompactionEnabled(!oldDescriptor.isCompactionEnabled()) 221 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(cf2)).removeColumnFamily(Bytes.toBytes(cf3)) 222 .setRegionReplication(3).build(); 223 224 // Start the Modify procedure && kill the executor 225 long procId = 226 procExec.submitProcedure(new ModifyTableProcedure(procExec.getEnvironment(), newDescriptor)); 227 228 // Restart the executor and execute the step twice 229 MasterProcedureTestingUtility.testRecoveryAndDoubleExecution(procExec, procId); 230 231 // Validate descriptor 232 TableDescriptor currentDescriptor = UTIL.getAdmin().getDescriptor(tableName); 233 assertEquals(newDescriptor.isCompactionEnabled(), currentDescriptor.isCompactionEnabled()); 234 assertEquals(2, newDescriptor.getColumnFamilyNames().size()); 235 236 // cf2 should be added cf3 should be removed 237 MasterProcedureTestingUtility.validateTableCreation(UTIL.getHBaseCluster().getMaster(), 238 tableName, regions, false, "cf1", cf2); 239 } 240 241 @Test 242 public void testRecoveryAndDoubleExecutionOnline() throws Exception { 243 final TableName tableName = TableName.valueOf(name.getMethodName()); 244 final String cf2 = "cf2"; 245 final String cf3 = "cf3"; 246 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor(); 247 248 // create the table 249 RegionInfo[] regions = 250 MasterProcedureTestingUtility.createTable(procExec, tableName, null, "cf1", cf3); 251 252 ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true); 253 254 // Modify multiple properties of the table. 255 TableDescriptorBuilder tableDescriptorBuilder = 256 TableDescriptorBuilder.newBuilder(UTIL.getAdmin().getDescriptor(tableName)); 257 ColumnFamilyDescriptor columnFamilyDescriptor = 258 ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(cf2)).build(); 259 boolean newCompactionEnableOption = !tableDescriptorBuilder.build().isCompactionEnabled(); 260 tableDescriptorBuilder.setCompactionEnabled(newCompactionEnableOption); 261 tableDescriptorBuilder.setColumnFamily(columnFamilyDescriptor); 262 tableDescriptorBuilder.removeColumnFamily(Bytes.toBytes(cf3)); 263 264 // Start the Modify procedure && kill the executor 265 long procId = procExec.submitProcedure( 266 new ModifyTableProcedure(procExec.getEnvironment(), tableDescriptorBuilder.build())); 267 268 // Restart the executor and execute the step twice 269 MasterProcedureTestingUtility.testRecoveryAndDoubleExecution(procExec, procId); 270 271 // Validate descriptor 272 TableDescriptor currentHtd = UTIL.getAdmin().getDescriptor(tableName); 273 assertEquals(newCompactionEnableOption, currentHtd.isCompactionEnabled()); 274 assertEquals(2, currentHtd.getColumnFamilyNames().size()); 275 assertTrue(currentHtd.hasColumnFamily(Bytes.toBytes(cf2))); 276 assertFalse(currentHtd.hasColumnFamily(Bytes.toBytes(cf3))); 277 278 // cf2 should be added cf3 should be removed 279 MasterProcedureTestingUtility.validateTableCreation(UTIL.getHBaseCluster().getMaster(), 280 tableName, regions, "cf1", cf2); 281 } 282 283 @Test 284 public void testColumnFamilyAdditionTwiceWithNonce() throws Exception { 285 final TableName tableName = TableName.valueOf(name.getMethodName()); 286 final String cf2 = "cf2"; 287 final String cf3 = "cf3"; 288 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor(); 289 290 // create the table 291 RegionInfo[] regions = 292 MasterProcedureTestingUtility.createTable(procExec, tableName, null, "cf1", cf3); 293 294 ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true); 295 // Modify multiple properties of the table. 296 TableDescriptor td = UTIL.getAdmin().getDescriptor(tableName); 297 TableDescriptor newTd = 298 TableDescriptorBuilder.newBuilder(td).setCompactionEnabled(!td.isCompactionEnabled()) 299 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(cf2)).build(); 300 301 PerClientRandomNonceGenerator nonceGenerator = PerClientRandomNonceGenerator.get(); 302 long nonceGroup = nonceGenerator.getNonceGroup(); 303 long newNonce = nonceGenerator.newNonce(); 304 NonceKey nonceKey = new NonceKey(nonceGroup, newNonce); 305 procExec.registerNonce(nonceKey); 306 307 // Start the Modify procedure && kill the executor 308 final long procId = procExec 309 .submitProcedure(new ModifyTableProcedure(procExec.getEnvironment(), newTd), nonceKey); 310 311 // Restart the executor after MODIFY_TABLE_UPDATE_TABLE_DESCRIPTOR and try to add column family 312 // as nonce are there , we should not fail 313 MasterProcedureTestingUtility.testRecoveryAndDoubleExecution(procExec, procId, new StepHook() { 314 @Override 315 public boolean execute(int step) throws IOException { 316 if (step == 3) { 317 return procId == UTIL.getHBaseCluster().getMaster().addColumn(tableName, 318 ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(cf2)).build(), nonceGroup, 319 newNonce); 320 } 321 return true; 322 } 323 }); 324 325 // Try with different nonce, now it should fail the checks 326 try { 327 UTIL.getHBaseCluster().getMaster().addColumn(tableName, 328 ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(cf2)).build(), nonceGroup, 329 nonceGenerator.newNonce()); 330 Assert.fail(); 331 } catch (InvalidFamilyOperationException e) { 332 } 333 334 // Validate descriptor 335 TableDescriptor currentHtd = UTIL.getAdmin().getDescriptor(tableName); 336 assertEquals(!td.isCompactionEnabled(), currentHtd.isCompactionEnabled()); 337 assertEquals(3, currentHtd.getColumnFamilyCount()); 338 assertTrue(currentHtd.hasColumnFamily(Bytes.toBytes(cf2))); 339 assertTrue(currentHtd.hasColumnFamily(Bytes.toBytes(cf3))); 340 341 // cf2 should be added 342 MasterProcedureTestingUtility.validateTableCreation(UTIL.getHBaseCluster().getMaster(), 343 tableName, regions, "cf1", cf2, cf3); 344 } 345 346 @Test 347 public void testRollbackAndDoubleExecutionOnline() throws Exception { 348 final TableName tableName = TableName.valueOf(name.getMethodName()); 349 final String familyName = "cf2"; 350 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor(); 351 352 // create the table 353 RegionInfo[] regions = 354 MasterProcedureTestingUtility.createTable(procExec, tableName, null, "cf1"); 355 356 ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true); 357 358 TableDescriptor td = UTIL.getAdmin().getDescriptor(tableName); 359 TableDescriptor newTd = 360 TableDescriptorBuilder.newBuilder(td).setCompactionEnabled(!td.isCompactionEnabled()) 361 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(familyName)).build(); 362 363 // Start the Modify procedure && kill the executor 364 long procId = 365 procExec.submitProcedure(new ModifyTableProcedure(procExec.getEnvironment(), newTd)); 366 367 int lastStep = 8; // failing before MODIFY_TABLE_UPDATE_TABLE_DESCRIPTOR 368 MasterProcedureTestingUtility.testRollbackAndDoubleExecution(procExec, procId, lastStep); 369 370 // cf2 should not be present 371 MasterProcedureTestingUtility.validateTableCreation(UTIL.getHBaseCluster().getMaster(), 372 tableName, regions, "cf1"); 373 } 374 375 @Test 376 public void testRollbackAndDoubleExecutionOffline() throws Exception { 377 final TableName tableName = TableName.valueOf(name.getMethodName()); 378 final String familyName = "cf2"; 379 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor(); 380 381 // create the table 382 RegionInfo[] regions = 383 MasterProcedureTestingUtility.createTable(procExec, tableName, null, "cf1"); 384 UTIL.getAdmin().disableTable(tableName); 385 386 ProcedureTestingUtility.waitNoProcedureRunning(procExec); 387 ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true); 388 389 TableDescriptor td = UTIL.getAdmin().getDescriptor(tableName); 390 TableDescriptor newTd = 391 TableDescriptorBuilder.newBuilder(td).setCompactionEnabled(!td.isCompactionEnabled()) 392 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(familyName)).setRegionReplication(3) 393 .build(); 394 395 // Start the Modify procedure && kill the executor 396 long procId = 397 procExec.submitProcedure(new ModifyTableProcedure(procExec.getEnvironment(), newTd)); 398 399 // Restart the executor and rollback the step twice 400 int lastStep = 8; // failing before MODIFY_TABLE_UPDATE_TABLE_DESCRIPTOR 401 MasterProcedureTestingUtility.testRollbackAndDoubleExecution(procExec, procId, lastStep); 402 403 // cf2 should not be present 404 MasterProcedureTestingUtility.validateTableCreation(UTIL.getHBaseCluster().getMaster(), 405 tableName, regions, "cf1"); 406 } 407 408 @Test 409 public void testConcurrentAddColumnFamily() throws IOException, InterruptedException { 410 final TableName tableName = TableName.valueOf(name.getMethodName()); 411 UTIL.createTable(tableName, column_Family1); 412 413 class ConcurrentAddColumnFamily extends Thread { 414 TableName tableName = null; 415 ColumnFamilyDescriptor columnFamilyDescriptor; 416 boolean exception; 417 418 public ConcurrentAddColumnFamily(TableName tableName, 419 ColumnFamilyDescriptor columnFamilyDescriptor) { 420 this.tableName = tableName; 421 this.columnFamilyDescriptor = columnFamilyDescriptor; 422 this.exception = false; 423 } 424 425 public void run() { 426 try { 427 UTIL.getAdmin().addColumnFamily(tableName, columnFamilyDescriptor); 428 } catch (Exception e) { 429 if (e.getClass().equals(ConcurrentTableModificationException.class)) { 430 this.exception = true; 431 } 432 } 433 } 434 } 435 ColumnFamilyDescriptor columnFamilyDescriptor = 436 ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(column_Family2)).build(); 437 ConcurrentAddColumnFamily t1 = new ConcurrentAddColumnFamily(tableName, columnFamilyDescriptor); 438 columnFamilyDescriptor = 439 ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(column_Family3)).build(); 440 ConcurrentAddColumnFamily t2 = new ConcurrentAddColumnFamily(tableName, columnFamilyDescriptor); 441 442 t1.start(); 443 t2.start(); 444 445 t1.join(); 446 t2.join(); 447 int noOfColumnFamilies = UTIL.getAdmin().getDescriptor(tableName).getColumnFamilies().length; 448 assertTrue("Expected ConcurrentTableModificationException.", 449 ((t1.exception || t2.exception) && noOfColumnFamilies == 2) || noOfColumnFamilies == 3); 450 } 451 452 @Test 453 public void testConcurrentDeleteColumnFamily() throws IOException, InterruptedException { 454 final TableName tableName = TableName.valueOf(name.getMethodName()); 455 TableDescriptorBuilder tableDescriptorBuilder = TableDescriptorBuilder.newBuilder(tableName); 456 ColumnFamilyDescriptor columnFamilyDescriptor = 457 ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(column_Family1)).build(); 458 tableDescriptorBuilder.setColumnFamily(columnFamilyDescriptor); 459 columnFamilyDescriptor = 460 ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(column_Family2)).build(); 461 tableDescriptorBuilder.setColumnFamily(columnFamilyDescriptor); 462 columnFamilyDescriptor = 463 ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(column_Family3)).build(); 464 tableDescriptorBuilder.setColumnFamily(columnFamilyDescriptor); 465 UTIL.getAdmin().createTable(tableDescriptorBuilder.build()); 466 467 class ConcurrentCreateDeleteTable extends Thread { 468 TableName tableName = null; 469 String columnFamily = null; 470 boolean exception; 471 472 public ConcurrentCreateDeleteTable(TableName tableName, String columnFamily) { 473 this.tableName = tableName; 474 this.columnFamily = columnFamily; 475 this.exception = false; 476 } 477 478 public void run() { 479 try { 480 UTIL.getAdmin().deleteColumnFamily(tableName, columnFamily.getBytes()); 481 } catch (Exception e) { 482 if (e.getClass().equals(ConcurrentTableModificationException.class)) { 483 this.exception = true; 484 } 485 } 486 } 487 } 488 ConcurrentCreateDeleteTable t1 = new ConcurrentCreateDeleteTable(tableName, column_Family2); 489 ConcurrentCreateDeleteTable t2 = new ConcurrentCreateDeleteTable(tableName, column_Family3); 490 491 t1.start(); 492 t2.start(); 493 494 t1.join(); 495 t2.join(); 496 int noOfColumnFamilies = UTIL.getAdmin().getDescriptor(tableName).getColumnFamilies().length; 497 assertTrue("Expected ConcurrentTableModificationException.", 498 ((t1.exception || t2.exception) && noOfColumnFamilies == 2) || noOfColumnFamilies == 1); 499 } 500 501 @Test 502 public void testConcurrentModifyColumnFamily() throws IOException, InterruptedException { 503 final TableName tableName = TableName.valueOf(name.getMethodName()); 504 UTIL.createTable(tableName, column_Family1); 505 506 class ConcurrentModifyColumnFamily extends Thread { 507 TableName tableName = null; 508 ColumnFamilyDescriptor hcd = null; 509 boolean exception; 510 511 public ConcurrentModifyColumnFamily(TableName tableName, ColumnFamilyDescriptor hcd) { 512 this.tableName = tableName; 513 this.hcd = hcd; 514 this.exception = false; 515 } 516 517 public void run() { 518 try { 519 UTIL.getAdmin().modifyColumnFamily(tableName, hcd); 520 } catch (Exception e) { 521 if (e.getClass().equals(ConcurrentTableModificationException.class)) { 522 this.exception = true; 523 } 524 } 525 } 526 } 527 ColumnFamilyDescriptor modColumnFamily1 = 528 ColumnFamilyDescriptorBuilder.newBuilder(column_Family1.getBytes()).setMaxVersions(5).build(); 529 ColumnFamilyDescriptor modColumnFamily2 = 530 ColumnFamilyDescriptorBuilder.newBuilder(column_Family1.getBytes()).setMaxVersions(6).build(); 531 532 ConcurrentModifyColumnFamily t1 = new ConcurrentModifyColumnFamily(tableName, modColumnFamily1); 533 ConcurrentModifyColumnFamily t2 = new ConcurrentModifyColumnFamily(tableName, modColumnFamily2); 534 535 t1.start(); 536 t2.start(); 537 538 t1.join(); 539 t2.join(); 540 541 int maxVersions = UTIL.getAdmin().getDescriptor(tableName) 542 .getColumnFamily(column_Family1.getBytes()).getMaxVersions(); 543 assertTrue("Expected ConcurrentTableModificationException.", (t1.exception && maxVersions == 5) 544 || (t2.exception && maxVersions == 6) || !(t1.exception && t2.exception)); 545 } 546 547 @Test 548 public void testConcurrentModifyTable() throws IOException, InterruptedException { 549 final TableName tableName = TableName.valueOf(name.getMethodName()); 550 UTIL.createTable(tableName, column_Family1); 551 552 class ConcurrentModifyTable extends Thread { 553 TableName tableName = null; 554 TableDescriptor htd = null; 555 boolean exception; 556 557 public ConcurrentModifyTable(TableName tableName, TableDescriptor htd) { 558 this.tableName = tableName; 559 this.htd = htd; 560 this.exception = false; 561 } 562 563 public void run() { 564 try { 565 UTIL.getAdmin().modifyTable(htd); 566 } catch (Exception e) { 567 if (e.getClass().equals(ConcurrentTableModificationException.class)) { 568 this.exception = true; 569 } 570 } 571 } 572 } 573 TableDescriptor htd = UTIL.getAdmin().getDescriptor(tableName); 574 TableDescriptor modifiedDescriptor = 575 TableDescriptorBuilder.newBuilder(htd).setCompactionEnabled(false).build(); 576 577 ConcurrentModifyTable t1 = new ConcurrentModifyTable(tableName, modifiedDescriptor); 578 ConcurrentModifyTable t2 = new ConcurrentModifyTable(tableName, modifiedDescriptor); 579 580 t1.start(); 581 t2.start(); 582 583 t1.join(); 584 t2.join(); 585 assertFalse("Expected ConcurrentTableModificationException.", (t1.exception || t2.exception)); 586 } 587}