PostgreSQL Source Code  git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
md.c File Reference
#include "postgres.h"
#include <unistd.h>
#include <fcntl.h>
#include <sys/file.h>
#include "access/xlogutils.h"
#include "commands/tablespace.h"
#include "common/file_utils.h"
#include "miscadmin.h"
#include "pg_trace.h"
#include "pgstat.h"
#include "storage/bufmgr.h"
#include "storage/fd.h"
#include "storage/md.h"
#include "storage/relfilelocator.h"
#include "storage/smgr.h"
#include "storage/sync.h"
#include "utils/memutils.h"
Include dependency graph for md.c:

Go to the source code of this file.

Data Structures

struct  _MdfdVec
 

Macros

#define INIT_MD_FILETAG(a, xx_rlocator, xx_forknum, xx_segno)
 
#define EXTENSION_FAIL   (1 << 0)
 
#define EXTENSION_RETURN_NULL   (1 << 1)
 
#define EXTENSION_CREATE   (1 << 2)
 
#define EXTENSION_CREATE_RECOVERY   (1 << 3)
 
#define EXTENSION_DONT_CHECK_SIZE   (1 << 4)
 
#define EXTENSION_DONT_OPEN   (1 << 5)
 

Typedefs

typedef struct _MdfdVec MdfdVec
 

Functions

static void mdunlinkfork (RelFileLocatorBackend rlocator, ForkNumber forknum, bool isRedo)
 
static MdfdVecmdopenfork (SMgrRelation reln, ForkNumber forknum, int behavior)
 
static void register_dirty_segment (SMgrRelation reln, ForkNumber forknum, MdfdVec *seg)
 
static void register_unlink_segment (RelFileLocatorBackend rlocator, ForkNumber forknum, BlockNumber segno)
 
static void register_forget_request (RelFileLocatorBackend rlocator, ForkNumber forknum, BlockNumber segno)
 
static void _fdvec_resize (SMgrRelation reln, ForkNumber forknum, int nseg)
 
static char * _mdfd_segpath (SMgrRelation reln, ForkNumber forknum, BlockNumber segno)
 
static MdfdVec_mdfd_openseg (SMgrRelation reln, ForkNumber forknum, BlockNumber segno, int oflags)
 
static MdfdVec_mdfd_getseg (SMgrRelation reln, ForkNumber forknum, BlockNumber blkno, bool skipFsync, int behavior)
 
static BlockNumber _mdnblocks (SMgrRelation reln, ForkNumber forknum, MdfdVec *seg)
 
static int _mdfd_open_flags (void)
 
void mdinit (void)
 
bool mdexists (SMgrRelation reln, ForkNumber forknum)
 
void mdcreate (SMgrRelation reln, ForkNumber forknum, bool isRedo)
 
void mdunlink (RelFileLocatorBackend rlocator, ForkNumber forknum, bool isRedo)
 
static int do_truncate (const char *path)
 
void mdextend (SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, const void *buffer, bool skipFsync)
 
void mdzeroextend (SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, int nblocks, bool skipFsync)
 
void mdopen (SMgrRelation reln)
 
void mdclose (SMgrRelation reln, ForkNumber forknum)
 
bool mdprefetch (SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, int nblocks)
 
static int buffers_to_iovec (struct iovec *iov, void **buffers, int nblocks)
 
uint32 mdmaxcombine (SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum)
 
void mdreadv (SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, void **buffers, BlockNumber nblocks)
 
void mdwritev (SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, const void **buffers, BlockNumber nblocks, bool skipFsync)
 
void mdwriteback (SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, BlockNumber nblocks)
 
BlockNumber mdnblocks (SMgrRelation reln, ForkNumber forknum)
 
void mdtruncate (SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks)
 
void mdregistersync (SMgrRelation reln, ForkNumber forknum)
 
void mdimmedsync (SMgrRelation reln, ForkNumber forknum)
 
void ForgetDatabaseSyncRequests (Oid dbid)
 
void DropRelationFiles (RelFileLocator *delrels, int ndelrels, bool isRedo)
 
int mdsyncfiletag (const FileTag *ftag, char *path)
 
int mdunlinkfiletag (const FileTag *ftag, char *path)
 
bool mdfiletagmatches (const FileTag *ftag, const FileTag *candidate)
 

Variables

static MemoryContext MdCxt
 

Macro Definition Documentation

◆ EXTENSION_CREATE

#define EXTENSION_CREATE   (1 << 2)

Definition at line 106 of file md.c.

◆ EXTENSION_CREATE_RECOVERY

#define EXTENSION_CREATE_RECOVERY   (1 << 3)

Definition at line 108 of file md.c.

◆ EXTENSION_DONT_CHECK_SIZE

#define EXTENSION_DONT_CHECK_SIZE   (1 << 4)

Definition at line 116 of file md.c.

◆ EXTENSION_DONT_OPEN

#define EXTENSION_DONT_OPEN   (1 << 5)

Definition at line 118 of file md.c.

◆ EXTENSION_FAIL

#define EXTENSION_FAIL   (1 << 0)

Definition at line 102 of file md.c.

◆ EXTENSION_RETURN_NULL

#define EXTENSION_RETURN_NULL   (1 << 1)

Definition at line 104 of file md.c.

◆ INIT_MD_FILETAG

#define INIT_MD_FILETAG (   a,
  xx_rlocator,
  xx_forknum,
  xx_segno 
)
Value:
( \
memset(&(a), 0, sizeof(FileTag)), \
(a).handler = SYNC_HANDLER_MD, \
(a).rlocator = (xx_rlocator), \
(a).forknum = (xx_forknum), \
(a).segno = (xx_segno) \
)
int a
Definition: isn.c:68
Definition: sync.h:51
@ SYNC_HANDLER_MD
Definition: sync.h:37

Definition at line 90 of file md.c.

Typedef Documentation

◆ MdfdVec

typedef struct _MdfdVec MdfdVec

Function Documentation

◆ _fdvec_resize()

static void _fdvec_resize ( SMgrRelation  reln,
ForkNumber  forknum,
int  nseg 
)
static

Definition at line 1499 of file md.c.

1502 {
1503  if (nseg == 0)
1504  {
1505  if (reln->md_num_open_segs[forknum] > 0)
1506  {
1507  pfree(reln->md_seg_fds[forknum]);
1508  reln->md_seg_fds[forknum] = NULL;
1509  }
1510  }
1511  else if (reln->md_num_open_segs[forknum] == 0)
1512  {
1513  reln->md_seg_fds[forknum] =
1514  MemoryContextAlloc(MdCxt, sizeof(MdfdVec) * nseg);
1515  }
1516  else
1517  {
1518  /*
1519  * It doesn't seem worthwhile complicating the code to amortize
1520  * repalloc() calls. Those are far faster than PathNameOpenFile() or
1521  * FileClose(), and the memory context internally will sometimes avoid
1522  * doing an actual reallocation.
1523  */
1524  reln->md_seg_fds[forknum] =
1525  repalloc(reln->md_seg_fds[forknum],
1526  sizeof(MdfdVec) * nseg);
1527  }
1528 
1529  reln->md_num_open_segs[forknum] = nseg;
1530 }
void pfree(void *pointer)
Definition: mcxt.c:1521
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1541
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1181
static MemoryContext MdCxt
Definition: md.c:86
int md_num_open_segs[MAX_FORKNUM+1]
Definition: smgr.h:60
struct _MdfdVec * md_seg_fds[MAX_FORKNUM+1]
Definition: smgr.h:61
Definition: md.c:81

References SMgrRelationData::md_num_open_segs, SMgrRelationData::md_seg_fds, MdCxt, MemoryContextAlloc(), pfree(), and repalloc().

Referenced by _mdfd_openseg(), mdclose(), mdcreate(), mdimmedsync(), mdopenfork(), mdregistersync(), and mdtruncate().

◆ _mdfd_getseg()

static MdfdVec * _mdfd_getseg ( SMgrRelation  reln,
ForkNumber  forknum,
BlockNumber  blkno,
bool  skipFsync,
int  behavior 
)
static

Definition at line 1605 of file md.c.

