v10-0001-Autoprewarm-global-objects-separately.patch

text/x-patch

Filename: v10-0001-Autoprewarm-global-objects-separately.patch
Type: text/x-patch
Part: 1
Message: Re: Using read stream in autoprewarm

Patch

Format: format-patch
Series: patch v10-0001
Subject: Autoprewarm global objects separately
File+
contrib/pg_prewarm/autoprewarm.c 22 29
From a945fd408a6c3e073394df5332790a6a0fcf5efe Mon Sep 17 00:00:00 2001
From: Melanie Plageman <melanieplageman@gmail.com>
Date: Wed, 2 Apr 2025 09:52:54 -0400
Subject: [PATCH v10 1/3] Autoprewarm global objects separately

Autoprewarm previously prewarmed global objects while prewarming blocks
from objects from the first valid database it encountered. This was
because you can't read in buffers without being connected to a database.

Prewarming global objects and objects from a single database in the
autoprewarm_database_main() function required a special case. Once we
convert autoprewarm to use a read stream, this special case will have to
be duplicated in multiple places.

Instead, modify apw_load_buffers() to prewarm the shared objects in one
invocation of autoprewarm_database_main() while connected to the first
valid database.

It is a bit fiddly but seems better than the alternative.

Reviewed-by: Nazir Bilal Yavuz <byavuz81@gmail.com>
Discussion: https://postgr.es/m/CAN55FZ0TBBmrJ2vtMQ9rEk-NTL2BWQzavVp%3DiRLOUskm%2BzvNNw%40mail.gmail.com
---
 contrib/pg_prewarm/autoprewarm.c | 51 ++++++++++++++------------------
 1 file changed, 22 insertions(+), 29 deletions(-)

diff --git a/contrib/pg_prewarm/autoprewarm.c b/contrib/pg_prewarm/autoprewarm.c
index 73485a2323c..172654fee25 100644
--- a/contrib/pg_prewarm/autoprewarm.c
+++ b/contrib/pg_prewarm/autoprewarm.c
@@ -347,44 +347,41 @@ apw_load_buffers(void)
 	apw_state->prewarm_start_idx = apw_state->prewarm_stop_idx = 0;
 	apw_state->prewarmed_blocks = 0;
 
-	/* Get the info position of the first block of the next database. */
+	/*
+	 * Loop through the records and launch a database worker to process
+	 * objects in each database. We'll stop at the boundary of each new
+	 * database and prewarm those blocks before moving to the next.
+	 */
 	while (apw_state->prewarm_start_idx < num_elements)
 	{
 		int			j = apw_state->prewarm_start_idx;
 		Oid			current_db = blkinfo[j].database;
 
 		/*
-		 * Advance the prewarm_stop_idx to the first BlockInfoRecord that does
-		 * not belong to this database.
+		 * Advance the position to the first BlockInfoRecord that does not
+		 * belong to the current database.
 		 */
-		j++;
-		while (j < num_elements)
+		for (; j < num_elements; j++)
 		{
-			if (current_db != blkinfo[j].database)
-			{
-				/*
-				 * Combine BlockInfoRecords for global objects with those of
-				 * the database.
-				 */
-				if (current_db != InvalidOid)
-					break;
-				current_db = blkinfo[j].database;
-			}
-
-			j++;
+			if (blkinfo[j].database != current_db)
+				break;
 		}
 
 		/*
-		 * If we reach this point with current_db == InvalidOid, then only
-		 * BlockInfoRecords belonging to global objects exist.  We can't
-		 * prewarm without a database connection, so just bail out.
+		 * We can't prewarm without a database connection, so if all of the
+		 * records belong to global objects, we have to bail out.
 		 */
-		if (current_db == InvalidOid)
+		if (current_db == InvalidOid && blkinfo[j].database == InvalidOid)
 			break;
 
+		/* Connect to the first valid db to prewarm global objects. */
+		if (current_db == InvalidOid)
+			current_db = blkinfo[j].database;
+
 		/* Configure stop point and database for next per-database worker. */
 		apw_state->prewarm_stop_idx = j;
 		apw_state->database = current_db;
+
 		Assert(apw_state->prewarm_start_idx < apw_state->prewarm_stop_idx);
 
 		/* If we've run out of free buffers, don't launch another worker. */
@@ -423,8 +420,8 @@ apw_load_buffers(void)
 }
 
 /*
- * Prewarm all blocks for one database (and possibly also global objects, if
- * those got grouped with this database).
+ * Prewarm all blocks for one database or global objects (while connected to a
+ * valid database).
  */
 void
 autoprewarm_database_main(Datum main_arg)
@@ -462,12 +459,8 @@ autoprewarm_database_main(Datum main_arg)
 
 		CHECK_FOR_INTERRUPTS();
 
-		/*
-		 * Quit if we've reached records for another database. If previous
-		 * blocks are of some global objects, then continue pre-warming.
-		 */
-		if (old_blk != NULL && old_blk->database != blk->database &&
-			old_blk->database != 0)
+		/* Quit if we've reached records for another database. */
+		if (old_blk != NULL && old_blk->database != blk->database)
 			break;
 
 		/*
-- 
2.34.1