Package org.voltdb

Source Code of org.voltdb.VoltSystemProcedure$SynthesizedPlanFragment

/* 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;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.voltdb.VoltTable.ColumnInfo;
import org.voltdb.catalog.Partition;
import org.voltdb.catalog.Procedure;
import org.voltdb.catalog.Site;

import edu.brown.hstore.HStoreConstants;
import edu.brown.hstore.Hstoreservice.WorkFragment;
import edu.brown.hstore.PartitionExecutor;
import edu.brown.hstore.txns.LocalTransaction;
import edu.brown.logging.LoggerUtil;
import edu.brown.logging.LoggerUtil.LoggerBoolean;
import edu.brown.utils.CollectionUtil;

/**
* System procedures extend VoltSystemProcedure and use its utility methods to
* create work in the system. This functionality is not available to standard
* user procedures (which extend VoltProcedure).
*/
public abstract class VoltSystemProcedure extends VoltProcedure {
    private static final Logger LOG = Logger.getLogger(VoltSystemProcedure.class);
    private static final LoggerBoolean debug = new LoggerBoolean();
    private static final LoggerBoolean trace = new LoggerBoolean();
    static {
        LoggerUtil.attachObserver(LOG, debug, trace);
    }

    /** Standard column type for host/partition/site id columns */
    protected static VoltType CTYPE_ID = VoltType.INTEGER;

    /** Standard column name for a host id column */
    protected static String CNAME_HOST_ID = "HOST_ID";

    /** Standard column name for a site id column */
    protected static String CNAME_SITE_ID = "SITE_ID";

    /** Standard column name for a partition id column */
    protected static String CNAME_PARTITION_ID = "PARTITION_ID";

    /** Standard schema for sysprocs returning a simple status table */
    public static ColumnInfo STATUS_SCHEMA =
        new ColumnInfo("STATUS", VoltType.BIGINT);   // public to fix javadoc linking warning

    /** Standard success return value for sysprocs returning STATUS_SCHEMA */
    protected static long STATUS_OK = 0L;
   
    protected CatalogContext catalogContext;
   
    protected final List<WorkFragment.Builder> fragments = new ArrayList<WorkFragment.Builder>();

    public abstract void initImpl();
   
    @Override
    public final void init(PartitionExecutor executor,
                           Procedure catalog_proc,
                           BackendTarget eeType) {
        super.init(executor, catalog_proc, eeType);
        this.catalogContext = executor.getCatalogContext();
        this.initImpl();
    }

    protected final void registerPlanFragment(long fragId) {
        this.executor.registerPlanFragment(fragId, this);
    }
   
//    protected final AbstractTransaction getTransactionState(Long txnId) {
//        return (this.executor.getHStoreSite().getTransaction(txnId));
//    }
   
    /** Bundles the data needed to describe a plan fragment. */
    public static class SynthesizedPlanFragment {
        public int destPartitionId = -1;
        public int fragmentId = -1;
        public int inputDependencyIds[] = null;
        public int outputDependencyIds[] = null;
        public ParameterSet parameters = null;
        public boolean multipartition = false;   /** true if distributes to all executable partitions */
        public boolean nonExecSites = false;     /** true if distributes once to each node */
        public boolean last_task = false;
    }

    abstract public DependencySet executePlanFragment(Long txn_id,
                                                      Map<Integer,List<VoltTable>> dependencies,
                                                      int fragmentId,
                                                      ParameterSet params,
                                                      PartitionExecutor.SystemProcedureExecutionContext context);

    /**
     * Produce work units, possibly on all sites, for a list of plan fragments.
     * The final plan fragment must aggregate intermediate results and produce
     * a single output dependency. This aggregate output is returned as the result.
     *
     * @param pfs an array of synthesized plan fragments
     * @param aggregatorOutputDependencyId dependency id produced by the aggregation pf
     *        The id of the table returned as the result of this procedure.
     * @return the resulting VoltTable as a length-one array.
     */
    protected VoltTable[] executeSysProcPlanFragments(SynthesizedPlanFragment pfs[],
                                                      int aggregatorOutputDependencyId) {
        // Block until we get all of our responses.
        // We can do this because our ExecutionSite is multi-threaded
        return (executeSysProcPlanFragmentsAsync(pfs));
    }

