package com.tesora.dve.sql.schema.cache; /* * #%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.Arrays; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.collections.CollectionUtils; import com.tesora.dve.exceptions.PEException; import com.tesora.dve.lockmanager.LockType; import com.tesora.dve.sql.expression.TableKey; import com.tesora.dve.sql.parser.ExtractedLiteral; import com.tesora.dve.sql.parser.ExtractedLiteral.Type; import com.tesora.dve.sql.schema.SchemaContext; import com.tesora.dve.sql.statement.CacheableStatement; import com.tesora.dve.sql.transform.execution.ConnectionValuesMap; import com.tesora.dve.sql.transform.execution.RootExecutionPlan; import com.tesora.dve.sql.transform.execution.RebuiltPlan; import com.tesora.dve.sql.util.Functional; import com.tesora.dve.sql.util.ListSet; public class NonMTCachedPlan implements RegularCachedPlan { public static final String GLOBAL_CACHE_NAME = "X8U_GLOBAL_5NT"; @SuppressWarnings("rawtypes") private final SchemaCacheKey[] tks; private final PlanCacheKey key; private final List<ExtractedLiteral.Type> extractedTypes; private final LockType lockType; private Map<String, SpecificCachedPlan> specificCachedPlanMap = new ConcurrentHashMap<String, NonMTCachedPlan.SpecificCachedPlan>(); public NonMTCachedPlan(ListSet<TableKey> tabs, PlanCacheKey pck, List<ExtractedLiteral> extractedLiterals, LockType lt) { this(tabs,Functional.apply(extractedLiterals,ExtractedLiteral.typeAccessor),pck, lt); } public NonMTCachedPlan(ListSet<TableKey> tabs, List<ExtractedLiteral.Type> extractedLiterals, PlanCacheKey pck, LockType lt) { tks = buildTableKeySet(tabs); key = pck; extractedTypes = extractedLiterals; lockType = lt; } @Override public PlanCacheKey getKey() { return key; } @Override public RebuiltPlan rebuildPlan(SchemaContext sc, List<ExtractedLiteral> literals) throws PEException { if (!isValid(sc, literals)) return new RebuiltPlan(null, null, true, tks, lockType); SpecificCachedPlan nmtcp = specificCachedPlanMap.get(sc.getConnection().getCacheName() == null ? GLOBAL_CACHE_NAME : sc.getConnection().getCacheName()); if (nmtcp != null) { return nmtcp.rebuildPlan(sc, literals); } else { // could not find the plan for the specified cache but don't clear this plan from the cache return new RebuiltPlan(null, null, false, tks, lockType); } } @Override public RebuiltPlan showPlan(SchemaContext sc, List<ExtractedLiteral> literals) throws PEException { return specificCachedPlanMap.get(GLOBAL_CACHE_NAME).showPlan(sc,literals); } @Override public List<ExtractedLiteral.Type> getLiteralTypes() { return extractedTypes; } @Override public boolean isValid(SchemaContext sc, List<ExtractedLiteral> literals) throws PEException { for(int i = 0; i < extractedTypes.size(); i++) { if (extractedTypes.get(i) != literals.get(i).getType()) return false; } return true; } @Override public boolean invalidate(SchemaCacheKey<?> unloaded) { if (unloaded.getCacheSegment() != CacheSegment.TABLE) return false; for(int i = 0; i < tks.length; i++) { if (tks[i].equals(unloaded)) { specificCachedPlanMap.clear(); return true; } } return false; } public boolean take(SchemaContext sc, CacheableStatement originalStatement, RootExecutionPlan thePlan) { boolean ret = true; if (!keysMatch(originalStatement.getAllTableKeys()) && !thePlan.isEmptyPlan()) { // remove this entry from the cache ret = false; } else { SpecificCachedPlan np = new SpecificCachedPlan(this, thePlan); specificCachedPlanMap.put(sc.getConnection().getCacheName() == null ? GLOBAL_CACHE_NAME : sc.getConnection().getCacheName(), np); } return ret; } @SuppressWarnings("rawtypes") private SchemaCacheKey[] buildTableKeySet(ListSet<TableKey> tabs) { ArrayList<SchemaCacheKey<?>> buf = new ArrayList<SchemaCacheKey<?>>(); for(TableKey tk : tabs) { SchemaCacheKey<?> sck = tk.getCacheKey(); buf.add(sck); } return buf.toArray(new SchemaCacheKey[0]); } private boolean keysMatch(ListSet<TableKey> allTableKeys) { return CollectionUtils.isEqualCollection( Arrays.asList(tks), Arrays.asList(buildTableKeySet(allTableKeys))); } public static class SpecificCachedPlan implements RegularCachedPlan { private final NonMTCachedPlan parent; private final RootExecutionPlan thePlan; public SpecificCachedPlan(NonMTCachedPlan nmtcp, RootExecutionPlan ep) { parent = nmtcp; thePlan = ep; thePlan.setOwningCache(parent); } @Override public PlanCacheKey getKey() { return parent.getKey(); } @Override public RebuiltPlan showPlan(SchemaContext sc, List<ExtractedLiteral> literals) throws PEException { ConnectionValuesMap cvs = thePlan.resetForNewPlan(sc, literals); return new RebuiltPlan(thePlan, cvs, false,null, null); } @Override public RebuiltPlan rebuildPlan(SchemaContext sc, List<ExtractedLiteral> literals) throws PEException { if (!isValid(sc, literals)) return new RebuiltPlan(null, null, true, parent.tks, parent.lockType); if (thePlan.isEmptyPlan()) { return new RebuiltPlan(thePlan, null, false, parent.tks, parent.lockType); } ConnectionValuesMap cv = thePlan.resetForNewPlan(sc, literals); return new RebuiltPlan(thePlan, cv, false, parent.tks, parent.lockType); } @Override public boolean isValid(SchemaContext sc, List<ExtractedLiteral> literals) throws PEException { if (thePlan.getValueManager().getNumberOfLiterals() != literals.size()) return false; return true; } @Override public boolean invalidate(SchemaCacheKey<?> unloaded) { return false; } @Override public List<Type> getLiteralTypes() { return null; } } }