PostgreSQL Source Code  git master
md.h File Reference
#include "storage/block.h"
#include "storage/relfilenode.h"
#include "storage/smgr.h"
#include "storage/sync.h"
Include dependency graph for md.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

void mdinit (void)
 
void mdopen (SMgrRelation reln)
 
void mdclose (SMgrRelation reln, ForkNumber forknum)
 
void mdcreate (SMgrRelation reln, ForkNumber forknum, bool isRedo)
 
bool mdexists (SMgrRelation reln, ForkNumber forknum)
 
void mdunlink (RelFileNodeBackend rnode, ForkNumber forknum, bool isRedo)
 
void mdextend (SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer, bool skipFsync)
 
void mdprefetch (SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum)
 
void mdread (SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer)
 
void mdwrite (SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer, 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 mdimmedsync (SMgrRelation reln, ForkNumber forknum)
 
void ForgetDatabaseSyncRequests (Oid dbid)
 
void DropRelationFiles (RelFileNode *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)
 

Function Documentation

◆ DropRelationFiles()

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

Definition at line 1001 of file md.c.

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

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

1002 {
1003  SMgrRelation *srels;
1004  int i;
1005 
1006  srels = palloc(sizeof(SMgrRelation) * ndelrels);
1007  for (i = 0; i < ndelrels; i++)
1008  {
1009  SMgrRelation srel = smgropen(delrels[i], InvalidBackendId);
1010 
1011  if (isRedo)
1012  {
1013  ForkNumber fork;
1014 
1015  for (fork = 0; fork <= MAX_FORKNUM; fork++)
1016  XLogDropRelation(delrels[i], fork);
1017  }
1018  srels[i] = srel;
1019  }
1020 
1021  smgrdounlinkall(srels, ndelrels, isRedo);
1022 
1023  for (i = 0; i < ndelrels; i++)
1024  smgrclose(srels[i]);
1025  pfree(srels);
1026 }
void smgrclose(SMgrRelation reln)
Definition: smgr.c:256
void smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo)
Definition: smgr.c:405
void pfree(void *pointer)
Definition: mcxt.c:1031
SMgrRelation smgropen(RelFileNode rnode, BackendId backend)
Definition: smgr.c:145
ForkNumber
Definition: relpath.h:40
#define InvalidBackendId
Definition: backendid.h:23
#define MAX_FORKNUM
Definition: relpath.h:55
void XLogDropRelation(RelFileNode rnode, ForkNumber forknum)
Definition: xlogutils.c:606
void * palloc(Size size)
Definition: mcxt.c:924
int i

◆ ForgetDatabaseSyncRequests()

void ForgetDatabaseSyncRequests ( Oid  dbid)

Definition at line 983 of file md.c.

References RelFileNode::dbNode, INIT_MD_FILETAG, InvalidBlockNumber, InvalidForkNumber, RegisterSyncRequest(), RelFileNode::relNode, RelFileNode::spcNode, and SYNC_FILTER_REQUEST.

Referenced by dbase_redo(), and dropdb().

984 {
985  FileTag tag;
986  RelFileNode rnode;
987 
988  rnode.dbNode = dbid;
989  rnode.spcNode = 0;
990  rnode.relNode = 0;
991 
993 
994  RegisterSyncRequest(&tag, SYNC_FILTER_REQUEST, true /* retryOnError */ );
995 }
#define INIT_MD_FILETAG(a, xx_rnode, xx_forknum, xx_segno)
Definition: md.c:92
bool RegisterSyncRequest(const FileTag *ftag, SyncRequestType type, bool retryOnError)
Definition: sync.c:530
#define InvalidBlockNumber
Definition: block.h:33
Definition: sync.h:45

◆ mdclose()

void mdclose ( SMgrRelation  reln,
ForkNumber  forknum 
)

Definition at line 506 of file md.c.

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

Referenced by mdexists().

507 {
508  int nopensegs = reln->md_num_open_segs[forknum];
509 
510  /* No work if already closed */
511  if (nopensegs == 0)
512  return;
513 
514  /* close segments starting from the end */
515  while (nopensegs > 0)
516  {
517  MdfdVec *v = &reln->md_seg_fds[forknum][nopensegs - 1];
518 
519  /* if not closed already */
520  if (v->mdfd_vfd >= 0)
521  {
522  FileClose(v->mdfd_vfd);
523  v->mdfd_vfd = -1;
524  }
525 
526  nopensegs--;
527  }
528 
529  /* resize just once, avoids pointless reallocations */
530  _fdvec_resize(reln, forknum, 0);
531 }
static void _fdvec_resize(SMgrRelation reln, ForkNumber forknum, int nseg)
Definition: md.c:1033
Definition: md.c:82
void FileClose(File file)
Definition: fd.c:1711
int md_num_open_segs[MAX_FORKNUM+1]
Definition: smgr.h:70
struct _MdfdVec * md_seg_fds[MAX_FORKNUM+1]
Definition: smgr.h:71
File mdfd_vfd
Definition: md.c:84

