Package edu.brown.optimizer

Source Code of edu.brown.optimizer.PlanOptimizer

package edu.brown.optimizer;

import java.util.Collection;
import java.util.Comparator;

import org.apache.log4j.Logger;
import org.voltdb.catalog.Column;
import org.voltdb.catalog.Database;
import org.voltdb.planner.PlannerContext;
import org.voltdb.plannodes.AbstractPlanNode;
import org.voltdb.types.PlanNodeType;
import org.voltdb.utils.Pair;

import edu.brown.logging.LoggerUtil.LoggerBoolean;
import edu.brown.optimizer.optimizations.AbstractOptimization;
import edu.brown.optimizer.optimizations.AggregatePushdownOptimization;
import edu.brown.optimizer.optimizations.CombineOptimization;
import edu.brown.optimizer.optimizations.LimitPushdownOptimization;
import edu.brown.optimizer.optimizations.ProjectionPushdownOptimization;
import edu.brown.optimizer.optimizations.RemoveDistributedReplicatedTableJoinOptimization;
import edu.brown.optimizer.optimizations.RemoveRedundantProjectionsOptimizations;
import edu.brown.plannodes.PlanNodeUtil;
import edu.brown.utils.ClassUtil;
import edu.brown.utils.StringBoxUtil;
import edu.brown.utils.StringUtil;

/**
* @author pavlo
* @author sw47
*/
public class PlanOptimizer {
    private static final Logger LOG = Logger.getLogger(PlanOptimizer.class);
    private static final LoggerBoolean debug = new LoggerBoolean();
    private static final LoggerBoolean trace = new LoggerBoolean();

    // ----------------------------------------------------------------------------
    // GLOBAL CONFIGURATION
    // ----------------------------------------------------------------------------

    /**
     * The list of PlanNodeTypes that we do not want to try to optimize
     */
    private static final PlanNodeType TO_IGNORE[] = { PlanNodeType.AGGREGATE, PlanNodeType.NESTLOOP, };
    private static final String BROKEN_SQL[] = {
            // "FROM CUSTOMER, FLIGHT, RESERVATION", // Airline DeleteReservation.GetCustomerReservation
            // "SELECT imb_ib_id, ib_bid", // AuctionMark NewBid.getMaxBidId
    };

    /**
     *
     */
    protected static final Comparator<Column> COLUMN_COMPARATOR = new Comparator<Column>() {
        public int compare(Column c0, Column c1) {
            Integer i0 = c0.getIndex();
            assert (i0 != null) : "Missing index for " + c0;
            Integer i1 = c1.getIndex();
            assert (i1 != null) : "Missing index for " + c1;
            return (i0.compareTo(i1));
        }
    };

    /**
     * List of the Optimizations that we will want to apply
     */
    @SuppressWarnings("unchecked")
    protected static final Class<? extends AbstractOptimization> OPTIMIZATONS[] =
        (Class<? extends AbstractOptimization>[]) new Class<?>[] {
            RemoveDistributedReplicatedTableJoinOptimization.class,   
            AggregatePushdownOptimization.class,
            ProjectionPushdownOptimization.class,
            LimitPushdownOptimization.class,
            RemoveRedundantProjectionsOptimizations.class,
            CombineOptimization.class,
    };

    // ----------------------------------------------------------------------------
    // INSTANCE CONFIGURATION
    // ----------------------------------------------------------------------------

    private final PlanOptimizerState state;

    // ----------------------------------------------------------------------------
    // CONSTRUCTOR
    // ----------------------------------------------------------------------------

    /**
     * @param context
     *            Information about context
     * @param catalogDb
     *            Catalog info about schema, metadata and procedures
     */
    public PlanOptimizer(PlannerContext context, Database catalogDb) {
        this.state = new PlanOptimizerState(catalogDb, context);
    }

    // ----------------------------------------------------------------------------
    // MAIN METHOD
    // ----------------------------------------------------------------------------

    /**
     * Main entry point for the PlanOptimizer
     */
    public AbstractPlanNode optimize(final String sql, final AbstractPlanNode root) {
        try {
            return _optimize(sql, root);
        } catch (Throwable ex) {
            ex.printStackTrace();
            throw new RuntimeException(ex);
        }
    }
       
