1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-09 22:41:56 +03:00

bufmgr/smgr: Don't cross segment boundaries in StartReadBuffers()

With real AIO it doesn't make sense to cross segment boundaries with one
IO. Add smgrmaxcombine() to allow upper layers to query which buffers can be
merged.

We could continue to cross segment boundaries when not using AIO, but it
doesn't really make sense, because md.c will never be able to perform the read
across the segment boundary in one system call. Which means we'll mark more
buffers as undergoing IO than really makes sense - if another backend desires
to read the same blocks, it'll be blocked longer than necessary. So it seems
better to just never cross the boundary.

Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi>
Reviewed-by: Noah Misch <noah@leadboat.com>
Discussion: https://postgr.es/m/1f6b50a7-38ef-4d87-8246-786d39f46ab9@iki.fi
This commit is contained in:
Andres Freund
2024-10-08 11:37:45 -04:00
parent 488f826c72
commit 755a4c10d1
5 changed files with 65 additions and 0 deletions
src
backend
storage
include
storage

@ -1259,6 +1259,7 @@ StartReadBuffersImpl(ReadBuffersOperation *operation,
{
int actual_nblocks = *nblocks;
int io_buffers_len = 0;
int maxcombine = 0;
Assert(*nblocks > 0);
Assert(*nblocks <= MAX_IO_COMBINE_LIMIT);
@ -1290,6 +1291,23 @@ StartReadBuffersImpl(ReadBuffersOperation *operation,
{
/* Extend the readable range to cover this block. */
io_buffers_len++;
/*
* Check how many blocks we can cover with the same IO. The smgr
* implementation might e.g. be limited due to a segment boundary.
*/
if (i == 0 && actual_nblocks > 1)
{
maxcombine = smgrmaxcombine(operation->smgr,
operation->forknum,
blockNum);
if (unlikely(maxcombine < actual_nblocks))
{
elog(DEBUG2, "limiting nblocks at %u from %u to %u",
blockNum, actual_nblocks, maxcombine);
actual_nblocks = maxcombine;
}
}
}
}
*nblocks = actual_nblocks;