PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
md.c File Reference
#include "postgres.h"
#include <unistd.h>
#include <fcntl.h>
#include <sys/file.h>
#include "miscadmin.h"
#include "access/xlog.h"
#include "catalog/catalog.h"
#include "portability/instr_time.h"
#include "postmaster/bgwriter.h"
#include "storage/fd.h"
#include "storage/bufmgr.h"
#include "storage/relfilenode.h"
#include "storage/smgr.h"
#include "utils/hsearch.h"
#include "utils/memutils.h"
#include "pg_trace.h"
Include dependency graph for md.c:

Go to the source code of this file.

Data Structures

struct  _MdfdVec
 
struct  PendingOperationEntry
 
struct  PendingUnlinkEntry
 

Macros

#define FSYNCS_PER_ABSORB   10
 
#define UNLINKS_PER_ABSORB   10
 
#define FORGET_RELATION_FSYNC   (InvalidBlockNumber)
 
#define FORGET_DATABASE_FSYNC   (InvalidBlockNumber-1)
 
#define UNLINK_RELATION_REQUEST   (InvalidBlockNumber-2)
 
#define FILE_POSSIBLY_DELETED(err)   ((err) == ENOENT)
 
#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)
 

Typedefs

typedef struct _MdfdVec MdfdVec
 
typedef uint16 CycleCtr
 

Functions

static void mdunlinkfork (RelFileNodeBackend rnode, ForkNumber forkNum, bool isRedo)
 
static MdfdVecmdopen (SMgrRelation reln, ForkNumber forknum, int behavior)
 
static void register_dirty_segment (SMgrRelation reln, ForkNumber forknum, MdfdVec *seg)
 
static void register_unlink (RelFileNodeBackend rnode)
 
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 forkno, BlockNumber segno, int oflags)
 
static MdfdVec_mdfd_getseg (SMgrRelation reln, ForkNumber forkno, BlockNumber blkno, bool skipFsync, int behavior)
 
static BlockNumber _mdnblocks (SMgrRelation reln, ForkNumber forknum, MdfdVec *seg)
 
void mdinit (void)
 
void SetForwardFsyncRequests (void)
 
bool mdexists (SMgrRelation reln, ForkNumber forkNum)
 
void mdcreate (SMgrRelation reln, ForkNumber forkNum, bool isRedo)
 
void mdunlink (RelFileNodeBackend rnode, ForkNumber forkNum, bool isRedo)
 
void mdextend (SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer, bool skipFsync)
 
void mdclose (SMgrRelation reln, ForkNumber forknum)
 
void mdprefetch (SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum)
 
void mdwriteback (SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, BlockNumber nblocks)
 
void mdread (SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer)
 
void mdwrite (SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer, bool skipFsync)
 
BlockNumber mdnblocks (SMgrRelation reln, ForkNumber forknum)
 
void mdtruncate (SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks)
 
void mdimmedsync (SMgrRelation reln, ForkNumber forknum)
 
void mdsync (void)
 
void mdpreckpt (void)
 
void mdpostckpt (void)
 
void RememberFsyncRequest (RelFileNode rnode, ForkNumber forknum, BlockNumber segno)
 
void ForgetRelationFsyncRequests (RelFileNode rnode, ForkNumber forknum)
 
void ForgetDatabaseFsyncRequests (Oid dbid)
 

Variables

static MemoryContext MdCxt
 
static HTABpendingOpsTable = NULL
 
static ListpendingUnlinks = NIL
 
static MemoryContext pendingOpsCxt
 
static CycleCtr mdsync_cycle_ctr = 0
 
static CycleCtr mdckpt_cycle_ctr = 0
 

Macro Definition Documentation

#define EXTENSION_CREATE   (1 << 2)

Definition at line 168 of file md.c.

Referenced by _mdfd_getseg(), and mdextend().

#define EXTENSION_CREATE_RECOVERY   (1 << 3)

Definition at line 170 of file md.c.

Referenced by _mdfd_getseg(), mdread(), and mdwrite().

#define EXTENSION_DONT_CHECK_SIZE   (1 << 4)

Definition at line 178 of file md.c.

Referenced by _mdfd_getseg(), and mdsync().

#define EXTENSION_FAIL   (1 << 0)

Definition at line 164 of file md.c.

Referenced by _mdfd_getseg(), mdnblocks(), mdprefetch(), mdread(), and mdwrite().

#define EXTENSION_RETURN_NULL   (1 << 1)

Definition at line 166 of file md.c.

Referenced by _mdfd_getseg(), mdexists(), mdopen(), mdsync(), and mdwriteback().

#define FILE_POSSIBLY_DELETED (   err)    ((err) == ENOENT)

Definition at line 65 of file md.c.

Referenced by _mdfd_getseg(), mdopen(), and mdsync().

#define FORGET_DATABASE_FSYNC   (InvalidBlockNumber-1)

Definition at line 54 of file md.c.

Referenced by ForgetDatabaseFsyncRequests(), and RememberFsyncRequest().

#define FORGET_RELATION_FSYNC   (InvalidBlockNumber)

Definition at line 53 of file md.c.

Referenced by ForgetRelationFsyncRequests(), and RememberFsyncRequest().

#define FSYNCS_PER_ABSORB   10

Definition at line 43 of file md.c.

Referenced by mdsync().

#define UNLINK_RELATION_REQUEST   (InvalidBlockNumber-2)

Definition at line 55 of file md.c.

Referenced by register_unlink(), and RememberFsyncRequest().

#define UNLINKS_PER_ABSORB   10

Definition at line 44 of file md.c.

Referenced by mdpostckpt().

Typedef Documentation

Definition at line 136 of file md.c.

Function Documentation

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

Definition at line 1711 of file md.c.

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

Referenced by _mdfd_openseg(), mdclose(), mdcreate(), mdopen(), and mdtruncate().

1714 {
1715  if (nseg == 0)
1716  {
1717  if (reln->md_num_open_segs[forknum] > 0)
1718  {
1719  pfree(reln->md_seg_fds[forknum]);
1720  reln->md_seg_fds[forknum] = NULL;
1721  }
1722  }
1723  else if (reln->md_num_open_segs[forknum] == 0)
1724  {
1725  reln->md_seg_fds[forknum] =
1726  MemoryContextAlloc(MdCxt, sizeof(MdfdVec) * nseg);
1727  }
1728  else
1729  {
1730  /*
1731  * It doesn't seem worthwhile complicating the code by having a more
1732  * aggressive growth strategy here; the number of segments doesn't
1733  * grow that fast, and the memory context internally will sometimes
1734  * avoid doing an actual reallocation.
1735  */
1736  reln->md_seg_fds[forknum] =
1737  repalloc(reln->md_seg_fds[forknum],
1738  sizeof(MdfdVec) * nseg);
1739  }
1740 
1741  reln->md_num_open_segs[forknum] = nseg;
1742 }
static MemoryContext MdCxt
Definition: md.c:114
void pfree(void *pointer)
Definition: mcxt.c:992
Definition: md.c:108
#define NULL
Definition: c.h:226
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1021
int md_num_open_segs[MAX_FORKNUM+1]
Definition: smgr.h:71
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:749
struct _MdfdVec * md_seg_fds[MAX_FORKNUM+1]
Definition: smgr.h:72
static MdfdVec * _mdfd_getseg ( SMgrRelation  reln,
ForkNumber  forkno,
BlockNumber  blkno,
bool  skipFsync,
int  behavior 
)
static

Definition at line 1812 of file md.c.

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_FAIL, EXTENSION_RETURN_NULL, FATAL, FILE_POSSIBLY_DELETED, InRecovery, SMgrRelationData::md_num_open_segs, SMgrRelationData::md_seg_fds, mdextend(), _MdfdVec::mdfd_segno, mdopen(), NULL, palloc0(), and pfree().

Referenced by mdextend(), mdprefetch(), mdread(), mdsync(), mdwrite(), and mdwriteback().

1814 {
1815  MdfdVec *v;
1816  BlockNumber targetseg;
1817  BlockNumber nextsegno;
1818 
1819  /* some way to handle non-existent segments needs to be specified */
1820  Assert(behavior &
1822 
1823  targetseg = blkno / ((BlockNumber) RELSEG_SIZE);
1824 
1825  /* if an existing and opened segment, we're done */
1826  if (targetseg < reln->md_num_open_segs[forknum])
1827  {
1828  v = &reln->md_seg_fds[forknum][targetseg];
1829  return v;
1830  }
1831 
1832  /*
1833  * The target segment is not yet open. Iterate over all the segments
1834  * between the last opened and the target segment. This way missing
1835  * segments either raise an error, or get created (according to
1836  * 'behavior'). Start with either the last opened, or the first segment if
1837  * none was opened before.
1838  */
1839  if (reln->md_num_open_segs[forknum] > 0)
1840  v = &reln->md_seg_fds[forknum][reln->md_num_open_segs[forknum] - 1];
1841  else
1842  {
1843  v = mdopen(reln, forknum, behavior);
1844  if (!v)
1845  return NULL; /* if behavior & EXTENSION_RETURN_NULL */
1846  }
1847 
1848  for (nextsegno = reln->md_num_open_segs[forknum];
1849  nextsegno <= targetseg; nextsegno++)
1850  {
1851  BlockNumber nblocks = _mdnblocks(reln, forknum, v);
1852  int flags = 0;
1853 
1854  Assert(nextsegno == v->mdfd_segno + 1);
1855 
1856  if (nblocks > ((BlockNumber) RELSEG_SIZE))
1857  elog(FATAL, "segment too big");
1858 
1859  if ((behavior & EXTENSION_CREATE) ||
1860  (InRecovery && (behavior & EXTENSION_CREATE_RECOVERY)))
1861  {
1862  /*
1863  * Normally we will create new segments only if authorized by the
1864  * caller (i.e., we are doing mdextend()). But when doing WAL
1865  * recovery, create segments anyway; this allows cases such as
1866  * replaying WAL data that has a write into a high-numbered
1867  * segment of a relation that was later deleted. We want to go
1868  * ahead and create the segments so we can finish out the replay.
1869  * However if the caller has specified
1870  * EXTENSION_REALLY_RETURN_NULL, then extension is not desired
1871  * even in recovery; we won't reach this point in that case.
1872  *
1873  * We have to maintain the invariant that segments before the last
1874  * active segment are of size RELSEG_SIZE; therefore, if
1875  * extending, pad them out with zeroes if needed. (This only
1876  * matters if in recovery, or if the caller is extending the
1877  * relation discontiguously, but that can happen in hash indexes.)
1878  */
1879  if (nblocks < ((BlockNumber) RELSEG_SIZE))
1880  {
1881  char *zerobuf = palloc0(BLCKSZ);
1882 
1883  mdextend(reln, forknum,
1884  nextsegno * ((BlockNumber) RELSEG_SIZE) - 1,
1885  zerobuf, skipFsync);
1886  pfree(zerobuf);
1887  }
1888  flags = O_CREAT;
1889  }
1890  else if (!(behavior & EXTENSION_DONT_CHECK_SIZE) &&
1891  nblocks < ((BlockNumber) RELSEG_SIZE))
1892  {
1893  /*
1894  * When not extending (or explicitly including truncated
1895  * segments), only open the next segment if the current one is
1896  * exactly RELSEG_SIZE. If not (this branch), either return NULL
1897  * or fail.
1898  */
1899  if (behavior & EXTENSION_RETURN_NULL)
1900  {
1901  /*
1902  * Some callers discern between reasons for _mdfd_getseg()
1903  * returning NULL based on errno. As there's no failing
1904  * syscall involved in this case, explicitly set errno to
1905  * ENOENT, as that seems the closest interpretation.
1906  */
1907  errno = ENOENT;
1908  return NULL;
1909  }
1910 
1911  ereport(ERROR,
1913  errmsg("could not open file \"%s\" (target block %u): previous segment is only %u blocks",
1914  _mdfd_segpath(reln, forknum, nextsegno),
1915  blkno, nblocks)));
1916  }
1917 
1918  v = _mdfd_openseg(reln, forknum, nextsegno, flags);
1919 
1920  if (v == NULL)
1921  {
1922  if ((behavior & EXTENSION_RETURN_NULL) &&
1923  FILE_POSSIBLY_DELETED(errno))
1924  return NULL;
1925  ereport(ERROR,
1927  errmsg("could not open file \"%s\" (target block %u): %m",
1928  _mdfd_segpath(reln, forknum, nextsegno),
1929  blkno)));
1930  }
1931  }
1932 
1933  return v;
1934 }
#define EXTENSION_DONT_CHECK_SIZE
Definition: md.c:178
BlockNumber mdfd_segno
Definition: md.c:111
bool InRecovery
Definition: xlog.c:190
uint32 BlockNumber
Definition: block.h:31
#define EXTENSION_FAIL
Definition: md.c:164
void mdextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer, bool skipFsync)
Definition: md.c:494
void pfree(void *pointer)
Definition: mcxt.c:992
#define ERROR
Definition: elog.h:43
#define EXTENSION_RETURN_NULL
Definition: md.c:166
#define FATAL
Definition: elog.h:52
int errcode_for_file_access(void)
Definition: elog.c:598
#define EXTENSION_CREATE_RECOVERY
Definition: md.c:170
#define ereport(elevel, rest)
Definition: elog.h:122
static MdfdVec * mdopen(SMgrRelation reln, ForkNumber forknum, int behavior)
Definition: md.c:573
void * palloc0(Size size)
Definition: mcxt.c:920
Definition: md.c:108
static MdfdVec * _mdfd_openseg(SMgrRelation reln, ForkNumber forkno, BlockNumber segno, int oflags)
Definition: md.c:1772
#define EXTENSION_CREATE
Definition: md.c:168
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:670
static BlockNumber _mdnblocks(SMgrRelation reln, ForkNumber forknum, MdfdVec *seg)
Definition: md.c:1940
int md_num_open_segs[MAX_FORKNUM+1]
Definition: smgr.h:71
int errmsg(const char *fmt,...)
Definition: elog.c:797
struct _MdfdVec * md_seg_fds[MAX_FORKNUM+1]
Definition: smgr.h:72
#define elog
Definition: elog.h:219
#define FILE_POSSIBLY_DELETED(err)
Definition: md.c:65
static char * _mdfd_segpath(SMgrRelation reln, ForkNumber forknum, BlockNumber segno)
Definition: md.c:1749
static MdfdVec * _mdfd_openseg ( SMgrRelation  reln,
ForkNumber  forkno,
BlockNumber  segno,
int  oflags 
)
static

