1
0
mirror of https://github.com/postgres/postgres.git synced 2025-09-03 15:22:11 +03:00

Replace RelationOpenSmgr() with RelationGetSmgr().

This is a back-patch of the v15-era commit f10f0ae42 into older
supported branches.  The idea is to design out bugs in which an
ill-timed relcache flush clears rel->rd_smgr partway through
some code sequence that wasn't expecting that.  We had another
report today of a corner case that reliably crashes v14 under
debug_discard_caches (nee CLOBBER_CACHE_ALWAYS), and therefore
would crash once in a blue moon in the field.  We're unlikely
to get rid of all such code paths unless we adopt the more
rigorous coding rules instituted by f10f0ae42.  Therefore,
even though this is a bit invasive, it's time to back-patch.
Some comfort can be taken in the fact that f10f0ae42 has been
in v15 for 16 months without problems.

I left the RelationOpenSmgr macro present in the back branches,
even though no core code should use it anymore, in order to not break
third-party extensions in minor releases.  Such extensions might opt
to start using RelationGetSmgr instead, to reduce their code
differential between v15 and earlier branches.  This carries a hazard
of failing to compile against headers from existing minor releases.
However, once compiled the extension should work fine even with such
releases, because RelationGetSmgr is a "static inline" function so
it creates no link-time dependency.  So depending on distribution
practices, that might be an OK tradeoff.

Per report from Spyridon Dimitrios Agathos.  Original patch
by Amul Sul.

Discussion: https://postgr.es/m/CAFM5RaqdgyusQvmWkyPYaWMwoK5gigdtW-7HcgHgOeAw7mqJ_Q@mail.gmail.com
Discussion: https://postgr.es/m/CANiYTQsU7yMFpQYnv=BrcRVqK_3U3mtAzAsJCaqtzsDHfsUbdQ@mail.gmail.com
This commit is contained in:
Tom Lane
2022-11-17 16:54:31 -05:00
parent 791dd75791
commit d4acf2eb94
20 changed files with 144 additions and 142 deletions

View File

@@ -24,6 +24,7 @@
#include "rewrite/prs2lock.h"
#include "storage/block.h"
#include "storage/relfilenode.h"
#include "storage/smgr.h"
#include "utils/relcache.h"
#include "utils/reltrigger.h"
@@ -53,8 +54,7 @@ typedef LockInfoData *LockInfo;
typedef struct RelationData
{
RelFileNode rd_node; /* relation physical identifier */
/* use "struct" here to avoid needing to include smgr.h: */
struct SMgrRelationData *rd_smgr; /* cached file handle, or NULL */
SMgrRelation rd_smgr; /* cached file handle, or NULL */
int rd_refcnt; /* reference count */
BackendId rd_backend; /* owning backend id, if temporary relation */
bool rd_islocaltemp; /* rel is a temp rel of this session */
@@ -468,9 +468,33 @@ typedef struct ViewOptions
#define RelationIsMapped(relation) \
((relation)->rd_rel->relfilenode == InvalidOid)
/*
* RelationGetSmgr
* Returns smgr file handle for a relation, opening it if needed.
*
* Very little code is authorized to touch rel->rd_smgr directly. Instead
* use this function to fetch its value.
*
* Note: since a relcache flush can cause the file handle to be closed again,
* it's unwise to hold onto the pointer returned by this function for any
* long period. Recommended practice is to just re-execute RelationGetSmgr
* each time you need to access the SMgrRelation. It's quite cheap in
* comparison to whatever an smgr function is going to do.
*/
static inline SMgrRelation
RelationGetSmgr(Relation rel)
{
if (unlikely(rel->rd_smgr == NULL))
smgrsetowner(&(rel->rd_smgr), smgropen(rel->rd_node, rel->rd_backend));
return rel->rd_smgr;
}
/*
* RelationOpenSmgr
* Open the relation at the smgr level, if not already done.
*
* XXX this is now deprecated, and should not be used in new code.
* Instead, call RelationGetSmgr in place of fetching rd_smgr directly.
*/
#define RelationOpenSmgr(relation) \
do { \
@@ -498,7 +522,8 @@ typedef struct ViewOptions
* Fetch relation's current insertion target block.
*
* Returns InvalidBlockNumber if there is no current target block. Note
* that the target block status is discarded on any smgr-level invalidation.
* that the target block status is discarded on any smgr-level invalidation,
* so there's no need to re-open the smgr handle if it's not currently open.
*/
#define RelationGetTargetBlock(relation) \
( (relation)->rd_smgr != NULL ? (relation)->rd_smgr->smgr_targblock : InvalidBlockNumber )
@@ -509,8 +534,7 @@ typedef struct ViewOptions
*/
#define RelationSetTargetBlock(relation, targblock) \
do { \
RelationOpenSmgr(relation); \
(relation)->rd_smgr->smgr_targblock = (targblock); \
RelationGetSmgr(relation)->smgr_targblock = (targblock); \
} while (0)
/*