blob: 0ea3456dfeff33df2bd9ce88a1b09a37ad868831 [file] [log] [blame]
/*
* planshare.c
* Plan shared plan
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
#include "postgres.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
#include "optimizer/planmain.h"
#include "optimizer/tlist.h"
#include "optimizer/subselect.h"
#include "optimizer/planshare.h"
#include "cdb/cdbgroup.h" /* cdbpathlocus_collocates() */
#include "cdb/cdbpath.h"
#include "cdb/cdbsetop.h" /* make_motion... routines */
#include "cdb/cdbmutate.h" /* add_slice_to_motion */
#include "cdb/cdbvars.h"
int get_plan_share_id(Plan *p)
{
if(IsA(p, Material))
return ((Material *) p)->share_id;
if(IsA(p, Sort))
return ((Sort *) p)->share_id;
Assert(IsA(p, ShareInputScan));
return ((ShareInputScan *) p)->share_id;
}
void set_plan_share_id(Plan *p, int share_id)
{
if(IsA(p, Material))
((Material *) p)->share_id = share_id;
else if(IsA(p, Sort))
((Sort *) p)->share_id = share_id;
else
{
Assert(IsA(p, ShareInputScan));
((ShareInputScan *) p)->share_id = share_id;
}
}
ShareType get_plan_share_type(Plan *p)
{
if(IsA(p, Material))
return ((Material *) p)->share_type;
if(IsA(p, Sort))
return ((Sort *) p)->share_type ;
Assert(IsA(p, ShareInputScan));
return ((ShareInputScan *) p)->share_type;
}
void set_plan_share_type(Plan *p, ShareType share_type)
{
if(IsA(p, Material))
((Material *) p)->share_type = share_type;
else if(IsA(p, Sort))
((Sort *) p)->share_type = share_type;
else
{
Assert(IsA(p, ShareInputScan));
((ShareInputScan *) p)->share_type = share_type;
}
}
void set_plan_share_type_xslice(Plan *p)
{
ShareType st = get_plan_share_type(p);
if(st == SHARE_MATERIAL)
set_plan_share_type(p, SHARE_MATERIAL_XSLICE);
else
{
Assert(st == SHARE_SORT);
set_plan_share_type(p, SHARE_SORT_XSLICE);
}
}
int get_plan_driver_slice(Plan *p)
{
if(IsA(p, Material))
return ((Material *) p)->driver_slice;
Assert(IsA(p, Sort));
return ((Sort *) p)->driver_slice;
}
void set_plan_driver_slice(Plan *p, int slice)
{
if(IsA(p, Material))
((Material *) p)->driver_slice = slice;
else
{
Assert(IsA(p, Sort));
((Sort *) p)->driver_slice = slice;
}
}
static void incr_plan_nsharer(Plan *p)
{
if(IsA(p, Material))
((Material *) p)->nsharer++;
else
{
Assert(IsA(p, Sort));
((Sort *) p)->nsharer++;
}
}
void incr_plan_nsharer_xslice(Plan *p)
{
if(IsA(p, Material))
((Material *) p)->nsharer_xslice++;
else
{
Assert(IsA(p, Sort));
((Sort *) p)->nsharer_xslice++;
}
}
static ShareInputScan *make_shareinputscan(PlannerInfo *root, Plan *inputplan)
{
ShareInputScan *sisc = NULL;
Path sipath;
Assert(IsA(inputplan, Material) || IsA(inputplan, Sort));
sisc = makeNode(ShareInputScan);
incr_plan_nsharer(inputplan);
sisc->plan.targetlist = copyObject(inputplan->targetlist);
sisc->plan.lefttree = inputplan;
sisc->plan.flow = copyObject(inputplan->flow);
set_plan_share_type((Plan *) sisc, get_plan_share_type(inputplan));
set_plan_share_id((Plan *) sisc, get_plan_share_id(inputplan));
sisc->driver_slice = -1;
sisc->plan.qual = NIL;
sisc->plan.righttree = NULL;
cost_shareinputscan(&sipath, root, inputplan->total_cost, inputplan->plan_rows, inputplan->plan_width);
sisc->plan.startup_cost = sipath.startup_cost;
sisc->plan.total_cost = sipath.total_cost;
sisc->plan.plan_rows = inputplan->plan_rows;
sisc->plan.plan_width = inputplan->plan_width;
sisc->plan.extParam = bms_copy(inputplan->extParam);
sisc->plan.allParam = bms_copy(inputplan->allParam);
return sisc;
}
List *share_plan(PlannerInfo *root, Plan *common, int numpartners)
{
List *shared_nodes = NULL;
ShareType stype;
Plan *shared = common;
bool xslice = false;
int i;
Assert(numpartners > 0);
if(numpartners == 1)
{
shared_nodes = lappend(shared_nodes, common);
return shared_nodes;
}
if (IsA(common, ShareInputScan))
{
shared = common->lefttree;
}
else if(IsA(common, Material))
{
Material *m = (Material *) common;
Assert(m->share_type == SHARE_NOTSHARED);
Assert(m->share_id == SHARE_ID_NOT_SHARED);
stype = xslice ? SHARE_MATERIAL_XSLICE : SHARE_MATERIAL;
m->share_id = SHARE_ID_NOT_ASSIGNED;
m->share_type = stype;
}
else if (IsA(common, Sort))
{
Sort *s = (Sort *) common;
Assert(s->share_type == SHARE_NOTSHARED);
stype = xslice ? SHARE_SORT_XSLICE : SHARE_SORT;
s->share_id = SHARE_ID_NOT_ASSIGNED;
s->share_type = stype;
}
else
{
Path matpath;
Material *m = make_material(common);
shared = (Plan *) m;
cost_material(&matpath, root, common->total_cost, common->plan_rows, common->plan_width);
shared->startup_cost = matpath.startup_cost;
shared->total_cost = matpath.total_cost;
shared->plan_rows = common->plan_rows;
shared->plan_width = common->plan_width;
shared->dispatch = common->dispatch;
shared->flow = copyObject(common->flow);
stype = xslice ? SHARE_MATERIAL_XSLICE : SHARE_MATERIAL;
m->share_id = SHARE_ID_NOT_ASSIGNED;
m->share_type = stype;
}
for(i=0; i<numpartners; ++i)
{
Plan *p = (Plan *) make_shareinputscan(root, shared);
shared_nodes = lappend(shared_nodes, p);
}
return shared_nodes;
}
/*
* Return the total cost of sharing common numpartner times.
* If the planner need to make a decision whether the common subplan should be shared
* or should be duplicated, planner should compare the cost returned by this function
* against common->total_cost * numpartners.
*/
Cost cost_share_plan(Plan *common, PlannerInfo *root, int numpartners)
{
Path sipath;
Path mapath;
if(IsA(common, Material) || IsA(common, Sort))
{
cost_shareinputscan(&sipath, root, common->total_cost, common->plan_rows, common->plan_width);
return common->total_cost + (sipath.total_cost - common->total_cost) * numpartners;
}
cost_material(&mapath, root, common->total_cost, common->plan_rows, common->plan_width);
cost_shareinputscan(&sipath, root, mapath.total_cost, common->plan_rows, common->plan_width);
return mapath.total_cost + (sipath.total_cost - mapath.total_cost) * numpartners;
}