Package edu.brown.designer.partitioners.plan

Source Code of edu.brown.designer.partitioners.plan.PartitionPlan

package edu.brown.designer.partitioners.plan;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import java.util.Vector;

import org.apache.log4j.Logger;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONStringer;
import org.voltdb.catalog.CatalogType;
import org.voltdb.catalog.Column;
import org.voltdb.catalog.Database;
import org.voltdb.catalog.ProcParameter;
import org.voltdb.catalog.Procedure;
import org.voltdb.catalog.Statement;
import org.voltdb.catalog.Table;
import org.voltdb.plannodes.AbstractPlanNode;
import org.voltdb.types.PartitionMethodType;

import edu.brown.catalog.CatalogUtil;
import edu.brown.catalog.special.NullProcParameter;
import edu.brown.catalog.special.RandomProcParameter;
import edu.brown.catalog.special.ReplicatedColumn;
import edu.brown.catalog.special.VerticalPartitionColumn;
import edu.brown.designer.DesignerHints;
import edu.brown.designer.partitioners.PartitionerUtil;
import edu.brown.designer.partitioners.VerticalPartitionerUtil;
import edu.brown.plannodes.PlanNodeUtil;
import edu.brown.utils.AbstractTreeWalker;
import edu.brown.utils.CollectionUtil;
import edu.brown.utils.JSONSerializable;
import edu.brown.utils.JSONUtil;

/**
* @author pavlo
*/
public class PartitionPlan implements JSONSerializable {
    protected static final Logger LOG = Logger.getLogger(PartitionPlan.class.getName());

    public enum Members {
        TABLE_ENTRIES, PROC_ENTRIES,
    }

    /**
     * Table Partition Entries
     */
    public final Map<Table, TableEntry> table_entries = new TreeMap<Table, TableEntry>();

    /**
     * Procedure Partition Entries
     */
    public final Map<Procedure, ProcedureEntry> proc_entries = new TreeMap<Procedure, ProcedureEntry>();

    /**
     * For each table, we store an ordered list tables up to the root of the
     * schema tree Table -> Vector
     * <Table>
     */
    private transient final Map<Table, List<Table>> table_ancestors = new HashMap<Table, List<Table>>();
    private transient Map<Table, Table> table_roots = new HashMap<Table, Table>();

    /**
     * List of children for each table
     */
    private transient final Map<Table, Set<Table>> table_children = new HashMap<Table, Set<Table>>();

    /**
     * For each table we store a set of the tables that are dependent to it
     * Table -> Set
     * <Table>
     */
    private transient final Map<Table, Set<Table>> table_descendants = new HashMap<Table, Set<Table>>();

    /**
     * Constructor
     */
    public PartitionPlan() {
        super();
    }

    /**
     * Copy Constructor
     *
     * @param pplan
     */
    public PartitionPlan(PartitionPlan pplan) {
        this();
        createFromMap(this, pplan.toMap());
    }

    public void addTablePartitionEntry(Table catalog_tbl, TableEntry pentry) {
        this.table_entries.put(catalog_tbl, pentry);
    }

    public void addProcedurePartitionEntry(Procedure catalog_proc, ProcedureEntry pentry) {
        this.proc_entries.put(catalog_proc, pentry);
    }

    public Map<Table, TableEntry> getTableEntries() {
        return (this.table_entries);
    }

    public TableEntry getTableEntry(Table catalog_tbl) {
        assert (catalog_tbl != null);
        return (this.table_entries.get(catalog_tbl));
    }

    public Map<Procedure, ProcedureEntry> getProcedureEntries() {
        return (this.proc_entries);
    }

    public ProcedureEntry getProcedureEntry(Procedure catalog_proc) {
        assert (catalog_proc != null);
        return (this.proc_entries.get(catalog_proc));
    }

    public void setNullProcParameter(Procedure catalog_proc) {
        ProcedureEntry entry = new ProcedureEntry(PartitionMethodType.NONE);
        this.proc_entries.put(catalog_proc, entry);
    }

    public void setRandomProcParameter(Procedure catalog_proc) {
        ProcedureEntry entry = new ProcedureEntry(PartitionMethodType.RANDOM);
        this.proc_entries.put(catalog_proc, entry);
    }

