Skip to content

Commit 24bc7d8

Browse files
committed
refactoring & bugfixes in scan_result_parts_storage() & select_partition_for_insert(), more tests
1 parent 7e465d2 commit 24bc7d8

13 files changed

+201
-118
lines changed

hash.sql

+4-4
Original file line numberDiff line numberDiff line change
@@ -75,15 +75,15 @@ BEGIN
7575

7676
IF lock_parent THEN
7777
/* Acquire data modification lock (prevent further modifications) */
78-
PERFORM @extschema@.prevent_relation_modification(parent_relid);
78+
PERFORM @extschema@.prevent_data_modification(parent_relid);
7979
ELSE
8080
/* Acquire lock on parent */
81-
PERFORM @extschema@.lock_partitioned_relation(parent_relid);
81+
PERFORM @extschema@.prevent_part_modification(parent_relid);
8282
END IF;
8383

8484
/* Acquire data modification lock (prevent further modifications) */
85-
PERFORM @extschema@.prevent_relation_modification(old_partition);
86-
PERFORM @extschema@.prevent_relation_modification(new_partition);
85+
PERFORM @extschema@.prevent_data_modification(old_partition);
86+
PERFORM @extschema@.prevent_data_modification(new_partition);
8787

8888
/* Ignore temporary tables */
8989
SELECT relpersistence FROM pg_catalog.pg_class

init.sql

+7-7
Original file line numberDiff line numberDiff line change
@@ -438,10 +438,10 @@ BEGIN
438438

439439
IF partition_data = true THEN
440440
/* Acquire data modification lock */
441-
PERFORM @extschema@.prevent_relation_modification(parent_relid);
441+
PERFORM @extschema@.prevent_data_modification(parent_relid);
442442
ELSE
443443
/* Acquire lock on parent */
444-
PERFORM @extschema@.lock_partitioned_relation(parent_relid);
444+
PERFORM @extschema@.prevent_part_modification(parent_relid);
445445
END IF;
446446

447447
/* Ignore temporary tables */
@@ -601,7 +601,7 @@ BEGIN
601601
PERFORM @extschema@.validate_relname(parent_relid);
602602

603603
/* Acquire data modification lock */
604-
PERFORM @extschema@.prevent_relation_modification(parent_relid);
604+
PERFORM @extschema@.prevent_data_modification(parent_relid);
605605