Definition at line 1772 of file md.c.

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

Referenced by _mdfd_getseg(), and mdnblocks().

1774 {
1775  MdfdVec *v;
1776  int fd;
1777  char *fullpath;
1778 
1779  fullpath = _mdfd_segpath(reln, forknum, segno);
1780 
1781  /* open the file */
1782  fd = PathNameOpenFile(fullpath, O_RDWR | PG_BINARY | oflags, 0600);
1783 
1784  pfree(fullpath);
1785 
1786  if (fd < 0)
1787  return NULL;
1788 
1789  if (segno <= reln->md_num_open_segs[forknum])
1790  _fdvec_resize(reln, forknum, segno + 1);
1791 
1792  /* fill the entry */
1793  v = &reln->md_seg_fds[forknum][segno];
1794  v->mdfd_vfd = fd;
1795  v->mdfd_segno = segno;
1796 
1797  Assert(_mdnblocks(reln, forknum, v) <= ((BlockNumber) RELSEG_SIZE));
1798 
1799  /* all done */
1800  return v;
1801 }
File PathNameOpenFile(FileName fileName, int fileFlags, int fileMode)
Definition: fd.c:1266
BlockNumber mdfd_segno
Definition: md.c:111
uint32 BlockNumber
Definition: block.h:31
static int fd(const char *x, int i)
Definition: preproc-init.c:105
#define PG_BINARY
Definition: c.h:1037
void pfree(void *pointer)
Definition: mcxt.c:992
static void _fdvec_resize(SMgrRelation reln, ForkNumber forknum, int nseg)
Definition: md.c:1711
Definition: md.c:108
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:670
static BlockNumber _mdnblocks(SMgrRelation reln, ForkNumber forknum, MdfdVec *seg)
Definition: md.c:1940
struct _MdfdVec * md_seg_fds[MAX_FORKNUM+1]
Definition: smgr.h:72
File mdfd_vfd
Definition: md.c:110
static char * _mdfd_segpath(SMgrRelation reln, ForkNumber forknum, BlockNumber segno)
Definition: md.c:1749
static char * _mdfd_segpath ( SMgrRelation  reln,
ForkNumber  forknum,
BlockNumber  segno 
)
static

Definition at line 1749 of file md.c.

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

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

1750 {
1751  char *path,
1752  *fullpath;
1753 
1754  path = relpath(reln->smgr_rnode, forknum);
1755 
1756  if (segno > 0)
1757  {
1758  fullpath = psprintf("%s.%u", path, segno);
1759  pfree(path);
1760  }
1761  else
1762  fullpath = path;
1763 
1764  return fullpath;
1765 }
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
void pfree(void *pointer)
Definition: mcxt.c:992
RelFileNodeBackend smgr_rnode
Definition: smgr.h:43
#define relpath(rnode, forknum)
Definition: relpath.h:71
static BlockNumber _mdnblocks ( SMgrRelation  reln,
ForkNumber  forknum,
MdfdVec seg 
)
static

Definition at line 1940 of file md.c.

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

Referenced by _mdfd_getseg(), _mdfd_openseg(), mdextend(), mdnblocks(), and mdopen().

1941 {
1942  off_t len;
1943 
1944  len = FileSeek(seg->mdfd_vfd, 0L, SEEK_END);
1945  if (len < 0)
1946  ereport(ERROR,
1948  errmsg("could not seek to end of file \"%s\": %m",
1949  FilePathName(seg->mdfd_vfd))));
1950  /* note that this calculation will ignore any partial block at EOF */
1951  return (BlockNumber) (len / BLCKSZ);
1952 }
uint32 BlockNumber
Definition: block.h:31
char * FilePathName(File file)
Definition: fd.c:1923
#define ERROR
Definition: elog.h:43
int errcode_for_file_access(void)
Definition: elog.c:598
#define ereport(elevel, rest)
Definition: elog.h:122
int errmsg(const char *fmt,...)
Definition: elog.c:797
off_t FileSeek(File file, off_t offset, int whence)
Definition: fd.c:1802
File mdfd_vfd
Definition: md.c:110
void ForgetDatabaseFsyncRequests ( Oid  dbid)

Definition at line 1684 of file md.c.

References RelFileNode::dbNode, FORGET_DATABASE_FSYNC, ForwardFsyncRequest(), InvalidForkNumber, IsUnderPostmaster, pg_usleep(), RelFileNode::relNode, RememberFsyncRequest(), and RelFileNode::spcNode.

Referenced by dbase_redo(), and dropdb().

1685 {
1686  RelFileNode rnode;
1687 
1688  rnode.dbNode = dbid;
1689  rnode.spcNode = 0;
1690  rnode.relNode = 0;
1691 
1692  if (pendingOpsTable)
1693  {
1694  /* standalone backend or startup process: fsync state is local */
1696  }
1697  else if (IsUnderPostmaster)
1698  {
1699  /* see notes in ForgetRelationFsyncRequests */
1700  while (!ForwardFsyncRequest(rnode, InvalidForkNumber,
1702  pg_usleep(10000L); /* 10 msec seems a good number */
1703  }
1704 }
void RememberFsyncRequest(RelFileNode rnode, ForkNumber forknum, BlockNumber segno)
Definition: md.c:1513
bool ForwardFsyncRequest(RelFileNode rnode, ForkNumber forknum, BlockNumber segno)
static HTAB * pendingOpsTable
Definition: md.c:154
void pg_usleep(long microsec)
Definition: signal.c:53
#define FORGET_DATABASE_FSYNC
Definition: md.c:54
bool IsUnderPostmaster
Definition: globals.c:100
void ForgetRelationFsyncRequests ( RelFileNode  rnode,
ForkNumber  forknum 
)

Definition at line 1651 of file md.c.

References FORGET_RELATION_FSYNC, ForwardFsyncRequest(), IsUnderPostmaster, pg_usleep(), and RememberFsyncRequest().

Referenced by mdunlink().

1652 {
1653  if (pendingOpsTable)
1654  {
1655  /* standalone backend or startup process: fsync state is local */
1657  }
1658  else if (IsUnderPostmaster)
1659  {
1660  /*
1661  * Notify the checkpointer about it. If we fail to queue the cancel
1662  * message, we have to sleep and try again ... ugly, but hopefully
1663  * won't happen often.
1664  *
1665  * XXX should we CHECK_FOR_INTERRUPTS in this loop? Escaping with an
1666  * error would leave the no-longer-used file still present on disk,
1667  * which would be bad, so I'm inclined to assume that the checkpointer
1668  * will always empty the queue soon.
1669  */
1670  while (!ForwardFsyncRequest(rnode, forknum, FORGET_RELATION_FSYNC))
1671  pg_usleep(10000L); /* 10 msec seems a good number */
1672 
1673  /*
1674  * Note we don't wait for the checkpointer to actually absorb the
1675  * cancel message; see mdsync() for the implications.
1676  */
1677  }
1678 }
void RememberFsyncRequest(RelFileNode rnode, ForkNumber forknum, BlockNumber segno)
Definition: md.c:1513
bool ForwardFsyncRequest(RelFileNode rnode, ForkNumber forknum, BlockNumber segno)
static HTAB * pendingOpsTable
Definition: md.c:154
#define FORGET_RELATION_FSYNC
Definition: md.c:53
void pg_usleep(long microsec)
Definition: signal.c:53
bool IsUnderPostmaster
Definition: globals.c:100
void mdclose ( SMgrRelation  reln,
ForkNumber  forknum 
)

Definition at line 627 of file md.c.

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

Referenced by mdexists().

628 {
629  int nopensegs = reln->md_num_open_segs[forknum];
630 
631  /* No work if already closed */
632  if (nopensegs == 0)
633  return;
634 
635  /* close segments starting from the end */
636  while (nopensegs > 0)
637  {
638  MdfdVec *v = &reln->md_seg_fds[forknum][nopensegs - 1];
639 
640  /* if not closed already */
641  if (v->mdfd_vfd >= 0)
642  {
643  FileClose(v->mdfd_vfd);
644  v->mdfd_vfd = -1;
645  }
646 
647  nopensegs--;
648  }
649 
650  /* resize just once, avoids pointless reallocations */
651  _fdvec_resize(reln, forknum, 0);
652 }
static void _fdvec_resize(SMgrRelation reln, ForkNumber forknum, int nseg)
Definition: md.c:1711
Definition: md.c:108
void FileClose(File file)
Definition: fd.c:1456
int md_num_open_segs[MAX_FORKNUM+1]
Definition: smgr.h:71
struct _MdfdVec * md_seg_fds[MAX_FORKNUM+1]
Definition: smgr.h:72
File mdfd_vfd
Definition: md.c:110
void mdcreate ( SMgrRelation  reln,
ForkNumber  forkNum,
bool  isRedo 
)

Definition at line 293 of file md.c.

References _fdvec_resize(), Assert, ereport, errcode_for_file_access(), errmsg(), ERROR, fd(), IsBootstrapProcessingMode, SMgrRelationData::md_num_open_segs, SMgrRelationData::md_seg_fds, _MdfdVec::mdfd_segno, _MdfdVec::mdfd_vfd, PathNameOpenFile(), pfree(), PG_BINARY, relpath, and SMgrRelationData::smgr_rnode.

294 {
295  MdfdVec *mdfd;
296  char *path;
297  File fd;
298 
299  if (isRedo && reln->md_num_open_segs[forkNum] > 0)
300  return; /* created and opened already... */
301 
302  Assert(reln->md_num_open_segs[forkNum] == 0);
303 
304  path = relpath(reln->smgr_rnode, forkNum);
305 
306  fd = PathNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, 0600);
307 
308  if (fd < 0)
309  {
310  int save_errno = errno;
311 
312  /*
313  * During bootstrap, there are cases where a system relation will be
314  * accessed (by internal backend processes) before the bootstrap
315  * script nominally creates it. Therefore, allow the file to exist
316  * already, even if isRedo is not set. (See also mdopen)
317  */
318  if (isRedo || IsBootstrapProcessingMode())
319  fd = PathNameOpenFile(path, O_RDWR | PG_BINARY, 0600);
320  if (fd < 0)
321  {
322  /* be sure to report the error reported by create, not open */
323  errno = save_errno;
324  ereport(ERROR,
326  errmsg("could not create file \"%s\": %m", path)));
327  }
328  }
329 
330  pfree(path);
331 
332  _fdvec_resize(reln, forkNum, 1);
333  mdfd = &reln->md_seg_fds[forkNum][0];
334  mdfd->mdfd_vfd = fd;
335  mdfd->mdfd_segno = 0;
336 }
File PathNameOpenFile(FileName fileName, int fileFlags, int fileMode)
Definition: fd.c:1266
BlockNumber mdfd_segno
Definition: md.c:111
static int fd(const char *x, int i)
Definition: preproc-init.c:105
#define PG_BINARY
Definition: c.h:1037
void pfree(void *pointer)
Definition: mcxt.c:992
#define ERROR
Definition: elog.h:43
RelFileNodeBackend smgr_rnode
Definition: smgr.h:43
int errcode_for_file_access(void)
Definition: elog.c:598
#define ereport(elevel, rest)
Definition: elog.h:122
static void _fdvec_resize(SMgrRelation reln, ForkNumber forknum, int nseg)
Definition: md.c:1711
Definition: md.c:108
#define Assert(condition)
Definition: c.h:670
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:365
int md_num_open_segs[MAX_FORKNUM+1]
Definition: smgr.h:71
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define relpath(rnode, forknum)
Definition: relpath.h:71
struct _MdfdVec * md_seg_fds[MAX_FORKNUM+1]
Definition: smgr.h:72
File mdfd_vfd
Definition: md.c:110
int File
Definition: fd.h:51
bool mdexists ( SMgrRelation  reln,
ForkNumber  forkNum 
)