    public int getTableCount() {
        return (this.table_entries.size());
    }

    public int getProcedureCount() {
        return (this.proc_entries.size());
    }

    /**
     *
     */
    public void initializeDependencies() {
        for (Table catalog_tbl : this.table_entries.keySet()) {
            TableEntry entry = this.table_entries.get(catalog_tbl);
            this.table_descendants.put(catalog_tbl, new HashSet<Table>());
            this.table_children.put(catalog_tbl, new HashSet<Table>());

            // Children
            for (Table other_tbl : this.table_entries.keySet()) {
                if (catalog_tbl.equals(other_tbl))
                    continue;
                TableEntry other = this.table_entries.get(other_tbl);
                if (!entry.equals(other) && other.getParent() != null && other.getParent().equals(catalog_tbl)) {
                    this.table_children.get(catalog_tbl).add(other_tbl);
                }
            } // FOR

            // Ancestors
            final Vector<Table> ancestors = new Vector<Table>();
            new AbstractTreeWalker<Table>() {
                protected void populate_children(AbstractTreeWalker.Children<Table> children, Table element) {
                    TableEntry current_entry = table_entries.get(element);
                    Table parent = current_entry.getParent();
                    if (parent != null) {
                        TableEntry parent_entry = PartitionPlan.this.table_entries.get(parent);
                        if (parent_entry == null) {
                            LOG.warn(String.format("Missing parent entry %s for child %s: %s", parent, element, table_entries.keySet()));
                        } else {
                            // assert(parent_entry != null) :
                            // "Missing parent entry " + parent + " for " +
                            // element;
                            if (!this.hasVisited(parent))
                                children.addAfter(parent);
                        }
                    }
                };

                @Override
                protected void callback(Table element) {
                    if (element != this.getFirst()) {
                        ancestors.add(element);
                    }
                }
            }.traverse(catalog_tbl);
            this.table_ancestors.put(catalog_tbl, ancestors);
        } // FOR

        // Descendants & Roots
        // Table last_tbl = null;
        for (Table catalog_tbl : this.table_ancestors.keySet()) {
            for (Table ancestor_tbl : this.table_ancestors.get(catalog_tbl)) {
                if (!this.table_descendants.containsKey(ancestor_tbl)) {
                    this.table_descendants.put(ancestor_tbl, new HashSet<Table>());
                }
                this.table_descendants.get(ancestor_tbl).add(catalog_tbl);
            } // FOR

            Table root = (this.table_ancestors.get(catalog_tbl).isEmpty() ? catalog_tbl : CollectionUtil.last(this.table_ancestors.get(catalog_tbl)));
            this.table_roots.put(catalog_tbl, root);

            // last_tbl = catalog_tbl;
        } // FOR
    }

    /**
     * Apply the partitioning plan to the given catalog
     *
     * @param catalog_db
     */
    public void apply(Database catalog_db) {
        this.apply(catalog_db, true);
    }