606606
IF NOT EXISTS (SELECT FROM @extschema@.pathman_config
607607
WHERE partrel = parent_relid) THEN
@@ -916,17 +916,17 @@ LANGUAGE C;
916916
* Lock partitioned relation to restrict concurrent
917917
* modification of partitioning scheme.
918918
*/
919-
CREATE OR REPLACE FUNCTION @extschema@.lock_partitioned_relation(
919+
CREATE OR REPLACE FUNCTION @extschema@.prevent_part_modification(
920920
parent_relid REGCLASS)
921-
RETURNS VOID AS 'pg_pathman', 'lock_partitioned_relation'
921+
RETURNS VOID AS 'pg_pathman', 'prevent_part_modification'
922922
LANGUAGE C STRICT;
923923

924924
/*
925925
* Lock relation to restrict concurrent modification of data.
926926
*/
927-
CREATE OR REPLACE FUNCTION @extschema@.prevent_relation_modification(
927+
CREATE OR REPLACE FUNCTION @extschema@.prevent_data_modification(
928928
parent_relid REGCLASS)
929-
RETURNS VOID AS 'pg_pathman', 'prevent_relation_modification'
929+
RETURNS VOID AS 'pg_pathman', 'prevent_data_modification'
930930
LANGUAGE C STRICT;
931931

932932

range.sql

+8-8
Original file line numberDiff line numberDiff line change
@@ -443,10 +443,10 @@ BEGIN
443443
PERFORM @extschema@.validate_relname(partition_relid);
444444

445445
/* Acquire lock on parent */
446-
PERFORM @extschema@.lock_partitioned_relation(parent_relid);
446+
PERFORM @extschema@.prevent_part_modification(parent_relid);
447447

448448
/* Acquire data modification lock (prevent further modifications) */
449-
PERFORM @extschema@.prevent_relation_modification(partition_relid);
449+
PERFORM @extschema@.prevent_data_modification(partition_relid);
450450

451451
part_expr_type = @extschema@.get_partition_key_type(parent_relid);
452452
part_expr := @extschema@.get_partition_key(parent_relid);
@@ -536,7 +536,7 @@ BEGIN
536536
PERFORM @extschema@.validate_relname(parent_relid);
537537

538538
/* Acquire lock on parent */
539-
PERFORM @extschema@.lock_partitioned_relation(parent_relid);
539+
PERFORM @extschema@.prevent_part_modification(parent_relid);
540540

541541
part_expr_type := @extschema@.get_partition_key_type(parent_relid);
542542

@@ -640,7 +640,7 @@ BEGIN
640640
PERFORM @extschema@.validate_relname(parent_relid);
641641

642642
/* Acquire lock on parent */
643-
PERFORM @extschema@.lock_partitioned_relation(parent_relid);
643+
PERFORM @extschema@.prevent_part_modification(parent_relid);
644644

645645
part_expr_type := @extschema@.get_partition_key_type(parent_relid);
646646

@@ -744,7 +744,7 @@ BEGIN
744744
PERFORM @extschema@.validate_relname(parent_relid);
745745

746746
/* Acquire lock on parent */
747-
PERFORM @extschema@.lock_partitioned_relation(parent_relid);
747+
PERFORM @extschema@.prevent_part_modification(parent_relid);
748748

749749
IF start_value >= end_value THEN
750750
RAISE EXCEPTION 'failed to create partition: start_value is greater than end_value';
@@ -798,7 +798,7 @@ BEGIN
798798
END IF;
799799

800800
/* Acquire lock on parent */
801-
PERFORM @extschema@.lock_partitioned_relation(parent_relid);
801+
PERFORM @extschema@.prevent_part_modification(parent_relid);
802802

803803
IF NOT delete_data THEN
804804
EXECUTE format('INSERT INTO %s SELECT * FROM %s',
@@ -849,7 +849,7 @@ BEGIN
849849
PERFORM @extschema@.validate_relname(partition_relid);
850850

851851
/* Acquire lock on parent */
852-
PERFORM @extschema@.lock_partitioned_relation(parent_relid);
852+
PERFORM @extschema@.prevent_part_modification(parent_relid);
853853

854854
/* Ignore temporary tables */
855855
SELECT relpersistence FROM pg_catalog.pg_class
@@ -926,7 +926,7 @@ BEGIN
926926
PERFORM @extschema@.validate_relname(partition_relid);
927927

928928
/* Acquire lock on parent */
929-
PERFORM @extschema@.prevent_relation_modification(parent_relid);
929+
PERFORM @extschema@.prevent_data_modification(parent_relid);
930930

931931
part_type := @extschema@.get_partition_type(parent_relid);
932932

src/include/partition_creation.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,9 @@ Node * build_raw_hash_check_tree(Node *raw_expression,
7676
Oid relid,
7777
Oid value_type);
7878

79-
void drop_check_constraint(Oid relid);
79+
/* Add & drop pg_pathman's check constraint */
80+
void drop_pathman_check_constraint(Oid relid);
81+
void add_pathman_check_constraint(Oid relid, Constraint *constraint);
8082

8183

8284
/* Update triggers */

src/include/xact_handling.h

+2-6
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,7 @@
2020
/*
2121
* Transaction locks.
2222
*/
23-
LockAcquireResult xact_lock_partitioned_rel(Oid relid, bool nowait);
24-
void xact_unlock_partitioned_rel(Oid relid);
25-
26-
LockAcquireResult xact_lock_rel_exclusive(Oid relid, bool nowait);
27-
void xact_unlock_rel_exclusive(Oid relid);
23+
LockAcquireResult xact_lock_rel(Oid relid, LOCKMODE lockmode, bool nowait);
2824

2925
/*
3026
* Utility checks.
@@ -35,7 +31,7 @@ bool xact_is_transaction_stmt(Node *stmt);
3531
bool xact_is_set_transaction_stmt(Node *stmt);
3632
bool xact_object_is_visible(TransactionId obj_xmin);
3733

38-
void prevent_relation_modification_internal(Oid relid);
34+
void prevent_data_modification_internal(Oid relid);
3935

4036

4137
#endif /* XACT_HANDLING_H */

src/partition_creation.c

+19-3
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ create_partitions_for_value_internal(Oid relid, Datum value, Oid value_type,
375375
else if (nparts == 1)
376376
{
377377
/* Unlock the parent (we're not going to spawn) */
378-
xact_unlock_partitioned_rel(relid);
378+
UnlockRelationOid(relid, ShareUpdateExclusiveLock);
379379

380380
/* Simply return the suitable partition */
381381
partid = parts[0];
@@ -1125,7 +1125,7 @@ copy_foreign_keys(Oid parent_relid, Oid partition_oid)
11251125

11261126
/* Drop pg_pathman's check constraint by 'relid' */
11271127
void
1128-
drop_check_constraint(Oid relid)
1128+
drop_pathman_check_constraint(Oid relid)
11291129
{
11301130
char *constr_name;
11311131
AlterTableStmt *stmt;
@@ -1146,9 +1146,25 @@ drop_check_constraint(Oid relid)
11461146

11471147
stmt->cmds = list_make1(cmd);
11481148

1149-
AlterTable(relid, ShareUpdateExclusiveLock, stmt);
1149+
/* See function AlterTableGetLockLevel() */
1150+
AlterTable(relid, AccessExclusiveLock, stmt);
11501151
}
11511152

1153+
/* Add pg_pathman's check constraint using 'relid' */
1154+
void
1155+
add_pathman_check_constraint(Oid relid, Constraint *constraint)
1156+
{
1157+
Relation part_rel = heap_open(relid, AccessExclusiveLock);
1158+
1159+
AddRelationNewConstraints(part_rel, NIL,
1160+
list_make1(constraint),
1161+
false, true, true);
1162+
1163+
heap_close(part_rel, NoLock);
1164+
}
1165+
1166+
1167+
11521168
/* Build RANGE check constraint expression tree */
11531169
Node *
11541170
build_raw_range_check_tree(Node *raw_expression,

src/partition_filter.c

+45-21
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,11 @@ scan_result_parts_storage(Oid partid, ResultPartsStorage *parts_storage)
253253
LockRelationOid(partid, parts_storage->head_open_lock_mode);
254254
if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(partid)))
255255
{
256+
/* Don't forget to drop invalid hash table entry */
257+
hash_search(parts_storage->result_rels_table,
258+
(const void *) &partid,
259+
HASH_REMOVE, NULL);
260+
256261
UnlockRelationOid(partid, parts_storage->head_open_lock_mode);
257262
return NULL;
258263
}
@@ -419,34 +424,50 @@ select_partition_for_insert(Datum value, Oid value_type,
419424
{
420425
MemoryContext old_mcxt;
421426
ResultRelInfoHolder *rri_holder;
427+
Oid parent_relid = PrelParentRelid(prel);
422428
Oid selected_partid = InvalidOid;
423429
Oid *parts;
424430
int nparts;
425431

426-
/* Search for matching partitions */
427-
parts = find_partitions_for_value(value, value_type, prel, &nparts);
428-
429-
if (nparts > 1)
430-
elog(ERROR, ERR_PART_ATTR_MULTIPLE);
431-
else if (nparts == 0)
432+
do
432433
{
433-
selected_partid = create_partitions_for_value(PrelParentRelid(prel),
434-
value, prel->ev_type);
434+
/* Search for matching partitions */
435+
parts = find_partitions_for_value(value, value_type, prel, &nparts);
435436

436-
/* get_pathman_relation_info() will refresh this entry */
437-
invalidate_pathman_relation_info(PrelParentRelid(prel), NULL);
438-
}
439-
else selected_partid = parts[0];
437+
if (nparts > 1)
438+
elog(ERROR, ERR_PART_ATTR_MULTIPLE);
439+
else if (nparts == 0)
440+
{
441+
selected_partid = create_partitions_for_value(parent_relid,
442+
value, prel->ev_type);
440443

441-
/* Replace parent table with a suitable partition */
442-
old_mcxt = MemoryContextSwitchTo(estate->es_query_cxt);
443-
rri_holder = scan_result_parts_storage(selected_partid, parts_storage);
444-
MemoryContextSwitchTo(old_mcxt);
444+
/* get_pathman_relation_info() will refresh this entry */
445+
invalidate_pathman_relation_info(parent_relid, NULL);
446+
}
447+
else selected_partid = parts[0];
445448

446-
/* Could not find suitable partition */
447-
if (rri_holder == NULL)
448-
elog(ERROR, ERR_PART_ATTR_NO_PART,
449-
datum_to_cstring(value, prel->ev_type));
449+
/* Replace parent table with a suitable partition */
450+
old_mcxt = MemoryContextSwitchTo(estate->es_query_cxt);
451+
rri_holder = scan_result_parts_storage(selected_partid, parts_storage);
452+
MemoryContextSwitchTo(old_mcxt);
453+
454+
/* This partition has been dropped, repeat with a new 'prel' */
455+
if (rri_holder == NULL)
456+
{
457+
/* get_pathman_relation_info() will refresh this entry */
458+
invalidate_pathman_relation_info(parent_relid, NULL);
459+
460+
/* Get a fresh PartRelationInfo */
461+
prel = get_pathman_relation_info(parent_relid);
462+
463+
/* Paranoid check (all partitions have vanished) */
464+
if (!prel)
465+
elog(ERROR, "table \"%s\" is not partitioned",
466+
get_rel_name_or_relid(parent_relid));
467+
}
468+
}
469+
/* Loop until we get some result */
470+
while (rri_holder == NULL);
450471

451472
return rri_holder;
452473
}
@@ -629,7 +650,10 @@ partition_filter_exec(CustomScanState *node)
629650
if (itemIsDone != ExprSingleResult)
630651
elog(ERROR, ERR_PART_ATTR_MULTIPLE_RESULTS);
631652

632-
/* Search for a matching partition */
653+
/*
654+
* Search for a matching partition.
655+
* WARNING: 'prel' might change after this call!
656+
*/
633657
rri_holder = select_partition_for_insert(value, prel->ev_type, prel,
634658
&state->result_parts, estate);
635659

src/pl_funcs.c

+8-8
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ PG_FUNCTION_INFO_V1( is_tuple_convertible );
6464
PG_FUNCTION_INFO_V1( add_to_pathman_config );
6565
PG_FUNCTION_INFO_V1( pathman_config_params_trigger_func );
6666

67-
PG_FUNCTION_INFO_V1( lock_partitioned_relation );
68-
PG_FUNCTION_INFO_V1( prevent_relation_modification );
67+
PG_FUNCTION_INFO_V1( prevent_part_modification );
68+
PG_FUNCTION_INFO_V1( prevent_data_modification );
6969

7070
PG_FUNCTION_INFO_V1( validate_part_callback_pl );
7171
PG_FUNCTION_INFO_V1( invoke_on_partition_created_callback );
@@ -774,8 +774,8 @@ add_to_pathman_config(PG_FUNCTION_ARGS)
774774
else ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
775775
errmsg("'parent_relid' should not be NULL")));
776776

777-
/* Protect relation from concurrent modification */
778-
xact_lock_rel_exclusive(relid, true);
777+
/* Protect data + definition from concurrent modification */
778+
LockRelationOid(relid, AccessExclusiveLock);
779779

780780
/* Check that relation exists */
781781
if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(relid)))
@@ -1000,12 +1000,12 @@ pathman_config_params_trigger_func(PG_FUNCTION_ARGS)
10001000
* Acquire appropriate lock on a partitioned relation.
10011001
*/
10021002
Datum
1003-
lock_partitioned_relation(PG_FUNCTION_ARGS)
1003+
prevent_part_modification(PG_FUNCTION_ARGS)
10041004
{
10051005
Oid relid = PG_GETARG_OID(0);
10061006

10071007
/* Lock partitioned relation till transaction's end */
1008-
xact_lock_partitioned_rel(relid, false);
1008+
LockRelationOid(relid, ShareUpdateExclusiveLock);
10091009

10101010
PG_RETURN_VOID();
10111011
}
@@ -1014,9 +1014,9 @@ lock_partitioned_relation(PG_FUNCTION_ARGS)
10141014
* Lock relation exclusively & check for current isolation level.
10151015
*/
10161016
Datum
1017-
prevent_relation_modification(PG_FUNCTION_ARGS)
1017+
prevent_data_modification(PG_FUNCTION_ARGS)
10181018
{
1019-
prevent_relation_modification_internal(PG_GETARG_OID(0));
1019+
prevent_data_modification_internal(PG_GETARG_OID(0));
10201020

10211021
PG_RETURN_VOID();
10221022
}