Definition at line 276 of file md.c.

References EXTENSION_RETURN_NULL, mdclose(), mdopen(), and NULL.

277 {
278  /*
279  * Close it first, to ensure that we notice if the fork has been unlinked
280  * since we opened it.
281  */
282  mdclose(reln, forkNum);
283 
284  return (mdopen(reln, forkNum, EXTENSION_RETURN_NULL) != NULL);
285 }
#define EXTENSION_RETURN_NULL
Definition: md.c:166
static MdfdVec * mdopen(SMgrRelation reln, ForkNumber forknum, int behavior)
Definition: md.c:573
#define NULL
Definition: c.h:226
void mdclose(SMgrRelation reln, ForkNumber forknum)
Definition: md.c:627
void mdextend ( SMgrRelation  reln,
ForkNumber  forknum,
BlockNumber  blocknum,
char *  buffer,
bool  skipFsync 
)

Definition at line 494 of file md.c.

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

Referenced by _mdfd_getseg().

496 {
497  off_t seekpos;
498  int nbytes;
499  MdfdVec *v;
500 
501  /* This assert is too expensive to have on normally ... */
502 #ifdef CHECK_WRITE_VS_EXTEND
503  Assert(blocknum >= mdnblocks(reln, forknum));
504 #endif
505 
506  /*
507  * If a relation manages to grow to 2^32-1 blocks, refuse to extend it any
508  * more --- we mustn't create a block whose number actually is
509  * InvalidBlockNumber.
510  */
511  if (blocknum == InvalidBlockNumber)
512  ereport(ERROR,
513  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
514  errmsg("cannot extend file \"%s\" beyond %u blocks",
515  relpath(reln->smgr_rnode, forknum),
517 
518  v = _mdfd_getseg(reln, forknum, blocknum, skipFsync, EXTENSION_CREATE);
519 
520  seekpos = (off_t) BLCKSZ *(blocknum % ((BlockNumber) RELSEG_SIZE));
521 
522  Assert(seekpos < (off_t) BLCKSZ * RELSEG_SIZE);
523 
524  /*
525  * Note: because caller usually obtained blocknum by calling mdnblocks,
526  * which did a seek(SEEK_END), this seek is often redundant and will be
527  * optimized away by fd.c. It's not redundant, however, if there is a
528  * partial page at the end of the file. In that case we want to try to
529  * overwrite the partial page with a full page. It's also not redundant
530  * if bufmgr.c had to dump another buffer of the same file to make room
531  * for the new page's buffer.
532  */
533  if (FileSeek(v->mdfd_vfd, seekpos, SEEK_SET) != seekpos)
534  ereport(ERROR,
536  errmsg("could not seek to block %u in file \"%s\": %m",
537  blocknum, FilePathName(v->mdfd_vfd))));
538 
539  if ((nbytes = FileWrite(v->mdfd_vfd, buffer, BLCKSZ)) != BLCKSZ)
540  {
541  if (nbytes < 0)
542  ereport(ERROR,
544  errmsg("could not extend file \"%s\": %m",
545  FilePathName(v->mdfd_vfd)),
546  errhint("Check free disk space.")));
547  /* short write: complain appropriately */
548  ereport(ERROR,
549  (errcode(ERRCODE_DISK_FULL),
550  errmsg("could not extend file \"%s\": wrote only %d of %d bytes at block %u",
552  nbytes, BLCKSZ, blocknum),
553  errhint("Check free disk space.")));
554  }
555 
556  if (!skipFsync && !SmgrIsTemp(reln))
557  register_dirty_segment(reln, forknum, v);
558 
559  Assert(_mdnblocks(reln, forknum, v) <= ((BlockNumber) RELSEG_SIZE));
560 }
int FileWrite(File file, char *buffer, int amount)
Definition: fd.c:1666
static MdfdVec * _mdfd_getseg(SMgrRelation reln, ForkNumber forkno, BlockNumber blkno, bool skipFsync, int behavior)
Definition: md.c:1812
int errhint(const char *fmt,...)
Definition: elog.c:987
BlockNumber mdnblocks(SMgrRelation reln, ForkNumber forknum)
Definition: md.c:872
int errcode(int sqlerrcode)
Definition: elog.c:575
uint32 BlockNumber
Definition: block.h:31
char * FilePathName(File file)
Definition: fd.c:1923
#define SmgrIsTemp(smgr)
Definition: smgr.h:80
#define ERROR
Definition: elog.h:43
RelFileNodeBackend smgr_rnode
Definition: smgr.h:43
int errcode_for_file_access(void)
Definition: elog.c:598
#define ereport(elevel, rest)
Definition: elog.h:122
Definition: md.c:108
#define EXTENSION_CREATE
Definition: md.c:168
#define Assert(condition)
Definition: c.h:670
static BlockNumber _mdnblocks(SMgrRelation reln, ForkNumber forknum, MdfdVec *seg)
Definition: md.c:1940
#define InvalidBlockNumber
Definition: block.h:33
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define relpath(rnode, forknum)
Definition: relpath.h:71
off_t FileSeek(File file, off_t offset, int whence)
Definition: fd.c:1802
File mdfd_vfd
Definition: md.c:110
static void register_dirty_segment(SMgrRelation reln, ForkNumber forknum, MdfdVec *seg)
Definition: md.c:1428
void mdimmedsync ( SMgrRelation  reln,
ForkNumber  forknum 
)

Definition at line 1024 of file md.c.

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

1025 {
1026  int segno;
1027 
1028  /*
1029  * NOTE: mdnblocks makes sure we have opened all active segments, so that
1030  * fsync loop will get them all!
1031  */
1032  mdnblocks(reln, forknum);
1033 
1034  segno = reln->md_num_open_segs[forknum];
1035 
1036  while (segno > 0)
1037  {
1038  MdfdVec *v = &reln->md_seg_fds[forknum][segno - 1];
1039 
1040  if (FileSync(v->mdfd_vfd) < 0)
1041  ereport(ERROR,
1043  errmsg("could not fsync file \"%s\": %m",
1044  FilePathName(v->mdfd_vfd))));
1045  segno--;
1046  }
1047 }
BlockNumber mdnblocks(SMgrRelation reln, ForkNumber forknum)
Definition: md.c:872
int FileSync(File file)
Definition: fd.c:1785
char * FilePathName(File file)
Definition: fd.c:1923
#define ERROR
Definition: elog.h:43
int errcode_for_file_access(void)
Definition: elog.c:598
#define ereport(elevel, rest)
Definition: elog.h:122
Definition: md.c:108
int md_num_open_segs[MAX_FORKNUM+1]
Definition: smgr.h:71
int errmsg(const char *fmt,...)
Definition: elog.c:797
struct _MdfdVec * md_seg_fds[MAX_FORKNUM+1]
Definition: smgr.h:72
File mdfd_vfd
Definition: md.c:110
void mdinit ( void  )

Definition at line 205 of file md.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate(), AmCheckpointerProcess, AmStartupProcess, HASHCTL::entrysize, HASH_BLOBS, HASH_CONTEXT, hash_create(), HASH_ELEM, HASHCTL::hcxt, IsUnderPostmaster, HASHCTL::keysize, MemoryContextAllowInCriticalSection(), MemSet, NIL, pendingOpsCxt, and TopMemoryContext.