1607 {
1608  MdfdVec *v;
1609  BlockNumber targetseg;
1610  BlockNumber nextsegno;
1611 
1612  /* some way to handle non-existent segments needs to be specified */
1613  Assert(behavior &
1616 
1617  targetseg = blkno / ((BlockNumber) RELSEG_SIZE);
1618 
1619  /* if an existing and opened segment, we're done */
1620  if (targetseg < reln->md_num_open_segs[forknum])
1621  {
1622  v = &reln->md_seg_fds[forknum][targetseg];
1623  return v;
1624  }
1625 
1626  /* The caller only wants the segment if we already had it open. */
1627  if (behavior & EXTENSION_DONT_OPEN)
1628  return NULL;
1629 
1630  /*
1631  * The target segment is not yet open. Iterate over all the segments
1632  * between the last opened and the target segment. This way missing
1633  * segments either raise an error, or get created (according to
1634  * 'behavior'). Start with either the last opened, or the first segment if
1635  * none was opened before.
1636  */
1637  if (reln->md_num_open_segs[forknum] > 0)
1638  v = &reln->md_seg_fds[forknum][reln->md_num_open_segs[forknum] - 1];
1639  else
1640  {
1641  v = mdopenfork(reln, forknum, behavior);
1642  if (!v)
1643  return NULL; /* if behavior & EXTENSION_RETURN_NULL */
1644  }
1645 
1646  for (nextsegno = reln->md_num_open_segs[forknum];
1647  nextsegno <= targetseg; nextsegno++)
1648  {
1649  BlockNumber nblocks = _mdnblocks(reln, forknum, v);
1650  int flags = 0;
1651 
1652  Assert(nextsegno == v->mdfd_segno + 1);
1653 
1654  if (nblocks > ((BlockNumber) RELSEG_SIZE))
1655  elog(FATAL, "segment too big");
1656 
1657  if ((behavior & EXTENSION_CREATE) ||
1658  (InRecovery && (behavior & EXTENSION_CREATE_RECOVERY)))
1659  {
1660  /*
1661  * Normally we will create new segments only if authorized by the
1662  * caller (i.e., we are doing mdextend()). But when doing WAL
1663  * recovery, create segments anyway; this allows cases such as
1664  * replaying WAL data that has a write into a high-numbered
1665  * segment of a relation that was later deleted. We want to go
1666  * ahead and create the segments so we can finish out the replay.
1667  *
1668  * We have to maintain the invariant that segments before the last
1669  * active segment are of size RELSEG_SIZE; therefore, if
1670  * extending, pad them out with zeroes if needed. (This only
1671  * matters if in recovery, or if the caller is extending the
1672  * relation discontiguously, but that can happen in hash indexes.)
1673  */
1674  if (nblocks < ((BlockNumber) RELSEG_SIZE))
1675  {
1676  char *zerobuf = palloc_aligned(BLCKSZ, PG_IO_ALIGN_SIZE,
1677  MCXT_ALLOC_ZERO);
1678 
1679  mdextend(reln, forknum,
1680  nextsegno * ((BlockNumber) RELSEG_SIZE) - 1,
1681  zerobuf, skipFsync);
1682  pfree(zerobuf);
1683  }
1684  flags = O_CREAT;
1685  }
1686  else if (!(behavior & EXTENSION_DONT_CHECK_SIZE) &&
1687  nblocks < ((BlockNumber) RELSEG_SIZE))
1688  {
1689  /*
1690  * When not extending (or explicitly including truncated
1691  * segments), only open the next segment if the current one is
1692  * exactly RELSEG_SIZE. If not (this branch), either return NULL
1693  * or fail.
1694  */
1695  if (behavior & EXTENSION_RETURN_NULL)
1696  {
1697  /*
1698  * Some callers discern between reasons for _mdfd_getseg()
1699  * returning NULL based on errno. As there's no failing
1700  * syscall involved in this case, explicitly set errno to
1701  * ENOENT, as that seems the closest interpretation.
1702  */
1703  errno = ENOENT;
1704  return NULL;
1705  }
1706 
1707  ereport(ERROR,
1709  errmsg("could not open file \"%s\" (target block %u): previous segment is only %u blocks",
1710  _mdfd_segpath(reln, forknum, nextsegno),
1711  blkno, nblocks)));
1712  }
1713 
1714  v = _mdfd_openseg(reln, forknum, nextsegno, flags);
1715 
1716  if (v == NULL)
1717  {
1718  if ((behavior & EXTENSION_RETURN_NULL) &&
1719  FILE_POSSIBLY_DELETED(errno))
1720  return NULL;
1721  ereport(ERROR,
1723  errmsg("could not open file \"%s\" (target block %u): %m",
1724  _mdfd_segpath(reln, forknum, nextsegno),
1725  blkno)));
1726  }
1727  }
1728 
1729  return v;
1730 }
uint32 BlockNumber
Definition: block.h:31
#define Assert(condition)
Definition: c.h:837
int errcode_for_file_access(void)
Definition: elog.c:876
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define FATAL
Definition: elog.h:41
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
#define FILE_POSSIBLY_DELETED(err)
Definition: fd.h:78
#define MCXT_ALLOC_ZERO
Definition: fe_memutils.h:30
void * palloc_aligned(Size size, Size alignto, int flags)
Definition: mcxt.c:1511
#define EXTENSION_CREATE_RECOVERY
Definition: md.c:108
static BlockNumber _mdnblocks(SMgrRelation reln, ForkNumber forknum, MdfdVec *seg)
Definition: md.c:1736
#define EXTENSION_DONT_OPEN
Definition: md.c:118
void mdextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, const void *buffer, bool skipFsync)
Definition: md.c:460
static MdfdVec * _mdfd_openseg(SMgrRelation reln, ForkNumber forknum, BlockNumber segno, int oflags)
Definition: md.c:1560
#define EXTENSION_RETURN_NULL
Definition: md.c:104
static char * _mdfd_segpath(SMgrRelation reln, ForkNumber forknum, BlockNumber segno)
Definition: md.c:1537
#define EXTENSION_CREATE
Definition: md.c:106
#define EXTENSION_DONT_CHECK_SIZE
Definition: md.c:116
#define EXTENSION_FAIL
Definition: md.c:102
static MdfdVec * mdopenfork(SMgrRelation reln, ForkNumber forknum, int behavior)
Definition: md.c:637
#define PG_IO_ALIGN_SIZE
BlockNumber mdfd_segno
Definition: md.c:83
bool InRecovery
Definition: xlogutils.c:50

References _mdfd_openseg(), _mdfd_segpath(), _mdnblocks(), Assert, elog, ereport, errcode_for_file_access(), errmsg(), ERROR, EXTENSION_CREATE, EXTENSION_CREATE_RECOVERY, EXTENSION_DONT_CHECK_SIZE, EXTENSION_DONT_OPEN, EXTENSION_FAIL, EXTENSION_RETURN_NULL, FATAL, FILE_POSSIBLY_DELETED, InRecovery, MCXT_ALLOC_ZERO, SMgrRelationData::md_num_open_segs, SMgrRelationData::md_seg_fds, mdextend(), _MdfdVec::mdfd_segno, mdopenfork(), palloc_aligned(), pfree(), and PG_IO_ALIGN_SIZE.

Referenced by mdextend(), mdprefetch(), mdreadv(), mdwriteback(), mdwritev(), and mdzeroextend().

◆ _mdfd_open_flags()

static int _mdfd_open_flags ( void  )
inlinestatic

Definition at line 144 of file md.c.

145 {
146  int flags = O_RDWR | PG_BINARY;
147 
149  flags |= PG_O_DIRECT;
150 
151  return flags;
152 }
#define PG_BINARY
Definition: c.h:1252
int io_direct_flags
Definition: fd.c:167
#define IO_DIRECT_DATA
Definition: fd.h:54
#define PG_O_DIRECT
Definition: fd.h:97

References IO_DIRECT_DATA, io_direct_flags, PG_BINARY, and PG_O_DIRECT.

Referenced by _mdfd_openseg(), mdcreate(), mdopenfork(), and mdsyncfiletag().

◆ _mdfd_openseg()

static MdfdVec * _mdfd_openseg ( SMgrRelation  reln,
ForkNumber  forknum,
BlockNumber  segno,
int  oflags 
)
static

Definition at line 1560 of file md.c.

1562 {
1563  MdfdVec *v;
1564  File fd;
1565  char *fullpath;
1566 
1567  fullpath = _mdfd_segpath(reln, forknum, segno);
1568 
1569  /* open the file */
1570  fd = PathNameOpenFile(fullpath, _mdfd_open_flags() | oflags);
1571 
1572  pfree(fullpath);
1573 
1574  if (fd < 0)
1575  return NULL;
1576 
1577  /*
1578  * Segments are always opened in order from lowest to highest, so we must
1579  * be adding a new one at the end.
1580  */
1581  Assert(segno == reln->md_num_open_segs[forknum]);
1582 
1583  _fdvec_resize(reln, forknum, segno + 1);
1584 
1585  /* fill the entry */
1586  v = &reln->md_seg_fds[forknum][segno];
1587  v->mdfd_vfd = fd;
1588  v->mdfd_segno = segno;
1589 
1590  Assert(_mdnblocks(reln, forknum, v) <= ((BlockNumber) RELSEG_SIZE));
1591 
1592  /* all done */
1593  return v;
1594 }
File PathNameOpenFile(const char *fileName, int fileFlags)
Definition: fd.c:1574
int File
Definition: fd.h:51
static int _mdfd_open_flags(void)
Definition: md.c:144
static void _fdvec_resize(SMgrRelation reln, ForkNumber forknum, int nseg)
Definition: md.c:1499
static int fd(const char *x, int i)
Definition: preproc-init.c:105
File mdfd_vfd
Definition: md.c:82

References _fdvec_resize(), _mdfd_open_flags(), _mdfd_segpath(), _mdnblocks(), Assert, fd(), SMgrRelationData::md_num_open_segs, SMgrRelationData::md_seg_fds, _MdfdVec::mdfd_segno, _MdfdVec::mdfd_vfd, PathNameOpenFile(), and pfree().

Referenced by _mdfd_getseg(), mdimmedsync(), mdnblocks(), and mdregistersync().

◆ _mdfd_segpath()

static char * _mdfd_segpath ( SMgrRelation  reln,
ForkNumber  forknum,
BlockNumber  segno 
)
static

Definition at line 1537 of file md.c.

1538 {
1539  char *path,
1540  *fullpath;
1541 
1542  path = relpath(reln->smgr_rlocator, forknum);
1543 
1544  if (segno > 0)
1545  {
1546  fullpath = psprintf("%s.%u", path, segno);
1547  pfree(path);
1548  }
1549  else
1550  fullpath = path;
1551 
1552  return fullpath;
1553 }
char * psprintf(const char *fmt,...)
Definition: psprintf.c:43
#define relpath(rlocator, forknum)
Definition: relpath.h:102
RelFileLocatorBackend smgr_rlocator
Definition: smgr.h:37

References pfree(), psprintf(), relpath, and SMgrRelationData::smgr_rlocator.

Referenced by _mdfd_getseg(), _mdfd_openseg(), and mdsyncfiletag().

◆ _mdnblocks()

static BlockNumber _mdnblocks ( SMgrRelation  reln,
ForkNumber  forknum,
MdfdVec seg 
)
static

Definition at line 1736 of file md.c.

1737 {
1738  off_t len;
1739 
1740  len = FileSize(seg->mdfd_vfd);
1741  if (len < 0)
1742  ereport(ERROR,
1744  errmsg("could not seek to end of file \"%s\": %m",
1745  FilePathName(seg->mdfd_vfd))));
1746  /* note that this calculation will ignore any partial block at EOF */
1747  return (BlockNumber) (len / BLCKSZ);
1748 }
char * FilePathName(File file)
Definition: fd.c:2483
off_t FileSize(File file)
Definition: fd.c:2431
const void size_t len

