citus/src/backend/distributed/executor/placement_access.c

162 lines
4.7 KiB
C

/*-------------------------------------------------------------------------
*
* citus_custom_scan.c
*
* Definitions of the functions used in generating the placement accesses
* for distributed query execution.
*
* Copyright (c) Citus Data, Inc.
*-------------------------------------------------------------------------
*/
#include "distributed/placement_access.h"
#include "distributed/metadata_cache.h"
static List * BuildPlacementSelectList(int32 groupId, List *relationShardList);
static List * BuildPlacementDDLList(int32 groupId, List *relationShardList);
static List * BuildPlacementAccessList(int32 groupId, List *relationShardList,
ShardPlacementAccessType accessType);
/*
* PlacementAccessListForTask returns a list of placement accesses for a given
* task and task placement.
*/
List *
PlacementAccessListForTask(Task *task, ShardPlacement *taskPlacement)
{
List *placementAccessList = NIL;
List *relationShardList = task->relationShardList;
bool addAnchorAccess = false;
ShardPlacementAccessType accessType = PLACEMENT_ACCESS_SELECT;
if (task->taskType == MODIFY_TASK)
{
/* DML command */
addAnchorAccess = true;
accessType = PLACEMENT_ACCESS_DML;
}
else if (task->taskType == DDL_TASK || task->taskType == VACUUM_ANALYZE_TASK)
{
/* DDL command */
addAnchorAccess = true;
accessType = PLACEMENT_ACCESS_DDL;
}
else if (relationShardList == NIL)
{
/* SELECT query that does not touch any shard placements */
addAnchorAccess = true;
accessType = PLACEMENT_ACCESS_SELECT;
}
if (addAnchorAccess)
{
ShardPlacementAccess *placementAccess =
CreatePlacementAccess(taskPlacement, accessType);
placementAccessList = lappend(placementAccessList, placementAccess);
}
/*
* We've already added anchor shardId's placement access to the list. Now,
* add the other placements in the relationShardList.
*/
if (accessType == PLACEMENT_ACCESS_DDL)
{
/*
* All relations appearing inter-shard DDL commands should be marked
* with DDL access.
*/
List *relationShardAccessList =
BuildPlacementDDLList(taskPlacement->groupId, relationShardList);
placementAccessList = list_concat(placementAccessList, relationShardAccessList);
}
else
{
/*
* In case of SELECTs or DML's, we add SELECT placement accesses to the
* elements in relationShardList. For SELECT queries, it is trivial, since
* the query is literally accesses the relationShardList in the same query.
*
* For DMLs, create placement accesses for placements that appear in a
* subselect.
*/
List *relationShardAccessList =
BuildPlacementSelectList(taskPlacement->groupId, relationShardList);
placementAccessList = list_concat(placementAccessList, relationShardAccessList);
}
return placementAccessList;
}
/*
* BuildPlacementSelectList builds a list of SELECT placement accesses
* which can be used to call StartPlacementListConnection or
* GetPlacementListConnection. If the node group does not have a placement
* (e.g. in case of a broadcast join) then the shard is skipped.
*/
static List *
BuildPlacementSelectList(int32 groupId, List *relationShardList)
{
return BuildPlacementAccessList(groupId, relationShardList, PLACEMENT_ACCESS_SELECT);
}
/*
* BuildPlacementDDLList is a warpper around BuildPlacementAccessList() for DDL access.
*/
static List *
BuildPlacementDDLList(int32 groupId, List *relationShardList)
{
return BuildPlacementAccessList(groupId, relationShardList, PLACEMENT_ACCESS_DDL);
}
/*
* BuildPlacementAccessList returns a list of placement accesses for the given
* relationShardList and the access type.
*/
static List *
BuildPlacementAccessList(int32 groupId, List *relationShardList,
ShardPlacementAccessType accessType)
{
ListCell *relationShardCell = NULL;
List *placementAccessList = NIL;
foreach(relationShardCell, relationShardList)
{
RelationShard *relationShard = (RelationShard *) lfirst(relationShardCell);
ShardPlacement *placement = FindShardPlacementOnGroup(groupId,
relationShard->shardId);
if (placement == NULL)
{
continue;
}
ShardPlacementAccess *placementAccess = CreatePlacementAccess(placement,
accessType);
placementAccessList = lappend(placementAccessList, placementAccess);
}
return placementAccessList;
}
/*
* CreatePlacementAccess returns a new ShardPlacementAccess for the given placement
* and access type.
*/
ShardPlacementAccess *
CreatePlacementAccess(ShardPlacement *placement, ShardPlacementAccessType accessType)
{
ShardPlacementAccess *placementAccess = (ShardPlacementAccess *) palloc0(
sizeof(ShardPlacementAccess));
placementAccess->placement = placement;
placementAccess->accessType = accessType;
return placementAccess;
}