src/pl_range_funcs.c

+6-11
Original file line numberDiff line numberDiff line change
@@ -670,15 +670,15 @@ merge_range_partitions_internal(Oid parent, Oid *parts, uint32 nparts)
670670
ranges = PrelGetRangesArray(prel);
671671

672672
/* Lock parent till transaction's end */
673-
xact_lock_partitioned_rel(parent, false);
673+
LockRelationOid(parent, ShareUpdateExclusiveLock);
674674

675675
/* Process partitions */
676676
for (i = 0; i < nparts; i++)
677677
{
678678
int j;
679679

680-
/* Lock partition in ACCESS EXCLUSIVE mode */
681-
prevent_relation_modification_internal(parts[0]);
680+
/* Prevent modification of partitions */
681+
LockRelationOid(parts[0], AccessExclusiveLock);
682682

683683
/* Look for the specified partition */
684684
for (j = 0; j < PrelChildrenCount(prel); j++)
@@ -1072,10 +1072,9 @@ modify_range_constraint(Oid partition_relid,
10721072
{
10731073
Node *expr;
10741074
Constraint *constraint;
1075-
Relation partition_rel;
10761075

10771076
/* Drop old constraint */
1078-
drop_check_constraint(partition_relid);
1077+
drop_pathman_check_constraint(partition_relid);
10791078

10801079
/* Parse expression */
10811080
expr = parse_partitioning_expression(partition_relid, expression, NULL, NULL);
@@ -1087,12 +1086,8 @@ modify_range_constraint(Oid partition_relid,
10871086
upper,
10881087
expression_type);
10891088

1090-
/* Open the relation and add new check constraint */
1091-
partition_rel = heap_open(partition_relid, AccessExclusiveLock);
1092-
AddRelationNewConstraints(partition_rel, NIL,
1093-
list_make1(constraint),
1094-
false, true, true);
1095-
heap_close(partition_rel, NoLock);
1089+
/* Add new constraint */
1090+
add_pathman_check_constraint(partition_relid, constraint);
10961091
}
10971092

10981093
/*

0 commit comments

Comments
 (0)