References ereport, errcode_for_file_access(), errmsg(), ERROR, FilePathName(), FileSize(), len, and _MdfdVec::mdfd_vfd.

Referenced by _mdfd_getseg(), _mdfd_openseg(), mdextend(), mdnblocks(), mdopenfork(), and mdzeroextend().

◆ buffers_to_iovec()

static int buffers_to_iovec ( struct iovec *  iov,
void **  buffers,
int  nblocks 
)
static

Definition at line 762 of file md.c.

763 {
764  struct iovec *iovp;
765  int iovcnt;
766 
767  Assert(nblocks >= 1);
768 
769  /* If this build supports direct I/O, buffers must be I/O aligned. */
770  for (int i = 0; i < nblocks; ++i)
771  {
772  if (PG_O_DIRECT != 0 && PG_IO_ALIGN_SIZE <= BLCKSZ)
773  Assert((uintptr_t) buffers[i] ==
774  TYPEALIGN(PG_IO_ALIGN_SIZE, buffers[i]));
775  }
776 
777  /* Start the first iovec off with the first buffer. */
778  iovp = &iov[0];
779  iovp->iov_base = buffers[0];
780  iovp->iov_len = BLCKSZ;
781  iovcnt = 1;
782 
783  /* Try to merge the rest. */
784  for (int i = 1; i < nblocks; ++i)
785  {
786  void *buffer = buffers[i];
787 
788  if (((char *) iovp->iov_base + iovp->iov_len) == buffer)
789  {
790  /* Contiguous with the last iovec. */
791  iovp->iov_len += BLCKSZ;
792  }
793  else
794  {
795  /* Need a new iovec. */
796  iovp++;
797  iovp->iov_base = buffer;
798  iovp->iov_len = BLCKSZ;
799  iovcnt++;
800  }
801  }
802 
803  return iovcnt;
804 }
#define TYPEALIGN(ALIGNVAL, LEN)
Definition: c.h:783
int i
Definition: isn.c:72

References Assert, i, PG_IO_ALIGN_SIZE, PG_O_DIRECT, and TYPEALIGN.

Referenced by mdreadv(), and mdwritev().

◆ do_truncate()

static int do_truncate ( const char *  path)
static

Definition at line 323 of file md.c.

324 {
325  int save_errno;
326  int ret;
327 
328  ret = pg_truncate(path, 0);
329 
330  /* Log a warning here to avoid repetition in callers. */
331  if (ret < 0 && errno != ENOENT)
332  {
333  save_errno = errno;
336  errmsg("could not truncate file \"%s\": %m", path)));
337  errno = save_errno;
338  }
339 
340  return ret;
341 }
#define WARNING
Definition: elog.h:36
int pg_truncate(const char *path, off_t length)
Definition: fd.c:719

References ereport, errcode_for_file_access(), errmsg(), pg_truncate(), and WARNING.

Referenced by mdunlinkfork().

◆ DropRelationFiles()

void DropRelationFiles ( RelFileLocator delrels,
int  ndelrels,
bool  isRedo 
)

Definition at line 1467 of file md.c.

1468 {
1469  SMgrRelation *srels;
1470  int i;
1471 
1472  srels = palloc(sizeof(SMgrRelation) * ndelrels);
1473  for (i = 0; i < ndelrels; i++)
1474  {
1475  SMgrRelation srel = smgropen(delrels[i], INVALID_PROC_NUMBER);
1476 
1477  if (isRedo)
1478  {
1479  ForkNumber fork;
1480 
1481  for (fork = 0; fork <= MAX_FORKNUM; fork++)
1482  XLogDropRelation(delrels[i], fork);
1483  }
1484  srels[i] = srel;
1485  }
1486 
1487  smgrdounlinkall(srels, ndelrels, isRedo);
1488 
1489  for (i = 0; i < ndelrels; i++)
1490  smgrclose(srels[i]);
1491  pfree(srels);
1492 }
void * palloc(Size size)
Definition: mcxt.c:1317
#define INVALID_PROC_NUMBER
Definition: procnumber.h:26
ForkNumber
Definition: relpath.h:56
#define MAX_FORKNUM
Definition: relpath.h:70
SMgrRelation smgropen(RelFileLocator rlocator, ProcNumber backend)
Definition: smgr.c:201
void smgrclose(SMgrRelation reln)
Definition: smgr.c:323
void smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo)
Definition: smgr.c:465
void XLogDropRelation(RelFileLocator rlocator, ForkNumber forknum)
Definition: xlogutils.c:641

References i, INVALID_PROC_NUMBER, MAX_FORKNUM, palloc(), pfree(), smgrclose(), smgrdounlinkall(), smgropen(), and XLogDropRelation().

Referenced by FinishPreparedTransaction(), xact_redo_abort(), and xact_redo_commit().

◆ ForgetDatabaseSyncRequests()

void ForgetDatabaseSyncRequests ( Oid  dbid)

Definition at line 1449 of file md.c.

1450 {
1451  FileTag tag;
1452  RelFileLocator rlocator;
1453 
1454  rlocator.dbOid = dbid;
1455  rlocator.spcOid = 0;
1456  rlocator.relNumber = 0;
1457 
1459 
1460  RegisterSyncRequest(&tag, SYNC_FILTER_REQUEST, true /* retryOnError */ );
1461 }
#define InvalidBlockNumber
Definition: block.h:33
#define INIT_MD_FILETAG(a, xx_rlocator, xx_forknum, xx_segno)
Definition: md.c:90
@ InvalidForkNumber
Definition: relpath.h:57
RelFileNumber relNumber
bool RegisterSyncRequest(const FileTag *ftag, SyncRequestType type, bool retryOnError)
Definition: sync.c:580
@ SYNC_FILTER_REQUEST
Definition: sync.h:28

References RelFileLocator::dbOid, INIT_MD_FILETAG, InvalidBlockNumber, InvalidForkNumber, RegisterSyncRequest(), RelFileLocator::relNumber, RelFileLocator::spcOid, and SYNC_FILTER_REQUEST.

Referenced by createdb_failure_callback(), dbase_redo(), and dropdb().

◆ mdclose()

void mdclose ( SMgrRelation  reln,
ForkNumber  forknum 
)

Definition at line 691 of file md.c.

692 {
693  int nopensegs = reln->md_num_open_segs[forknum];
694 
695  /* No work if already closed */
696  if (nopensegs == 0)
697  return;
698 
699  /* close segments starting from the end */
700  while (nopensegs > 0)
701  {
702  MdfdVec *v = &reln->md_seg_fds[forknum][nopensegs - 1];
703 
704  FileClose(v->mdfd_vfd);
705  _fdvec_resize(reln, forknum, nopensegs - 1);
706  nopensegs--;
707  }
708 }
void FileClose(File file)
Definition: fd.c:1977

References _fdvec_resize(), FileClose(), SMgrRelationData::md_num_open_segs, SMgrRelationData::md_seg_fds, and _MdfdVec::mdfd_vfd.

Referenced by mdexists().

◆ mdcreate()

void mdcreate ( SMgrRelation  reln,
ForkNumber  forknum,
bool  isRedo 
)

Definition at line 190 of file md.c.

191 {
192  MdfdVec *mdfd;
193  char *path;
194  File fd;
195 
196  if (isRedo && reln->md_num_open_segs[forknum] > 0)
197  return; /* created and opened already... */
198 
199  Assert(reln->md_num_open_segs[forknum] == 0);
200 
201  /*
202  * We may be using the target table space for the first time in this
203  * database, so create a per-database subdirectory if needed.
204  *
205  * XXX this is a fairly ugly violation of module layering, but this seems
206  * to be the best place to put the check. Maybe TablespaceCreateDbspace
207  * should be here and not in commands/tablespace.c? But that would imply
208  * importing a lot of stuff that smgr.c oughtn't know, either.
209  */
212  isRedo);
213 
214  path = relpath(reln->smgr_rlocator, forknum);
215 
216  fd = PathNameOpenFile(path, _mdfd_open_flags() | O_CREAT | O_EXCL);
217 
218  if (fd < 0)
219  {
220  int save_errno = errno;
221 
222  if (isRedo)
224  if (fd < 0)
225  {
226  /* be sure to report the error reported by create, not open */
227  errno = save_errno;
228  ereport(ERROR,
230  errmsg("could not create file \"%s\": %m", path)));
231  }
232  }
233 
234  pfree(path);
235 
236  _fdvec_resize(reln, forknum, 1);
237  mdfd = &reln->md_seg_fds[forknum][0];
238  mdfd->mdfd_vfd = fd;
239  mdfd->mdfd_segno = 0;
240 
241  if (!SmgrIsTemp(reln))
242  register_dirty_segment(reln, forknum, mdfd);
243 }
void TablespaceCreateDbspace(Oid spcOid, Oid dbOid, bool isRedo)
Definition: tablespace.c:112
static void register_dirty_segment(SMgrRelation reln, ForkNumber forknum, MdfdVec *seg)
Definition: md.c:1374
#define SmgrIsTemp(smgr)
Definition: smgr.h:73
RelFileLocator locator

References _fdvec_resize(), _mdfd_open_flags(), Assert, RelFileLocator::dbOid, ereport, errcode_for_file_access(), errmsg(), ERROR, fd(), RelFileLocatorBackend::locator, SMgrRelationData::md_num_open_segs, SMgrRelationData::md_seg_fds, _MdfdVec::mdfd_segno, _MdfdVec::mdfd_vfd, PathNameOpenFile(), pfree(), register_dirty_segment(), relpath, SMgrRelationData::smgr_rlocator, SmgrIsTemp, RelFileLocator::spcOid, and TablespaceCreateDbspace().

◆ mdexists()

bool mdexists ( SMgrRelation  reln,
ForkNumber  forknum 
)

Definition at line 171 of file md.c.

