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)
 
bool 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 1020 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().

1021 {
1022  SMgrRelation *srels;
1023  int i;
1024 
1025  srels = palloc(sizeof(SMgrRelation) * ndelrels);
1026  for (i = 0; i < ndelrels; i++)
1027  {
1028  SMgrRelation srel = smgropen(delrels[i], InvalidBackendId);
1029 
1030  if (isRedo)
1031  {
1032  ForkNumber fork;
1033 
1034  for (fork = 0; fork <= MAX_FORKNUM; fork++)
1035  XLogDropRelation(delrels[i], fork);
1036  }
1037  srels[i] = srel;
1038  }
1039 
1040  smgrdounlinkall(srels, ndelrels, isRedo);
1041 
1042  for (i = 0; i < ndelrels; i++)
1043  smgrclose(srels[i]);
1044  pfree(srels);
1045 }
void smgrclose(SMgrRelation reln)
Definition: smgr.c:256
void smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo)
Definition: smgr.c:384
void pfree(void *pointer)
Definition: mcxt.c:1056
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:615
void * palloc(Size size)
Definition: mcxt.c:949
int i

◆ ForgetDatabaseSyncRequests()

void ForgetDatabaseSyncRequests ( Oid  dbid)

Definition at line 1002 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().

1003 {
1004  FileTag tag;
1005  RelFileNode rnode;
1006 
1007  rnode.dbNode = dbid;
1008  rnode.spcNode = 0;
1009  rnode.relNode = 0;
1010 
1012 
1013  RegisterSyncRequest(&tag, SYNC_FILTER_REQUEST, true /* retryOnError */ );
1014 }
#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:532
#define InvalidBlockNumber
Definition: block.h:33
Definition: sync.h:45

◆ mdclose()

void mdclose ( SMgrRelation  reln,
ForkNumber  forknum 
)

Definition at line 505 of file md.c.

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

Referenced by mdexists().

506 {
507  int nopensegs = reln->md_num_open_segs[forknum];
508 
509  /* No work if already closed */
510  if (nopensegs == 0)
511  return;
512 
513  /* close segments starting from the end */
514  while (nopensegs > 0)
515  {
516  MdfdVec *v = &reln->md_seg_fds[forknum][nopensegs - 1];
517 
518  FileClose(v->mdfd_vfd);
519  _fdvec_resize(reln, forknum, nopensegs - 1);
520  nopensegs--;
521  }
522 }
static void _fdvec_resize(SMgrRelation reln, ForkNumber forknum, int nseg)
Definition: md.c:1052
Definition: md.c:82
void FileClose(File file)
Definition: fd.c:1824
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:1434
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:1234
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ERROR
Definition: elog.h:43
RelFileNodeBackend smgr_rnode
Definition: smgr.h:42
int errcode_for_file_access(void)
Definition: elog.c:633
static void _fdvec_resize(SMgrRelation reln, ForkNumber forknum, int nseg)
Definition: md.c:1052
Definition: md.c:82
#define ereport(elevel,...)
Definition: elog.h:144
RelFileNode node
Definition: relfilenode.h:74
#define Assert(condition)
Definition: c.h:738
void TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo)
Definition: tablespace.c:115
int md_num_open_segs[MAX_FORKNUM+1]
Definition: smgr.h:70
int errmsg(const char *fmt,...)
Definition: elog.c:824
#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:49

◆ 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:451
#define EXTENSION_RETURN_NULL
Definition: md.c:106
void mdclose(SMgrRelation reln, ForkNumber forknum)
Definition: md.c:505

◆ mdextend()

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

Definition at line 387 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().

389 {
390  off_t seekpos;
391  int nbytes;
392  MdfdVec *v;
393 
394  /* This assert is too expensive to have on normally ... */
395 #ifdef CHECK_WRITE_VS_EXTEND
396  Assert(blocknum >= mdnblocks(reln, forknum));
397 #endif
398 
399  /*
400  * If a relation manages to grow to 2^32-1 blocks, refuse to extend it any
401  * more --- we mustn't create a block whose number actually is
402  * InvalidBlockNumber.
403  */
404  if (blocknum == InvalidBlockNumber)
405  ereport(ERROR,
406  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
407  errmsg("cannot extend file \"%s\" beyond %u blocks",
408  relpath(reln->smgr_rnode, forknum),
410 
411  v = _mdfd_getseg(reln, forknum, blocknum, skipFsync, EXTENSION_CREATE);
412 
413  seekpos = (off_t) BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE));
414 
415  Assert(seekpos < (off_t) BLCKSZ * RELSEG_SIZE);
416 
417  if ((nbytes = FileWrite(v->mdfd_vfd, buffer, BLCKSZ, seekpos, WAIT_EVENT_DATA_FILE_EXTEND)) != BLCKSZ)
418  {
419  if (nbytes < 0)
420  ereport(ERROR,
422  errmsg("could not extend file \"%s\": %m",
423  FilePathName(v->mdfd_vfd)),
424  errhint("Check free disk space.")));
425  /* short write: complain appropriately */
426  ereport(ERROR,
427  (errcode(ERRCODE_DISK_FULL),
428  errmsg("could not extend file \"%s\": wrote only %d of %d bytes at block %u",
430  nbytes, BLCKSZ, blocknum),
431  errhint("Check free disk space.")));
432  }
433 
434  if (!skipFsync && !SmgrIsTemp(reln))
435  register_dirty_segment(reln, forknum, v);
436 
437  Assert(_mdnblocks(reln, forknum, v) <= ((BlockNumber) RELSEG_SIZE));
438 }
static MdfdVec * _mdfd_getseg(SMgrRelation reln, ForkNumber forkno, BlockNumber blkno, bool skipFsync, int behavior)
Definition: md.c:1158
int errhint(const char *fmt,...)
Definition: elog.c:1071
BlockNumber mdnblocks(SMgrRelation reln, ForkNumber forknum)
Definition: md.c:735
int errcode(int sqlerrcode)
Definition: elog.c:610
uint32 BlockNumber
Definition: block.h:31
char * FilePathName(File file)
Definition: fd.c:2198
#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:633
int FileWrite(File file, char *buffer, int amount, off_t offset, uint32 wait_event_info)
Definition: fd.c:2027
Definition: md.c:82
#define ereport(elevel,...)
Definition: elog.h:144
#define EXTENSION_CREATE
Definition: md.c:108
#define Assert(condition)
Definition: c.h:738
static BlockNumber _mdnblocks(SMgrRelation reln, ForkNumber forknum, MdfdVec *seg)
Definition: md.c:1283
#define InvalidBlockNumber
Definition: block.h:33
int errmsg(const char *fmt,...)
Definition: elog.c:824
#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:945

◆ mdfiletagmatches()

bool mdfiletagmatches ( const FileTag ftag,
const FileTag candidate 
)

Definition at line 1370 of file md.c.

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

1371 {
1372  /*
1373  * For now we only use filter requests as a way to drop all scheduled
1374  * callbacks relating to a given database, when dropping the database.
1375  * We'll return true for all candidates that have the same database OID as
1376  * the ftag from the SYNC_FILTER_REQUEST request, so they're forgotten.
1377  */
1378  return ftag->rnode.dbNode == candidate->rnode.dbNode;
1379 }
RelFileNode rnode
Definition: sync.h:49

◆ mdimmedsync()

void mdimmedsync ( SMgrRelation  reln,
ForkNumber  forknum 
)

Definition at line 892 of file md.c.

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

893 {
894  int segno;
895  int min_inactive_seg;
896 
897  /*
898  * NOTE: mdnblocks makes sure we have opened all active segments, so that
899  * fsync loop will get them all!
900  */
901  mdnblocks(reln, forknum);
902 
903  min_inactive_seg = segno = reln->md_num_open_segs[forknum];
904 
905  /*
906  * Temporarily open inactive segments, then close them after sync. There
907  * may be some inactive segments left opened after fsync() error, but that
908  * is harmless. We don't bother to clean them up and take a risk of
909  * further trouble. The next mdclose() will soon close them.
910  */
911  while (_mdfd_openseg(reln, forknum, segno, 0) != NULL)
912  segno++;
913 
914  while (segno > 0)
915  {
916  MdfdVec *v = &reln->md_seg_fds[forknum][segno - 1];
917 
921  errmsg("could not fsync file \"%s\": %m",
922  FilePathName(v->mdfd_vfd))));
923 
924  /* Close inactive segments immediately */
925  if (segno > min_inactive_seg)
926  {
927  FileClose(v->mdfd_vfd);
928  _fdvec_resize(reln, forknum, segno - 1);
929  }
930 
931  segno--;
932  }
933 }
BlockNumber mdnblocks(SMgrRelation reln, ForkNumber forknum)
Definition: md.c:735
char * FilePathName(File file)
Definition: fd.c:2198
#define ERROR
Definition: elog.h:43
int FileSync(File file, uint32 wait_event_info)
Definition: fd.c:2125
int errcode_for_file_access(void)
Definition: elog.c:633
int data_sync_elevel(int elevel)
Definition: fd.c:3597
static void _fdvec_resize(SMgrRelation reln, ForkNumber forknum, int nseg)
Definition: md.c:1052
Definition: md.c:82
static MdfdVec * _mdfd_openseg(SMgrRelation reln, ForkNumber forkno, BlockNumber segno, int oflags)
Definition: md.c:1113
#define ereport(elevel,...)
Definition: elog.h:144
void FileClose(File file)
Definition: fd.c:1824
int md_num_open_segs[MAX_FORKNUM+1]
Definition: smgr.h:70
int errmsg(const char *fmt,...)
Definition: elog.c:824
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:170
static MemoryContext MdCxt
Definition: md.c:88
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
MemoryContext TopMemoryContext
Definition: mcxt.c:44

◆ mdnblocks()

BlockNumber mdnblocks ( SMgrRelation  reln,
ForkNumber  forknum 
)

Definition at line 735 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().

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

◆ mdopen()

void mdopen ( SMgrRelation  reln)

Definition at line 494 of file md.c.

References MAX_FORKNUM, and SMgrRelationData::md_num_open_segs.

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

◆ mdprefetch()

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

Definition at line 528 of file md.c.

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

529 {
530 #ifdef USE_PREFETCH
531  off_t seekpos;
532  MdfdVec *v;
533 
534  v = _mdfd_getseg(reln, forknum, blocknum, false,
536  if (v == NULL)
537  return false;
538 
539  seekpos = (off_t) BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE));
540 
541  Assert(seekpos < (off_t) BLCKSZ * RELSEG_SIZE);
542 
543  (void) FilePrefetch(v->mdfd_vfd, seekpos, BLCKSZ, WAIT_EVENT_DATA_FILE_PREFETCH);
544 #endif /* USE_PREFETCH */
545 
546  return true;
547 }
static MdfdVec * _mdfd_getseg(SMgrRelation reln, ForkNumber forkno, BlockNumber blkno, bool skipFsync, int behavior)
Definition: md.c:1158
bool InRecovery
Definition: xlog.c:204
uint32 BlockNumber
Definition: block.h:31
#define EXTENSION_FAIL
Definition: md.c:104
#define EXTENSION_RETURN_NULL
Definition: md.c:106
Definition: md.c:82
int FilePrefetch(File file, off_t offset, int amount, uint32 wait_event_info)
Definition: fd.c:1920
#define Assert(condition)
Definition: c.h:738
File mdfd_vfd
Definition: md.c:84

◆ mdread()

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

Definition at line 605 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.

607 {
608  off_t seekpos;
609  int nbytes;
610  MdfdVec *v;
611 
612  TRACE_POSTGRESQL_SMGR_MD_READ_START(forknum, blocknum,
613  reln->smgr_rnode.node.spcNode,
614  reln->smgr_rnode.node.dbNode,
615  reln->smgr_rnode.node.relNode,
616  reln->smgr_rnode.backend);
617 
618  v = _mdfd_getseg(reln, forknum, blocknum, false,
620 
621  seekpos = (off_t) BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE));
622 
623  Assert(seekpos < (off_t) BLCKSZ * RELSEG_SIZE);
624 
625  nbytes = FileRead(v->mdfd_vfd, buffer, BLCKSZ, seekpos, WAIT_EVENT_DATA_FILE_READ);
626 
627  TRACE_POSTGRESQL_SMGR_MD_READ_DONE(forknum, blocknum,
628  reln->smgr_rnode.node.spcNode,
629  reln->smgr_rnode.node.dbNode,
630  reln->smgr_rnode.node.relNode,
631  reln->smgr_rnode.backend,
632  nbytes,
633  BLCKSZ);
634 
635  if (nbytes != BLCKSZ)
636  {
637  if (nbytes < 0)
638  ereport(ERROR,
640  errmsg("could not read block %u in file \"%s\": %m",
641  blocknum, FilePathName(v->mdfd_vfd))));
642 
643  /*
644  * Short read: we are at or past EOF, or we read a partial block at
645  * EOF. Normally this is an error; upper levels should never try to
646  * read a nonexistent block. However, if zero_damaged_pages is ON or
647  * we are InRecovery, we should instead return zeroes without
648  * complaining. This allows, for example, the case of trying to
649  * update a block that was later truncated away.
650  */
652  MemSet(buffer, 0, BLCKSZ);
653  else
654  ereport(ERROR,
656  errmsg("could not read block %u in file \"%s\": read only %d of %d bytes",
657  blocknum, FilePathName(v->mdfd_vfd),
658  nbytes, BLCKSZ)));
659  }
660 }
static MdfdVec * _mdfd_getseg(SMgrRelation reln, ForkNumber forkno, BlockNumber blkno, bool skipFsync, int behavior)
Definition: md.c:1158
bool InRecovery
Definition: xlog.c:204
int errcode(int sqlerrcode)
Definition: elog.c:610
#define MemSet(start, val, len)
Definition: c.h:971
uint32 BlockNumber
Definition: block.h:31
char * FilePathName(File file)
Definition: fd.c:2198
#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:633
#define EXTENSION_CREATE_RECOVERY
Definition: md.c:110
#define ERRCODE_DATA_CORRUPTED
Definition: pg_basebackup.c:45
Definition: md.c:82
#define ereport(elevel,...)
Definition: elog.h:144
RelFileNode node
Definition: relfilenode.h:74
#define Assert(condition)
Definition: c.h:738
BackendId backend
Definition: relfilenode.h:75
int errmsg(const char *fmt,...)
Definition: elog.c:824
int FileRead(File file, char *buffer, int amount, off_t offset, uint32 wait_event_info)
Definition: fd.c:1971
File mdfd_vfd
Definition: md.c:84
bool zero_damaged_pages
Definition: bufmgr.c:123

◆ mdsyncfiletag()

int mdsyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 1304 of file md.c.

References _mdfd_segpath(), FileClose(), FilePathName(), FileSync(), FileTag::forknum, InvalidBackendId, MAXPGPATH, SMgrRelationData::md_num_open_segs, SMgrRelationData::md_seg_fds, _MdfdVec::mdfd_vfd, PathNameOpenFile(), pfree(), PG_BINARY, FileTag::rnode, FileTag::segno, smgropen(), strlcpy(), and WAIT_EVENT_DATA_FILE_SYNC.

1305 {
1307  File file;
1308  bool need_to_close;
1309  int result,
1310  save_errno;
1311 
1312  /* See if we already have the file open, or need to open it. */
1313  if (ftag->segno < reln->md_num_open_segs[ftag->forknum])
1314  {
1315  file = reln->md_seg_fds[ftag->forknum][ftag->segno].mdfd_vfd;
1316  strlcpy(path, FilePathName(file), MAXPGPATH);
1317  need_to_close = false;
1318  }
1319  else
1320  {
1321  char *p;
1322 
1323  p = _mdfd_segpath(reln, ftag->forknum, ftag->segno);
1324  strlcpy(path, p, MAXPGPATH);
1325  pfree(p);
1326 
1327  file = PathNameOpenFile(path, O_RDWR | PG_BINARY);
1328  if (file < 0)
1329  return -1;
1330  need_to_close = true;
1331  }
1332 
1333  /* Sync the file. */
1334  result = FileSync(file, WAIT_EVENT_DATA_FILE_SYNC);
1335  save_errno = errno;
1336 
1337  if (need_to_close)
1338  FileClose(file);
1339 
1340  errno = save_errno;
1341  return result;
1342 }
uint32 segno
Definition: sync.h:50
File PathNameOpenFile(const char *fileName, int fileFlags)
Definition: fd.c:1434
int16 forknum
Definition: sync.h:48
RelFileNode rnode
Definition: sync.h:49
char * FilePathName(File file)
Definition: fd.c:2198
#define PG_BINARY
Definition: c.h:1234
void pfree(void *pointer)
Definition: mcxt.c:1056
#define MAXPGPATH
int FileSync(File file, uint32 wait_event_info)
Definition: fd.c:2125
SMgrRelation smgropen(RelFileNode rnode, BackendId backend)
Definition: smgr.c:145
#define InvalidBackendId
Definition: backendid.h:23
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
void FileClose(File file)
Definition: fd.c:1824
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
int File
Definition: fd.h:49
static char * _mdfd_segpath(SMgrRelation reln, ForkNumber forknum, BlockNumber segno)
Definition: md.c:1090

