pg.ddx.io  pgsql-hackers@postgresql.org mailing list archive  
help / color / mirror / Atom feed
Optimize truncation logic to reduce AccessExclusive lock impact
5+ messages / 4 participants
[nested] [flat]

* Optimize truncation logic to reduce AccessExclusive lock impact
@ 2025-03-18 06:03 Stepan Neretin <slpmcf@gmail.com>
  2025-03-19 02:09 ` Re: Optimize truncation logic to reduce AccessExclusive lock impact David Rowley <dgrowleyml@gmail.com>
  0 siblings, 1 reply; 5+ messages in thread

From: Stepan Neretin @ 2025-03-18 06:03 UTC (permalink / raw)
  To: PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>

Hi hackers,

We've encountered an issue where autovacuum holds an AccessExclusive lock
for an extended period when attempting to truncate heap tables. The root
cause appears to be the way autovacuum handles block truncation,
specifically when scanning shared buffers during smgrtruncate. This issue
is particularly painful for large shared buffer configurations (e.g., 1.8
TiB with NUMA and multiple workers), and pg_statistic is among the most
affected tables.

When autovacuum detects freeable blocks at the tail of a relation, it
attempts to truncate them. It acquires an AccessExclusive lock and scans
all shared buffers to remove the corresponding blocks. With a large shared
buffer configuration (e.g., 1.8 TiB, 200 million blocks, and multiple NUMA
nodes), this process is slow and significantly impacts performance.

We propose modifying the truncation condition in should_attempt_truncation
to avoid unnecessary full buffer scans. The new formula ensures we only
attempt truncation when we can free at least 3% of the relation size + 2
pages. This change prevents excessive truncation attempts on small tables
while reducing the impact on larger relations. Previously, small tables
could theoretically be truncated to a single page, but with this change,
they may remain around 3 pages instead. We don't see this as a significant
issue.

The idea for this patch was proposed by Yuriy Sokolov.

There is also an open discussion about optimizing the shared buffer
traversal to minimize the impact of AccessExclusive locks. This patch is a
step toward improving the situation.

The patch is attached to this message.

Best regards, Stepan Neretin.

Attachments:

  [text/x-patch] 03164ee7bce36946eaa521f6db2be1b30bead577.diff (1.0K, ../../CA+Yyo5Trs9x03-sc4PpmEXPY9K_B_jbEbNd01RbF+vOxs3zVUA@mail.gmail.com/3-03164ee7bce36946eaa521f6db2be1b30bead577.diff)
  download | inline diff:
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index 159b822740ab32989d8e5d4da71a61c3450ec0f3..d8211470fc34cac00b3da2d8c1bd786ba9ed1e08 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -67,8 +67,8 @@
  * REL_TRUNCATE_MINIMUM or (relsize / REL_TRUNCATE_FRACTION) (whichever
  * is less) potentially-freeable pages.
  */
-#define REL_TRUNCATE_MINIMUM	1000
-#define REL_TRUNCATE_FRACTION	16
+#define REL_TRUNCATE_MINIMUM	2
+#define REL_TRUNCATE_FRACTION	32
 
 /*
  * Timing parameters for truncate locking heuristics.
@@ -3089,9 +3089,7 @@ should_attempt_truncation(LVRelState *vacrel)
 		return false;
 
 	possibly_freeable = vacrel->rel_pages - vacrel->nonempty_pages;
-	if (possibly_freeable > 0 &&
-		(possibly_freeable >= REL_TRUNCATE_MINIMUM ||
-		 possibly_freeable >= vacrel->rel_pages / REL_TRUNCATE_FRACTION))
+	if (possibly_freeable >= vacrel->rel_pages / REL_TRUNCATE_FRACTION + REL_TRUNCATE_MINIMUM)
 		return true;
 
 	return false;


^ permalink  raw  reply  [nested|flat] 5+ messages in thread

* Re: Optimize truncation logic to reduce AccessExclusive lock impact
  2025-03-18 06:03 Optimize truncation logic to reduce AccessExclusive lock impact Stepan Neretin <slpmcf@gmail.com>
@ 2025-03-19 02:09 ` David Rowley <dgrowleyml@gmail.com>
  2025-03-19 16:05   ` Re: Optimize truncation logic to reduce AccessExclusive lock impact Yura Sokolov <y.sokolov@postgrespro.ru>
  0 siblings, 1 reply; 5+ messages in thread

From: David Rowley @ 2025-03-19 02:09 UTC (permalink / raw)
  To: Stepan Neretin <slpmcf@gmail.com>; +Cc: PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>

On Tue, 18 Mar 2025 at 19:04, Stepan Neretin <slpmcf@gmail.com> wrote:
> We propose modifying the truncation condition in should_attempt_truncation to avoid unnecessary full buffer scans. The new formula ensures we only attempt truncation when we can free at least 3% of the relation size + 2 pages. This change prevents excessive truncation attempts on small tables while reducing the impact on larger relations. Previously, small tables could theoretically be truncated to a single page, but with this change, they may remain around 3 pages instead. We don't see this as a significant issue.

I'm just following this code through. Looking at
DropRelationBuffers(), d6ad34f34 added an optimisation so that we can
skip scanning all of shared buffers while in recovery (where
smgrnblocks_cached() can return a non-InvalidBlockNumber value), which
the following code might decide to lookup the buffers one-by-one
rather than scanning the entire buffer pool:

if (BlockNumberIsValid(nBlocksToInvalidate) &&
    nBlocksToInvalidate < BUF_DROP_FULL_SCAN_THRESHOLD)
    {
        for (j = 0; j < nforks; j++)
            FindAndDropRelationBuffers(rlocator.locator, forkNum[j],
                nForkBlock[j], firstDelBlock[j]);
        return;
}

While I don't know this code too well, from a quick look, it seem to
me that since DropRelationBuffers() is being called from
smgrtruncate() in this case, smgrtruncate() has access to old_nblocks
so it knows the old size of the relation. Couldn't we do something
like have another version of DropRelationBuffers() which accepts a
parameter for the old number of blocks and uses that instead of
calling smgrnblocks_cached()?  That would allow the
FindAndDropRelationBuffers() optimisation to be used in cases where
the buffers to truncate is small or shared buffers is large.

As for the patch being proposed, it looks like you're maybe just
showing the answer to the question left in the comment below is "Yes".

/*
 * Space/time tradeoff parameters: do these need to be user-tunable?
 *
 * To consider truncating the relation, we want there to be at least
 * REL_TRUNCATE_MINIMUM or (relsize / REL_TRUNCATE_FRACTION) (whichever
 * is less) potentially-freeable pages.
 */
#define REL_TRUNCATE_MINIMUM 1000
#define REL_TRUNCATE_FRACTION 16

David





^ permalink  raw  reply  [nested|flat] 5+ messages in thread

* Re: Optimize truncation logic to reduce AccessExclusive lock impact
  2025-03-18 06:03 Optimize truncation logic to reduce AccessExclusive lock impact Stepan Neretin <slpmcf@gmail.com>
  2025-03-19 02:09 ` Re: Optimize truncation logic to reduce AccessExclusive lock impact David Rowley <dgrowleyml@gmail.com>