206 {
208  "MdSmgr",
210 
211  /*
212  * Create pending-operations hashtable if we need it. Currently, we need
213  * it if we are standalone (not under a postmaster) or if we are a startup
214  * or checkpointer auxiliary process.
215  */
217  {
218  HASHCTL hash_ctl;
219 
220  /*
221  * XXX: The checkpointer needs to add entries to the pending ops table
222  * when absorbing fsync requests. That is done within a critical
223  * section, which isn't usually allowed, but we make an exception. It
224  * means that there's a theoretical possibility that you run out of
225  * memory while absorbing fsync requests, which leads to a PANIC.
226  * Fortunately the hash table is small so that's unlikely to happen in
227  * practice.
228  */
230  "Pending ops context",
233 
234  MemSet(&hash_ctl, 0, sizeof(hash_ctl));
235  hash_ctl.keysize = sizeof(RelFileNode);
236  hash_ctl.entrysize = sizeof(PendingOperationEntry);
237  hash_ctl.hcxt = pendingOpsCxt;
238  pendingOpsTable = hash_create("Pending Ops Table",
239  100L,
240  &hash_ctl,
243  }
244 }
#define NIL
Definition: pg_list.h:69
#define AmStartupProcess()
Definition: miscadmin.h:403
#define HASH_CONTEXT
Definition: hsearch.h:93
void MemoryContextAllowInCriticalSection(MemoryContext context, bool allow)
Definition: mcxt.c:374
#define HASH_ELEM
Definition: hsearch.h:87
MemoryContext hcxt
Definition: hsearch.h:78
Size entrysize
Definition: hsearch.h:73
#define MemSet(start, val, len)
Definition: c.h:852
static HTAB * pendingOpsTable
Definition: md.c:154
static MemoryContext MdCxt
Definition: md.c:114
#define AmCheckpointerProcess()
Definition: miscadmin.h:405
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:145
struct RelFileNode RelFileNode
bool IsUnderPostmaster
Definition: globals.c:100
MemoryContext TopMemoryContext
Definition: mcxt.c:43
#define HASH_BLOBS
Definition: hsearch.h:88
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:440
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:301
Size keysize
Definition: hsearch.h:72
static MemoryContext pendingOpsCxt
Definition: md.c:156
static List * pendingUnlinks
Definition: md.c:155
BlockNumber mdnblocks ( SMgrRelation  reln,
ForkNumber  forknum 
)

Definition at line 872 of file md.c.

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

Referenced by mdextend(), mdimmedsync(), mdtruncate(), and mdwrite().

873 {
874  MdfdVec *v = mdopen(reln, forknum, EXTENSION_FAIL);
875  BlockNumber nblocks;
876  BlockNumber segno = 0;
877 
878  /* mdopen has opened the first segment */
879  Assert(reln->md_num_open_segs[forknum] > 0);
880 
881  /*
882  * Start from the last open segments, to avoid redundant seeks. We have
883  * previously verified that these segments are exactly RELSEG_SIZE long,
884  * and it's useless to recheck that each time.
885  *
886  * NOTE: this assumption could only be wrong if another backend has
887  * truncated the relation. We rely on higher code levels to handle that
888  * scenario by closing and re-opening the md fd, which is handled via
889  * relcache flush. (Since the checkpointer doesn't participate in
890  * relcache flush, it could have segment entries for inactive segments;
891  * that's OK because the checkpointer never needs to compute relation
892  * size.)
893  */
894  segno = reln->md_num_open_segs[forknum] - 1;
895  v = &reln->md_seg_fds[forknum][segno];
896 
897  for (;;)
898  {
899  nblocks = _mdnblocks(reln, forknum, v);
900  if (nblocks > ((BlockNumber) RELSEG_SIZE))
901  elog(FATAL, "segment too big");
902  if (nblocks < ((BlockNumber) RELSEG_SIZE))
903  return (segno * ((BlockNumber) RELSEG_SIZE)) + nblocks;
904 
905  /*
906  * If segment is exactly RELSEG_SIZE, advance to next one.
907  */
908  segno++;
909 
910  /*
911  * We used to pass O_CREAT here, but that's has the disadvantage that
912  * it might create a segment which has vanished through some operating
913  * system misadventure. In such a case, creating the segment here
914  * undermines _mdfd_getseg's attempts to notice and report an error
915  * upon access to a missing segment.
916  */
917  v = _mdfd_openseg(reln, forknum, segno, 0);
918  if (v == NULL)
919  return segno * ((BlockNumber) RELSEG_SIZE);
920  }
921 }
uint32 BlockNumber
Definition: block.h:31
#define EXTENSION_FAIL
Definition: md.c:164
#define FATAL
Definition: elog.h:52
static MdfdVec * mdopen(SMgrRelation reln, ForkNumber forknum, int behavior)
Definition: md.c:573
Definition: md.c:108
static MdfdVec * _mdfd_openseg(SMgrRelation reln, ForkNumber forkno, BlockNumber segno, int oflags)
Definition: md.c:1772
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:670
static BlockNumber _mdnblocks(SMgrRelation reln, ForkNumber forknum, MdfdVec *seg)
Definition: md.c:1940
int md_num_open_segs[MAX_FORKNUM+1]
Definition: smgr.h:71
struct _MdfdVec * md_seg_fds[MAX_FORKNUM+1]
Definition: smgr.h:72
#define elog
Definition: elog.h:219
static MdfdVec * mdopen ( SMgrRelation  reln,
ForkNumber  forknum,
int  behavior 
)
static

Definition at line 573 of file md.c.

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

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

574 {
575  MdfdVec *mdfd;
576  char *path;
577  File fd;
578 
579  /* No work if already open */
580  if (reln->md_num_open_segs[forknum] > 0)
581  return &reln->md_seg_fds[forknum][0];
582 
583  path = relpath(reln->smgr_rnode, forknum);
584 
585  fd = PathNameOpenFile(path, O_RDWR | PG_BINARY, 0600);
586 
587  if (fd < 0)
588  {
589  /*
590  * During bootstrap, there are cases where a system relation will be
591  * accessed (by internal backend processes) before the bootstrap
592  * script nominally creates it. Therefore, accept mdopen() as a
593  * substitute for mdcreate() in bootstrap mode only. (See mdcreate)
594  */
596  fd = PathNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, 0600);
597  if (fd < 0)
598  {
599  if ((behavior & EXTENSION_RETURN_NULL) &&
600  FILE_POSSIBLY_DELETED(errno))
601  {
602  pfree(path);
603  return NULL;
604  }
605  ereport(ERROR,
607  errmsg("could not open file \"%s\": %m", path)));
608  }
609  }
610 
611  pfree(path);
612 
613  _fdvec_resize(reln, forknum, 1);
614  mdfd = &reln->md_seg_fds[forknum][0];
615  mdfd->mdfd_vfd = fd;
616  mdfd->mdfd_segno = 0;
617 
618  Assert(_mdnblocks(reln, forknum, mdfd) <= ((BlockNumber) RELSEG_SIZE));
619 
620  return mdfd;
621 }
File PathNameOpenFile(FileName fileName, int fileFlags, int fileMode)
Definition: fd.c:1266
BlockNumber mdfd_segno
Definition: md.c:111
uint32 BlockNumber
Definition: block.h:31
static int fd(const char *x, int i)
Definition: preproc-init.c:105
#define PG_BINARY
Definition: c.h:1037
void pfree(void *pointer)
Definition: mcxt.c:992
#define ERROR
Definition: elog.h:43
#define EXTENSION_RETURN_NULL
Definition: md.c:166
RelFileNodeBackend smgr_rnode
Definition: smgr.h:43
int errcode_for_file_access(void)
Definition: elog.c:598
#define ereport(elevel, rest)
Definition: elog.h:122
static void _fdvec_resize(SMgrRelation reln, ForkNumber forknum, int nseg)
Definition: md.c:1711
Definition: md.c:108
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:670
static BlockNumber _mdnblocks(SMgrRelation reln, ForkNumber forknum, MdfdVec *seg)
Definition: md.c:1940
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:365
int md_num_open_segs[MAX_FORKNUM+1]
Definition: smgr.h:71
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define relpath(rnode, forknum)
Definition: relpath.h:71
struct _MdfdVec * md_seg_fds[MAX_FORKNUM+1]
Definition: smgr.h:72
File mdfd_vfd
Definition: md.c:110
int File
Definition: fd.h:51
#define FILE_POSSIBLY_DELETED(err)
Definition: md.c:65
void mdpostckpt ( void  )

Definition at line 1360 of file md.c.

References AbsorbFsyncRequests(), PendingUnlinkEntry::cycle_ctr, ereport, errcode_for_file_access(), errmsg(), linitial, list_delete_first(), MAIN_FORKNUM, mdckpt_cycle_ctr, NIL, pfree(), relpathperm, PendingUnlinkEntry::rnode, unlink(), UNLINKS_PER_ABSORB, and WARNING.

1361 {
1362  int absorb_counter;
1363 
1364  absorb_counter = UNLINKS_PER_ABSORB;
1365  while (pendingUnlinks != NIL)
1366  {
1368  char *path;
1369 
1370  /*
1371  * New entries are appended to the end, so if the entry is new we've
1372  * reached the end of old entries.
1373  *
1374  * Note: if just the right number of consecutive checkpoints fail, we
1375  * could be fooled here by cycle_ctr wraparound. However, the only
1376  * consequence is that we'd delay unlinking for one more checkpoint,
1377  * which is perfectly tolerable.
1378  */
1379  if (entry->cycle_ctr == mdckpt_cycle_ctr)
1380  break;
1381 
1382  /* Unlink the file */
1383  path = relpathperm(entry->rnode, MAIN_FORKNUM);
1384  if (unlink(path) < 0)
1385  {
1386  /*
1387  * There's a race condition, when the database is dropped at the
1388  * same time that we process the pending unlink requests. If the
1389  * DROP DATABASE deletes the file before we do, we will get ENOENT
1390  * here. rmtree() also has to ignore ENOENT errors, to deal with
1391  * the possibility that we delete the file first.
1392  */
1393  if (errno != ENOENT)
1394  ereport(WARNING,
1396  errmsg("could not remove file \"%s\": %m", path)));
1397  }
1398  pfree(path);
1399 
1400  /* And remove the list entry */
1402  pfree(entry);
1403 
1404  /*
1405  * As in mdsync, we don't want to stop absorbing fsync requests for a
1406  * long time when there are many deletions to be done. We can safely
1407  * call AbsorbFsyncRequests() at this point in the loop (note it might
1408  * try to delete list entries).
1409  */
1410  if (--absorb_counter <= 0)
1411  {
1413  absorb_counter = UNLINKS_PER_ABSORB;
1414  }
1415  }
1416 }
#define NIL
Definition: pg_list.h:69
#define relpathperm(rnode, forknum)
Definition: relpath.h:67
CycleCtr cycle_ctr
Definition: md.c:151
static CycleCtr mdckpt_cycle_ctr
Definition: md.c:159
void pfree(void *pointer)
Definition: mcxt.c:992
#define linitial(l)
Definition: pg_list.h:110
RelFileNode rnode
Definition: md.c:150
int errcode_for_file_access(void)
Definition: elog.c:598
int unlink(const char *filename)
#define ereport(elevel, rest)
Definition: elog.h:122
#define WARNING
Definition: elog.h:40
int errmsg(const char *fmt,...)
Definition: elog.c:797
void AbsorbFsyncRequests(void)
#define UNLINKS_PER_ABSORB
Definition: md.c:44
static List * pendingUnlinks
Definition: md.c:155
List * list_delete_first(List *list)
Definition: list.c:666
void mdpreckpt ( void  )

Definition at line 1345 of file md.c.

References mdckpt_cycle_ctr.

1346 {
1347  /*
1348  * Any unlink requests arriving after this point will be assigned the next
1349  * cycle counter, and won't be unlinked until next checkpoint.
1350  */
1351  mdckpt_cycle_ctr++;
1352 }
static CycleCtr mdckpt_cycle_ctr
Definition: md.c:159
void mdprefetch ( SMgrRelation  reln,
ForkNumber  forknum,
BlockNumber  blocknum 
)

Definition at line 658 of file md.c.

References _mdfd_getseg(), Assert, EXTENSION_FAIL, FilePrefetch(), and _MdfdVec::mdfd_vfd.

659 {
660 #ifdef USE_PREFETCH
661  off_t seekpos;
662  MdfdVec *v;
663 
664  v = _mdfd_getseg(reln, forknum, blocknum, false, EXTENSION_FAIL);
665 
666  seekpos = (off_t) BLCKSZ *(blocknum % ((BlockNumber) RELSEG_SIZE));
667 
668  Assert(seekpos < (off_t) BLCKSZ * RELSEG_SIZE);
669 
670  (void) FilePrefetch(v->mdfd_vfd, seekpos, BLCKSZ);
671 #endif /* USE_PREFETCH */
672 }
static MdfdVec * _mdfd_getseg(SMgrRelation reln, ForkNumber forkno, BlockNumber blkno, bool skipFsync, int behavior)
Definition: md.c:1812
uint32 BlockNumber
Definition: block.h:31
#define EXTENSION_FAIL
Definition: md.c:164
int FilePrefetch(File file, off_t offset, int amount)
Definition: fd.c:1553
Definition: md.c:108
#define Assert(condition)
Definition: c.h:670
File mdfd_vfd
Definition: md.c:110
void mdread ( SMgrRelation  reln,
ForkNumber  forknum,
BlockNumber  blocknum,
char *  buffer 
)

Definition at line 730 of file md.c.

References _mdfd_getseg(), Assert, RelFileNodeBackend::backend, RelFileNode::dbNode, ereport, errcode(), errcode_for_file_access(), errmsg(), ERROR, EXTENSION_CREATE_RECOVERY, EXTENSION_FAIL, FilePathName(), FileRead(), FileSeek(), InRecovery, _MdfdVec::mdfd_vfd, MemSet, RelFileNodeBackend::node, RelFileNode::relNode, SMgrRelationData::smgr_rnode, RelFileNode::spcNode, and zero_damaged_pages.

