SLRU_PAGES_PER_SEGMENT as configure parameter

Started by Daniil Davydov11 months ago4 messages
#1Daniil Davydov
3danissimo@gmail.com
1 attachment(s)

Hi,
The constant SLRU_PAGES_PER_SEGMENT defines the size of the SLRU
segments. It is currently hardcoded in slru.h. It would be nice to be
able to set this parameter during configuration (for example, by
analogy with --with-segsize-blocks).
What will it give us:
1) The ability to test pg_upgrade more extensively, since without it
you need to generate too much data to fill a significant number of
segments.
2) The number of segments is arbitrary: 32. However, I have not heard
about any estimates in terms of performance; with such a patch (for
REL_17_STABLE), it will be realistic to do this.

--
Best regards,
Daniil Davydov

Attachments:

0001-SLRU_PAGES_PER_SEGMENT-as-configure-parameter.patchtext/x-patch; charset=US-ASCII; name=0001-SLRU_PAGES_PER_SEGMENT-as-configure-parameter.patchDownload
From d962b1a9b5e2852706e256abbb6d9ca5155842a7 Mon Sep 17 00:00:00 2001
From: Daniil Davidov <d.davydov@postgrespro.ru>
Date: Thu, 6 Feb 2025 14:34:36 +0700
Subject: [PATCH] SLRU_PAGES_PER_SEGMENT as configure parameter

---
 configure                                     |  52 ++++++++
 src/backend/utils/misc/guc_tables.c           |  12 ++
 src/include/access/slru.h                     |  15 ---
 src/include/pg_config.h.in                    |  13 ++
 .../modules/test_slru/expected/test_slru.out  | 123 ++++++++++--------
 src/test/modules/test_slru/sql/test_slru.sql  | 122 +++++++++++------
 src/test/modules/test_slru/test_slru.c        |   6 -
 7 files changed, 228 insertions(+), 115 deletions(-)

diff --git a/configure b/configure
index 97996b7f6b..514418e589 100755
--- a/configure
+++ b/configure
@@ -845,6 +845,7 @@ enable_dtrace
 enable_tap_tests
 enable_injection_points
 with_blocksize
+with_slru_pps
 with_segsize
 with_segsize_blocks
 with_wal_blocksize
@@ -1559,6 +1560,7 @@ Optional Packages:
                           set table segment size in blocks [0]
   --with-wal-blocksize=BLOCKSIZE
                           set WAL block size in kB [8]
+  --with-slru-pps=SLRUPPS set slru segment size in blocks
   --with-llvm             build with LLVM based JIT support
   --without-icu           build without ICU support
   --with-tcl              build Tcl modules (PL/Tcl)
@@ -3762,6 +3764,56 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
+#
+# SLRU pages per segment
+#
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for slru pages per segment" >&5
+$as_echo_n "checking for slru pages per segment... " >&6; }
+
+
+
+# Check whether --with-slru-pps was given.
+if test "${with_slru_pps+set}" = set; then :
+  withval=$with_slru_pps;
+  case $withval in
+    yes)
+      as_fn_error $? "argument required for --with_slru_pps option" "$LINENO" 5
+      ;;
+    no)
+      as_fn_error $? "argument required for --with_slru_pps option" "$LINENO" 5
+      ;;
+    *)
+      slru_pages_per_segment=$withval
+      ;;
+  esac
+
+else
+  slru_pages_per_segment=32
+fi
+
+
+INT_MAX=2147483647
+if test "${slru_pages_per_segment}" -lt 32; then
+	as_fn_error $? "Invalid slru_pps value. It cannot be less, then 32." "$LINENO" 5
+	exit 1
+elif test "${slru_pages_per_segment}" -gt "${INT_MAX}"; then
+	as_fn_error $? "Invalid slru_pps value. It cannot be greater, then INT_MAX." "$LINENO" 5
+	exit 1
+elif test $((${slru_pages_per_segment} % 2)) -ne 0; then
+	as_fn_error $? "Invalid slru_pps value. It must be a power of 2." "$LINENO" 5
+  exit 1
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${slru_pages_per_segment}" >&5
+$as_echo "${slru_pages_per_segment}" >&6; }
+
+
+cat >>confdefs.h <<_ACEOF
+#define SLRU_PAGES_PER_SEGMENT ${slru_pages_per_segment}
+_ACEOF
+
+
+
+
 #
 # Relation segment size
 #
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index c42fccf3fe..bf1aa3a56c 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -596,6 +596,7 @@ static int	max_function_args;
 static int	max_index_keys;
 static int	max_identifier_length;
 static int	block_size;
+static int	slru_pages_per_segment;
 static int	segment_size;
 static int	shared_memory_size_mb;
 static int	shared_memory_size_in_huge_pages;
@@ -3266,6 +3267,17 @@ struct config_int ConfigureNamesInt[] =
 		NULL, NULL, NULL
 	},
 
+	{
+		{"slru_pps", PGC_INTERNAL, PRESET_OPTIONS,
+			gettext_noop("Shows the number of slru pages per segment."),
+			NULL,
+			GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
+		},
+		&slru_pages_per_segment,
+		SLRU_PAGES_PER_SEGMENT, SLRU_PAGES_PER_SEGMENT, SLRU_PAGES_PER_SEGMENT,
+		NULL, NULL, NULL
+	},
+
 	{
 		{"segment_size", PGC_INTERNAL, PRESET_OPTIONS,
 			gettext_noop("Shows the number of pages per disk file."),
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index 02fcb3bca5..c75fc215d1 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -23,21 +23,6 @@
  */
 #define SLRU_MAX_ALLOWED_BUFFERS ((1024 * 1024 * 1024) / BLCKSZ)
 
-/*
- * Define SLRU segment size.  A page is the same BLCKSZ as is used everywhere
- * else in Postgres.  The segment size can be chosen somewhat arbitrarily;
- * we make it 32 pages by default, or 256Kb, i.e. 1M transactions for CLOG
- * or 64K transactions for SUBTRANS.
- *
- * Note: because TransactionIds are 32 bits and wrap around at 0xFFFFFFFF,
- * page numbering also wraps around at 0xFFFFFFFF/xxxx_XACTS_PER_PAGE (where
- * xxxx is CLOG or SUBTRANS, respectively), and segment numbering at
- * 0xFFFFFFFF/xxxx_XACTS_PER_PAGE/SLRU_PAGES_PER_SEGMENT.  We need
- * take no explicit notice of that fact in slru.c, except when comparing
- * segment and page numbers in SimpleLruTruncate (see PagePrecedes()).
- */
-#define SLRU_PAGES_PER_SEGMENT	32
-
 /*
  * Page status codes.  Note that these do not include the "dirty" bit.
  * page_dirty can be true only in the VALID or WRITE_IN_PROGRESS states;
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 2397d90b46..54f5d366fd 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -30,6 +30,19 @@
    Changing BLCKSZ requires an initdb. */
 #undef BLCKSZ
 
+/* SLRU segment size. A page is the same BLCKSZ as is used everywhere
+ * else in Postgres.  The segment size can be chosen somewhat arbitrarily;
+ * we make it 32 pages by default, or 256Kb, i.e. 1M transactions for CLOG
+ * or 64K transactions for SUBTRANS.
+ *
+ * Note: because TransactionIds are 32 bits and wrap around at 0xFFFFFFFF,
+ * page numbering also wraps around at 0xFFFFFFFF/xxxx_XACTS_PER_PAGE (where
+ * xxxx is CLOG or SUBTRANS, respectively), and segment numbering at
+ * 0xFFFFFFFF/xxxx_XACTS_PER_PAGE/SLRU_PAGES_PER_SEGMENT.  We need
+ * take no explicit notice of that fact in slru.c, except when comparing
+ * segment and page numbers in SimpleLruTruncate (see PagePrecedes()). */
+#undef SLRU_PAGES_PER_SEGMENT
+
 /* Saved arguments from configure */
 #undef CONFIGURE_ARGS
 
diff --git a/src/test/modules/test_slru/expected/test_slru.out b/src/test/modules/test_slru/expected/test_slru.out
index 185c56e5d6..1184db276d 100644
--- a/src/test/modules/test_slru/expected/test_slru.out
+++ b/src/test/modules/test_slru/expected/test_slru.out
@@ -1,52 +1,62 @@
 CREATE EXTENSION test_slru;
-SELECT test_slru_page_exists(12345);
+-- how many pages can fit on one slru segment
+SELECT current_setting('slru_pps')::INT AS slru_pps \gset
+SELECT (:slru_pps * 6.8125) AS pageno \gset
+-- count from zero
+SELECT (:pageno + (:slru_pps * 1.5) - 1) AS pageno_max \gset
+SELECT (:pageno_max - (:slru_pps / 2)) AS pageno_middle \gset
+-- non existed page
+SELECT test_slru_page_exists(:pageno::BIGINT);
  test_slru_page_exists 
 -----------------------
  f
 (1 row)
 
-SELECT test_slru_page_write(12345, 'Test SLRU');
+SELECT test_slru_page_write(:pageno::BIGINT, 'Test SLRU');
  test_slru_page_write 
 ----------------------
  
 (1 row)
 
-SELECT test_slru_page_read(12345);
+SELECT test_slru_page_read(:pageno::BIGINT);
  test_slru_page_read 
 ---------------------
  Test SLRU
 (1 row)
 
-SELECT test_slru_page_exists(12345);
+SELECT test_slru_page_exists(:pageno::BIGINT);
  test_slru_page_exists 
 -----------------------
  t
 (1 row)
 
--- 48 extra pages
-SELECT count(test_slru_page_write(a, 'Test SLRU'))
-  FROM generate_series(12346, 12393, 1) as a;
- count 
--------
-    48
-(1 row)
-
+-- Generate extra pages. Redirect output into table because number of funciton
+-- calls depends on the current value of slru_pps parameter.
+CREATE TABLE slru_write_results (
+		pageno BIGINT,
+		write_count INTEGER
+);
+INSERT INTO slru_write_results (pageno, write_count)
+SELECT a, count(test_slru_page_write(a::BIGINT, 'Test SLRU'))
+FROM generate_series(:pageno, :pageno_max, 1) AS a
+GROUP BY a;
+DROP TABLE slru_write_results;
 -- Reading page in buffer for read and write
-SELECT test_slru_page_read(12377, true);
+SELECT test_slru_page_read(:pageno_middle::BIGINT, true);
  test_slru_page_read 
 ---------------------
  Test SLRU
 (1 row)
 
 -- Reading page in buffer for read-only
-SELECT test_slru_page_readonly(12377);
+SELECT test_slru_page_readonly(:pageno_middle::BIGINT);
  test_slru_page_readonly 
 -------------------------
  Test SLRU
 (1 row)
 
 -- Reading page not in buffer with read-only
-SELECT test_slru_page_readonly(12346);
+SELECT test_slru_page_readonly(:pageno::BIGINT);
  test_slru_page_readonly 
 -------------------------
  Test SLRU
@@ -60,47 +70,45 @@ SELECT test_slru_page_writeall();
 (1 row)
 
 -- Flush the last page written out.
-SELECT test_slru_page_sync(12393);
-NOTICE:  Called SlruSyncFileTag() for segment 387 on path pg_test_slru/000000000000183
+SELECT test_slru_page_sync(:pageno_max::BIGINT);
  test_slru_page_sync 
 ---------------------
  
 (1 row)
 
-SELECT test_slru_page_exists(12393);
+SELECT test_slru_page_exists(:pageno_max::BIGINT);
  test_slru_page_exists 
 -----------------------
  t
 (1 row)
 
 -- Segment deletion
-SELECT test_slru_page_delete(12393);
-NOTICE:  Called SlruDeleteSegment() for segment 387
+SELECT test_slru_page_delete(:pageno_max::BIGINT);
  test_slru_page_delete 
 -----------------------
  
 (1 row)
 
-SELECT test_slru_page_exists(12393);
+SELECT test_slru_page_exists(:pageno_max::BIGINT);
  test_slru_page_exists 
 -----------------------
  f
 (1 row)
 
 -- Page truncation
-SELECT test_slru_page_exists(12377);
+SELECT test_slru_page_exists(:pageno_middle::BIGINT);
  test_slru_page_exists 
 -----------------------
  t
 (1 row)
 
-SELECT test_slru_page_truncate(12377);
+SELECT test_slru_page_truncate(:pageno_middle::BIGINT);
  test_slru_page_truncate 
 -------------------------
  
 (1 row)
 
-SELECT test_slru_page_exists(12377);
+SELECT test_slru_page_exists(:pageno_middle::BIGINT);
  test_slru_page_exists 
 -----------------------
  t
@@ -114,19 +122,19 @@ NOTICE:  Calling test_slru_scan_cb()
  
 (1 row)
 
-SELECT test_slru_page_exists(12345);
+SELECT test_slru_page_exists(:pageno::BIGINT);
  test_slru_page_exists 
 -----------------------
  f
 (1 row)
 
-SELECT test_slru_page_exists(12377);
+SELECT test_slru_page_exists(:pageno_middle::BIGINT);
  test_slru_page_exists 
 -----------------------
  f
 (1 row)
 
-SELECT test_slru_page_exists(12393);
+SELECT test_slru_page_exists(:pageno_max::BIGINT);
  test_slru_page_exists 
 -----------------------
  f
@@ -135,54 +143,63 @@ SELECT test_slru_page_exists(12393);
 --
 -- Test 64-bit pages
 --
-SELECT test_slru_page_exists(0x1234500000000);
+\set no_such_page	0x1234500000000
+-- second page in SLRU segments
+\set pageno			0x1234500000001
+-- count from zero
+SELECT (:no_such_page + (:slru_pps * 1.5)) AS pageno_max \gset
+SELECT (:pageno_max - (:slru_pps / 2)) AS pageno_middle \gset
+SELECT test_slru_page_exists(:no_such_page);
  test_slru_page_exists 
 -----------------------
  f
 (1 row)
 
-SELECT test_slru_page_write(0x1234500000000, 'Test SLRU 64-bit');
+SELECT test_slru_page_write(:no_such_page, 'Test SLRU 64-bit');
  test_slru_page_write 
 ----------------------
  
 (1 row)
 
-SELECT test_slru_page_read(0x1234500000000);
+SELECT test_slru_page_read(:no_such_page);
  test_slru_page_read 
 ---------------------
  Test SLRU 64-bit
 (1 row)
 
-SELECT test_slru_page_exists(0x1234500000000);
+SELECT test_slru_page_exists(:no_such_page);
  test_slru_page_exists 
 -----------------------
  t
 (1 row)
 
--- 48 extra pages
-SELECT count(test_slru_page_write(a, 'Test SLRU 64-bit'))
-  FROM generate_series(0x1234500000001, 0x1234500000030, 1) as a;
- count 
--------
-    48
-(1 row)
-
+-- Generate extra pages. Redirect output into table because number of funciton
+-- calls depends on the current value of slru_pps parameter.
+CREATE TABLE slru_write_results (
+		pageno BIGINT,
+		write_count INTEGER
+);
+INSERT INTO slru_write_results (pageno, write_count)
+SELECT a, count(test_slru_page_write(a::BIGINT, 'Test SLRU 64-bit'))
+FROM generate_series(:pageno, :pageno_max, 1) AS a
+GROUP BY a;
+DROP TABLE slru_write_results;
 -- Reading page in buffer for read and write
-SELECT test_slru_page_read(0x1234500000020, true);
+SELECT test_slru_page_read(:pageno_middle::BIGINT, true);
  test_slru_page_read 
 ---------------------
  Test SLRU 64-bit
 (1 row)
 
 -- Reading page in buffer for read-only
-SELECT test_slru_page_readonly(0x1234500000020);
+SELECT test_slru_page_readonly(:pageno_middle::BIGINT);
  test_slru_page_readonly 
 -------------------------
  Test SLRU 64-bit
 (1 row)
 
 -- Reading page not in buffer with read-only
-SELECT test_slru_page_readonly(0x1234500000001);
+SELECT test_slru_page_readonly(:pageno);
  test_slru_page_readonly 
 -------------------------
  Test SLRU 64-bit
@@ -196,47 +213,45 @@ SELECT test_slru_page_writeall();
 (1 row)
 
 -- Flush the last page written out.
-SELECT test_slru_page_sync(0x1234500000030);
-NOTICE:  Called SlruSyncFileTag() for segment 10007944888321 on path pg_test_slru/000091A28000001
+SELECT test_slru_page_sync(:pageno_max::BIGINT);
  test_slru_page_sync 
 ---------------------
  
 (1 row)
 
-SELECT test_slru_page_exists(0x1234500000030);
+SELECT test_slru_page_exists(:pageno_max::BIGINT);
  test_slru_page_exists 
 -----------------------
  t
 (1 row)
 
 -- Segment deletion
-SELECT test_slru_page_delete(0x1234500000030);
-NOTICE:  Called SlruDeleteSegment() for segment 10007944888321
+SELECT test_slru_page_delete(:pageno_max::BIGINT);
  test_slru_page_delete 
 -----------------------
  
 (1 row)
 
-SELECT test_slru_page_exists(0x1234500000030);
+SELECT test_slru_page_exists(:pageno_max::BIGINT);
  test_slru_page_exists 
 -----------------------
  f
 (1 row)
 
 -- Page truncation
-SELECT test_slru_page_exists(0x1234500000020);
+SELECT test_slru_page_exists(:pageno_middle::BIGINT);
  test_slru_page_exists 
 -----------------------
  f
 (1 row)
 
-SELECT test_slru_page_truncate(0x1234500000020);
+SELECT test_slru_page_truncate(:pageno_middle::BIGINT);
  test_slru_page_truncate 
 -------------------------
  
 (1 row)
 
-SELECT test_slru_page_exists(0x1234500000020);
+SELECT test_slru_page_exists(:pageno_middle::BIGINT);
  test_slru_page_exists 
 -----------------------
  f
@@ -249,19 +264,19 @@ SELECT test_slru_delete_all();
  
 (1 row)
 
-SELECT test_slru_page_exists(0x1234500000000);
+SELECT test_slru_page_exists(:no_such_page);
  test_slru_page_exists 
 -----------------------
  f
 (1 row)
 
-SELECT test_slru_page_exists(0x1234500000020);
+SELECT test_slru_page_exists(:pageno_middle::BIGINT);
  test_slru_page_exists 
 -----------------------
  f
 (1 row)
 
-SELECT test_slru_page_exists(0x1234500000030);
+SELECT test_slru_page_exists(:pageno_max::BIGINT);
  test_slru_page_exists 
 -----------------------
  f
diff --git a/src/test/modules/test_slru/sql/test_slru.sql b/src/test/modules/test_slru/sql/test_slru.sql
index b1b376581a..ee6bd32353 100644
--- a/src/test/modules/test_slru/sql/test_slru.sql
+++ b/src/test/modules/test_slru/sql/test_slru.sql
@@ -1,76 +1,118 @@
 CREATE EXTENSION test_slru;
 
-SELECT test_slru_page_exists(12345);
-SELECT test_slru_page_write(12345, 'Test SLRU');
-SELECT test_slru_page_read(12345);
-SELECT test_slru_page_exists(12345);
+-- how many pages can fit on one slru segment
+SELECT current_setting('slru_pps')::INT AS slru_pps \gset
 
--- 48 extra pages
-SELECT count(test_slru_page_write(a, 'Test SLRU'))
-  FROM generate_series(12346, 12393, 1) as a;
+SELECT (:slru_pps * 6.8125) AS pageno \gset
+
+-- count from zero
+SELECT (:pageno + (:slru_pps * 1.5) - 1) AS pageno_max \gset
+
+SELECT (:pageno_max - (:slru_pps / 2)) AS pageno_middle \gset
+
+-- non existed page
+SELECT test_slru_page_exists(:pageno::BIGINT);
+SELECT test_slru_page_write(:pageno::BIGINT, 'Test SLRU');
+SELECT test_slru_page_read(:pageno::BIGINT);
+SELECT test_slru_page_exists(:pageno::BIGINT);
+
+-- Generate extra pages. Redirect output into table because number of funciton
+-- calls depends on the current value of slru_pps parameter.
+
+CREATE TABLE slru_write_results (
+		pageno BIGINT,
+		write_count INTEGER
+);
+
+INSERT INTO slru_write_results (pageno, write_count)
+SELECT a, count(test_slru_page_write(a::BIGINT, 'Test SLRU'))
+FROM generate_series(:pageno, :pageno_max, 1) AS a
+GROUP BY a;
+
+DROP TABLE slru_write_results;
 
 -- Reading page in buffer for read and write
-SELECT test_slru_page_read(12377, true);
+SELECT test_slru_page_read(:pageno_middle::BIGINT, true);
 -- Reading page in buffer for read-only
-SELECT test_slru_page_readonly(12377);
+SELECT test_slru_page_readonly(:pageno_middle::BIGINT);
 -- Reading page not in buffer with read-only
-SELECT test_slru_page_readonly(12346);
+SELECT test_slru_page_readonly(:pageno::BIGINT);
 
 -- Write all the pages in buffers
 SELECT test_slru_page_writeall();
 -- Flush the last page written out.
-SELECT test_slru_page_sync(12393);
-SELECT test_slru_page_exists(12393);
+SELECT test_slru_page_sync(:pageno_max::BIGINT);
+SELECT test_slru_page_exists(:pageno_max::BIGINT);
 -- Segment deletion
-SELECT test_slru_page_delete(12393);
-SELECT test_slru_page_exists(12393);
+SELECT test_slru_page_delete(:pageno_max::BIGINT);
+SELECT test_slru_page_exists(:pageno_max::BIGINT);
 -- Page truncation
-SELECT test_slru_page_exists(12377);
-SELECT test_slru_page_truncate(12377);
-SELECT test_slru_page_exists(12377);
+SELECT test_slru_page_exists(:pageno_middle::BIGINT);
+SELECT test_slru_page_truncate(:pageno_middle::BIGINT);
+SELECT test_slru_page_exists(:pageno_middle::BIGINT);
 
 -- Full deletion
 SELECT test_slru_delete_all();
-SELECT test_slru_page_exists(12345);
-SELECT test_slru_page_exists(12377);
-SELECT test_slru_page_exists(12393);
+SELECT test_slru_page_exists(:pageno::BIGINT);
+SELECT test_slru_page_exists(:pageno_middle::BIGINT);
+SELECT test_slru_page_exists(:pageno_max::BIGINT);
 
 --
 -- Test 64-bit pages
 --
-SELECT test_slru_page_exists(0x1234500000000);
-SELECT test_slru_page_write(0x1234500000000, 'Test SLRU 64-bit');
-SELECT test_slru_page_read(0x1234500000000);
-SELECT test_slru_page_exists(0x1234500000000);
+\set no_such_page	0x1234500000000
+-- second page in SLRU segments
+\set pageno			0x1234500000001
+
+-- count from zero
+SELECT (:no_such_page + (:slru_pps * 1.5)) AS pageno_max \gset
+
+SELECT (:pageno_max - (:slru_pps / 2)) AS pageno_middle \gset
+
+SELECT test_slru_page_exists(:no_such_page);
+SELECT test_slru_page_write(:no_such_page, 'Test SLRU 64-bit');
+SELECT test_slru_page_read(:no_such_page);
+SELECT test_slru_page_exists(:no_such_page);
+
+-- Generate extra pages. Redirect output into table because number of funciton
+-- calls depends on the current value of slru_pps parameter.
+
+CREATE TABLE slru_write_results (
+		pageno BIGINT,
+		write_count INTEGER
+);
+
+INSERT INTO slru_write_results (pageno, write_count)
+SELECT a, count(test_slru_page_write(a::BIGINT, 'Test SLRU 64-bit'))
+FROM generate_series(:pageno, :pageno_max, 1) AS a
+GROUP BY a;
 
--- 48 extra pages
-SELECT count(test_slru_page_write(a, 'Test SLRU 64-bit'))
-  FROM generate_series(0x1234500000001, 0x1234500000030, 1) as a;
+DROP TABLE slru_write_results;
 
 -- Reading page in buffer for read and write
-SELECT test_slru_page_read(0x1234500000020, true);
+SELECT test_slru_page_read(:pageno_middle::BIGINT, true);
 -- Reading page in buffer for read-only
-SELECT test_slru_page_readonly(0x1234500000020);
+SELECT test_slru_page_readonly(:pageno_middle::BIGINT);
 -- Reading page not in buffer with read-only
-SELECT test_slru_page_readonly(0x1234500000001);
+SELECT test_slru_page_readonly(:pageno);
 
 -- Write all the pages in buffers
 SELECT test_slru_page_writeall();
 -- Flush the last page written out.
-SELECT test_slru_page_sync(0x1234500000030);
-SELECT test_slru_page_exists(0x1234500000030);
+SELECT test_slru_page_sync(:pageno_max::BIGINT);
+SELECT test_slru_page_exists(:pageno_max::BIGINT);
 -- Segment deletion
-SELECT test_slru_page_delete(0x1234500000030);
-SELECT test_slru_page_exists(0x1234500000030);
+SELECT test_slru_page_delete(:pageno_max::BIGINT);
+SELECT test_slru_page_exists(:pageno_max::BIGINT);
 -- Page truncation
-SELECT test_slru_page_exists(0x1234500000020);
-SELECT test_slru_page_truncate(0x1234500000020);
-SELECT test_slru_page_exists(0x1234500000020);
+SELECT test_slru_page_exists(:pageno_middle::BIGINT);
+SELECT test_slru_page_truncate(:pageno_middle::BIGINT);
+SELECT test_slru_page_exists(:pageno_middle::BIGINT);
 
 -- Full deletion
 SELECT test_slru_delete_all();
-SELECT test_slru_page_exists(0x1234500000000);
-SELECT test_slru_page_exists(0x1234500000020);
-SELECT test_slru_page_exists(0x1234500000030);
+SELECT test_slru_page_exists(:no_such_page);
+SELECT test_slru_page_exists(:pageno_middle::BIGINT);
+SELECT test_slru_page_exists(:pageno_max::BIGINT);
 
 DROP EXTENSION test_slru;
diff --git a/src/test/modules/test_slru/test_slru.c b/src/test/modules/test_slru/test_slru.c
index d227b06703..7c55798dc8 100644
--- a/src/test/modules/test_slru/test_slru.c
+++ b/src/test/modules/test_slru/test_slru.c
@@ -151,9 +151,6 @@ test_slru_page_sync(PG_FUNCTION_ARGS)
 	ftag.segno = pageno / SLRU_PAGES_PER_SEGMENT;
 	SlruSyncFileTag(TestSlruCtl, &ftag, path);
 
-	elog(NOTICE, "Called SlruSyncFileTag() for segment %lld on path %s",
-		 (long long) ftag.segno, path);
-
 	PG_RETURN_VOID();
 }
 
@@ -166,9 +163,6 @@ test_slru_page_delete(PG_FUNCTION_ARGS)
 	ftag.segno = pageno / SLRU_PAGES_PER_SEGMENT;
 	SlruDeleteSegment(TestSlruCtl, ftag.segno);
 
-	elog(NOTICE, "Called SlruDeleteSegment() for segment %lld",
-		 (long long) ftag.segno);
-
 	PG_RETURN_VOID();
 }
 