172 {
173  /*
174  * Close it first, to ensure that we notice if the fork has been unlinked
175  * since we opened it. As an optimization, we can skip that in recovery,
176  * which already closes relations when dropping them.
177  */
178  if (!InRecovery)
179  mdclose(reln, forknum);
180 
181  return (mdopenfork(reln, forknum, EXTENSION_RETURN_NULL) != NULL);
182 }
void mdclose(SMgrRelation reln, ForkNumber forknum)
Definition: md.c:691

References EXTENSION_RETURN_NULL, InRecovery, mdclose(), and mdopenfork().

◆ mdextend()

void mdextend ( SMgrRelation  reln,
ForkNumber  forknum,
BlockNumber  blocknum,
const void *  buffer,
bool  skipFsync 
)

Definition at line 460 of file md.c.

462 {
463  off_t seekpos;
464  int nbytes;
465  MdfdVec *v;
466 
467  /* If this build supports direct I/O, the buffer must be I/O aligned. */
468  if (PG_O_DIRECT != 0 && PG_IO_ALIGN_SIZE <= BLCKSZ)
469  Assert((uintptr_t) buffer == TYPEALIGN(PG_IO_ALIGN_SIZE, buffer));
470 
471  /* This assert is too expensive to have on normally ... */
472 #ifdef CHECK_WRITE_VS_EXTEND
473  Assert(blocknum >= mdnblocks(reln, forknum));
474 #endif
475 
476  /*
477  * If a relation manages to grow to 2^32-1 blocks, refuse to extend it any
478  * more --- we mustn't create a block whose number actually is
479  * InvalidBlockNumber. (Note that this failure should be unreachable
480  * because of upstream checks in bufmgr.c.)
481  */
482  if (blocknum == InvalidBlockNumber)
483  ereport(ERROR,
484  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
485  errmsg("cannot extend file \"%s\" beyond %u blocks",
486  relpath(reln->smgr_rlocator, forknum),
488 
489  v = _mdfd_getseg(reln, forknum, blocknum, skipFsync, EXTENSION_CREATE);
490 
491  seekpos = (off_t) BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE));
492 
493  Assert(seekpos < (off_t) BLCKSZ * RELSEG_SIZE);
494 
495  if ((nbytes = FileWrite(v->mdfd_vfd, buffer, BLCKSZ, seekpos, WAIT_EVENT_DATA_FILE_EXTEND)) != BLCKSZ)
496  {
497  if (nbytes < 0)
498  ereport(ERROR,
500  errmsg("could not extend file \"%s\": %m",
501  FilePathName(v->mdfd_vfd)),
502  errhint("Check free disk space.")));
503  /* short write: complain appropriately */
504  ereport(ERROR,
505  (errcode(ERRCODE_DISK_FULL),
506  errmsg("could not extend file \"%s\": wrote only %d of %d bytes at block %u",
508  nbytes, BLCKSZ, blocknum),
509  errhint("Check free disk space.")));
510  }
511 
512  if (!skipFsync && !SmgrIsTemp(reln))
513  register_dirty_segment(reln, forknum, v);
514 
515  Assert(_mdnblocks(reln, forknum, v) <= ((BlockNumber) RELSEG_SIZE));
516 }
int errhint(const char *fmt,...)
Definition: elog.c:1317
int errcode(int sqlerrcode)
Definition: elog.c:853
static ssize_t FileWrite(File file, const void *buffer, size_t amount, off_t offset, uint32 wait_event_info)
Definition: fd.h:208
BlockNumber mdnblocks(SMgrRelation reln, ForkNumber forknum)
Definition: md.c:1110
static MdfdVec * _mdfd_getseg(SMgrRelation reln, ForkNumber forknum, BlockNumber blkno, bool skipFsync, int behavior)
Definition: md.c:1605

References _mdfd_getseg(), _mdnblocks(), Assert, ereport, errcode(), errcode_for_file_access(), errhint(), errmsg(), ERROR, EXTENSION_CREATE, FilePathName(), FileWrite(), InvalidBlockNumber, _MdfdVec::mdfd_vfd, mdnblocks(), PG_IO_ALIGN_SIZE, PG_O_DIRECT, register_dirty_segment(), relpath, SMgrRelationData::smgr_rlocator, SmgrIsTemp, and TYPEALIGN.

Referenced by _mdfd_getseg().

◆ mdfiletagmatches()

bool mdfiletagmatches ( const FileTag ftag,
const FileTag candidate 
)

Definition at line 1829 of file md.c.

1830 {
1831  /*
1832  * For now we only use filter requests as a way to drop all scheduled
1833  * callbacks relating to a given database, when dropping the database.
1834  * We'll return true for all candidates that have the same database OID as
1835  * the ftag from the SYNC_FILTER_REQUEST request, so they're forgotten.
1836  */
1837  return ftag->rlocator.dbOid == candidate->rlocator.dbOid;
1838 }
RelFileLocator rlocator
Definition: sync.h:54

References RelFileLocator::dbOid, and FileTag::rlocator.

◆ mdimmedsync()

void mdimmedsync ( SMgrRelation  reln,
ForkNumber  forknum 
)

Definition at line 1312 of file md.c.

1313 {
1314  int segno;
1315  int min_inactive_seg;
1316 
1317  /*
1318  * NOTE: mdnblocks makes sure we have opened all active segments, so that
1319  * the loop below will get them all!
1320  */
1321  mdnblocks(reln, forknum);
1322 
1323  min_inactive_seg = segno = reln->md_num_open_segs[forknum];
1324 
1325  /*
1326  * Temporarily open inactive segments, then close them after sync. There
1327  * may be some inactive segments left opened after fsync() error, but that
1328  * is harmless. We don't bother to clean them up and take a risk of
1329  * further trouble. The next mdclose() will soon close them.
1330  */
1331  while (_mdfd_openseg(reln, forknum, segno, 0) != NULL)
1332  segno++;
1333 
1334  while (segno > 0)
1335  {
1336  MdfdVec *v = &reln->md_seg_fds[forknum][segno - 1];
1337 
1338  /*
1339  * fsyncs done through mdimmedsync() should be tracked in a separate
1340  * IOContext than those done through mdsyncfiletag() to differentiate
1341  * between unavoidable client backend fsyncs (e.g. those done during
1342  * index build) and those which ideally would have been done by the
1343  * checkpointer. Since other IO operations bypassing the buffer
1344  * manager could also be tracked in such an IOContext, wait until
1345  * these are also tracked to track immediate fsyncs.
1346  */
1347  if (FileSync(v->mdfd_vfd, WAIT_EVENT_DATA_FILE_IMMEDIATE_SYNC) < 0)
1350  errmsg("could not fsync file \"%s\": %m",
1351  FilePathName(v->mdfd_vfd))));
1352 
1353  /* Close inactive segments immediately */
1354  if (segno > min_inactive_seg)
1355  {
1356  FileClose(v->mdfd_vfd);
1357  _fdvec_resize(reln, forknum, segno - 1);
1358  }
1359 
1360  segno--;
1361  }
1362 }
int FileSync(File file, uint32 wait_event_info)
Definition: fd.c:2319
int data_sync_elevel(int elevel)
Definition: fd.c:3959

References _fdvec_resize(), _mdfd_openseg(), data_sync_elevel(), ereport, errcode_for_file_access(), errmsg(), ERROR, FileClose(), FilePathName(), FileSync(), SMgrRelationData::md_num_open_segs, SMgrRelationData::md_seg_fds, _MdfdVec::mdfd_vfd, and mdnblocks().

◆ mdinit()

void mdinit ( void  )

Definition at line 158 of file md.c.

159 {
161  "MdSmgr",
163 }
MemoryContext TopMemoryContext
Definition: mcxt.c:149
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, MdCxt, and TopMemoryContext.

◆ mdmaxcombine()

uint32 mdmaxcombine ( SMgrRelation  reln,
ForkNumber  forknum,
BlockNumber  blocknum 
)

Definition at line 811 of file md.c.

813 {
814  BlockNumber segoff;
815 
816  segoff = blocknum % ((BlockNumber) RELSEG_SIZE);
817 
818  return RELSEG_SIZE - segoff;
819 }

◆ mdnblocks()

BlockNumber mdnblocks ( SMgrRelation  reln,
ForkNumber  forknum 
)

Definition at line 1110 of file md.c.

1111 {
1112  MdfdVec *v;
1113  BlockNumber nblocks;
1114  BlockNumber segno;
1115 
1116  mdopenfork(reln, forknum, EXTENSION_FAIL);
1117 
1118  /* mdopen has opened the first segment */
1119  Assert(reln->md_num_open_segs[forknum] > 0);
1120 
1121  /*
1122  * Start from the last open segments, to avoid redundant seeks. We have
1123  * previously verified that these segments are exactly RELSEG_SIZE long,
1124  * and it's useless to recheck that each time.
1125  *
1126  * NOTE: this assumption could only be wrong if another backend has
1127  * truncated the relation. We rely on higher code levels to handle that
1128  * scenario by closing and re-opening the md fd, which is handled via
1129  * relcache flush. (Since the checkpointer doesn't participate in
1130  * relcache flush, it could have segment entries for inactive segments;
1131  * that's OK because the checkpointer never needs to compute relation
1132  * size.)
1133  */
1134  segno = reln->md_num_open_segs[forknum] - 1;
1135  v = &reln->md_seg_fds[forknum][segno];
1136 
1137  for (;;)
1138  {
1139  nblocks = _mdnblocks(reln, forknum, v);
1140  if (nblocks > ((BlockNumber) RELSEG_SIZE))
1141  elog(FATAL, "segment too big");
1142  if (nblocks < ((BlockNumber) RELSEG_SIZE))
1143  return (segno * ((BlockNumber) RELSEG_SIZE)) + nblocks;
1144 
1145  /*
1146  * If segment is exactly RELSEG_SIZE, advance to next one.
1147  */
1148  segno++;
1149 
1150  /*
1151  * We used to pass O_CREAT here, but that has the disadvantage that it
1152  * might create a segment which has vanished through some operating
1153  * system misadventure. In such a case, creating the segment here
1154  * undermines _mdfd_getseg's attempts to notice and report an error
1155  * upon access to a missing segment.
1156  */
1157  v = _mdfd_openseg(reln, forknum, segno, 0);
1158  if (v == NULL)
1159  return segno * ((BlockNumber) RELSEG_SIZE);
1160  }
1161 }

