mirror of
https://github.com/postgres/postgres.git
synced 2025-11-29 23:43:17 +03:00
Create and use wait events for read, write, and fsync operations.
Previous commits, notably53be0b1addand6f3bd98ebf, made it possible to see from pg_stat_activity when a backend was stuck waiting for another backend, but it's also fairly common for a backend to be stuck waiting for an I/O. Add wait events for those operations, too. Rushabh Lathia, with further hacking by me. Reviewed and tested by Michael Paquier, Amit Kapila, Rajkumar Raghuwanshi, and Rahila Syed. Discussion: http://postgr.es/m/CAGPqQf0LsYHXREPAZqYGVkDqHSyjf=KsD=k0GTVPAuzyThh-VQ@mail.gmail.com
This commit is contained in:
@@ -37,6 +37,7 @@
|
||||
#include "postgres.h"
|
||||
|
||||
#include "executor/instrument.h"
|
||||
#include "pgstat.h"
|
||||
#include "storage/fd.h"
|
||||
#include "storage/buffile.h"
|
||||
#include "storage/buf_internals.h"
|
||||
@@ -254,7 +255,10 @@ BufFileLoadBuffer(BufFile *file)
|
||||
/*
|
||||
* Read whatever we can get, up to a full bufferload.
|
||||
*/
|
||||
file->nbytes = FileRead(thisfile, file->buffer, sizeof(file->buffer));
|
||||
file->nbytes = FileRead(thisfile,
|
||||
file->buffer,
|
||||
sizeof(file->buffer),
|
||||
WAIT_EVENT_BUFFILE_READ);
|
||||
if (file->nbytes < 0)
|
||||
file->nbytes = 0;
|
||||
file->offsets[file->curFile] += file->nbytes;
|
||||
@@ -317,7 +321,10 @@ BufFileDumpBuffer(BufFile *file)
|
||||
return; /* seek failed, give up */
|
||||
file->offsets[file->curFile] = file->curOffset;
|
||||
}
|
||||
bytestowrite = FileWrite(thisfile, file->buffer + wpos, bytestowrite);
|
||||
bytestowrite = FileWrite(thisfile,
|
||||
file->buffer + wpos,
|
||||
bytestowrite,
|
||||
WAIT_EVENT_BUFFILE_WRITE);
|
||||
if (bytestowrite <= 0)
|
||||
return; /* failed to write */
|
||||
file->offsets[file->curFile] += bytestowrite;
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "storage/copydir.h"
|
||||
#include "storage/fd.h"
|
||||
#include "miscadmin.h"
|
||||
|
||||
#include "pgstat.h"
|
||||
|
||||
/*
|
||||
* copydir: copy a directory
|
||||
@@ -169,7 +169,9 @@ copy_file(char *fromfile, char *tofile)
|
||||
/* If we got a cancel signal during the copy of the file, quit */
|
||||
CHECK_FOR_INTERRUPTS();
|
||||
|
||||
pgstat_report_wait_start(WAIT_EVENT_COPY_FILE_READ);
|
||||
nbytes = read(srcfd, buffer, COPY_BUF_SIZE);
|
||||
pgstat_report_wait_end();
|
||||
if (nbytes < 0)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
@@ -177,8 +179,10 @@ copy_file(char *fromfile, char *tofile)
|
||||
if (nbytes == 0)
|
||||
break;
|
||||
errno = 0;
|
||||
pgstat_report_wait_start(WAIT_EVENT_COPY_FILE_WRITE);
|
||||
if ((int) write(dstfd, buffer, nbytes) != nbytes)
|
||||
{
|
||||
pgstat_report_wait_end();
|
||||
/* if write didn't set errno, assume problem is no disk space */
|
||||
if (errno == 0)
|
||||
errno = ENOSPC;
|
||||
@@ -186,6 +190,7 @@ copy_file(char *fromfile, char *tofile)
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not write to file \"%s\": %m", tofile)));
|
||||
}
|
||||
pgstat_report_wait_end();
|
||||
|
||||
/*
|
||||
* We fsync the files later but first flush them to avoid spamming the
|
||||
|
||||
@@ -1550,7 +1550,7 @@ FileClose(File file)
|
||||
* to read into.
|
||||
*/
|
||||
int
|
||||
FilePrefetch(File file, off_t offset, int amount)
|
||||
FilePrefetch(File file, off_t offset, int amount, uint32 wait_event_info)
|
||||
{
|
||||
#if defined(USE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED)
|
||||
int returnCode;
|
||||
@@ -1565,8 +1565,10 @@ FilePrefetch(File file, off_t offset, int amount)
|
||||
if (returnCode < 0)
|
||||
return returnCode;
|
||||
|
||||
pgstat_report_wait_start(wait_event_info);
|
||||
returnCode = posix_fadvise(VfdCache[file].fd, offset, amount,
|
||||
POSIX_FADV_WILLNEED);
|
||||
pgstat_report_wait_end();
|
||||
|
||||
return returnCode;
|
||||
#else
|
||||
@@ -1576,7 +1578,7 @@ FilePrefetch(File file, off_t offset, int amount)
|
||||
}
|
||||
|
||||
void
|
||||
FileWriteback(File file, off_t offset, off_t nbytes)
|
||||
FileWriteback(File file, off_t offset, off_t nbytes, uint32 wait_event_info)
|
||||
{
|
||||
int returnCode;
|
||||
|
||||
@@ -1597,11 +1599,13 @@ FileWriteback(File file, off_t offset, off_t nbytes)
|
||||
if (returnCode < 0)
|
||||
return;
|
||||
|
||||
pgstat_report_wait_start(wait_event_info);
|
||||
pg_flush_data(VfdCache[file].fd, offset, nbytes);
|
||||
pgstat_report_wait_end();
|
||||
}
|
||||
|
||||
int
|
||||
FileRead(File file, char *buffer, int amount)
|
||||
FileRead(File file, char *buffer, int amount, uint32 wait_event_info)
|
||||
{
|
||||
int returnCode;
|
||||
Vfd *vfdP;
|
||||
@@ -1620,7 +1624,9 @@ FileRead(File file, char *buffer, int amount)
|
||||
vfdP = &VfdCache[file];
|
||||
|
||||
retry:
|
||||
pgstat_report_wait_start(wait_event_info);
|
||||
returnCode = read(vfdP->fd, buffer, amount);
|
||||
pgstat_report_wait_end();
|
||||
|
||||
if (returnCode >= 0)
|
||||
{
|
||||
@@ -1663,7 +1669,7 @@ retry:
|
||||
}
|
||||
|
||||
int
|
||||
FileWrite(File file, char *buffer, int amount)
|
||||
FileWrite(File file, char *buffer, int amount, uint32 wait_event_info)
|
||||
{
|
||||
int returnCode;
|
||||
Vfd *vfdP;
|
||||
@@ -1721,7 +1727,9 @@ FileWrite(File file, char *buffer, int amount)
|
||||
|
||||
retry:
|
||||
errno = 0;
|
||||
pgstat_report_wait_start(wait_event_info);
|
||||
returnCode = write(vfdP->fd, buffer, amount);
|
||||
pgstat_report_wait_end();
|
||||
|
||||
/* if write didn't set errno, assume problem is no disk space */
|
||||
if (returnCode != amount && errno == 0)
|
||||
@@ -1782,7 +1790,7 @@ retry:
|
||||
}
|
||||
|
||||
int
|
||||
FileSync(File file)
|
||||
FileSync(File file, uint32 wait_event_info)
|
||||
{
|
||||
int returnCode;
|
||||
|
||||
@@ -1795,7 +1803,11 @@ FileSync(File file)
|
||||
if (returnCode < 0)
|
||||
return returnCode;
|
||||
|
||||
return pg_fsync(VfdCache[file].fd);
|
||||
pgstat_report_wait_start(wait_event_info);
|
||||
returnCode = pg_fsync(VfdCache[file].fd);
|
||||
pgstat_report_wait_end();
|
||||
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
off_t
|
||||
@@ -1887,7 +1899,7 @@ FileTell(File file)
|
||||
#endif
|
||||
|
||||
int
|
||||
FileTruncate(File file, off_t offset)
|
||||
FileTruncate(File file, off_t offset, uint32 wait_event_info)
|
||||
{
|
||||
int returnCode;
|
||||
|
||||
@@ -1900,7 +1912,9 @@ FileTruncate(File file, off_t offset)
|
||||
if (returnCode < 0)
|
||||
return returnCode;
|
||||
|
||||
pgstat_report_wait_start(wait_event_info);
|
||||
returnCode = ftruncate(VfdCache[file].fd, offset);
|
||||
pgstat_report_wait_end();
|
||||
|
||||
if (returnCode == 0 && VfdCache[file].fileSize > offset)
|
||||
{
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
#ifdef HAVE_SYS_SHM_H
|
||||
#include <sys/shm.h>
|
||||
#endif
|
||||
#include "pgstat.h"
|
||||
|
||||
#include "portability/mem.h"
|
||||
#include "storage/dsm_impl.h"
|
||||
@@ -911,10 +912,12 @@ dsm_impl_mmap(dsm_op op, dsm_handle handle, Size request_size,
|
||||
|
||||
if (goal > ZBUFFER_SIZE)
|
||||
goal = ZBUFFER_SIZE;
|
||||
pgstat_report_wait_start(WAIT_EVENT_DSM_FILL_ZERO_WRITE);
|
||||
if (write(fd, zbuffer, goal) == goal)
|
||||
remaining -= goal;
|
||||
else
|
||||
success = false;
|
||||
pgstat_report_wait_end();
|
||||
}
|
||||
|
||||
if (!success)
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "miscadmin.h"
|
||||
#include "access/xlog.h"
|
||||
#include "catalog/catalog.h"
|
||||
#include "pgstat.h"
|
||||
#include "portability/instr_time.h"
|
||||
#include "postmaster/bgwriter.h"
|
||||
#include "storage/fd.h"
|
||||
@@ -536,7 +537,7 @@ mdextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
|
||||
errmsg("could not seek to block %u in file \"%s\": %m",
|
||||
blocknum, FilePathName(v->mdfd_vfd))));
|
||||
|
||||
if ((nbytes = FileWrite(v->mdfd_vfd, buffer, BLCKSZ)) != BLCKSZ)
|
||||
if ((nbytes = FileWrite(v->mdfd_vfd, buffer, BLCKSZ, WAIT_EVENT_DATA_FILE_EXTEND)) != BLCKSZ)
|
||||
{
|
||||
if (nbytes < 0)
|
||||
ereport(ERROR,
|
||||
@@ -667,7 +668,7 @@ mdprefetch(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum)
|
||||
|
||||
Assert(seekpos < (off_t) BLCKSZ * RELSEG_SIZE);
|
||||
|
||||
(void) FilePrefetch(v->mdfd_vfd, seekpos, BLCKSZ);
|
||||
(void) FilePrefetch(v->mdfd_vfd, seekpos, BLCKSZ, WAIT_EVENT_DATA_FILE_PREFETCH);
|
||||
#endif /* USE_PREFETCH */
|
||||
}
|
||||
|
||||
@@ -716,7 +717,7 @@ mdwriteback(SMgrRelation reln, ForkNumber forknum,
|
||||
|
||||
seekpos = (off_t) BLCKSZ *(blocknum % ((BlockNumber) RELSEG_SIZE));
|
||||
|
||||
FileWriteback(v->mdfd_vfd, seekpos, (off_t) BLCKSZ * nflush);
|
||||
FileWriteback(v->mdfd_vfd, seekpos, (off_t) BLCKSZ * nflush, WAIT_EVENT_DATA_FILE_FLUSH);
|
||||
|
||||
nblocks -= nflush;
|
||||
blocknum += nflush;
|
||||
@@ -753,7 +754,7 @@ mdread(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
|
||||
errmsg("could not seek to block %u in file \"%s\": %m",
|
||||
blocknum, FilePathName(v->mdfd_vfd))));
|
||||
|
||||
nbytes = FileRead(v->mdfd_vfd, buffer, BLCKSZ);
|
||||
nbytes = FileRead(v->mdfd_vfd, buffer, BLCKSZ, WAIT_EVENT_DATA_FILE_READ);
|
||||
|
||||
TRACE_POSTGRESQL_SMGR_MD_READ_DONE(forknum, blocknum,
|
||||
reln->smgr_rnode.node.spcNode,
|
||||
@@ -829,7 +830,7 @@ mdwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
|
||||
errmsg("could not seek to block %u in file \"%s\": %m",
|
||||
blocknum, FilePathName(v->mdfd_vfd))));
|
||||
|
||||
nbytes = FileWrite(v->mdfd_vfd, buffer, BLCKSZ);
|
||||
nbytes = FileWrite(v->mdfd_vfd, buffer, BLCKSZ, WAIT_EVENT_DATA_FILE_WRITE);
|
||||
|
||||
TRACE_POSTGRESQL_SMGR_MD_WRITE_DONE(forknum, blocknum,
|
||||
reln->smgr_rnode.node.spcNode,
|
||||
@@ -967,7 +968,7 @@ mdtruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks)
|
||||
* This segment is no longer active. We truncate the file, but do
|
||||
* not delete it, for reasons explained in the header comments.
|
||||
*/
|
||||
if (FileTruncate(v->mdfd_vfd, 0) < 0)
|
||||
if (FileTruncate(v->mdfd_vfd, 0, WAIT_EVENT_DATA_FILE_TRUNCATE) < 0)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not truncate file \"%s\": %m",
|
||||
@@ -993,7 +994,7 @@ mdtruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks)
|
||||
*/
|
||||
BlockNumber lastsegblocks = nblocks - priorblocks;
|
||||
|
||||
if (FileTruncate(v->mdfd_vfd, (off_t) lastsegblocks * BLCKSZ) < 0)
|
||||
if (FileTruncate(v->mdfd_vfd, (off_t) lastsegblocks * BLCKSZ, WAIT_EVENT_DATA_FILE_TRUNCATE) < 0)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not truncate file \"%s\" to %u blocks: %m",
|
||||
@@ -1037,7 +1038,7 @@ mdimmedsync(SMgrRelation reln, ForkNumber forknum)
|
||||
{
|
||||
MdfdVec *v = &reln->md_seg_fds[forknum][segno - 1];
|
||||
|
||||
if (FileSync(v->mdfd_vfd) < 0)
|
||||
if (FileSync(v->mdfd_vfd, WAIT_EVENT_DATA_FILE_IMMEDIATE_SYNC) < 0)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not fsync file \"%s\": %m",
|
||||
@@ -1232,7 +1233,7 @@ mdsync(void)
|
||||
INSTR_TIME_SET_CURRENT(sync_start);
|
||||
|
||||
if (seg != NULL &&
|
||||
FileSync(seg->mdfd_vfd) >= 0)
|
||||
FileSync(seg->mdfd_vfd, WAIT_EVENT_DATA_FILE_SYNC) >= 0)
|
||||
{
|
||||
/* Success; update statistics about sync timing */
|
||||
INSTR_TIME_SET_CURRENT(sync_end);
|
||||
@@ -1443,7 +1444,7 @@ register_dirty_segment(SMgrRelation reln, ForkNumber forknum, MdfdVec *seg)
|
||||
ereport(DEBUG1,
|
||||
(errmsg("could not forward fsync request because request queue is full")));
|
||||
|
||||
if (FileSync(seg->mdfd_vfd) < 0)
|
||||
if (FileSync(seg->mdfd_vfd, WAIT_EVENT_DATA_FILE_SYNC) < 0)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not fsync file \"%s\": %m",
|
||||
|
||||
Reference in New Issue
Block a user