PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
md.h File Reference
#include "storage/block.h"
#include "storage/relfilelocator.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 (RelFileLocatorBackend rlocator, ForkNumber forknum, bool isRedo)
 
void mdextend (SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, const void *buffer, bool skipFsync)
 
void mdzeroextend (SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, int nblocks, bool skipFsync)
 
bool mdprefetch (SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, int nblocks)
 
uint32 mdmaxcombine (SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum)
 
void mdreadv (SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, void **buffers, BlockNumber nblocks)
 
void mdwritev (SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, const void **buffers, BlockNumber nblocks, bool skipFsync)
 
void mdwriteback (SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, BlockNumber nblocks)
 
BlockNumber mdnblocks (SMgrRelation reln, ForkNumber forknum)
 
void mdtruncate (SMgrRelation reln, ForkNumber forknum, BlockNumber old_blocks, BlockNumber nblocks)
 
void mdimmedsync (SMgrRelation reln, ForkNumber forknum)
 
void mdregistersync (SMgrRelation reln, ForkNumber forknum)
 
void ForgetDatabaseSyncRequests (Oid dbid)
 
void DropRelationFiles (RelFileLocator *delrels, int ndelrels, bool isRedo)
 
int mdsyncfiletag (const FileTag *ftag, char *path)
 
int mdunlinkfiletag (const FileTag *ftag, char *path)
 
bool mdfiletagmatches (const FileTag *ftag, const FileTag *candidate)
 

Function Documentation

◆ DropRelationFiles()

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

Definition at line 1461 of file md.c.

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

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

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

◆ ForgetDatabaseSyncRequests()

void ForgetDatabaseSyncRequests ( Oid  dbid)

Definition at line 1443 of file md.c.

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

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

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

◆ mdclose()

void mdclose ( SMgrRelation  reln,
ForkNumber  forknum 
)

Definition at line 683 of file md.c.

684{
685 int nopensegs = reln->md_num_open_segs[forknum];
686
687 /* No work if already closed */
688 if (nopensegs == 0)
689 return;
690
691 /* close segments starting from the end */
692 while (nopensegs > 0)
693 {
694 MdfdVec *v = &reln->md_seg_fds[forknum][nopensegs - 1];
695
697 _fdvec_resize(reln, forknum, nopensegs - 1);
698 nopensegs--;
699 }
700}
void FileClose(File file)
Definition: fd.c:1977
static void _fdvec_resize(SMgrRelation reln, ForkNumber forknum, int nseg)
Definition: md.c:1493
int md_num_open_segs[MAX_FORKNUM+1]
Definition: smgr.h:60
struct _MdfdVec * md_seg_fds[MAX_FORKNUM+1]
Definition: smgr.h:61
Definition: md.c:81
File mdfd_vfd
Definition: md.c:82

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

Referenced by mdexists().

◆ mdcreate()

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

Definition at line 182 of file md.c.

183{
184 MdfdVec *mdfd;
185 char *path;
186 File fd;
187
188 if (isRedo && reln->md_num_open_segs[forknum] > 0)
189 return; /* created and opened already... */
190
191 Assert(reln->md_num_open_segs[forknum] == 0);
192
193 /*
194 * We may be using the target table space for the first time in this
195 * database, so create a per-database subdirectory if needed.
196 *
197 * XXX this is a fairly ugly violation of module layering, but this seems
198 * to be the best place to put the check. Maybe TablespaceCreateDbspace
199 * should be here and not in commands/tablespace.c? But that would imply
200 * importing a lot of stuff that smgr.c oughtn't know, either.
201 */
204 isRedo);
205
206 path = relpath(reln->smgr_rlocator, forknum);
207
208 fd = PathNameOpenFile(path, _mdfd_open_flags() | O_CREAT | O_EXCL);
209
210 if (fd < 0)
211 {
212 int save_errno = errno;
213
214 if (isRedo)
216 if (fd < 0)
217 {
218 /* be sure to report the error reported by create, not open */
219 errno = save_errno;
222 errmsg("could not create file \"%s\": %m", path)));
223 }
224 }
225
226 pfree(path);
227
228 _fdvec_resize(reln, forknum, 1);
229 mdfd = &reln->md_seg_fds[forknum][0];
230 mdfd->mdfd_vfd = fd;
231 mdfd->mdfd_segno = 0;
232
233 if (!SmgrIsTemp(reln))
234 register_dirty_segment(reln, forknum, mdfd);
235}
void TablespaceCreateDbspace(Oid spcOid, Oid dbOid, bool isRedo)
Definition: tablespace.c:112
#define Assert(condition)
Definition: c.h:815
int errcode_for_file_access(void)
Definition: elog.c:876
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
File PathNameOpenFile(const char *fileName, int fileFlags)
Definition: fd.c:1574
int File
Definition: fd.h:51
static void register_dirty_segment(SMgrRelation reln, ForkNumber forknum, MdfdVec *seg)
Definition: md.c:1368
static int _mdfd_open_flags(void)
Definition: md.c:136
static int fd(const char *x, int i)
Definition: preproc-init.c:105
#define relpath(rlocator, forknum)
Definition: relpath.h:102
#define SmgrIsTemp(smgr)
Definition: smgr.h:73
RelFileLocator locator
RelFileLocatorBackend smgr_rlocator
Definition: smgr.h:37
BlockNumber mdfd_segno
Definition: md.c:83

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

◆ mdexists()