732 {
733  off_t seekpos;
734  int nbytes;
735  MdfdVec *v;
736 
737  TRACE_POSTGRESQL_SMGR_MD_READ_START(forknum, blocknum,
738  reln->smgr_rnode.node.spcNode,
739  reln->smgr_rnode.node.dbNode,
740  reln->smgr_rnode.node.relNode,
741  reln->smgr_rnode.backend);
742 
743  v = _mdfd_getseg(reln, forknum, blocknum, false,
745 
746  seekpos = (off_t) BLCKSZ *(blocknum % ((BlockNumber) RELSEG_SIZE));
747 
748  Assert(seekpos < (off_t) BLCKSZ * RELSEG_SIZE);
749 
750  if (FileSeek(v->mdfd_vfd, seekpos, SEEK_SET) != seekpos)
751  ereport(ERROR,
753  errmsg("could not seek to block %u in file \"%s\": %m",
754  blocknum, FilePathName(v->mdfd_vfd))));
755 
756  nbytes = FileRead(v->mdfd_vfd, buffer, BLCKSZ);
757 
758  TRACE_POSTGRESQL_SMGR_MD_READ_DONE(forknum, blocknum,
759  reln->smgr_rnode.node.spcNode,
760  reln->smgr_rnode.node.dbNode,
761  reln->smgr_rnode.node.relNode,
762  reln->smgr_rnode.backend,
763  nbytes,
764  BLCKSZ);
765 
766  if (nbytes != BLCKSZ)
767  {
768  if (nbytes < 0)
769  ereport(ERROR,
771  errmsg("could not read block %u in file \"%s\": %m",
772  blocknum, FilePathName(v->mdfd_vfd))));
773 
774  /*
775  * Short read: we are at or past EOF, or we read a partial block at
776  * EOF. Normally this is an error; upper levels should never try to
777  * read a nonexistent block. However, if zero_damaged_pages is ON or
778  * we are InRecovery, we should instead return zeroes without
779  * complaining. This allows, for example, the case of trying to
780  * update a block that was later truncated away.
781  */
783  MemSet(buffer, 0, BLCKSZ);
784  else
785  ereport(ERROR,
786  (errcode(ERRCODE_DATA_CORRUPTED),
787  errmsg("could not read block %u in file \"%s\": read only %d of %d bytes",
788  blocknum, FilePathName(v->mdfd_vfd),
789  nbytes, BLCKSZ)));
790  }
791 }
static MdfdVec * _mdfd_getseg(SMgrRelation reln, ForkNumber forkno, BlockNumber blkno, bool skipFsync, int behavior)
Definition: md.c:1812
bool InRecovery
Definition: xlog.c:190
int errcode(int sqlerrcode)
Definition: elog.c:575
#define MemSet(start, val, len)
Definition: c.h:852
uint32 BlockNumber
Definition: block.h:31
char * FilePathName(File file)
Definition: fd.c:1923
#define EXTENSION_FAIL
Definition: md.c:164
#define ERROR
Definition: elog.h:43
RelFileNodeBackend smgr_rnode
Definition: smgr.h:43
int errcode_for_file_access(void)
Definition: elog.c:598
#define EXTENSION_CREATE_RECOVERY
Definition: md.c:170
#define ereport(elevel, rest)
Definition: elog.h:122
Definition: md.c:108
RelFileNode node
Definition: relfilenode.h:74
#define Assert(condition)
Definition: c.h:670
BackendId backend
Definition: relfilenode.h:75
int errmsg(const char *fmt,...)
Definition: elog.c:797
off_t FileSeek(File file, off_t offset, int whence)
Definition: fd.c:1802
File mdfd_vfd
Definition: md.c:110
int FileRead(File file, char *buffer, int amount)
Definition: fd.c:1604
bool zero_damaged_pages
Definition: bufmgr.c:108
void mdsync ( void  )

Definition at line 1053 of file md.c.

References _mdfd_getseg(), _mdfd_segpath(), AbsorbFsyncRequests(), Assert, bms_first_member(), bms_free(), PendingOperationEntry::canceled, CheckpointStats, CheckpointStatsData::ckpt_agg_sync_time, CheckpointStatsData::ckpt_longest_sync, CheckpointStatsData::ckpt_sync_rels, PendingOperationEntry::cycle_ctr, DEBUG1, elog, enableFsync, ereport, errcode_for_file_access(), errmsg(), ERROR, EXTENSION_DONT_CHECK_SIZE, EXTENSION_RETURN_NULL, FILE_POSSIBLY_DELETED, FilePathName(), FileSync(), FSYNCS_PER_ABSORB, HASH_REMOVE, hash_search(), hash_seq_init(), hash_seq_search(), INSTR_TIME_GET_MICROSEC, INSTR_TIME_SET_CURRENT, INSTR_TIME_SUBTRACT, InvalidBackendId, log_checkpoints, longest(), MAX_FORKNUM, _MdfdVec::mdfd_vfd, mdsync_cycle_ctr, NULL, pfree(), PendingOperationEntry::requests, PendingOperationEntry::rnode, and smgropen().

Referenced by SetForwardFsyncRequests().

1054 {
1055  static bool mdsync_in_progress = false;
1056 
1057  HASH_SEQ_STATUS hstat;
1058  PendingOperationEntry *entry;
1059  int absorb_counter;
1060 
1061  /* Statistics on sync times */
1062  int processed = 0;
1063  instr_time sync_start,
1064  sync_end,
1065  sync_diff;
1066  uint64 elapsed;
1067  uint64 longest = 0;
1068  uint64 total_elapsed = 0;
1069 
1070  /*
1071  * This is only called during checkpoints, and checkpoints should only
1072  * occur in processes that have created a pendingOpsTable.
1073  */
1074  if (!pendingOpsTable)
1075  elog(ERROR, "cannot sync without a pendingOpsTable");
1076 
1077  /*
1078  * If we are in the checkpointer, the sync had better include all fsync
1079  * requests that were queued by backends up to this point. The tightest
1080  * race condition that could occur is that a buffer that must be written
1081  * and fsync'd for the checkpoint could have been dumped by a backend just
1082  * before it was visited by BufferSync(). We know the backend will have
1083  * queued an fsync request before clearing the buffer's dirtybit, so we
1084  * are safe as long as we do an Absorb after completing BufferSync().
1085  */
1087 
1088  /*
1089  * To avoid excess fsync'ing (in the worst case, maybe a never-terminating
1090  * checkpoint), we want to ignore fsync requests that are entered into the
1091  * hashtable after this point --- they should be processed next time,
1092  * instead. We use mdsync_cycle_ctr to tell old entries apart from new
1093  * ones: new ones will have cycle_ctr equal to the incremented value of
1094  * mdsync_cycle_ctr.
1095  *
1096  * In normal circumstances, all entries present in the table at this point
1097  * will have cycle_ctr exactly equal to the current (about to be old)
1098  * value of mdsync_cycle_ctr. However, if we fail partway through the
1099  * fsync'ing loop, then older values of cycle_ctr might remain when we
1100  * come back here to try again. Repeated checkpoint failures would
1101  * eventually wrap the counter around to the point where an old entry
1102  * might appear new, causing us to skip it, possibly allowing a checkpoint
1103  * to succeed that should not have. To forestall wraparound, any time the
1104  * previous mdsync() failed to complete, run through the table and
1105  * forcibly set cycle_ctr = mdsync_cycle_ctr.
1106  *
1107  * Think not to merge this loop with the main loop, as the problem is
1108  * exactly that that loop may fail before having visited all the entries.
1109  * From a performance point of view it doesn't matter anyway, as this path
1110  * will never be taken in a system that's functioning normally.
1111  */
1112  if (mdsync_in_progress)
1113  {
1114  /* prior try failed, so update any stale cycle_ctr values */
1115  hash_seq_init(&hstat, pendingOpsTable);
1116  while ((entry = (PendingOperationEntry *) hash_seq_search(&hstat)) != NULL)
1117  {
1118  entry->cycle_ctr = mdsync_cycle_ctr;
1119  }
1120  }
1121 
1122  /* Advance counter so that new hashtable entries are distinguishable */
1123  mdsync_cycle_ctr++;
1124 
1125  /* Set flag to detect failure if we don't reach the end of the loop */
1126  mdsync_in_progress = true;
1127 
1128  /* Now scan the hashtable for fsync requests to process */
1129  absorb_counter = FSYNCS_PER_ABSORB;
1130  hash_seq_init(&hstat, pendingOpsTable);
1131  while ((entry = (PendingOperationEntry *) hash_seq_search(&hstat)) != NULL)
1132  {
1133  ForkNumber forknum;
1134 
1135  /*
1136  * If the entry is new then don't process it this time; it might
1137  * contain multiple fsync-request bits, but they are all new. Note
1138  * "continue" bypasses the hash-remove call at the bottom of the loop.
1139  */
1140  if (entry->cycle_ctr == mdsync_cycle_ctr)
1141  continue;
1142 
1143  /* Else assert we haven't missed it */
1144  Assert((CycleCtr) (entry->cycle_ctr + 1) == mdsync_cycle_ctr);
1145 
1146  /*
1147  * Scan over the forks and segments represented by the entry.
1148  *
1149  * The bitmap manipulations are slightly tricky, because we can call
1150  * AbsorbFsyncRequests() inside the loop and that could result in
1151  * bms_add_member() modifying and even re-palloc'ing the bitmapsets.
1152  * This is okay because we unlink each bitmapset from the hashtable
1153  * entry before scanning it. That means that any incoming fsync
1154  * requests will be processed now if they reach the table before we
1155  * begin to scan their fork.
1156  */
1157  for (forknum = 0; forknum <= MAX_FORKNUM; forknum++)
1158  {
1159  Bitmapset *requests = entry->requests[forknum];
1160  int segno;
1161 
1162  entry->requests[forknum] = NULL;
1163  entry->canceled[forknum] = false;
1164 
1165  while ((segno = bms_first_member(requests)) >= 0)
1166  {
1167  int failures;
1168 
1169  /*
1170  * If fsync is off then we don't have to bother opening the
1171  * file at all. (We delay checking until this point so that
1172  * changing fsync on the fly behaves sensibly.)
1173  */
1174  if (!enableFsync)
1175  continue;
1176 
1177  /*
1178  * If in checkpointer, we want to absorb pending requests
1179  * every so often to prevent overflow of the fsync request
1180  * queue. It is unspecified whether newly-added entries will
1181  * be visited by hash_seq_search, but we don't care since we
1182  * don't need to process them anyway.
1183  */
1184  if (--absorb_counter <= 0)
1185  {
1187  absorb_counter = FSYNCS_PER_ABSORB;
1188  }
1189 
1190  /*
1191  * The fsync table could contain requests to fsync segments
1192  * that have been deleted (unlinked) by the time we get to
1193  * them. Rather than just hoping an ENOENT (or EACCES on
1194  * Windows) error can be ignored, what we do on error is
1195  * absorb pending requests and then retry. Since mdunlink()
1196  * queues a "cancel" message before actually unlinking, the
1197  * fsync request is guaranteed to be marked canceled after the
1198  * absorb if it really was this case. DROP DATABASE likewise
1199  * has to tell us to forget fsync requests before it starts
1200  * deletions.
1201  */
1202  for (failures = 0;; failures++) /* loop exits at "break" */
1203  {
1204  SMgrRelation reln;
1205  MdfdVec *seg;
1206  char *path;
1207  int save_errno;
1208 
1209  /*
1210  * Find or create an smgr hash entry for this relation.
1211  * This may seem a bit unclean -- md calling smgr? But
1212  * it's really the best solution. It ensures that the
1213  * open file reference isn't permanently leaked if we get
1214  * an error here. (You may say "but an unreferenced
1215  * SMgrRelation is still a leak!" Not really, because the
1216  * only case in which a checkpoint is done by a process
1217  * that isn't about to shut down is in the checkpointer,
1218  * and it will periodically do smgrcloseall(). This fact
1219  * justifies our not closing the reln in the success path
1220  * either, which is a good thing since in non-checkpointer
1221  * cases we couldn't safely do that.)
1222  */
1223  reln = smgropen(entry->rnode, InvalidBackendId);
1224 
1225  /* Attempt to open and fsync the target segment */
1226  seg = _mdfd_getseg(reln, forknum,
1227  (BlockNumber) segno * (BlockNumber) RELSEG_SIZE,
1228  false,
1231 
1232  INSTR_TIME_SET_CURRENT(sync_start);
1233 
1234  if (seg != NULL &&
1235  FileSync(seg->mdfd_vfd) >= 0)
1236  {
1237  /* Success; update statistics about sync timing */
1238  INSTR_TIME_SET_CURRENT(sync_end);
1239  sync_diff = sync_end;
1240  INSTR_TIME_SUBTRACT(sync_diff, sync_start);
1241  elapsed = INSTR_TIME_GET_MICROSEC(sync_diff);
1242  if (elapsed > longest)
1243  longest = elapsed;
1244  total_elapsed += elapsed;
1245  processed++;
1246  if (log_checkpoints)
1247  elog(DEBUG1, "checkpoint sync: number=%d file=%s time=%.3f msec",
1248  processed,
1249  FilePathName(seg->mdfd_vfd),
1250  (double) elapsed / 1000);
1251 
1252  break; /* out of retry loop */
1253  }
1254 
1255  /* Compute file name for use in message */
1256  save_errno = errno;
1257  path = _mdfd_segpath(reln, forknum, (BlockNumber) segno);
1258  errno = save_errno;
1259 
1260  /*
1261  * It is possible that the relation has been dropped or
1262  * truncated since the fsync request was entered.
1263  * Therefore, allow ENOENT, but only if we didn't fail
1264  * already on this file. This applies both for
1265  * _mdfd_getseg() and for FileSync, since fd.c might have
1266  * closed the file behind our back.
1267  *
1268  * XXX is there any point in allowing more than one retry?
1269  * Don't see one at the moment, but easy to change the
1270  * test here if so.
1271  */
1272  if (!FILE_POSSIBLY_DELETED(errno) ||
1273  failures > 0)
1274  ereport(ERROR,
1276  errmsg("could not fsync file \"%s\": %m",
1277  path)));
1278  else
1279  ereport(DEBUG1,
1281  errmsg("could not fsync file \"%s\" but retrying: %m",
1282  path)));
1283  pfree(path);
1284 
1285  /*
1286  * Absorb incoming requests and check to see if a cancel
1287  * arrived for this relation fork.
1288  */
1290  absorb_counter = FSYNCS_PER_ABSORB; /* might as well... */
1291 
1292  if (entry->canceled[forknum])
1293  break;
1294  } /* end retry loop */
1295  }
1296  bms_free(requests);
1297  }
1298 
1299  /*
1300  * We've finished everything that was requested before we started to
1301  * scan the entry. If no new requests have been inserted meanwhile,
1302  * remove the entry. Otherwise, update its cycle counter, as all the
1303  * requests now in it must have arrived during this cycle.
1304  */
1305  for (forknum = 0; forknum <= MAX_FORKNUM; forknum++)
1306  {
1307  if (entry->requests[forknum] != NULL)
1308  break;
1309  }
1310  if (forknum <= MAX_FORKNUM)
1311  entry->cycle_ctr = mdsync_cycle_ctr;
1312  else
1313  {
1314  /* Okay to remove it */
1315  if (hash_search(pendingOpsTable, &entry->rnode,
1316  HASH_REMOVE, NULL) == NULL)
1317  elog(ERROR, "pendingOpsTable corrupted");
1318  }
1319  } /* end loop over hashtable entries */
1320 
1321  /* Return sync performance metrics for report at checkpoint end */
1322  CheckpointStats.ckpt_sync_rels = processed;
1324  CheckpointStats.ckpt_agg_sync_time = total_elapsed;
1325 
1326  /* Flag successful completion of mdsync */
1327  mdsync_in_progress = false;
1328 }
uint64 ckpt_agg_sync_time
Definition: xlog.h:213
bool log_checkpoints
Definition: xlog.c:100
int bms_first_member(Bitmapset *a)
Definition: bitmapset.c:855
int ckpt_sync_rels
Definition: xlog.h:211
#define DEBUG1
Definition: elog.h:25
static MdfdVec * _mdfd_getseg(SMgrRelation reln, ForkNumber forkno, BlockNumber blkno, bool skipFsync, int behavior)
Definition: md.c:1812
#define EXTENSION_DONT_CHECK_SIZE
Definition: md.c:178
static CycleCtr mdsync_cycle_ctr
Definition: md.c:158
#define FSYNCS_PER_ABSORB
Definition: md.c:43
struct timeval instr_time
Definition: instr_time.h:147
RelFileNode rnode
Definition: md.c:140
int FileSync(File file)
Definition: fd.c:1785
uint32 BlockNumber
Definition: block.h:31
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:885
char * FilePathName(File file)
Definition: fd.c:1923
CycleCtr cycle_ctr
Definition: md.c:141
static HTAB * pendingOpsTable
Definition: md.c:154
bool canceled[MAX_FORKNUM+1]
Definition: md.c:145
void pfree(void *pointer)
Definition: mcxt.c:992
#define ERROR
Definition: elog.h:43
#define EXTENSION_RETURN_NULL
Definition: md.c:166
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:167
int errcode_for_file_access(void)
Definition: elog.c:598
#define ereport(elevel, rest)
Definition: elog.h:122
SMgrRelation smgropen(RelFileNode rnode, BackendId backend)
Definition: smgr.c:137
ForkNumber
Definition: relpath.h:24
#define InvalidBackendId
Definition: backendid.h:23
Definition: md.c:108
void bms_free(Bitmapset *a)
Definition: bitmapset.c:200
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:670
#define INSTR_TIME_GET_MICROSEC(t)
Definition: instr_time.h:202
CheckpointStatsData CheckpointStats
Definition: xlog.c:171
#define MAX_FORKNUM
Definition: relpath.h:39
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1353
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1343
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:153
static chr * longest(struct vars *v, struct dfa *d, chr *start, chr *stop, int *hitstopp)
Definition: rege_dfa.c:42
bool enableFsync
Definition: globals.c:110
int errmsg(const char *fmt,...)
Definition: elog.c:797
Bitmapset * requests[MAX_FORKNUM+1]
Definition: md.c:143
#define elog
Definition: elog.h:219
void AbsorbFsyncRequests(void)
File mdfd_vfd
Definition: md.c:110
uint16 CycleCtr
Definition: md.c:136
#define FILE_POSSIBLY_DELETED(err)
Definition: md.c:65
static char * _mdfd_segpath(SMgrRelation reln, ForkNumber forknum, BlockNumber segno)
Definition: md.c:1749
uint64 ckpt_longest_sync
Definition: xlog.h:212
void mdtruncate ( SMgrRelation  reln,
ForkNumber  forknum,
BlockNumber  nblocks 
)

