Skip to content

Commit 156cf1f

Browse files
committed
Merge branch 'merge_concurrent_locks' of github.com:postgrespro/pg_pathman into merge_concurrent_locks
2 parents 5d9d01b + 1145931 commit 156cf1f

11 files changed

+166
-56
lines changed

Diff for: hash.sql

+5-3
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ BEGIN
2929
/* Acquire exclusive lock on parent */
3030
PERFORM @[email protected]_partitioned_relation(parent_relid);
3131

32+
IF partition_data = true THEN
33+
/* Acquire data modification lock */
34+
PERFORM @[email protected]_relation_modification(parent_relid);
35+
END IF;
36+
3237
PERFORM @[email protected]_relname(parent_relid);
3338
attribute := lower(attribute);
3439
PERFORM @[email protected]_relation_checks(parent_relid, attribute);
@@ -78,9 +83,6 @@ BEGIN
7883
END IF;
7984

8085
RETURN partitions_count;
81-
82-
EXCEPTION WHEN others THEN
83-
RAISE EXCEPTION '%', SQLERRM;
8486
END
8587
$$ LANGUAGE plpgsql
8688
SET client_min_messages = WARNING;

Diff for: init.sql

+16
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,22 @@ LANGUAGE C STRICT;
655655
RETURNS VOID AS 'pg_pathman', 'lock_partitioned_relation'
656656
LANGUAGE C STRICT;
657657

658+
/*
659+
* Lock relation to restrict concurrent modification of data.
660+
*/
661+
CREATE OR REPLACE FUNCTION @[email protected]_relation_modification(
662+
REGCLASS)
663+
RETURNS VOID AS 'pg_pathman', 'lock_relation_modification'
664+
LANGUAGE C STRICT;
665+
666+
/*
667+
* Check if we can distribute data without bad consequences.
668+
*/
669+
CREATE OR REPLACE FUNCTION @[email protected]_blocking_partitioning_checks(
670+
REGCLASS)
671+
RETURNS VOID AS 'pg_pathman', 'common_blocking_partitioning_checks'
672+
LANGUAGE C STRICT;
673+
658674

659675
/*
660676
* DEBUG: Place this inside some plpgsql fuction and set breakpoint.

Diff for: range.sql

+42-30
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,14 @@ BEGIN
9797
/* Acquire exclusive lock on parent */
9898
PERFORM @[email protected]_partitioned_relation(parent_relid);
9999

100+
IF partition_data = true THEN
101+
/* Perform some checks regarding the blocking partitioning */
102+
PERFORM @[email protected]_blocking_partitioning_checks(parent_relid);
103+
104+
/* Acquire data modification lock (prevent further modifications) */
105+
PERFORM @[email protected]_relation_modification(parent_relid);
106+
END IF;
107+
100108
PERFORM @[email protected]_relname(parent_relid);
101109
p_attribute := lower(p_attribute);
102110
PERFORM @[email protected]_relation_checks(parent_relid, p_attribute);
@@ -166,9 +174,6 @@ BEGIN
166174
END IF;
167175

168176
RETURN p_count;
169-
170-
EXCEPTION WHEN others THEN
171-
RAISE EXCEPTION '%', SQLERRM;
172177
END
173178
$$ LANGUAGE plpgsql;
174179

@@ -194,6 +199,14 @@ BEGIN
194199
/* Acquire exclusive lock on parent */
195200
PERFORM @[email protected]_partitioned_relation(parent_relid);
196201

202+
IF partition_data = true THEN
203+
/* Perform some checks regarding the blocking partitioning */
204+
PERFORM @[email protected]_blocking_partitioning_checks(parent_relid);
205+
206+
/* Acquire data modification lock (prevent further modifications) */
207+
PERFORM @[email protected]_relation_modification(parent_relid);
208+
END IF;
209+
197210
PERFORM @[email protected]_relname(parent_relid);
198211
p_attribute := lower(p_attribute);
199212
PERFORM @[email protected]_relation_checks(parent_relid, p_attribute);
@@ -264,9 +277,6 @@ BEGIN
264277
END IF;
265278

266279
RETURN p_count;
267-
268-
EXCEPTION WHEN others THEN
269-
RAISE EXCEPTION '%', SQLERRM;
270280
END
271281
$$ LANGUAGE plpgsql;
272282