bool mdexists ( SMgrRelation  reln,
ForkNumber  forknum 
)

Definition at line 163 of file md.c.

164{
165 /*
166 * Close it first, to ensure that we notice if the fork has been unlinked
167 * since we opened it. As an optimization, we can skip that in recovery,
168 * which already closes relations when dropping them.
169 */
170 if (!InRecovery)
171 mdclose(reln, forknum);
172
173 return (mdopenfork(reln, forknum, EXTENSION_RETURN_NULL) != NULL);
174}
void mdclose(SMgrRelation reln, ForkNumber forknum)
Definition: md.c:683
#define EXTENSION_RETURN_NULL
Definition: md.c:104
static MdfdVec * mdopenfork(SMgrRelation reln, ForkNumber forknum, int behavior)
Definition: md.c:629
bool InRecovery
Definition: xlogutils.c:50

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

◆ mdextend()

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

Definition at line 452 of file md.c.

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

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

Referenced by _mdfd_getseg().

◆ mdfiletagmatches()

bool mdfiletagmatches ( const FileTag ftag,
const FileTag candidate 
)

Definition at line 1831 of file md.c.

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

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

◆ mdimmedsync()

void mdimmedsync ( SMgrRelation  reln,
ForkNumber  forknum 
)

Definition at line 1306 of file md.c.

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

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

◆ mdinit()

void mdinit ( void  )

Definition at line 150 of file md.c.

151{
153 "MdSmgr",
155}
MemoryContext TopMemoryContext
Definition: mcxt.c:149
static MemoryContext MdCxt
Definition: md.c:86
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, MdCxt, and TopMemoryContext.

◆ mdmaxcombine()

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

Definition at line 803 of file md.c.

805{
806 BlockNumber segoff;
807
808 segoff = blocknum % ((BlockNumber) RELSEG_SIZE);
809
810 return RELSEG_SIZE - segoff;
811}

◆ mdnblocks()

BlockNumber mdnblocks ( SMgrRelation  reln,
ForkNumber  forknum 
)

Definition at line 1102 of file md.c.

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

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

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

◆ mdopen()

void mdopen ( SMgrRelation  reln)

Definition at line 672 of file md.c.

673{
674 /* mark it not open */
675 for (int forknum = 0; forknum <= MAX_FORKNUM; forknum++)
676 reln->md_num_open_segs[forknum] = 0;
677}

References MAX_FORKNUM, and SMgrRelationData::md_num_open_segs.

◆ mdprefetch()

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

Definition at line 706 of file md.c.

708{
709#ifdef USE_PREFETCH
710
712
713 if ((uint64) blocknum + nblocks > (uint64) MaxBlockNumber + 1)
714 return false;
715
716 while (nblocks > 0)
717 {
718 off_t seekpos;
719 MdfdVec *v;
720 int nblocks_this_segment;
721
722 v = _mdfd_getseg(reln, forknum, blocknum, false,
724 if (v == NULL)
725 return false;
726
727 seekpos = (off_t) BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE));
728
729 Assert(seekpos < (off_t) BLCKSZ * RELSEG_SIZE);
730
731 nblocks_this_segment =
732 Min(nblocks,
733 RELSEG_SIZE - (blocknum % ((BlockNumber) RELSEG_SIZE)));
734
735 (void) FilePrefetch(v->mdfd_vfd, seekpos, BLCKSZ * nblocks_this_segment,
736 WAIT_EVENT_DATA_FILE_PREFETCH);
737
738 blocknum += nblocks_this_segment;
739 nblocks -= nblocks_this_segment;
740 }
741#endif /* USE_PREFETCH */
742
743 return true;
744}
#define MaxBlockNumber
Definition: block.h:35
#define Min(x, y)
Definition: c.h:961
uint64_t uint64
Definition: c.h:489
int io_direct_flags
Definition: fd.c:167
int FilePrefetch(File file, off_t offset, off_t amount, uint32 wait_event_info)
Definition: fd.c:2076
#define IO_DIRECT_DATA
Definition: fd.h:54

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

◆ mdreadv()

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

Definition at line 817 of file md.c.

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

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

◆ mdregistersync()

void mdregistersync ( SMgrRelation  reln,
ForkNumber  forknum 
)

Definition at line 1255 of file md.c.

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

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

◆ mdsyncfiletag()

int mdsyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 1759 of file md.c.

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

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

◆ mdtruncate()

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

Definition at line 1166 of file md.c.

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

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

◆ mdunlink()

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

Definition at line 299 of file md.c.

300{
301 /* Now do the per-fork work */
302 if (forknum == InvalidForkNumber)
303 {
304 for (forknum = 0; forknum <= MAX_FORKNUM; forknum++)
305 mdunlinkfork(rlocator, forknum, isRedo);
306 }
307 else
308 mdunlinkfork(rlocator, forknum, isRedo);
309}
static void mdunlinkfork(RelFileLocatorBackend rlocator, ForkNumber forknum, bool isRedo)
Definition: md.c:336

References InvalidForkNumber, MAX_FORKNUM, and mdunlinkfork().

◆ mdunlinkfiletag()

int mdunlinkfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 1812 of file md.c.

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

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

◆ mdwriteback()

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

Definition at line 1043 of file md.c.

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

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

◆ mdwritev()

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

Definition at line 938 of file md.c.

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

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

◆ mdzeroextend()

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

Definition at line 517 of file md.c.

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

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