Increase io_combine_limit range to 1MB.
authorThomas Munro <tmunro@postgresql.org>
Wed, 19 Mar 2025 02:23:12 +0000 (15:23 +1300)
committerThomas Munro <tmunro@postgresql.org>
Wed, 19 Mar 2025 02:40:35 +0000 (15:40 +1300)
The default of 128kB is unchanged, but the upper limit is changed from
32 blocks to 128 blocks, unless the operating system's IOV_MAX is too
low.  Some other RDBMSes seem to cap their multi-block buffer pool I/O
around this number, and it seems useful to allow experimentation.

The concrete change is to our definition of PG_IOV_MAX, which provides
the maximum for io_combine_limit and io_max_combine_limit.  It also
affects a couple of other places that work with arrays of struct iovec
or smaller objects on the stack, so we still don't want to use the
system IOV_MAX directly without a clamp: it is not under our control and
likely to be 1024.  128 seems acceptable for our current usage.

For Windows, we can't use real scatter/gather yet, so we continue to
define our own IOV_MAX value of 16 and emulate preadv()/pwritev() with
loops.  Someone would need to research the trade-offs of raising that
number.

NB if trying to see this working: you might temporarily need to hack
BAS_BULKREAD to be bigger, since otherwise the obvious way of "a very
big SELECT" is limited by that for now.

Suggested-by: Tomas Vondra <tomas@vondra.me>
Discussion: https://postgr.es/m/CA%2BhUKG%2B2T9p-%2BzM6Eeou-RAJjTML6eit1qn26f9twznX59qtCA%40mail.gmail.com

doc/src/sgml/config.sgml
src/backend/storage/aio/read_stream.c
src/backend/utils/misc/postgresql.conf.sample
src/include/port/pg_iovec.h

index 2988865b116345317b7abdc76e1d174ac11b34a5..4fd377d1c5fef4dfe4ad23ab83c2505a91782db7 100644 (file)
@@ -2638,6 +2638,8 @@ include_dir 'conf.d'
          This parameter can only be set in
          the <filename>postgresql.conf</filename> file or on the server
          command line.
+         The maximum possible size depends on the operating system and block
+         size, but is typically 1MB on Unix and 128kB on Windows.
          The default is 128kB.
         </para>
        </listitem>
@@ -2655,6 +2657,8 @@ include_dir 'conf.d'
          higher than the <varname>io_max_combine_limit</varname> parameter, the
          lower value will silently be used instead, so both may need to be raised
          to increase the I/O size.
+         The maximum possible size depends on the operating system and block
+         size, but is typically 1MB on Unix and 128kB on Windows.
          The default is 128kB.
         </para>
        </listitem>
index d65fa07b44c428c3f0b3c343347fcaee8c2c468a..45bdf819d5770408c7ef83887a9ff90d195c2ea1 100644 (file)
@@ -515,9 +515,10 @@ read_stream_begin_impl(int flags,
     * finishes we don't want to have to wait for its buffers to be consumed
     * before starting a new one.
     *
-    * Be careful not to allow int16 to overflow (even though that's not
-    * possible with the current GUC range limits), allowing also for the
-    * spare entry and the overflow space.
+    * Be careful not to allow int16 to overflow.  That is possible with the
+    * current GUC range limits, so this is an artificial limit of ~32k
+    * buffers and we'd need to adjust the types to exceed that.  We also have
+    * to allow for the spare entry and the overflow space.
     */
    max_pinned_buffers = (max_ios + 1) * io_combine_limit;
    max_pinned_buffers = Min(max_pinned_buffers,
index 66bda60f4caffbef873d8ff332bdb956cde167a9..6abd1baeac857957bde81b67d6f41e4a4bd03c0f 100644 (file)
 #backend_flush_after = 0       # measured in pages, 0 disables
 #effective_io_concurrency = 16     # 1-1000; 0 disables prefetching
 #maintenance_io_concurrency = 16   # 1-1000; 0 disables prefetching
-#io_max_combine_limit = 128kB      # usually 1-32 blocks (depends on OS)
+#io_max_combine_limit = 128kB      # usually 1-128 blocks (depends on OS)
                    # (change requires restart)
-#io_combine_limit = 128kB      # usually 1-32 blocks (depends on OS)
+#io_combine_limit = 128kB      # usually 1-128 blocks (depends on OS)
 
 #io_method = worker            # worker, sync (change requires restart)
 #io_max_concurrency = -1       # Max number of IOs that one process
index d9891d3805d1928017ff485f2db2c991caf8b02c..df40c7208be48137f7a07b286f1c9fa9778a5aa1 100644 (file)
@@ -33,8 +33,12 @@ struct iovec
 
 #endif
 
-/* Define a reasonable maximum that is safe to use on the stack. */
-#define PG_IOV_MAX Min(IOV_MAX, 32)
+/*
+ * Define a reasonable maximum that is safe to use on the stack in arrays of
+ * struct iovec and other small types.  The operating system could limit us to
+ * a number as low as 16, but most systems have 1024.
+ */
+#define PG_IOV_MAX Min(IOV_MAX, 128)
 
 /*
  * Like preadv(), but with a prefix to remind us of a side-effect: on Windows