diff --git hbase-client/src/main/java/org/apache/hadoop/hbase/NamespaceExistException.java hbase-client/src/main/java/org/apache/hadoop/hbase/NamespaceExistException.java new file mode 100644 index 0000000..a0a0823 --- /dev/null +++ hbase-client/src/main/java/org/apache/hadoop/hbase/NamespaceExistException.java @@ -0,0 +1,39 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.hbase; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; + +/** + * Thrown when a namespace exists but should not + */ +@InterfaceAudience.Public +@InterfaceStability.Stable +public class NamespaceExistException extends DoNotRetryIOException { + + private static final long serialVersionUID = -1582357514338825412L; + + public NamespaceExistException() { + } + + public NamespaceExistException(String namespace) { + super(namespace); + } +} diff --git hbase-client/src/main/java/org/apache/hadoop/hbase/NamespaceNotFoundException.java hbase-client/src/main/java/org/apache/hadoop/hbase/NamespaceNotFoundException.java new file mode 100644 index 0000000..f4f5dcc --- /dev/null +++ hbase-client/src/main/java/org/apache/hadoop/hbase/NamespaceNotFoundException.java @@ -0,0 +1,39 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.hbase; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; + +/** + * Thrown when a namespace can not be located + */ +@InterfaceAudience.Public +@InterfaceStability.Stable +public class NamespaceNotFoundException extends DoNotRetryIOException { + + private static final long serialVersionUID = -6673607347330260324L; + + public NamespaceNotFoundException() { + } + + public NamespaceNotFoundException(String namespace) { + super(namespace); + } +} diff --git hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java index 82d77e9..13eed87 100644 --- hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java +++ hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java @@ -42,8 +42,6 @@ import java.util.concurrent.atomic.AtomicReference; import javax.management.ObjectName; -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.classification.InterfaceAudience; @@ -53,22 +51,21 @@ import org.apache.hadoop.hbase.Abortable; import org.apache.hadoop.hbase.Chore; import org.apache.hadoop.hbase.ClusterId; import org.apache.hadoop.hbase.ClusterStatus; -import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.HBaseIOException; -import org.apache.hadoop.hbase.NamespaceDescriptor; -import org.apache.hadoop.hbase.constraint.ConstraintException; -import org.apache.hadoop.hbase.exceptions.DeserializationException; import org.apache.hadoop.hbase.HColumnDescriptor; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.HTableDescriptor; import org.apache.hadoop.hbase.HealthCheckChore; import org.apache.hadoop.hbase.MasterNotRunningException; +import org.apache.hadoop.hbase.NamespaceDescriptor; +import org.apache.hadoop.hbase.NamespaceNotFoundException; import org.apache.hadoop.hbase.PleaseHoldException; import org.apache.hadoop.hbase.Server; import org.apache.hadoop.hbase.ServerLoad; import org.apache.hadoop.hbase.ServerName; import org.apache.hadoop.hbase.TableDescriptors; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.TableNotDisabledException; import org.apache.hadoop.hbase.TableNotFoundException; import org.apache.hadoop.hbase.UnknownRegionException; @@ -80,13 +77,14 @@ import org.apache.hadoop.hbase.client.MetaScanner.MetaScannerVisitor; import org.apache.hadoop.hbase.client.MetaScanner.MetaScannerVisitorBase; import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.coprocessor.CoprocessorHost; +import org.apache.hadoop.hbase.exceptions.DeserializationException; import org.apache.hadoop.hbase.exceptions.MergeRegionException; import org.apache.hadoop.hbase.exceptions.UnknownProtocolException; import org.apache.hadoop.hbase.executor.ExecutorService; import org.apache.hadoop.hbase.executor.ExecutorType; +import org.apache.hadoop.hbase.ipc.RequestContext; import org.apache.hadoop.hbase.ipc.RpcServer; import org.apache.hadoop.hbase.ipc.RpcServer.BlockingServiceAndInterface; -import org.apache.hadoop.hbase.ipc.RequestContext; import org.apache.hadoop.hbase.ipc.RpcServerInterface; import org.apache.hadoop.hbase.ipc.ServerRpcController; import org.apache.hadoop.hbase.ipc.SimpleRpcScheduler; @@ -222,7 +220,9 @@ import org.apache.hadoop.net.DNS; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.Watcher; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import com.google.protobuf.Descriptors; import com.google.protobuf.Message; import com.google.protobuf.RpcCallback; @@ -369,7 +369,7 @@ MasterServices, Server { /** The health check chore. */ private HealthCheckChore healthCheckChore; - + /** * is in distributedLogReplay mode. When true, SplitLogWorker directly replays WAL edits to newly * assigned region servers instead of creating recovered.edits files. @@ -499,7 +499,7 @@ MasterServices, Server { } } - distributedLogReplay = this.conf.getBoolean(HConstants.DISTRIBUTED_LOG_REPLAY_KEY, + distributedLogReplay = this.conf.getBoolean(HConstants.DISTRIBUTED_LOG_REPLAY_KEY, HConstants.DEFAULT_DISTRIBUTED_LOG_REPLAY_CONFIG); } @@ -1455,6 +1455,7 @@ MasterServices, Server { return !isStopped(); } + @Override public IsMasterRunningResponse isMasterRunning(RpcController c, IsMasterRunningRequest req) throws ServiceException { return IsMasterRunningResponse.newBuilder().setIsMasterRunning(isMasterRunning()).build(); @@ -1812,9 +1813,7 @@ MasterServices, Server { } String namespace = hTableDescriptor.getTableName().getNamespaceAsString(); - if (getNamespaceDescriptor(namespace) == null) { - throw new ConstraintException("Namespace " + namespace + " does not exist"); - } + getNamespaceDescriptor(namespace); // ensure namespace exists HRegionInfo[] newRegions = getHRegionInfos(hTableDescriptor, splitKeys); checkInitialized(); @@ -2195,6 +2194,7 @@ MasterServices, Server { } } Collections.sort(backupMasters, new Comparator() { + @Override public int compare(ServerName s1, ServerName s2) { return s1.getServerName().compareTo(s2.getServerName()); }}); @@ -2302,6 +2302,7 @@ MasterServices, Server { this.zooKeeper.reconnectAfterExpiration(); Callable callable = new Callable () { + @Override public Boolean call() throws InterruptedException, IOException, KeeperException { MonitoredTask status = @@ -2474,6 +2475,7 @@ MasterServices, Server { return this.stopped; } + @Override public boolean isAborted() { return this.abort; } @@ -2505,6 +2507,7 @@ MasterServices, Server { * * @return true if master is ready to go, false if not. */ + @Override public boolean isInitialized() { return initialized; } @@ -2514,6 +2517,7 @@ MasterServices, Server { * assignMeta to prevent processing of ServerShutdownHandler. * @return true if assignMeta has completed; */ + @Override public boolean isServerShutdownHandlerEnabled() { return this.serverShutdownHandlerEnabled; } @@ -2612,6 +2616,7 @@ MasterServices, Server { * @return GetTableDescriptorsResponse * @throws ServiceException */ + @Override public GetTableDescriptorsResponse getTableDescriptors( RpcController controller, GetTableDescriptorsRequest req) throws ServiceException { List descriptors = new ArrayList(); @@ -2680,6 +2685,7 @@ MasterServices, Server { * @return GetTableNamesResponse * @throws ServiceException */ + @Override public GetTableNamesResponse getTableNames( RpcController controller, GetTableNamesRequest req) throws ServiceException { try { @@ -3121,6 +3127,7 @@ MasterServices, Server { return org.apache.commons.lang.StringUtils.isNotBlank(healthScriptLocation); } + @Override public void createNamespace(NamespaceDescriptor descriptor) throws IOException { TableName.isLegalNamespaceName(Bytes.toBytes(descriptor.getName())); if (cpHost != null) { @@ -3135,6 +3142,7 @@ MasterServices, Server { } } + @Override public void modifyNamespace(NamespaceDescriptor descriptor) throws IOException { TableName.isLegalNamespaceName(Bytes.toBytes(descriptor.getName())); if (cpHost != null) { @@ -3149,6 +3157,7 @@ MasterServices, Server { } } + @Override public void deleteNamespace(String name) throws IOException { if (cpHost != null) { if (cpHost.preDeleteNamespace(name)) { @@ -3162,19 +3171,29 @@ MasterServices, Server { } } + @Override public NamespaceDescriptor getNamespaceDescriptor(String name) throws IOException { - return tableNamespaceManager.get(name); + NamespaceDescriptor nsd = tableNamespaceManager.get(name); + if (nsd == null) { + throw new NamespaceNotFoundException(name); + } + return nsd; } + @Override public List listNamespaceDescriptors() throws IOException { return Lists.newArrayList(tableNamespaceManager.list()); } + @Override public List listTableDescriptorsByNamespace(String name) throws IOException { + getNamespaceDescriptor(name); // check that namespace exists return Lists.newArrayList(tableDescriptors.getByNamespace(name).values()); } + @Override public List listTableNamesByNamespace(String name) throws IOException { + getNamespaceDescriptor(name); // check that namespace exists List tableNames = Lists.newArrayList(); for (HTableDescriptor descriptor: tableDescriptors.getByNamespace(name).values()) { tableNames.add(descriptor.getTableName()); diff --git hbase-server/src/main/java/org/apache/hadoop/hbase/master/TableNamespaceManager.java hbase-server/src/main/java/org/apache/hadoop/hbase/master/TableNamespaceManager.java index 1a635c8..e706ef4 100644 --- hbase-server/src/main/java/org/apache/hadoop/hbase/master/TableNamespaceManager.java +++ hbase-server/src/main/java/org/apache/hadoop/hbase/master/TableNamespaceManager.java @@ -33,6 +33,8 @@ import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.HTableDescriptor; import org.apache.hadoop.hbase.NamespaceDescriptor; +import org.apache.hadoop.hbase.NamespaceExistException; +import org.apache.hadoop.hbase.NamespaceNotFoundException; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.ZKNamespaceManager; import org.apache.hadoop.hbase.catalog.MetaReader; @@ -123,7 +125,7 @@ public class TableNamespaceManager { public synchronized void create(NamespaceDescriptor ns) throws IOException { if (get(ns.getName()) != null) { - throw new ConstraintException("Namespace "+ns.getName()+" already exists"); + throw new NamespaceExistException(ns.getName()); } FileSystem fs = masterServices.getMasterFileSystem().getFileSystem(); fs.mkdirs(FSUtils.getNamespaceDir( @@ -133,7 +135,7 @@ public class TableNamespaceManager { public synchronized void update(NamespaceDescriptor ns) throws IOException { if (get(ns.getName()) == null) { - throw new ConstraintException("Namespace "+ns.getName()+" does not exist"); + throw new NamespaceNotFoundException(ns.getName()); } upsert(ns); } @@ -154,6 +156,9 @@ public class TableNamespaceManager { } public synchronized void remove(String name) throws IOException { + if (get(name) == null) { + throw new NamespaceNotFoundException(name); + } if (NamespaceDescriptor.RESERVED_NAMESPACES.contains(name)) { throw new ConstraintException("Reserved namespace "+name+" cannot be removed."); } @@ -161,7 +166,7 @@ public class TableNamespaceManager { try { tableCount = masterServices.listTableDescriptorsByNamespace(name).size(); } catch (FileNotFoundException fnfe) { - throw new ConstraintException("namespace " + name + " does not exist"); + throw new NamespaceNotFoundException(name); } if (tableCount > 0) { throw new ConstraintException("Only empty namespaces can be removed. " + diff --git hbase-server/src/test/java/org/apache/hadoop/hbase/TestNamespace.java hbase-server/src/test/java/org/apache/hadoop/hbase/TestNamespace.java index 4dd156e..9ba304f 100644 --- hbase-server/src/test/java/org/apache/hadoop/hbase/TestNamespace.java +++ hbase-server/src/test/java/org/apache/hadoop/hbase/TestNamespace.java @@ -18,7 +18,17 @@ */ package org.apache.hadoop.hbase; -import com.google.common.collect.Sets; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.util.Set; +import java.util.concurrent.Callable; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.fs.FileSystem; @@ -27,23 +37,19 @@ import org.apache.hadoop.hbase.client.Get; import org.apache.hadoop.hbase.client.HBaseAdmin; import org.apache.hadoop.hbase.client.HTable; import org.apache.hadoop.hbase.client.Put; -import org.apache.hadoop.hbase.constraint.ConstraintException; import org.apache.hadoop.hbase.master.HMaster; -import org.apache.hadoop.hbase.migration.NamespaceUpgrade; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.FSUtils; import org.apache.hadoop.hbase.zookeeper.ZKUtil; import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher; import org.junit.AfterClass; +import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.junit.experimental.categories.Category; -import java.io.IOException; -import java.util.Set; - -import static org.junit.Assert.*; +import com.google.common.collect.Sets; @Category(MediumTests.class) public class TestNamespace { @@ -117,8 +123,8 @@ public class TestNamespace { } //verify system tables aren't listed assertEquals(0, admin.listTables().length); - - //Try creating default and system namespaces. + + //Try creating default and system namespaces. boolean exceptionCaught = false; try { admin.createNamespace(NamespaceDescriptor.DEFAULT_NAMESPACE); @@ -139,7 +145,7 @@ public class TestNamespace { assertTrue(exceptionCaught); } } - + @Test public void testDeleteReservedNS() throws Exception { boolean exceptionCaught = false; @@ -192,7 +198,7 @@ public class TestNamespace { LOG.info(testName); byte[] tableName = Bytes.toBytes("my_table"); - byte[] tableNameFoo = Bytes.toBytes(nsName+".my_table"); + byte[] tableNameFoo = Bytes.toBytes(nsName+":my_table"); //create namespace and verify admin.createNamespace(NamespaceDescriptor.create(nsName).build()); TEST_UTIL.createTable(tableName, Bytes.toBytes(nsName)); @@ -219,8 +225,8 @@ public class TestNamespace { desc.addFamily(colDesc); try { admin.createTable(desc); - fail("Expected no namespace constraint exception"); - } catch (ConstraintException ex) { + fail("Expected no namespace exists exception"); + } catch (NamespaceNotFoundException ex) { } //create table and in new namespace admin.createNamespace(NamespaceDescriptor.create(nsName).build()); @@ -262,7 +268,7 @@ public class TestNamespace { HColumnDescriptor colDesc = new HColumnDescriptor("cf1"); desc.addFamily(colDesc); admin.createTable(desc); - assertTrue(admin.listTables().length == 1); + assertTrue(admin.listTables().length == 1); admin.disableTable(desc.getTableName()); admin.deleteTable(desc.getTableName()); } @@ -307,4 +313,109 @@ public class TestNamespace { ZooKeeperWatcher.namespaceZNode).size()); } -} + @Test(timeout = 60000) + public void testNamespaceOperations() throws IOException { + admin.createNamespace(NamespaceDescriptor.create(prefix + "ns1").build()); + admin.createNamespace(NamespaceDescriptor.create(prefix + "ns2").build()); + + // create namespace that already exists + runWithExpectedException(new Callable() { + @Override + public Void call() throws Exception { + admin.createNamespace(NamespaceDescriptor.create(prefix + "ns1").build()); + return null; + } + }, NamespaceExistException.class); + + // create a table in non-existing namespace + runWithExpectedException(new Callable() { + @Override + public Void call() throws Exception { + HTableDescriptor htd = new HTableDescriptor(TableName.valueOf("non_existing_namespace", "table1")); + htd.addFamily(new HColumnDescriptor("family1")); + admin.createTable(htd); + return null; + } + }, NamespaceNotFoundException.class); + + // get descriptor for existing namespace + admin.getNamespaceDescriptor(prefix + "ns1"); + + // get descriptor for non-existing namespace + runWithExpectedException(new Callable() { + @Override + public NamespaceDescriptor call() throws Exception { + return admin.getNamespaceDescriptor("non_existing_namespace"); + } + }, NamespaceNotFoundException.class); + + // delete descriptor for existing namespace + admin.deleteNamespace(prefix + "ns2"); + + // delete descriptor for non-existing namespace + runWithExpectedException(new Callable() { + @Override + public Void call() throws Exception { + admin.deleteNamespace("non_existing_namespace"); + return null; + } + }, NamespaceNotFoundException.class); + + // modify namespace descriptor for existing namespace + NamespaceDescriptor ns1 = admin.getNamespaceDescriptor(prefix + "ns1"); + ns1.setConfiguration("foo", "bar"); + admin.modifyNamespace(ns1); + + // modify namespace descriptor for non-existing namespace + runWithExpectedException(new Callable() { + @Override + public Void call() throws Exception { + admin.modifyNamespace(NamespaceDescriptor.create("non_existing_namespace").build()); + return null; + } + }, NamespaceNotFoundException.class); + + // get table descriptors for existing namespace + HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(prefix + "ns1", "table1")); + htd.addFamily(new HColumnDescriptor("family1")); + admin.createTable(htd); + HTableDescriptor[] htds = admin.listTableDescriptorsByNamespace(prefix + "ns1"); + assertNotNull("Should have not returned null", htds); + assertEquals("Should have returned non-empty array", 1, htds.length); + + // get table descriptors for non-existing namespace + runWithExpectedException(new Callable() { + @Override + public Void call() throws Exception { + admin.listTableDescriptorsByNamespace("non_existing_namespace"); + return null; + } + }, NamespaceNotFoundException.class); + + // get table names for existing namespace + TableName[] tableNames = admin.listTableNamesByNamespace(prefix + "ns1"); + assertNotNull("Should have not returned null", tableNames); + assertEquals("Should have returned non-empty array", 1, tableNames.length); + + // get table names for non-existing namespace + runWithExpectedException(new Callable() { + @Override + public Void call() throws Exception { + admin.listTableNamesByNamespace("non_existing_namespace"); + return null; + } + }, NamespaceNotFoundException.class); + + } + + private static void runWithExpectedException(Callable callable, Class exceptionClass) { + try { + callable.call(); + } catch(Exception ex) { + Assert.assertEquals(exceptionClass, ex.getClass()); + return; + } + fail("Should have thrown exception " + exceptionClass); + } + +} \ No newline at end of file