Esempio n. 1
0
/*
 * cdbpathtoplan_create_flow
 */
Flow *
cdbpathtoplan_create_flow(PlannerInfo  *root,
                          CdbPathLocus  locus,
                          Relids        relids,
                          List         *pathkeys,
                          Plan         *plan)
{
    Flow       *flow = NULL;

    /* Distribution */
    if (CdbPathLocus_IsEntry(locus))
    {
        flow = makeFlow(FLOW_SINGLETON);
        flow->segindex = -1;
    }
    else if (CdbPathLocus_IsSingleQE(locus))
    {
        flow = makeFlow(FLOW_SINGLETON);
        flow->segindex = 0;
    }
    else if (CdbPathLocus_IsGeneral(locus))
    {
        flow = makeFlow(FLOW_SINGLETON);
        flow->segindex = 0;
    }
    else if (CdbPathLocus_IsReplicated(locus))
    {
        flow = makeFlow(FLOW_REPLICATED);
    }
    else if (CdbPathLocus_IsHashed(locus) ||
             CdbPathLocus_IsHashedOJ(locus))
    {
        flow = makeFlow(FLOW_PARTITIONED);
        flow->hashExpr = cdbpathlocus_get_partkey_exprs(locus,
                                                        relids,
                                                        plan->targetlist);
        /*
         * hashExpr can be NIL if the rel is partitioned on columns that aren't
         * projected (i.e. are not present in the result of this Path operator).
         */
    }
    else if (CdbPathLocus_IsStrewn(locus))
        flow = makeFlow(FLOW_PARTITIONED);
    else
        Insist(0);
	
    /*
     * Describe the ordering of the result rows.  The ordering info will be
     * truncated upon encountering an expr which is not already present in the
     * plan's targetlist.  Duplicate cols and constant cols will be omitted.
     */
    if (pathkeys)
    {
        Sort   *sort = make_sort_from_pathkeys(root, plan, pathkeys, relids, false);

        if (sort)
        {
            flow->numSortCols = sort->numCols;
            flow->sortColIdx = sort->sortColIdx;
            flow->sortOperators = sort->sortOperators;
        }
    }

    flow->req_move = MOVEMENT_NONE;
	flow->locustype = locus.locustype;
    return flow;
}                               /* cdbpathtoplan_create_flow */
Esempio n. 2
0
/*
 * cdbpathtoplan_create_motion_plan
 */
