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

Go to the source code of this file.

Functions

SMgrRelation RelationCreateStorage (RelFileNode rnode, char relpersistence)
 
void RelationDropStorage (Relation rel)
 
void RelationPreserveStorage (RelFileNode rnode, bool atCommit)
 
void RelationPreTruncate (Relation rel)
 
void RelationTruncate (Relation rel, BlockNumber nblocks)
 
void RelationCopyStorage (SMgrRelation src, SMgrRelation dst, ForkNumber forkNum, char relpersistence)
 
bool RelFileNodeSkippingWAL (RelFileNode rnode)
 
Size EstimatePendingSyncsSpace (void)
 
void SerializePendingSyncs (Size maxSize, char *startAddress)
 
void RestorePendingSyncs (char *startAddress)
 
void smgrDoPendingDeletes (bool isCommit)
 
void smgrDoPendingSyncs (bool isCommit, bool isParallelWorker)
 
int smgrGetPendingDeletes (bool forCommit, RelFileNode **ptr)
 
void AtSubCommit_smgr (void)
 
void AtSubAbort_smgr (void)
 
void PostPrepare_smgr (void)
 

Variables

int wal_skip_threshold
 

Function Documentation

◆ AtSubAbort_smgr()

void AtSubAbort_smgr ( void  )

Definition at line 914 of file storage.c.

915 {
916  smgrDoPendingDeletes(false);
917 }
void smgrDoPendingDeletes(bool isCommit)
Definition: storage.c:612

References smgrDoPendingDeletes().

Referenced by AbortSubTransaction().

◆ AtSubCommit_smgr()

void AtSubCommit_smgr ( void  )

Definition at line 894 of file storage.c.

895 {
896  int nestLevel = GetCurrentTransactionNestLevel();
897  PendingRelDelete *pending;
898 
899  for (pending = pendingDeletes; pending != NULL; pending = pending->next)
900  {
901  if (pending->nestLevel >= nestLevel)
902  pending->nestLevel = nestLevel - 1;
903  }
904 }
static PendingRelDelete * pendingDeletes
Definition: storage.c:75
struct PendingRelDelete * next
Definition: storage.c:66
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:909

References GetCurrentTransactionNestLevel(), PendingRelDelete::nestLevel, PendingRelDelete::next, and pendingDeletes.

Referenced by CommitSubTransaction().

◆ EstimatePendingSyncsSpace()

Size EstimatePendingSyncsSpace ( void  )

Definition at line 527 of file storage.c.

528 {
529  long entries;
530 
532  return mul_size(1 + entries, sizeof(RelFileNode));
533 }
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1382
Size mul_size(Size s1, Size s2)
Definition: shmem.c:519
HTAB * pendingSyncHash
Definition: storage.c:76

References hash_get_num_entries(), mul_size(), and pendingSyncHash.

Referenced by InitializeParallelDSM().

◆ PostPrepare_smgr()

void PostPrepare_smgr ( void  )

Definition at line 873 of file storage.c.

874 {
875  PendingRelDelete *pending;
877 
878  for (pending = pendingDeletes; pending != NULL; pending = next)
879  {
880  next = pending->next;
882  /* must explicitly free the list entry */
883  pfree(pending);
884  }
885 }
static int32 next
Definition: blutils.c:219
void pfree(void *pointer)
Definition: mcxt.c:1169

References next, PendingRelDelete::next, pendingDeletes, and pfree().

Referenced by PrepareTransaction().

◆ RelationCopyStorage()

void RelationCopyStorage ( SMgrRelation  src,
SMgrRelation  dst,
ForkNumber  forkNum,
char  relpersistence 
)

Definition at line 414 of file storage.c.

