aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/transam/xlogutils.c3
-rw-r--r--src/backend/storage/smgr/smgr.c42
-rw-r--r--src/include/storage/smgr.h1
3 files changed, 42 insertions, 4 deletions
diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c
index f1918f6b078..05e74de9211 100644
--- a/src/backend/access/transam/xlogutils.c
+++ b/src/backend/access/transam/xlogutils.c
@@ -445,6 +445,9 @@ CreateFakeRelcacheEntry(RelFileNode rnode)
void
FreeFakeRelcacheEntry(Relation fakerel)
{
+ /* make sure the fakerel is not referenced by the SmgrRelation anymore */
+ if (fakerel->rd_smgr != NULL)
+ smgrclearowner(&fakerel->rd_smgr, fakerel->rd_smgr);
pfree(fakerel);
}
diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c
index 37be3081803..fcbdc4117a5 100644
--- a/src/backend/storage/smgr/smgr.c
+++ b/src/backend/storage/smgr/smgr.c
@@ -84,6 +84,7 @@ static SMgrRelation first_unowned_reln = NULL;
/* local function prototypes */
static void smgrshutdown(int code, Datum arg);
+static void add_to_unowned_list(SMgrRelation reln);
static void remove_from_unowned_list(SMgrRelation reln);
@@ -174,9 +175,8 @@ smgropen(RelFileNode rnode, BackendId backend)
for (forknum = 0; forknum <= MAX_FORKNUM; forknum++)
reln->md_fd[forknum] = NULL;
- /* place it at head of unowned list (to make smgrsetowner cheap) */
- reln->next_unowned_reln = first_unowned_reln;
- first_unowned_reln = reln;
+ /* it has no owner yet */
+ add_to_unowned_list(reln);
}
return reln;
@@ -191,7 +191,7 @@ smgropen(RelFileNode rnode, BackendId backend)
void
smgrsetowner(SMgrRelation *owner, SMgrRelation reln)
{
- /* We don't currently support "disowning" an SMgrRelation here */
+ /* We don't support "disowning" an SMgrRelation here, use smgrclearowner */
Assert(owner != NULL);
/*
@@ -214,6 +214,40 @@ smgrsetowner(SMgrRelation *owner, SMgrRelation reln)
}
/*
+ * smgrclearowner() -- Remove long-lived reference to an SMgrRelation object
+ * if one exists
+ */
+void
+smgrclearowner(SMgrRelation *owner, SMgrRelation reln)
+{
+ /* Do nothing if the SMgrRelation object is not owned by the owner */
+ if (reln->smgr_owner != owner)
+ return;
+
+ /* unset the owner's reference */
+ *owner = NULL;
+
+ /* unset our reference to the owner */
+ reln->smgr_owner = NULL;
+
+ add_to_unowned_list(reln);
+}
+
+/*
+ * add_to_unowned_list -- link an SMgrRelation onto the unowned list
+ *
+ * Check remove_from_unowned_list()'s comments for performance
+ * considerations.
+ */
+static void
+add_to_unowned_list(SMgrRelation reln)
+{
+ /* place it at head of the list (to make smgrsetowner cheap) */
+ reln->next_unowned_reln = first_unowned_reln;
+ first_unowned_reln = reln;
+}
+
+/*
* remove_from_unowned_list -- unlink an SMgrRelation from the unowned list
*
* If the reln is not present in the list, nothing happens. Typically this
diff --git a/src/include/storage/smgr.h b/src/include/storage/smgr.h
index 8f523a61288..c7ab235ba42 100644
--- a/src/include/storage/smgr.h
+++ b/src/include/storage/smgr.h
@@ -80,6 +80,7 @@ extern void smgrinit(void);
extern SMgrRelation smgropen(RelFileNode rnode, BackendId backend);
extern bool smgrexists(SMgrRelation reln, ForkNumber forknum);
extern void smgrsetowner(SMgrRelation *owner, SMgrRelation reln);
+extern void smgrclearowner(SMgrRelation *owner, SMgrRelation reln);
extern void smgrclose(SMgrRelation reln);
extern void smgrcloseall(void);
extern void smgrclosenode(RelFileNodeBackend rnode);