◆ mdcreate()

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

Definition at line 178 of file md.c.

References _fdvec_resize(), Assert, RelFileNode::dbNode, ereport, errcode_for_file_access(), errmsg(), ERROR, fd(), SMgrRelationData::md_num_open_segs, SMgrRelationData::md_seg_fds, _MdfdVec::mdfd_segno, _MdfdVec::mdfd_vfd, RelFileNodeBackend::node, PathNameOpenFile(), pfree(), PG_BINARY, relpath, SMgrRelationData::smgr_rnode, RelFileNode::spcNode, and TablespaceCreateDbspace().

179 {
180  MdfdVec *mdfd;
181  char *path;
182  File fd;
183 
184  if (isRedo && reln->md_num_open_segs[forkNum] > 0)
185  return; /* created and opened already... */
186 
187  Assert(reln->md_num_open_segs[forkNum] == 0);
188 
189  /*
190  * We may be using the target table space for the first time in this
191  * database, so create a per-database subdirectory if needed.
192  *
193  * XXX this is a fairly ugly violation of module layering, but this seems
194  * to be the best place to put the check. Maybe TablespaceCreateDbspace
195  * should be here and not in commands/tablespace.c? But that would imply
196  * importing a lot of stuff that smgr.c oughtn't know, either.
197  */
199  reln->smgr_rnode.node.dbNode,
200  isRedo);
201 
202  path = relpath(reln->smgr_rnode, forkNum);
203 
204  fd = PathNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY);
205 
206  if (fd < 0)
207  {
208  int save_errno = errno;
209 
210  if (isRedo)
211  fd = PathNameOpenFile(path, O_RDWR | PG_BINARY);
212  if (fd < 0)
213  {
214  /* be sure to report the error reported by create, not open */
215  errno = save_errno;
216  ereport(ERROR,
218  errmsg("could not create file \"%s\": %m", path)));
219  }
220  }
221 
222  pfree(path);
223 
224  _fdvec_resize(reln, forkNum, 1);
225  mdfd = &reln->md_seg_fds[forkNum][0];
226  mdfd->mdfd_vfd = fd;
227  mdfd->mdfd_segno = 0;
228 }
File PathNameOpenFile(const char *fileName, int fileFlags)
Definition: fd.c:1321
BlockNumber mdfd_segno
Definition: md.c:85
static int fd(const char *x, int i)
Definition: preproc-init.c:105
#define PG_BINARY
Definition: c.h:1191
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ERROR
Definition: elog.h:43
RelFileNodeBackend smgr_rnode
Definition: smgr.h:42
int errcode_for_file_access(void)
Definition: elog.c:593
#define ereport(elevel, rest)
Definition: elog.h:141
static void _fdvec_resize(SMgrRelation reln, ForkNumber forknum, int nseg)
Definition: md.c:1033
Definition: md.c:82
RelFileNode node
Definition: relfilenode.h:74
#define Assert(condition)
Definition: c.h:732
void TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo)
Definition: tablespace.c:116
int md_num_open_segs[MAX_FORKNUM+1]
Definition: smgr.h:70
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define relpath(rnode, forknum)
Definition: relpath.h:87
struct _MdfdVec * md_seg_fds[MAX_FORKNUM+1]
Definition: smgr.h:71
File mdfd_vfd
Definition: md.c:84
int File
Definition: fd.h:45

◆ mdexists()

bool mdexists ( SMgrRelation  reln,
ForkNumber  forknum 
)

Definition at line 161 of file md.c.

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

162 {
163  /*
164  * Close it first, to ensure that we notice if the fork has been unlinked
165  * since we opened it.
166  */
167  mdclose(reln, forkNum);
168 
169  return (mdopenfork(reln, forkNum, EXTENSION_RETURN_NULL) != NULL);
170 }
static MdfdVec * mdopenfork(SMgrRelation reln, ForkNumber forknum, int behavior)
Definition: md.c:452
#define EXTENSION_RETURN_NULL
Definition: md.c:106
void mdclose(SMgrRelation reln, ForkNumber forknum)
Definition: md.c:506

◆ mdextend()

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

Definition at line 388 of file md.c.

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

Referenced by _mdfd_getseg().

390 {
391  off_t seekpos;
392  int nbytes;
393  MdfdVec *v;
394 
395  /* This assert is too expensive to have on normally ... */
396 #ifdef CHECK_WRITE_VS_EXTEND
397  Assert(blocknum >= mdnblocks(reln, forknum));
398 #endif
399 
400  /*
401  * If a relation manages to grow to 2^32-1 blocks, refuse to extend it any
402  * more --- we mustn't create a block whose number actually is
403  * InvalidBlockNumber.
404  */
405  if (blocknum == InvalidBlockNumber)
406  ereport(ERROR,
407  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
408  errmsg("cannot extend file \"%s\" beyond %u blocks",
409  relpath(reln->smgr_rnode, forknum),
411 
412  v = _mdfd_getseg(reln, forknum, blocknum, skipFsync, EXTENSION_CREATE);
413 
414  seekpos = (off_t) BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE));
415 
416  Assert(seekpos < (off_t) BLCKSZ * RELSEG_SIZE);
417 
418  if ((nbytes = FileWrite(v->mdfd_vfd, buffer, BLCKSZ, seekpos, WAIT_EVENT_DATA_FILE_EXTEND)) != BLCKSZ)
419  {
420  if (nbytes < 0)
421  ereport(ERROR,
423  errmsg("could not extend file \"%s\": %m",
424  FilePathName(v->mdfd_vfd)),
425  errhint("Check free disk space.")));
426  /* short write: complain appropriately */
427  ereport(ERROR,
428  (errcode(ERRCODE_DISK_FULL),
429  errmsg("could not extend file \"%s\": wrote only %d of %d bytes at block %u",
431  nbytes, BLCKSZ, blocknum),
432  errhint("Check free disk space.")));
433  }
434 
435  if (!skipFsync && !SmgrIsTemp(reln))
436  register_dirty_segment(reln, forknum, v);
437 
438  Assert(_mdnblocks(reln, forknum, v) <= ((BlockNumber) RELSEG_SIZE));
439 }
static MdfdVec * _mdfd_getseg(SMgrRelation reln, ForkNumber forkno, BlockNumber blkno, bool skipFsync, int behavior)
Definition: md.c:1134
int errhint(const char *fmt,...)
Definition: elog.c:974
BlockNumber mdnblocks(SMgrRelation reln, ForkNumber forknum)
Definition: md.c:739
int errcode(int sqlerrcode)
Definition: elog.c:570
uint32 BlockNumber
Definition: block.h:31
char * FilePathName(File file)
Definition: fd.c:2085
#define SmgrIsTemp(smgr)
Definition: smgr.h:79
#define ERROR
Definition: elog.h:43
RelFileNodeBackend smgr_rnode
Definition: smgr.h:42
int errcode_for_file_access(void)
Definition: elog.c:593
#define ereport(elevel, rest)
Definition: elog.h:141
int FileWrite(File file, char *buffer, int amount, off_t offset, uint32 wait_event_info)
Definition: fd.c:1914
Definition: md.c:82
#define EXTENSION_CREATE
Definition: md.c:108
#define Assert(condition)
Definition: c.h:732
static BlockNumber _mdnblocks(SMgrRelation reln, ForkNumber forknum, MdfdVec *seg)
Definition: md.c:1259
#define InvalidBlockNumber
Definition: block.h:33
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define relpath(rnode, forknum)
Definition: relpath.h:87
File mdfd_vfd
Definition: md.c:84
static void register_dirty_segment(SMgrRelation reln, ForkNumber forknum, MdfdVec *seg)
Definition: md.c:926

◆ mdfiletagmatches()

bool mdfiletagmatches ( const FileTag ftag,
const FileTag candidate 
)

Definition at line 1330 of file md.c.

References RelFileNode::dbNode, and FileTag::rnode.

1331 {
1332  /*
1333  * For now we only use filter requests as a way to drop all scheduled
1334  * callbacks relating to a given database, when dropping the database.
1335  * We'll return true for all candidates that have the same database OID as
1336  * the ftag from the SYNC_FILTER_REQUEST request, so they're forgotten.
1337  */
1338  return ftag->rnode.dbNode == candidate->rnode.dbNode;
1339 }
RelFileNode rnode
Definition: sync.h:49

◆ mdimmedsync()

void mdimmedsync ( SMgrRelation  reln,
ForkNumber  forknum 
)

Definition at line 891 of file md.c.

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

892 {
893  int segno;
894 
895  /*
896  * NOTE: mdnblocks makes sure we have opened all active segments, so that
897  * fsync loop will get them all!
898  */
899  mdnblocks(reln, forknum);
900 
901  segno = reln->md_num_open_segs[forknum];
902 
903  while (segno > 0)
904  {
905  MdfdVec *v = &reln->md_seg_fds[forknum][segno - 1];
906 
910  errmsg("could not fsync file \"%s\": %m",
911  FilePathName(v->mdfd_vfd))));
912  segno--;
913  }
914 }
BlockNumber mdnblocks(SMgrRelation reln, ForkNumber forknum)
Definition: md.c:739
char * FilePathName(File file)
Definition: fd.c:2085
#define ERROR
Definition: elog.h:43
int FileSync(File file, uint32 wait_event_info)
Definition: fd.c:2012
int errcode_for_file_access(void)
Definition: elog.c:593
#define ereport(elevel, rest)
Definition: elog.h:141
int data_sync_elevel(int elevel)
Definition: fd.c:3482
Definition: md.c:82
int md_num_open_segs[MAX_FORKNUM+1]
Definition: smgr.h:70
int errmsg(const char *fmt,...)
Definition: elog.c:784
struct _MdfdVec * md_seg_fds[MAX_FORKNUM+1]
Definition: smgr.h:71
File mdfd_vfd
Definition: md.c:84

◆ mdinit()

void mdinit ( void  )

Definition at line 148 of file md.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, and TopMemoryContext.

149 {
151  "MdSmgr",
153 }
#define AllocSetContextCreate
Definition: memutils.h:169
static MemoryContext MdCxt
Definition: md.c:88
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:191
MemoryContext TopMemoryContext
Definition: mcxt.c:44

◆ mdnblocks()

BlockNumber mdnblocks ( SMgrRelation  reln,
ForkNumber  forknum 
)

Definition at line 739 of file md.c.

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

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

740 {
741  MdfdVec *v = mdopenfork(reln, forknum, EXTENSION_FAIL);
742  BlockNumber nblocks;
743  BlockNumber segno = 0;
744 
745  /* mdopen has opened the first segment */
746  Assert(reln->md_num_open_segs[forknum] > 0);
747 
748  /*
749  * Start from the last open segments, to avoid redundant seeks. We have
750  * previously verified that these segments are exactly RELSEG_SIZE long,
751  * and it's useless to recheck that each time.
752  *
753  * NOTE: this assumption could only be wrong if another backend has
754  * truncated the relation. We rely on higher code levels to handle that
755  * scenario by closing and re-opening the md fd, which is handled via
756  * relcache flush. (Since the checkpointer doesn't participate in
757  * relcache flush, it could have segment entries for inactive segments;
758  * that's OK because the checkpointer never needs to compute relation
759  * size.)
760  */
761  segno = reln->md_num_open_segs[forknum] - 1;
762  v = &reln->md_seg_fds[forknum][segno];
763 
764  for (;;)
765  {
766  nblocks = _mdnblocks(reln, forknum, v);
767  if (nblocks > ((BlockNumber) RELSEG_SIZE))
768  elog(FATAL, "segment too big");
769  if (nblocks < ((BlockNumber) RELSEG_SIZE))
770  return (segno * ((BlockNumber) RELSEG_SIZE)) + nblocks;
771 
772  /*
773  * If segment is exactly RELSEG_SIZE, advance to next one.
774  */
775  segno++;
776 
777  /*
778  * We used to pass O_CREAT here, but that has the disadvantage that it
779  * might create a segment which has vanished through some operating
780  * system misadventure. In such a case, creating the segment here
781  * undermines _mdfd_getseg's attempts to notice and report an error
782  * upon access to a missing segment.
783  */
784  v = _mdfd_openseg(reln, forknum, segno, 0);
785  if (v == NULL)
786  return segno * ((BlockNumber) RELSEG_SIZE);
787  }
788 }
uint32 BlockNumber
Definition: block.h:31
#define EXTENSION_FAIL
Definition: md.c:104
static MdfdVec * mdopenfork(SMgrRelation reln, ForkNumber forknum, int behavior)
Definition: md.c:452
#define FATAL
Definition: elog.h:52
Definition: md.c:82
static MdfdVec * _mdfd_openseg(SMgrRelation reln, ForkNumber forkno, BlockNumber segno, int oflags)
Definition: md.c:1094
#define Assert(condition)
Definition: c.h:732
static BlockNumber _mdnblocks(SMgrRelation reln, ForkNumber forknum, MdfdVec *seg)
Definition: md.c:1259
int md_num_open_segs[MAX_FORKNUM+1]
Definition: smgr.h:70
#define elog(elevel,...)
Definition: elog.h:226
struct _MdfdVec * md_seg_fds[MAX_FORKNUM+1]
Definition: smgr.h:71

◆ mdopen()

void mdopen ( SMgrRelation  reln)

Definition at line 495 of file md.c.

References MAX_FORKNUM, and SMgrRelationData::md_num_open_segs.

496 {
497  /* mark it not open */
498  for (int forknum = 0; forknum <= MAX_FORKNUM; forknum++)
499  reln->md_num_open_segs[forknum] = 0;
500 }
#define MAX_FORKNUM
Definition: relpath.h:55
int md_num_open_segs[MAX_FORKNUM+1]
Definition: smgr.h:70

◆ mdprefetch()

void mdprefetch ( SMgrRelation  reln,
ForkNumber  forknum,
BlockNumber  blocknum 
)

Definition at line 537 of file md.c.

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