@@ -289,6 +299,14 @@ BEGIN
289299
/* Acquire exclusive lock on parent */
290300
PERFORM @[email protected]_partitioned_relation(parent_relid);
291301

302+
IF partition_data = true THEN
303+
/* Perform some checks regarding the blocking partitioning */
304+
PERFORM @[email protected]_blocking_partitioning_checks(parent_relid);
305+
306+
/* Acquire data modification lock (prevent further modifications) */
307+
PERFORM @[email protected]_relation_modification(parent_relid);
308+
END IF;
309+
292310
PERFORM @[email protected]_relname(parent_relid);
293311
p_attribute := lower(p_attribute);
294312
PERFORM @[email protected]_relation_checks(parent_relid, p_attribute);
@@ -332,9 +350,6 @@ BEGIN
332350
END IF;
333351

334352
RETURN part_count; /* number of created partitions */
335-
336-
EXCEPTION WHEN others THEN
337-
RAISE EXCEPTION '%', SQLERRM;
338353
END
339354
$$ LANGUAGE plpgsql;
340355

@@ -357,6 +372,14 @@ BEGIN
357372
/* Acquire exclusive lock on parent */
358373
PERFORM @[email protected]_partitioned_relation(parent_relid);
359374

375+
IF partition_data = true THEN
376+
/* Perform some checks regarding the blocking partitioning */
377+
PERFORM @[email protected]_blocking_partitioning_checks(parent_relid);
378+
379+
/* Acquire data modification lock (prevent further modifications) */
380+
PERFORM @[email protected]_relation_modification(parent_relid);
381+
END IF;
382+
360383
PERFORM @[email protected]_relname(parent_relid);
361384
p_attribute := lower(p_attribute);
362385
PERFORM @[email protected]_relation_checks(parent_relid, p_attribute);
@@ -397,9 +420,6 @@ BEGIN
397420
END IF;
398421

399422
RETURN part_count; /* number of created partitions */
400-
401-
EXCEPTION WHEN others THEN
402-
RAISE EXCEPTION '%', SQLERRM;
403423
END
404424
$$ LANGUAGE plpgsql;
405425

@@ -501,6 +521,10 @@ BEGIN
501521
/* Acquire exclusive lock on parent */
502522
PERFORM @[email protected]_partitioned_relation(v_parent_relid);
503523

524+
/* Acquire data modification lock (prevent further modifications) */
525+
PERFORM @[email protected]_blocking_partitioning_checks(p_partition);
526+
PERFORM @[email protected]_relation_modification(p_partition);
527+
504528
SELECT attname, parttype
505529
FROM @[email protected]_config
506530
WHERE partrel = v_parent_relid
@@ -585,6 +609,12 @@ BEGIN
585609
v_parent_relid1 := @[email protected]_parent_of_partition(partition1);
586610
v_parent_relid2 := @[email protected]_parent_of_partition(partition2);
587611

612+
/* Acquire data modification locks (prevent further modifications) */
613+
PERFORM @[email protected]_blocking_partitioning_checks(partition1);
614+
PERFORM @[email protected]_relation_modification(partition1);
615+
PERFORM @[email protected]_blocking_partitioning_checks(partition2);
616+
PERFORM @[email protected]_relation_modification(partition2);
617+
588618
IF v_parent_relid1 != v_parent_relid2 THEN
589619
RAISE EXCEPTION 'Cannot merge partitions with different parents';
590620
END IF;
@@ -730,9 +760,6 @@ BEGIN
730760
/* Invalidate cache */
731761
PERFORM @[email protected]_update_partitions(parent_relid);
732762
RETURN v_part_name;
733-
734-
EXCEPTION WHEN others THEN
735-
RAISE EXCEPTION '%', SQLERRM;
736763
END
737764
$$
738765
LANGUAGE plpgsql;
@@ -828,9 +855,6 @@ BEGIN
828855
/* Invalidate cache */
829856
PERFORM @[email protected]_update_partitions(parent_relid);
830857
RETURN v_part_name;
831-
832-
EXCEPTION WHEN others THEN
833-
RAISE EXCEPTION '%', SQLERRM;
834858
END
835859
$$
836860
LANGUAGE plpgsql;
@@ -920,9 +944,6 @@ BEGIN
920944
PERFORM @[email protected]_update_partitions(parent_relid);
921945