References _mdfd_openseg(), _mdnblocks(), Assert, elog, EXTENSION_FAIL, FATAL, SMgrRelationData::md_num_open_segs, SMgrRelationData::md_seg_fds, and mdopenfork().

Referenced by mdextend(), mdimmedsync(), mdregistersync(), mdtruncate(), mdwritev(), and mdzeroextend().

◆ mdopen()

void mdopen ( SMgrRelation  reln)

Definition at line 680 of file md.c.

681 {
682  /* mark it not open */
683  for (int forknum = 0; forknum <= MAX_FORKNUM; forknum++)
684  reln->md_num_open_segs[forknum] = 0;
685 }

References MAX_FORKNUM, and SMgrRelationData::md_num_open_segs.

◆ mdopenfork()

static MdfdVec * mdopenfork ( SMgrRelation  reln,
ForkNumber  forknum,
int  behavior 
)
static

Definition at line 637 of file md.c.

638 {
639  MdfdVec *mdfd;
640  char *path;
641  File fd;
642 
643  /* No work if already open */
644  if (reln->md_num_open_segs[forknum] > 0)
645  return &reln->md_seg_fds[forknum][0];
646 
647  path = relpath(reln->smgr_rlocator, forknum);
648 
650 
651  if (fd < 0)
652  {
653  if ((behavior & EXTENSION_RETURN_NULL) &&
654  FILE_POSSIBLY_DELETED(errno))
655  {
656  pfree(path);
657  return NULL;
658  }
659  ereport(ERROR,
661  errmsg("could not open file \"%s\": %m", path)));
662  }
663 
664  pfree(path);
665 
666  _fdvec_resize(reln, forknum, 1);
667  mdfd = &reln->md_seg_fds[forknum][0];
668  mdfd->mdfd_vfd = fd;
669  mdfd->mdfd_segno = 0;
670 
671  Assert(_mdnblocks(reln, forknum, mdfd) <= ((BlockNumber) RELSEG_SIZE));
672 
673  return mdfd;
674 }

References _fdvec_resize(), _mdfd_open_flags(), _mdnblocks(), Assert, ereport, errcode_for_file_access(), errmsg(), ERROR, EXTENSION_RETURN_NULL, fd(), FILE_POSSIBLY_DELETED, SMgrRelationData::md_num_open_segs, SMgrRelationData::md_seg_fds, _MdfdVec::mdfd_segno, _MdfdVec::mdfd_vfd, PathNameOpenFile(), pfree(), relpath, and SMgrRelationData::smgr_rlocator.

Referenced by _mdfd_getseg(), mdexists(), and mdnblocks().

◆ mdprefetch()

bool mdprefetch ( SMgrRelation  reln,
ForkNumber  forknum,
BlockNumber  blocknum,
int  nblocks 
)

Definition at line 714 of file md.c.

716 {
717 #ifdef USE_PREFETCH
718 
720 
721  if ((uint64) blocknum + nblocks > (uint64) MaxBlockNumber + 1)
722  return false;
723 
724  while (nblocks > 0)
725  {
726  off_t seekpos;
727  MdfdVec *v;
728  int nblocks_this_segment;
729 
730  v = _mdfd_getseg(reln, forknum, blocknum, false,
732  if (v == NULL)
733  return false;
734 
735  seekpos = (off_t) BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE));
736 
737  Assert(seekpos < (off_t) BLCKSZ * RELSEG_SIZE);
738 
739  nblocks_this_segment =
740  Min(nblocks,
741  RELSEG_SIZE - (blocknum % ((BlockNumber) RELSEG_SIZE)));
742 
743  (void) FilePrefetch(v->mdfd_vfd, seekpos, BLCKSZ * nblocks_this_segment,
744  WAIT_EVENT_DATA_FILE_PREFETCH);
745 
746  blocknum += nblocks_this_segment;
747  nblocks -= nblocks_this_segment;
748  }
749 #endif /* USE_PREFETCH */
750 
751  return true;
752 }
#define MaxBlockNumber
Definition: block.h:35
#define Min(x, y)
Definition: c.h:983
int FilePrefetch(File file, off_t offset, off_t amount, uint32 wait_event_info)
Definition: fd.c:2076

References _mdfd_getseg(), Assert, EXTENSION_FAIL, EXTENSION_RETURN_NULL, FilePrefetch(), InRecovery, IO_DIRECT_DATA, io_direct_flags, MaxBlockNumber, _MdfdVec::mdfd_vfd, and Min.

◆ mdreadv()

void mdreadv ( SMgrRelation  reln,
ForkNumber  forknum,
BlockNumber  blocknum,
void **  buffers,
BlockNumber  nblocks 
)

Definition at line 825 of file md.c.

827 {
828  while (nblocks > 0)
829  {
830  struct iovec iov[PG_IOV_MAX];
831  int iovcnt;
832  off_t seekpos;
833  int nbytes;
834  MdfdVec *v;
835  BlockNumber nblocks_this_segment;
836  size_t transferred_this_segment;
837  size_t size_this_segment;
838 
839  v = _mdfd_getseg(reln, forknum, blocknum, false,
841 
842  seekpos = (off_t) BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE));
843 
844  Assert(seekpos < (off_t) BLCKSZ * RELSEG_SIZE);
845 
846  nblocks_this_segment =
847  Min(nblocks,
848  RELSEG_SIZE - (blocknum % ((BlockNumber) RELSEG_SIZE)));
849  nblocks_this_segment = Min(nblocks_this_segment, lengthof(iov));
850 
851  if (nblocks_this_segment != nblocks)
852  elog(ERROR, "read crosses segment boundary");
853 
854  iovcnt = buffers_to_iovec(iov, buffers, nblocks_this_segment);
855  size_this_segment = nblocks_this_segment * BLCKSZ;
856  transferred_this_segment = 0;
857 
858  /*
859  * Inner loop to continue after a short read. We'll keep going until
860  * we hit EOF rather than assuming that a short read means we hit the
861  * end.
862  */
863  for (;;)
864  {
865  TRACE_POSTGRESQL_SMGR_MD_READ_START(forknum, blocknum,
869  reln->smgr_rlocator.backend);
870  nbytes = FileReadV(v->mdfd_vfd, iov, iovcnt, seekpos,
871  WAIT_EVENT_DATA_FILE_READ);
872  TRACE_POSTGRESQL_SMGR_MD_READ_DONE(forknum, blocknum,
876  reln->smgr_rlocator.backend,
877  nbytes,
878  size_this_segment - transferred_this_segment);
879 
880 #ifdef SIMULATE_SHORT_READ
881  nbytes = Min(nbytes, 4096);
882 #endif
883 
884  if (nbytes < 0)
885  ereport(ERROR,
887  errmsg("could not read blocks %u..%u in file \"%s\": %m",
888  blocknum,
889  blocknum + nblocks_this_segment - 1,
890  FilePathName(v->mdfd_vfd))));
891 
892  if (nbytes == 0)
893  {
894  /*
895  * We are at or past EOF, or we read a partial block at EOF.
896  * Normally this is an error; upper levels should never try to
897  * read a nonexistent block. However, if zero_damaged_pages
898  * is ON or we are InRecovery, we should instead return zeroes
899  * without complaining. This allows, for example, the case of
900  * trying to update a block that was later truncated away.
901  */
903  {
904  for (BlockNumber i = transferred_this_segment / BLCKSZ;
905  i < nblocks_this_segment;
906  ++i)
907  memset(buffers[i], 0, BLCKSZ);
908  break;
909  }
910  else
911  ereport(ERROR,
913  errmsg("could not read blocks %u..%u in file \"%s\": read only %zu of %zu bytes",
914  blocknum,
915  blocknum + nblocks_this_segment - 1,
917  transferred_this_segment,
918  size_this_segment)));
919  }
920 
921  /* One loop should usually be enough. */
922  transferred_this_segment += nbytes;
923  Assert(transferred_this_segment <= size_this_segment);
924  if (transferred_this_segment == size_this_segment)
925  break;
926 
927  /* Adjust position and vectors after a short read. */
928  seekpos += nbytes;
929  iovcnt = compute_remaining_iovec(iov, iov, iovcnt, nbytes);
930  }
931 
932  nblocks -= nblocks_this_segment;
933  buffers += nblocks_this_segment;
934  blocknum += nblocks_this_segment;
935  }
936 }
bool zero_damaged_pages
Definition: bufmgr.c:140
#define lengthof(array)
Definition: c.h:767
ssize_t FileReadV(File file, const struct iovec *iov, int iovcnt, off_t offset, uint32 wait_event_info)
Definition: fd.c:2158
int compute_remaining_iovec(struct iovec *destination, const struct iovec *source, int iovcnt, size_t transferred)
Definition: file_utils.c:593
static int buffers_to_iovec(struct iovec *iov, void **buffers, int nblocks)
Definition: md.c:762
#define ERRCODE_DATA_CORRUPTED
Definition: pg_basebackup.c:41
#define PG_IOV_MAX
Definition: pg_iovec.h:37

References _mdfd_getseg(), Assert, RelFileLocatorBackend::backend, buffers_to_iovec(), compute_remaining_iovec(), RelFileLocator::dbOid, elog, ereport, errcode(), ERRCODE_DATA_CORRUPTED, errcode_for_file_access(), errmsg(), ERROR, EXTENSION_CREATE_RECOVERY, EXTENSION_FAIL, FilePathName(), FileReadV(), i, InRecovery, lengthof, RelFileLocatorBackend::locator, _MdfdVec::mdfd_vfd, Min, PG_IOV_MAX, RelFileLocator::relNumber, SMgrRelationData::smgr_rlocator, RelFileLocator::spcOid, and zero_damaged_pages.

◆ mdregistersync()

void mdregistersync ( SMgrRelation  reln,
ForkNumber  forknum 
)

Definition at line 1261 of file md.c.

1262 {
1263  int segno;
1264  int min_inactive_seg;
1265 
1266  /*
1267  * NOTE: mdnblocks makes sure we have opened all active segments, so that
1268  * the loop below will get them all!
1269  */
1270  mdnblocks(reln, forknum);
1271 
1272  min_inactive_seg = segno = reln->md_num_open_segs[forknum];
1273 
1274  /*
1275  * Temporarily open inactive segments, then close them after sync. There
1276  * may be some inactive segments left opened after error, but that is
1277  * harmless. We don't bother to clean them up and take a risk of further
1278  * trouble. The next mdclose() will soon close them.
1279  */
1280  while (_mdfd_openseg(reln, forknum, segno, 0) != NULL)
1281  segno++;
1282 
1283  while (segno > 0)
1284  {
1285  MdfdVec *v = &reln->md_seg_fds[forknum][segno - 1];
1286 
1287  register_dirty_segment(reln, forknum, v);
1288 
1289  /* Close inactive segments immediately */
1290  if (segno > min_inactive_seg)
1291  {
1292  FileClose(v->mdfd_vfd);
1293  _fdvec_resize(reln, forknum, segno - 1);
1294  }
1295 
1296  segno--;
1297  }
1298 }

References _fdvec_resize(), _mdfd_openseg(), FileClose(), SMgrRelationData::md_num_open_segs, SMgrRelationData::md_seg_fds, _MdfdVec::mdfd_vfd, mdnblocks(), and register_dirty_segment().

◆ mdsyncfiletag()

int mdsyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 1757 of file md.c.

1758 {
1760  File file;
1761  instr_time io_start;
1762  bool need_to_close;
1763  int result,
1764  save_errno;
1765 
1766  /* See if we already have the file open, or need to open it. */
1767  if (ftag->segno < reln->md_num_open_segs[ftag->forknum])
1768  {
1769  file = reln->md_seg_fds[ftag->forknum][ftag->segno].mdfd_vfd;
1770  strlcpy(path, FilePathName(file), MAXPGPATH);
1771  need_to_close = false;
1772  }
1773  else
1774  {
1775  char *p;
1776 
1777  p = _mdfd_segpath(reln, ftag->forknum, ftag->segno);
1778  strlcpy(path, p, MAXPGPATH);
1779  pfree(p);
1780 
1781  file = PathNameOpenFile(path, _mdfd_open_flags());
1782  if (file < 0)
1783  return -1;
1784  need_to_close = true;
1785  }
1786 
1788 
1789  /* Sync the file. */
1790  result = FileSync(file, WAIT_EVENT_DATA_FILE_SYNC);
1791  save_errno = errno;
1792 
1793  if (need_to_close)
1794  FileClose(file);
1795 
1797  IOOP_FSYNC, io_start, 1);
1798 
1799  errno = save_errno;
1800  return result;
1801 }
bool track_io_timing
Definition: bufmgr.c:143
#define MAXPGPATH
@ IOOBJECT_RELATION
Definition: pgstat.h:314
@ IOCONTEXT_NORMAL
Definition: pgstat.h:324
@ IOOP_FSYNC
Definition: pgstat.h:334
instr_time pgstat_prepare_io_time(bool track_io_guc)
Definition: pgstat_io.c:100
void pgstat_count_io_op_time(IOObject io_object, IOContext io_context, IOOp io_op, instr_time start_time, uint32 cnt)
Definition: pgstat_io.c:122
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
int16 forknum
Definition: sync.h:53
uint64 segno
Definition: sync.h:55

References _mdfd_open_flags(), _mdfd_segpath(), FileClose(), FilePathName(), FileSync(), FileTag::forknum, INVALID_PROC_NUMBER, IOCONTEXT_NORMAL, IOOBJECT_RELATION, IOOP_FSYNC, MAXPGPATH, SMgrRelationData::md_num_open_segs, SMgrRelationData::md_seg_fds, _MdfdVec::mdfd_vfd, PathNameOpenFile(), pfree(), pgstat_count_io_op_time(), pgstat_prepare_io_time(), FileTag::rlocator, FileTag::segno, smgropen(), strlcpy(), and track_io_timing.

◆ mdtruncate()

void mdtruncate ( SMgrRelation  reln,
ForkNumber  forknum,
BlockNumber  nblocks 
)

Definition at line 1167 of file md.c.

1168 {
1169  BlockNumber curnblk;
1170  BlockNumber priorblocks;
1171  int curopensegs;
1172 
1173  /*
1174  * NOTE: mdnblocks makes sure we have opened all active segments, so that
1175  * truncation loop will get them all!
1176  */
1177  curnblk = mdnblocks(reln, forknum);
1178  if (nblocks > curnblk)
1179  {
1180  /* Bogus request ... but no complaint if InRecovery */
1181  if (InRecovery)
1182  return;
1183  ereport(ERROR,
1184  (errmsg("could not truncate file \"%s\" to %u blocks: it's only %u blocks now",
1185  relpath(reln->smgr_rlocator, forknum),
1186  nblocks, curnblk)));
1187  }
1188  if (nblocks == curnblk)
1189  return; /* no work */
1190 
1191  /*
1192  * Truncate segments, starting at the last one. Starting at the end makes
1193  * managing the memory for the fd array easier, should there be errors.
1194  */
1195  curopensegs = reln->md_num_open_segs[forknum];
1196  while (curopensegs > 0)
1197  {
1198  MdfdVec *v;
1199 
1200  priorblocks = (curopensegs - 1) * RELSEG_SIZE;
1201 
1202  v = &reln->md_seg_fds[forknum][curopensegs - 1];
1203 
1204  if (priorblocks > nblocks)
1205  {
1206  /*
1207  * This segment is no longer active. We truncate the file, but do
1208  * not delete it, for reasons explained in the header comments.
1209  */
1210  if (FileTruncate(v->mdfd_vfd, 0, WAIT_EVENT_DATA_FILE_TRUNCATE) < 0)
1211  ereport(ERROR,
1213  errmsg("could not truncate file \"%s\": %m",
1214  FilePathName(v->mdfd_vfd))));
1215 
1216  if (!SmgrIsTemp(reln))
1217  register_dirty_segment(reln, forknum, v);
1218 
1219  /* we never drop the 1st segment */
1220  Assert(v != &reln->md_seg_fds[forknum][0]);
1221 
1222  FileClose(v->mdfd_vfd);
1223  _fdvec_resize(reln, forknum, curopensegs - 1);
1224  }
1225  else if (priorblocks + ((BlockNumber) RELSEG_SIZE) > nblocks)
1226  {
1227  /*
1228  * This is the last segment we want to keep. Truncate the file to
1229  * the right length. NOTE: if nblocks is exactly a multiple K of
1230  * RELSEG_SIZE, we will truncate the K+1st segment to 0 length but
1231  * keep it. This adheres to the invariant given in the header
1232  * comments.
1233  */
1234  BlockNumber lastsegblocks = nblocks - priorblocks;
1235 
1236  if (FileTruncate(v->mdfd_vfd, (off_t) lastsegblocks * BLCKSZ, WAIT_EVENT_DATA_FILE_TRUNCATE) < 0)
1237  ereport(ERROR,
1239  errmsg("could not truncate file \"%s\" to %u blocks: %m",
1240  FilePathName(v->mdfd_vfd),
1241  nblocks)));
1242  if (!SmgrIsTemp(reln))
1243  register_dirty_segment(reln, forknum, v);
1244  }
1245  else
1246  {
1247  /*
1248  * We still need this segment, so nothing to do for this and any
1249  * earlier segment.
1250  */
1251  break;
1252  }
1253  curopensegs--;
1254  }
1255 }
int FileTruncate(File file, off_t offset, uint32 wait_event_info)
Definition: fd.c:2448

References _fdvec_resize(), Assert, ereport, errcode_for_file_access(), errmsg(), ERROR, FileClose(), FilePathName(), FileTruncate(), InRecovery, SMgrRelationData::md_num_open_segs, SMgrRelationData::md_seg_fds, _MdfdVec::mdfd_vfd, mdnblocks(), register_dirty_segment(), relpath, SMgrRelationData::smgr_rlocator, and SmgrIsTemp.

◆ mdunlink()

void mdunlink ( RelFileLocatorBackend  rlocator,
ForkNumber  forknum,
bool  isRedo 
)

Definition at line 307 of file md.c.

308 {
309  /* Now do the per-fork work */
310  if (forknum == InvalidForkNumber)
311  {
312  for (forknum = 0; forknum <= MAX_FORKNUM; forknum++)
313  mdunlinkfork(rlocator, forknum, isRedo);
314  }
315  else
316  mdunlinkfork(rlocator, forknum, isRedo);
317 }
static void mdunlinkfork(RelFileLocatorBackend rlocator, ForkNumber forknum, bool isRedo)
Definition: md.c:344

References InvalidForkNumber, MAX_FORKNUM, and mdunlinkfork().

◆ mdunlinkfiletag()

int mdunlinkfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 1810 of file md.c.

1811 {
1812  char *p;
1813 
1814  /* Compute the path. */
1815  p = relpathperm(ftag->rlocator, MAIN_FORKNUM);
1816  strlcpy(path, p, MAXPGPATH);
1817  pfree(p);
1818 
1819  /* Try to unlink the file. */
1820  return unlink(path);
1821 }
@ MAIN_FORKNUM
Definition: relpath.h:58
#define relpathperm(rlocator, forknum)
Definition: relpath.h:98

References MAIN_FORKNUM, MAXPGPATH, pfree(), relpathperm, FileTag::rlocator, and strlcpy().

◆ mdunlinkfork()

static void mdunlinkfork ( RelFileLocatorBackend  rlocator,
ForkNumber  forknum,
bool  isRedo 
)
static

