diff --git a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/HMSHandler.java b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/HMSHandler.java index 76eedeadb617..48465aefda1e 100644 --- a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/HMSHandler.java +++ b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/HMSHandler.java @@ -206,78 +206,11 @@ public void shutdown() { @Override public void create_catalog(CreateCatalogRequest rqst) throws AlreadyExistsException, InvalidObjectException, MetaException { - Catalog catalog = rqst.getCatalog(); - startFunction("create_catalog", ": " + catalog.toString()); + startFunction("create_catalog", ": " + rqst.getCatalog().toString()); boolean success = false; Exception ex = null; try { - try { - getMS().getCatalog(catalog.getName()); - throw new AlreadyExistsException("Catalog " + catalog.getName() + " already exists"); - } catch (NoSuchObjectException e) { - // expected - } - - if (!MetaStoreUtils.validateName(catalog.getName(), null)) { - throw new InvalidObjectException(catalog.getName() + " is not a valid catalog name"); - } - - if (catalog.getLocationUri() == null) { - throw new InvalidObjectException("You must specify a path for the catalog"); - } - - RawStore ms = getMS(); - Path catPath = new Path(catalog.getLocationUri()); - boolean madeDir = false; - Map transactionalListenersResponses = Collections.emptyMap(); - try { - firePreEvent(new PreCreateCatalogEvent(this, catalog)); - if (!wh.isDir(catPath)) { - if (!wh.mkdirs(catPath)) { - throw new MetaException("Unable to create catalog path " + catPath + - ", failed to create catalog " + catalog.getName()); - } - madeDir = true; - } - // set the create time of catalog - long time = System.currentTimeMillis() / 1000; - catalog.setCreateTime((int) time); - ms.openTransaction(); - ms.createCatalog(catalog); - - // Create a default database inside the catalog - CreateDatabaseRequest cdr = new CreateDatabaseRequest(DEFAULT_DATABASE_NAME); - cdr.setCatalogName(catalog.getName()); - cdr.setLocationUri(catalog.getLocationUri()); - cdr.setParameters(Collections.emptyMap()); - cdr.setDescription("Default database for catalog " + catalog.getName()); - AbstractRequestHandler.offer(this, cdr).getResult(); - - if (!transactionalListeners.isEmpty()) { - transactionalListenersResponses = - MetaStoreListenerNotifier.notifyEvent(transactionalListeners, - EventType.CREATE_CATALOG, - new CreateCatalogEvent(true, this, catalog)); - } - - success = ms.commitTransaction(); - } finally { - if (!success) { - ms.rollbackTransaction(); - if (madeDir) { - wh.deleteDir(catPath, false, false); - } - } - - if (!listeners.isEmpty()) { - MetaStoreListenerNotifier.notifyEvent(listeners, - EventType.CREATE_CATALOG, - new CreateCatalogEvent(success, this, catalog), - null, - transactionalListenersResponses, ms); - } - } - success = true; + success = AbstractRequestHandler.offer(this, rqst).success(); } catch (Exception e) { ex = e; throw handleException(e) @@ -293,44 +226,14 @@ public void alter_catalog(AlterCatalogRequest rqst) throws TException { startFunction("alter_catalog " + rqst.getName()); boolean success = false; Exception ex = null; - RawStore ms = getMS(); - Map transactionalListenersResponses = Collections.emptyMap(); - GetCatalogResponse oldCat = null; - try { - oldCat = get_catalog(new GetCatalogRequest(rqst.getName())); - // Above should have thrown NoSuchObjectException if there is no such catalog - assert oldCat != null && oldCat.getCatalog() != null; - firePreEvent(new PreAlterCatalogEvent(oldCat.getCatalog(), rqst.getNewCat(), this)); - - ms.openTransaction(); - ms.alterCatalog(rqst.getName(), rqst.getNewCat()); - - if (!transactionalListeners.isEmpty()) { - transactionalListenersResponses = - MetaStoreListenerNotifier.notifyEvent(transactionalListeners, - EventType.ALTER_CATALOG, - new AlterCatalogEvent(oldCat.getCatalog(), rqst.getNewCat(), true, this)); - } - - success = ms.commitTransaction(); - } catch (MetaException|NoSuchObjectException e) { + success = AbstractRequestHandler.offer(this, rqst).success(); + } catch (Exception e) { ex = e; - throw e; + throw handleException(e).defaultTException(); } finally { - if (!success) { - ms.rollbackTransaction(); - } - - if ((null != oldCat) && (!listeners.isEmpty())) { - MetaStoreListenerNotifier.notifyEvent(listeners, - EventType.ALTER_CATALOG, - new AlterCatalogEvent(oldCat.getCatalog(), rqst.getNewCat(), success, this), - null, transactionalListenersResponses, ms); - } endFunction("alter_catalog", success, ex); } - } @Override @@ -373,19 +276,11 @@ public GetCatalogsResponse get_catalogs() throws MetaException { @Override public void drop_catalog(DropCatalogRequest rqst) throws NoSuchObjectException, InvalidOperationException, MetaException { - String catName = rqst.getName(); - boolean ifExists = rqst.isIfExists(); - startFunction("drop_catalog", ": " + catName); - if (DEFAULT_CATALOG_NAME.equalsIgnoreCase(catName)) { - endFunction("drop_catalog", false, null); - throw new MetaException("Can not drop " + DEFAULT_CATALOG_NAME + " catalog"); - } - + startFunction("drop_catalog", ": " + rqst.getName()); boolean success = false; Exception ex = null; try { - dropCatalogCore(catName, ifExists); - success = true; + success = AbstractRequestHandler.offer(this, rqst).success(); } catch (Exception e) { ex = e; throw handleException(e) @@ -394,73 +289,6 @@ public void drop_catalog(DropCatalogRequest rqst) } finally { endFunction("drop_catalog", success, ex); } - - } - - private void dropCatalogCore(String catName, boolean ifExists) - throws MetaException, NoSuchObjectException, InvalidOperationException { - boolean success = false; - Catalog cat = null; - Map transactionalListenerResponses = Collections.emptyMap(); - RawStore ms = getMS(); - try { - ms.openTransaction(); - cat = ms.getCatalog(catName); - - firePreEvent(new PreDropCatalogEvent(this, cat)); - - List allDbs = get_databases(prependNotNullCatToDbName(catName, null)); - if (allDbs != null && !allDbs.isEmpty()) { - // It might just be the default, in which case we can drop that one if it's empty - if (allDbs.size() == 1 && allDbs.get(0).equals(DEFAULT_DATABASE_NAME)) { - try { - DropDatabaseRequest req = new DropDatabaseRequest(); - req.setName(DEFAULT_DATABASE_NAME); - req.setCatalogName(catName); - req.setDeleteData(true); - req.setCascade(false); - drop_database_req(req); - } catch (InvalidOperationException e) { - // This means there are tables of something in the database - throw new InvalidOperationException("There are still objects in the default " + - "database for catalog " + catName); - } - } else { - throw new InvalidOperationException("There are non-default databases in the catalog " + - catName + " so it cannot be dropped."); - } - } - - ms.dropCatalog(catName); - if (!transactionalListeners.isEmpty()) { - transactionalListenerResponses = - MetaStoreListenerNotifier.notifyEvent(transactionalListeners, - EventType.DROP_CATALOG, - new DropCatalogEvent(true, this, cat)); - } - - success = ms.commitTransaction(); - } catch (NoSuchObjectException e) { - if (!ifExists) { - throw new NoSuchObjectException(e.getMessage()); - } else { - ms.rollbackTransaction(); - } - } finally { - if (success) { - wh.deleteDir(wh.getDnsPath(new Path(cat.getLocationUri())), false, false); - } else { - ms.rollbackTransaction(); - } - - if (!listeners.isEmpty()) { - MetaStoreListenerNotifier.notifyEvent(listeners, - EventType.DROP_CATALOG, - new DropCatalogEvent(success, this, cat), - null, - transactionalListenerResponses, ms); - } - } } @Override diff --git a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/handler/AlterCatalogHandler.java b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/handler/AlterCatalogHandler.java new file mode 100644 index 000000000000..5b41f242d72f --- /dev/null +++ b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/handler/AlterCatalogHandler.java @@ -0,0 +1,111 @@ +/* + * 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.hive.metastore.handler; + +import java.io.IOException; +import java.util.Collections; +import java.util.Map; + +import org.apache.hadoop.hive.metastore.HMSHandler; +import org.apache.hadoop.hive.metastore.IHMSHandler; +import org.apache.hadoop.hive.metastore.MetaStoreListenerNotifier; +import org.apache.hadoop.hive.metastore.RawStore; +import org.apache.hadoop.hive.metastore.api.AlterCatalogRequest; +import org.apache.hadoop.hive.metastore.api.Catalog; +import org.apache.hadoop.hive.metastore.api.GetCatalogRequest; +import org.apache.hadoop.hive.metastore.api.GetCatalogResponse; +import org.apache.hadoop.hive.metastore.api.MetaException; +import org.apache.hadoop.hive.metastore.events.AlterCatalogEvent; +import org.apache.hadoop.hive.metastore.events.PreAlterCatalogEvent; +import org.apache.hadoop.hive.metastore.messaging.EventMessage.EventType; +import org.apache.thrift.TException; + +@SuppressWarnings("unused") +@RequestHandler(requestBody = AlterCatalogRequest.class) +public class AlterCatalogHandler + extends AbstractRequestHandler { + private RawStore ms; + private String catName; + private Catalog newCat; + private Catalog oldCat; + + AlterCatalogHandler(IHMSHandler handler, AlterCatalogRequest request) { + super(handler, false, request); + } + + @Override + protected void beforeExecute() throws TException, IOException { + this.catName = request.getName(); + this.newCat = request.getNewCat(); + this.ms = handler.getMS(); + GetCatalogResponse oldCatResp = ((HMSHandler) handler).get_catalog(new GetCatalogRequest(catName)); + if (oldCatResp == null || oldCatResp.getCatalog() == null) { + throw new MetaException("Catalog " + catName + " has no catalog body"); + } + this.oldCat = oldCatResp.getCatalog(); + ((HMSHandler) handler).firePreEvent(new PreAlterCatalogEvent(oldCat, newCat, handler)); + } + + @Override + protected AlterCatalogResult execute() throws TException, IOException { + boolean success = false; + Map transactionalListenersResponses = Collections.emptyMap(); + ms.openTransaction(); + try { + ms.alterCatalog(catName, newCat); + + if (!handler.getTransactionalListeners().isEmpty()) { + transactionalListenersResponses = + MetaStoreListenerNotifier.notifyEvent(handler.getTransactionalListeners(), + EventType.ALTER_CATALOG, + new AlterCatalogEvent(oldCat, newCat, true, handler)); + } + + success = ms.commitTransaction(); + } finally { + if (!success) { + ms.rollbackTransaction(); + } + } + return new AlterCatalogResult(success, transactionalListenersResponses); + } + + @Override + protected void afterExecute(AlterCatalogResult result) throws TException, IOException { + boolean success = result != null && result.success(); + if (!handler.getListeners().isEmpty()) { + MetaStoreListenerNotifier.notifyEvent(handler.getListeners(), + EventType.ALTER_CATALOG, + new AlterCatalogEvent(oldCat, newCat, success, handler), + null, + result != null ? result.transactionalListenersResponses() : Collections.emptyMap(), ms); + } + super.afterExecute(result); + } + + @Override + public String toString() { + return "AlterCatalogHandler [" + id + "] - alter catalog " + catName + ":"; + } + + public record AlterCatalogResult(boolean success, Map transactionalListenersResponses) + implements Result { + + } +} diff --git a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/handler/CreateCatalogHandler.java b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/handler/CreateCatalogHandler.java new file mode 100644 index 000000000000..3adee68560c1 --- /dev/null +++ b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/handler/CreateCatalogHandler.java @@ -0,0 +1,146 @@ +/* + * 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.hive.metastore.handler; + +import java.io.IOException; +import java.util.Collections; +import java.util.Map; + +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.hive.metastore.HMSHandler; +import org.apache.hadoop.hive.metastore.IHMSHandler; +import org.apache.hadoop.hive.metastore.MetaStoreListenerNotifier; +import org.apache.hadoop.hive.metastore.RawStore; +import org.apache.hadoop.hive.metastore.api.AlreadyExistsException; +import org.apache.hadoop.hive.metastore.api.Catalog; +import org.apache.hadoop.hive.metastore.api.CreateCatalogRequest; +import org.apache.hadoop.hive.metastore.api.CreateDatabaseRequest; +import org.apache.hadoop.hive.metastore.api.InvalidObjectException; +import org.apache.hadoop.hive.metastore.api.MetaException; +import org.apache.hadoop.hive.metastore.api.NoSuchObjectException; +import org.apache.hadoop.hive.metastore.events.CreateCatalogEvent; +import org.apache.hadoop.hive.metastore.events.PreCreateCatalogEvent; +import org.apache.hadoop.hive.metastore.messaging.EventMessage.EventType; +import org.apache.hadoop.hive.metastore.utils.MetaStoreUtils; +import org.apache.thrift.TException; + +import static org.apache.hadoop.hive.metastore.Warehouse.DEFAULT_DATABASE_NAME; + +@SuppressWarnings("unused") +@RequestHandler(requestBody = CreateCatalogRequest.class) +public class CreateCatalogHandler + extends AbstractRequestHandler { + private RawStore ms; + private Catalog catalog; + + CreateCatalogHandler(IHMSHandler handler, CreateCatalogRequest request) { + super(handler, false, request); + } + + @Override + protected void beforeExecute() throws TException, IOException { + this.catalog = request.getCatalog(); + this.ms = handler.getMS(); + try { + ms.getCatalog(catalog.getName()); + throw new AlreadyExistsException("Catalog " + catalog.getName() + " already exists"); + } catch (NoSuchObjectException e) { + // expected — catalog does not yet exist + } + + if (!MetaStoreUtils.validateName(catalog.getName(), null)) { + throw new InvalidObjectException(catalog.getName() + " is not a valid catalog name"); + } + + if (catalog.getLocationUri() == null) { + throw new InvalidObjectException("You must specify a path for the catalog"); + } + } + + @Override + protected CreateCatalogResult execute() throws TException, IOException { + boolean success = false; + boolean madeDir = false; + Map transactionalListenersResponses = Collections.emptyMap(); + Path catPath = new Path(catalog.getLocationUri()); + try { + ((HMSHandler) handler).firePreEvent(new PreCreateCatalogEvent(handler, catalog)); + if (!handler.getWh().isDir(catPath)) { + if (!handler.getWh().mkdirs(catPath)) { + throw new MetaException("Unable to create catalog path " + catPath + + ", failed to create catalog " + catalog.getName()); + } + madeDir = true; + } + // set the create time of catalog + long time = System.currentTimeMillis() / 1000; + catalog.setCreateTime((int) time); + ms.openTransaction(); + ms.createCatalog(catalog); + + // Create a default database inside the catalog + CreateDatabaseRequest cdr = new CreateDatabaseRequest(DEFAULT_DATABASE_NAME); + cdr.setCatalogName(catalog.getName()); + cdr.setLocationUri(catalog.getLocationUri()); + cdr.setParameters(Collections.emptyMap()); + cdr.setDescription("Default database for catalog " + catalog.getName()); + AbstractRequestHandler.offer(handler, cdr).getResult(); + + if (!handler.getTransactionalListeners().isEmpty()) { + transactionalListenersResponses = + MetaStoreListenerNotifier.notifyEvent(handler.getTransactionalListeners(), + EventType.CREATE_CATALOG, + new CreateCatalogEvent(true, handler, catalog)); + } + + success = ms.commitTransaction(); + } finally { + if (!success) { + ms.rollbackTransaction(); + if (madeDir) { + handler.getWh().deleteDir(catPath, false, false); + } + } + } + return new CreateCatalogResult(success, transactionalListenersResponses); + } + + @Override + protected void afterExecute(CreateCatalogResult result) throws TException, IOException { + boolean success = result != null && result.success(); + if (!handler.getListeners().isEmpty()) { + MetaStoreListenerNotifier.notifyEvent(handler.getListeners(), + EventType.CREATE_CATALOG, + new CreateCatalogEvent(success, handler, catalog), + null, + result != null ? result.transactionalListenersResponses() : Collections.emptyMap(), ms); + } + super.afterExecute(result); + } + + @Override + public String toString() { + return "CreateCatalogHandler [" + id + "] - create catalog " + catalog.getName() + ":"; + } + + public record CreateCatalogResult(boolean success, + Map transactionalListenersResponses) implements Result { + + } +} diff --git a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/handler/DropCatalogHandler.java b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/handler/DropCatalogHandler.java new file mode 100644 index 000000000000..a2eb32e370af --- /dev/null +++ b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/handler/DropCatalogHandler.java @@ -0,0 +1,143 @@ +/* + * 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.hive.metastore.handler; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.hive.metastore.HMSHandler; +import org.apache.hadoop.hive.metastore.IHMSHandler; +import org.apache.hadoop.hive.metastore.MetaStoreListenerNotifier; +import org.apache.hadoop.hive.metastore.RawStore; +import org.apache.hadoop.hive.metastore.api.Catalog; +import org.apache.hadoop.hive.metastore.api.DropCatalogRequest; +import org.apache.hadoop.hive.metastore.api.DropDatabaseRequest; +import org.apache.hadoop.hive.metastore.api.InvalidOperationException; +import org.apache.hadoop.hive.metastore.api.MetaException; +import org.apache.hadoop.hive.metastore.api.NoSuchObjectException; +import org.apache.hadoop.hive.metastore.events.DropCatalogEvent; +import org.apache.hadoop.hive.metastore.events.PreDropCatalogEvent; +import org.apache.hadoop.hive.metastore.messaging.EventMessage.EventType; +import org.apache.thrift.TException; + +import static org.apache.hadoop.hive.metastore.Warehouse.DEFAULT_CATALOG_NAME; +import static org.apache.hadoop.hive.metastore.Warehouse.DEFAULT_DATABASE_NAME; +import static org.apache.hadoop.hive.metastore.utils.MetaStoreUtils.prependNotNullCatToDbName; + +@SuppressWarnings("unused") +@RequestHandler(requestBody = DropCatalogRequest.class) +public class DropCatalogHandler + extends AbstractRequestHandler { + private RawStore ms; + private Catalog cat; + private String catName; + + DropCatalogHandler(IHMSHandler handler, DropCatalogRequest request) { + super(handler, false, request); + } + + @Override + protected void beforeExecute() throws TException, IOException { + this.catName = request.getName(); + this.ms = handler.getMS(); + if (DEFAULT_CATALOG_NAME.equalsIgnoreCase(catName)) { + throw new MetaException("Can not drop " + DEFAULT_CATALOG_NAME + " catalog"); + } + } + + @Override + protected DropCatalogResult execute() throws TException, IOException { + boolean success = false; + Map transactionalListenerResponses = Collections.emptyMap(); + try { + ms.openTransaction(); + cat = ms.getCatalog(catName); + + ((HMSHandler) handler).firePreEvent(new PreDropCatalogEvent(handler, cat)); + + List allDbs = ((HMSHandler) handler).get_databases(prependNotNullCatToDbName(catName, null)); + if (allDbs != null && !allDbs.isEmpty()) { + // Only the default database may remain; drop it if it is empty + if (allDbs.size() == 1 && allDbs.get(0).equals(DEFAULT_DATABASE_NAME)) { + try { + DropDatabaseRequest req = new DropDatabaseRequest(); + req.setName(DEFAULT_DATABASE_NAME); + req.setCatalogName(catName); + req.setDeleteData(true); + req.setCascade(false); + ((HMSHandler) handler).drop_database_req(req); + } catch (InvalidOperationException e) { + throw new InvalidOperationException("There are still objects in the default " + + "database for catalog " + catName); + } + } else { + throw new InvalidOperationException("There are non-default databases in the catalog " + + catName + " so it cannot be dropped."); + } + } + + ms.dropCatalog(catName); + if (!handler.getTransactionalListeners().isEmpty()) { + transactionalListenerResponses = + MetaStoreListenerNotifier.notifyEvent(handler.getTransactionalListeners(), + EventType.DROP_CATALOG, + new DropCatalogEvent(true, handler, cat)); + } + + success = ms.commitTransaction(); + } catch (NoSuchObjectException e) { + if (!request.isIfExists()) { + throw new NoSuchObjectException(e.getMessage()); + } + success = true; + } finally { + if (success && cat != null) { + handler.getWh().deleteDir(handler.getWh().getDnsPath(new Path(cat.getLocationUri())), false, false); + } else { + ms.rollbackTransaction(); + } + } + return new DropCatalogResult(success, transactionalListenerResponses); + } + + @Override + protected void afterExecute(DropCatalogResult result) throws TException, IOException { + if (!handler.getListeners().isEmpty()) { + MetaStoreListenerNotifier.notifyEvent(handler.getListeners(), + EventType.DROP_CATALOG, + new DropCatalogEvent(result != null && result.success(), handler, cat), + null, + result != null ? result.transactionalListenerResponses() : Collections.emptyMap(), ms); + } + super.afterExecute(result); + } + + @Override + public String toString() { + return "DropCatalogHandler [" + id + "] - drop catalog " + catName + ":"; + } + + public record DropCatalogResult(boolean success, + Map transactionalListenerResponses) implements Result { + + } +}