Definition at line 927 of file md.c.

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_rnode, and SmgrIsTemp.

928 {
929  BlockNumber curnblk;
930  BlockNumber priorblocks;
931  int curopensegs;
932 
933  /*
934  * NOTE: mdnblocks makes sure we have opened all active segments, so that
935  * truncation loop will get them all!
936  */
937  curnblk = mdnblocks(reln, forknum);
938  if (nblocks > curnblk)
939  {
940  /* Bogus request ... but no complaint if InRecovery */
941  if (InRecovery)
942  return;
943  ereport(ERROR,
944  (errmsg("could not truncate file \"%s\" to %u blocks: it's only %u blocks now",
945  relpath(reln->smgr_rnode, forknum),
946  nblocks, curnblk)));
947  }
948  if (nblocks == curnblk)
949  return; /* no work */
950 
951  /*
952  * Truncate segments, starting at the last one. Starting at the end makes
953  * managing the memory for the fd array easier, should there be errors.
954  */
955  curopensegs = reln->md_num_open_segs[forknum];
956  while (curopensegs > 0)
957  {
958  MdfdVec *v;
959 
960  priorblocks = (curopensegs - 1) * RELSEG_SIZE;
961 
962  v = &reln->md_seg_fds[forknum][curopensegs - 1];
963 
964  if (priorblocks > nblocks)
965  {
966  /*
967  * This segment is no longer active. We truncate the file, but do
968  * not delete it, for reasons explained in the header comments.
969  */
970  if (FileTruncate(v->mdfd_vfd, 0) < 0)
971  ereport(ERROR,
973  errmsg("could not truncate file \"%s\": %m",
974  FilePathName(v->mdfd_vfd))));
975 
976  if (!SmgrIsTemp(reln))
977  register_dirty_segment(reln, forknum, v);
978 
979  /* we never drop the 1st segment */
980  Assert(v != &reln->md_seg_fds[forknum][0]);
981 
982  FileClose(v->mdfd_vfd);
983  _fdvec_resize(reln, forknum, curopensegs - 1);
984  }
985  else if (priorblocks + ((BlockNumber) RELSEG_SIZE) > nblocks)
986  {
987  /*
988  * This is the last segment we want to keep. Truncate the file to
989  * the right length. NOTE: if nblocks is exactly a multiple K of
990  * RELSEG_SIZE, we will truncate the K+1st segment to 0 length but
991  * keep it. This adheres to the invariant given in the header
992  * comments.
993  */
994  BlockNumber lastsegblocks = nblocks - priorblocks;
995 
996  if (FileTruncate(v->mdfd_vfd, (off_t) lastsegblocks * BLCKSZ) < 0)
997  ereport(ERROR,
999  errmsg("could not truncate file \"%s\" to %u blocks: %m",
1000  FilePathName(v->mdfd_vfd),
1001  nblocks)));
1002  if (!SmgrIsTemp(reln))
1003  register_dirty_segment(reln, forknum, v);
1004  }
1005  else
1006  {
1007  /*
1008  * We still need this segment, so nothing to do for this and any
1009  * earlier segment.
1010  */
1011  break;
1012  }
1013  curopensegs--;
1014  }
1015 }
BlockNumber mdnblocks(SMgrRelation reln, ForkNumber forknum)
Definition: md.c:872
bool InRecovery
Definition: xlog.c:190
uint32 BlockNumber
Definition: block.h:31
char * FilePathName(File file)
Definition: fd.c:1923
#define SmgrIsTemp(smgr)
Definition: smgr.h:80
#define ERROR
Definition: elog.h:43
RelFileNodeBackend smgr_rnode
Definition: smgr.h:43
int FileTruncate(File file, off_t offset)
Definition: fd.c:1890
int errcode_for_file_access(void)
Definition: elog.c:598
#define ereport(elevel, rest)
Definition: elog.h:122
static void _fdvec_resize(SMgrRelation reln, ForkNumber forknum, int nseg)
Definition: md.c:1711
Definition: md.c:108
void FileClose(File file)
Definition: fd.c:1456
#define Assert(condition)
Definition: c.h:670
int md_num_open_segs[MAX_FORKNUM+1]
Definition: smgr.h:71
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define relpath(rnode, forknum)
Definition: relpath.h:71
struct _MdfdVec * md_seg_fds[MAX_FORKNUM+1]
Definition: smgr.h:72
File mdfd_vfd
Definition: md.c:110
static void register_dirty_segment(SMgrRelation reln, ForkNumber forknum, MdfdVec *seg)
Definition: md.c:1428
void mdunlink ( RelFileNodeBackend  rnode,
ForkNumber  forkNum,
bool  isRedo 
)

Definition at line 386 of file md.c.

References ForgetRelationFsyncRequests(), InvalidForkNumber, MAX_FORKNUM, mdunlinkfork(), RelFileNodeBackend::node, and RelFileNodeBackendIsTemp.

