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

init.sql

Lines changed: 9 additions & 1 deletion
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 @extschema@.common_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
*/

range.sql

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,10 @@ BEGIN
9898
PERFORM @extschema@.lock_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 @extschema@.common_blocking_partitioning_checks(parent_relid);
103+
104+
/* Acquire data modification lock (prevent further modifications) */
102105
PERFORM @extschema@.lock_relation_modification(parent_relid);
103106
END IF;
104107

@@ -200,7 +203,10 @@ BEGIN
200203
PERFORM @extschema@.lock_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 @extschema@.common_blocking_partitioning_checks(parent_relid);
208+
209+
/* Acquire data modification lock (prevent further modifications) */
204210
PERFORM @extschema@.lock_relation_modification(parent_relid);
205211
END IF;
206212

@@ -300,7 +306,10 @@ BEGIN
300306
PERFORM @extschema@.lock_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 @extschema@.common_blocking_partitioning_checks(parent_relid);
311+
312+
/* Acquire data modification lock (prevent further modifications) */
304313
PERFORM @extschema@.lock_relation_modification(parent_relid);
305314
END IF;
306315

@@ -373,7 +382,10 @@ BEGIN
373382
PERFORM @extschema@.lock_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 @extschema@.common_blocking_partitioning_checks(parent_relid);
387+
388+
/* Acquire data modification lock (prevent further modifications) */
377389
PERFORM @extschema@.lock_relation_modification(parent_relid);
378390
END IF;
379391

@@ -521,7 +533,8 @@ BEGIN
521533
/* Acquire exclusive lock on parent */
522534
PERFORM @extschema@.lock_partitioned_relation(v_parent_relid);
523535

524-
/* Acquire data modification lock */
536+
/* Acquire data modification lock (prevent further modifications) */
537+
PERFORM @extschema@.common_blocking_partitioning_checks(p_partition);
525538
PERFORM @extschema@.lock_relation_modification(p_partition);
526539

527540
SELECT attname, parttype
@@ -608,8 +621,10 @@ BEGIN
608621
v_parent_relid1 := @extschema@.get_parent_of_partition(partition1);
609622
v_parent_relid2 := @extschema@.get_parent_of_partition(partition2);
610623

611-
/* Acquire data modification lock */
624+
/* Acquire data modification locks (prevent further modifications) */
625+
PERFORM @extschema@.common_blocking_partitioning_checks(partition1);
612626
PERFORM @extschema@.lock_relation_modification(partition1);
627+
PERFORM @extschema@.common_blocking_partitioning_checks(partition2);
613628
PERFORM @extschema@.lock_relation_modification(partition2);
614629

615630
IF v_parent_relid1 != v_parent_relid2 THEN

src/pathman_workers.c

Lines changed: 1 addition & 1 deletion
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,

src/pg_pathman.c

Lines changed: 1 addition & 1 deletion
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);

src/pl_funcs.c

Lines changed: 20 additions & 0 deletions
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.

src/xact_handling.c

Lines changed: 35 additions & 3 deletions
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?

src/xact_handling.h

Lines changed: 6 additions & 6 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy