Hi, I am posting the new v2 patch, which is now rebased on the `master` branch. Waiting for your feedback :)
-- Best regards, Daniil Davydov
From 2e43a1411ebcb37b2c0c1d6bac758e48799d2c4e Mon Sep 17 00:00:00 2001 From: Daniil Davidov <d.davy...@postgrespro.ru> Date: Tue, 11 Mar 2025 17:11:16 +0700 Subject: [PATCH v2] Add macros for safety access to smgr --- src/backend/storage/buffer/bufmgr.c | 55 ++++++++++++--------------- src/backend/storage/buffer/localbuf.c | 10 +++-- src/include/storage/bufmgr.h | 14 +++++++ 3 files changed, 45 insertions(+), 34 deletions(-) diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 7915ed624c1..c55228f298a 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -887,11 +887,8 @@ ExtendBufferedRelBy(BufferManagerRelation bmr, Assert(bmr.smgr == NULL || bmr.relpersistence != 0); Assert(extend_by > 0); - if (bmr.smgr == NULL) - { - bmr.smgr = RelationGetSmgr(bmr.rel); + if (bmr.relpersistence == 0) bmr.relpersistence = bmr.rel->rd_rel->relpersistence; - } return ExtendBufferedRelCommon(bmr, fork, strategy, flags, extend_by, InvalidBlockNumber, @@ -923,11 +920,8 @@ ExtendBufferedRelTo(BufferManagerRelation bmr, Assert(bmr.smgr == NULL || bmr.relpersistence != 0); Assert(extend_to != InvalidBlockNumber && extend_to > 0); - if (bmr.smgr == NULL) - { - bmr.smgr = RelationGetSmgr(bmr.rel); + if (bmr.relpersistence == 0) bmr.relpersistence = bmr.rel->rd_rel->relpersistence; - } /* * If desired, create the file if it doesn't exist. If @@ -935,15 +929,15 @@ ExtendBufferedRelTo(BufferManagerRelation bmr, * an smgrexists call. */ if ((flags & EB_CREATE_FORK_IF_NEEDED) && - (bmr.smgr->smgr_cached_nblocks[fork] == 0 || - bmr.smgr->smgr_cached_nblocks[fork] == InvalidBlockNumber) && - !smgrexists(bmr.smgr, fork)) + (BMR_GET_SMGR(bmr)->smgr_cached_nblocks[fork] == 0 || + BMR_GET_SMGR(bmr)->smgr_cached_nblocks[fork] == InvalidBlockNumber) && + !smgrexists(BMR_GET_SMGR(bmr), fork)) { LockRelationForExtension(bmr.rel, ExclusiveLock); /* recheck, fork might have been created concurrently */ - if (!smgrexists(bmr.smgr, fork)) - smgrcreate(bmr.smgr, fork, flags & EB_PERFORMING_RECOVERY); + if (!smgrexists(BMR_GET_SMGR(bmr), fork)) + smgrcreate(BMR_GET_SMGR(bmr), fork, flags & EB_PERFORMING_RECOVERY); UnlockRelationForExtension(bmr.rel, ExclusiveLock); } @@ -953,13 +947,13 @@ ExtendBufferedRelTo(BufferManagerRelation bmr, * kernel. */ if (flags & EB_CLEAR_SIZE_CACHE) - bmr.smgr->smgr_cached_nblocks[fork] = InvalidBlockNumber; + BMR_GET_SMGR(bmr)->smgr_cached_nblocks[fork] = InvalidBlockNumber; /* * Estimate how many pages we'll need to extend by. This avoids acquiring * unnecessarily many victim buffers. */ - current_size = smgrnblocks(bmr.smgr, fork); + current_size = smgrnblocks(BMR_GET_SMGR(bmr), fork); /* * Since no-one else can be looking at the page contents yet, there is no @@ -1003,7 +997,7 @@ ExtendBufferedRelTo(BufferManagerRelation bmr, if (buffer == InvalidBuffer) { Assert(extended_by == 0); - buffer = ReadBuffer_common(bmr.rel, bmr.smgr, bmr.relpersistence, + buffer = ReadBuffer_common(bmr.rel, BMR_GET_SMGR(bmr), bmr.relpersistence, fork, extend_to - 1, mode, strategy); } @@ -2153,10 +2147,10 @@ ExtendBufferedRelCommon(BufferManagerRelation bmr, BlockNumber first_block; TRACE_POSTGRESQL_BUFFER_EXTEND_START(fork, - bmr.smgr->smgr_rlocator.locator.spcOid, - bmr.smgr->smgr_rlocator.locator.dbOid, - bmr.smgr->smgr_rlocator.locator.relNumber, - bmr.smgr->smgr_rlocator.backend, + BMR_GET_SMGR(bmr)->smgr_rlocator.locator.spcOid, + BMR_GET_SMGR(bmr)->smgr_rlocator.locator.dbOid, + BMR_GET_SMGR(bmr)->smgr_rlocator.locator.relNumber, + BMR_GET_SMGR(bmr)->smgr_rlocator.backend, extend_by); if (bmr.relpersistence == RELPERSISTENCE_TEMP) @@ -2170,10 +2164,10 @@ ExtendBufferedRelCommon(BufferManagerRelation bmr, *extended_by = extend_by; TRACE_POSTGRESQL_BUFFER_EXTEND_DONE(fork, - bmr.smgr->smgr_rlocator.locator.spcOid, - bmr.smgr->smgr_rlocator.locator.dbOid, - bmr.smgr->smgr_rlocator.locator.relNumber, - bmr.smgr->smgr_rlocator.backend, + BMR_GET_SMGR(bmr)->smgr_rlocator.locator.spcOid, + BMR_GET_SMGR(bmr)->smgr_rlocator.locator.dbOid, + BMR_GET_SMGR(bmr)->smgr_rlocator.locator.relNumber, + BMR_GET_SMGR(bmr)->smgr_rlocator.backend, *extended_by, first_block); @@ -2239,9 +2233,9 @@ ExtendBufferedRelShared(BufferManagerRelation bmr, * kernel. */ if (flags & EB_CLEAR_SIZE_CACHE) - bmr.smgr->smgr_cached_nblocks[fork] = InvalidBlockNumber; + BMR_GET_SMGR(bmr)->smgr_cached_nblocks[fork] = InvalidBlockNumber; - first_block = smgrnblocks(bmr.smgr, fork); + first_block = smgrnblocks(BMR_GET_SMGR(bmr), fork); /* * Now that we have the accurate relation size, check if the caller wants @@ -2284,7 +2278,7 @@ ExtendBufferedRelShared(BufferManagerRelation bmr, ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("cannot extend relation %s beyond %u blocks", - relpath(bmr.smgr->smgr_rlocator, fork).str, + relpath(BMR_GET_SMGR(bmr)->smgr_rlocator, fork).str, MaxBlockNumber))); /* @@ -2306,7 +2300,8 @@ ExtendBufferedRelShared(BufferManagerRelation bmr, ResourceOwnerEnlarge(CurrentResourceOwner); ReservePrivateRefCountEntry(); - InitBufferTag(&tag, &bmr.smgr->smgr_rlocator.locator, fork, first_block + i); + InitBufferTag(&tag, &BMR_GET_SMGR(bmr)->smgr_rlocator.locator, fork, + first_block + i); hash = BufTableHashCode(&tag); partition_lock = BufMappingPartitionLock(hash); @@ -2356,7 +2351,7 @@ ExtendBufferedRelShared(BufferManagerRelation bmr, ereport(ERROR, (errmsg("unexpected data beyond EOF in block %u of relation %s", existing_hdr->tag.blockNum, - relpath(bmr.smgr->smgr_rlocator, fork).str), + relpath(BMR_GET_SMGR(bmr)->smgr_rlocator, fork).str), errhint("This has been seen to occur with buggy kernels; consider updating your system."))); /* @@ -2414,7 +2409,7 @@ ExtendBufferedRelShared(BufferManagerRelation bmr, * * We don't need to set checksum for all-zero pages. */ - smgrzeroextend(bmr.smgr, fork, first_block, extend_by, false); + smgrzeroextend(BMR_GET_SMGR(bmr), fork, first_block, extend_by, false); /* * Release the file-extension lock; it's now OK for someone else to extend diff --git a/src/backend/storage/buffer/localbuf.c b/src/backend/storage/buffer/localbuf.c index 80b83444eb2..0b03920c17f 100644 --- a/src/backend/storage/buffer/localbuf.c +++ b/src/backend/storage/buffer/localbuf.c @@ -24,6 +24,7 @@ #include "utils/guc_hooks.h" #include "utils/memutils.h" #include "utils/resowner.h" +#include "utils/rel.h" /*#define LBDEBUG*/ @@ -341,7 +342,7 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, MemSet(buf_block, 0, BLCKSZ); } - first_block = smgrnblocks(bmr.smgr, fork); + first_block = smgrnblocks(BMR_GET_SMGR(bmr), fork); if (extend_upto != InvalidBlockNumber) { @@ -360,7 +361,7 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("cannot extend relation %s beyond %u blocks", - relpath(bmr.smgr->smgr_rlocator, fork).str, + relpath(BMR_GET_SMGR(bmr)->smgr_rlocator, fork).str, MaxBlockNumber))); for (uint32 i = 0; i < extend_by; i++) @@ -377,7 +378,8 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, /* in case we need to pin an existing buffer below */ ResourceOwnerEnlarge(CurrentResourceOwner); - InitBufferTag(&tag, &bmr.smgr->smgr_rlocator.locator, fork, first_block + i); + InitBufferTag(&tag, &BMR_GET_SMGR(bmr)->smgr_rlocator.locator, fork, + first_block + i); hresult = (LocalBufferLookupEnt *) hash_search(LocalBufHash, &tag, HASH_ENTER, &found); @@ -417,7 +419,7 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, io_start = pgstat_prepare_io_time(track_io_timing); /* actually extend relation */ - smgrzeroextend(bmr.smgr, fork, first_block, extend_by, false); + smgrzeroextend(BMR_GET_SMGR(bmr), fork, first_block, extend_by, false); pgstat_count_io_op_time(IOOBJECT_TEMP_RELATION, IOCONTEXT_NORMAL, IOOP_EXTEND, io_start, 1, extend_by * BLCKSZ); diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h index 7c1e4316dde..3f4228f88dc 100644 --- a/src/include/storage/bufmgr.h +++ b/src/include/storage/bufmgr.h @@ -100,13 +100,27 @@ typedef enum ExtendBufferedFlags typedef struct BufferManagerRelation { Relation rel; + + /* + * Must be accessed via BMR_GET_SMGR if we want to access some fields + * of structure + */ struct SMgrRelationData *smgr; + char relpersistence; } BufferManagerRelation; #define BMR_REL(p_rel) ((BufferManagerRelation){.rel = p_rel}) #define BMR_SMGR(p_smgr, p_relpersistence) ((BufferManagerRelation){.smgr = p_smgr, .relpersistence = p_relpersistence}) +/* + * In case of cache invalidation, we need to be sure that we access a valid + * smgr reference + */ + +#define BMR_GET_SMGR(bmr) \ + (RelationIsValid((bmr).rel) ? RelationGetSmgr((bmr).rel) : (bmr).smgr) + /* Zero out page if reading fails. */ #define READ_BUFFERS_ZERO_ON_ERROR (1 << 0) /* Call smgrprefetch() if I/O necessary. */ -- 2.43.0