416 {
418  Page page;
419  bool use_wal;
420  bool copying_initfork;
421  BlockNumber nblocks;
422  BlockNumber blkno;
423 
424  page = (Page) buf.data;
425 
426  /*
427  * The init fork for an unlogged relation in many respects has to be
428  * treated the same as normal relation, changes need to be WAL logged and
429  * it needs to be synced to disk.
430  */
431  copying_initfork = relpersistence == RELPERSISTENCE_UNLOGGED &&
432  forkNum == INIT_FORKNUM;
433 
434  /*
435  * We need to log the copied data in WAL iff WAL archiving/streaming is
436  * enabled AND it's a permanent relation. This gives the same answer as
437  * "RelationNeedsWAL(rel) || copying_initfork", because we know the
438  * current operation created a new relfilenode.
439  */
440  use_wal = XLogIsNeeded() &&
441  (relpersistence == RELPERSISTENCE_PERMANENT || copying_initfork);
442 
443  nblocks = smgrnblocks(src, forkNum);
444 
445  for (blkno = 0; blkno < nblocks; blkno++)
446  {
447  /* If we got a cancel signal during the copy of the data, quit */
449 
450  smgrread(src, forkNum, blkno, buf.data);
451 
452  if (!PageIsVerifiedExtended(page, blkno,
454  {
455  /*
456  * For paranoia's sake, capture the file path before invoking the
457  * ereport machinery. This guards against the possibility of a
458  * relcache flush caused by, e.g., an errcontext callback.
459  * (errcontext callbacks shouldn't be risking any such thing, but
460  * people have been known to forget that rule.)
461  */
462  char *relpath = relpathbackend(src->smgr_rnode.node,
463  src->smgr_rnode.backend,
464  forkNum);
465 
466  ereport(ERROR,
468  errmsg("invalid page in block %u of relation %s",
469  blkno, relpath)));
470  }
471 
472  /*
473  * WAL-log the copied page. Unfortunately we don't know what kind of a
474  * page this is, so we have to log the full page including any unused
475  * space.
476  */
477  if (use_wal)
478  log_newpage(&dst->smgr_rnode.node, forkNum, blkno, page, false);
479 
480  PageSetChecksumInplace(page, blkno);
481 
482  /*
483  * Now write the page. We say skipFsync = true because there's no
484  * need for smgr to schedule an fsync for this write; we'll do it
485  * ourselves below.
486  */
487  smgrextend(dst, forkNum, blkno, buf.data, true);
488  }
489 
490  /*
491  * When we WAL-logged rel pages, we must nonetheless fsync them. The
492  * reason is that since we're copying outside shared buffers, a CHECKPOINT
493  * occurring during the copy has no way to flush the previously written
494  * data to disk (indeed it won't know the new rel even exists). A crash
495  * later on would replay WAL from the checkpoint, therefore it wouldn't
496  * replay our earlier WAL entries. If we do not fsync those pages here,
497  * they might still not be on disk when the crash occurs.
498  */
499  if (use_wal || copying_initfork)
500  smgrimmedsync(dst, forkNum);
501 }
uint32 BlockNumber
Definition: block.h:31
bool PageIsVerifiedExtended(Page page, BlockNumber blkno, int flags)
Definition: bufpage.c:88
void PageSetChecksumInplace(Page page, BlockNumber blkno)
Definition: bufpage.c:1532
Pointer Page
Definition: bufpage.h:78
#define PIV_LOG_WARNING
Definition: bufpage.h:412
#define PIV_REPORT_STAT
Definition: bufpage.h:413
int errcode(int sqlerrcode)
Definition: elog.c:693
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define ERROR
Definition: elog.h:33
#define ereport(elevel,...)
Definition: elog.h:143
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:120
#define ERRCODE_DATA_CORRUPTED
Definition: pg_basebackup.c:42
static char * buf
Definition: pg_test_fsync.c:70
@ INIT_FORKNUM
Definition: relpath.h:46
#define relpath(rnode, forknum)
Definition: relpath.h:87
#define relpathbackend(rnode, backend, forknum)
Definition: relpath.h:78
BlockNumber smgrnblocks(SMgrRelation reln, ForkNumber forknum)
Definition: smgr.c:548
void smgrextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer, bool skipFsync)
Definition: smgr.c:462
void smgrimmedsync(SMgrRelation reln, ForkNumber forknum)
Definition: smgr.c:660
void smgrread(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer)
Definition: smgr.c:501
BackendId backend
Definition: relfilenode.h:75
RelFileNode node
Definition: relfilenode.h:74
RelFileNodeBackend smgr_rnode
Definition: smgr.h:42
#define XLogIsNeeded()
Definition: xlog.h:164
XLogRecPtr log_newpage(RelFileNode *rnode, ForkNumber forkNum, BlockNumber blkno, Page page, bool page_std)
Definition: xloginsert.c:1050

References RelFileNodeBackend::backend, buf, CHECK_FOR_INTERRUPTS, ereport, errcode(), ERRCODE_DATA_CORRUPTED, errmsg(), ERROR, INIT_FORKNUM, log_newpage(), RelFileNodeBackend::node, PageIsVerifiedExtended(), PageSetChecksumInplace(), PIV_LOG_WARNING, PIV_REPORT_STAT, relpath, relpathbackend, SMgrRelationData::smgr_rnode, smgrextend(), smgrimmedsync(), smgrnblocks(), smgrread(), and XLogIsNeeded.

Referenced by heapam_relation_copy_data(), and index_copy_data().