538 {
539 #ifdef USE_PREFETCH
540  off_t seekpos;
541  MdfdVec *v;
542 
543  v = _mdfd_getseg(reln, forknum, blocknum, false, EXTENSION_FAIL);
544 
545  seekpos = (off_t) BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE));
546 
547  Assert(seekpos < (off_t) BLCKSZ * RELSEG_SIZE);
548 
549  (void) FilePrefetch(v->mdfd_vfd, seekpos, BLCKSZ, WAIT_EVENT_DATA_FILE_PREFETCH);
550 #endif /* USE_PREFETCH */
551 }
static MdfdVec * _mdfd_getseg(SMgrRelation reln, ForkNumber forkno, BlockNumber blkno, bool skipFsync, int behavior)
Definition: md.c:1134
uint32 BlockNumber
Definition: block.h:31
#define EXTENSION_FAIL
Definition: md.c:104
Definition: md.c:82
int FilePrefetch(File file, off_t offset, int amount, uint32 wait_event_info)
Definition: fd.c:1807
#define Assert(condition)
Definition: c.h:732
File mdfd_vfd
Definition: md.c:84

◆ mdread()

void mdread ( SMgrRelation  reln,
ForkNumber  forknum,
BlockNumber  blocknum,
char *  buffer 
)

Definition at line 609 of file md.c.

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

611 {
612  off_t seekpos;
613  int nbytes;
614  MdfdVec *v;
615 
616  TRACE_POSTGRESQL_SMGR_MD_READ_START(forknum, blocknum,
617  reln->smgr_rnode.node.spcNode,
618  reln->smgr_rnode.node.dbNode,
619  reln->smgr_rnode.node.relNode,
620  reln->smgr_rnode.backend);
621 
622  v = _mdfd_getseg(reln, forknum, blocknum, false,
624 
625  seekpos = (off_t) BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE));
626 
627  Assert(seekpos < (off_t) BLCKSZ * RELSEG_SIZE);
628 
629  nbytes = FileRead(v->mdfd_vfd, buffer, BLCKSZ, seekpos, WAIT_EVENT_DATA_FILE_READ);
630 
631  TRACE_POSTGRESQL_SMGR_MD_READ_DONE(forknum, blocknum,
632  reln->smgr_rnode.node.spcNode,
633  reln->smgr_rnode.node.dbNode,
634  reln->smgr_rnode.node.relNode,
635  reln->smgr_rnode.backend,
636  nbytes,
637  BLCKSZ);
638 
639  if (nbytes != BLCKSZ)
640  {
641  if (nbytes < 0)
642  ereport(ERROR,
644  errmsg("could not read block %u in file \"%s\": %m",
645  blocknum, FilePathName(v->mdfd_vfd))));
646 
647  /*
648  * Short read: we are at or past EOF, or we read a partial block at
649  * EOF. Normally this is an error; upper levels should never try to
650  * read a nonexistent block. However, if zero_damaged_pages is ON or
651  * we are InRecovery, we should instead return zeroes without
652  * complaining. This allows, for example, the case of trying to
653  * update a block that was later truncated away.
654  */
656  MemSet(buffer, 0, BLCKSZ);
657  else
658  ereport(ERROR,
660  errmsg("could not read block %u in file \"%s\": read only %d of %d bytes",
661  blocknum, FilePathName(v->mdfd_vfd),
662  nbytes, BLCKSZ)));
663  }
664 }
static MdfdVec * _mdfd_getseg(SMgrRelation reln, ForkNumber forkno, BlockNumber blkno, bool skipFsync, int behavior)
Definition: md.c:1134
bool InRecovery
Definition: xlog.c:200
int errcode(int sqlerrcode)
Definition: elog.c:570
#define MemSet(start, val, len)
Definition: c.h:955
uint32 BlockNumber
Definition: block.h:31
char * FilePathName(File file)
Definition: fd.c:2085
#define EXTENSION_FAIL
Definition: md.c:104
#define ERROR
Definition: elog.h:43
RelFileNodeBackend smgr_rnode
Definition: smgr.h:42
int errcode_for_file_access(void)
Definition: elog.c:593
#define EXTENSION_CREATE_RECOVERY
Definition: md.c:110
#define ereport(elevel, rest)
Definition: elog.h:141
#define ERRCODE_DATA_CORRUPTED
Definition: pg_basebackup.c:44
Definition: md.c:82
RelFileNode node
Definition: relfilenode.h:74
#define Assert(condition)
Definition: c.h:732
BackendId backend
Definition: relfilenode.h:75
int errmsg(const char *fmt,...)
Definition: elog.c:784
int FileRead(File file, char *buffer, int amount, off_t offset, uint32 wait_event_info)
Definition: fd.c:1858
File mdfd_vfd
Definition: md.c:84
bool zero_damaged_pages
Definition: bufmgr.c:109