-- 
2.43.0

#2Daniel Gustafsson
daniel@yesql.se
In reply to: Daniil Davydov (#1)
Re: SLRU_PAGES_PER_SEGMENT as configure parameter

On 6 Feb 2025, at 11:53, Daniil Davydov <3danissimo@gmail.com> wrote:

The constant SLRU_PAGES_PER_SEGMENT defines the size of the SLRU
segments. It is currently hardcoded in slru.h. It would be nice to be
able to set this parameter during configuration (for example, by
analogy with --with-segsize-blocks).

Not commenting on the gist of the patch, but the mechanics:

configure | 52 ++++++++

You should include the configure.ac changes and not just the generated code in
configure (which is fine to include for review, but the committer will
re-generate it regardless). Please also include the corresponding Meson change
to keep the buildsystems in sync.

--
Daniel Gustafsson

#3Daniil Davydov
3danissimo@gmail.com
In reply to: Daniel Gustafsson (#2)
1 attachment(s)
Re: SLRU_PAGES_PER_SEGMENT as configure parameter

On Thu, Feb 6, 2025 at 8:23 PM Daniel Gustafsson <daniel@yesql.se> wrote:

You should include the configure.ac changes and not just the generated code in
configure (which is fine to include for review, but the committer will
re-generate it regardless). Please also include the corresponding Meson change
to keep the buildsystems in sync.

Thank you for your comment. I'm applying a patch that also includes
configure.ac, meson_options.txt and meson.build changes.
It would also be interesting to know what you think about the idea of
allowing such a parameter to be configured.

--
Best regards,
Daniil Davydov

Attachments:

0002-SLRU_PAGES_PER_SEGMENT-as-configure-parameter.patchtext/x-patch; charset=US-ASCII; name=0002-SLRU_PAGES_PER_SEGMENT-as-configure-parameter.patchDownload
From 836d648297b8ede905115f4e823953ebfa273642 Mon Sep 17 00:00:00 2001
From: Daniil Davidov <d.davydov@postgrespro.ru>
Date: Thu, 6 Feb 2025 14:34:36 +0700
Subject: [PATCH] SLRU_PAGES_PER_SEGMENT as configure parameter

---
 configure                                     |  53 ++++++++
 configure.ac                                  |  36 +++++
 meson.build                                   |  17 +++
 meson_options.txt                             |   3 +
 src/backend/utils/misc/guc_tables.c           |  12 ++
 src/include/access/slru.h                     |  15 ---
 src/include/pg_config.h.in                    |  15 +++
 .../modules/test_slru/expected/test_slru.out  | 123 ++++++++++--------
 src/test/modules/test_slru/sql/test_slru.sql  | 122 +++++++++++------
 src/test/modules/test_slru/test_slru.c        |   6 -
 10 files changed, 287 insertions(+), 115 deletions(-)

diff --git a/configure b/configure
index 97996b7f6b..ff15660f5f 100755
--- a/configure
+++ b/configure
@@ -845,6 +845,7 @@ enable_dtrace
 enable_tap_tests
 enable_injection_points
 with_blocksize
+with_slru_pps
 with_segsize
 with_segsize_blocks
 with_wal_blocksize
@@ -1554,6 +1555,7 @@ Optional Packages:
   --with-pgport=PORTNUM   set default port number [5432]
   --with-blocksize=BLOCKSIZE
                           set table block size in kB [8]
+  --with-slru-pps=SLRUPPS set slru segment size in blocks
   --with-segsize=SEGSIZE  set table segment size in GB [1]
   --with-segsize-blocks=SEGSIZE_BLOCKS
                           set table segment size in blocks [0]
@@ -3762,6 +3764,57 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
+#
+# SLRU pages per segment
+#
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for slru pages per segment" >&5
+$as_echo_n "checking for slru pages per segment... " >&6; }
+
+
+
+# Check whether --with-slru-pps was given.
+if test "${with_slru_pps+set}" = set; then :
+  withval=$with_slru_pps;
+  case $withval in
+    yes)
+      as_fn_error $? "argument required for --with-slru-pps option" "$LINENO" 5
+      ;;
+    no)
+      as_fn_error $? "argument required for --with-slru-pps option" "$LINENO" 5
+      ;;
+    *)
+      slru_pages_per_segment=$withval
+      ;;
+  esac
+
+else
+  slru_pages_per_segment=32
+fi
+
+
+
+INT_MAX=2147483647
+if test "${slru_pages_per_segment}" -lt 32; then :
+  as_fn_error $? "Invalid slru_pps value. It cannot be less than 32." "$LINENO" 5
+fi
+
+if test "${slru_pages_per_segment}" -gt "${INT_MAX}"; then :
+  as_fn_error $? "Invalid slru_pps value. It cannot be greater than INT_MAX." "$LINENO" 5
+fi
+
+if test $(expr ${slru_pages_per_segment} % 2) -ne 0; then :
+  as_fn_error $? "Invalid slru_pps value. It must be a power of 2." "$LINENO" 5
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${slru_pages_per_segment} pages" >&5
+$as_echo "${slru_pages_per_segment} pages" >&6; }
+
+
+cat >>confdefs.h <<_ACEOF
+#define SLRU_PAGES_PER_SEGMENT ${slru_pages_per_segment}
+_ACEOF
+
+
 #
 # Relation segment size
 #