◆ mdtruncate()

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

Definition at line 790 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.

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

◆ mdunlink()

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

Definition at line 277 of file md.c.

References InvalidForkNumber, MAX_FORKNUM, and mdunlinkfork().

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

◆ mdunlinkfiletag()

int mdunlinkfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 1351 of file md.c.

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

1352 {
1353  char *p;
1354 
1355  /* Compute the path. */
1356  p = relpathperm(ftag->rnode, MAIN_FORKNUM);
1357  strlcpy(path, p, MAXPGPATH);
1358  pfree(p);
1359 
1360  /* Try to unlink the file. */
1361  return unlink(path);
1362 }
#define relpathperm(rnode, forknum)
Definition: relpath.h:83
RelFileNode rnode
Definition: sync.h:49
void pfree(void *pointer)
Definition: mcxt.c:1056
#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 670 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.

672 {
673  off_t seekpos;
674  int nbytes;
675  MdfdVec *v;
676 
677  /* This assert is too expensive to have on normally ... */
678 #ifdef CHECK_WRITE_VS_EXTEND
679  Assert(blocknum < mdnblocks(reln, forknum));
680 #endif
681 
682  TRACE_POSTGRESQL_SMGR_MD_WRITE_START(forknum, blocknum,
683  reln->smgr_rnode.node.spcNode,
684  reln->smgr_rnode.node.dbNode,
685  reln->smgr_rnode.node.relNode,
686  reln->smgr_rnode.backend);
687 
688  v = _mdfd_getseg(reln, forknum, blocknum, skipFsync,
690 
691  seekpos = (off_t) BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE));
692 
693  Assert(seekpos < (off_t) BLCKSZ * RELSEG_SIZE);
694 
695  nbytes = FileWrite(v->mdfd_vfd, buffer, BLCKSZ, seekpos, WAIT_EVENT_DATA_FILE_WRITE);
696 
697  TRACE_POSTGRESQL_SMGR_MD_WRITE_DONE(forknum, blocknum,
698  reln->smgr_rnode.node.spcNode,
699  reln->smgr_rnode.node.dbNode,
700  reln->smgr_rnode.node.relNode,
701  reln->smgr_rnode.backend,
702  nbytes,
703  BLCKSZ);
704 
705  if (nbytes != BLCKSZ)
706  {
707  if (nbytes < 0)
708  ereport(ERROR,
710  errmsg("could not write block %u in file \"%s\": %m",
711  blocknum, FilePathName(v->mdfd_vfd))));
712  /* short write: complain appropriately */
713  ereport(ERROR,
714  (errcode(ERRCODE_DISK_FULL),
715  errmsg("could not write block %u in file \"%s\": wrote only %d of %d bytes",
716  blocknum,
718  nbytes, BLCKSZ),
719  errhint("Check free disk space.")));
720  }
721 
722  if (!skipFsync && !SmgrIsTemp(reln))
723  register_dirty_segment(reln, forknum, v);
724 }
static MdfdVec * _mdfd_getseg(SMgrRelation reln, ForkNumber forkno, BlockNumber blkno, bool skipFsync, int behavior)
Definition: md.c:1158
int errhint(const char *fmt,...)
Definition: elog.c:1071
BlockNumber mdnblocks(SMgrRelation reln, ForkNumber forknum)
Definition: md.c:735
int errcode(int sqlerrcode)
Definition: elog.c:610
uint32 BlockNumber
Definition: block.h:31
char * FilePathName(File file)
Definition: fd.c:2198
#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:633
#define EXTENSION_CREATE_RECOVERY
Definition: md.c:110
int FileWrite(File file, char *buffer, int amount, off_t offset, uint32 wait_event_info)
Definition: fd.c:2027
Definition: md.c:82
#define ereport(elevel,...)
Definition: elog.h:144
RelFileNode node
Definition: relfilenode.h:74
#define Assert(condition)
Definition: c.h:738
BackendId backend
Definition: relfilenode.h:75
int errmsg(const char *fmt,...)
Definition: elog.c:824
File mdfd_vfd
Definition: md.c:84
static void register_dirty_segment(SMgrRelation reln, ForkNumber forknum, MdfdVec *seg)
Definition: md.c:945

◆ mdwriteback()

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

Definition at line 556 of file md.c.

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

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