    public void apply(Database catalog_db, boolean enableVerticalPartitions) {
        final boolean debug = LOG.isDebugEnabled();
        if (debug)
            LOG.debug("Applying PartitionPlan to catalog");

        Set<VerticalPartitionColumn> vp_cols = new HashSet<VerticalPartitionColumn>();
        Collection<Table> tables = new HashSet<Table>(catalog_db.getTables());
        for (Table catalog_tbl : tables) {
            if (catalog_tbl.getSystable())
                continue;
            TableEntry pentry = this.table_entries.get(catalog_tbl);
            if (pentry != null) {
                if (debug)
                    LOG.debug("Applying PartitionEntry to " + catalog_tbl.getName() + ": " + pentry);

                if (pentry.getMethod() == PartitionMethodType.REPLICATION) {
                    catalog_tbl.setIsreplicated(true);
                    catalog_tbl.setPartitioncolumn(ReplicatedColumn.get(catalog_tbl));
                } else {
                    Column catalog_col = (Column) pentry.getAttribute();
                    assert (catalog_col != null);
                    if (catalog_col instanceof VerticalPartitionColumn && enableVerticalPartitions == false) {
                        catalog_col = ((VerticalPartitionColumn) catalog_col).getHorizontalColumn();
                    }
                    catalog_tbl.setPartitioncolumn(catalog_col);
                    catalog_tbl.setIsreplicated(false);
                }
                if (catalog_tbl.getPartitioncolumn() instanceof VerticalPartitionColumn) {
                    assert (enableVerticalPartitions) : "Unexpected " + catalog_tbl.getPartitioncolumn().fullName();
                    VerticalPartitionColumn vp_col = (VerticalPartitionColumn) catalog_tbl.getPartitioncolumn();
                    vp_cols.add(vp_col);
                }
            } else {
                if (debug)
                    LOG.warn("Missing PartitionEntry for " + catalog_tbl);
            }
        } // FOR

        // Create optimized queries
        if (vp_cols.isEmpty() == false) {
            boolean clearCache = false;
            for (VerticalPartitionColumn vc : vp_cols) {
                boolean ret = VerticalPartitionerUtil.generateOptimizedQueries(catalog_db, vc);
                if (ret == false) {
                    LOG.warn(String.format("Failed to generate optimized queries for %s\n%s", vc.getClass().getSimpleName(), vc));
                } else {
                    assert (vc.hasOptimizedQueries()) : vc;
                    Statement catalog_stmt = CollectionUtil.first(vc.getOptimizedQueries());
                    assert (catalog_stmt != null);
                    Procedure catalog_proc = catalog_stmt.getParent();
                    String stmtName = catalog_stmt.getName();
                    if (vc.isUpdateApplied() == false)
                        vc.applyUpdate();

                    catalog_stmt = catalog_proc.getStatements().get(stmtName);
                    AbstractPlanNode root = PlanNodeUtil.getRootPlanNodeForStatement(catalog_stmt, false);
                    if (debug)
                        LOG.debug(catalog_stmt.fullName() + "\n" + PlanNodeUtil.debug(root));
                    clearCache = true;
                }
            } // FOR
            if (clearCache) {
                CatalogUtil.clearCache(catalog_db);
                PlanNodeUtil.clearCache();
            }
        }

        for (Procedure catalog_proc : catalog_db.getProcedures()) {
            ProcedureEntry pentry = this.proc_entries.get(catalog_proc);
            if (catalog_proc.getSystemproc() || pentry == null || catalog_proc.getParameters().size() == 0)
                continue;
            if (debug)
                LOG.debug("Applying PartitionEntry to " + catalog_proc.getName() + ": " + pentry);

            ProcParameter catalog_proc_param = null;
            switch (pentry.getMethod()) {
                case NONE:
                    catalog_proc_param = NullProcParameter.singleton(catalog_proc);
                    break;
                case RANDOM:
                    catalog_proc_param = RandomProcParameter.singleton(catalog_proc);
                    break;
                case HASH:
                    catalog_proc_param = pentry.getAttribute();
                    break;
                default:
                    assert (false) : "Unexpected PartitionMethodType for " + catalog_proc + ": " + pentry.getMethod();
            } // SWITCH

            assert (catalog_proc_param != null) : "Null ProcParameter for " + catalog_proc;
            catalog_proc.setPartitionparameter(catalog_proc_param.getIndex());

            Boolean single_partition = pentry.isSinglePartition();
            if (single_partition != null)
                catalog_proc.setSinglepartition(single_partition);
        } // FOR
    }

    /**
     * Get the set of catalog items that differ between this PartitionPlan and
     * another PartitionPlan
     *
     * @param other
     * @return
     */
    public Collection<CatalogType> getChangedEntries(PartitionPlan other) {
        Set<CatalogType> changed = new HashSet<CatalogType>();
        changed.addAll(this.getChangedTableEntries(other));
        changed.addAll(this.getChangedProcedureEntries(other));
        return (changed);
    }

    public Collection<Table> getChangedTableEntries(PartitionPlan other) {
        Set<Table> changed = new HashSet<Table>();
        for (Entry<Table, TableEntry> e : this.table_entries.entrySet()) {
            if (!other.table_entries.containsKey(e.getKey())) {
                changed.add(e.getKey());
            } else {
                TableEntry pe0 = e.getValue();
                TableEntry pe1 = other.table_entries.get(e.getKey());
                if (!pe0.equals(pe1))
                    changed.add(e.getKey());
            }
        } // FOR
        return (changed);
    }

