package com.tesora.dve.sql.statement.ddl; /* * #%L * Tesora Inc. * Database Virtualization Engine * %% * Copyright (C) 2011 - 2014 Tesora Inc. * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ import java.util.HashMap; import java.util.List; import com.tesora.dve.common.catalog.CatalogDAO; import com.tesora.dve.common.catalog.CatalogEntity; import com.tesora.dve.common.catalog.Container; import com.tesora.dve.common.catalog.PersistentGroup; import com.tesora.dve.common.catalog.UserDatabase; import com.tesora.dve.common.catalog.UserTable; import com.tesora.dve.exceptions.PEException; import com.tesora.dve.groupmanager.GroupManager; import com.tesora.dve.locking.ClusterLock; import com.tesora.dve.queryplan.QueryStepDDLGeneralOperation.DDLCallback; import com.tesora.dve.server.connectionmanager.SSConnection; import com.tesora.dve.server.messaging.SQLCommand; import com.tesora.dve.sql.SchemaException; import com.tesora.dve.sql.ParserException.Pass; import com.tesora.dve.sql.parser.TranslatorUtils; import com.tesora.dve.sql.schema.PEPersistentGroup; import com.tesora.dve.sql.schema.Persistable; import com.tesora.dve.sql.schema.SchemaContext; import com.tesora.dve.sql.schema.cache.CacheInvalidationRecord; import com.tesora.dve.sql.transform.execution.ExecutionStep; import com.tesora.dve.sql.transform.execution.ComplexDDLExecutionStep; import com.tesora.dve.worker.WorkerGroup; public class PEDropStorageGroupStatement extends PEDropStatement<PEPersistentGroup, PersistentGroup> { public PEDropStorageGroupStatement( Persistable<PEPersistentGroup, PersistentGroup> targ) { super(PEPersistentGroup.class, null, true, targ, TranslatorUtils.PERSISTENT_GROUP_TAG); } public void ensureUnreferenced(SchemaContext pc) { try { String any = getReferencingUserData(pc,getTarget().get()); if (any != null) throw new SchemaException(Pass.PLANNER, "Unable to drop persistent group " + getTarget().get().getName() + " because used by " + any); } catch (PEException pe) { throw new SchemaException(Pass.PLANNER, "Unable to compute referenced set of persistent group",pe); } } private String getReferencingUserData(SchemaContext sc, PEPersistentGroup pesg) throws PEException { sc.beginSaveContext(); PersistentGroup pg = null; try { pesg.persistTree(sc,true); pg = pesg.getPersistent(sc); } finally { sc.endSaveContext(); } HashMap<String,Object> params = new HashMap<String, Object>(); params.put("pg",pg); // find any database that references the group as a persistent group List<CatalogEntity> any = sc.getCatalog().query("from UserDatabase where defaultStorageGroup = :pg", params); if (!any.isEmpty()) return "database " + ((UserDatabase)any.get(0)).getName(); // now check tables any = sc.getCatalog().query("from UserTable where persistentGroup = :pg", params); if (!any.isEmpty()) return "table " + ((UserTable)any.get(0)).getName(); // containers any = sc.getCatalog().query("from Container where storageGroup = :pg", params); if (!any.isEmpty()) return "container " + ((Container)any.get(0)).getName(); return null; } @Override protected ExecutionStep buildStep(SchemaContext sc) throws PEException { return new ComplexDDLExecutionStep(getDatabase(sc), getTarget().get(), getRoot(), getAction(), new DropStorageGroupCallback(getDeleteObjects(sc),getCatalogObjects(sc),getInvalidationRecord(sc))); } private static class DropStorageGroupCallback extends DDLCallback { private final CacheInvalidationRecord invalid; private final List<CatalogEntity> toDelete; private final List<CatalogEntity> toUpdate; private ClusterLock xlock; public DropStorageGroupCallback(List<CatalogEntity> toDelete, List<CatalogEntity> toUpdate, CacheInvalidationRecord record) { super(); this.toDelete = toDelete; this.toUpdate = toUpdate; this.invalid = record; } @Override public SQLCommand getCommand(CatalogDAO c) { return SQLCommand.EMPTY; } @Override public String description() { return "drop storage group"; } @Override public CacheInvalidationRecord getInvalidationRecord() { return invalid; } @Override public List<CatalogEntity> getUpdatedObjects() throws PEException { return toUpdate; } @Override public List<CatalogEntity> getDeletedObjects() throws PEException { return toDelete; } @Override public void onFinally(SSConnection conn) throws Throwable { if (xlock != null) { xlock.exclusiveUnlock(conn, "finished dropping storage group"); xlock = null; } } @Override public void beforeTxn(SSConnection conn, CatalogDAO c, WorkerGroup wg) throws PEException { if (xlock == null) { xlock = GroupManager.getCoordinationServices().getClusterLock(SSConnection.USERLAND_TEMPORARY_TABLES_LOCK_NAME); xlock.exclusiveLock(conn, "dropping storage group"); } } } }