@ 2025-03-19 16:05   ` Yura Sokolov <y.sokolov@postgrespro.ru>
  2025-03-21 11:50     ` Re: Optimize truncation logic to reduce AccessExclusive lock impact Yura Sokolov <y.sokolov@postgrespro.ru>
  0 siblings, 1 reply; 5+ messages in thread

From: Yura Sokolov @ 2025-03-19 16:05 UTC (permalink / raw)
  To: David Rowley <dgrowleyml@gmail.com>; Stepan Neretin <slpmcf@gmail.com>; +Cc: PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>

19.03.2025 05:09, David Rowley wrote:
> On Tue, 18 Mar 2025 at 19:04, Stepan Neretin <slpmcf@gmail.com> wrote:
>> We propose modifying the truncation condition in should_attempt_truncation to avoid unnecessary full buffer scans. The new formula ensures we only attempt truncation when we can free at least 3% of the relation size + 2 pages. This change prevents excessive truncation attempts on small tables while reducing the impact on larger relations. Previously, small tables could theoretically be truncated to a single page, but with this change, they may remain around 3 pages instead. We don't see this as a significant issue.
> 
> I'm just following this code through. Looking at
> DropRelationBuffers(), d6ad34f34 added an optimisation so that we can
> skip scanning all of shared buffers while in recovery (where
> smgrnblocks_cached() can return a non-InvalidBlockNumber value), which
> the following code might decide to lookup the buffers one-by-one
> rather than scanning the entire buffer pool:
> 
> if (BlockNumberIsValid(nBlocksToInvalidate) &&
>     nBlocksToInvalidate < BUF_DROP_FULL_SCAN_THRESHOLD)
>     {
>         for (j = 0; j < nforks; j++)
>             FindAndDropRelationBuffers(rlocator.locator, forkNum[j],
>                 nForkBlock[j], firstDelBlock[j]);
>         return;
> }
> 
> While I don't know this code too well, from a quick look, it seem to
> me that since DropRelationBuffers() is being called from
> smgrtruncate() in this case, smgrtruncate() has access to old_nblocks
> so it knows the old size of the relation. Couldn't we do something
> like have another version of DropRelationBuffers() which accepts a
> parameter for the old number of blocks and uses that instead of
> calling smgrnblocks_cached()?  That would allow the
> FindAndDropRelationBuffers() optimisation to be used in cases where
> the buffers to truncate is small or shared buffers is large.