    public Collection<Procedure> getChangedProcedureEntries(PartitionPlan other) {
        Set<Procedure> changed = new HashSet<Procedure>();
        for (Entry<Procedure, ProcedureEntry> e : this.proc_entries.entrySet()) {
            if (!other.proc_entries.containsKey(e.getKey())) {
                changed.add(e.getKey());
            } else {
                ProcedureEntry pe0 = e.getValue();
                ProcedureEntry pe1 = other.proc_entries.get(e.getKey());
                if (!pe0.equals(pe1))
                    changed.add(e.getKey());
            }
        } // FOR
        return (changed);
    }

    /**
     * Return the root tables of this PartitionPlan
     *
     * @return
     */
    public Collection<Table> getRoots() {
        Set<Table> roots = new HashSet<Table>();
        for (Table catalog_tbl : this.table_entries.keySet()) {
            TableEntry entry = this.table_entries.get(catalog_tbl);
            if (entry.getParent() == null)
                roots.add(catalog_tbl);
        } // FOR
        return (roots);
    }

    /**
     * @param catalog_tbl
     * @return
     */
    public Table getRoot(Table catalog_tbl) {
        return (this.table_roots.get(catalog_tbl));
    }

    /**
     * Return the set of non-replicated roots for this PartitionPlan
     *
     * @return
     */
    public Collection<Table> getNonReplicatedRoots() {
        Set<Table> roots = new HashSet<Table>();
        for (Table catalog_tbl : this.table_entries.keySet()) {
            TableEntry entry = this.table_entries.get(catalog_tbl);
            if (entry.getParent() == null && entry.getMethod() != PartitionMethodType.REPLICATION) {
                roots.add(catalog_tbl);
            }
        } // FOR
        return (roots);
    }

    public Collection<Table> getAncestors(Table catalog_tbl) {
        return (this.table_ancestors.get(catalog_tbl));
    }

    public Collection<Table> getDescendants(Table catalog_tbl) {
        return (this.table_descendants.get(catalog_tbl));
    }

    /**
     * @param catalog_tbl
     * @return
     */
    public Set<Table> getChildren(Table catalog_tbl) {
        // assert(this.table_children.containsKey(catalog_tbl)) :
        // "No entry for " + catalog_tbl;
        return (this.table_children.get(catalog_tbl));
    }

