summaryrefslogtreecommitdiff
path: root/src/include
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2021-07-12 17:01:29 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2021-07-12 17:01:36 -0400
commitf10f0ae420ee62400876ab34dca2c09c20dcd030 (patch)
treeced34194fca859a625ef5d74a5479921cecad951 /src/include
parent5b60cf35f566697030a2895dfe27dde2e34dd370 (diff)
Replace RelationOpenSmgr() with RelationGetSmgr().
The idea behind this patch is to design out bugs like the one fixed by commit 9d523119f. Previously, once one did RelationOpenSmgr(rel), it was considered okay to access rel->rd_smgr directly for some not-very-clear interval. But since that pointer will be cleared by relcache flushes, we had bugs arising from overreliance on a previous RelationOpenSmgr call still being effective. Now, very little code except that in rel.h and relcache.c should ever touch the rd_smgr field directly. The normal coding rule is to use RelationGetSmgr(rel) and not expect the result to be valid for longer than one smgr function call. There are a couple of places where using the function every single time seemed like overkill, but they are now annotated with large warning comments. Amul Sul, after an idea of mine. Discussion: https://postgr.es/m/CANiYTQsU7yMFpQYnv=BrcRVqK_3U3mtAzAsJCaqtzsDHfsUbdQ@mail.gmail.com
Diffstat (limited to 'src/include')
-rw-r--r--src/include/utils/rel.h37
1 files changed, 24 insertions, 13 deletions
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index 77d176a9348..b4faa1c1238 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -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 */
@@ -528,14 +528,25 @@ typedef struct ViewOptions
((relation)->rd_rel->relfilenode == InvalidOid))
/*
- * RelationOpenSmgr
- * Open the relation at the smgr level, if not already done.
- */
-#define RelationOpenSmgr(relation) \
- do { \
- if ((relation)->rd_smgr == NULL) \
- smgrsetowner(&((relation)->rd_smgr), smgropen((relation)->rd_node, (relation)->rd_backend)); \
- } while (0)
+ * 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;
+}
/*
* RelationCloseSmgr
@@ -557,7 +568,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 )
@@ -568,8 +580,7 @@ typedef struct ViewOptions
*/
#define RelationSetTargetBlock(relation, targblock) \
do { \
- RelationOpenSmgr(relation); \
- (relation)->rd_smgr->smgr_targblock = (targblock); \
+ RelationGetSmgr(relation)->smgr_targblock = (targblock); \
} while (0)
/*