Definition at line 344 of file md.c.

345 {
346  char *path;
347  int ret;
348  int save_errno;
349 
350  path = relpath(rlocator, forknum);
351 
352  /*
353  * Truncate and then unlink the first segment, or just register a request
354  * to unlink it later, as described in the comments for mdunlink().
355  */
356  if (isRedo || IsBinaryUpgrade || forknum != MAIN_FORKNUM ||
357  RelFileLocatorBackendIsTemp(rlocator))
358  {
359  if (!RelFileLocatorBackendIsTemp(rlocator))
360  {
361  /* Prevent other backends' fds from holding on to the disk space */
362  ret = do_truncate(path);
363 
364  /* Forget any pending sync requests for the first segment */
365  save_errno = errno;
366  register_forget_request(rlocator, forknum, 0 /* first seg */ );
367  errno = save_errno;
368  }
369  else
370  ret = 0;
371 
372  /* Next unlink the file, unless it was already found to be missing */
373  if (ret >= 0 || errno != ENOENT)
374  {
375  ret = unlink(path);
376  if (ret < 0 && errno != ENOENT)
377  {
378  save_errno = errno;
381  errmsg("could not remove file \"%s\": %m", path)));
382  errno = save_errno;
383  }
384  }
385  }
386  else
387  {
388  /* Prevent other backends' fds from holding on to the disk space */
389  ret = do_truncate(path);
390 
391  /* Register request to unlink first segment later */
392  save_errno = errno;
393  register_unlink_segment(rlocator, forknum, 0 /* first seg */ );
394  errno = save_errno;
395  }
396 
397  /*
398  * Delete any additional segments.
399  *
400  * Note that because we loop until getting ENOENT, we will correctly
401  * remove all inactive segments as well as active ones. Ideally we'd
402  * continue the loop until getting exactly that errno, but that risks an
403  * infinite loop if the problem is directory-wide (for instance, if we
404  * suddenly can't read the data directory itself). We compromise by
405  * continuing after a non-ENOENT truncate error, but stopping after any
406  * unlink error. If there is indeed a directory-wide problem, additional
407  * unlink attempts wouldn't work anyway.
408  */
409  if (ret >= 0 || errno != ENOENT)
410  {
411  char *segpath = (char *) palloc(strlen(path) + 12);
412  BlockNumber segno;
413 
414  for (segno = 1;; segno++)
415  {
416  sprintf(segpath, "%s.%u", path, segno);
417 
418  if (!RelFileLocatorBackendIsTemp(rlocator))
419  {
420  /*
421  * Prevent other backends' fds from holding on to the disk
422  * space. We're done if we see ENOENT, though.
423  */
424  if (do_truncate(segpath) < 0 && errno == ENOENT)
425  break;
426 
427  /*
428  * Forget any pending sync requests for this segment before we
429  * try to unlink.
430  */
431  register_forget_request(rlocator, forknum, segno);
432  }
433 
434  if (unlink(segpath) < 0)
435  {
436  /* ENOENT is expected after the last segment... */
437  if (errno != ENOENT)
440  errmsg("could not remove file \"%s\": %m", segpath)));
441  break;
442  }
443  }
444  pfree(segpath);
445  }
446 
447  pfree(path);
448 }
bool IsBinaryUpgrade
Definition: globals.c:120
static void register_forget_request(RelFileLocatorBackend rlocator, ForkNumber forknum, BlockNumber segno)
Definition: md.c:1435
static void register_unlink_segment(RelFileLocatorBackend rlocator, ForkNumber forknum, BlockNumber segno)
Definition: md.c:1418
static int do_truncate(const char *path)
Definition: md.c:323
#define sprintf
Definition: port.h:240
#define RelFileLocatorBackendIsTemp(rlocator)

References do_truncate(), ereport, errcode_for_file_access(), errmsg(), IsBinaryUpgrade, MAIN_FORKNUM, palloc(), pfree(), register_forget_request(), register_unlink_segment(), RelFileLocatorBackendIsTemp, relpath, sprintf, and WARNING.

Referenced by mdunlink().

◆ mdwriteback()

void mdwriteback ( SMgrRelation  reln,
ForkNumber  forknum,
BlockNumber  blocknum,
BlockNumber  nblocks 
)

Definition at line 1051 of file md.c.

1053 {
1055 
1056  /*
1057  * Issue flush requests in as few requests as possible; have to split at
1058  * segment boundaries though, since those are actually separate files.
1059  */
1060  while (nblocks > 0)
1061  {
1062  BlockNumber nflush = nblocks;
1063  off_t seekpos;
1064  MdfdVec *v;
1065  int segnum_start,
1066  segnum_end;
1067 
1068  v = _mdfd_getseg(reln, forknum, blocknum, true /* not used */ ,
1070 
1071  /*
1072  * We might be flushing buffers of already removed relations, that's
1073  * ok, just ignore that case. If the segment file wasn't open already
1074  * (ie from a recent mdwrite()), then we don't want to re-open it, to
1075  * avoid a race with PROCSIGNAL_BARRIER_SMGRRELEASE that might leave
1076  * us with a descriptor to a file that is about to be unlinked.
1077  */
1078  if (!v)
1079  return;
1080 
1081  /* compute offset inside the current segment */
1082  segnum_start = blocknum / RELSEG_SIZE;
1083 
1084  /* compute number of desired writes within the current segment */
1085  segnum_end = (blocknum + nblocks - 1) / RELSEG_SIZE;
1086  if (segnum_start != segnum_end)
1087  nflush = RELSEG_SIZE - (blocknum % ((BlockNumber) RELSEG_SIZE));
1088 
1089  Assert(nflush >= 1);
1090  Assert(nflush <= nblocks);
1091 
1092  seekpos = (off_t) BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE));
1093 
1094  FileWriteback(v->mdfd_vfd, seekpos, (off_t) BLCKSZ * nflush, WAIT_EVENT_DATA_FILE_FLUSH);
1095 
1096  nblocks -= nflush;
1097  blocknum += nflush;
1098  }
1099 }
void FileWriteback(File file, off_t offset, off_t nbytes, uint32 wait_event_info)
Definition: fd.c:2132

References _mdfd_getseg(), Assert, EXTENSION_DONT_OPEN, FileWriteback(), IO_DIRECT_DATA, io_direct_flags, and _MdfdVec::mdfd_vfd.

◆ mdwritev()

void mdwritev ( SMgrRelation  reln,
ForkNumber  forknum,
BlockNumber  blocknum,
const void **  buffers,
BlockNumber  nblocks,
bool  skipFsync 
)

Definition at line 946 of file md.c.

948 {
949  /* This assert is too expensive to have on normally ... */
950 #ifdef CHECK_WRITE_VS_EXTEND
951  Assert((uint64) blocknum + (uint64) nblocks <= (uint64) mdnblocks(reln, forknum));
952 #endif
953 
954  while (nblocks > 0)
955  {
956  struct iovec iov[PG_IOV_MAX];
957  int iovcnt;
958  off_t seekpos;
959  int nbytes;
960  MdfdVec *v;
961  BlockNumber nblocks_this_segment;
962  size_t transferred_this_segment;
963  size_t size_this_segment;
964 
965  v = _mdfd_getseg(reln, forknum, blocknum, skipFsync,
967 
968  seekpos = (off_t) BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE));
969 
970  Assert(seekpos < (off_t) BLCKSZ * RELSEG_SIZE);
971 
972  nblocks_this_segment =
973  Min(nblocks,
974  RELSEG_SIZE - (blocknum % ((BlockNumber) RELSEG_SIZE)));
975  nblocks_this_segment = Min(nblocks_this_segment, lengthof(iov));
976 
977  if (nblocks_this_segment != nblocks)
978  elog(ERROR, "write crosses segment boundary");
979 
980  iovcnt = buffers_to_iovec(iov, (void **) buffers, nblocks_this_segment);
981  size_this_segment = nblocks_this_segment * BLCKSZ;
982  transferred_this_segment = 0;
983 
984  /*
985  * Inner loop to continue after a short write. If the reason is that
986  * we're out of disk space, a future attempt should get an ENOSPC
987  * error from the kernel.
988  */
989  for (;;)
990  {
991  TRACE_POSTGRESQL_SMGR_MD_WRITE_START(forknum, blocknum,
995  reln->smgr_rlocator.backend);
996  nbytes = FileWriteV(v->mdfd_vfd, iov, iovcnt, seekpos,
997  WAIT_EVENT_DATA_FILE_WRITE);
998  TRACE_POSTGRESQL_SMGR_MD_WRITE_DONE(forknum, blocknum,
1000  reln->smgr_rlocator.locator.dbOid,
1002  reln->smgr_rlocator.backend,
1003  nbytes,
1004  size_this_segment - transferred_this_segment);
1005 
1006 #ifdef SIMULATE_SHORT_WRITE
1007  nbytes = Min(nbytes, 4096);
1008 #endif
1009 
1010  if (nbytes < 0)
1011  {
1012  bool enospc = errno == ENOSPC;
1013 
1014  ereport(ERROR,
1016  errmsg("could not write blocks %u..%u in file \"%s\": %m",
1017  blocknum,
1018  blocknum + nblocks_this_segment - 1,
1019  FilePathName(v->mdfd_vfd)),
1020  enospc ? errhint("Check free disk space.") : 0));
1021  }
1022 
1023  /* One loop should usually be enough. */
1024  transferred_this_segment += nbytes;
1025  Assert(transferred_this_segment <= size_this_segment);
1026  if (transferred_this_segment == size_this_segment)
1027  break;
1028 
1029  /* Adjust position and iovecs after a short write. */
1030  seekpos += nbytes;
1031  iovcnt = compute_remaining_iovec(iov, iov, iovcnt, nbytes);
1032  }
1033 
1034  if (!skipFsync && !SmgrIsTemp(reln))
1035  register_dirty_segment(reln, forknum, v);
1036 
1037  nblocks -= nblocks_this_segment;
1038  buffers += nblocks_this_segment;
1039  blocknum += nblocks_this_segment;
1040  }
1041 }
ssize_t FileWriteV(File file, const struct iovec *iov, int iovcnt, off_t offset, uint32 wait_event_info)
Definition: fd.c:2214