diff --git a/configure.ac b/configure.ac
index 3c76c9ebc8..2fd0e331c0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -288,6 +288,42 @@ AC_DEFINE_UNQUOTED([BLCKSZ], ${BLCKSZ}, [
  Changing BLCKSZ requires an initdb.
 ])
 
+#
+# SLRU pages per segment
+#
+AC_MSG_CHECKING([for slru pages per segment])
+PGAC_ARG_REQ(with, slru-pps, [SLRUPPS], [set slru segment size in blocks],
+             [slru_pages_per_segment=$withval],
+             [slru_pages_per_segment=32])
+
+INT_MAX=2147483647
+AS_IF([test "${slru_pages_per_segment}" -lt 32],
+      [AC_MSG_ERROR([Invalid slru_pps value. It cannot be less than 32.])])
+
+AS_IF([test "${slru_pages_per_segment}" -gt "${INT_MAX}"],
+      [AC_MSG_ERROR([Invalid slru_pps value. It cannot be greater than INT_MAX.])])
+
+AS_IF([test $(expr ${slru_pages_per_segment} % 2) -ne 0],
+      [AC_MSG_ERROR([Invalid slru_pps value. It must be a power of 2.])])
+
+AC_MSG_RESULT([${slru_pages_per_segment} pages])
+
+AC_DEFINE_UNQUOTED([SLRU_PAGES_PER_SEGMENT], ${slru_pages_per_segment}, [
+  SLRU segment size in pages. A page is the same BLCKSZ as is used everywhere
+	else in Postgres.  The segment size can be chosen somewhat arbitrarily;
+	we make it 32 pages by default, or 256Kb, i.e. 1M transactions for CLOG
+	or 64K transactions for SUBTRANS.
+
+	Note: because TransactionIds are 32 bits and wrap around at 0xFFFFFFFF,
+	default page numbering also wraps around at 0xFFFFFFFF/xxxx_XACTS_PER_PAGE
+	(where xxxx is CLOG or SUBTRANS, respectively), and segment numbering at
+	0xFFFFFFFF/xxxx_XACTS_PER_PAGE/SLRU_PAGES_PER_SEGMENT.  We need
+	take no explicit notice of that fact in slru.c, except when comparing
+	segment and page numbers in SimpleLruTruncate (see PagePrecedes()).
+
+	Changing SLRU_PAGES_PER_SEGMENT requires an initdb.
+])
+
 #
 # Relation segment size
 #