922946
RETURN v_part_name;
923-
924-
EXCEPTION WHEN others THEN
925-
RAISE EXCEPTION '%', SQLERRM;
926947
END
927948
$$
928949
LANGUAGE plpgsql;
@@ -953,9 +974,6 @@ BEGIN
953974
PERFORM @[email protected]_update_partitions(parent_relid);
954975

955976
RETURN part_name;
956-
957-
EXCEPTION WHEN others THEN
958-
RAISE EXCEPTION '%', SQLERRM;
959977
END
960978
$$
961979
LANGUAGE plpgsql;
@@ -1017,9 +1035,6 @@ BEGIN
10171035
PERFORM @[email protected]_update_partitions(parent_relid);
10181036

10191037
RETURN p_partition;
1020-
1021-
EXCEPTION WHEN others THEN
1022-
RAISE EXCEPTION '%', SQLERRM;
10231038
END
10241039
$$
10251040
LANGUAGE plpgsql;
@@ -1064,9 +1079,6 @@ BEGIN
10641079
PERFORM @[email protected]_update_partitions(parent_relid);
10651080

10661081
RETURN p_partition;
1067-
1068-
EXCEPTION WHEN others THEN
1069-
RAISE EXCEPTION '%', SQLERRM;
10701082
END
10711083
$$
10721084
LANGUAGE plpgsql;

Diff for: src/nodes_common.c

+4-11
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,8 @@ unpack_runtimeappend_private(RuntimeAppendState *scan_state, CustomScan *cscan)
240240

241241
/* Transform partition ranges into plain array of partition Oids */
242242
Oid *
243-
get_partition_oids(List *ranges, int *n, const PartRelationInfo *prel)
243+
get_partition_oids(List *ranges, int *n, const PartRelationInfo *prel,
244+
bool include_parent)
244245
{
245246
ListCell *range_cell;
246247
uint32 allocated = INITIAL_ALLOC_NUM;
@@ -250,7 +251,7 @@ get_partition_oids(List *ranges, int *n, const PartRelationInfo *prel)
250251

251252
/* If required, add parent to result */
252253
Assert(INITIAL_ALLOC_NUM >= 1);
253-
if (prel->enable_parent)
254+
if (include_parent)
254255
result[used++] = PrelParentRelid(prel);
255256

256257
/* Deal with selected partitions */
@@ -372,10 +373,6 @@ create_append_plan_common(PlannerInfo *root, RelOptInfo *rel,
372373
{
373374
Plan *child_plan = (Plan *) lfirst(lc2);
374375
RelOptInfo *child_rel = ((Path *) lfirst(lc1))->parent;
375-
Oid child_relid;
376-
377-
/* Fetch relid of the 'child_rel' */
378-
child_relid = root->simple_rte_array[child_rel->relid]->relid;
379376

380377
/* Replace rel's tlist with a matching one */
381378
if (!cscan->scan.plan.targetlist)
@@ -390,10 +387,6 @@ create_append_plan_common(PlannerInfo *root, RelOptInfo *rel,
390387
if (!cscan->custom_scan_tlist)
391388
cscan->custom_scan_tlist = replace_tlist_varnos(child_plan->targetlist,
392389
rel);
393-
394-
/* If this is a plan for parent table, fill it with quals */
395-
if (PrelParentRelid(prel) == child_relid)
396-
child_plan->qual = get_actual_clauses(clauses);
397390
}
398391
}
399392

@@ -529,7 +522,7 @@ rescan_append_common(CustomScanState *node)
529522
}
530523

531524
/* Get Oids of the required partitions */
532-
parts = get_partition_oids(ranges, &nparts, prel);
525+
parts = get_partition_oids(ranges, &nparts, prel, prel->enable_parent);
533526

534527
/* Select new plans for this run using 'parts' */
535528
if (scan_state->cur_plans)

Diff for: src/nodes_common.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ clear_plan_states(CustomScanState *scan_state)
6060
}
6161
}
6262