◆ mdsyncfiletag()

int mdsyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 1280 of file md.c.

References _mdfd_getseg(), _mdfd_segpath(), EXTENSION_DONT_CHECK_SIZE, EXTENSION_RETURN_NULL, FileSync(), FileTag::forknum, InvalidBackendId, MAXPGPATH, _MdfdVec::mdfd_vfd, pfree(), FileTag::rnode, FileTag::segno, smgropen(), strlcpy(), and WAIT_EVENT_DATA_FILE_SYNC.

1281 {
1283  MdfdVec *v;
1284  char *p;
1285 
1286  /* Provide the path for informational messages. */
1287  p = _mdfd_segpath(reln, ftag->forknum, ftag->segno);
1288  strlcpy(path, p, MAXPGPATH);
1289  pfree(p);
1290 
1291  /* Try to open the requested segment. */
1292  v = _mdfd_getseg(reln,
1293  ftag->forknum,
1294  ftag->segno * (BlockNumber) RELSEG_SIZE,
1295  false,
1297  if (v == NULL)
1298  return -1;
1299 
1300  /* Try to fsync the file. */
1302 }
uint32 segno
Definition: sync.h:50
static MdfdVec * _mdfd_getseg(SMgrRelation reln, ForkNumber forkno, BlockNumber blkno, bool skipFsync, int behavior)
Definition: md.c:1134
#define EXTENSION_DONT_CHECK_SIZE
Definition: md.c:118
int16 forknum
Definition: sync.h:48
RelFileNode rnode
Definition: sync.h:49
uint32 BlockNumber
Definition: block.h:31
void pfree(void *pointer)
Definition: mcxt.c:1031
#define EXTENSION_RETURN_NULL
Definition: md.c:106
#define MAXPGPATH
int FileSync(File file, uint32 wait_event_info)
Definition: fd.c:2012
SMgrRelation smgropen(RelFileNode rnode, BackendId backend)
Definition: smgr.c:145
#define InvalidBackendId
Definition: backendid.h:23
Definition: md.c:82
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
File mdfd_vfd
Definition: md.c:84
static char * _mdfd_segpath(SMgrRelation reln, ForkNumber forknum, BlockNumber segno)
Definition: md.c:1071

◆ mdtruncate()

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

Definition at line 794 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, SmgrIsTemp, and WAIT_EVENT_DATA_FILE_TRUNCATE.

795 {
796  BlockNumber curnblk;
797  BlockNumber priorblocks;
798  int curopensegs;
799 
800  /*
801  * NOTE: mdnblocks makes sure we have opened all active segments, so that
802  * truncation loop will get them all!
803  */
804  curnblk = mdnblocks(reln, forknum);
805  if (nblocks > curnblk)
806  {
807  /* Bogus request ... but no complaint if InRecovery */
808  if (InRecovery)
809  return;
810  ereport(ERROR,
811  (errmsg("could not truncate file \"%s\" to %u blocks: it's only %u blocks now",
812  relpath(reln->smgr_rnode, forknum),
813  nblocks, curnblk)));
814  }
815  if (nblocks == curnblk)
816  return; /* no work */
817 
818  /*
819  * Truncate segments, starting at the last one. Starting at the end makes
820  * managing the memory for the fd array easier, should there be errors.
821  */
822  curopensegs = reln->md_num_open_segs[forknum];
823  while (curopensegs > 0)
824  {
825  MdfdVec *v;
826 
827  priorblocks = (curopensegs - 1) * RELSEG_SIZE;
828 
829  v = &reln->md_seg_fds[forknum][curopensegs - 1];
830 
831  if (priorblocks > nblocks)
832  {
833  /*
834  * This segment is no longer active. We truncate the file, but do
835  * not delete it, for reasons explained in the header comments.
836  */
838  ereport(ERROR,
840  errmsg("could not truncate file \"%s\": %m",
841  FilePathName(v->mdfd_vfd))));
842 
843  if (!SmgrIsTemp(reln))
844  register_dirty_segment(reln, forknum, v);
845 
846  /* we never drop the 1st segment */
847  Assert(v != &reln->md_seg_fds[forknum][0]);
848 
849  FileClose(v->mdfd_vfd);
850  _fdvec_resize(reln, forknum, curopensegs - 1);
851  }
852  else if (priorblocks + ((BlockNumber) RELSEG_SIZE) > nblocks)
853  {
854  /*
855  * This is the last segment we want to keep. Truncate the file to
856  * the right length. NOTE: if nblocks is exactly a multiple K of
857  * RELSEG_SIZE, we will truncate the K+1st segment to 0 length but
858  * keep it. This adheres to the invariant given in the header
859  * comments.
860  */
861  BlockNumber lastsegblocks = nblocks - priorblocks;
862 
863  if (FileTruncate(v->mdfd_vfd, (off_t) lastsegblocks * BLCKSZ, WAIT_EVENT_DATA_FILE_TRUNCATE) < 0)
864  ereport(ERROR,
866  errmsg("could not truncate file \"%s\" to %u blocks: %m",
868  nblocks)));
869  if (!SmgrIsTemp(reln))
870  register_dirty_segment(reln, forknum, v);
871  }
872  else
873  {
874  /*
875  * We still need this segment, so nothing to do for this and any
876  * earlier segment.
877  */
878  break;
879  }
880  curopensegs--;
881  }
882 }
BlockNumber mdnblocks(SMgrRelation reln, ForkNumber forknum)
Definition: md.c:739
bool InRecovery
Definition: xlog.c:200
uint32 BlockNumber
Definition: block.h:31
char * FilePathName(File file)
Definition: fd.c:2085
#define SmgrIsTemp(smgr)
Definition: smgr.h:79
#define ERROR
Definition: elog.h:43
RelFileNodeBackend smgr_rnode
Definition: smgr.h:42
int errcode_for_file_access(void)
Definition: elog.c:593
#define ereport(elevel, rest)
Definition: elog.h:141
static void _fdvec_resize(SMgrRelation reln, ForkNumber forknum, int nseg)
Definition: md.c:1033
Definition: md.c:82
void FileClose(File file)
Definition: fd.c:1711
#define Assert(condition)
Definition: c.h:732
int md_num_open_segs[MAX_FORKNUM+1]
Definition: smgr.h:70
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define relpath(rnode, forknum)
Definition: relpath.h:87
struct _MdfdVec * md_seg_fds[MAX_FORKNUM+1]
Definition: smgr.h:71
int FileTruncate(File file, off_t offset, uint32 wait_event_info)
Definition: fd.c:2050
File mdfd_vfd
Definition: md.c:84
static void register_dirty_segment(SMgrRelation reln, ForkNumber forknum, MdfdVec *seg)
Definition: md.c:926

