Skip to content

Commit e82348b

Browse files
committed
check transaction isolation level for blocking partitioning operations
1 parent 173dd50 commit e82348b

File tree

7 files changed

+93
-18
lines changed

7 files changed

+93
-18
lines changed

Diff for: init.sql

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

658-
659658
/*
660659
* Lock relation to restrict concurrent modification of data.
661660
*/
@@ -664,6 +663,15 @@ LANGUAGE C STRICT;
664663
RETURNS VOID AS 'pg_pathman', 'lock_relation_modification'
665664
LANGUAGE C STRICT;
666665

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+
674+
667675
/*
668676
* DEBUG: Place this inside some plpgsql fuction and set breakpoint.
669677
*/

Diff for: range.sql

+21-6
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,10 @@ BEGIN
9898
PERFORM @[email protected]_partitioned_relation(parent_relid);
9999

100100
IF partition_data = true THEN
101-
/* Acquire data modification lock */
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) */
102105
PERFORM @[email protected]_relation_modification(parent_relid);
103106
END IF;
104107

@@ -200,7 +203,10 @@ BEGIN
200203
PERFORM @[email protected]_partitioned_relation(parent_relid);
201204

202205
IF partition_data = true THEN
203-
/* Acquire data modification lock */
206+
/* Perform some checks regarding the blocking partitioning */
207+
PERFORM @[email protected]_blocking_partitioning_checks(parent_relid);
208+
209+
/* Acquire data modification lock (prevent further modifications) */
204210
PERFORM @[email protected]_relation_modification(parent_relid);
205211
END IF;
206212

@@ -300,7 +306,10 @@ BEGIN
300306
PERFORM @[email protected]_partitioned_relation(parent_relid);
301307

302308
IF partition_data = true THEN
303-
/* Acquire data modification lock */
309+
/* Perform some checks regarding the blocking partitioning */
310+
PERFORM @[email protected]_blocking_partitioning_checks(parent_relid);
311+
312+
/* Acquire data modification lock (prevent further modifications) */
304313
PERFORM @[email protected]_relation_modification(parent_relid);
305314
END IF;
306315

@@ -373,7 +382,10 @@ BEGIN
373382
PERFORM @[email protected]_partitioned_relation(parent_relid);
374383

375384
IF partition_data = true THEN
376-
/* Acquire data modification lock */
385+
/* Perform some checks regarding the blocking partitioning */
386+
PERFORM @[email protected]_blocking_partitioning_checks(parent_relid);
387+
388+
/* Acquire data modification lock (prevent further modifications) */
377389
PERFORM @[email protected]_relation_modification(parent_relid);
378390
END IF;
379391

@@ -521,7 +533,8 @@ BEGIN
521533
/* Acquire exclusive lock on parent */
522534
PERFORM @[email protected]_partitioned_relation(v_parent_relid);
523535

524-
/* Acquire data modification lock */
536+
/* Acquire data modification lock (prevent further modifications) */
537+
PERFORM @[email protected]_blocking_partitioning_checks(p_partition);
525538
PERFORM @[email protected]_relation_modification(p_partition);
526539

527540
SELECT attname, parttype
@@ -608,8 +621,10 @@ BEGIN
608621
v_parent_relid1 := @[email protected]_parent_of_partition(partition1);
609622
v_parent_relid2 := @[email protected]_parent_of_partition(partition2);
610623

611-
/* Acquire data modification lock */
624+
/* Acquire data modification locks (prevent further modifications) */
625+
PERFORM @[email protected]_blocking_partitioning_checks(partition1);
612626
PERFORM @[email protected]_relation_modification(partition1);
627+
PERFORM @[email protected]_blocking_partitioning_checks(partition2);
613628
PERFORM @[email protected]_relation_modification(partition2);
614629

615630
IF v_parent_relid1 != v_parent_relid2 THEN

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

