diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c index f1918f6b078e224d81a1bbb327b2c2b995c1a935..05e74de92119fadbaad275ecaac40981d79ed971 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 37be3081803c69bc20ae9a9818c51dd2416dd0fd..fcbdc4117a56692e81f18cc7c3c5c2ac842d33f5 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); /* @@ -213,6 +213,40 @@ smgrsetowner(SMgrRelation *owner, SMgrRelation reln) *owner = 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 * diff --git a/src/include/storage/smgr.h b/src/include/storage/smgr.h index 8f523a61288fd35b80eccbc53b2e32feaec0ef2f..c7ab235ba42bfd22dead49409a83076ca8ad7f63 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);