/* This file is part of VoltDB. * Copyright (C) 2008-2010 VoltDB L.L.C. * * VoltDB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * VoltDB 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with VoltDB. If not, see <http://www.gnu.org/licenses/>. */ package org.voltdb.planner; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; import java.util.concurrent.atomic.AtomicInteger; import org.apache.log4j.Logger; import org.voltdb.expressions.AbstractExpression; import org.voltdb.planner.PlanColumn.SortOrder; import org.voltdb.planner.PlanColumn.Storage; public class PlannerContext { private static final Logger LOG = Logger.getLogger(PlannerContext.class); /** * Generator for PlanColumn.m_guid */ private final AtomicInteger s_nextId = new AtomicInteger(-1); /** * Global hash of PlanColumn guid to PlanColumn reference */ private final TreeMap<Integer, PlanColumn> s_columnPool = new TreeMap<Integer, PlanColumn>(); private transient final Map<Integer, PlanColumn> hashcode_col_xref = new HashMap<Integer, PlanColumn>(); /** * Return the Collection of all the PlanColumns managed under this PlannerContext instance * @return */ public Collection<PlanColumn> getAllPlanColumns() { return s_columnPool.values(); } public PlanColumn getPlanColumn(AbstractExpression expression, String columnName) { return getPlanColumn(expression, columnName, SortOrder.kUnsorted, Storage.kTemporary); } /** Provide the common defaults */ public synchronized PlanColumn getPlanColumn(AbstractExpression expression, String columnName, SortOrder sortOrder, Storage storage) { // Check if one already exists int hashCode = PlanColumn.computeHashCode(expression, columnName, sortOrder, storage); PlanColumn retval = hashcode_col_xref.get(hashCode); // We've never seen this one before, so we have to make a new one... if (retval == null) { int guid = this.getNextPlanColumnGUID(); retval = new PlanColumn(guid, expression, columnName, sortOrder, storage); assert(s_columnPool.get(guid) == null); s_columnPool.put(guid, retval); LOG.debug("Added new " + retval); } return retval; } private synchronized int getNextPlanColumnGUID() { if (s_nextId.get() == -1) { s_nextId.set(s_columnPool.isEmpty() ? 0 : s_columnPool.lastKey() * 10); // HACK LOG.debug("Initialized NextId = " + s_nextId); } int guid = -1; while (true) { int new_guid = s_nextId.incrementAndGet(); if (s_columnPool.get(new_guid) == null) { guid = new_guid; break; } } // WHILE assert(guid > 0); return (guid); } /** * Internal Registration * HashCode -> PlanColumn */ protected synchronized void registerPlanColumn(PlanColumn col) { int hashCode = col.hashCode(); this.hashcode_col_xref.put(hashCode, col); // if (col.guid() > this.s_nextId) // this.s_nextId } public PlanColumn clonePlanColumn(PlanColumn orig) { PlanColumn clone = this.getPlanColumn(orig.m_expression, orig.getDisplayName(), orig.getSortOrder(), orig.getStorage()); return (clone); } public synchronized void add(int guid, PlanColumn col) { assert(!this.s_columnPool.containsKey(guid)) : "PlannerContext already contains entry for guid #" + guid + ": " + this.s_columnPool.get(guid); this.s_columnPool.put(guid, col); this.registerPlanColumn(col); } /** * Retrieve a column instance by guid. */ public PlanColumn get(int guid) { PlanColumn column = s_columnPool.get(guid); // assert(column != null) : "Failed to retrieve PlanColumn guid=" + guid; return column; } public synchronized void freeColumn(int guid) { // PlanColumn pc = s_columnPool.remove(guid); // LOG.info("REMOVED[" + guid + "]: " + pc); } public synchronized boolean hasColumn(int guid) { return (s_columnPool.containsKey(guid)); } @Override public String toString() { return this.s_columnPool.toString(); } public String debug() { StringBuilder sb = new StringBuilder(); for (Entry<Integer, PlanColumn> e : this.s_columnPool.entrySet()) { sb.append(String.format("[%02d] %s\n", e.getKey(), e.getValue().toString())); } return (sb.toString()); } // PAVLO: Global singleton for us to use to get back the PlanColumns we need private static final PlannerContext m_singleton = new PlannerContext(); public static PlannerContext singleton() { return (m_singleton); } }