Skip to content

Commit

Permalink
Blow out cached bounds of all children when parent is invalidated.
Browse files Browse the repository at this point in the history
A concrete example where leaving them is not ok is
 - Range partition table
 - Delete entry from pathman_config (psin was blown, but bounds not)
 - Now hash partition table; bounds cache with uninitialized hash_idx is used.

While here, also spawn relcache inval message on delete from pathman_config, not
only from pathman_config_params.
  • Loading branch information
arssher committed Feb 25, 2019
1 parent 10e6c71 commit 85fc5cc
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 9 deletions.
6 changes: 5 additions & 1 deletion init.sql
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ ALTER TABLE @extschema@.pathman_config ENABLE ROW LEVEL SECURITY;
ALTER TABLE @extschema@.pathman_config_params ENABLE ROW LEVEL SECURITY;

/*
* Invalidate relcache every time someone changes parameters config.
* Invalidate relcache every time someone changes parameters config or pathman_config
*/
CREATE OR REPLACE FUNCTION @extschema@.pathman_config_params_trigger_func()
RETURNS TRIGGER AS 'pg_pathman', 'pathman_config_params_trigger_func'
Expand All @@ -121,6 +121,10 @@ CREATE TRIGGER pathman_config_params_trigger
AFTER INSERT OR UPDATE OR DELETE ON @extschema@.pathman_config_params
FOR EACH ROW EXECUTE PROCEDURE @extschema@.pathman_config_params_trigger_func();

CREATE TRIGGER pathman_config_trigger
AFTER INSERT OR UPDATE OR DELETE ON @extschema@.pathman_config
FOR EACH ROW EXECUTE PROCEDURE @extschema@.pathman_config_params_trigger_func();

/*
* Enable dump of config tables with pg_dump.
*/
Expand Down
4 changes: 4 additions & 0 deletions pg_pathman--1.4--1.5.sql
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ ALTER TABLE @extschema@.pathman_config ADD CONSTRAINT pathman_config_interval_ch
parttype,
range_interval));

CREATE TRIGGER pathman_config_trigger
AFTER INSERT OR UPDATE OR DELETE ON @extschema@.pathman_config
FOR EACH ROW EXECUTE PROCEDURE @extschema@.pathman_config_params_trigger_func();

/*
* Get parsed and analyzed expression.
*/
Expand Down
2 changes: 1 addition & 1 deletion src/hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -874,7 +874,7 @@ pathman_relcache_hook(Datum arg, Oid relid)
else if (relid >= FirstNormalObjectId)
{
/* Invalidate PartBoundInfo entry if needed */
forget_bounds_of_partition(relid);
forget_bounds_of_rel(relid);

/* Invalidate PartParentInfo entry if needed */
forget_parent_of_partition(relid);
Expand Down
2 changes: 1 addition & 1 deletion src/include/relation_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ void shout_if_prel_is_invalid(const Oid parent_oid,
const PartType expected_part_type);

/* Bounds cache */
void forget_bounds_of_partition(Oid partition);
void forget_bounds_of_rel(Oid partition);
PartBoundInfo *get_bounds_of_partition(Oid partition, const PartRelationInfo *prel);
Expr *get_partition_constraint_expr(Oid partition, bool raise_error);
void invalidate_bounds_cache(void);
Expand Down
17 changes: 12 additions & 5 deletions src/pl_funcs.c
Original file line number Diff line number Diff line change
Expand Up @@ -904,14 +904,16 @@ pathman_config_params_trigger_func(PG_FUNCTION_ARGS)
{
TriggerData *trigdata = (TriggerData *) fcinfo->context;
Oid pathman_config_params;
Oid pathman_config;
Oid partrel;
Datum partrel_datum;
bool partrel_isnull;

/* Fetch Oid of PATHMAN_CONFIG_PARAMS */
pathman_config_params = get_pathman_config_params_relid(true);
pathman_config = get_pathman_config_relid(true);

/* Handle "pg_pathman.enabled = t" case */
/* Handle "pg_pathman.enabled = f" case */
if (!OidIsValid(pathman_config_params))
goto pathman_config_params_trigger_func_return;

Expand All @@ -925,12 +927,17 @@ pathman_config_params_trigger_func(PG_FUNCTION_ARGS)
trigdata->tg_trigger->tgname);

/* Handle wrong relation */
if (RelationGetRelid(trigdata->tg_relation) != pathman_config_params)
elog(ERROR, "%s: must be fired for relation \"%s\"",
if (RelationGetRelid(trigdata->tg_relation) != pathman_config_params &&
RelationGetRelid(trigdata->tg_relation) != pathman_config)
elog(ERROR, "%s: must be fired for relation \"%s\" or \"%s\"",
trigdata->tg_trigger->tgname,
get_rel_name(pathman_config_params));
get_rel_name(pathman_config_params),
get_rel_name(pathman_config));

/* Extract partitioned relation's Oid */
/*
* Extract partitioned relation's Oid.
* Hacky: 1 is attrnum of relid for both pathman_config and pathman_config_params
*/
partrel_datum = heap_getattr(trigdata->tg_trigtuple,
Anum_pathman_config_params_partrel,
RelationGetDescr(trigdata->tg_relation),
Expand Down
40 changes: 39 additions & 1 deletion src/relation_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ static void fill_pbin_with_bounds(PartBoundInfo *pbin,

static int cmp_range_entries(const void *p1, const void *p2, void *arg);

static void forget_bounds_of_partition(Oid partition);

static bool query_contains_subqueries(Node *node, void *context);


Expand Down Expand Up @@ -929,7 +931,7 @@ PrelExpressionAttributesMap(const PartRelationInfo *prel,
*/

/* Remove partition's constraint from cache */
void
static void
forget_bounds_of_partition(Oid partition)
{
PartBoundInfo *pbin;
Expand All @@ -953,6 +955,42 @@ forget_bounds_of_partition(Oid partition)
HASH_REMOVE,
NULL);
}

}

/*
* Remove rel's constraint from cache, if relid is partition;
* Remove all children constraints, if it is parent.
*/
void
forget_bounds_of_rel(Oid relid)
{
PartStatusInfo *psin;

forget_bounds_of_partition(relid);

/*
* If it was the parent who got invalidated, purge children's bounds.
* We assume here that if bounds_cache has something, parent must be also
* in status_cache. Fragile, but seems better then blowing out full bounds
* cache or digging pathman_config on each relcache invalidation.
*/

/* Find status cache entry for this relation */
psin = pathman_cache_search_relid(status_cache,
relid, HASH_FIND,
NULL);
if (psin != NULL && psin->prel != NULL)
{
uint32 i;
PartRelationInfo *prel = psin->prel;
Oid *children = PrelGetChildrenArray(prel);

for (i = 0; i < PrelChildrenCount(prel); i++)
{
forget_bounds_of_partition(children[i]);
}
}
}

/* Return partition's constraint as expression tree */
Expand Down

0 comments on commit 85fc5cc

Please sign in to comment.