Yes, it will work for smaller relations.
But it doesn't fix issue with large relations:
- imho, there is no big need to truncate 2TB table to release every 8MB of
free space, but it happens now.

So, probably we should do both:
- improve truncate of smaller relations
- reduce frequency of truncation larger relations.

I believe, suggested patch is acceptable in its form and will not harm
after optimization for small relations will be implemented.
(Disclaimer: I'm the author of the patch.)

> As for the patch being proposed, it looks like you're maybe just
> showing the answer to the question left in the comment below is "Yes".
>
> /*
>  * Space/time tradeoff parameters: do these need to be user-tunable?

Well, the patch changes formula as well. It is harder to implement
user-tunable formula.

-------
regards
Yura Sokolov





^ permalink  raw  reply  [nested|flat] 5+ messages in thread

* Re: Optimize truncation logic to reduce AccessExclusive lock impact
  2025-03-18 06:03 Optimize truncation logic to reduce AccessExclusive lock impact Stepan Neretin <slpmcf@gmail.com>
  2025-03-19 02:09 ` Re: Optimize truncation logic to reduce AccessExclusive lock impact David Rowley <dgrowleyml@gmail.com>
  2025-03-19 16:05   ` Re: Optimize truncation logic to reduce AccessExclusive lock impact Yura Sokolov <y.sokolov@postgrespro.ru>
@ 2025-03-21 11:50     ` Yura Sokolov <y.sokolov@postgrespro.ru>
  2026-09-17 02:44       ` Re: Optimize truncation logic to reduce AccessExclusive lock impact shihao zhong <zhong950419@gmail.com>
  0 siblings, 1 reply; 5+ messages in thread

From: Yura Sokolov @ 2025-03-21 11:50 UTC (permalink / raw)
  To: David Rowley <dgrowleyml@gmail.com>; Stepan Neretin <slpmcf@gmail.com>; +Cc: PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>

19.03.2025 19:05, Yura Sokolov wrote:
> 19.03.2025 05:09, David Rowley wrote:
>> On Tue, 18 Mar 2025 at 19:04, Stepan Neretin <slpmcf@gmail.com> wrote:
>>> We propose modifying the truncation condition in should_attempt_truncation to avoid unnecessary full buffer scans. 
>> I'm just following this code through. Looking at
>> DropRelationBuffers(), d6ad34f34 added an optimisation so that we can
>> skip scanning all of shared buffers while in recovery (where
>> smgrnblocks_cached() can return a non-InvalidBlockNumber value), which
>> the following code might decide to lookup the buffers one-by-one
>> rather than scanning the entire buffer pool:
>>
>> if (BlockNumberIsValid(nBlocksToInvalidate) &&
>>     nBlocksToInvalidate < BUF_DROP_FULL_SCAN_THRESHOLD)
>>     {
>>         for (j = 0; j < nforks; j++)
>>             FindAndDropRelationBuffers(rlocator.locator, forkNum[j],
>>                 nForkBlock[j], firstDelBlock[j]);
>>         return;
>> }
>>
>> While I don't know this code too well, from a quick look, it seem to
>> me that since DropRelationBuffers() is being called from
>> smgrtruncate() in this case, smgrtruncate() has access to old_nblocks
>> so it knows the old size of the relation. Couldn't we do something
>> like have another version of DropRelationBuffers() which accepts a
>> parameter for the old number of blocks and uses that instead of
>> calling smgrnblocks_cached()?  That would allow the
>> FindAndDropRelationBuffers() optimisation to be used in cases where
>> the buffers to truncate is small or shared buffers is large.
> 
> Yes, it will work for smaller relations.
> But it doesn't fix issue with large relations:
> - imho, there is no big need to truncate 2TB table to release every 8MB of
> free space, but it happens now.

After thinking a bit, I realized I was not quite right: if large table is
truncated on small number of pages, and we know old size and new one, we
can precisely remove them from shared buffers.

Exactly as you've described, excuse me for not understanding you clearly
for the first time.

But the question still remains: should we use this possibility with huge
tables, or we should just truncate them rarely?

-- 
regards
Yura Sokolov aka funny-falcon





^ permalink  raw  reply  [nested|flat] 5+ messages in thread

* Re: Optimize truncation logic to reduce AccessExclusive lock impact
  2025-03-18 06:03 Optimize truncation logic to reduce AccessExclusive lock impact Stepan Neretin <slpmcf@gmail.com>
  2025-03-19 02:09 ` Re: Optimize truncation logic to reduce AccessExclusive lock impact David Rowley <dgrowleyml@gmail.com>
  2025-03-19 16:05   ` Re: Optimize truncation logic to reduce AccessExclusive lock impact Yura Sokolov <y.sokolov@postgrespro.ru>
  2025-03-21 11:50     ` Re: Optimize truncation logic to reduce AccessExclusive lock impact Yura Sokolov <y.sokolov@postgrespro.ru>
@ 2026-09-17 02:44       ` shihao zhong <zhong950419@gmail.com>
  0 siblings, 0 replies; 5+ messages in thread

From: shihao zhong @ 2026-09-17 02:44 UTC (permalink / raw)
  To: Yura Sokolov <y.sokolov@postgrespro.ru>; +Cc: David Rowley <dgrowleyml@gmail.com>; Stepan Neretin <slpmcf@gmail.com>; PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>

> Couldn't we do something like have another version of
DropRelationBuffers()
> which accepts a parameter for the old number of blocks and uses that
instead
> of calling smgrnblocks_cached()?

Hi David,

Here is a patch for that idea. It only covers relation truncation, such
as the tail truncation done by vacuum. DROP TABLE and plain TRUNCATE go
through DropRelationsAllBuffers() and are not changed.

smgrtruncate() already gets the current fork sizes from its callers as
old_nblocks. The patch passes them on to DropRelationBuffers(), so no
lseek() is added. It also adds an assertion to RelationTruncate() that
the caller holds AccessExclusiveLock.

In the original thread Tom said there is no room for "good enough" here,
because a dirty buffer left behind breaks the checkpointer. This is why
the passed sizes are safe.

1. Nothing can extend the relation between measuring and dropping.
Outside recovery the caller holds AccessExclusiveLock. During recovery
only the startup process extends relations, and the passed sizes equal
the cached ones, so recovery does not change.

2. If the size we pass is larger than the real one, we only do some
useless lookups. If it were smaller, we would miss buffers past it. That
can only happen if the relation grows after we measure it, and point 1
rules that out.

3. Buffers can exist past the end of the file after a failed extension.
They are neither valid nor dirty, so nobody writes them, and skipping
them is harmless.

One case does differ from today. Reading past the end of the file with
zero_damaged_pages can leave a valid zero page behind. If the data is
already corrupt and someone writes to that page, the full scan would
drop it. The patch leaves it for the checkpointer. I think that is fine
for a setting meant for recovering from corruption.

To look for missed buffers, I used a temporary check that scanned the
whole pool after each targeted drop. It caught deliberately wrong sizes,
and found nothing in the full test suite or in a concurrent stress run.

Numbers come from release builds on the same base commit, timing only
the DropRelationBuffers() call. Values are medians of 8 truncations.

Truncating 2000 pages, with 8 clients running pgbench -S:

  shared_buffers   master     patched
  2GB               1.83 ms   0.24 ms
  8GB               6.29 ms   0.18 ms
  32GB             23.35 ms   0.27 ms

Truncating 30000 pages with 8GB, which is below the scan threshold of
32768 blocks:

  background load      master     patched
  none                  7.24 ms   2.72 ms
  32 clients, -S        9.16 ms   4.06 ms
  8 clients, TPC-B      8.66 ms   3.49 ms

Above the threshold both sides do the same full scan. With 2GB and 30000
pages, where the threshold is 8192 blocks, both took about 4.6 ms.

Background throughput was the same on both sides in every run.

Thanks,
Shihao

Attachments:

  [application/octet-stream] v1-0001-Let-smgrtruncate-pass-the-known-fork-sizes-to-Dro.patch (6.9K, ../../CAGRkXqRcNOrciQy=8sAYF=8Dsin2tYNpnUwe6V5JM+vXKeUHeA@mail.gmail.com/3-v1-0001-Let-smgrtruncate-pass-the-known-fork-sizes-to-Dro.patch)
  download | inline diff:
From 5227f71f94fd28867ad52499c57ea3d875fcbf07 Mon Sep 17 00:00:00 2001
From: Zhong ShiHao <zhong950419@gmail.com>
Date: Wed, 16 Sep 2026 19:55:23 -0400
Subject: [PATCH v1] Let smgrtruncate() pass the known fork sizes to
 DropRelationBuffers()

DropRelationBuffers() can avoid scanning the whole buffer pool when it
knows the size of every fork, but it took that size from
smgrnblocks_cached(), which returns a value only during recovery.  So on
a primary the targeted path was never used, and every truncation, most
often the one done by vacuum, scanned the entire buffer pool while
holding AccessExclusiveLock, no matter how few pages it removed.

smgrtruncate() already receives the current fork sizes from its callers
as old_nblocks, because it runs in a critical section and cannot measure
them itself.  Pass those sizes on to DropRelationBuffers().

This is safe because nothing can extend the relation between the
measurement and the buffer drop.  Outside recovery the caller holds
AccessExclusiveLock, as smgrtruncate() already requires, and during
recovery only the startup process extends relations.  During recovery
the supplied sizes are the same values the smgr cache would have given,
so behavior there does not change.

Also add an assertion to RelationTruncate() that the caller holds
AccessExclusiveLock, since the buffer drop now depends on it.
---
 src/backend/catalog/storage.c       |  7 ++++++
 src/backend/storage/buffer/bufmgr.c | 38 ++++++++++++++++++++++++-----
 src/backend/storage/smgr/smgr.c     |  2 +-
 src/include/storage/bufmgr.h        |  3 ++-
 4 files changed, 42 insertions(+), 8 deletions(-)

diff --git a/src/backend/catalog/storage.c b/src/backend/catalog/storage.c
index e443a4993c5..d037184334c 100644
--- a/src/backend/catalog/storage.c
+++ b/src/backend/catalog/storage.c
@@ -30,6 +30,7 @@
 #include "pgstat.h"
 #include "storage/bulk_write.h"
 #include "storage/freespace.h"
+#include "storage/lmgr.h"
 #include "storage/proc.h"
 #include "storage/smgr.h"
 #include "utils/hsearch.h"
@@ -297,6 +298,12 @@ RelationTruncate(Relation rel, BlockNumber nblocks)
 	int			nforks = 0;
 	SMgrRelation reln;
 
+	/*
+	 * DropRelationBuffers() relies on the fork sizes we measure below staying
+	 * valid until the buffers are dropped, which needs this lock.
+	 */
+	Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false));
+
 	/*
 	 * Make sure smgr_targblock etc aren't pointing somewhere past new end.
 	 * (Note: don't rely on this reln pointer below this loop.)
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 5c82865a084..91a3965b776 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -4782,11 +4782,17 @@ BufferGetLSNAtomic(Buffer buffer)
  *		later.  It is also the responsibility of higher-level code to ensure
  *		that no other process could be trying to load more pages of the
  *		relation into buffers.
+ *
+ *		If nForkBlocks is not NULL, it gives the current size of each fork,
+ *		and the caller must make sure that no fork can grow before we are
+ *		done.  If it is NULL, the sizes are taken from the smgr cache.  If
+ *		the size of any fork is unknown, the whole buffer pool is scanned.
  * --------------------------------------------------------------------
  */
 void
 DropRelationBuffers(SMgrRelation smgr_reln, ForkNumber *forkNum,
-					int nforks, BlockNumber *firstDelBlock)
+					int nforks, BlockNumber *nForkBlocks,
+					BlockNumber *firstDelBlock)
 {
 	int			i;
 	int			j;
@@ -4815,10 +4821,27 @@ DropRelationBuffers(SMgrRelation smgr_reln, ForkNumber *forkNum,
 	 * otherwise the background writer or checkpointer can lead to a PANIC
 	 * error while flushing buffers corresponding to files that don't exist.
 	 *
-	 * To know the exact size, we rely on the size cached for each fork by us
-	 * during recovery which limits the optimization to recovery and on
-	 * standbys but we can easily extend it once we have shared cache for
-	 * relation size.
+	 * A size that is too large would only cost some extra lookups, but a size
+	 * that is too small would leave buffers behind.
+	 *
+	 * If the caller supplied the sizes, use them.  smgrtruncate() does so,
+	 * after measuring the forks just before calling us.  Nothing can extend
+	 * the relation in between.  Outside recovery the caller holds
+	 * AccessExclusiveLock, and during recovery only the startup process
+	 * extends relations.  During recovery the supplied sizes are the same
+	 * values that the smgr cache would give us.
+	 *
+	 * Buffers can still exist beyond the measured size if an earlier attempt
+	 * to extend the relation failed, see ExtendBufferedRelShared().  Those
+	 * buffers are neither valid nor dirty, so nobody will try to write them,
+	 * and it is fine to leave them for the next extension to reuse.  Reading
+	 * past the end of the file with zero_damaged_pages can leave a valid but
+	 * clean buffer there too, but that setting is only meant for recovering
+	 * from corruption.
+	 *
+	 * Otherwise we fall back on the size cached for each fork, which is only
+	 * trustworthy during recovery, so the optimization is limited to recovery
+	 * and standbys.
 	 *
 	 * In recovery, we cache the value returned by the first lseek(SEEK_END)
 	 * and the future writes keeps the cached value up-to-date. See
@@ -4831,7 +4854,10 @@ DropRelationBuffers(SMgrRelation smgr_reln, ForkNumber *forkNum,
 	for (i = 0; i < nforks; i++)
 	{
 		/* Get the number of blocks for a relation's fork */
-		nForkBlock[i] = smgrnblocks_cached(smgr_reln, forkNum[i]);
+		if (nForkBlocks != NULL)
+			nForkBlock[i] = nForkBlocks[i];
+		else
+			nForkBlock[i] = smgrnblocks_cached(smgr_reln, forkNum[i]);
 
 		if (nForkBlock[i] == InvalidBlockNumber)
 		{
diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c
index 5391640d861..d563dfc6f21 100644
--- a/src/backend/storage/smgr/smgr.c
+++ b/src/backend/storage/smgr/smgr.c
@@ -881,7 +881,7 @@ smgrtruncate(SMgrRelation reln, ForkNumber *forknum, int nforks,
 	 * Get rid of any buffers for the about-to-be-deleted blocks. bufmgr will
 	 * just drop them without bothering to write the contents.
 	 */
-	DropRelationBuffers(reln, forknum, nforks, nblocks);
+	DropRelationBuffers(reln, forknum, nforks, old_nblocks, nblocks);
 
 	/*
 	 * Send a shared-inval message to force other backends to close any smgr
diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h
index 6837b35fc6d..76433fda5d2 100644
--- a/src/include/storage/bufmgr.h
+++ b/src/include/storage/bufmgr.h
@@ -301,7 +301,8 @@ extern void CreateAndCopyRelationData(RelFileLocator src_rlocator,
 extern void FlushDatabaseBuffers(Oid dbid);
 extern void DropRelationBuffers(SMgrRelation smgr_reln,
 								ForkNumber *forkNum,
-								int nforks, BlockNumber *firstDelBlock);
+								int nforks, BlockNumber *nForkBlocks,
+								BlockNumber *firstDelBlock);
 extern void DropRelationsAllBuffers(SMgrRelation *smgr_reln,
 									int nlocators);
 extern void DropDatabaseBuffers(Oid dbid);
-- 
2.37.1 (Apple Git-137.1)



^ permalink  raw  reply  [nested|flat] 5+ messages in thread


end of thread, other threads:[~2026-09-17 02:44 UTC | newest]

Thread overview: 5+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2025-03-18 06:03 Optimize truncation logic to reduce AccessExclusive lock impact Stepan Neretin <slpmcf@gmail.com>
2025-03-19 02:09 ` David Rowley <dgrowleyml@gmail.com>
2025-03-19 16:05   ` Yura Sokolov <y.sokolov@postgrespro.ru>
2025-03-21 11:50     ` Yura Sokolov <y.sokolov@postgrespro.ru>
2026-09-17 02:44       ` shihao zhong <zhong950419@gmail.com>

This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox