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)
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