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 commitf10f0ae42
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 byf10f0ae42
. Therefore, even though this is a bit invasive, it's time to back-patch. Some comfort can be taken in the fact thatf10f0ae42
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:
@@ -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)
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user