387 {
388  /*
389  * We have to clean out any pending fsync requests for the doomed
390  * relation, else the next mdsync() will fail. There can't be any such
391  * requests for a temp relation, though. We can send just one request
392  * even when deleting multiple forks, since the fsync queuing code accepts
393  * the "InvalidForkNumber = all forks" convention.
394  */
395  if (!RelFileNodeBackendIsTemp(rnode))
396  ForgetRelationFsyncRequests(rnode.node, forkNum);
397 
398  /* Now do the per-fork work */
399  if (forkNum == InvalidForkNumber)
400  {
401  for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
402  mdunlinkfork(rnode, forkNum, isRedo);
403  }
404  else
405  mdunlinkfork(rnode, forkNum, isRedo);
406 }
#define RelFileNodeBackendIsTemp(rnode)
Definition: relfilenode.h:78
void ForgetRelationFsyncRequests(RelFileNode rnode, ForkNumber forknum)
Definition: md.c:1651
static void mdunlinkfork(RelFileNodeBackend rnode, ForkNumber forkNum, bool isRedo)
Definition: md.c:409
RelFileNode node
Definition: relfilenode.h:74
#define MAX_FORKNUM
Definition: relpath.h:39
static void mdunlinkfork ( RelFileNodeBackend  rnode,
ForkNumber  forkNum,
bool  isRedo 
)
static

Definition at line 409 of file md.c.

References CloseTransientFile(), ereport, errcode_for_file_access(), errmsg(), fd(), ftruncate, MAIN_FORKNUM, OpenTransientFile(), palloc(), pfree(), PG_BINARY, register_unlink(), RelFileNodeBackendIsTemp, relpath, unlink(), and WARNING.

Referenced by mdunlink().

410 {
411  char *path;
412  int ret;
413 
414  path = relpath(rnode, forkNum);
415 
416  /*
417  * Delete or truncate the first segment.
418  */
419  if (isRedo || forkNum != MAIN_FORKNUM || RelFileNodeBackendIsTemp(rnode))
420  {
421  ret = unlink(path);
422  if (ret < 0 && errno != ENOENT)
425  errmsg("could not remove file \"%s\": %m", path)));
426  }
427  else
428  {
429  /* truncate(2) would be easier here, but Windows hasn't got it */
430  int fd;
431 
432  fd = OpenTransientFile(path, O_RDWR | PG_BINARY, 0);
433  if (fd >= 0)
434  {
435  int save_errno;
436 
437  ret = ftruncate(fd, 0);
438  save_errno = errno;
439  CloseTransientFile(fd);
440  errno = save_errno;
441  }
442  else
443  ret = -1;
444  if (ret < 0 && errno != ENOENT)
447  errmsg("could not truncate file \"%s\": %m", path)));
448 
449  /* Register request to unlink first segment later */
450  register_unlink(rnode);
451  }
452 
453  /*
454  * Delete any additional segments.
455  */
456  if (ret >= 0)
457  {
458  char *segpath = (char *) palloc(strlen(path) + 12);
459  BlockNumber segno;
460 
461  /*
462  * Note that because we loop until getting ENOENT, we will correctly
463  * remove all inactive segments as well as active ones.
464  */
465  for (segno = 1;; segno++)
466  {
467  sprintf(segpath, "%s.%u", path, segno);
468  if (unlink(segpath) < 0)
469  {
470  /* ENOENT is expected after the last segment... */
471  if (errno != ENOENT)
474  errmsg("could not remove file \"%s\": %m", segpath)));
475  break;
476  }
477  }
478  pfree(segpath);
479  }
480 
481  pfree(path);
482 }
#define RelFileNodeBackendIsTemp(rnode)
Definition: relfilenode.h:78
uint32 BlockNumber
Definition: block.h:31
static int fd(const char *x, int i)
Definition: preproc-init.c:105
#define PG_BINARY
Definition: c.h:1037
void pfree(void *pointer)
Definition: mcxt.c:992
int OpenTransientFile(FileName fileName, int fileFlags, int fileMode)
Definition: fd.c:2093
int errcode_for_file_access(void)
Definition: elog.c:598
int unlink(const char *filename)
#define ereport(elevel, rest)
Definition: elog.h:122
int CloseTransientFile(int fd)
Definition: fd.c:2254
#define WARNING
Definition: elog.h:40
#define ftruncate(a, b)
Definition: win32.h:67
void * palloc(Size size)
Definition: mcxt.c:891
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define relpath(rnode, forknum)
Definition: relpath.h:71
static void register_unlink(RelFileNodeBackend rnode)
Definition: md.c:1464
void mdwrite ( SMgrRelation  reln,
ForkNumber  forknum,
BlockNumber  blocknum,
char *  buffer,
bool  skipFsync 
)

Definition at line 801 of file md.c.

References _mdfd_getseg(), Assert, RelFileNodeBackend::backend, RelFileNode::dbNode, ereport, errcode(), errcode_for_file_access(), errhint(), errmsg(), ERROR, EXTENSION_CREATE_RECOVERY, EXTENSION_FAIL, FilePathName(), FileSeek(), FileWrite(), _MdfdVec::mdfd_vfd, mdnblocks(), RelFileNodeBackend::node, register_dirty_segment(), RelFileNode::relNode, SMgrRelationData::smgr_rnode, SmgrIsTemp, and RelFileNode::spcNode.

803 {
804  off_t seekpos;
805  int nbytes;
806  MdfdVec *v;
807 
808  /* This assert is too expensive to have on normally ... */
809 #ifdef CHECK_WRITE_VS_EXTEND
810  Assert(blocknum < mdnblocks(reln, forknum));
811 #endif
812 
813  TRACE_POSTGRESQL_SMGR_MD_WRITE_START(forknum, blocknum,
814  reln->smgr_rnode.node.spcNode,
815  reln->smgr_rnode.node.dbNode,
816  reln->smgr_rnode.node.relNode,
817  reln->smgr_rnode.backend);
818 
819  v = _mdfd_getseg(reln, forknum, blocknum, skipFsync,
821 
822  seekpos = (off_t) BLCKSZ *(blocknum % ((BlockNumber) RELSEG_SIZE));
823 
824  Assert(seekpos < (off_t) BLCKSZ * RELSEG_SIZE);
825 
826  if (FileSeek(v->mdfd_vfd, seekpos, SEEK_SET) != seekpos)
827  ereport(ERROR,
829  errmsg("could not seek to block %u in file \"%s\": %m",
830  blocknum, FilePathName(v->mdfd_vfd))));
831 
832  nbytes = FileWrite(v->mdfd_vfd, buffer, BLCKSZ);
833 
834  TRACE_POSTGRESQL_SMGR_MD_WRITE_DONE(forknum, blocknum,
835  reln->smgr_rnode.node.spcNode,
836  reln->smgr_rnode.node.dbNode,
837  reln->smgr_rnode.node.relNode,
838  reln->smgr_rnode.backend,
839  nbytes,
840  BLCKSZ);
841 
842  if (nbytes != BLCKSZ)
843  {
844  if (nbytes < 0)
845  ereport(ERROR,
847  errmsg("could not write block %u in file \"%s\": %m",
848  blocknum, FilePathName(v->mdfd_vfd))));
849  /* short write: complain appropriately */
850  ereport(ERROR,
851  (errcode(ERRCODE_DISK_FULL),
852  errmsg("could not write block %u in file \"%s\": wrote only %d of %d bytes",
853  blocknum,
855  nbytes, BLCKSZ),
856  errhint("Check free disk space.")));
857  }
858 
859  if (!skipFsync && !SmgrIsTemp(reln))
860  register_dirty_segment(reln, forknum, v);
861 }
int FileWrite(File file, char *buffer, int amount)
Definition: fd.c:1666
static MdfdVec * _mdfd_getseg(SMgrRelation reln, ForkNumber forkno, BlockNumber blkno, bool skipFsync, int behavior)
Definition: md.c:1812
int errhint(const char *fmt,...)
Definition: elog.c:987
BlockNumber mdnblocks(SMgrRelation reln, ForkNumber forknum)
Definition: md.c:872
int errcode(int sqlerrcode)
Definition: elog.c:575
uint32 BlockNumber
Definition: block.h:31
char * FilePathName(File file)
Definition: fd.c:1923
#define EXTENSION_FAIL
Definition: md.c:164
#define SmgrIsTemp(smgr)
Definition: smgr.h:80
#define ERROR
Definition: elog.h:43
RelFileNodeBackend smgr_rnode
Definition: smgr.h:43
int errcode_for_file_access(void)
Definition: elog.c:598
#define EXTENSION_CREATE_RECOVERY
Definition: md.c:170
#define ereport(elevel, rest)
Definition: elog.h:122
Definition: md.c:108
RelFileNode node
Definition: relfilenode.h:74
#define Assert(condition)
Definition: c.h:670
BackendId backend
Definition: relfilenode.h:75
int errmsg(const char *fmt,...)
Definition: elog.c:797
off_t FileSeek(File file, off_t offset, int whence)
Definition: fd.c:1802
File mdfd_vfd
Definition: md.c:110
static void register_dirty_segment(SMgrRelation reln, ForkNumber forknum, MdfdVec *seg)
Definition: md.c:1428
void mdwriteback ( SMgrRelation  reln,
ForkNumber  forknum,
BlockNumber  blocknum,
BlockNumber  nblocks 
)

Definition at line 681 of file md.c.

References _mdfd_getseg(), Assert, EXTENSION_RETURN_NULL, FileWriteback(), and _MdfdVec::mdfd_vfd.

683 {
684  /*
685  * Issue flush requests in as few requests as possible; have to split at
686  * segment boundaries though, since those are actually separate files.
687  */
688  while (nblocks > 0)
689  {
690  BlockNumber nflush = nblocks;
691  off_t seekpos;
692  MdfdVec *v;
693  int segnum_start,
694  segnum_end;
695 
696  v = _mdfd_getseg(reln, forknum, blocknum, true /* not used */ ,
698 
699  /*
700  * We might be flushing buffers of already removed relations, that's
701  * ok, just ignore that case.
702  */
703  if (!v)
704  return;
705 
706  /* compute offset inside the current segment */
707  segnum_start = blocknum / RELSEG_SIZE;
708 
709  /* compute number of desired writes within the current segment */
710  segnum_end = (blocknum + nblocks - 1) / RELSEG_SIZE;
711  if (segnum_start != segnum_end)
712  nflush = RELSEG_SIZE - (blocknum % ((BlockNumber) RELSEG_SIZE));
713 
714  Assert(nflush >= 1);
715  Assert(nflush <= nblocks);
716 
717  seekpos = (off_t) BLCKSZ *(blocknum % ((BlockNumber) RELSEG_SIZE));
718 
719  FileWriteback(v->mdfd_vfd, seekpos, (off_t) BLCKSZ * nflush);
720 
721  nblocks -= nflush;
722  blocknum += nflush;
723  }
724 }
void FileWriteback(File file, off_t offset, off_t nbytes)
Definition: fd.c:1579
static MdfdVec * _mdfd_getseg(SMgrRelation reln, ForkNumber forkno, BlockNumber blkno, bool skipFsync, int behavior)
Definition: md.c:1812
uint32 BlockNumber
Definition: block.h:31
#define EXTENSION_RETURN_NULL
Definition: md.c:166
Definition: md.c:108
#define Assert(condition)
Definition: c.h:670
File mdfd_vfd
Definition: md.c:110
static void register_dirty_segment ( SMgrRelation  reln,
ForkNumber  forknum,
MdfdVec seg 
)
static

Definition at line 1428 of file md.c.

References Assert, DEBUG1, ereport, errcode_for_file_access(), errmsg(), ERROR, FilePathName(), FileSync(), ForwardFsyncRequest(), _MdfdVec::mdfd_segno, _MdfdVec::mdfd_vfd, RelFileNodeBackend::node, RememberFsyncRequest(), SMgrRelationData::smgr_rnode, and SmgrIsTemp.

Referenced by mdextend(), mdtruncate(), and mdwrite().

1429 {
1430  /* Temp relations should never be fsync'd */
1431  Assert(!SmgrIsTemp(reln));
1432 
1433  if (pendingOpsTable)
1434  {
1435  /* push it into local pending-ops table */
1436  RememberFsyncRequest(reln->smgr_rnode.node, forknum, seg->mdfd_segno);
1437  }
1438  else
1439  {
1440  if (ForwardFsyncRequest(reln->smgr_rnode.node, forknum, seg->mdfd_segno))
1441  return; /* passed it off successfully */
1442 
1443  ereport(DEBUG1,
1444  (errmsg("could not forward fsync request because request queue is full")));
1445 
1446  if (FileSync(seg->mdfd_vfd) < 0)
1447  ereport(ERROR,
1449  errmsg("could not fsync file \"%s\": %m",
1450  FilePathName(seg->mdfd_vfd))));
1451  }
1452 }
void RememberFsyncRequest(RelFileNode rnode, ForkNumber forknum, BlockNumber segno)
Definition: md.c:1513
#define DEBUG1
Definition: elog.h:25
bool ForwardFsyncRequest(RelFileNode rnode, ForkNumber forknum, BlockNumber segno)
BlockNumber mdfd_segno
Definition: md.c:111
int FileSync(File file)
Definition: fd.c:1785
char * FilePathName(File file)
Definition: fd.c:1923
static HTAB * pendingOpsTable
Definition: md.c:154
#define SmgrIsTemp(smgr)
Definition: smgr.h:80
#define ERROR
Definition: elog.h:43
RelFileNodeBackend smgr_rnode
Definition: smgr.h:43
int errcode_for_file_access(void)
Definition: elog.c:598
#define ereport(elevel, rest)
Definition: elog.h:122
RelFileNode node
Definition: relfilenode.h:74
#define Assert(condition)
Definition: c.h:670
int errmsg(const char *fmt,...)
Definition: elog.c:797
File mdfd_vfd
Definition: md.c:110
static void register_unlink ( RelFileNodeBackend  rnode)
static