+20
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ PG_FUNCTION_INFO_V1( add_to_pathman_config );
5454
PG_FUNCTION_INFO_V1( invalidate_relcache );
5555
PG_FUNCTION_INFO_V1( lock_partitioned_relation );
5656
PG_FUNCTION_INFO_V1( lock_relation_modification );
57+
PG_FUNCTION_INFO_V1( common_blocking_partitioning_checks );
5758
PG_FUNCTION_INFO_V1( debug_capture );
5859

5960

@@ -713,6 +714,25 @@ lock_relation_modification(PG_FUNCTION_ARGS)
713714
PG_RETURN_VOID();
714715
}
715716

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+
716736

717737
/*
718738
* NOTE: used for DEBUG, set breakpoint here.

Diff for: src/xact_handling.c

+35-3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "xact_handling.h"
1212

1313
#include "postgres.h"
14+
#include "access/xact.h"
1415
#include "catalog/catalog.h"
1516
#include "miscadmin.h"
1617
#include "storage/lmgr.h"
@@ -45,7 +46,7 @@ xact_unlock_partitioned_rel(Oid relid)
4546
void
4647
xact_lock_rel_data(Oid relid)
4748
{
48-
LockRelationOid(relid, RowExclusiveLock);
49+
LockRelationOid(relid, ShareLock);
4950
}
5051

5152
/*
@@ -54,15 +55,15 @@ xact_lock_rel_data(Oid relid)
5455
void
5556
xact_unlock_rel_data(Oid relid)
5657
{
57-
UnlockRelationOid(relid, RowExclusiveLock);
58+
UnlockRelationOid(relid, ShareLock);
5859
}
5960

6061
/*
6162
* Check whether we already hold a lock that
6263
* might conflict with partition spawning BGW.
6364
*/
6465
bool
65-
xact_conflicting_lock_exists(Oid relid)
66+
xact_bgw_conflicting_lock_exists(Oid relid)
6667
{
6768
LOCKMODE lockmode;
6869

@@ -78,6 +79,37 @@ xact_conflicting_lock_exists(Oid relid)
7879
return false;
7980
}
8081

82+
/*
83+
* Check if table is being modified
84+
* concurrently in a separate transaction.
85+
*/
86+
bool
87+
xact_is_table_being_modified(Oid relid)
88+
{
89+
/*
90+
* Check if someone has already started a
91+
* transaction and modified table's contents.
92+
*/
93+
if (ConditionalLockRelationOid(relid, ExclusiveLock))
94+
{
95+
UnlockRelationOid(relid, ExclusiveLock);
96+
return false;
97+
}
98+
99+
return true;
100+
}
101+
102+
/*
103+
* Check if current transaction's level is READ COMMITTED.
104+
*/
105+
bool
106+
xact_is_level_read_committed(void)
107+
{
108+
if (XactIsoLevel <= XACT_READ_COMMITTED)
109+
return true;
110+
111+
return false;
112+
}
81113

82114
/*
83115
* Do we hold the specified lock?

Diff for: src/xact_handling.h

+6-6
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,6 @@
1414
#include "pathman.h"
1515

1616

17-
/*
18-
* List of partitioned relations locked by this backend (plain Oids).
19-
*/
20-
extern List *locked_by_me;
21-
2217
/*
2318
* Transaction locks.
2419
*/
@@ -28,6 +23,11 @@ void xact_unlock_partitioned_rel(Oid relid);
2823
void xact_lock_rel_data(Oid relid);
2924
void xact_unlock_rel_data(Oid relid);
3025

31-
bool xact_conflicting_lock_exists(Oid relid);
26+
/*
27+
* Utility checks.
28+
*/
29+
bool xact_bgw_conflicting_lock_exists(Oid relid);
30+
bool xact_is_table_being_modified(Oid relid);
31+
bool xact_is_level_read_committed(void);
3232

3333
#endif

0 commit comments

Comments
 (0)