Skip to content

Commit 67d8a5d

Browse files
committed
introduce new subsystem called 'xact_handling' & function get_pathman_relation_info_after_lock(), extract extract_binary_interval_from_text() from create_partitions_internal(), improve BGW startup
1 parent 9422887 commit 67d8a5d

File tree

11 files changed

+216
-84
lines changed

11 files changed

+216
-84
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
MODULE_big = pg_pathman
44
OBJS = src/init.o src/relation_info.o src/utils.o src/partition_filter.o src/runtimeappend.o \
55
src/runtime_merge_append.o src/pg_pathman.o src/dsm_array.o src/rangeset.o src/pl_funcs.o \
6-
src/worker.o src/hooks.o src/nodes_common.o $(WIN32RES)
6+
src/worker.o src/hooks.o src/nodes_common.o src/xact_handling.o $(WIN32RES)
77

88
EXTENSION = pg_pathman
99
EXTVERSION = 0.1

init.sql

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -317,13 +317,16 @@ SET pg_pathman.enable_partitionfilter = off;
317317

318318

319319

320+
/*
321+
* Create DDL trigger to call pathman_ddl_trigger_func().
322+
*/
320323
CREATE EVENT TRIGGER pathman_ddl_trigger
321324
ON sql_drop
322325
EXECUTE PROCEDURE @extschema@.pathman_ddl_trigger_func();
323326

324327

325328
/*
326-
* Attach partitioned table
329+
* Attach a previously partitioned table
327330
*/
328331
CREATE OR REPLACE FUNCTION @extschema@.add_to_pathman_config(
329332
parent_relid REGCLASS,
@@ -356,6 +359,14 @@ CREATE OR REPLACE FUNCTION @extschema@.get_parent_of_partition(REGCLASS)
356359
RETURNS REGCLASS AS 'pg_pathman', 'get_parent_of_partition_pl'
357360
LANGUAGE C STRICT;
358361

362+
/*
363+
* Checks if attribute is nullable
364+
*/
365+
CREATE OR REPLACE FUNCTION @extschema@.is_attribute_nullable(
366+
REGCLASS, TEXT)
367+
RETURNS BOOLEAN AS 'pg_pathman', 'is_attribute_nullable'
368+
LANGUAGE C STRICT;
369+
359370
/*
360371
* Check if regclass is date or timestamp
361372
*/
@@ -365,19 +376,18 @@ RETURNS BOOLEAN AS 'pg_pathman', 'is_date_type'
365376
LANGUAGE C STRICT;
366377

367378
/*
368-
* Checks if attribute is nullable
379+
* Returns attribute type name for relation
369380
*/
370-
CREATE OR REPLACE FUNCTION @extschema@.is_attribute_nullable(
381+
CREATE OR REPLACE FUNCTION @extschema@.get_attribute_type_name(
371382
REGCLASS, TEXT)
372-
RETURNS BOOLEAN AS 'pg_pathman', 'is_attribute_nullable'
383+
RETURNS TEXT AS 'pg_pathman', 'get_attribute_type_name'
373384
LANGUAGE C STRICT;
374385

375386
/*
376-
* Returns attribute type name for relation
387+
* Get parent of pg_pathman's partition.
377388
*/
378-
CREATE OR REPLACE FUNCTION @extschema@.get_attribute_type_name(
379-
REGCLASS, TEXT)
380-
RETURNS TEXT AS 'pg_pathman', 'get_attribute_type_name'
389+
CREATE OR REPLACE FUNCTION @extschema@.get_parent_of_partition(REGCLASS)
390+
RETURNS REGCLASS AS 'pg_pathman', 'get_parent_of_partition_pl'
381391
LANGUAGE C STRICT;
382392

383393
/*
@@ -406,6 +416,16 @@ CREATE OR REPLACE FUNCTION @extschema@.build_update_trigger_func_name(
406416
RETURNS TEXT AS 'pg_pathman', 'build_update_trigger_func_name'
407417
LANGUAGE C STRICT;
408418

419+
420+
/*
421+
* Lock partitioned relation to restrict concurrent modification of partitioning scheme.
422+
*/
423+
CREATE OR REPLACE FUNCTION @extschema@.lock_partitioned_relation(
424+
REGCLASS)
425+
RETURNS VOID AS 'pg_pathman', 'lock_partitioned_relation'
426+
LANGUAGE C STRICT;
427+
428+
409429
/*
410430
* DEBUG: Place this inside some plpgsql fuction and set breakpoint.
411431
*/

src/init.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -285,10 +285,8 @@ init_shmem_config(void)
285285
*/
286286
if (!IsUnderPostmaster)
287287
{
288-
/* Initialize locks */
289-
pmstate->load_config_lock = LWLockAssign();
290-
pmstate->dsm_init_lock = LWLockAssign();
291-
pmstate->edit_partitions_lock = LWLockAssign();
288+
/* NOTE: dsm_array is redundant, hence the commented code */
289+
/* pmstate->dsm_init_lock = LWLockAssign(); */
292290
}
293291
}
294292
}