Definition at line 1464 of file md.c.

References Assert, ForwardFsyncRequest(), IsUnderPostmaster, MAIN_FORKNUM, RelFileNodeBackend::node, pg_usleep(), RelFileNodeBackendIsTemp, RememberFsyncRequest(), and UNLINK_RELATION_REQUEST.

Referenced by mdunlinkfork().

1465 {
1466  /* Should never be used with temp relations */
1468 
1469  if (pendingOpsTable)
1470  {
1471  /* push it into local pending-ops table */
1474  }
1475  else
1476  {
1477  /*
1478  * Notify the checkpointer about it. If we fail to queue the request
1479  * message, we have to sleep and try again, because we can't simply
1480  * delete the file now. Ugly, but hopefully won't happen often.
1481  *
1482  * XXX should we just leave the file orphaned instead?
1483  */
1485  while (!ForwardFsyncRequest(rnode.node, MAIN_FORKNUM,
1487  pg_usleep(10000L); /* 10 msec seems a good number */
1488  }
1489 }
#define UNLINK_RELATION_REQUEST
Definition: md.c:55
void RememberFsyncRequest(RelFileNode rnode, ForkNumber forknum, BlockNumber segno)
Definition: md.c:1513
#define RelFileNodeBackendIsTemp(rnode)
Definition: relfilenode.h:78
bool ForwardFsyncRequest(RelFileNode rnode, ForkNumber forknum, BlockNumber segno)
static HTAB * pendingOpsTable
Definition: md.c:154
void pg_usleep(long microsec)
Definition: signal.c:53
bool IsUnderPostmaster
Definition: globals.c:100
RelFileNode node
Definition: relfilenode.h:74
#define Assert(condition)
Definition: c.h:670
void RememberFsyncRequest ( RelFileNode  rnode,
ForkNumber  forknum,
BlockNumber  segno 
)

Definition at line 1513 of file md.c.

References Assert, bms_add_member(), bms_free(), PendingOperationEntry::canceled, PendingOperationEntry::cycle_ctr, PendingUnlinkEntry::cycle_ctr, RelFileNode::dbNode, FORGET_DATABASE_FSYNC, FORGET_RELATION_FSYNC, HASH_ENTER, HASH_FIND, hash_search(), hash_seq_init(), hash_seq_search(), InvalidForkNumber, lappend(), lfirst, list_delete_cell(), list_head(), lnext, MAIN_FORKNUM, MAX_FORKNUM, mdckpt_cycle_ctr, mdsync_cycle_ctr, MemoryContextSwitchTo(), MemSet, next, NULL, palloc(), pfree(), PendingOperationEntry::requests, PendingOperationEntry::rnode, PendingUnlinkEntry::rnode, and UNLINK_RELATION_REQUEST.

Referenced by AbsorbFsyncRequests(), ForgetDatabaseFsyncRequests(), ForgetRelationFsyncRequests(), register_dirty_segment(), and register_unlink().

1514 {
1516 
1517  if (segno == FORGET_RELATION_FSYNC)
1518  {
1519  /* Remove any pending requests for the relation (one or all forks) */
1520  PendingOperationEntry *entry;
1521 
1523  &rnode,
1524  HASH_FIND,
1525  NULL);
1526  if (entry)
1527  {
1528  /*
1529  * We can't just delete the entry since mdsync could have an
1530  * active hashtable scan. Instead we delete the bitmapsets; this
1531  * is safe because of the way mdsync is coded. We also set the
1532  * "canceled" flags so that mdsync can tell that a cancel arrived
1533  * for the fork(s).
1534  */
1535  if (forknum == InvalidForkNumber)
1536  {
1537  /* remove requests for all forks */
1538  for (forknum = 0; forknum <= MAX_FORKNUM; forknum++)
1539  {
1540  bms_free(entry->requests[forknum]);
1541  entry->requests[forknum] = NULL;
1542  entry->canceled[forknum] = true;
1543  }
1544  }
1545  else
1546  {
1547  /* remove requests for single fork */
1548  bms_free(entry->requests[forknum]);
1549  entry->requests[forknum] = NULL;
1550  entry->canceled[forknum] = true;
1551  }
1552  }
1553  }
1554  else if (segno == FORGET_DATABASE_FSYNC)
1555  {
1556  /* Remove any pending requests for the entire database */
1557  HASH_SEQ_STATUS hstat;
1558  PendingOperationEntry *entry;
1559  ListCell *cell,
1560  *prev,
1561  *next;
1562 
1563  /* Remove fsync requests */
1564  hash_seq_init(&hstat, pendingOpsTable);
1565  while ((entry = (PendingOperationEntry *) hash_seq_search(&hstat)) != NULL)
1566  {
1567  if (entry->rnode.dbNode == rnode.dbNode)
1568  {
1569  /* remove requests for all forks */
1570  for (forknum = 0; forknum <= MAX_FORKNUM; forknum++)
1571  {
1572  bms_free(entry->requests[forknum]);
1573  entry->requests[forknum] = NULL;
1574  entry->canceled[forknum] = true;
1575  }
1576  }
1577  }
1578 
1579  /* Remove unlink requests */
1580  prev = NULL;
1581  for (cell = list_head(pendingUnlinks); cell; cell = next)
1582  {
1583  PendingUnlinkEntry *entry = (PendingUnlinkEntry *) lfirst(cell);
1584 
1585  next = lnext(cell);
1586  if (entry->rnode.dbNode == rnode.dbNode)
1587  {
1589  pfree(entry);
1590  }
1591  else
1592  prev = cell;
1593  }
1594  }
1595  else if (segno == UNLINK_RELATION_REQUEST)
1596  {
1597  /* Unlink request: put it in the linked list */
1599  PendingUnlinkEntry *entry;
1600 
1601  /* PendingUnlinkEntry doesn't store forknum, since it's always MAIN */
1602  Assert(forknum == MAIN_FORKNUM);
1603 
1604  entry = palloc(sizeof(PendingUnlinkEntry));
1605  entry->rnode = rnode;
1606  entry->cycle_ctr = mdckpt_cycle_ctr;
1607 
1609 
1610  MemoryContextSwitchTo(oldcxt);
1611  }
1612  else
1613  {
1614  /* Normal case: enter a request to fsync this segment */
1616  PendingOperationEntry *entry;
1617  bool found;
1618 
1620  &rnode,
1621  HASH_ENTER,
1622  &found);
1623  /* if new entry, initialize it */
1624  if (!found)
1625  {
1626  entry->cycle_ctr = mdsync_cycle_ctr;
1627  MemSet(entry->requests, 0, sizeof(entry->requests));
1628  MemSet(entry->canceled, 0, sizeof(entry->canceled));
1629  }
1630 
1631  /*
1632  * NB: it's intentional that we don't change cycle_ctr if the entry
1633  * already exists. The cycle_ctr must represent the oldest fsync
1634  * request that could be in the entry.
1635  */
1636 
1637  entry->requests[forknum] = bms_add_member(entry->requests[forknum],
1638  (int) segno);
1639 
1640  MemoryContextSwitchTo(oldcxt);
1641  }
1642 }
#define UNLINK_RELATION_REQUEST
Definition: md.c:55
CycleCtr cycle_ctr
Definition: md.c:151
static int32 next
Definition: blutils.c:210
static CycleCtr mdsync_cycle_ctr
Definition: md.c:158
RelFileNode rnode
Definition: md.c:140
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static CycleCtr mdckpt_cycle_ctr
Definition: md.c:159
#define MemSet(start, val, len)
Definition: c.h:852
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:885
CycleCtr cycle_ctr
Definition: md.c:141
static HTAB * pendingOpsTable
Definition: md.c:154
bool canceled[MAX_FORKNUM+1]
Definition: md.c:145
#define FORGET_RELATION_FSYNC
Definition: md.c:53
void pfree(void *pointer)
Definition: mcxt.c:992
RelFileNode rnode
Definition: md.c:150
#define FORGET_DATABASE_FSYNC
Definition: md.c:54
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
#define lnext(lc)
Definition: pg_list.h:105
List * lappend(List *list, void *datum)
Definition: list.c:128
List * list_delete_cell(List *list, ListCell *cell, ListCell *prev)
Definition: list.c:528
void bms_free(Bitmapset *a)
Definition: bitmapset.c:200
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:670
#define lfirst(lc)
Definition: pg_list.h:106
#define MAX_FORKNUM
Definition: relpath.h:39
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1353
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:668
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1343
void * palloc(Size size)
Definition: mcxt.c:891
Bitmapset * requests[MAX_FORKNUM+1]
Definition: md.c:143
static MemoryContext pendingOpsCxt
Definition: md.c:156
static List * pendingUnlinks
Definition: md.c:155
void SetForwardFsyncRequests ( void  )

Definition at line 253 of file md.c.

References Assert, hash_destroy(), mdsync(), NIL, and NULL.

Referenced by StartupXLOG().

254 {
255  /* Perform any pending fsyncs we may have queued up, then drop table */
256  if (pendingOpsTable)
257  {
258  mdsync();
260  }
262 
263  /*
264  * We should not have any pending unlink requests, since mdunlink doesn't
265  * queue unlink requests when isRedo.
266  */
268 }
#define NIL
Definition: pg_list.h:69
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:793
void mdsync(void)
Definition: md.c:1053
static HTAB * pendingOpsTable
Definition: md.c:154
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:670
static List * pendingUnlinks
Definition: md.c:155

Variable Documentation

CycleCtr mdckpt_cycle_ctr = 0
static

Definition at line 159 of file md.c.

Referenced by mdpostckpt(), mdpreckpt(), and RememberFsyncRequest().

MemoryContext MdCxt
static

Definition at line 114 of file md.c.

CycleCtr mdsync_cycle_ctr = 0
static

Definition at line 158 of file md.c.

Referenced by mdsync(), and RememberFsyncRequest().

MemoryContext pendingOpsCxt
static

Definition at line 156 of file md.c.

Referenced by mdinit().

HTAB* pendingOpsTable = NULL
static

Definition at line 154 of file md.c.

List* pendingUnlinks = NIL
static

Definition at line 155 of file md.c.