diff --git a/meson.build b/meson.build
index ed9f4737d3..2506de52f1 100644
--- a/meson.build
+++ b/meson.build
@@ -430,6 +430,8 @@ cdata.set('USE_INJECTION_POINTS', get_option('injection_points') ? 1 : false)
 
 blocksize = get_option('blocksize').to_int() * 1024
 
+slru_pages_per_segment = get_option('slru_pps').to_int()
+
 if get_option('segsize_blocks') != 0
   if get_option('segsize') != 1
     warning('both segsize and segsize_blocks specified, segsize_blocks wins')
@@ -449,6 +451,21 @@ cdata.set('BLCKSZ', blocksize, description:
    lp_off and lp_len fields in ItemIdData (see include/storage/itemid.h).
    Changing BLCKSZ requires an initdb.''')
 
+cdata.set('SLRU_PAGES_PER_SEGMENT', slru_pages_per_segment, description:
+'''SLRU segment size in pages. A page is the same BLCKSZ as is used everywhere
+	 else in Postgres.  The segment size can be chosen somewhat arbitrarily;
+	 we make it 32 pages by default, or 256Kb, i.e. 1M transactions for CLOG
+	 or 64K transactions for SUBTRANS.
+
+	 Note: because TransactionIds are 32 bits and wrap around at 0xFFFFFFFF,
+	 default page numbering also wraps around at 0xFFFFFFFF/xxxx_XACTS_PER_PAGE
+	 (where xxxx is CLOG or SUBTRANS, respectively), and segment numbering at
+	 0xFFFFFFFF/xxxx_XACTS_PER_PAGE/SLRU_PAGES_PER_SEGMENT.  We need
+	 take no explicit notice of that fact in slru.c, except when comparing
+	 segment and page numbers in SimpleLruTruncate (see PagePrecedes()).
+
+	 Changing SLRU_PAGES_PER_SEGMENT requires an initdb.''')
+
 cdata.set('XLOG_BLCKSZ', get_option('wal_blocksize').to_int() * 1024)
 cdata.set('RELSEG_SIZE', segsize)
 cdata.set('DEF_PGPORT', get_option('pgport'))
diff --git a/meson_options.txt b/meson_options.txt
index 246cecf382..ca26aa526c 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -7,6 +7,9 @@ option('blocksize', type: 'combo',
   value: '8',
   description: 'Relation block size, in kilobytes')
 
+option('slru_pps', type: 'integer', value: 32,
+  description: 'SLRU segment size, in blocks')
+
 option('wal_blocksize', type: 'combo',
   choices: ['1', '2', '4', '8', '16', '32', '64'],
   value: '8',
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index c42fccf3fe..bf1aa3a56c 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -596,6 +596,7 @@ static int	max_function_args;
 static int	max_index_keys;
 static int	max_identifier_length;
 static int	block_size;
+static int	slru_pages_per_segment;
 static int	segment_size;
 static int	shared_memory_size_mb;
 static int	shared_memory_size_in_huge_pages;
@@ -3266,6 +3267,17 @@ struct config_int ConfigureNamesInt[] =
 		NULL, NULL, NULL
 	},
 
+	{
+		{"slru_pps", PGC_INTERNAL, PRESET_OPTIONS,
+			gettext_noop("Shows the number of slru pages per segment."),
+			NULL,
+			GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
+		},
+		&slru_pages_per_segment,
+		SLRU_PAGES_PER_SEGMENT, SLRU_PAGES_PER_SEGMENT, SLRU_PAGES_PER_SEGMENT,
+		NULL, NULL, NULL
+	},
+
 	{
 		{"segment_size", PGC_INTERNAL, PRESET_OPTIONS,
 			gettext_noop("Shows the number of pages per disk file."),
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index 02fcb3bca5..c75fc215d1 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -23,21 +23,6 @@
  */
 #define SLRU_MAX_ALLOWED_BUFFERS ((1024 * 1024 * 1024) / BLCKSZ)
 
-/*
- * Define SLRU segment size.  A page is the same BLCKSZ as is used everywhere
- * else in Postgres.  The segment size can be chosen somewhat arbitrarily;
- * we make it 32 pages by default, or 256Kb, i.e. 1M transactions for CLOG
- * or 64K transactions for SUBTRANS.
- *
- * Note: because TransactionIds are 32 bits and wrap around at 0xFFFFFFFF,
- * page numbering also wraps around at 0xFFFFFFFF/xxxx_XACTS_PER_PAGE (where
- * xxxx is CLOG or SUBTRANS, respectively), and segment numbering at
- * 0xFFFFFFFF/xxxx_XACTS_PER_PAGE/SLRU_PAGES_PER_SEGMENT.  We need
- * take no explicit notice of that fact in slru.c, except when comparing
- * segment and page numbers in SimpleLruTruncate (see PagePrecedes()).
- */
-#define SLRU_PAGES_PER_SEGMENT	32
-
 /*
  * Page status codes.  Note that these do not include the "dirty" bit.
  * page_dirty can be true only in the VALID or WRITE_IN_PROGRESS states;
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 2397d90b46..18e012a6b3 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -30,6 +30,21 @@
    Changing BLCKSZ requires an initdb. */
 #undef BLCKSZ
 
+/* SLRU segment size in pages. A page is the same BLCKSZ as is used everywhere
+	else in Postgres.  The segment size can be chosen somewhat arbitrarily;
+	we make it 32 pages by default, or 256Kb, i.e. 1M transactions for CLOG
+	or 64K transactions for SUBTRANS.
+
+	Note: because TransactionIds are 32 bits and wrap around at 0xFFFFFFFF,
+	default page numbering also wraps around at 0xFFFFFFFF/xxxx_XACTS_PER_PAGE
+	(where xxxx is CLOG or SUBTRANS, respectively), and segment numbering at
+	0xFFFFFFFF/xxxx_XACTS_PER_PAGE/SLRU_PAGES_PER_SEGMENT.  We need
+	take no explicit notice of that fact in slru.c, except when comparing
+	segment and page numbers in SimpleLruTruncate (see PagePrecedes()).
+
+	Changing SLRU_PAGES_PER_SEGMENT requires an initdb. */
+#undef SLRU_PAGES_PER_SEGMENT
+
 /* Saved arguments from configure */
 #undef CONFIGURE_ARGS
 
diff --git a/src/test/modules/test_slru/expected/test_slru.out b/src/test/modules/test_slru/expected/test_slru.out
index 185c56e5d6..1184db276d 100644
--- a/src/test/modules/test_slru/expected/test_slru.out
+++ b/src/test/modules/test_slru/expected/test_slru.out
@@ -1,52 +1,62 @@
 CREATE EXTENSION test_slru;
-SELECT test_slru_page_exists(12345);
+-- how many pages can fit on one slru segment
+SELECT current_setting('slru_pps')::INT AS slru_pps \gset
+SELECT (:slru_pps * 6.8125) AS pageno \gset
+-- count from zero
+SELECT (:pageno + (:slru_pps * 1.5) - 1) AS pageno_max \gset
+SELECT (:pageno_max - (:slru_pps / 2)) AS pageno_middle \gset
+-- non existed page
+SELECT test_slru_page_exists(:pageno::BIGINT);
  test_slru_page_exists 
 -----------------------
  f
 (1 row)
 
-SELECT test_slru_page_write(12345, 'Test SLRU');
+SELECT test_slru_page_write(:pageno::BIGINT, 'Test SLRU');
  test_slru_page_write 
 ----------------------
  
 (1 row)
 
-SELECT test_slru_page_read(12345);
+SELECT test_slru_page_read(:pageno::BIGINT);
  test_slru_page_read 
 ---------------------
  Test SLRU
 (1 row)
 
-SELECT test_slru_page_exists(12345);
+SELECT test_slru_page_exists(:pageno::BIGINT);
  test_slru_page_exists 
 -----------------------
  t
 (1 row)
 
--- 48 extra pages
-SELECT count(test_slru_page_write(a, 'Test SLRU'))
-  FROM generate_series(12346, 12393, 1) as a;
- count 
--------
-    48
-(1 row)
-
+-- Generate extra pages. Redirect output into table because number of funciton
+-- calls depends on the current value of slru_pps parameter.
+CREATE TABLE slru_write_results (
+		pageno BIGINT,
+		write_count INTEGER
+);
+INSERT INTO slru_write_results (pageno, write_count)
+SELECT a, count(test_slru_page_write(a::BIGINT, 'Test SLRU'))
+FROM generate_series(:pageno, :pageno_max, 1) AS a
+GROUP BY a;
+DROP TABLE slru_write_results;
 -- Reading page in buffer for read and write
-SELECT test_slru_page_read(12377, true);
+SELECT test_slru_page_read(:pageno_middle::BIGINT, true);
  test_slru_page_read 
 ---------------------
  Test SLRU
 (1 row)
 
 -- Reading page in buffer for read-only
-SELECT test_slru_page_readonly(12377);
+SELECT test_slru_page_readonly(:pageno_middle::BIGINT);
  test_slru_page_readonly 
 -------------------------
  Test SLRU
 (1 row)
 
 -- Reading page not in buffer with read-only
-SELECT test_slru_page_readonly(12346);
+SELECT test_slru_page_readonly(:pageno::BIGINT);
  test_slru_page_readonly 
 -------------------------
  Test SLRU
@@ -60,47 +70,45 @@ SELECT test_slru_page_writeall();
 (1 row)
 
 -- Flush the last page written out.
-SELECT test_slru_page_sync(12393);
-NOTICE:  Called SlruSyncFileTag() for segment 387 on path pg_test_slru/000000000000183
+SELECT test_slru_page_sync(:pageno_max::BIGINT);
  test_slru_page_sync 
 ---------------------
  
 (1 row)
 
-SELECT test_slru_page_exists(12393);
+SELECT test_slru_page_exists(:pageno_max::BIGINT);
  test_slru_page_exists 
 -----------------------
  t
 (1 row)
 
 -- Segment deletion
-SELECT test_slru_page_delete(12393);
-NOTICE:  Called SlruDeleteSegment() for segment 387
+SELECT test_slru_page_delete(:pageno_max::BIGINT);
  test_slru_page_delete 
 -----------------------
  
 (1 row)
 
-SELECT test_slru_page_exists(12393);
+SELECT test_slru_page_exists(:pageno_max::BIGINT);
  test_slru_page_exists 
 -----------------------
  f
 (1 row)
 
 -- Page truncation
-SELECT test_slru_page_exists(12377);
+SELECT test_slru_page_exists(:pageno_middle::BIGINT);
  test_slru_page_exists 
 -----------------------
  t
 (1 row)
 
-SELECT test_slru_page_truncate(12377);
+SELECT test_slru_page_truncate(:pageno_middle::BIGINT);
  test_slru_page_truncate 
 -------------------------
  
 (1 row)
 
-SELECT test_slru_page_exists(12377);
+SELECT test_slru_page_exists(:pageno_middle::BIGINT);
  test_slru_page_exists 
 -----------------------
  t
@@ -114,19 +122,19 @@ NOTICE:  Calling test_slru_scan_cb()
  
 (1 row)
 
-SELECT test_slru_page_exists(12345);
+SELECT test_slru_page_exists(:pageno::BIGINT);
  test_slru_page_exists 
 -----------------------
  f
 (1 row)
 
-SELECT test_slru_page_exists(12377);
+SELECT test_slru_page_exists(:pageno_middle::BIGINT);
  test_slru_page_exists 
 -----------------------
  f
 (1 row)
 
-SELECT test_slru_page_exists(12393);
+SELECT test_slru_page_exists(:pageno_max::BIGINT);
  test_slru_page_exists 
 -----------------------
  f
@@ -135,54 +143,63 @@ SELECT test_slru_page_exists(12393);
 --
 -- Test 64-bit pages
 --
-SELECT test_slru_page_exists(0x1234500000000);
+\set no_such_page	0x1234500000000
+-- second page in SLRU segments
+\set pageno			0x1234500000001
+-- count from zero
+SELECT (:no_such_page + (:slru_pps * 1.5)) AS pageno_max \gset
+SELECT (:pageno_max - (:slru_pps / 2)) AS pageno_middle \gset
+SELECT test_slru_page_exists(:no_such_page);
  test_slru_page_exists 
 -----------------------
  f
 (1 row)
 
-SELECT test_slru_page_write(0x1234500000000, 'Test SLRU 64-bit');
+SELECT test_slru_page_write(:no_such_page, 'Test SLRU 64-bit');
  test_slru_page_write 
 ----------------------
  
 (1 row)
 
-SELECT test_slru_page_read(0x1234500000000);
+SELECT test_slru_page_read(:no_such_page);
  test_slru_page_read 
 ---------------------
  Test SLRU 64-bit
 (1 row)
 
-SELECT test_slru_page_exists(0x1234500000000);
+SELECT test_slru_page_exists(:no_such_page);
  test_slru_page_exists 
 -----------------------
  t
 (1 row)
 
--- 48 extra pages
-SELECT count(test_slru_page_write(a, 'Test SLRU 64-bit'))
-  FROM generate_series(0x1234500000001, 0x1234500000030, 1) as a;
- count 
--------
-    48
-(1 row)
-
+-- Generate extra pages. Redirect output into table because number of funciton
+-- calls depends on the current value of slru_pps parameter.
+CREATE TABLE slru_write_results (
+		pageno BIGINT,
+		write_count INTEGER
+);
+INSERT INTO slru_write_results (pageno, write_count)
+SELECT a, count(test_slru_page_write(a::BIGINT, 'Test SLRU 64-bit'))
+FROM generate_series(:pageno, :pageno_max, 1) AS a
+GROUP BY a;
+DROP TABLE slru_write_results;
 -- Reading page in buffer for read and write
-SELECT test_slru_page_read(0x1234500000020, true);
+SELECT test_slru_page_read(:pageno_middle::BIGINT, true);
  test_slru_page_read 
 ---------------------
  Test SLRU 64-bit
 (1 row)
 
 -- Reading page in buffer for read-only
-SELECT test_slru_page_readonly(0x1234500000020);
+SELECT test_slru_page_readonly(:pageno_middle::BIGINT);
  test_slru_page_readonly 
 -------------------------
  Test SLRU 64-bit
 (1 row)
 
 -- Reading page not in buffer with read-only
-SELECT test_slru_page_readonly(0x1234500000001);
+SELECT test_slru_page_readonly(:pageno);
  test_slru_page_readonly 
 -------------------------
  Test SLRU 64-bit
@@ -196,47 +213,45 @@ SELECT test_slru_page_writeall();
 (1 row)
 
 -- Flush the last page written out.
-SELECT test_slru_page_sync(0x1234500000030);
-NOTICE:  Called SlruSyncFileTag() for segment 10007944888321 on path pg_test_slru/000091A28000001
+SELECT test_slru_page_sync(:pageno_max::BIGINT);
  test_slru_page_sync 
 ---------------------
  
 (1 row)
 
-SELECT test_slru_page_exists(0x1234500000030);
+SELECT test_slru_page_exists(:pageno_max::BIGINT);
  test_slru_page_exists 
 -----------------------
  t
 (1 row)
 
 -- Segment deletion
-SELECT test_slru_page_delete(0x1234500000030);
-NOTICE:  Called SlruDeleteSegment() for segment 10007944888321
+SELECT test_slru_page_delete(:pageno_max::BIGINT);
  test_slru_page_delete 
 -----------------------
  
 (1 row)
 
-SELECT test_slru_page_exists(0x1234500000030);
+SELECT test_slru_page_exists(:pageno_max::BIGINT);
  test_slru_page_exists 
 -----------------------
  f
 (1 row)
 
 -- Page truncation
-SELECT test_slru_page_exists(0x1234500000020);
+SELECT test_slru_page_exists(:pageno_middle::BIGINT);
  test_slru_page_exists 
 -----------------------
  f
 (1 row)
 
-SELECT test_slru_page_truncate(0x1234500000020);
+SELECT test_slru_page_truncate(:pageno_middle::BIGINT);
  test_slru_page_truncate 
 -------------------------
  
 (1 row)
 
-SELECT test_slru_page_exists(0x1234500000020);
+SELECT test_slru_page_exists(:pageno_middle::BIGINT);
  test_slru_page_exists 
 -----------------------
  f
@@ -249,19 +264,19 @@ SELECT test_slru_delete_all();
  
 (1 row)
 
-SELECT test_slru_page_exists(0x1234500000000);
+SELECT test_slru_page_exists(:no_such_page);
  test_slru_page_exists 
 -----------------------
  f
 (1 row)
 
-SELECT test_slru_page_exists(0x1234500000020);
+SELECT test_slru_page_exists(:pageno_middle::BIGINT);
  test_slru_page_exists 
 -----------------------
  f
 (1 row)
 
-SELECT test_slru_page_exists(0x1234500000030);
+SELECT test_slru_page_exists(:pageno_max::BIGINT);
  test_slru_page_exists 
 -----------------------
  f
diff --git a/src/test/modules/test_slru/sql/test_slru.sql b/src/test/modules/test_slru/sql/test_slru.sql
index b1b376581a..ee6bd32353 100644
--- a/src/test/modules/test_slru/sql/test_slru.sql
+++ b/src/test/modules/test_slru/sql/test_slru.sql
@@ -1,76 +1,118 @@
 CREATE EXTENSION test_slru;
 
-SELECT test_slru_page_exists(12345);
-SELECT test_slru_page_write(12345, 'Test SLRU');
-SELECT test_slru_page_read(12345);
-SELECT test_slru_page_exists(12345);
+-- how many pages can fit on one slru segment
+SELECT current_setting('slru_pps')::INT AS slru_pps \gset
 
--- 48 extra pages
-SELECT count(test_slru_page_write(a, 'Test SLRU'))
-  FROM generate_series(12346, 12393, 1) as a;
+SELECT (:slru_pps * 6.8125) AS pageno \gset
+
+-- count from zero
+SELECT (:pageno + (:slru_pps * 1.5) - 1) AS pageno_max \gset
+
+SELECT (:pageno_max - (:slru_pps / 2)) AS pageno_middle \gset
+
+-- non existed page
+SELECT test_slru_page_exists(:pageno::BIGINT);
+SELECT test_slru_page_write(:pageno::BIGINT, 'Test SLRU');
+SELECT test_slru_page_read(:pageno::BIGINT);
+SELECT test_slru_page_exists(:pageno::BIGINT);
+
+-- Generate extra pages. Redirect output into table because number of funciton
+-- calls depends on the current value of slru_pps parameter.
+
+CREATE TABLE slru_write_results (
+		pageno BIGINT,
+		write_count INTEGER
+);
+
+INSERT INTO slru_write_results (pageno, write_count)
+SELECT a, count(test_slru_page_write(a::BIGINT, 'Test SLRU'))
+FROM generate_series(:pageno, :pageno_max, 1) AS a
+GROUP BY a;
+
+DROP TABLE slru_write_results;
 
 -- Reading page in buffer for read and write
-SELECT test_slru_page_read(12377, true);
+SELECT test_slru_page_read(:pageno_middle::BIGINT, true);
 -- Reading page in buffer for read-only
-SELECT test_slru_page_readonly(12377);
+SELECT test_slru_page_readonly(:pageno_middle::BIGINT);
 -- Reading page not in buffer with read-only
-SELECT test_slru_page_readonly(12346);
+SELECT test_slru_page_readonly(:pageno::BIGINT);
 
 -- Write all the pages in buffers
 SELECT test_slru_page_writeall();
 -- Flush the last page written out.
-SELECT test_slru_page_sync(12393);
-SELECT test_slru_page_exists(12393);
+SELECT test_slru_page_sync(:pageno_max::BIGINT);
+SELECT test_slru_page_exists(:pageno_max::BIGINT);
 -- Segment deletion
-SELECT test_slru_page_delete(12393);
-SELECT test_slru_page_exists(12393);
+SELECT test_slru_page_delete(:pageno_max::BIGINT);
+SELECT test_slru_page_exists(:pageno_max::BIGINT);
 -- Page truncation
-SELECT test_slru_page_exists(12377);
-SELECT test_slru_page_truncate(12377);
-SELECT test_slru_page_exists(12377);
+SELECT test_slru_page_exists(:pageno_middle::BIGINT);
+SELECT test_slru_page_truncate(:pageno_middle::BIGINT);
+SELECT test_slru_page_exists(:pageno_middle::BIGINT);
 
 -- Full deletion
 SELECT test_slru_delete_all();
-SELECT test_slru_page_exists(12345);
-SELECT test_slru_page_exists(12377);
-SELECT test_slru_page_exists(12393);
+SELECT test_slru_page_exists(:pageno::BIGINT);
+SELECT test_slru_page_exists(:pageno_middle::BIGINT);
+SELECT test_slru_page_exists(:pageno_max::BIGINT);
 
 --
 -- Test 64-bit pages
 --
-SELECT test_slru_page_exists(0x1234500000000);
-SELECT test_slru_page_write(0x1234500000000, 'Test SLRU 64-bit');
-SELECT test_slru_page_read(0x1234500000000);
-SELECT test_slru_page_exists(0x1234500000000);
+\set no_such_page	0x1234500000000
+-- second page in SLRU segments
+\set pageno			0x1234500000001
+
+-- count from zero
+SELECT (:no_such_page + (:slru_pps * 1.5)) AS pageno_max \gset
+
+SELECT (:pageno_max - (:slru_pps / 2)) AS pageno_middle \gset
+
+SELECT test_slru_page_exists(:no_such_page);
+SELECT test_slru_page_write(:no_such_page, 'Test SLRU 64-bit');
+SELECT test_slru_page_read(:no_such_page);
+SELECT test_slru_page_exists(:no_such_page);
+
+-- Generate extra pages. Redirect output into table because number of funciton
+-- calls depends on the current value of slru_pps parameter.
+
+CREATE TABLE slru_write_results (
+		pageno BIGINT,
+		write_count INTEGER
+);
+
+INSERT INTO slru_write_results (pageno, write_count)
+SELECT a, count(test_slru_page_write(a::BIGINT, 'Test SLRU 64-bit'))
+FROM generate_series(:pageno, :pageno_max, 1) AS a
+GROUP BY a;
 
--- 48 extra pages
-SELECT count(test_slru_page_write(a, 'Test SLRU 64-bit'))
-  FROM generate_series(0x1234500000001, 0x1234500000030, 1) as a;
+DROP TABLE slru_write_results;
 
 -- Reading page in buffer for read and write
-SELECT test_slru_page_read(0x1234500000020, true);
+SELECT test_slru_page_read(:pageno_middle::BIGINT, true);
 -- Reading page in buffer for read-only
-SELECT test_slru_page_readonly(0x1234500000020);
+SELECT test_slru_page_readonly(:pageno_middle::BIGINT);
 -- Reading page not in buffer with read-only
-SELECT test_slru_page_readonly(0x1234500000001);
+SELECT test_slru_page_readonly(:pageno);
 
 -- Write all the pages in buffers
 SELECT test_slru_page_writeall();
 -- Flush the last page written out.
-SELECT test_slru_page_sync(0x1234500000030);
-SELECT test_slru_page_exists(0x1234500000030);
+SELECT test_slru_page_sync(:pageno_max::BIGINT);
+SELECT test_slru_page_exists(:pageno_max::BIGINT);
 -- Segment deletion
-SELECT test_slru_page_delete(0x1234500000030);
-SELECT test_slru_page_exists(0x1234500000030);
+SELECT test_slru_page_delete(:pageno_max::BIGINT);
+SELECT test_slru_page_exists(:pageno_max::BIGINT);
 -- Page truncation
-SELECT test_slru_page_exists(0x1234500000020);
-SELECT test_slru_page_truncate(0x1234500000020);
-SELECT test_slru_page_exists(0x1234500000020);
+SELECT test_slru_page_exists(:pageno_middle::BIGINT);
+SELECT test_slru_page_truncate(:pageno_middle::BIGINT);
+SELECT test_slru_page_exists(:pageno_middle::BIGINT);
 
 -- Full deletion
 SELECT test_slru_delete_all();
-SELECT test_slru_page_exists(0x1234500000000);
-SELECT test_slru_page_exists(0x1234500000020);
-SELECT test_slru_page_exists(0x1234500000030);
+SELECT test_slru_page_exists(:no_such_page);
+SELECT test_slru_page_exists(:pageno_middle::BIGINT);
+SELECT test_slru_page_exists(:pageno_max::BIGINT);
 
 DROP EXTENSION test_slru;
diff --git a/src/test/modules/test_slru/test_slru.c b/src/test/modules/test_slru/test_slru.c
index d227b06703..7c55798dc8 100644
--- a/src/test/modules/test_slru/test_slru.c
+++ b/src/test/modules/test_slru/test_slru.c
@@ -151,9 +151,6 @@ test_slru_page_sync(PG_FUNCTION_ARGS)
 	ftag.segno = pageno / SLRU_PAGES_PER_SEGMENT;
 	SlruSyncFileTag(TestSlruCtl, &ftag, path);
 
-	elog(NOTICE, "Called SlruSyncFileTag() for segment %lld on path %s",
-		 (long long) ftag.segno, path);
-
 	PG_RETURN_VOID();
 }
 
@@ -166,9 +163,6 @@ test_slru_page_delete(PG_FUNCTION_ARGS)
 	ftag.segno = pageno / SLRU_PAGES_PER_SEGMENT;
 	SlruDeleteSegment(TestSlruCtl, ftag.segno);
 
-	elog(NOTICE, "Called SlruDeleteSegment() for segment %lld",
-		 (long long) ftag.segno);
-
 	PG_RETURN_VOID();
 }
 
-- 
2.43.0

#4Daniel Gustafsson
daniel@yesql.se
In reply to: Daniil Davydov (#3)
Re: SLRU_PAGES_PER_SEGMENT as configure parameter

On 7 Feb 2025, at 06:54, Daniil Davydov <3danissimo@gmail.com> wrote:

On Thu, Feb 6, 2025 at 8:23 PM Daniel Gustafsson <daniel@yesql.se> wrote:

You should include the configure.ac changes and not just the generated code in
configure (which is fine to include for review, but the committer will
re-generate it regardless). Please also include the corresponding Meson change
to keep the buildsystems in sync.

Thank you for your comment. I'm applying a patch that also includes
configure.ac, meson_options.txt and meson.build changes.

+AC_DEFINE_UNQUOTED([SLRU_PAGES_PER_SEGMENT], ${slru_pages_per_segment}, [
+  SLRU segment size in pages. A page is the same BLCKSZ as is used everywhere
+	else in Postgres.  The segment size can be chosen somewhat arbitrarily;
+       ...
It's not per project style to add large paragraphs like that to autoconf or
Meson, which segways nicely into commenting that the GUC and the build-time
parameters are missing from the documentation.  Something like the above
message should be in the documentation rather than the build infrastructure.

- elog(NOTICE, "Called SlruSyncFileTag() for segment %lld on path %s",
- (long long) ftag.segno, path);
-
...
- elog(NOTICE, "Called SlruDeleteSegment() for segment %lld",
- (long long) ftag.segno);
-
What's the motivation for these changes?

It would also be interesting to know what you think about the idea of
allowing such a parameter to be configured.

It could perhaps be useful for (mostly) testing purposes, but since it requires
recompilation why not just change SLRU_PAGES_PER_SEGMENT in slru.h and
recompile? That would save a lot of code while achieving the same thing no?

If you foresee a performance enchancement in production usecases at certaint
values I recommend doing benchmarking to show this.

--
Daniel Gustafsson