    public Map<CatalogType, CatalogType> toMap() {
        HashMap<CatalogType, CatalogType> map = new HashMap<CatalogType, CatalogType>();
        // TABLES
        for (Entry<Table, TableEntry> e : this.table_entries.entrySet()) {
            switch (e.getValue().getMethod()) {
                case REPLICATION:
                    map.put(e.getKey(), ReplicatedColumn.get(e.getKey()));
                    break;
                case HASH:
                case MAP:
                    map.put(e.getKey(), e.getValue().getAttribute());
                    break;
                default:
                    assert (false) : "Unexpected " + e.getValue().getMethod();
            }

        } // FOR
          // PROCEDURES
        for (Entry<Procedure, ProcedureEntry> e : this.proc_entries.entrySet()) {
            switch (e.getValue().getMethod()) {
                case NONE:
                    map.put(e.getKey(), NullProcParameter.singleton(e.getKey()));
                    break;
                case HASH:
                    map.put(e.getKey(), e.getValue().getAttribute());
                    break;
                default:
                    assert (false) : "Unexpected " + e.getValue().getMethod();
            }
        } // FOR
        return (map);
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof PartitionPlan))
            return (false);
        PartitionPlan other = (PartitionPlan) obj;
        return (this.proc_entries.equals(other.proc_entries) && this.table_entries.equals(other.table_entries));
    }

    public String toString() {
        final int col_width = 30;
        final String format = "%-" + col_width + "s";

        StringBuilder sb = new StringBuilder();
        String labels[] = { "TABLE", "METHOD", "ATTRIBUTE", "MAPPING" };
        for (String label : labels) {
            sb.append(String.format(format, label));
        }

        String single_line = "";
        String double_line = "";
        for (int i = 0, cnt = col_width * labels.length; i < cnt; i++) {
            single_line += "-";
            double_line += "=";
        } // FOR
        sb.append("\n").append(single_line).append("\n");
        for (Table catalog_tbl : this.table_entries.keySet()) {
            TableEntry entry = this.table_entries.get(catalog_tbl);
            assert (entry != null) : "Null PartitionEntry: " + catalog_tbl;
            String mapping = (entry.getParent() != null ? CatalogUtil.getDisplayName(entry.getParentAttribute()) : "<none>");
            sb.append(String.format(format, catalog_tbl.getName())).append(String.format(format, entry.getMethod()))
                    .append(String.format(format, (entry.getAttribute() != null ? entry.getAttribute().getName() : "<none>"))).append(String.format(format, mapping)).append("\n");
        } // FOR
        sb.append(double_line).append("\n");

        labels = new String[] { "PROCEDURE", "METHOD", "ATTRIBUTE", "SINGLEPARTITION" };
        for (String label : labels) {
            sb.append(String.format(format, label));
        }
        sb.append("\n").append(single_line).append("\n");
        for (Procedure catalog_proc : this.proc_entries.keySet()) {
            ProcedureEntry entry = this.proc_entries.get(catalog_proc);
            assert (entry != null) : "Null PartitionEntry: " + catalog_proc;
            sb.append(String.format(format, catalog_proc.getName())).append(String.format(format, entry.getMethod()))
                    .append(String.format(format, (entry.getAttribute() != null ? entry.getAttribute().getName() : "<none>"))).append(String.format(format, entry.isSinglePartition())).append("\n");
        } // FOR

        return (sb.toString());
    }

    // ----------------------------------------------------------------------------
    // STATIC GENERATION METHODS
    // ----------------------------------------------------------------------------

    public static PartitionPlan createFromMap(Map<? extends CatalogType, ? extends CatalogType> pplan_map) {
        return (createFromMap(new PartitionPlan(), pplan_map));
    }

    public static PartitionPlan createFromMap(final PartitionPlan pplan, Map<? extends CatalogType, ? extends CatalogType> pplan_map) {
        assert (pplan_map.isEmpty() == false) : "PartitionPlan map is empty!";
        Database catalog_db = null;

        for (Entry<? extends CatalogType, ? extends CatalogType> e : pplan_map.entrySet()) {
            PartitionMethodType method = null;
            if (e.getValue() != null)
                assert (e.getKey().equals(e.getValue().getParent())) : e;

            // Table Partitioning
            if (e.getKey() instanceof Table) {
                Table catalog_tbl = (Table) e.getKey();
                Column catalog_col = (Column) e.getValue();
                Column attribute = null;
                if (catalog_col instanceof ReplicatedColumn) {
                    method = PartitionMethodType.REPLICATION;
                } else {
                    method = PartitionMethodType.HASH;
                    attribute = catalog_col;
                    assert (catalog_col != null) : "Unexcept Null Partitioning Column: " + catalog_tbl.getName();
                    assert (catalog_col.getParent().equals(e.getKey())) : "Parent mismatch: " + catalog_col.getParent() + " != " + e.getKey();
                }
                TableEntry pentry = new TableEntry(method, attribute, null, null);
                try {
                    pplan.addTablePartitionEntry(catalog_tbl, pentry);
                } catch (AssertionError ex) {
                    LOG.fatal("FAILED: " + e);
                    throw ex;
                }

                // Procedure Partitioning
            } else if (e.getKey() instanceof Procedure) {
                Procedure catalog_proc = (Procedure) e.getKey();
                ProcParameter catalog_proc_param = (ProcParameter) e.getValue();
                boolean single_partition = true;
                ProcParameter attribute = null;

                if (catalog_proc.getSystemproc()) {
                    continue;
                } else if (catalog_proc_param instanceof NullProcParameter || catalog_proc_param == null || catalog_proc.getParameters().size() == 0) {
                    method = PartitionMethodType.NONE;
                    single_partition = false;
                    // attribute =
                    // NullProcParameter.getNullProcParameter(catalog_proc);
                } else {
                    method = PartitionMethodType.HASH;
                    attribute = catalog_proc_param;
                    single_partition = catalog_proc.getSinglepartition();
                    assert (catalog_proc_param != null) : "Unexcept Null ProcParameter: " + catalog_proc;
                    assert (catalog_proc_param.getParent().equals(e.getKey())) : "Parent mismatch: " + catalog_proc_param.getParent() + " != " + e.getKey();
                }
                ProcedureEntry pentry = new ProcedureEntry(method, attribute, single_partition);
                try {
                    pplan.addProcedurePartitionEntry(catalog_proc, pentry);
                } catch (AssertionError ex) {
                    LOG.fatal("FAILED: " + e);
                    throw ex;
                }

                // Unknown!
            } else {
                assert (false) : "Unexpected CatalogType: " + e.getKey();
            }
            catalog_db = CatalogUtil.getDatabase(e.getKey());
        }
        // Then go back and try to resolve foreign key relations for tables
        for (TableEntry pentry : pplan.getTableEntries().values()) {
            if (pentry.isReplicated())
                continue;
            assert (pentry != null);

            // Check whether it is partitioned on a foreign key attribute that
            // has a parent
            // who is not replicate
            Column partition_col = pentry.getAttribute();

            Column parent_col = CatalogUtil.getForeignKeyParent(partition_col);
            if (parent_col != null) {
                pentry.setMethod(PartitionMethodType.MAP);
                pentry.setParent((Table) parent_col.getParent());
                pentry.setParentAttribute(parent_col);
            }
        } // FOR
        assert (catalog_db != null);

        // Construct a partition tree from ourselves and then populate the
        // dependency relationships
        // PartitionTree ptree = PartitionPlanTreeGenerator.generate(catalog_db,
        // pplan);
        // pplan.setPartitionTree(ptree);
        pplan.initializeDependencies();

        return (pplan);

    }

    /**
     * Create a partitioning plan object from a catalog
     *
     * @param catalog_db
     * @return
     */
    public static PartitionPlan createFromCatalog(Database catalog_db) {
        return (createFromCatalog(catalog_db, null));
    }

    public static PartitionPlan createFromCatalog(Database catalog_db, DesignerHints hints) {
        final Map<CatalogType, CatalogType> pplan_map = new HashMap<CatalogType, CatalogType>();

        // Table Partitioning
        for (Table catalog_tbl : catalog_db.getTables()) {
            if (catalog_tbl.getSystable())
                continue;
            if (catalog_tbl.getIsreplicated()) {
                pplan_map.put(catalog_tbl, ReplicatedColumn.get(catalog_tbl));
            } else {
                Column partition_col = catalog_tbl.getPartitioncolumn();
                pplan_map.put(catalog_tbl, partition_col);
            }
        } // FOR
          // Procedure Partitioning
        for (Procedure catalog_proc : catalog_db.getProcedures()) {
            if (PartitionerUtil.shouldIgnoreProcedure(hints, catalog_proc)) {
                continue;
            } else if (catalog_proc.getPartitionparameter() == NullProcParameter.PARAM_IDX) {
                pplan_map.put(catalog_proc, NullProcParameter.singleton(catalog_proc));
            } else {
                int param_idx = catalog_proc.getPartitionparameter();
                assert (param_idx >= 0);
                ProcParameter catalog_proc_param = catalog_proc.getParameters().get(param_idx);
                assert (catalog_proc_param != null) : "Null ProcParameter for " + catalog_proc.getName() + ": Idx #" + param_idx;
                pplan_map.put(catalog_proc, catalog_proc_param);
            }
        }
        return (PartitionPlan.createFromMap(pplan_map));
    }

    // ----------------------------------------------------------------------------
    // SERIALIZATION METHODS
    // ----------------------------------------------------------------------------

    @Override
    public void load(File input_path, Database catalog_db) throws IOException {
        JSONUtil.load(this, catalog_db, input_path);
    }

    @Override
    public void save(File output_path) throws IOException {
        JSONUtil.save(this, output_path);
    }

    @Override
    public String toJSONString() {
        return (JSONUtil.toJSONString(this));
    }

    @Override
    public void toJSON(JSONStringer stringer) throws JSONException {
        JSONUtil.fieldsToJSON(stringer, this, PartitionPlan.class, PartitionPlan.Members.values());
    }

    @Override
    public void fromJSON(JSONObject json_object, Database catalog_db) throws JSONException {
        JSONUtil.fieldsFromJSON(json_object, catalog_db, this, PartitionPlan.class, PartitionPlan.Members.values());
        this.initializeDependencies();
    }
}
TOP

Related Classes of edu.brown.designer.partitioners.plan.PartitionPlan

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.