On Wed, Aug 3, 2022 at 1:41 PM Dilip Kumar <dilipbal...@gmail.com> wrote: > > On Wed, Aug 3, 2022 at 12:00 PM Dilip Kumar <dilipbal...@gmail.com> wrote: > > > > > Okay, so AtEOXact_SMgr will only get rid of unowned smgr and ours are > > owned by a fake relcache and whose lifetime is just portal memory > > context which will go away at the transaction end. So as Andres > > suggested options could be that a) we catch the error and do > > FreeFakeRelcacheEntry. b) directly use smgropen instead of > > RelationGetSmgr because actually, we do not want the owner to be set > > for these smgrs. > > > > I think option b) looks better to me, I will prepare a patch and test > > whether the error goes away with that or not. > > > > Here is the patch which directly uses smgropen instead of using fake > relcache entry. We don't preserve the smgr pointer and whenever > required we again call the smgropen. > > With this patch it resolved the problem for me at least what I was > able to reproduce. I was able to reproduce the WARNING messages that > Robert got as well as the valgrind error that Justin got and with this > patch both are resolved.
Another version of the patch which closes the smgr at the end using smgrcloserellocator() and I have also added a commit message. -- Regards, Dilip Kumar EnterpriseDB: http://www.enterprisedb.com
From b151b54880dd17c94a25e8de908e30fe0d9a8542 Mon Sep 17 00:00:00 2001 From: Dilip Kumar <dilip.ku...@enterprisedb.com> Date: Wed, 3 Aug 2022 13:28:46 +0530 Subject: [PATCH v1] Avoid setting the fake relcache entry as smgr owner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During CREATE DATABASE, we are not connected to the source and the destination DB so in order to operate on the storage we are using FakeRelCacheEntry and by using that we are calling RelationGetSmgr(). So the problem is that this function will set the temporary FakeRelCacheEntry as an owner of the smgr. Now if there is any error before we close the FakeRelCacheEntry then the memory of the fake relcache entry will be released at the transaction abort but the smgr will survive the transaction. So now smgr is pointing to some already release memory and it will have random behavior when we try to access the smgr next time. For fixing the issue instead of using the FakeRelCacheEntry, directly call the smgropen() but do not keep the reference to the smgr. So every time call smgropen() whenever we need it. This is required to ensure that we do not access the smgr pointer which might have already been closed during interrupt processing. --- src/backend/commands/dbcommands.c | 15 +++-------- src/backend/storage/buffer/bufmgr.c | 51 +++++++++++++++++-------------------- 2 files changed, 28 insertions(+), 38 deletions(-) diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index 7bc53f3..9342e8e 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -258,8 +258,8 @@ ScanSourceDatabasePgClass(Oid tbid, Oid dbid, char *srcpath) Page page; List *rlocatorlist = NIL; LockRelId relid; - Relation rel; Snapshot snapshot; + SMgrRelation smgr; BufferAccessStrategy bstrategy; /* Get pg_class relfilenumber. */ @@ -276,16 +276,9 @@ ScanSourceDatabasePgClass(Oid tbid, Oid dbid, char *srcpath) rlocator.dbOid = dbid; rlocator.relNumber = relfilenumber; - /* - * We can't use a real relcache entry for a relation in some other - * database, but since we're only going to access the fields related to - * physical storage, a fake one is good enough. If we didn't do this and - * used the smgr layer directly, we would have to worry about - * invalidations. - */ - rel = CreateFakeRelcacheEntry(rlocator); - nblocks = smgrnblocks(RelationGetSmgr(rel), MAIN_FORKNUM); - FreeFakeRelcacheEntry(rel); + smgr = smgropen(rlocator, InvalidBackendId); + nblocks = smgrnblocks(smgr, MAIN_FORKNUM); + smgrclose(smgr); /* Use a buffer access strategy since this is a bulk read operation. */ bstrategy = GetAccessStrategy(BAS_BULKREAD); diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 6b30138..8a7ccf5 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -487,9 +487,9 @@ static void FindAndDropRelationBuffers(RelFileLocator rlocator, ForkNumber forkNum, BlockNumber nForkBlock, BlockNumber firstDelBlock); -static void RelationCopyStorageUsingBuffer(Relation src, Relation dst, - ForkNumber forkNum, - bool isunlogged); +static void RelationCopyStorageUsingBuffer(RelFileLocator srclocator, + RelFileLocator dstlocator, + ForkNumber forkNum, bool permanent); static void AtProcExit_Buffers(int code, Datum arg); static void CheckForBufferLeaks(void); static int rlocator_comparator(const void *p1, const void *p2); @@ -3701,8 +3701,9 @@ FlushRelationsAllBuffers(SMgrRelation *smgrs, int nrels) * -------------------------------------------------------------------- */ static void -RelationCopyStorageUsingBuffer(Relation src, Relation dst, ForkNumber forkNum, - bool permanent) +RelationCopyStorageUsingBuffer(RelFileLocator srclocator, + RelFileLocator dstlocator, + ForkNumber forkNum, bool permanent) { Buffer srcBuf; Buffer dstBuf; @@ -3722,7 +3723,8 @@ RelationCopyStorageUsingBuffer(Relation src, Relation dst, ForkNumber forkNum, use_wal = XLogIsNeeded() && (permanent || forkNum == INIT_FORKNUM); /* Get number of blocks in the source relation. */ - nblocks = smgrnblocks(RelationGetSmgr(src), forkNum); + nblocks = smgrnblocks(smgropen(srclocator, InvalidBackendId), + forkNum); /* Nothing to copy; just return. */ if (nblocks == 0) @@ -3738,7 +3740,7 @@ RelationCopyStorageUsingBuffer(Relation src, Relation dst, ForkNumber forkNum, CHECK_FOR_INTERRUPTS(); /* Read block from source relation. */ - srcBuf = ReadBufferWithoutRelcache(src->rd_locator, forkNum, blkno, + srcBuf = ReadBufferWithoutRelcache(srclocator, forkNum, blkno, RBM_NORMAL, bstrategy_src, permanent); srcPage = BufferGetPage(srcBuf); @@ -3749,7 +3751,7 @@ RelationCopyStorageUsingBuffer(Relation src, Relation dst, ForkNumber forkNum, } /* Use P_NEW to extend the destination relation. */ - dstBuf = ReadBufferWithoutRelcache(dst->rd_locator, forkNum, P_NEW, + dstBuf = ReadBufferWithoutRelcache(dstlocator, forkNum, P_NEW, RBM_NORMAL, bstrategy_dst, permanent); LockBuffer(dstBuf, BUFFER_LOCK_EXCLUSIVE); @@ -3787,8 +3789,7 @@ void CreateAndCopyRelationData(RelFileLocator src_rlocator, RelFileLocator dst_rlocator, bool permanent) { - Relation src_rel; - Relation dst_rel; + RelFileLocatorBackend rlocator; char relpersistence; /* Set the relpersistence. */ @@ -3796,16 +3797,6 @@ CreateAndCopyRelationData(RelFileLocator src_rlocator, RELPERSISTENCE_PERMANENT : RELPERSISTENCE_UNLOGGED; /* - * We can't use a real relcache entry for a relation in some other - * database, but since we're only going to access the fields related to - * physical storage, a fake one is good enough. If we didn't do this and - * used the smgr layer directly, we would have to worry about - * invalidations. - */ - src_rel = CreateFakeRelcacheEntry(src_rlocator); - dst_rel = CreateFakeRelcacheEntry(dst_rlocator); - - /* * Create and copy all forks of the relation. During create database we * have a separate cleanup mechanism which deletes complete database * directory. Therefore, each individual relation doesn't need to be @@ -3814,15 +3805,16 @@ CreateAndCopyRelationData(RelFileLocator src_rlocator, RelationCreateStorage(dst_rlocator, relpersistence, false); /* copy main fork. */ - RelationCopyStorageUsingBuffer(src_rel, dst_rel, MAIN_FORKNUM, permanent); + RelationCopyStorageUsingBuffer(src_rlocator, dst_rlocator, MAIN_FORKNUM, + permanent); /* copy those extra forks that exist */ for (ForkNumber forkNum = MAIN_FORKNUM + 1; forkNum <= MAX_FORKNUM; forkNum++) { - if (smgrexists(RelationGetSmgr(src_rel), forkNum)) + if (smgrexists(smgropen(src_rlocator, InvalidBackendId), forkNum)) { - smgrcreate(RelationGetSmgr(dst_rel), forkNum, false); + smgrcreate(smgropen(dst_rlocator, InvalidBackendId), forkNum, false); /* * WAL log creation if the relation is persistent, or this is the @@ -3832,14 +3824,19 @@ CreateAndCopyRelationData(RelFileLocator src_rlocator, log_smgrcreate(&dst_rlocator, forkNum); /* Copy a fork's data, block by block. */ - RelationCopyStorageUsingBuffer(src_rel, dst_rel, forkNum, + RelationCopyStorageUsingBuffer(src_rlocator, dst_rlocator, forkNum, permanent); } } - /* Release fake relcache entries. */ - FreeFakeRelcacheEntry(src_rel); - FreeFakeRelcacheEntry(dst_rel); + /* close source and destination smgr if exists. */ + rlocator.backend = InvalidBackendId; + + rlocator.locator = src_rlocator; + smgrcloserellocator(rlocator); + + rlocator.locator = dst_rlocator; + smgrcloserellocator(rlocator); } /* --------------------------------------------------------------------- -- 1.8.3.1