src/pathman.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,7 @@ Oid get_pathman_config_relid(void);
6969
*/
7070
typedef struct PathmanState
7171
{
72-
LWLock *dsm_init_lock,
73-
*load_config_lock,
74-
*edit_partitions_lock;
72+
LWLock *dsm_init_lock; /* unused */
7573
} PathmanState;
7674

7775

src/pg_pathman.c

Lines changed: 70 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "partition_filter.h"
1717
#include "runtimeappend.h"
1818
#include "runtime_merge_append.h"
19+
#include "xact_handling.h"
1920

2021
#include "postgres.h"
2122
#include "access/heapam.h"
@@ -60,6 +61,9 @@ static Node *wrapper_make_expression(WrapperNode *wrap, int index, bool *alwaysT
6061
static bool disable_inheritance_subselect_walker(Node *node, void *context);
6162

6263
/* "Partition creation"-related functions */
64+
static Datum extract_binary_interval_from_text(Datum interval_text,
65+
Oid part_atttype,
66+
Oid *interval_type);
6367
static bool spawn_partitions(Oid partitioned_rel,
6468
Datum value,
6569
Datum leading_bound,
@@ -128,14 +132,15 @@ _PG_init(void)
128132

129133
if (!process_shared_preload_libraries_in_progress)
130134
{
131-
elog(ERROR, "Pathman module must be initialized in postmaster. "
135+
elog(ERROR, "pg_pathman module must be initialized by Postmaster. "
132136
"Put the following line to configuration file: "
133137
"shared_preload_libraries='pg_pathman'");
134138
}
135139

136140
/* Request additional shared resources */
137141
RequestAddinShmemSpace(estimate_pathman_shmem_size());
138-
RequestAddinLWLocks(3);
142+
143+
/* NOTE: we don't need LWLocks now. RequestAddinLWLocks(1); */
139144

140145
/* Assign pg_pathman's initial state */
141146
temp_init_state.initialization_needed = true;
@@ -791,6 +796,57 @@ spawn_partitions(Oid partitioned_rel, /* parent's Oid */
791796
return spawned;
792797
}
793798

799+
/*
800+
* Convert interval from TEXT to binary form using partitioned column's type.
801+
*/
802+
static Datum
803+
extract_binary_interval_from_text(Datum interval_text, /* interval as TEXT */
804+
Oid part_atttype, /* partitioned column's type */
805+
Oid *interval_type) /* returned value */
806+
{
807+
Datum interval_binary;
808+
const char *interval_cstring;
809+
810+
interval_cstring = TextDatumGetCString(interval_text);
811+
812+
/* If 'part_atttype' is a *date type*, cast 'range_interval' to INTERVAL */
813+
if (is_date_type_internal(part_atttype))
814+
{
815+
int32 interval_typmod = PATHMAN_CONFIG_interval_typmod;
816+
817+
/* Convert interval from CSTRING to internal form */
818+
interval_binary = DirectFunctionCall3(interval_in,
819+
CStringGetDatum(interval_cstring),
820+
ObjectIdGetDatum(InvalidOid),
821+
Int32GetDatum(interval_typmod));
822+
if (interval_type)
823+
*interval_type = INTERVALOID;
824+
}
825+
/* Otherwise cast it to the partitioned column's type */
826+
else
827+
{
828+
HeapTuple htup;
829+
Oid typein_proc = InvalidOid;
830+
831+
htup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(part_atttype));
832+
if (HeapTupleIsValid(htup))
833+
{
834+
typein_proc = ((Form_pg_type) GETSTRUCT(htup))->typinput;
835+
ReleaseSysCache(htup);
836+
}
837+
else
838+
elog(ERROR, "Cannot find input function for type %u", part_atttype);
839+
840+
/* Convert interval from CSTRING to 'prel->atttype' */
841+
interval_binary = OidFunctionCall1(typein_proc,
842+
CStringGetDatum(interval_cstring));
843+
if (interval_type)
844+
*interval_type = part_atttype;
845+
}
846+
847+
return interval_binary;
848+
}
849+
794850
/*
795851
* Append partitions (if needed) and return Oid of the partition to contain value.
796852
*
@@ -808,9 +864,6 @@ create_partitions_internal(Oid relid, Datum value, Oid value_type)
808864
Datum values[Natts_pathman_config];
809865
bool isnull[Natts_pathman_config];
810866

811-
prel = get_pathman_relation_info(relid);
812-
shout_if_prel_is_invalid(relid, prel, PT_RANGE);
813-
814867
/* Get both PartRelationInfo & PATHMAN_CONFIG contents for this relation */
815868
if (pathman_config_contains_relation(relid, values, isnull, NULL))
816869
{
@@ -820,54 +873,27 @@ create_partitions_internal(Oid relid, Datum value, Oid value_type)
820873
Oid interval_type = InvalidOid;
821874
Datum interval_binary, /* assigned 'width' of a single partition */
822875
interval_text;
823-
const char *interval_cstring;
824876

825877
FmgrInfo interval_type_cmp;
826878

827-
/* Fill the FmgrInfo struct with a cmp(value, part_attribute) function */
828-
fill_type_cmp_fmgr_info(&interval_type_cmp, value_type, prel->atttype);
829-
830-
/* Convert interval from TEXT to CSTRING */
831-
interval_text = values[Anum_pathman_config_range_interval - 1];
832-
interval_cstring = TextDatumGetCString(interval_text);
879+
/* Fetch PartRelationInfo by 'relid' */
880+
prel = get_pathman_relation_info(relid);
881+
shout_if_prel_is_invalid(relid, prel, PT_RANGE);
833882

834883
/* Read max & min range values from PartRelationInfo */
835884
min_rvalue = prel->ranges[0].min;
836885
max_rvalue = prel->ranges[PrelLastChild(prel)].max;
837886

838-
/* If this is a *date type*, cast 'range_interval' to INTERVAL */
839-
if (is_date_type_internal(value_type))
840-
{
841-
int32 interval_typmod = PATHMAN_CONFIG_interval_typmod;
842-
843-
/* Convert interval from CSTRING to internal form */
844-
interval_binary = DirectFunctionCall3(interval_in,
845-
CStringGetDatum(interval_cstring),
846-
ObjectIdGetDatum(InvalidOid),
847-
Int32GetDatum(interval_typmod));
848-
interval_type = INTERVALOID;
849-
}
850-
/* Otherwise cast it to the partitioned column's type */
851-
else
852-
{
853-
HeapTuple htup;
854-
Oid typein_proc = InvalidOid;
887+
/* Retrieve interval as TEXT from tuple */
888+
interval_text = values[Anum_pathman_config_range_interval - 1];
855889

856-
htup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(prel->atttype));
857-
if (HeapTupleIsValid(htup))
858-
{
859-
typein_proc = ((Form_pg_type) GETSTRUCT(htup))->typinput;
860-
ReleaseSysCache(htup);
861-
}
862-
else
863-
elog(ERROR, "Cannot find input function for type %u",
864-
prel->atttype);
865-
866-
/* Convert interval from CSTRING to 'prel->atttype' */
867-
interval_binary = OidFunctionCall1(typein_proc,
868-
CStringGetDatum(interval_cstring));
869-
interval_type = prel->atttype;
870-
}
890+
/* Convert interval to binary representation */
891+
interval_binary = extract_binary_interval_from_text(interval_text,
892+
prel->atttype,
893+
&interval_type);
894+
895+
/* Fill the FmgrInfo struct with a cmp(value, part_attribute) function */
896+
fill_type_cmp_fmgr_info(&interval_type_cmp, value_type, prel->atttype);
871897

872898
if (SPI_connect() != SPI_OK_CONNECT)
873899
elog(ERROR, "Could not connect using SPI");

src/pl_funcs.c

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "init.h"
1313
#include "utils.h"
1414
#include "relation_info.h"
15+
#include "xact_handling.h"
1516

1617
#include "catalog/indexing.h"
1718
#include "commands/sequence.h"
@@ -48,6 +49,7 @@ PG_FUNCTION_INFO_V1( build_update_trigger_name );
4849
PG_FUNCTION_INFO_V1( is_date_type );
4950
PG_FUNCTION_INFO_V1( is_attribute_nullable );
5051
PG_FUNCTION_INFO_V1( add_to_pathman_config );
52+
PG_FUNCTION_INFO_V1( lock_partitioned_relation );
5153
PG_FUNCTION_INFO_V1( debug_capture );
5254

5355

@@ -211,29 +213,10 @@ find_or_create_range_partition(PG_FUNCTION_ARGS)
211213
PG_RETURN_NULL();
212214
else
213215
{
214-
Oid child_oid = InvalidOid;
215-
216-
/* FIXME: useless double-checked lock (no new data) */
217-
LWLockAcquire(pmstate->load_config_lock, LW_EXCLUSIVE);
218-
LWLockAcquire(pmstate->edit_partitions_lock, LW_EXCLUSIVE);
219-
220-
/*
221-
* Check if someone else has already created partition.
222-
*/
223-
search_state = search_range_partition_eq(value, &cmp_func, prel,
224-
&found_rentry);
225-
if (search_state == SEARCH_RANGEREL_FOUND)
226-
{
227-
LWLockRelease(pmstate->load_config_lock);
228-
LWLockRelease(pmstate->edit_partitions_lock);
229-
230-
PG_RETURN_OID(found_rentry.child_oid);
231-
}
232-
233-
child_oid = create_partitions(parent_oid, value, value_type);
216+
Oid child_oid = create_partitions(parent_oid, value, value_type);
234217

235-
LWLockRelease(pmstate->load_config_lock);
236-
LWLockRelease(pmstate->edit_partitions_lock);
218+
/* get_pathman_relation_info() will refresh this entry */
219+
invalidate_pathman_relation_info(parent_oid, NULL);
237220

238221
PG_RETURN_OID(child_oid);
239222
}
@@ -680,6 +663,21 @@ add_to_pathman_config(PG_FUNCTION_ARGS)
680663
}
681664

682665

666+
/*
667+
* Acquire appropriate lock on a partitioned relation.
668+
*/
669+
Datum
670+
lock_partitioned_relation(PG_FUNCTION_ARGS)
671+
{
672+
Oid relid = PG_GETARG_OID(0);
673+
674+
/* Lock partitioned relation till transaction's end */
675+
xact_lock_partitioned_rel(relid);
676+
677+
PG_RETURN_VOID();
678+
}
679+
680+
683681
/*
684682
* NOTE: used for DEBUG, set breakpoint here.
685683
*/

src/relation_info.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "relation_info.h"
1212
#include "init.h"
1313
#include "utils.h"
14+
#include "xact_handling.h"
1415

1516
#include "access/htup_details.h"
1617
#include "access/xact.h"
@@ -240,6 +241,22 @@ get_pathman_relation_info(Oid relid)
240241
return prel;
241242
}
242243