    /**
     * Produce work units, possibly on all sites, for a list of plan fragments.
     * The final plan fragment must aggregate intermediate results and produce
     * a single output dependency. This aggregate output is returned as the result.
     *
     * @param pfs an array of synthesized plan fragments
     * @param aggregatorOutputDependencyId dependency id produced by the aggregation pf
     *        The id of the table returned as the result of this procedure.
     */
    protected final VoltTable[] executeSysProcPlanFragmentsAsync(SynthesizedPlanFragment pfs[]) {
        LocalTransaction ts = this.getTransactionState();
        if (debug.val) LOG.debug(ts + " - Preparing to execute " + pfs.length + " sysproc fragments");
       
        this.fragments.clear();
        ParameterSet parameters[] = new ParameterSet[pfs.length];
        for (int i = 0; i < pfs.length; i++) {
            SynthesizedPlanFragment pf = pfs[i];
            // check mutually exclusive flags
            assert(!(pf.multipartition && pf.nonExecSites));
            assert(pf.parameters != null);

            // We'll let the PartitionExecutor decide how to serialize our ParameterSets
            parameters[i] = pf.parameters;

            // If the multipartition flag is set to true and we don't have a destPartitionId,
            // then we'll just make it go to all partitions. This is so that we can support
            // old-school VoltDB's sysprocs
            int partitions[] = null;
            if (pf.destPartitionId < 0) {
                if (pf.multipartition) {
                    partitions = CollectionUtil.toIntArray(catalogContext.getAllPartitionIds());
                }
                // If it's not multipartitioned and they still don't have a destPartitionId,
                // then we'll make it just go to this PartitionExecutor's local partition
                else {
                    partitions = new int[]{ this.executor.getPartitionId() };
                }
                if (debug.val) LOG.debug(this.getClass() + " => " + Arrays.toString(partitions));
            }
            else {
                partitions = new int[]{ pf.destPartitionId };
            }
           
            // Create a WorkFragment for each target partition
            for (int destPartitionId : partitions) {
                if (debug.val)
                    LOG.debug(String.format("%s - Creating %s for partition %s [fragmentId=%d]",
                              ts, WorkFragment.class.getSimpleName(),
                              destPartitionId, pf.fragmentId));
                WorkFragment.Builder builder = WorkFragment.newBuilder()
                                                        .setPartitionId(destPartitionId)
                                                        .setReadOnly(false)
                                                        .setLastFragment(pf.last_task)
                                                        .addFragmentId(pf.fragmentId)
                                                        .addStmtCounter(0)
                                                        .addStmtIndex(0)
                                                        .addStmtIgnore(false)
                                                        .addParamIndex(i);
                ts.getTouchedPartitions().put(destPartitionId);
               
                boolean needs_input = false;
                for (int ii = 0; ii < pf.outputDependencyIds.length; ii++) {
                    // Input Dependencies
                    if (pf.inputDependencyIds != null && ii < pf.inputDependencyIds.length) {
                        builder.addInputDepId(pf.inputDependencyIds[ii]);
                        needs_input = needs_input || (pf.inputDependencyIds[ii] != HStoreConstants.NULL_DEPENDENCY_ID);
                    } else {
                        builder.addInputDepId(HStoreConstants.NULL_DEPENDENCY_ID);
                    }
                    // Output Dependencies
                    builder.addOutputDepId(pf.outputDependencyIds[ii]);
                } // FOR
                builder.setNeedsInput(needs_input);
                this.fragments.add(builder);
            } // FOR
        } // FOR

        // For some reason we have problems if we're using the transaction profiler
        // with sysprocs, so we'll just always turn it off
        if (hstore_conf.site.txn_profiling && ts.profiler != null) ts.profiler.disableProfiling();
       
        // Bombs away!
        return (this.executor.dispatchWorkFragments(ts, 1, parameters, this.fragments, false));
    }
   
    /**
     * Helper method that will return true if the invoking partition
     * is the first partition at this HStoreSite
     * @return
     */
    protected final boolean isFirstLocalPartition() {
        return (Collections.min(hstore_site.getLocalPartitionIds()) == this.partitionId);
    }
   
    /**
     * Helper method that will queue and execute the given SynthesizedPlanFragment id
     * at the local partition
     * @param fragId
     * @param params
     * @return
     */
    protected final VoltTable[] executeLocal(final int fragId, final ParameterSet params) {
        final SynthesizedPlanFragment pfs[] = new SynthesizedPlanFragment[1];
       
        int i = 0;
        pfs[i] = new SynthesizedPlanFragment();
        pfs[i].fragmentId = fragId;
        pfs[i].inputDependencyIds = new int[] { };
        pfs[i].outputDependencyIds = new int[] { fragId };
        pfs[i].multipartition = true;
        pfs[i].nonExecSites = false;
        pfs[i].destPartitionId = this.partitionId;
        pfs[i].parameters = params;
        pfs[i].last_task = true;
       
        return (this.executeSysProcPlanFragments(pfs, fragId));
    }
   