Motion *
cdbpathtoplan_create_motion_plan(PlannerInfo   *root,
                                 CdbMotionPath *path,
                                 Plan          *subplan)
{
    Motion *motion = NULL;
    Path   *subpath = path->subpath;

    /* Send all tuples to a single process? */
    if (CdbPathLocus_IsBottleneck(path->path.locus))
    {
        int destSegIndex = -1;                          /* to dispatcher */

        if (CdbPathLocus_IsSingleQE(path->path.locus))
            destSegIndex = gp_singleton_segindex;      /* to singleton qExec */

        if (path->path.pathkeys)
        {
            /*
             * Build a dummy Sort node.  We'll take its sort key info to
             * define our Merge Receive keys.  Unchanged subplan ptr is
             * returned to us if ordering is degenerate (all cols constant).
             */
            Sort   *sort = make_sort_from_pathkeys(root,
                                                   subplan,
                                                   path->path.pathkeys,
                                                   path->path.parent->relids,
                                                   true);

            /* Merge Receive to preserve ordering */
            if (sort)
            {
                /* Result node might have been added below the Sort */
                subplan = sort->plan.lefttree; 
                motion = make_sorted_union_motion(subplan,
                                                  destSegIndex,
                                                  sort->numCols,
                                                  sort->sortColIdx,
                                                  sort->sortOperators,
                                                  false /* useExecutorVarFormat */
                                                  );
            }
        
            /* Degenerate ordering... build unordered Union Receive */
            else
                motion = make_union_motion(subplan,
                                           destSegIndex,
                                           false /* useExecutorVarFormat */
                                           );
        }
        
        /* Unordered Union Receive */
        else
            motion = make_union_motion(subplan,
                                       destSegIndex,
                                       false /* useExecutorVarFormat */
                                       );
    }

    /* Send all of the tuples to all of the QEs in gang above... */
    else if (CdbPathLocus_IsReplicated(path->path.locus))
            motion = make_broadcast_motion(subplan,
                                           false /* useExecutorVarFormat */
                                           );

    /* Hashed redistribution to all QEs in gang above... */
    else if (CdbPathLocus_IsHashed(path->path.locus) ||
             CdbPathLocus_IsHashedOJ(path->path.locus))
    {
        List   *hashExpr = cdbpathlocus_get_partkey_exprs(path->path.locus,
                                                          path->path.parent->relids,
                                                          subplan->targetlist);
        Insist(hashExpr);

        /**
         * If there are subplans in the hashExpr, push it down to lower level.
         */
        if (contain_subplans( (Node *) hashExpr)
        	&&is_projection_capable_plan(subplan))
		{
			subplan->targetlist = add_to_flat_tlist(subplan->targetlist, hashExpr, true /* resjunk */);
        }

        motion = make_hashed_motion(subplan,
                                    hashExpr,
                                    false /* useExecutorVarFormat */);
    }
    else
        Insist(0);

    /*
     * Decorate the subplan with a Flow node telling the plan slicer
     * what kind of gang will be needed to execute the subplan.
     */
    subplan->flow = cdbpathtoplan_create_flow(root,
                                              subpath->locus,
                                              subpath->parent
                                                ? subpath->parent->relids
                                                : NULL,
                                              subpath->pathkeys,
                                              subplan);

	/**
	 * If plan has a flow node, and its child is projection capable,
	 * then ensure all entries of hashExpr are in the targetlist.
	 */
	if (subplan->flow
			&& subplan->flow->hashExpr
			&& is_projection_capable_plan(subplan))
	{
		subplan->targetlist = add_to_flat_tlist(subplan->targetlist, subplan->flow->hashExpr, true /* resjunk */);
	}

    return motion;
}                               /* cdbpathtoplan_create_motion_plan */
Esempio n. 3
0
/*
 * cdbpath_create_motion_path
 *    Returns a Path that delivers the subpath result to the
 *    given locus, or NULL if it can't be done.
 *
 *    'pathkeys' must specify an ordering equal to or weaker than the
 *    subpath's existing ordering.
 *
 *    If no motion is needed, the caller's subpath is returned unchanged.
 *    Else if require_existing_order is true, NULL is returned if the
 *      motion would not preserve an ordering at least as strong as the
 *      specified ordering; also NULL is returned if pathkeys is NIL
 *      meaning the caller is just checking and doesn't want to add motion.
 *    Else a CdbMotionPath is returned having either the specified pathkeys
 *      (if given and the motion uses Merge Receive), or the pathkeys
 *      of the original subpath (if the motion is order-preserving), or no
 *      pathkeys otherwise (the usual case).
 */
