diff --git hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/CreateTableProcedure.java hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/CreateTableProcedure.java index 183871d..d8de128 100644 --- hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/CreateTableProcedure.java +++ hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/CreateTableProcedure.java @@ -37,6 +37,7 @@ import org.apache.hadoop.hbase.MetaTableAccessor; import org.apache.hadoop.hbase.TableDescriptor; import org.apache.hadoop.hbase.TableExistsException; import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.DoNotRetryIOException; import org.apache.hadoop.hbase.client.RegionReplicaUtil; import org.apache.hadoop.hbase.client.TableState; import org.apache.hadoop.hbase.master.AssignmentManager; @@ -283,6 +284,14 @@ public class CreateTableProcedure setFailure("master-create-table", new TableExistsException(getTableName())); return false; } + + // check that we have at least 1 CF + if (hTableDescriptor.getColumnFamilies().length == 0) { + setFailure("master-create-table", new DoNotRetryIOException("Table " + + getTableName().toString() + " should have at least one column family.")); + return false; + } + return true; } diff --git hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/ModifyTableProcedure.java hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/ModifyTableProcedure.java index 9231639..958a7ca 100644 --- hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/ModifyTableProcedure.java +++ hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/ModifyTableProcedure.java @@ -48,6 +48,7 @@ import org.apache.hadoop.hbase.procedure2.StateMachineProcedure; import org.apache.hadoop.hbase.protobuf.generated.MasterProcedureProtos; import org.apache.hadoop.hbase.protobuf.generated.MasterProcedureProtos.ModifyTableState; import org.apache.hadoop.hbase.util.ServerRegionReplicaUtil; +import org.apache.hadoop.hbase.DoNotRetryIOException; import org.apache.hadoop.security.UserGroupInformation; @InterfaceAudience.Private @@ -285,6 +286,12 @@ public class ModifyTableProcedure throw new TableNotFoundException(getTableName()); } + // check that we have at least 1 CF + if (modifiedHTableDescriptor.getColumnFamilies().length == 0) { + throw new DoNotRetryIOException("Table " + getTableName().toString() + + " should have at least one column family."); + } + // In order to update the descriptor, we need to retrieve the old descriptor for comparison. this.unmodifiedHTableDescriptor = env.getMasterServices().getTableDescriptors().get(getTableName()); diff --git hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java index d20b478..7a19796 100644 --- hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java +++ hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java @@ -785,6 +785,13 @@ public class HRegion implements HeapSize, PropagatingConfigurationObserver, Regi * @throws IOException e */ private long initialize(final CancelableProgressable reporter) throws IOException { + + //Refuse to open the region if there is no column family in the table + if (htableDescriptor.getColumnFamilies().length == 0) { + throw new DoNotRetryIOException("Table " + htableDescriptor.getNameAsString() + + "should have at least one column family."); + } + MonitoredTask status = TaskMonitor.get().createStatus("Initializing region " + this); long nextSeqId = -1; try { diff --git hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide.java hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide.java index 3b88184..96f48ec 100644 --- hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide.java +++ hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide.java @@ -5206,8 +5206,6 @@ public class TestFromClientSide { HTableDescriptor htd = new HTableDescriptor(TableName.valueOf("testIllegalTableDescriptor")); HColumnDescriptor hcd = new HColumnDescriptor(FAMILY); - // create table with 0 families - checkTableIsIllegal(htd); htd.addFamily(hcd); checkTableIsLegal(htd); @@ -5297,6 +5295,29 @@ public class TestFromClientSide { htd.setConfiguration("hbase.table.sanity.checks", Boolean.FALSE.toString()); checkTableIsLegal(htd); + // create table with 0 families, fail even with hbase.table.sanity.checks set as FALSE + HTableDescriptor htdCf = new HTableDescriptor(TableName.valueOf("testcf")); + HColumnDescriptor hcdCf = new HColumnDescriptor(FAMILY); + htdCf.setConfiguration("hbase.table.sanity.checks", Boolean.FALSE.toString()); + checkTableIsIllegal(htdCf); + + htdCf.addFamily(hcdCf); + + Admin admin = TEST_UTIL.getHBaseAdmin(); + admin.createTable(htdCf); + assertTrue(admin.tableExists(htdCf.getTableName())); + admin.disableTable(htdCf.getTableName()); + htdCf.removeFamily(FAMILY); + // modify table with 0 family will fail + try { + admin.modifyTable(htdCf.getTableName(), htdCf); + fail(); + } catch (Exception ex) { + + } finally { + admin.deleteTable(htdCf.getTableName()); + } + assertFalse(listAppender.getMessages().isEmpty()); assertTrue(listAppender.getMessages().get(0).startsWith("MEMSTORE_FLUSHSIZE for table " + "descriptor or \"hbase.hregion.memstore.flush.size\" (0) is too small, which might " diff --git hbase-server/src/test/java/org/apache/hadoop/hbase/namespace/TestNamespaceAuditor.java hbase-server/src/test/java/org/apache/hadoop/hbase/namespace/TestNamespaceAuditor.java index e3b841b..78fde21 100644 --- hbase-server/src/test/java/org/apache/hadoop/hbase/namespace/TestNamespaceAuditor.java +++ hbase-server/src/test/java/org/apache/hadoop/hbase/namespace/TestNamespaceAuditor.java @@ -148,12 +148,17 @@ public class TestNamespaceAuditor { ADMIN.createNamespace(nspDesc); assertNotNull("Namespace descriptor found null.", ADMIN.getNamespaceDescriptor(nsp)); assertEquals(ADMIN.listNamespaceDescriptors().length, 3); + HColumnDescriptor fam1 = new HColumnDescriptor("fam1"); + HTableDescriptor tableDescOne = new HTableDescriptor(TableName.valueOf(nsp + TableName.NAMESPACE_DELIM + "table1")); + tableDescOne.addFamily(fam1); HTableDescriptor tableDescTwo = new HTableDescriptor(TableName.valueOf(nsp + TableName.NAMESPACE_DELIM + "table2")); + tableDescTwo.addFamily(fam1); HTableDescriptor tableDescThree = new HTableDescriptor(TableName.valueOf(nsp + TableName.NAMESPACE_DELIM + "table3")); + tableDescThree.addFamily(fam1); ADMIN.createTable(tableDescOne); boolean constraintViolated = false; try { @@ -252,10 +257,13 @@ public class TestNamespaceAuditor { assertNotNull("Namespace descriptor found null.", ADMIN.getNamespaceDescriptor(namespace)); NamespaceTableAndRegionInfo stateInfo = getNamespaceState(nspDesc.getName()); assertNotNull("Namespace state found null for " + namespace, stateInfo); + HColumnDescriptor fam1 = new HColumnDescriptor("fam1"); HTableDescriptor tableDescOne = new HTableDescriptor(TableName.valueOf(namespace + TableName.NAMESPACE_DELIM + "table1")); + tableDescOne.addFamily(fam1); HTableDescriptor tableDescTwo = new HTableDescriptor(TableName.valueOf(namespace + TableName.NAMESPACE_DELIM + "table2")); + tableDescTwo.addFamily(fam1); ADMIN.createTable(tableDescOne); ADMIN.createTable(tableDescTwo, Bytes.toBytes("AAA"), Bytes.toBytes("ZZZ"), 5); stateInfo = getNamespaceState(nspDesc.getName()); @@ -598,9 +606,13 @@ public class TestNamespaceAuditor { TableName tableOne = TableName.valueOf(nsp1 + TableName.NAMESPACE_DELIM + "table1"); TableName tableTwo = TableName.valueOf(nsp1 + TableName.NAMESPACE_DELIM + "table2"); TableName tableThree = TableName.valueOf(nsp1 + TableName.NAMESPACE_DELIM + "table3"); + HColumnDescriptor fam1 = new HColumnDescriptor("fam1"); HTableDescriptor tableDescOne = new HTableDescriptor(tableOne); + tableDescOne.addFamily(fam1); HTableDescriptor tableDescTwo = new HTableDescriptor(tableTwo); + tableDescTwo.addFamily(fam1); HTableDescriptor tableDescThree = new HTableDescriptor(tableThree); + tableDescThree.addFamily(fam1); ADMIN.createTable(tableDescOne, Bytes.toBytes("1"), Bytes.toBytes("1000"), 3); ADMIN.createTable(tableDescTwo, Bytes.toBytes("1"), Bytes.toBytes("1000"), 3); ADMIN.createTable(tableDescThree, Bytes.toBytes("1"), Bytes.toBytes("1000"), 4); @@ -690,10 +702,13 @@ public class TestNamespaceAuditor { ADMIN.createNamespace(nspDesc); assertNotNull("Namespace descriptor found null.", ADMIN.getNamespaceDescriptor(nsp)); assertEquals(ADMIN.listNamespaceDescriptors().length, 3); + HColumnDescriptor fam1 = new HColumnDescriptor("fam1"); HTableDescriptor tableDescOne = new HTableDescriptor(TableName.valueOf(nsp + TableName.NAMESPACE_DELIM + "table1")); + tableDescOne.addFamily(fam1); HTableDescriptor tableDescTwo = new HTableDescriptor(TableName.valueOf(nsp + TableName.NAMESPACE_DELIM + "table2")); + tableDescTwo.addFamily(fam1); ADMIN.createTable(tableDescOne); ADMIN.createTable(tableDescTwo, Bytes.toBytes("AAA"), Bytes.toBytes("ZZZ"), 4); } @@ -708,7 +723,9 @@ public class TestNamespaceAuditor { assertNotNull("Namespace descriptor found null.", ADMIN.getNamespaceDescriptor(nsp)); TableName tableName = TableName.valueOf(nsp + TableName.NAMESPACE_DELIM + "table1"); TableName cloneTableName = TableName.valueOf(nsp + TableName.NAMESPACE_DELIM + "table2"); + HColumnDescriptor fam1 = new HColumnDescriptor("fam1"); HTableDescriptor tableDescOne = new HTableDescriptor(tableName); + tableDescOne.addFamily(fam1); ADMIN.createTable(tableDescOne); String snapshot = "snapshot_testTableQuotaExceedWithCloneSnapshot"; ADMIN.snapshot(snapshot, tableName); @@ -726,7 +743,10 @@ public class TestNamespaceAuditor { assertNotNull("Namespace descriptor found null.", ADMIN.getNamespaceDescriptor(nsp)); TableName tableName = TableName.valueOf(nsp + TableName.NAMESPACE_DELIM + "table1"); TableName cloneTableName = TableName.valueOf(nsp + TableName.NAMESPACE_DELIM + "table2"); + + HColumnDescriptor fam1 = new HColumnDescriptor("fam1"); HTableDescriptor tableDescOne = new HTableDescriptor(tableName); + tableDescOne.addFamily(fam1); ADMIN.createTable(tableDescOne, Bytes.toBytes("AAA"), Bytes.toBytes("ZZZ"), 4); String snapshot = "snapshot_testCloneSnapshot"; @@ -761,6 +781,8 @@ public class TestNamespaceAuditor { assertNotNull("Namespace descriptor found null.", ADMIN.getNamespaceDescriptor(nsp)); TableName tableName1 = TableName.valueOf(nsp + TableName.NAMESPACE_DELIM + "table1"); HTableDescriptor tableDescOne = new HTableDescriptor(tableName1); + HColumnDescriptor fam1 = new HColumnDescriptor("fam1"); + tableDescOne.addFamily(fam1); ADMIN.createTable(tableDescOne, Bytes.toBytes("AAA"), Bytes.toBytes("ZZZ"), 4); NamespaceTableAndRegionInfo nstate = getNamespaceState(nsp); @@ -796,6 +818,9 @@ public class TestNamespaceAuditor { assertNotNull("Namespace descriptor found null.", ndesc); TableName tableName1 = TableName.valueOf(nsp + TableName.NAMESPACE_DELIM + "table1"); HTableDescriptor tableDescOne = new HTableDescriptor(tableName1); + HColumnDescriptor fam1 = new HColumnDescriptor("fam1"); + tableDescOne.addFamily(fam1); + ADMIN.createTable(tableDescOne, Bytes.toBytes("AAA"), Bytes.toBytes("ZZZ"), 4); NamespaceTableAndRegionInfo nstate = getNamespaceState(nsp); diff --git hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestRegionMover.java hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestRegionMover.java index 0ecf1eb..a75ff2b 100644 --- hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestRegionMover.java +++ hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestRegionMover.java @@ -35,6 +35,7 @@ import org.apache.hadoop.hbase.client.Admin; import org.apache.hadoop.hbase.regionserver.HRegionServer; import org.apache.hadoop.hbase.testclassification.MediumTests; import org.apache.hadoop.hbase.util.RegionMover.RegionMoverBuilder; +import org.apache.hadoop.hbase.HColumnDescriptor; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -70,6 +71,9 @@ public class TestRegionMover { TEST_UTIL.deleteTable(tableName); } HTableDescriptor tableDesc = new HTableDescriptor(tableName); + HColumnDescriptor fam1 = new HColumnDescriptor("fam1"); + tableDesc.addFamily(fam1); + try { admin.setBalancerRunning(false, true); String startKey = "a";