◆ RelationCreateStorage()

SMgrRelation RelationCreateStorage ( RelFileNode  rnode,
char  relpersistence 
)

Definition at line 118 of file storage.c.

119 {
120  PendingRelDelete *pending;
121  SMgrRelation srel;
122  BackendId backend;
123  bool needs_wal;
124 
125  Assert(!IsInParallelMode()); /* couldn't update pendingSyncHash */
126 
127  switch (relpersistence)
128  {
129  case RELPERSISTENCE_TEMP:
130  backend = BackendIdForTempRelations();
131  needs_wal = false;
132  break;
133  case RELPERSISTENCE_UNLOGGED:
134  backend = InvalidBackendId;
135  needs_wal = false;
136  break;
137  case RELPERSISTENCE_PERMANENT:
138  backend = InvalidBackendId;
139  needs_wal = true;
140  break;
141  default:
142  elog(ERROR, "invalid relpersistence: %c", relpersistence);
143  return NULL; /* placate compiler */
144  }
145 
146  srel = smgropen(rnode, backend);
147  smgrcreate(srel, MAIN_FORKNUM, false);
148 
149  if (needs_wal)
151 
152  /* Add the relation to the list of stuff to delete at abort */
153  pending = (PendingRelDelete *)
155  pending->relnode = rnode;
156  pending->backend = backend;
157  pending->atCommit = false; /* delete if abort */
159  pending->next = pendingDeletes;
160  pendingDeletes = pending;
161 
162  if (relpersistence == RELPERSISTENCE_PERMANENT && !XLogIsNeeded())
163  {
164  Assert(backend == InvalidBackendId);
165  AddPendingSync(&rnode);
166  }
167 
168  return srel;
169 }
int BackendId
Definition: backendid.h:21
#define BackendIdForTempRelations()
Definition: backendid.h:34
#define InvalidBackendId
Definition: backendid.h:23
#define elog(elevel,...)
Definition: elog.h:218
Assert(fmt[strlen(fmt) - 1] !='\n')
MemoryContext TopMemoryContext
Definition: mcxt.c:48
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:863
@ MAIN_FORKNUM
Definition: relpath.h:43
void smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
Definition: smgr.c:333
SMgrRelation smgropen(RelFileNode rnode, BackendId backend)
Definition: smgr.c:146
void log_smgrcreate(const RelFileNode *rnode, ForkNumber forkNum)
Definition: storage.c:175
static void AddPendingSync(const RelFileNode *rnode)
Definition: storage.c:84
RelFileNode relnode
Definition: storage.c:62
BackendId backend
Definition: storage.c:63
bool IsInParallelMode(void)
Definition: xact.c:1064

References AddPendingSync(), Assert(), PendingRelDelete::atCommit, PendingRelDelete::backend, BackendIdForTempRelations, elog, ERROR, GetCurrentTransactionNestLevel(), InvalidBackendId, IsInParallelMode(), log_smgrcreate(), MAIN_FORKNUM, MemoryContextAlloc(), PendingRelDelete::nestLevel, PendingRelDelete::next, RelFileNodeBackend::node, pendingDeletes, PendingRelDelete::relnode, SMgrRelationData::smgr_rnode, smgrcreate(), smgropen(), TopMemoryContext, and XLogIsNeeded.

Referenced by heap_create(), heapam_relation_copy_data(), heapam_relation_set_new_filenode(), index_copy_data(), and RelationSetNewRelfilenode().

◆ RelationDropStorage()

void RelationDropStorage ( Relation  rel)

Definition at line 195 of file storage.c.

196 {
197  PendingRelDelete *pending;
198 
199  /* Add the relation to the list of stuff to delete at commit */
200  pending = (PendingRelDelete *)
202  pending->relnode = rel->rd_node;
203  pending->backend = rel->rd_backend;
204  pending->atCommit = true; /* delete if commit */
206  pending->next = pendingDeletes;
207  pendingDeletes = pending;
208 
209  /*
210  * NOTE: if the relation was created in this transaction, it will now be
211  * present in the pending-delete list twice, once with atCommit true and
212  * once with atCommit false. Hence, it will be physically deleted at end
213  * of xact in either case (and the other entry will be ignored by
214  * smgrDoPendingDeletes, so no error will occur). We could instead remove
215  * the existing list entry and delete the physical file immediately, but
216  * for now I'll keep the logic simple.
217  */
218 
219  RelationCloseSmgr(rel);
220 }
#define RelationCloseSmgr(relation)
Definition: rel.h:558
RelFileNode rd_node
Definition: rel.h:56
BackendId rd_backend
Definition: rel.h:59