    protected final VoltTable[] executeOncePerSite(final int distributeId, final int aggregateId) {
        return this.executeOncePerSite(distributeId, aggregateId, new ParameterSet());
    }
   
    /**
     * Helper method that will queue up the distributed SynthesizedPlanFragment (distributeId)
     * at the first partition at each site and then execute the aggregate
     * SynthesizedPlanFragment (aggregateId) at the local partition. Note that the same
     * ParameterSet will be given to both the distributed and aggregate operations
     * @param distributeId
     * @param aggregateId
     * @param params
     * @return
     */
    protected final VoltTable[] executeOncePerSite(final int distributeId, final int aggregateId, final ParameterSet params) {
        final SynthesizedPlanFragment pfs[] = new SynthesizedPlanFragment[catalogContext.numberOfSites + 1];
       
        int i = 0;
        for (Site catalog_site : catalogContext.sites.values()) {
            Partition catalog_part = null;
            int first_id = Integer.MAX_VALUE;
            for (Partition p : catalog_site.getPartitions().values()) {
                if (catalog_part == null || p.getId() < first_id) {
                    catalog_part = p;
                    first_id = p.getId();
                }
            } // FOR
            assert(catalog_part != null) : "No partitions for " + catalog_site;

            if (debug.val)
                LOG.debug(String.format("Creating PlanFragment #%d for %s on %s",
                          distributeId, catalog_part, catalog_site));
            pfs[i] = new SynthesizedPlanFragment();
            pfs[i].fragmentId = distributeId;
            pfs[i].inputDependencyIds = new int[] { };
            pfs[i].outputDependencyIds = new int[] { distributeId };
            pfs[i].multipartition = true;
            pfs[i].nonExecSites = false;
            pfs[i].destPartitionId = catalog_part.getId();
            pfs[i].parameters = params;
            pfs[i].last_task = (catalog_site.getId() != hstore_site.getSiteId());
            i += 1;
        } // FOR

        // a final plan fragment to aggregate the results
        pfs[i] = new SynthesizedPlanFragment();
        pfs[i].fragmentId = aggregateId;
        pfs[i].inputDependencyIds = new int[] { distributeId };
        pfs[i].outputDependencyIds = new int[] { aggregateId };
        pfs[i].multipartition = false;
        pfs[i].nonExecSites = false;
        pfs[i].destPartitionId = this.partitionId;
        pfs[i].parameters = params;
        pfs[i].last_task = true;
       
        return (this.executeSysProcPlanFragments(pfs, aggregateId));
    }
   
    /**
     * Helper method that will queue up the distributed SynthesizedPlanFragment (distributeId)
     * at all of the partitions in the cluster. Note that the same ParameterSet will be given
     * to both the distributed and aggregate operations
     * @param distributeId
     * @param aggregateId
     * @param params
     * @return
     */
    protected final VoltTable[] executeOncePerPartition(final int distributeId, final int aggregateId, final ParameterSet params) {
        final SynthesizedPlanFragment pfs[] = new SynthesizedPlanFragment[catalogContext.numberOfPartitions + 1];
       
        int i = 0;
        for (Partition catalog_part : catalogContext.getAllPartitions()) {
            pfs[i] = new SynthesizedPlanFragment();
            pfs[i].fragmentId = distributeId;
            pfs[i].inputDependencyIds = new int[] { };
            pfs[i].outputDependencyIds = new int[] { distributeId };
            pfs[i].multipartition = true;
            pfs[i].nonExecSites = false;
            pfs[i].destPartitionId = catalog_part.getId();
            pfs[i].parameters = params;
            pfs[i].last_task = false; // (catalog_part.getId() != this.partitionId);
            i += 1;
        } // FOR

        // a final plan fragment to aggregate the results
        pfs[i] = new SynthesizedPlanFragment();
        pfs[i].fragmentId = aggregateId;
        pfs[i].inputDependencyIds = new int[] { distributeId };
        pfs[i].outputDependencyIds = new int[] { aggregateId };
        pfs[i].multipartition = false;
        pfs[i].nonExecSites = false;
        pfs[i].destPartitionId = this.partitionId;
        pfs[i].parameters = params;
        pfs[i].last_task = true;
       
        return (this.executeSysProcPlanFragments(pfs, aggregateId));
    }
   
    /**
     * Returns the formatted procedure name to use to invoke the given sysproc class
     * This is what is passed into the client
     * @param procClass
     * @return
     */
    public static final String procCallName(Class<? extends VoltSystemProcedure> procClass) {
        return "@" + procClass.getSimpleName();
    }
}
TOP

Related Classes of org.voltdb.VoltSystemProcedure$SynthesizedPlanFragment

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.