Update the places where we check circular dependency

velioglu/cyclic_dep_with_tho
Burak Velioglu 2022-03-07 14:59:21 +03:00
parent 6f25b74c40
commit 3c40ceef96
No known key found for this signature in database
GPG Key ID: F6827E620F6549C6
5 changed files with 59 additions and 42 deletions

View File

@ -31,7 +31,6 @@
typedef bool (*AddressPredicate)(const ObjectAddress *);
static void ErrorIfCircularDependencyExists(const ObjectAddress *objectAddress);
static int ObjectAddressComparator(const void *a, const void *b);
static List * GetDependencyCreateDDLCommands(const ObjectAddress *dependency);
static List * FilterObjectAddressListByPredicate(List *objectAddressList,
@ -57,13 +56,6 @@ EnsureDependenciesExistOnAllNodes(const ObjectAddress *target)
List *dependenciesWithCommands = NIL;
List *ddlCommands = NULL;
/*
* Having circular dependency between distributed objects prevents Citus from
* adding a new node. So, error out if circular dependency exists for the given
* target object.
*/
ErrorIfCircularDependencyExists(target);
/* collect all dependencies in creation order and get their ddl commands */
List *dependencies = GetDependenciesForObject(target);
ObjectAddress *dependency = NULL;
@ -143,40 +135,6 @@ EnsureDependenciesExistOnAllNodes(const ObjectAddress *target)
}
/*
* ErrorIfCircularDependencyExists checks whether given object has circular dependency
* with itself via existing objects of pg_dist_object.
*/
static void
ErrorIfCircularDependencyExists(const ObjectAddress *objectAddress)
{
List *dependencies = GetAllSupportedDependenciesForObject(objectAddress);
ObjectAddress *dependency = NULL;
foreach_ptr(dependency, dependencies)
{
if (dependency->classId == objectAddress->classId &&
dependency->objectId == objectAddress->objectId &&
dependency->objectSubId == objectAddress->objectSubId)
{
char *objectDescription = NULL;
#if PG_VERSION_NUM >= PG_VERSION_14
objectDescription = getObjectDescription(objectAddress, false);
#else
objectDescription = getObjectDescription(objectAddress);
#endif
ereport(ERROR, (errmsg("Citus can not handle circular dependencies "
"between distributed objects"),
errdetail("\"%s\" circularly depends itself, resolve "
"circular dependency first",
objectDescription)));
}
}
}
/*
* Copied from PG object_address_comparator function to compare ObjectAddresses.
*/

View File

@ -58,6 +58,7 @@
#include "distributed/metadata_cache.h"
#endif
#include "distributed/metadata_sync.h"
#include "distributed/metadata/dependency.h"
#include "distributed/metadata/distobject.h"
#include "distributed/multi_executor.h"
#include "distributed/multi_explain.h"
@ -656,6 +657,18 @@ ProcessUtilityInternal(PlannedStmt *pstmt,
*/
if (EnableDDLPropagation)
{
/*
* Having circular dependency between distributed objects prevents Citus from
* adding a new node. So, error out if circular dependency exists for the given
* target object.
*
* We need to check circular dependency here in addition to checking it within
* MarkObjectDistributedLocally since altering already distributed object won't
* call MarkObjectDistributedLocally but will hit the check here.
*/
ObjectAddress targetObject = GetObjectAddressFromParseTree(parsetree, false);
ErrorIfCircularDependencyExists(&targetObject);
if (ops && ops->postprocess)
{
List *processJobs = ops->postprocess(parsetree, queryString);

View File

@ -378,6 +378,40 @@ RecurseObjectDependencies(ObjectAddress target, expandFn expand, followFn follow
}
/*
* ErrorIfCircularDependencyExists checks whether given object has circular dependency
* with itself via existing objects of pg_dist_object.
*/
void
ErrorIfCircularDependencyExists(const ObjectAddress *objectAddress)
{
List *dependencies = GetAllSupportedDependenciesForObject(objectAddress);
ObjectAddress *dependency = NULL;
foreach_ptr(dependency, dependencies)
{
if (dependency->classId == objectAddress->classId &&
dependency->objectId == objectAddress->objectId &&
dependency->objectSubId == objectAddress->objectSubId)
{
char *objectDescription = NULL;
#if PG_VERSION_NUM >= PG_VERSION_14
objectDescription = getObjectDescription(objectAddress, false);
#else
objectDescription = getObjectDescription(objectAddress);
#endif
ereport(ERROR, (errmsg("Citus can not handle circular dependencies "
"between distributed objects"),
errdetail("\"%s\" circularly depends itself, resolve "
"circular dependency first",
objectDescription)));
}
}
}
/*
* DependencyDefinitionFromPgDepend loads all pg_depend records describing the
* dependencies of target.

View File

@ -30,6 +30,7 @@
#include "commands/extension.h"
#include "distributed/colocation_utils.h"
#include "distributed/commands/utility_hook.h"
#include "distributed/metadata/dependency.h"
#include "distributed/metadata/distobject.h"
#include "distributed/metadata/pg_dist_object.h"
#include "distributed/metadata_cache.h"
@ -198,6 +199,16 @@ MarkObjectDistributedViaSuperUser(const ObjectAddress *distAddress)
static void
MarkObjectDistributedLocally(const ObjectAddress *distAddress)
{
/*
* Having circular dependency between distributed objects prevents Citus from
* adding a new node. So, error out if circular dependency exists for the given
* target object.
*
* Similar check also added to postprocess phase of ProcessUtilityInternal to
* handle altering already distributed objects.
*/
ErrorIfCircularDependencyExists(distAddress);
int paramCount = 3;
Oid paramTypes[3] = {
OIDOID,

View File

@ -24,6 +24,7 @@ extern List * GetAllDependenciesForObject(const ObjectAddress *target);
extern void EnsureRelationDependenciesCanBeDistributed(ObjectAddress *relationAddress);
extern ObjectAddress * GetUndistributableDependency(ObjectAddress *target);
extern List * OrderObjectAddressListInDependencyOrder(List *objectAddressList);
extern void ErrorIfCircularDependencyExists(const ObjectAddress *objectAddress);
extern bool SupportedDependencyByCitus(const ObjectAddress *address);
extern List * GetPgDependTuplesForDependingObjects(Oid targetObjectClassId,
Oid targetObjectId);