@@ -36,7 +36,7 @@ typedef struct PartitionDirectoryData
3636{
3737 MemoryContext pdir_mcxt ;
3838 HTAB * pdir_hash ;
39- bool omit_detached ;
39+ Snapshot omit_detached_snapshot ;
4040} PartitionDirectoryData ;
4141
4242typedef struct PartitionDirectoryEntry
@@ -47,17 +47,23 @@ typedef struct PartitionDirectoryEntry
4747} PartitionDirectoryEntry ;
4848
4949static PartitionDesc RelationBuildPartitionDesc (Relation rel ,
50- bool omit_detached );
50+ Snapshot omit_detached_snapshot );
5151
5252
5353/*
54- * RelationGetPartitionDesc -- get partition descriptor, if relation is partitioned
54+ * RelationGetPartitionDescExt
55+ * Get partition descriptor of a partitioned table, building one and
56+ * caching it for later use if not already or if the cached one would
57+ * not be suitable for a given request
5558 *
5659 * We keep two partdescs in relcache: rd_partdesc includes all partitions
57- * (even those being concurrently marked detached), while rd_partdesc_nodetached
58- * omits (some of) those. We store the pg_inherits.xmin value for the latter,
59- * to determine whether it can be validly reused in each case, since that
60- * depends on the active snapshot.
60+ * (even the one being concurrently marked detached), while
61+ * rd_partdesc_nodetached omits the detach-pending partition. If the latter one
62+ * is present, rd_partdesc_nodetach_xmin would have been set to the xmin of
63+ * the detach-pending partition's pg_inherits row, which is used to determine
64+ * whether rd_partdesc_nodetach can be validly reused for a given request by
65+ * checking if the xmin appears visible to 'omit_detached_snapshot' passed by
66+ * the caller.
6167 *
6268 * Note: we arrange for partition descriptors to not get freed until the
6369 * relcache entry's refcount goes to zero (see hacks in RelationClose,
@@ -68,7 +74,7 @@ static PartitionDesc RelationBuildPartitionDesc(Relation rel,
6874 * that the data doesn't become stale.
6975 */
7076PartitionDesc
71- RelationGetPartitionDesc (Relation rel , bool omit_detached )
77+ RelationGetPartitionDescExt (Relation rel , Snapshot omit_detached_snapshot )
7278{
7379 Assert (rel -> rd_rel -> relkind == RELKIND_PARTITIONED_TABLE );
7480
@@ -77,36 +83,51 @@ RelationGetPartitionDesc(Relation rel, bool omit_detached)
7783 * do so when we are asked to include all partitions including detached;
7884 * and also when we know that there are no detached partitions.
7985 *
80- * If there is no active snapshot, detached partitions aren't omitted
81- * either, so we can use the cached descriptor too in that case.
86+ * omit_detached_snapshot being NULL means that the caller doesn't care
87+ * that the returned partition descriptor may contain detached partitions,
88+ * so we we can used the cached descriptor in that case too.
8289 */
8390 if (likely (rel -> rd_partdesc &&
84- (!rel -> rd_partdesc -> detached_exist || ! omit_detached ||
85- ! ActiveSnapshotSet () )))
91+ (!rel -> rd_partdesc -> detached_exist ||
92+ omit_detached_snapshot == NULL )))
8693 return rel -> rd_partdesc ;
8794
8895 /*
89- * If we're asked to omit detached partitions, we may be able to use a
90- * cached descriptor too. We determine that based on the pg_inherits.xmin
91- * that was saved alongside that descriptor: if the xmin that was not in
92- * progress for that active snapshot is also not in progress for the
93- * current active snapshot, then we can use it. Otherwise build one from
94- * scratch.
96+ * If we're asked to omit the detached partition, we may be able to use
97+ * the other cached descriptor, which has been made to omit the detached
98+ * partition. Whether that descriptor can be reused in this case is
99+ * determined based on cross-checking the visibility of
100+ * rd_partdesc_nodetached_xmin, that is, the pg_inherits.xmin of the
101+ * pg_inherits row of the detached partition: if the xmin seems in-progress
102+ * to both the given omit_detached_snapshot and to the snapshot that would
103+ * have been passed when rd_partdesc_nodetached was built, then we can
104+ * reuse it. Otherwise we must build one from scratch.
95105 */
96- if (omit_detached &&
97- rel -> rd_partdesc_nodetached &&
98- ActiveSnapshotSet ())
106+ if (rel -> rd_partdesc_nodetached && omit_detached_snapshot )
99107 {
100- Snapshot activesnap ;
101-
102108 Assert (TransactionIdIsValid (rel -> rd_partdesc_nodetached_xmin ));
103- activesnap = GetActiveSnapshot ();
104109
105- if (!XidInMVCCSnapshot (rel -> rd_partdesc_nodetached_xmin , activesnap ))
110+ if (!XidInMVCCSnapshot (rel -> rd_partdesc_nodetached_xmin ,
111+ omit_detached_snapshot ))
106112 return rel -> rd_partdesc_nodetached ;
107113 }
108114
109- return RelationBuildPartitionDesc (rel , omit_detached );
115+ return RelationBuildPartitionDesc (rel , omit_detached_snapshot );
116+ }
117+
118+ /*
119+ * RelationGetPartitionDesc
120+ * Like RelationGetPartitionDescExt() but for callers that are fine with
121+ * ActiveSnapshot being used as omit_detached_snapshot
122+ */
123+ PartitionDesc
124+ RelationGetPartitionDesc (Relation rel , bool omit_detached )
125+ {
126+ Snapshot snapshot = NULL ;
127+
128+ if (omit_detached && ActiveSnapshotSet ())
129+ snapshot = GetActiveSnapshot ();
130+ return RelationGetPartitionDescExt (rel , snapshot );
110131}
111132
112133/*
@@ -131,7 +152,8 @@ RelationGetPartitionDesc(Relation rel, bool omit_detached)
131152 * for them.
132153 */
133154static PartitionDesc
134- RelationBuildPartitionDesc (Relation rel , bool omit_detached )
155+ RelationBuildPartitionDesc (Relation rel ,
156+ Snapshot omit_detached_snapshot )
135157{
136158 PartitionDesc partdesc ;
137159 PartitionBoundInfo boundinfo = NULL ;
@@ -162,7 +184,8 @@ RelationBuildPartitionDesc(Relation rel, bool omit_detached)
162184 detached_exist = false;
163185 detached_xmin = InvalidTransactionId ;
164186 inhoids = find_inheritance_children_extended (RelationGetRelid (rel ),
165- omit_detached , NoLock ,
187+ omit_detached_snapshot ,
188+ NoLock ,
166189 & detached_exist ,
167190 & detached_xmin );
168191
@@ -362,11 +385,11 @@ RelationBuildPartitionDesc(Relation rel, bool omit_detached)
362385 *
363386 * Note that if a partition was found by the catalog's scan to have been
364387 * detached, but the pg_inherit tuple saying so was not visible to the
365- * active snapshot (find_inheritance_children_extended will not have set
366- * detached_xmin in that case), we consider there to be no "omittable"
367- * detached partitions.
388+ * omit_detached_snapshot (find_inheritance_children_extended() will not
389+ * have set detached_xmin in that case), we consider there to be no
390+ * "omittable" detached partitions.
368391 */
369- is_omit = omit_detached && detached_exist && ActiveSnapshotSet () &&
392+ is_omit = detached_exist && omit_detached_snapshot &&
370393 TransactionIdIsValid (detached_xmin );
371394
372395 /*
@@ -420,7 +443,7 @@ RelationBuildPartitionDesc(Relation rel, bool omit_detached)
420443 * Create a new partition directory object.
421444 */
422445PartitionDirectory
423- CreatePartitionDirectory (MemoryContext mcxt , bool omit_detached )
446+ CreatePartitionDirectory (MemoryContext mcxt , Snapshot omit_detached_snapshot )
424447{
425448 MemoryContext oldcontext = MemoryContextSwitchTo (mcxt );
426449 PartitionDirectory pdir ;
@@ -435,7 +458,7 @@ CreatePartitionDirectory(MemoryContext mcxt, bool omit_detached)
435458
436459 pdir -> pdir_hash = hash_create ("partition directory" , 256 , & ctl ,
437460 HASH_ELEM | HASH_BLOBS | HASH_CONTEXT );
438- pdir -> omit_detached = omit_detached ;
461+ pdir -> omit_detached_snapshot = omit_detached_snapshot ;
439462
440463 MemoryContextSwitchTo (oldcontext );
441464 return pdir ;
@@ -468,7 +491,8 @@ PartitionDirectoryLookup(PartitionDirectory pdir, Relation rel)
468491 */
469492 RelationIncrementReferenceCount (rel );
470493 pde -> rel = rel ;
471- pde -> pd = RelationGetPartitionDesc (rel , pdir -> omit_detached );
494+ pde -> pd = RelationGetPartitionDescExt (rel ,
495+ pdir -> omit_detached_snapshot );
472496 Assert (pde -> pd != NULL );
473497 }
474498 return pde -> pd ;
0 commit comments