References PendingRelDelete::atCommit, PendingRelDelete::backend, GetCurrentTransactionNestLevel(), MemoryContextAlloc(), PendingRelDelete::nestLevel, PendingRelDelete::next, pendingDeletes, RelationData::rd_backend, RelationData::rd_node, RelationCloseSmgr, PendingRelDelete::relnode, and TopMemoryContext.

Referenced by DefineQueryRewrite(), heap_drop_with_catalog(), heapam_relation_copy_data(), index_copy_data(), index_drop(), reindex_index(), and RelationSetNewRelfilenode().

◆ RelationPreserveStorage()

void RelationPreserveStorage ( RelFileNode  rnode,
bool  atCommit 
)

Definition at line 240 of file storage.c.

241 {
242  PendingRelDelete *pending;
243  PendingRelDelete *prev;
245 
246  prev = NULL;
247  for (pending = pendingDeletes; pending != NULL; pending = next)
248  {
249  next = pending->next;
250  if (RelFileNodeEquals(rnode, pending->relnode)
251  && pending->atCommit == atCommit)
252  {
253  /* unlink and delete list entry */
254  if (prev)
255  prev->next = next;
256  else
258  pfree(pending);
259  /* prev does not change */
260  }
261  else
262  {
263  /* unrelated entry, don't touch it */
264  prev = pending;
265  }
266  }
267 }
#define RelFileNodeEquals(node1, node2)
Definition: relfilenode.h:88

References PendingRelDelete::atCommit, next, PendingRelDelete::next, pendingDeletes, pfree(), RelFileNodeEquals, and PendingRelDelete::relnode.

Referenced by ATExecAddIndex(), and write_relmap_file().

◆ RelationPreTruncate()

void RelationPreTruncate ( Relation  rel)

Definition at line 386 of file storage.c.

387 {
388  PendingRelSync *pending;
389 
390  if (!pendingSyncHash)
391  return;
392 
393  pending = hash_search(pendingSyncHash,
394  &(RelationGetSmgr(rel)->smgr_rnode.node),
395  HASH_FIND, NULL);
396  if (pending)
397  pending->is_truncated = true;
398 }
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
@ HASH_FIND
Definition: hsearch.h:113
static SMgrRelation RelationGetSmgr(Relation rel)
Definition: rel.h:545
bool is_truncated
Definition: storage.c:72
dlist_node node
Definition: smgr.h:72

References HASH_FIND, hash_search(), PendingRelSync::is_truncated, SMgrRelationData::node, pendingSyncHash, and RelationGetSmgr().

Referenced by RelationTruncate().

◆ RelationTruncate()

void RelationTruncate ( Relation  rel,
BlockNumber  nblocks 
)

Definition at line 277 of file storage.c.