244+
/* Acquire lock on a table and try to get PartRelationInfo */
245+
const PartRelationInfo *
246+
get_pathman_relation_info_after_lock(Oid relid, bool unlock_if_not_found)
247+
{
248+
const PartRelationInfo *prel;
249+
250+
/* Restrict concurrent partition creation (it's dangerous) */
251+
xact_lock_partitioned_rel(relid);
252+
253+
prel = get_pathman_relation_info(relid);
254+
if (!prel && unlock_if_not_found)
255+
xact_unlock_partitioned_rel(relid);
256+
257+
return prel;
258+
}
259+
243260
/* Remove PartRelationInfo from local cache. */
244261
void
245262
remove_pathman_relation_info(Oid relid)

src/relation_info.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ const PartRelationInfo *refresh_pathman_relation_info(Oid relid,
121121
void invalidate_pathman_relation_info(Oid relid, bool *found);
122122
void remove_pathman_relation_info(Oid relid);
123123
const PartRelationInfo *get_pathman_relation_info(Oid relid);
124+
const PartRelationInfo *get_pathman_relation_info_after_lock(Oid relid,
125+
bool unlock_if_not_found);
124126

125127
void delay_pathman_shutdown(void);
126128
void delay_invalidation_parent_rel(Oid parent);

0 commit comments

Comments
 (0)