/* 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.List;
import org.voltdb.catalog.Database;
import org.voltdb.plannodes.AbstractPlanNode;
import org.voltdb.plannodes.ReceivePlanNode;
import org.voltdb.plannodes.SendPlanNode;
/**
* Wrapper class for one static method that accepts a CompiledPlan
* instance with one PlanFragment and it splits it up into a set of
* PlanFragments. It splits plans anywhere it sees a Recv/Send-PlanNode
* pair, and makes the RecvNode's fragment depend on the SendNode's
* fragment.
*
*/
public class Fragmentizer {
/**
* Static method that is the main entry point for chopping up a plan.
* Note this will modify the plan in place as well as returning it.
*
* @param plan The plan to chop up.
* @return The chopped up plan.
*/
static CompiledPlan fragmentize(CompiledPlan plan, Database db) {
assert(plan != null);
assert(plan.fragments != null);
assert(plan.fragments.size() == 1);
// there should be only one fragment in the plan at this point
CompiledPlan.Fragment rootFragment = plan.fragments.get(0);
// rootFragment.planGraph.updateOutputColumns(db);
// chop up the plan and set all the proper dependencies recursively
recursiveFindFragment(rootFragment, rootFragment.planGraph, plan.fragments);
return plan;
}
/**
* Chop up the plan and set all the proper dependencies recursively
*
* @param currentFragment The fragment currently being examined recurively. This
* will likely contain the root of plan-subgraph currently being walked.
* @param currentNode The node in the plan graph currently being visited. This is
* the main unit of recursion here.
* @param fragments The list of fragments (initially one) that will be appended to
* as the method splits up the plan.
*/
static void recursiveFindFragment(
CompiledPlan.Fragment currentFragment,
AbstractPlanNode currentNode,
List<CompiledPlan.Fragment> fragments) {
// the place to split is the send-recv node pairing
if (currentNode instanceof ReceivePlanNode) {
ReceivePlanNode recvNode = (ReceivePlanNode) currentNode;
assert(recvNode.getChildPlanNodeCount() == 1);
AbstractPlanNode childNode = recvNode.getChild(0);
assert(childNode instanceof SendPlanNode);
SendPlanNode sendNode = (SendPlanNode) childNode;
// disconnect the send and receive nodes
sendNode.clearParents();
recvNode.clearChildren();
// make a new plan fragment rooted at the send
CompiledPlan.Fragment subFrag = new CompiledPlan.Fragment();
// put the multipartition hint from planning in the metadata
// for the new planfragment
subFrag.multiPartition = sendNode.isMultiPartition;
subFrag.planGraph = sendNode;
currentFragment.hasDependencies = true;
fragments.add(subFrag);
// THIS NEXT CHUNK OF CODE IS BROKEN BY THE 2-FRAGS
// PER PLAN ASSUMPTION
// make sure the parent fragment depends on the child
// sorry this is ugly append to an array code
/*int[] parentDepList = currentFragment.dependencyIds;
int[] newDepList = new int[parentDepList.length + 1];
for (int i = 0; i < parentDepList.length; i++)
newDepList[i] = parentDepList[i];
newDepList[newDepList.length - 1] = sendNode.getDependencyId();
currentFragment.dependencyIds = newDepList;*/
// recursive call on the new fragment
recursiveFindFragment(subFrag, sendNode, fragments);
// stop here if we found a recv node
return;
}
// if not a recv node, just do a boring recursive call
// stopping condition is when there are no children
for (int i = 0; i < currentNode.getChildPlanNodeCount(); i++) {
AbstractPlanNode childNode = currentNode.getChild(i);
recursiveFindFragment(currentFragment, childNode, fragments);
}
}
}