    public AbstractPlanNode _optimize(final String sql, final AbstractPlanNode root) {
        // HACK
        for (String broken : BROKEN_SQL) {
            if (sql.contains(broken)) {
                if (debug.val)
                    LOG.debug("Given SQL contains broken fragment '" + broken + "'. Skipping...\n" + sql);
                return (null);
            }
        }

        // check to see if the join nodes have the wrong offsets. If so fix them
        // and propagate them.
        // XXX: Why is this here and not down with the rest of the stuff???
        PlanOptimizerUtil.fixJoinColumnOffsets(state, root);

        // Check if our tree contains anything that we want to ignore
        Collection<PlanNodeType> types = PlanNodeUtil.getPlanNodeTypes(root);
        if (trace.val)
            LOG.trace(sql + " - PlanNodeTypes: " + types);
        for (PlanNodeType t : TO_IGNORE) {
            if (types.contains(t)) {
                if (trace.val)
                    LOG.trace(String.format("Tree rooted at %s contains %s. Skipping optimization...", root, t));
                return (null);
            }
        } // FOR

        // Skip single partition query plans
        // if (types.contains(PlanNodeType.RECEIVE) == false) return (null);

        AbstractPlanNode new_root = root;
        if (trace.val)
            LOG.trace("BEFORE: " + sql + "\n" + StringBoxUtil.box(PlanNodeUtil.debug(root)));
//             LOG.debug("LET 'ER RIP!");
//         }

        // STEP #1:
        // Populate the PlanOptimizerState with the information that we will
        // need to figure out our various optimizations
        if (debug.val)
            LOG.debug(StringUtil.header("POPULATING OPTIMIZER STATE", "*"));
        PlanOptimizerUtil.populateTableNodeInfo(state, new_root);
        PlanOptimizerUtil.populateJoinTableInfo(state, new_root);

        // STEP #2
        // Apply all the optimizations that we have
        // We will pass in the new_root each time to ensure that each
        // optimization
        // gets a full view of the quey plan tree
        if (debug.val)
            LOG.debug(StringUtil.header("APPLYING OPTIMIZATIONS", "*"));
        for (Class<? extends AbstractOptimization> optClass : OPTIMIZATONS) {
            if (debug.val)
                LOG.debug(StringUtil.header(optClass.getSimpleName()));

            // Always reset everything so that each optimization has a clean
            // slate to work with
            state.clearDirtyNodes();
            state.updateColumnInfo(new_root);

            try {
                AbstractOptimization opt = ClassUtil.newInstance(optClass,
                                                                 new Object[] { state },
                                                                 new Class<?>[] { PlanOptimizerState.class });
                assert (opt != null);
                Pair<Boolean, AbstractPlanNode> p = opt.optimize(new_root);
                if (p.getFirst()) {
                    if (debug.val)
                        LOG.debug(String.format("%s modified query plan", optClass.getSimpleName()));
                    new_root = p.getSecond();
                }
            } catch (Throwable ex) {
                if (debug.val)
                    LOG.debug("Last Query Plan:\n" + PlanNodeUtil.debug(new_root));

                String msg = String.format("Failed to apply %s to query plan\n%s", optClass.getSimpleName(), sql);
                if (ex instanceof AssertionError)
                    throw new RuntimeException(msg, ex);
                LOG.warn(msg, ex);
                return (null);
            }

            // STEP #3
            // If any nodes were modified by this optimization, go through the tree
            // and make sure our output columns and other information is all in sync
            if (state.hasDirtyNodes())
                PlanOptimizerUtil.updateAllColumns(state, new_root, false);
        } // FOR
        PlanOptimizerUtil.updateAllColumns(state, new_root, true);

        if (trace.val)
            LOG.trace("AFTER: " + sql + "\n" + StringBoxUtil.box(PlanNodeUtil.debug(new_root)));

        return (new_root);
    }

    public PlanOptimizerState getPlanOptimizerState() {
        return this.state;
    }

}
TOP

Related Classes of edu.brown.optimizer.PlanOptimizer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.