References _mdfd_getseg(), Assert, RelFileLocatorBackend::backend, buffers_to_iovec(), compute_remaining_iovec(), RelFileLocator::dbOid, elog, ereport, errcode_for_file_access(), errhint(), errmsg(), ERROR, EXTENSION_CREATE_RECOVERY, EXTENSION_FAIL, FilePathName(), FileWriteV(), lengthof, RelFileLocatorBackend::locator, _MdfdVec::mdfd_vfd, mdnblocks(), Min, PG_IOV_MAX, register_dirty_segment(), RelFileLocator::relNumber, SMgrRelationData::smgr_rlocator, SmgrIsTemp, and RelFileLocator::spcOid.

◆ mdzeroextend()

void mdzeroextend ( SMgrRelation  reln,
ForkNumber  forknum,
BlockNumber  blocknum,
int  nblocks,
bool  skipFsync 
)

Definition at line 525 of file md.c.

527 {
528  MdfdVec *v;
529  BlockNumber curblocknum = blocknum;
530  int remblocks = nblocks;
531 
532  Assert(nblocks > 0);
533 
534  /* This assert is too expensive to have on normally ... */
535 #ifdef CHECK_WRITE_VS_EXTEND
536  Assert(blocknum >= mdnblocks(reln, forknum));
537 #endif
538 
539  /*
540  * If a relation manages to grow to 2^32-1 blocks, refuse to extend it any
541  * more --- we mustn't create a block whose number actually is
542  * InvalidBlockNumber or larger.
543  */
544  if ((uint64) blocknum + nblocks >= (uint64) InvalidBlockNumber)
545  ereport(ERROR,
546  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
547  errmsg("cannot extend file \"%s\" beyond %u blocks",
548  relpath(reln->smgr_rlocator, forknum),
550 
551  while (remblocks > 0)
552  {
553  BlockNumber segstartblock = curblocknum % ((BlockNumber) RELSEG_SIZE);
554  off_t seekpos = (off_t) BLCKSZ * segstartblock;
555  int numblocks;
556 
557  if (segstartblock + remblocks > RELSEG_SIZE)
558  numblocks = RELSEG_SIZE - segstartblock;
559  else
560  numblocks = remblocks;
561 
562  v = _mdfd_getseg(reln, forknum, curblocknum, skipFsync, EXTENSION_CREATE);
563 
564  Assert(segstartblock < RELSEG_SIZE);
565  Assert(segstartblock + numblocks <= RELSEG_SIZE);
566 
567  /*
568  * If available and useful, use posix_fallocate() (via
569  * FileFallocate()) to extend the relation. That's often more
570  * efficient than using write(), as it commonly won't cause the kernel
571  * to allocate page cache space for the extended pages.
572  *
573  * However, we don't use FileFallocate() for small extensions, as it
574  * defeats delayed allocation on some filesystems. Not clear where
575  * that decision should be made though? For now just use a cutoff of
576  * 8, anything between 4 and 8 worked OK in some local testing.
577  */
578  if (numblocks > 8)
579  {
580  int ret;
581 
582  ret = FileFallocate(v->mdfd_vfd,
583  seekpos, (off_t) BLCKSZ * numblocks,
584  WAIT_EVENT_DATA_FILE_EXTEND);
585  if (ret != 0)
586  {
587  ereport(ERROR,
589  errmsg("could not extend file \"%s\" with FileFallocate(): %m",
590  FilePathName(v->mdfd_vfd)),
591  errhint("Check free disk space."));
592  }
593  }
594  else
595  {
596  int ret;
597 
598  /*
599  * Even if we don't want to use fallocate, we can still extend a
600  * bit more efficiently than writing each 8kB block individually.
601  * pg_pwrite_zeros() (via FileZero()) uses pg_pwritev_with_retry()
602  * to avoid multiple writes or needing a zeroed buffer for the
603  * whole length of the extension.
604  */
605  ret = FileZero(v->mdfd_vfd,
606  seekpos, (off_t) BLCKSZ * numblocks,
607  WAIT_EVENT_DATA_FILE_EXTEND);
608  if (ret < 0)
609  ereport(ERROR,
611  errmsg("could not extend file \"%s\": %m",
612  FilePathName(v->mdfd_vfd)),
613  errhint("Check free disk space."));
614  }
615 
616  if (!skipFsync && !SmgrIsTemp(reln))
617  register_dirty_segment(reln, forknum, v);
618 
619  Assert(_mdnblocks(reln, forknum, v) <= ((BlockNumber) RELSEG_SIZE));
620 
621  remblocks -= numblocks;
622  curblocknum += numblocks;
623  }
624 }
int FileFallocate(File file, off_t offset, off_t amount, uint32 wait_event_info)
Definition: fd.c:2391
int FileZero(File file, off_t offset, off_t amount, uint32 wait_event_info)
Definition: fd.c:2346

References _mdfd_getseg(), _mdnblocks(), Assert, ereport, errcode(), errcode_for_file_access(), errhint(), errmsg(), ERROR, EXTENSION_CREATE, FileFallocate(), FilePathName(), FileZero(), InvalidBlockNumber, _MdfdVec::mdfd_vfd, mdnblocks(), register_dirty_segment(), relpath, SMgrRelationData::smgr_rlocator, and SmgrIsTemp.

◆ register_dirty_segment()

static void register_dirty_segment ( SMgrRelation  reln,
ForkNumber  forknum,
MdfdVec seg 
)
static

Definition at line 1374 of file md.c.

1375 {
1376  FileTag tag;
1377 
1378  INIT_MD_FILETAG(tag, reln->smgr_rlocator.locator, forknum, seg->mdfd_segno);
1379 
1380  /* Temp relations should never be fsync'd */
1381  Assert(!SmgrIsTemp(reln));
1382 
1383  if (!RegisterSyncRequest(&tag, SYNC_REQUEST, false /* retryOnError */ ))
1384  {
1385  instr_time io_start;
1386 
1387  ereport(DEBUG1,
1388  (errmsg_internal("could not forward fsync request because request queue is full")));
1389 
1391 
1392  if (FileSync(seg->mdfd_vfd, WAIT_EVENT_DATA_FILE_SYNC) < 0)
1395  errmsg("could not fsync file \"%s\": %m",
1396  FilePathName(seg->mdfd_vfd))));
1397 
1398  /*
1399  * We have no way of knowing if the current IOContext is
1400  * IOCONTEXT_NORMAL or IOCONTEXT_[BULKREAD, BULKWRITE, VACUUM] at this
1401  * point, so count the fsync as being in the IOCONTEXT_NORMAL
1402  * IOContext. This is probably okay, because the number of backend
1403  * fsyncs doesn't say anything about the efficacy of the
1404  * BufferAccessStrategy. And counting both fsyncs done in
1405  * IOCONTEXT_NORMAL and IOCONTEXT_[BULKREAD, BULKWRITE, VACUUM] under
1406  * IOCONTEXT_NORMAL is likely clearer when investigating the number of
1407  * backend fsyncs.
1408  */
1410  IOOP_FSYNC, io_start, 1);
1411  }
1412 }
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1157
#define DEBUG1
Definition: elog.h:30
@ SYNC_REQUEST
Definition: sync.h:25

References Assert, data_sync_elevel(), DEBUG1, ereport, errcode_for_file_access(), errmsg(), errmsg_internal(), ERROR, FilePathName(), FileSync(), INIT_MD_FILETAG, IOCONTEXT_NORMAL, IOOBJECT_RELATION, IOOP_FSYNC, RelFileLocatorBackend::locator, _MdfdVec::mdfd_segno, _MdfdVec::mdfd_vfd, pgstat_count_io_op_time(), pgstat_prepare_io_time(), RegisterSyncRequest(), SMgrRelationData::smgr_rlocator, SmgrIsTemp, SYNC_REQUEST, and track_io_timing.

Referenced by mdcreate(), mdextend(), mdregistersync(), mdtruncate(), mdwritev(), and mdzeroextend().

◆ register_forget_request()

static void register_forget_request ( RelFileLocatorBackend  rlocator,
ForkNumber  forknum,
BlockNumber  segno 
)
static

Definition at line 1435 of file md.c.

1437 {
1438  FileTag tag;
1439 
1440  INIT_MD_FILETAG(tag, rlocator.locator, forknum, segno);
1441 
1442  RegisterSyncRequest(&tag, SYNC_FORGET_REQUEST, true /* retryOnError */ );
1443 }
@ SYNC_FORGET_REQUEST
Definition: sync.h:27

References INIT_MD_FILETAG, RelFileLocatorBackend::locator, RegisterSyncRequest(), and SYNC_FORGET_REQUEST.

Referenced by mdunlinkfork().

◆ register_unlink_segment()

static void register_unlink_segment ( RelFileLocatorBackend  rlocator,
ForkNumber  forknum,
BlockNumber  segno 
)
static

Definition at line 1418 of file md.c.

1420 {
1421  FileTag tag;
1422 
1423  INIT_MD_FILETAG(tag, rlocator.locator, forknum, segno);
1424 
1425  /* Should never be used with temp relations */
1426  Assert(!RelFileLocatorBackendIsTemp(rlocator));
1427 
1428  RegisterSyncRequest(&tag, SYNC_UNLINK_REQUEST, true /* retryOnError */ );
1429 }
@ SYNC_UNLINK_REQUEST
Definition: sync.h:26

References Assert, INIT_MD_FILETAG, RelFileLocatorBackend::locator, RegisterSyncRequest(), RelFileLocatorBackendIsTemp, and SYNC_UNLINK_REQUEST.

Referenced by mdunlinkfork().

Variable Documentation

◆ MdCxt

MemoryContext MdCxt
static

Definition at line 86 of file md.c.

Referenced by _fdvec_resize(), and mdinit().