HBASE-9510 Namespace operations should throw clean exceptions

git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1523902 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Michael Stack 2013-09-17 05:43:06 +00:00
parent 866a2c6c42
commit 040b53e09a
3 changed files with 167 additions and 24 deletions

View File

@ -51,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;
@ -218,8 +217,11 @@ import org.apache.hadoop.metrics.util.MBeanUtil;
import org.apache.hadoop.net.DNS;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.Watcher;
import org.apache.hadoop.hbase.exceptions.DeserializationException;
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;
@ -366,7 +368,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.
@ -489,7 +491,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);
}
@ -902,7 +904,7 @@ MasterServices, Server {
status.setStatus("Starting namespace manager");
initNamespace();
}
if (this.cpHost != null) {
try {
this.cpHost.preMasterInitialization();
@ -1361,6 +1363,7 @@ MasterServices, Server {
return !isStopped();
}
@Override
public IsMasterRunningResponse isMasterRunning(RpcController c, IsMasterRunningRequest req)
throws ServiceException {
return IsMasterRunningResponse.newBuilder().setIsMasterRunning(isMasterRunning()).build();
@ -1718,9 +1721,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();
@ -2101,6 +2102,7 @@ MasterServices, Server {
}
}
Collections.sort(backupMasters, new Comparator<ServerName>() {
@Override
public int compare(ServerName s1, ServerName s2) {
return s1.getServerName().compareTo(s2.getServerName());
}});
@ -2208,6 +2210,7 @@ MasterServices, Server {
this.zooKeeper.reconnectAfterExpiration();
Callable<Boolean> callable = new Callable<Boolean> () {
@Override
public Boolean call() throws InterruptedException,
IOException, KeeperException {
MonitoredTask status =
@ -2383,6 +2386,7 @@ MasterServices, Server {
return this.stopped;
}
@Override
public boolean isAborted() {
return this.abort;
}
@ -2414,6 +2418,7 @@ MasterServices, Server {
*
* @return true if master is ready to go, false if not.
*/
@Override
public boolean isInitialized() {
return initialized;
}
@ -2423,6 +2428,7 @@ MasterServices, Server {
* assignMeta to prevent processing of ServerShutdownHandler.
* @return true if assignMeta has completed;
*/
@Override
public boolean isServerShutdownHandlerEnabled() {
return this.serverShutdownHandlerEnabled;
}
@ -2521,6 +2527,7 @@ MasterServices, Server {
* @return GetTableDescriptorsResponse
* @throws ServiceException
*/
@Override
public GetTableDescriptorsResponse getTableDescriptors(
RpcController controller, GetTableDescriptorsRequest req) throws ServiceException {
List<HTableDescriptor> descriptors = new ArrayList<HTableDescriptor>();
@ -2589,6 +2596,7 @@ MasterServices, Server {
* @return GetTableNamesResponse
* @throws ServiceException
*/
@Override
public GetTableNamesResponse getTableNames(
RpcController controller, GetTableNamesRequest req) throws ServiceException {
try {
@ -3030,6 +3038,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) {
@ -3044,6 +3053,7 @@ MasterServices, Server {
}
}
@Override
public void modifyNamespace(NamespaceDescriptor descriptor) throws IOException {
TableName.isLegalNamespaceName(Bytes.toBytes(descriptor.getName()));
if (cpHost != null) {
@ -3058,6 +3068,7 @@ MasterServices, Server {
}
}
@Override
public void deleteNamespace(String name) throws IOException {
if (cpHost != null) {
if (cpHost.preDeleteNamespace(name)) {
@ -3071,19 +3082,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<NamespaceDescriptor> listNamespaceDescriptors() throws IOException {
return Lists.newArrayList(tableNamespaceManager.list());
}
@Override
public List<HTableDescriptor> listTableDescriptorsByNamespace(String name) throws IOException {
getNamespaceDescriptor(name); // check that namespace exists
return Lists.newArrayList(tableDescriptors.getByNamespace(name).values());
}
@Override
public List<TableName> listTableNamesByNamespace(String name) throws IOException {
getNamespaceDescriptor(name); // check that namespace exists
List<TableName> tableNames = Lists.newArrayList();
for (HTableDescriptor descriptor: tableDescriptors.getByNamespace(name).values()) {
tableNames.add(descriptor.getTableName());

View File

@ -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;
@ -113,14 +115,14 @@ public class TableNamespaceManager {
nsTable = new HTable(conf, TableName.NAMESPACE_TABLE_NAME);
zkNamespaceManager = new ZKNamespaceManager(masterServices.getZooKeeper());
zkNamespaceManager.start();
if (get(nsTable, NamespaceDescriptor.DEFAULT_NAMESPACE.getName()) == null) {
create(nsTable, NamespaceDescriptor.DEFAULT_NAMESPACE);
}
if (get(nsTable, NamespaceDescriptor.SYSTEM_NAMESPACE.getName()) == null) {
create(nsTable, NamespaceDescriptor.SYSTEM_NAMESPACE);
}
ResultScanner scanner = nsTable.getScanner(HTableDescriptor.NAMESPACE_FAMILY_INFO_BYTES);
try {
for(Result result : scanner) {
@ -160,7 +162,7 @@ public class TableNamespaceManager {
public synchronized void update(NamespaceDescriptor ns) throws IOException {
HTable table = getNamespaceTable();
if (get(table, ns.getName()) == null) {
throw new ConstraintException("Namespace "+ns.getName()+" does not exist");
throw new NamespaceNotFoundException(ns.getName());
}
upsert(table, ns);
}
@ -179,7 +181,7 @@ public class TableNamespaceManager {
private void create(HTable table, NamespaceDescriptor ns) throws IOException {
if (get(table, 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(
@ -203,6 +205,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.");
}
@ -210,7 +215,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. " +

View File

@ -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;
@ -33,7 +43,9 @@ 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 com.google.common.collect.Sets;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
@ -117,8 +129,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 +151,7 @@ public class TestNamespace {
assertTrue(exceptionCaught);
}
}
@Test
public void testDeleteReservedNS() throws Exception {
boolean exceptionCaught = false;
@ -192,7 +204,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 +231,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 +274,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 +319,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<Void>() {
@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<Void>() {
@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<NamespaceDescriptor>() {
@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<Void>() {
@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<Void>() {
@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<Void>() {
@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<Void>() {
@Override
public Void call() throws Exception {
admin.listTableNamesByNamespace("non_existing_namespace");
return null;
}
}, NamespaceNotFoundException.class);
}
private static <V, E> void runWithExpectedException(Callable<V> callable, Class<E> exceptionClass) {
try {
callable.call();
} catch(Exception ex) {
Assert.assertEquals(exceptionClass, ex.getClass());
return;
}
fail("Should have thrown exception " + exceptionClass);
}
}