◆ mdunlink()

void mdunlink ( RelFileNodeBackend  rnode,
ForkNumber  forknum,
bool  isRedo 
)

Definition at line 278 of file md.c.

References InvalidForkNumber, MAX_FORKNUM, and mdunlinkfork().

279 {
280  /* Now do the per-fork work */
281  if (forkNum == InvalidForkNumber)
282  {
283  for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
284  mdunlinkfork(rnode, forkNum, isRedo);
285  }
286  else
287  mdunlinkfork(rnode, forkNum, isRedo);
288 }
static void mdunlinkfork(RelFileNodeBackend rnode, ForkNumber forkNum, bool isRedo)
Definition: md.c:291
#define MAX_FORKNUM
Definition: relpath.h:55

◆ mdunlinkfiletag()

int mdunlinkfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 1311 of file md.c.

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

1312 {
1313  char *p;
1314 
1315  /* Compute the path. */
1316  p = relpathperm(ftag->rnode, MAIN_FORKNUM);
1317  strlcpy(path, p, MAXPGPATH);
1318  pfree(p);
1319 
1320  /* Try to unlink the file. */
1321  return unlink(path);
1322 }
#define relpathperm(rnode, forknum)
Definition: relpath.h:83
RelFileNode rnode
Definition: sync.h:49
void pfree(void *pointer)
Definition: mcxt.c:1031
#define MAXPGPATH
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45

◆ mdwrite()

void mdwrite ( SMgrRelation  reln,
ForkNumber  forknum,
BlockNumber  blocknum,
char *  buffer,
bool  skipFsync 
)

Definition at line 674 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(), FileWrite(), _MdfdVec::mdfd_vfd, mdnblocks(), RelFileNodeBackend::node, register_dirty_segment(), RelFileNode::relNode, SMgrRelationData::smgr_rnode, SmgrIsTemp, RelFileNode::spcNode, and WAIT_EVENT_DATA_FILE_WRITE.