Path *
cdbpath_create_motion_path(PlannerInfo     *root,
                           Path            *subpath,
                           List            *pathkeys,
                           bool             require_existing_order,
                           CdbPathLocus     locus)
{
    CdbMotionPath      *pathnode;

    UnusedArg(root);
    Assert(cdbpathlocus_is_valid(locus) &&
           cdbpathlocus_is_valid(subpath->locus));

    /* Moving subpath output to a single executor process (qDisp or qExec)? */
    if (CdbPathLocus_IsBottleneck(locus))
    {
        /* entry-->entry or singleQE-->singleQE?  No motion needed. */
        if (CdbPathLocus_IsEqual(subpath->locus, locus))
            return subpath;

        /* entry-->singleQE?  Don't move.  Slice's QE will run on entry db. */
        if (CdbPathLocus_IsEntry(subpath->locus))
            return subpath;

        /* singleQE-->entry?  Don't move.  Slice's QE will run on entry db. */
        if (CdbPathLocus_IsSingleQE(subpath->locus))
        {
            /* Create CdbMotionPath node to indicate that the slice must be
             * dispatched to a singleton gang running on the entry db.  We
             * merely use this node to note that the path has 'Entry' locus;
             * no corresponding Motion node will be created in the Plan tree.
             */
            Assert(CdbPathLocus_IsEntry(locus));

            pathnode = makeNode(CdbMotionPath);
            pathnode->path.pathtype = T_Motion;
            pathnode->path.parent = subpath->parent;
            pathnode->path.locus = locus;
            pathnode->path.pathkeys = pathkeys;
            pathnode->subpath = subpath;

            /* Costs, etc, are same as subpath. */
            pathnode->path.startup_cost = subpath->total_cost;
            pathnode->path.total_cost = subpath->total_cost;
            pathnode->path.memory = subpath->memory;
            pathnode->path.motionHazard = subpath->motionHazard;
            pathnode->path.rescannable = subpath->rescannable;
            return (Path *)pathnode;
        }

        /* No motion needed if subpath can run anywhere giving same output. */
        if (CdbPathLocus_IsGeneral(subpath->locus))
            return subpath;

        /* Fail if caller refuses motion. */
        if (require_existing_order &&
            !pathkeys)
            return NULL;

        /* replicated-->singleton would give redundant copies of the rows. */
        if (CdbPathLocus_IsReplicated(subpath->locus))
            goto invalid_motion_request;

        /* Must be partitioned-->singleton.
         *  If caller gave pathkeys, they'll be used for Merge Receive.
         *  If no pathkeys, Union Receive will arbitrarily interleave
         *  the rows from the subpath partitions in no special order.
         */
        if (!CdbPathLocus_IsPartitioned(subpath->locus))
            goto invalid_motion_request;
    }

    /* Output from a single process to be distributed over a gang? */
    else if (CdbPathLocus_IsBottleneck(subpath->locus))
    {
        /* Must be bottleneck-->partitioned or bottleneck-->replicated */
        if (!CdbPathLocus_IsPartitioned(locus) &&
            !CdbPathLocus_IsReplicated(locus))
            goto invalid_motion_request;

        /* Fail if caller disallows motion. */
        if (require_existing_order &&
            !pathkeys)
            return NULL;

        /* Each qExec receives a subset of the rows, with ordering preserved. */
        pathkeys = subpath->pathkeys;
    }

    /* Redistributing partitioned subpath output from one gang to another? */
    else if (CdbPathLocus_IsPartitioned(subpath->locus))
    {
        /* partitioned-->partitioned? */
        if (CdbPathLocus_IsPartitioned(locus))
        {
            /* No motion if subpath partitioning matches caller's request. */
            if (cdbpathlocus_compare(CdbPathLocus_Comparison_Equal, subpath->locus, locus))
                return subpath;
        }

        /* Must be partitioned-->replicated */
        else if (!CdbPathLocus_IsReplicated(locus))
            goto invalid_motion_request;

        /* Fail if caller insists on ordered result or no motion. */
        if (require_existing_order)
            return NULL;

        /* Output streams lose any ordering they had.
         * Only a qDisp or singleton qExec can merge sorted streams (for now).
         */
        pathkeys = NIL;
    }

    /* If subplan uses no tables, it can run on qDisp or a singleton qExec. */
    else if (CdbPathLocus_IsGeneral(subpath->locus))
    {
        /* No motion needed if general-->general or general-->replicated. */
        if (CdbPathLocus_IsGeneral(locus) ||
            CdbPathLocus_IsReplicated(locus))
            return subpath;

        /* Must be general-->partitioned. */
        if (!CdbPathLocus_IsPartitioned(locus))
            goto invalid_motion_request;

        /* Fail if caller wants no motion. */
        if (require_existing_order &&
            !pathkeys)
            return NULL;

        /* Since the motion is 1-to-many, the rows remain in the same order. */
        pathkeys = subpath->pathkeys;
    }

    /* Does subpath produce same multiset of rows on every qExec of its gang? */
    else if (CdbPathLocus_IsReplicated(subpath->locus))
    {
        /* No-op if replicated-->replicated. */
        if (CdbPathLocus_IsReplicated(locus))
            return subpath;

        /* Other destinations aren't used or supported at present. */
        goto invalid_motion_request;
    }
    else
        goto invalid_motion_request;

    /* Don't materialize before motion. */
    if (IsA(subpath, MaterialPath))
        subpath = ((MaterialPath *)subpath)->subpath;

	/*
	 * MPP-3300: materialize *before* motion can never help us, motion
	 * pushes data. other nodes pull. We relieve motion deadlocks by
	 * adding materialize nodes on top of motion nodes
	 */

    /* Create CdbMotionPath node. */
    pathnode = makeNode(CdbMotionPath);
    pathnode->path.pathtype = T_Motion;
    pathnode->path.parent = subpath->parent;
    pathnode->path.locus = locus;
    pathnode->path.pathkeys = pathkeys;
    pathnode->subpath = subpath;

    /* Cost of motion */
    cdbpath_cost_motion(root, pathnode);

    /* Tell operators above us that slack may be needed for deadlock safety. */
    pathnode->path.motionHazard = true;
    pathnode->path.rescannable = false;

    return (Path *)pathnode;

    /* Unexpected source or destination locus. */
invalid_motion_request:
    Assert(0);
    return NULL;
}                               /* cdbpath_create_motion_path */