package com.tesora.dve.sql.schema; /* * #%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.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import com.tesora.dve.common.catalog.CatalogEntity; import com.tesora.dve.common.catalog.Container; import com.tesora.dve.common.catalog.DistributionModel; import com.tesora.dve.common.catalog.PersistentContainer; import com.tesora.dve.exceptions.PEException; import com.tesora.dve.sql.schema.DistributionVector.Model; import com.tesora.dve.sql.schema.cache.SchemaCacheKey; import com.tesora.dve.sql.schema.cache.SchemaEdge; public class PEContainer extends Persistable<PEContainer, Container> implements PersistentContainer { private SchemaEdge<PETable> baseTable; private SchemaEdge<PEPersistentGroup> defaultStorageGroup; // the model on which the container is distributed private Model model; // and the range if applicable private SchemaEdge<RangeDistribution> range; @SuppressWarnings("unchecked") public PEContainer(SchemaContext pc, Name n, PEPersistentGroup defStorage, Model model, RangeDistribution anyRange) { super(getContainerKey(n)); setName(n); this.defaultStorageGroup = StructuralUtils.buildEdge(pc,defStorage, false); this.baseTable = null; this.model = model; if (anyRange != null) range = StructuralUtils.buildEdge(pc,anyRange, false); else range = null; setPersistent(pc, null, null); } @SuppressWarnings("unchecked") public PEContainer(SchemaContext pc, Container container) { super(getContainerKey(container)); pc.startLoading(this, container); setPersistent(pc, container, container.getId()); UnqualifiedName dbn = new UnqualifiedName(container.getName()); setName(dbn); if (container.getStorageGroup() != null) defaultStorageGroup = StructuralUtils.buildEdge(pc, PEPersistentGroup.load(container.getStorageGroup(), pc), true); if (container.getBaseTable() != null) baseTable = StructuralUtils.buildEdge(pc,PETable.load(container.getBaseTable(), pc),true); this.model = Model.getModelFromPersistent(container.getDistributionModel().getName()); if (container.getRange() != null) this.range = StructuralUtils.buildEdge(pc,RangeDistribution.load(container.getRange(), pc),true); pc.finishedLoading(this, container); } public static PEContainer load(Container container, SchemaContext pc) { PEContainer peContainer = (PEContainer) pc.getLoaded(container, getContainerKey(container)); if (peContainer == null) peContainer = new PEContainer(pc, container); return peContainer; } public PEPersistentGroup getDefaultStorage(SchemaContext pc) { return defaultStorageGroup.get(pc); } @Override protected Class<? extends CatalogEntity> getPersistentClass() { return Container.class; } @Override protected int getID(Container p) { return p.getId(); } @Override protected Container lookup(SchemaContext sc) throws PEException { return sc.getCatalog().findContainer(getName().getUnqualified().get()); } @Override protected Container createEmptyNew(SchemaContext sc) throws PEException { Map<String, DistributionModel> persistentModels = sc.getCatalog().getDistributionModelMap(); Container container = new Container(name.getUnqualified().get(), defaultStorageGroup.get(sc).getPersistent(sc), persistentModels.get(model.getPersistentName()), (range == null ? null : range.get(sc).getPersistent(sc))); sc.getSaveContext().add(this, container); return container; } @Override protected void populateNew(SchemaContext sc, Container p) throws PEException { p.setName(p.getName()); p.setStorageGroup(defaultStorageGroup.get(sc).getPersistent(sc)); p.setBaseTable((baseTable != null) ? baseTable.get(sc).persistTree(sc) : null); } @Override protected Persistable<PEContainer, Container> load(SchemaContext sc, Container p) throws PEException { return PEContainer.load(p, sc); } @Override public Persistable<PEContainer, Container> reload(SchemaContext sc) throws PEException { Container pcont = sc.getCatalog().findContainer(getName().getUnqualified().get()); return PEContainer.load(pcont, sc); } @Override protected void updateExisting(SchemaContext sc, Container p) throws PEException { PETable pet = getBaseTable(sc); if (p.getBaseTable() == null && pet != null) p.setBaseTable(pet.persistTree(sc)); else if (p.getBaseTable() != null && pet == null) p.setBaseTable(null); } @Override protected String getDiffTag() { return "Container"; } @Override public boolean collectDifferences(SchemaContext sc, List<String> messages, Persistable<PEContainer, Container> oth, boolean first, @SuppressWarnings("rawtypes") Set<Persistable> visited) { PEContainer other = oth.get(); if (visited.contains(this) && visited.contains(other)) { return false; } visited.add(this); visited.add(other); if (maybeBuildDiffMessage(sc, messages, "name", getName(), other.getName(), first, visited)) return true; if (defaultStorageGroup.get(sc).collectDifferences(sc, messages, other.getDefaultStorage(sc), first, visited)) return true; if (maybeBuildDiffMessage(sc, messages, "model", getContainerDistributionModel(), other.getContainerDistributionModel(), first, visited)) return true; if (getContainerDistributionModel() == DistributionVector.Model.RANGE && getRange(sc).collectDifferences(sc, messages, other.getRange(sc), first, visited)) return true; PETable mybase = getBaseTable(sc); PETable yourbase = other.getBaseTable(sc); if (mybase == null && yourbase == null) { // we're the same } else if (mybase != null && yourbase != null) { if (maybeBuildDiffMessage(sc, messages, "base table", mybase.getName(),yourbase.getName(), first, visited)) return true; } else if (mybase != null) { messages.add("Missing base table"); if (first) return true; } else { messages.add("Extra base table"); if (first) return true; } return false; } public boolean hasBaseTable() { return (baseTable != null); } public PETable getBaseTable(SchemaContext sc) { if (baseTable == null) return null; return baseTable.get(sc); } public List<PEColumn> getDiscriminantColumns(SchemaContext sc) { TreeMap<Integer, PEColumn> cols = new TreeMap<Integer,PEColumn>(); for(PEColumn pec : baseTable.get(sc).getColumns(sc)) { if (pec.isPartOfContainerDistributionVector()) cols.put(pec.getContainerDistributionValuePosition(),pec); } return new ArrayList<PEColumn>(cols.values()); } @SuppressWarnings("unchecked") public void setBaseTable(SchemaContext sc, PETable baseTable) { this.baseTable = StructuralUtils.buildEdge(sc,baseTable, false); } public Model getContainerDistributionModel() { return model; } public RangeDistribution getRange(SchemaContext sc) { if (range == null) return null; return range.get(sc); } public static SchemaCacheKey<?> getContainerKey(Name n) { return new ContainerCacheKey(n.getUnqualified().getUnquotedName().get()); } public static SchemaCacheKey<?> getContainerKey(Container c) { return new ContainerCacheKey(c.getName()); } public static class ContainerCacheKey extends SchemaCacheKey<PEContainer> { private static final long serialVersionUID = 1L; private String name; public ContainerCacheKey(String n) { super(); name = n; } @Override public int hashCode() { return initHash(PEContainer.class,name.hashCode()); } @Override public String toString() { return "PEContainer:" + name; } @Override public boolean equals(Object o) { if (o instanceof ContainerCacheKey) { ContainerCacheKey occk = (ContainerCacheKey) o; return name.equals(occk.name); } return false; } @Override public PEContainer load(SchemaContext sc) { Container cont = sc.getCatalog().findContainer(name); if (cont == null) return null; return PEContainer.load(cont, sc); } } @Override public DistributionModel getDistributionModel() { return model.getSingleton(); } }