278 {
279  bool fsm;
280  bool vm;
281  bool need_fsm_vacuum = false;
282  ForkNumber forks[MAX_FORKNUM];
283  BlockNumber blocks[MAX_FORKNUM];
284  int nforks = 0;
285  SMgrRelation reln;
286 
287  /*
288  * Make sure smgr_targblock etc aren't pointing somewhere past new end.
289  * (Note: don't rely on this reln pointer below this loop.)
290  */
291  reln = RelationGetSmgr(rel);
293  for (int i = 0; i <= MAX_FORKNUM; ++i)
295 
296  /* Prepare for truncation of MAIN fork of the relation */
297  forks[nforks] = MAIN_FORKNUM;
298  blocks[nforks] = nblocks;
299  nforks++;
300 
301  /* Prepare for truncation of the FSM if it exists */
303  if (fsm)
304  {
305  blocks[nforks] = FreeSpaceMapPrepareTruncateRel(rel, nblocks);
306  if (BlockNumberIsValid(blocks[nforks]))
307  {
308  forks[nforks] = FSM_FORKNUM;
309  nforks++;
310  need_fsm_vacuum = true;
311  }
312  }
313 
314  /* Prepare for truncation of the visibility map too if it exists */
316  if (vm)
317  {
318  blocks[nforks] = visibilitymap_prepare_truncate(rel, nblocks);
319  if (BlockNumberIsValid(blocks[nforks]))
320  {
321  forks[nforks] = VISIBILITYMAP_FORKNUM;
322  nforks++;
323  }
324  }
325 
326  RelationPreTruncate(rel);
327 
328  /*
329  * We WAL-log the truncation before actually truncating, which means
330  * trouble if the truncation fails. If we then crash, the WAL replay
331  * likely isn't going to succeed in the truncation either, and cause a
332  * PANIC. It's tempting to put a critical section here, but that cure
333  * would be worse than the disease. It would turn a usually harmless
334  * failure to truncate, that might spell trouble at WAL replay, into a
335  * certain PANIC.
336  */
337  if (RelationNeedsWAL(rel))
338  {
339  /*
340  * Make an XLOG entry reporting the file truncation.
341  */
342  XLogRecPtr lsn;
343  xl_smgr_truncate xlrec;
344 
345  xlrec.blkno = nblocks;
346  xlrec.rnode = rel->rd_node;
347  xlrec.flags = SMGR_TRUNCATE_ALL;
348 
349  XLogBeginInsert();
350  XLogRegisterData((char *) &xlrec, sizeof(xlrec));
351 
352  lsn = XLogInsert(RM_SMGR_ID,
354 
355  /*
356  * Flush, because otherwise the truncation of the main relation might
357  * hit the disk before the WAL record, and the truncation of the FSM
358  * or visibility map. If we crashed during that window, we'd be left
359  * with a truncated heap, but the FSM or visibility map would still
360  * contain entries for the non-existent heap pages.
361  */
362  if (fsm || vm)
363  XLogFlush(lsn);
364  }
365 
366  /* Do the real work to truncate relation forks */
367  smgrtruncate(RelationGetSmgr(rel), forks, nforks, blocks);
368 
369  /*
370  * Update upper-level FSM pages to account for the truncation. This is
371  * important because the just-truncated pages were likely marked as
372  * all-free, and would be preferentially selected.
373  */
374  if (need_fsm_vacuum)
376 }
#define InvalidBlockNumber
Definition: block.h:33
#define BlockNumberIsValid(blockNumber)
Definition: block.h:70
void FreeSpaceMapVacuumRange(Relation rel, BlockNumber start, BlockNumber end)
Definition: freespace.c:352
BlockNumber FreeSpaceMapPrepareTruncateRel(Relation rel, BlockNumber nblocks)
Definition: freespace.c:261
int i
Definition: isn.c:73
#define RelationNeedsWAL(relation)
Definition: rel.h:602
ForkNumber
Definition: relpath.h:41
@ FSM_FORKNUM
Definition: relpath.h:44
@ VISIBILITYMAP_FORKNUM
Definition: relpath.h:45
#define MAX_FORKNUM
Definition: relpath.h:55
void smgrtruncate(SMgrRelation reln, ForkNumber *forknum, int nforks, BlockNumber *nblocks)
Definition: smgr.c:595
bool smgrexists(SMgrRelation reln, ForkNumber forknum)
Definition: smgr.c:247
void RelationPreTruncate(Relation rel)
Definition: storage.c:386
#define SMGR_TRUNCATE_ALL
Definition: storage_xlog.h:43
#define XLOG_SMGR_TRUNCATE
Definition: storage_xlog.h:31
BlockNumber smgr_targblock
Definition: smgr.h:53
BlockNumber smgr_cached_nblocks[MAX_FORKNUM+1]
Definition: smgr.h:54
BlockNumber blkno
Definition: storage_xlog.h:48
RelFileNode rnode
Definition: storage_xlog.h:49
BlockNumber visibilitymap_prepare_truncate(Relation rel, BlockNumber nheapblocks)
void XLogFlush(XLogRecPtr record)
Definition: xlog.c:2924
uint64 XLogRecPtr
Definition: xlogdefs.h:21
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:429
void XLogBeginInsert(void)
Definition: xloginsert.c:136
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:337
#define XLR_SPECIAL_REL_UPDATE
Definition: xlogrecord.h:71

References xl_smgr_truncate::blkno, BlockNumberIsValid, xl_smgr_truncate::flags, FreeSpaceMapPrepareTruncateRel(), FreeSpaceMapVacuumRange(), FSM_FORKNUM, i, InvalidBlockNumber, MAIN_FORKNUM, MAX_FORKNUM, RelationData::rd_node, RelationGetSmgr(), RelationNeedsWAL, RelationPreTruncate(), xl_smgr_truncate::rnode, SMgrRelationData::smgr_cached_nblocks, SMgrRelationData::smgr_targblock, SMGR_TRUNCATE_ALL, smgrexists(), smgrtruncate(), VISIBILITYMAP_FORKNUM, visibilitymap_prepare_truncate(), XLOG_SMGR_TRUNCATE, XLogBeginInsert(), XLogFlush(), XLogInsert(), XLogRegisterData(), and XLR_SPECIAL_REL_UPDATE.

Referenced by heapam_relation_nontransactional_truncate(), lazy_truncate_heap(), RelationTruncateIndexes(), and spgvacuumscan().

◆ RelFileNodeSkippingWAL()

bool RelFileNodeSkippingWAL ( RelFileNode  rnode)

Definition at line 513 of file storage.c.

514 {
515  if (!pendingSyncHash ||
516  hash_search(pendingSyncHash, &rnode, HASH_FIND, NULL) == NULL)
517  return false;
518 
519  return true;
520 }

References HASH_FIND, hash_search(), and pendingSyncHash.

Referenced by MarkBufferDirtyHint(), and RelationInitPhysicalAddr().

◆ RestorePendingSyncs()

void RestorePendingSyncs ( char *  startAddress)

Definition at line 591 of file storage.c.

592 {
593  RelFileNode *rnode;
594 
595  Assert(pendingSyncHash == NULL);
596  for (rnode = (RelFileNode *) startAddress; rnode->relNode != 0; rnode++)
597  AddPendingSync(rnode);
598 }

References AddPendingSync(), Assert(), pendingSyncHash, and RelFileNode::relNode.

Referenced by ParallelWorkerMain().

◆ SerializePendingSyncs()

void SerializePendingSyncs ( Size  maxSize,
char *  startAddress 
)

Definition at line 540 of file storage.c.

541 {
542  HTAB *tmphash;
543  HASHCTL ctl;
544  HASH_SEQ_STATUS scan;
545  PendingRelSync *sync;
546  PendingRelDelete *delete;
547  RelFileNode *src;
548  RelFileNode *dest = (RelFileNode *) startAddress;
549 
550  if (!pendingSyncHash)
551  goto terminate;
552 
553  /* Create temporary hash to collect active relfilenodes */
554  ctl.keysize = sizeof(RelFileNode);
555  ctl.entrysize = sizeof(RelFileNode);
557  tmphash = hash_create("tmp relfilenodes",
560 
561  /* collect all rnodes from pending syncs */
563  while ((sync = (PendingRelSync *) hash_seq_search(&scan)))
564  (void) hash_search(tmphash, &sync->rnode, HASH_ENTER, NULL);
565 
566  /* remove deleted rnodes */
567  for (delete = pendingDeletes; delete != NULL; delete = delete->next)
568  if (delete->atCommit)
569  (void) hash_search(tmphash, (void *) &delete->relnode,
570  HASH_REMOVE, NULL);
571 
572  hash_seq_init(&scan, tmphash);
573  while ((src = (RelFileNode *) hash_seq_search(&scan)))
574  *dest++ = *src;
575 
576  hash_destroy(tmphash);
577 
578 terminate:
579  MemSet(dest, 0, sizeof(RelFileNode));
580 }
#define MemSet(start, val, len)
Definition: c.h:1008
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:862
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:349
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1436
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
@ HASH_REMOVE
Definition: hsearch.h:115
@ HASH_ENTER
Definition: hsearch.h:114
#define HASH_CONTEXT
Definition: hsearch.h:102
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
MemoryContext CurrentMemoryContext
Definition: mcxt.c:42
struct RelFileNode RelFileNode
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76
MemoryContext hcxt
Definition: hsearch.h:86
Definition: dynahash.c:220
RelFileNode rnode
Definition: storage.c:71

References CurrentMemoryContext, generate_unaccent_rules::dest, HASHCTL::entrysize, HASH_BLOBS, HASH_CONTEXT, hash_create(), hash_destroy(), HASH_ELEM, HASH_ENTER, hash_get_num_entries(), HASH_REMOVE, hash_search(), hash_seq_init(), hash_seq_search(), HASHCTL::hcxt, HASHCTL::keysize, MemSet, PendingRelDelete::next, pendingDeletes, pendingSyncHash, and PendingRelSync::rnode.

Referenced by InitializeParallelDSM().

◆ smgrDoPendingDeletes()

void smgrDoPendingDeletes ( bool  isCommit)

Definition at line 612 of file storage.c.

613 {
614  int nestLevel = GetCurrentTransactionNestLevel();
615  PendingRelDelete *pending;
616  PendingRelDelete *prev;
618  int nrels = 0,
619  maxrels = 0;
620  SMgrRelation *srels = NULL;
621 
622  prev = NULL;
623  for (pending = pendingDeletes; pending != NULL; pending = next)
624  {
625  next = pending->next;
626  if (pending->nestLevel < nestLevel)
627  {
628  /* outer-level entries should not be processed yet */
629  prev = pending;
630  }
631  else
632  {
633  /* unlink list entry first, so we don't retry on failure */
634  if (prev)
635  prev->next = next;
636  else
638  /* do deletion if called for */
639  if (pending->atCommit == isCommit)
640  {
641  SMgrRelation srel;
642 
643  srel = smgropen(pending->relnode, pending->backend);
644 
645  /* allocate the initial array, or extend it, if needed */
646  if (maxrels == 0)
647  {
648  maxrels = 8;
649  srels = palloc(sizeof(SMgrRelation) * maxrels);
650  }
651  else if (maxrels <= nrels)
652  {
653  maxrels *= 2;
654  srels = repalloc(srels, sizeof(SMgrRelation) * maxrels);
655  }
656 
657  srels[nrels++] = srel;
658  }
659  /* must explicitly free the list entry */
660  pfree(pending);
661  /* prev does not change */
662  }
663  }
664 
665  if (nrels > 0)
666  {
667  smgrdounlinkall(srels, nrels, false);
668 
669  for (int i = 0; i < nrels; i++)
670  smgrclose(srels[i]);
671 
672  pfree(srels);
673  }
674 }
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1182
void * palloc(Size size)
Definition: mcxt.c:1062
void smgrclose(SMgrRelation reln)
Definition: smgr.c:256
void smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo)
Definition: smgr.c:384

References PendingRelDelete::atCommit, PendingRelDelete::backend, GetCurrentTransactionNestLevel(), i, PendingRelDelete::nestLevel, next, PendingRelDelete::next, palloc(), pendingDeletes, pfree(), PendingRelDelete::relnode, repalloc(), smgrclose(), smgrdounlinkall(), and smgropen().

Referenced by AbortTransaction(), AtSubAbort_smgr(), and CommitTransaction().

◆ smgrDoPendingSyncs()

void smgrDoPendingSyncs ( bool  isCommit,
bool  isParallelWorker 
)

Definition at line 680 of file storage.c.

681 {
682  PendingRelDelete *pending;
683  int nrels = 0,
684  maxrels = 0;
685  SMgrRelation *srels = NULL;
686  HASH_SEQ_STATUS scan;
687  PendingRelSync *pendingsync;
688 
690 
691  if (!pendingSyncHash)
692  return; /* no relation needs sync */
693 
694  /* Abort -- just throw away all pending syncs */
695  if (!isCommit)
696  {
697  pendingSyncHash = NULL;
698  return;
699  }
700 
702 
703  /* Parallel worker -- just throw away all pending syncs */
704  if (isParallelWorker)
705  {
706  pendingSyncHash = NULL;
707  return;
708  }
709 
710  /* Skip syncing nodes that smgrDoPendingDeletes() will delete. */
711  for (pending = pendingDeletes; pending != NULL; pending = pending->next)
712  if (pending->atCommit)
713  (void) hash_search(pendingSyncHash, (void *) &pending->relnode,
714  HASH_REMOVE, NULL);
715 
717  while ((pendingsync = (PendingRelSync *) hash_seq_search(&scan)))
718  {
719  ForkNumber fork;
720  BlockNumber nblocks[MAX_FORKNUM + 1];
721  BlockNumber total_blocks = 0;
722  SMgrRelation srel;
723 
724  srel = smgropen(pendingsync->rnode, InvalidBackendId);
725 
726  /*
727  * We emit newpage WAL records for smaller relations.
728  *
729  * Small WAL records have a chance to be emitted along with other
730  * backends' WAL records. We emit WAL records instead of syncing for
731  * files that are smaller than a certain threshold, expecting faster
732  * commit. The threshold is defined by the GUC wal_skip_threshold.
733  */
734  if (!pendingsync->is_truncated)
735  {
736  for (fork = 0; fork <= MAX_FORKNUM; fork++)
737  {
738  if (smgrexists(srel, fork))
739  {
740  BlockNumber n = smgrnblocks(srel, fork);
741 
742  /* we shouldn't come here for unlogged relations */
743  Assert(fork != INIT_FORKNUM);
744  nblocks[fork] = n;
745  total_blocks += n;
746  }
747  else
748  nblocks[fork] = InvalidBlockNumber;
749  }
750  }
751 
752  /*
753  * Sync file or emit WAL records for its contents.
754  *
755  * Although we emit WAL record if the file is small enough, do file
756  * sync regardless of the size if the file has experienced a
757  * truncation. It is because the file would be followed by trailing
758  * garbage blocks after a crash recovery if, while a past longer file
759  * had been flushed out, we omitted syncing-out of the file and
760  * emitted WAL instead. You might think that we could choose WAL if
761  * the current main fork is longer than ever, but there's a case where
762  * main fork is longer than ever but FSM fork gets shorter.
763  */
764  if (pendingsync->is_truncated ||
765  total_blocks * BLCKSZ / 1024 >= wal_skip_threshold)
766  {
767  /* allocate the initial array, or extend it, if needed */
768  if (maxrels == 0)
769  {
770  maxrels = 8;
771  srels = palloc(sizeof(SMgrRelation) * maxrels);
772  }
773  else if (maxrels <= nrels)
774  {
775  maxrels *= 2;
776  srels = repalloc(srels, sizeof(SMgrRelation) * maxrels);
777  }
778 
779  srels[nrels++] = srel;
780  }
781  else
782  {
783  /* Emit WAL records for all blocks. The file is small enough. */
784  for (fork = 0; fork <= MAX_FORKNUM; fork++)
785  {
786  int n = nblocks[fork];
787  Relation rel;
788 
789  if (!BlockNumberIsValid(n))
790  continue;
791 
792  /*
793  * Emit WAL for the whole file. Unfortunately we don't know
794  * what kind of a page this is, so we have to log the full
795  * page including any unused space. ReadBufferExtended()
796  * counts some pgstat events; unfortunately, we discard them.
797  */
799  log_newpage_range(rel, fork, 0, n, false);
801  }
802  }
803  }
804 
805  pendingSyncHash = NULL;
806 
807  if (nrels > 0)
808  {
809  smgrdosyncall(srels, nrels);
810  pfree(srels);
811  }
812 }
#define AssertPendingSyncs_RelationCache()
Definition: relcache.h:132
void smgrdosyncall(SMgrRelation *rels, int nrels)
Definition: smgr.c:348
int wal_skip_threshold
Definition: storage.c:38
void log_newpage_range(Relation rel, ForkNumber forkNum, BlockNumber startblk, BlockNumber endblk, bool page_std)
Definition: xloginsert.c:1177
void FreeFakeRelcacheEntry(Relation fakerel)
Definition: xlogutils.c:617
Relation CreateFakeRelcacheEntry(RelFileNode rnode)
Definition: xlogutils.c:574

References Assert(), AssertPendingSyncs_RelationCache, PendingRelDelete::atCommit, BlockNumberIsValid, CreateFakeRelcacheEntry(), FreeFakeRelcacheEntry(), GetCurrentTransactionNestLevel(), HASH_REMOVE, hash_search(), hash_seq_init(), hash_seq_search(), INIT_FORKNUM, InvalidBackendId, InvalidBlockNumber, PendingRelSync::is_truncated, log_newpage_range(), MAX_FORKNUM, PendingRelDelete::next, RelFileNodeBackend::node, palloc(), pendingDeletes, pendingSyncHash, pfree(), PendingRelDelete::relnode, repalloc(), PendingRelSync::rnode, SMgrRelationData::smgr_rnode, smgrdosyncall(), smgrexists(), smgrnblocks(), smgropen(), and wal_skip_threshold.

Referenced by AbortTransaction(), CommitTransaction(), and PrepareTransaction().

◆ smgrGetPendingDeletes()

int smgrGetPendingDeletes ( bool  forCommit,
RelFileNode **  ptr 
)

Definition at line 832 of file storage.c.

833 {
834  int nestLevel = GetCurrentTransactionNestLevel();
835  int nrels;
836  RelFileNode *rptr;
837  PendingRelDelete *pending;
838 
839  nrels = 0;
840  for (pending = pendingDeletes; pending != NULL; pending = pending->next)
841  {
842  if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit
843  && pending->backend == InvalidBackendId)
844  nrels++;
845  }
846  if (nrels == 0)
847  {
848  *ptr = NULL;
849  return 0;
850  }
851  rptr = (RelFileNode *) palloc(nrels * sizeof(RelFileNode));
852  *ptr = rptr;
853  for (pending = pendingDeletes; pending != NULL; pending = pending->next)
854  {
855  if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit
856  && pending->backend == InvalidBackendId)
857  {
858  *rptr = pending->relnode;
859  rptr++;
860  }
861  }
862  return nrels;
863 }

References PendingRelDelete::atCommit, PendingRelDelete::backend, GetCurrentTransactionNestLevel(), InvalidBackendId, PendingRelDelete::nestLevel, PendingRelDelete::next, palloc(), pendingDeletes, and PendingRelDelete::relnode.

Referenced by RecordTransactionAbort(), RecordTransactionCommit(), and StartPrepare().

Variable Documentation

◆ wal_skip_threshold

int wal_skip_threshold
extern

Definition at line 38 of file storage.c.

Referenced by smgrDoPendingSyncs().