63-
Oid * get_partition_oids(List *ranges, int *n, const PartRelationInfo *prel);
63+
Oid * get_partition_oids(List *ranges, int *n, const PartRelationInfo *prel,
64+
bool include_parent);
6465

6566
Path * create_append_path_common(PlannerInfo *root,
6667
AppendPath *inner_append,

Diff for: src/partition_filter.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ partition_filter_exec(CustomScanState *node)
199199
old_cxt = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
200200

201201
ranges = walk_expr_tree((Expr *) &state->temp_const, &wcxt)->rangeset;
202-
parts = get_partition_oids(ranges, &nparts, prel);
202+
parts = get_partition_oids(ranges, &nparts, prel, false);
203203

204204
if (nparts > 1)
205205
elog(ERROR, "PartitionFilter selected more than one partition");
@@ -222,7 +222,7 @@ partition_filter_exec(CustomScanState *node)
222222
elog(ERROR,
223223
"There is no suitable partition for key '%s'",
224224
datum_to_cstring(state->temp_const.constvalue,
225-
state->temp_const.consttype));
225+
state->temp_const.consttype));
226226
}
227227
else
228228
selected_partid = parts[0];

Diff for: src/pathman_workers.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ bgw_main_spawn_partitions(Datum main_arg)
361361
#endif
362362

363363
/* Check again if there's a conflicting lock */
364-
if (xact_conflicting_lock_exists(args->partitioned_table))
364+
if (xact_bgw_conflicting_lock_exists(args->partitioned_table))
365365
{
366366
elog(LOG, "%s: there's a conflicting lock on relation \"%s\"",
367367
spawn_partitions_bgw,

Diff for: src/pg_pathman.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -976,7 +976,7 @@ create_partitions(Oid relid, Datum value, Oid value_type)
976976
* If table has been partitioned in some previous xact AND
977977
* we don't hold any conflicting locks, run BGWorker.
978978
*/
979-
if (part_in_prev_xact && !xact_conflicting_lock_exists(relid))
979+
if (part_in_prev_xact && !xact_bgw_conflicting_lock_exists(relid))
980980
{
981981
elog(DEBUG2, "create_partitions(): chose BGWorker [%u]", MyProcPid);
982982
last_partition = create_partitions_bg_worker(relid, value, value_type);

Diff for: src/pl_funcs.c

+32
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ PG_FUNCTION_INFO_V1( is_attribute_nullable );
5353
PG_FUNCTION_INFO_V1( add_to_pathman_config );
5454
PG_FUNCTION_INFO_V1( invalidate_relcache );
5555
PG_FUNCTION_INFO_V1( lock_partitioned_relation );
56+
PG_FUNCTION_INFO_V1( lock_relation_modification );
57+
PG_FUNCTION_INFO_V1( common_blocking_partitioning_checks );
5658
PG_FUNCTION_INFO_V1( debug_capture );
5759

5860

@@ -701,6 +703,36 @@ lock_partitioned_relation(PG_FUNCTION_ARGS)
701703
PG_RETURN_VOID();
702704
}
703705

706+
Datum
707+
lock_relation_modification(PG_FUNCTION_ARGS)
708+
{
709+
Oid relid = PG_GETARG_OID(0);
710+
711+
/* Lock partitioned relation till transaction's end */
712+
xact_lock_rel_data(relid);
713+
714+
PG_RETURN_VOID();
715+
}
716+
717+
Datum
718+
common_blocking_partitioning_checks(PG_FUNCTION_ARGS)
719+
{
720+
Oid relid = PG_GETARG_OID(0);
721+
722+
if (!xact_is_level_read_committed())
723+
ereport(ERROR,
724+
(errmsg("Cannot perform blocking partitioning operation"),
725+
errdetail("Expected READ COMMITTED isolation level")));
726+
727+
if (xact_is_table_being_modified(relid))
728+
ereport(ERROR,
729+
(errmsg("Cannot perform blocking partitioning operation"),
730+
errdetail("Table \"%s\" is being modified concurrently",
731+
get_rel_name_or_relid(relid))));
732+
733+
PG_RETURN_VOID();
734+
}
735+
704736

705737
/*
706738
* NOTE: used for DEBUG, set breakpoint here.

0 commit comments

Comments
 (0)