=== Applying patches on top of PostgreSQL commit ID ef6a95c7c64de07dff4dd1f1da88ffae7b086ef3 === /etc/rc.d/jail: WARNING: Per-jail configuration via jail_* variables is obsolete. Please consider migrating to /etc/jail.conf. Wed Jun 3 06:10:28 UTC 2026 On branch cf/6835 nothing to commit, working tree clean === using 'git am' to apply patch ./v1-0001-Add-temp-table-monitoring-columns-to-pg_stat_data.patch === Applying: Add temp table monitoring columns to pg_stat_database Using index info to reconstruct a base tree... M doc/src/sgml/monitoring.sgml M src/backend/catalog/heap.c M src/backend/catalog/system_views.sql M src/backend/storage/buffer/bufmgr.c M src/backend/storage/buffer/localbuf.c M src/backend/utils/activity/pgstat_database.c M src/backend/utils/adt/pgstatfuncs.c M src/include/catalog/catversion.h M src/include/catalog/pg_proc.dat M src/include/pgstat.h M src/test/regress/expected/rules.out Falling back to patching base and 3-way merge... Auto-merging src/test/regress/expected/rules.out Auto-merging src/include/pgstat.h Auto-merging src/include/catalog/pg_proc.dat Auto-merging src/include/catalog/catversion.h CONFLICT (content): Merge conflict in src/include/catalog/catversion.h Auto-merging src/backend/utils/adt/pgstatfuncs.c Auto-merging src/backend/utils/activity/pgstat_database.c Auto-merging src/backend/storage/buffer/localbuf.c Auto-merging src/backend/storage/buffer/bufmgr.c CONFLICT (content): Merge conflict in src/backend/storage/buffer/bufmgr.c Auto-merging src/backend/catalog/system_views.sql Auto-merging src/backend/catalog/heap.c Auto-merging doc/src/sgml/monitoring.sgml error: Failed to merge in the changes. hint: Use 'git am --show-current-patch=diff' to see the failed patch Patch failed at 0001 Add temp table monitoring columns to pg_stat_database When you have resolved this problem, run "git am --continue". If you prefer to skip this patch, run "git am --skip" instead. To restore the original branch and stop patching, run "git am --abort". === using patch(1) to apply patch ./v1-0001-Add-temp-table-monitoring-columns-to-pg_stat_data.patch === patching file doc/src/sgml/monitoring.sgml Hunk #1 succeeded at 3880 (offset 114 lines). patching file src/backend/catalog/heap.c Hunk #1 succeeded at 1540 (offset 20 lines). patching file src/backend/catalog/system_views.sql Hunk #1 succeeded at 1167 (offset 34 lines). patching file src/backend/storage/buffer/bufmgr.c Hunk #1 succeeded at 841 (offset 13 lines). Hunk #2 FAILED at 1250. Hunk #3 FAILED at 1991. Hunk #4 FAILED at 2061. 3 out of 4 hunks FAILED -- saving rejects to file src/backend/storage/buffer/bufmgr.c.rej patching file src/backend/storage/buffer/localbuf.c Hunk #1 succeeded at 219 (offset 1 line). Hunk #2 succeeded at 491 (offset 9 lines). Hunk #3 succeeded at 522 (offset 9 lines). patching file src/backend/utils/activity/pgstat_database.c patching file src/backend/utils/adt/pgstatfuncs.c Hunk #1 succeeded at 1114 (offset 4 lines). patching file src/include/catalog/catversion.h Hunk #1 FAILED at 57. 1 out of 1 hunk FAILED -- saving rejects to file src/include/catalog/catversion.h.rej patching file src/include/catalog/pg_proc.dat Hunk #1 succeeded at 5921 (offset 23 lines). patching file src/include/pgstat.h Hunk #1 succeeded at 384 (offset 19 lines). Hunk #2 succeeded at 654 (offset 24 lines). patching file src/test/regress/expected/rules.out Hunk #1 succeeded at 1908 (offset 15 lines). Unstaged changes after reset: M doc/src/sgml/monitoring.sgml M src/backend/catalog/heap.c M src/backend/catalog/system_views.sql M src/backend/storage/buffer/bufmgr.c M src/backend/storage/buffer/localbuf.c M src/backend/utils/activity/pgstat_database.c M src/backend/utils/adt/pgstatfuncs.c M src/include/catalog/pg_proc.dat M src/include/pgstat.h M src/test/regress/expected/rules.out Removing src/backend/storage/buffer/bufmgr.c.rej Removing src/include/catalog/catversion.h.rej === using 'git apply' to apply patch ./v1-0001-Add-temp-table-monitoring-columns-to-pg_stat_data.patch === Applied patch to 'doc/src/sgml/monitoring.sgml' cleanly. Applied patch to 'src/backend/catalog/heap.c' cleanly. Applied patch to 'src/backend/catalog/system_views.sql' cleanly. Applied patch to 'src/backend/storage/buffer/bufmgr.c' with conflicts. Applied patch to 'src/backend/storage/buffer/localbuf.c' cleanly. Applied patch to 'src/backend/utils/activity/pgstat_database.c' cleanly. Applied patch to 'src/backend/utils/adt/pgstatfuncs.c' cleanly. Applied patch to 'src/include/catalog/catversion.h' with conflicts. Applied patch to 'src/include/catalog/pg_proc.dat' cleanly. Applied patch to 'src/include/pgstat.h' cleanly. Applied patch to 'src/test/regress/expected/rules.out' cleanly. U src/backend/storage/buffer/bufmgr.c U src/include/catalog/catversion.h diff --cc src/backend/storage/buffer/bufmgr.c index cc398db124d,78c1db9c318..00000000000 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@@ -1246,14 -1247,21 +1247,23 @@@ PinBufferForBlock(Relation rel smgr->smgr_rlocator.backend); if (persistence == RELPERSISTENCE_TEMP) - { bufHdr = LocalBufferAlloc(smgr, forkNum, blockNum, foundPtr); ++<<<<<<< ours ++======= + if (*foundPtr) + { + pgBufferUsage.local_blks_hit++; + pgstat_count_local_blk_hit(MyDatabaseId); + } + } ++>>>>>>> theirs else - { bufHdr = BufferAlloc(smgr, persistence, forkNum, blockNum, strategy, foundPtr, io_context); - if (*foundPtr) - pgBufferUsage.shared_blks_hit++; - } + + if (*foundPtr) + TrackBufferHit(io_object, io_context, rel, persistence, smgr, forkNum, blockNum); + if (rel) { /* @@@ -2029,149 -1957,136 +2039,169 @@@ AsyncReadBuffers(ReadBuffersOperation * ioh = pgaio_io_acquire(CurrentResourceOwner, &operation->io_return); } + operation->foreign_io = false; + pgaio_wref_clear(&operation->io_wref); + /* - * Check if we can start IO on the first to-be-read buffer. + * Try to start IO on the first buffer in a new run of blocks. If AIO is + * in progress, be it in this backend or another backend, we just + * associate the wait reference with the operation and wait in + * WaitReadBuffers(). This turns out to be important for performance in + * two workloads: + * + * 1) A read stream that has to read the same block multiple times within + * the readahead distance. This can happen e.g. for the table accesses of + * an index scan. * - * If an I/O is already in progress in another backend, we want to wait - * for the outcome: either done, or something went wrong and we will - * retry. + * 2) Concurrent scans by multiple backends on the same relation. + * + * If we were to synchronously wait for the in-progress IO, we'd not be + * able to keep enough I/O in flight. + * + * If we do find there is ongoing I/O for the buffer, we set up a 1-block + * ReadBuffersOperation that WaitReadBuffers then can wait on. + * + * It's possible that another backend has started IO on the buffer but not + * yet set its wait reference. In this case, we have no choice but to wait + * for either the wait reference to be valid or the IO to be done. */ - if (!ReadBuffersCanStartIO(buffers[nblocks_done], false)) + status = StartBufferIO(buffers[nblocks_done], true, true, + &operation->io_wref); + if (status != BUFFER_IO_READY_FOR_IO) { - /* - * Someone else has already completed this block, we're done. - * - * When IO is necessary, ->nblocks_done is updated in - * ProcessReadBuffersResult(), but that is not called if no IO is - * necessary. Thus update here. - */ - operation->nblocks_done += 1; + pgaio_io_release(ioh); *nblocks_progress = 1; + if (status == BUFFER_IO_ALREADY_DONE) + { + /* + * Someone has already completed this block, we're done. + * + * When IO is necessary, ->nblocks_done is updated in + * ProcessReadBuffersResult(), but that is not called if no IO is + * necessary. Thus update here. + */ + operation->nblocks_done += 1; + Assert(operation->nblocks_done <= operation->nblocks); - pgaio_io_release(ioh); - pgaio_wref_clear(&operation->io_wref); - did_start_io = false; + Assert(!pgaio_wref_valid(&operation->io_wref)); - /* - * Report and track this as a 'hit' for this backend, even though it - * must have started out as a miss in PinBufferForBlock(). The other - * backend will track this as a 'read'. - */ - TRACE_POSTGRESQL_BUFFER_READ_DONE(forknum, blocknum + operation->nblocks_done, - operation->smgr->smgr_rlocator.locator.spcOid, - operation->smgr->smgr_rlocator.locator.dbOid, - operation->smgr->smgr_rlocator.locator.relNumber, - operation->smgr->smgr_rlocator.backend, - true); + /* + * Report and track this as a 'hit' for this backend, even though + * it must have started out as a miss in PinBufferForBlock(). The + * other backend will track this as a 'read'. + */ + TrackBufferHit(io_object, io_context, + operation->rel, operation->persistence, + operation->smgr, operation->forknum, + blocknum); + return false; + } ++<<<<<<< ours + /* The IO is already in-progress */ + Assert(status == BUFFER_IO_IN_PROGRESS); + Assert(pgaio_wref_valid(&operation->io_wref)); + operation->foreign_io = true; ++======= + if (persistence == RELPERSISTENCE_TEMP) + { + pgBufferUsage.local_blks_hit += 1; + pgstat_count_local_blk_hit(MyDatabaseId); + } + else + pgBufferUsage.shared_blks_hit += 1; ++>>>>>>> theirs - if (operation->rel) - pgstat_count_buffer_hit(operation->rel); + return true; + } - pgstat_count_io_op(io_object, io_context, IOOP_HIT, 1, 0); + Assert(io_buffers[0] == buffers[nblocks_done]); + io_pages[0] = BufferGetBlock(buffers[nblocks_done]); + io_buffers_len = 1; - if (VacuumCostActive) - VacuumCostBalance += VacuumCostPageHit; - } - else + /* + * NB: As little code as possible should be added between the + * StartBufferIO() above, the further StartBufferIO()s below and the + * smgrstartreadv(), as some of the buffers are now marked as + * IO_IN_PROGRESS and will thus cause other backends to wait. + */ + + /* + * How many neighboring-on-disk blocks can we scatter-read into other + * buffers at the same time? In this case we don't wait if we see an I/O + * already in progress (see comment above). + */ + for (int i = nblocks_done + 1; i < operation->nblocks; i++) { - instr_time io_start; + /* Must be consecutive block numbers. */ + Assert(BufferGetBlockNumber(buffers[i - 1]) == + BufferGetBlockNumber(buffers[i]) - 1); - /* We found a buffer that we need to read in. */ - Assert(io_buffers[0] == buffers[nblocks_done]); - io_pages[0] = BufferGetBlock(buffers[nblocks_done]); - io_buffers_len = 1; + status = StartBufferIO(buffers[i], true, false, NULL); + if (status != BUFFER_IO_READY_FOR_IO) + break; - /* - * How many neighboring-on-disk blocks can we scatter-read into other - * buffers at the same time? In this case we don't wait if we see an - * I/O already in progress. We already set BM_IO_IN_PROGRESS for the - * head block, so we should get on with that I/O as soon as possible. - */ - for (int i = nblocks_done + 1; i < operation->nblocks; i++) - { - if (!ReadBuffersCanStartIO(buffers[i], true)) - break; - /* Must be consecutive block numbers. */ - Assert(BufferGetBlockNumber(buffers[i - 1]) == - BufferGetBlockNumber(buffers[i]) - 1); - Assert(io_buffers[io_buffers_len] == buffers[i]); + Assert(io_buffers[io_buffers_len] == buffers[i]); - io_pages[io_buffers_len++] = BufferGetBlock(buffers[i]); - } + io_pages[io_buffers_len++] = BufferGetBlock(buffers[i]); + } - /* get a reference to wait for in WaitReadBuffers() */ - pgaio_io_get_wref(ioh, &operation->io_wref); + /* get a reference to wait for in WaitReadBuffers() */ + pgaio_io_get_wref(ioh, &operation->io_wref); - /* provide the list of buffers to the completion callbacks */ - pgaio_io_set_handle_data_32(ioh, (uint32 *) io_buffers, io_buffers_len); + /* provide the list of buffers to the completion callbacks */ + pgaio_io_set_handle_data_32(ioh, (uint32 *) io_buffers, io_buffers_len); - pgaio_io_register_callbacks(ioh, - persistence == RELPERSISTENCE_TEMP ? - PGAIO_HCB_LOCAL_BUFFER_READV : - PGAIO_HCB_SHARED_BUFFER_READV, - flags); + pgaio_io_register_callbacks(ioh, + persistence == RELPERSISTENCE_TEMP ? + PGAIO_HCB_LOCAL_BUFFER_READV : + PGAIO_HCB_SHARED_BUFFER_READV, + flags); - pgaio_io_set_flag(ioh, ioh_flags); + pgaio_io_set_flag(ioh, ioh_flags); - /* --- - * Even though we're trying to issue IO asynchronously, track the time - * in smgrstartreadv(): - * - if io_method == IOMETHOD_SYNC, we will always perform the IO - * immediately - * - the io method might not support the IO (e.g. worker IO for a temp - * table) - * --- - */ - io_start = pgstat_prepare_io_time(track_io_timing); - smgrstartreadv(ioh, operation->smgr, forknum, - blocknum + nblocks_done, - io_pages, io_buffers_len); - pgstat_count_io_op_time(io_object, io_context, IOOP_READ, - io_start, 1, io_buffers_len * BLCKSZ); + /* --- + * Even though we're trying to issue IO asynchronously, track the time + * in smgrstartreadv(): + * - if io_method == IOMETHOD_SYNC, we will always perform the IO + * immediately + * - the io method might not support the IO (e.g. worker IO for a temp + * table) + * --- + */ + io_start = pgstat_prepare_io_time(track_io_timing); + smgrstartreadv(ioh, operation->smgr, forknum, + blocknum, + io_pages, io_buffers_len); + pgstat_count_io_op_time(io_object, io_context, IOOP_READ, + io_start, 1, io_buffers_len * BLCKSZ); ++<<<<<<< ours + if (persistence == RELPERSISTENCE_TEMP) + pgBufferUsage.local_blks_read += io_buffers_len; + else + pgBufferUsage.shared_blks_read += io_buffers_len; ++======= + if (persistence == RELPERSISTENCE_TEMP) + { + pgBufferUsage.local_blks_read += io_buffers_len; + pgstat_count_local_blk_read(MyDatabaseId, io_buffers_len); + } + else + pgBufferUsage.shared_blks_read += io_buffers_len; ++>>>>>>> theirs - /* - * Track vacuum cost when issuing IO, not after waiting for it. - * Otherwise we could end up issuing a lot of IO in a short timespan, - * despite a low cost limit. - */ - if (VacuumCostActive) - VacuumCostBalance += VacuumCostPageMiss * io_buffers_len; + /* + * Track vacuum cost when issuing IO, not after waiting for it. Otherwise + * we could end up issuing a lot of IO in a short timespan, despite a low + * cost limit. + */ + if (VacuumCostActive) + VacuumCostBalance += VacuumCostPageMiss * io_buffers_len; - *nblocks_progress = io_buffers_len; - did_start_io = true; - } + *nblocks_progress = io_buffers_len; - return did_start_io; + return true; } /* diff --cc src/include/catalog/catversion.h index a1416260abc,59bebd8b079..00000000000 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@@ -57,6 -57,6 +57,10 @@@ */ /* yyyymmddN */ ++<<<<<<< ours +#define CATALOG_VERSION_NO 202605131 ++======= + #define CATALOG_VERSION_NO 202603106 ++>>>>>>> theirs #endif