676 {
677  off_t seekpos;
678  int nbytes;
679  MdfdVec *v;
680 
681  /* This assert is too expensive to have on normally ... */
682 #ifdef CHECK_WRITE_VS_EXTEND
683  Assert(blocknum < mdnblocks(reln, forknum));
684 #endif
685 
686  TRACE_POSTGRESQL_SMGR_MD_WRITE_START(forknum, blocknum,
687  reln->smgr_rnode.node.spcNode,
688  reln->smgr_rnode.node.dbNode,
689  reln->smgr_rnode.node.relNode,
690  reln->smgr_rnode.backend);
691 
692  v = _mdfd_getseg(reln, forknum, blocknum, skipFsync,
694 
695  seekpos = (off_t) BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE));
696 
697  Assert(seekpos < (off_t) BLCKSZ * RELSEG_SIZE);
698 
699  nbytes = FileWrite(v->mdfd_vfd, buffer, BLCKSZ, seekpos, WAIT_EVENT_DATA_FILE_WRITE);
700 
701  TRACE_POSTGRESQL_SMGR_MD_WRITE_DONE(forknum, blocknum,
702  reln->smgr_rnode.node.spcNode,
703  reln->smgr_rnode.node.dbNode,
704  reln->smgr_rnode.node.relNode,
705  reln->smgr_rnode.backend,
706  nbytes,
707  BLCKSZ);
708 
709  if (nbytes != BLCKSZ)
710  {
711  if (nbytes < 0)
712  ereport(ERROR,
714  errmsg("could not write block %u in file \"%s\": %m",
715  blocknum, FilePathName(v->mdfd_vfd))));
716  /* short write: complain appropriately */
717  ereport(ERROR,
718  (errcode(ERRCODE_DISK_FULL),
719  errmsg("could not write block %u in file \"%s\": wrote only %d of %d bytes",
720  blocknum,
722  nbytes, BLCKSZ),
723  errhint("Check free disk space.")));
724  }
725 
726  if (!skipFsync && !SmgrIsTemp(reln))
727  register_dirty_segment(reln, forknum, v);
728 }
static MdfdVec * _mdfd_getseg(SMgrRelation reln, ForkNumber forkno, BlockNumber blkno, bool skipFsync, int behavior)
Definition: md.c:1134
int errhint(const char *fmt,...)
Definition: elog.c:974
BlockNumber mdnblocks(SMgrRelation reln, ForkNumber forknum)
Definition: md.c:739
int errcode(int sqlerrcode)
Definition: elog.c:570
uint32 BlockNumber
Definition: block.h:31
char * FilePathName(File file)
Definition: fd.c:2085
#define EXTENSION_FAIL
Definition: md.c:104
#define SmgrIsTemp(smgr)
Definition: smgr.h:79
#define ERROR
Definition: elog.h:43
RelFileNodeBackend smgr_rnode
Definition: smgr.h:42
int errcode_for_file_access(void)
Definition: elog.c:593
#define EXTENSION_CREATE_RECOVERY
Definition: md.c:110
#define ereport(elevel, rest)
Definition: elog.h:141
int FileWrite(File file, char *buffer, int amount, off_t offset, uint32 wait_event_info)
Definition: fd.c:1914
Definition: md.c:82
RelFileNode node
Definition: relfilenode.h:74
#define Assert(condition)
Definition: c.h:732
BackendId backend
Definition: relfilenode.h:75
int errmsg(const char *fmt,...)
Definition: elog.c:784
File mdfd_vfd
Definition: md.c:84
static void register_dirty_segment(SMgrRelation reln, ForkNumber forknum, MdfdVec *seg)
Definition: md.c:926

◆ mdwriteback()

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

Definition at line 560 of file md.c.

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

562 {
563  /*
564  * Issue flush requests in as few requests as possible; have to split at
565  * segment boundaries though, since those are actually separate files.
566  */
567  while (nblocks > 0)
568  {
569  BlockNumber nflush = nblocks;
570  off_t seekpos;
571  MdfdVec *v;
572  int segnum_start,
573  segnum_end;
574 
575  v = _mdfd_getseg(reln, forknum, blocknum, true /* not used */ ,
577 
578  /*
579  * We might be flushing buffers of already removed relations, that's
580  * ok, just ignore that case.
581  */
582  if (!v)
583  return;
584 
585  /* compute offset inside the current segment */
586  segnum_start = blocknum / RELSEG_SIZE;
587 
588  /* compute number of desired writes within the current segment */
589  segnum_end = (blocknum + nblocks - 1) / RELSEG_SIZE;
590  if (segnum_start != segnum_end)
591  nflush = RELSEG_SIZE - (blocknum % ((BlockNumber) RELSEG_SIZE));
592 
593  Assert(nflush >= 1);
594  Assert(nflush <= nblocks);
595 
596  seekpos = (off_t) BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE));
597 
598  FileWriteback(v->mdfd_vfd, seekpos, (off_t) BLCKSZ * nflush, WAIT_EVENT_DATA_FILE_FLUSH);
599 
600  nblocks -= nflush;
601  blocknum += nflush;
602  }
603 }
static MdfdVec * _mdfd_getseg(SMgrRelation reln, ForkNumber forkno, BlockNumber blkno, bool skipFsync, int behavior)
Definition: md.c:1134
uint32 BlockNumber
Definition: block.h:31
#define EXTENSION_RETURN_NULL
Definition: md.c:106
Definition: md.c:82
#define Assert(condition)
Definition: c.h:732
void FileWriteback(File file, off_t offset, off_t nbytes, uint32 wait_event_info)
Definition: fd.c:1835
File mdfd_vfd
Definition: md.c:84