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 897 of file storage.c.

References smgrDoPendingDeletes().

Referenced by AbortSubTransaction().

898 {
899  smgrDoPendingDeletes(false);
900 }
void smgrDoPendingDeletes(bool isCommit)
Definition: storage.c:595

◆ AtSubCommit_smgr()

void AtSubCommit_smgr ( void  )

Definition at line 877 of file storage.c.

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

Referenced by CommitSubTransaction().

878 {
879  int nestLevel = GetCurrentTransactionNestLevel();
880  PendingRelDelete *pending;
881 
882  for (pending = pendingDeletes; pending != NULL; pending = pending->next)
883  {
884  if (pending->nestLevel >= nestLevel)
885  pending->nestLevel = nestLevel - 1;
886  }
887 }
struct PendingRelDelete * next
Definition: storage.c:66
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:857
static PendingRelDelete * pendingDeletes
Definition: storage.c:75

◆ EstimatePendingSyncsSpace()

Size EstimatePendingSyncsSpace ( void  )

Definition at line 510 of file storage.c.

References hash_get_num_entries(), and mul_size().

Referenced by InitializeParallelDSM().

511 {
512  long entries;
513 
515  return mul_size(1 + entries, sizeof(RelFileNode));
516 }
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1347
HTAB * pendingSyncHash
Definition: storage.c:76
Size mul_size(Size s1, Size s2)
Definition: shmem.c:515

◆ PostPrepare_smgr()

void PostPrepare_smgr ( void  )

Definition at line 856 of file storage.c.

References PendingRelDelete::next, and pfree().

Referenced by PrepareTransaction().

857 {
858  PendingRelDelete *pending;
860 
861  for (pending = pendingDeletes; pending != NULL; pending = next)
862  {
863  next = pending->next;
865  /* must explicitly free the list entry */
866  pfree(pending);
867  }
868 }
static int32 next
Definition: blutils.c:219
void pfree(void *pointer)
Definition: mcxt.c:1057
struct PendingRelDelete * next
Definition: storage.c:66
static PendingRelDelete * pendingDeletes
Definition: storage.c:75

◆ RelationCopyStorage()

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

Definition at line 408 of file storage.c.

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

Referenced by heapam_relation_copy_data(), and index_copy_data().

410 {
412  Page page;
413  bool use_wal;
414  bool copying_initfork;
415  BlockNumber nblocks;
416  BlockNumber blkno;
417 
418  page = (Page) buf.data;
419 
420  /*
421  * The init fork for an unlogged relation in many respects has to be
422  * treated the same as normal relation, changes need to be WAL logged and
423  * it needs to be synced to disk.
424  */
425  copying_initfork = relpersistence == RELPERSISTENCE_UNLOGGED &&
426  forkNum == INIT_FORKNUM;
427 
428  /*
429  * We need to log the copied data in WAL iff WAL archiving/streaming is
430  * enabled AND it's a permanent relation. This gives the same answer as
431  * "RelationNeedsWAL(rel) || copying_initfork", because we know the
432  * current operation created a new relfilenode.
433  */
434  use_wal = XLogIsNeeded() &&
435  (relpersistence == RELPERSISTENCE_PERMANENT || copying_initfork);
436 
437  nblocks = smgrnblocks(src, forkNum);
438 
439  for (blkno = 0; blkno < nblocks; blkno++)
440  {
441  /* If we got a cancel signal during the copy of the data, quit */
443 
444  smgrread(src, forkNum, blkno, buf.data);
445 
446  if (!PageIsVerified(page, blkno))
447  ereport(ERROR,
449  errmsg("invalid page in block %u of relation %s",
450  blkno,
452  src->smgr_rnode.backend,
453  forkNum))));
454 
455  /*
456  * WAL-log the copied page. Unfortunately we don't know what kind of a
457  * page this is, so we have to log the full page including any unused
458  * space.
459  */
460  if (use_wal)
461  log_newpage(&dst->smgr_rnode.node, forkNum, blkno, page, false);
462 
463  PageSetChecksumInplace(page, blkno);
464 
465  /*
466  * Now write the page. We say skipFsync = true because there's no
467  * need for smgr to schedule an fsync for this write; we'll do it
468  * ourselves below.
469  */
470  smgrextend(dst, forkNum, blkno, buf.data, true);
471  }
472 
473  /*
474  * When we WAL-logged rel pages, we must nonetheless fsync them. The
475  * reason is that since we're copying outside shared buffers, a CHECKPOINT
476  * occurring during the copy has no way to flush the previously written
477  * data to disk (indeed it won't know the new rel even exists). A crash
478  * later on would replay WAL from the checkpoint, therefore it wouldn't
479  * replay our earlier WAL entries. If we do not fsync those pages here,
480  * they might still not be on disk when the crash occurs.
481  */
482  if (use_wal || copying_initfork)
483  smgrimmedsync(dst, forkNum);
484 }
bool PageIsVerified(Page page, BlockNumber blkno)
Definition: bufpage.c:82
#define XLogIsNeeded()
Definition: xlog.h:191
int errcode(int sqlerrcode)
Definition: elog.c:610
uint32 BlockNumber
Definition: block.h:31
void smgrread(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer)
Definition: smgr.c:502
char data[BLCKSZ]
Definition: c.h:1083
#define ERROR
Definition: elog.h:43
RelFileNodeBackend smgr_rnode
Definition: smgr.h:42
static char * buf
Definition: pg_test_fsync.c:68
#define ERRCODE_DATA_CORRUPTED
Definition: pg_basebackup.c:45
#define ereport(elevel,...)
Definition: elog.h:144
RelFileNode node
Definition: relfilenode.h:74
BlockNumber smgrnblocks(SMgrRelation reln, ForkNumber forknum)
Definition: smgr.c:549
BackendId backend
Definition: relfilenode.h:75
void PageSetChecksumInplace(Page page, BlockNumber blkno)
Definition: bufpage.c:1414
void smgrextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer, bool skipFsync)
Definition: smgr.c:463
int errmsg(const char *fmt,...)
Definition: elog.c:821
XLogRecPtr log_newpage(RelFileNode *rnode, ForkNumber forkNum, BlockNumber blkno, Page page, bool page_std)
Definition: xloginsert.c:996
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
#define relpathbackend(rnode, backend, forknum)
Definition: relpath.h:78
void smgrimmedsync(SMgrRelation reln, ForkNumber forknum)
Definition: smgr.c:643
Pointer Page
Definition: bufpage.h:78

◆ RelationCreateStorage()

SMgrRelation RelationCreateStorage ( RelFileNode  rnode,
char  relpersistence 
)

Definition at line 118 of file storage.c.

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

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 }
BackendId backend
Definition: storage.c:63
void smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
Definition: smgr.c:334
#define XLogIsNeeded()
Definition: xlog.h:191
static void AddPendingSync(const RelFileNode *rnode)
Definition: storage.c:84
bool IsInParallelMode(void)
Definition: xact.c:1012
#define ERROR
Definition: elog.h:43
RelFileNodeBackend smgr_rnode
Definition: smgr.h:42
#define BackendIdForTempRelations()
Definition: backendid.h:34
MemoryContext TopMemoryContext
Definition: mcxt.c:44
SMgrRelation smgropen(RelFileNode rnode, BackendId backend)
Definition: smgr.c:146
struct PendingRelDelete * next
Definition: storage.c:66
#define InvalidBackendId
Definition: backendid.h:23
int BackendId
Definition: backendid.h:21
RelFileNode node
Definition: relfilenode.h:74
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:857
#define Assert(condition)
Definition: c.h:746
static PendingRelDelete * pendingDeletes
Definition: storage.c:75
RelFileNode relnode
Definition: storage.c:62
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:797
#define elog(elevel,...)
Definition: elog.h:214
void log_smgrcreate(const RelFileNode *rnode, ForkNumber forkNum)
Definition: storage.c:175

◆ RelationDropStorage()

void RelationDropStorage ( Relation  rel)

Definition at line 195 of file storage.c.

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(), and RelationSetNewRelfilenode().

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 }
BackendId backend
Definition: storage.c:63
#define RelationCloseSmgr(relation)
Definition: rel.h:525
MemoryContext TopMemoryContext
Definition: mcxt.c:44
struct PendingRelDelete * next
Definition: storage.c:66
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:857
RelFileNode rd_node
Definition: rel.h:55
BackendId rd_backend
Definition: rel.h:59
static PendingRelDelete * pendingDeletes
Definition: storage.c:75
RelFileNode relnode
Definition: storage.c:62
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:797

◆ RelationPreserveStorage()

void RelationPreserveStorage ( RelFileNode  rnode,
bool  atCommit 
)

Definition at line 240 of file storage.c.

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

Referenced by ATExecAddIndex(), and write_relmap_file().

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 }
static int32 next
Definition: blutils.c:219
void pfree(void *pointer)
Definition: mcxt.c:1057
struct PendingRelDelete * next
Definition: storage.c:66
static PendingRelDelete * pendingDeletes
Definition: storage.c:75
RelFileNode relnode
Definition: storage.c:62
#define RelFileNodeEquals(node1, node2)
Definition: relfilenode.h:88

◆ RelationPreTruncate()

void RelationPreTruncate ( Relation  rel)

Definition at line 386 of file storage.c.

References HASH_FIND, hash_search(), PendingRelSync::is_truncated, RelFileNodeBackend::node, RelationData::rd_smgr, RelationOpenSmgr, and SMgrRelationData::smgr_rnode.

Referenced by RelationTruncate().

387 {
388  PendingRelSync *pending;
389 
390  if (!pendingSyncHash)
391  return;
392  RelationOpenSmgr(rel);
393 
394  pending = hash_search(pendingSyncHash, &(rel->rd_smgr->smgr_rnode.node),
395  HASH_FIND, NULL);
396  if (pending)
397  pending->is_truncated = true;
398 }
struct SMgrRelationData * rd_smgr
Definition: rel.h:57
bool is_truncated
Definition: storage.c:72
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:919
#define RelationOpenSmgr(relation)
Definition: rel.h:513
HTAB * pendingSyncHash
Definition: storage.c:76
RelFileNodeBackend smgr_rnode
Definition: smgr.h:42
RelFileNode node
Definition: relfilenode.h:74

◆ RelationTruncate()

void RelationTruncate ( Relation  rel,
BlockNumber  nblocks 
)

Definition at line 277 of file storage.c.

References xl_smgr_truncate::blkno, BlockNumberIsValid, blocks, xl_smgr_truncate::flags, FreeSpaceMapPrepareTruncateRel(), FreeSpaceMapVacuumRange(), FSM_FORKNUM, i, InvalidBlockNumber, MAIN_FORKNUM, MAX_FORKNUM, RelationData::rd_node, RelationData::rd_smgr, RelationNeedsWAL, RelationOpenSmgr, 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().

278 {
279  bool fsm;
280  bool vm;
281  bool need_fsm_vacuum = false;
282  ForkNumber forks[MAX_FORKNUM];
284  int nforks = 0;
285 
286  /* Open it at the smgr level if not already done */
287  RelationOpenSmgr(rel);
288 
289  /*
290  * Make sure smgr_targblock etc aren't pointing somewhere past new end
291  */
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 */
302  fsm = smgrexists(rel->rd_smgr, FSM_FORKNUM);
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(rel->rd_smgr, 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 XLR_SPECIAL_REL_UPDATE
Definition: xlogrecord.h:71
void RelationPreTruncate(Relation rel)
Definition: storage.c:386
struct SMgrRelationData * rd_smgr
Definition: rel.h:57
uint32 BlockNumber
Definition: block.h:31
RelFileNode rnode
Definition: storage_xlog.h:49
bool smgrexists(SMgrRelation reln, ForkNumber forknum)
Definition: smgr.c:248
void XLogFlush(XLogRecPtr record)
Definition: xlog.c:2847
BlockNumber smgr_cached_nblocks[MAX_FORKNUM+1]
Definition: smgr.h:54
#define RelationOpenSmgr(relation)
Definition: rel.h:513
BlockNumber FreeSpaceMapPrepareTruncateRel(Relation rel, BlockNumber nblocks)
Definition: freespace.c:261
ForkNumber
Definition: relpath.h:40
#define XLOG_SMGR_TRUNCATE
Definition: storage_xlog.h:31
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:330
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:422
void smgrtruncate(SMgrRelation reln, ForkNumber *forknum, int nforks, BlockNumber *nblocks)
Definition: smgr.c:578
#define BlockNumberIsValid(blockNumber)
Definition: block.h:70
RelFileNode rd_node
Definition: rel.h:55
uint64 XLogRecPtr
Definition: xlogdefs.h:21
BlockNumber smgr_targblock
Definition: smgr.h:53
#define InvalidBlockNumber
Definition: block.h:33
#define MAX_FORKNUM
Definition: relpath.h:55
#define RelationNeedsWAL(relation)
Definition: rel.h:562
static int64 blocks
Definition: pg_checksums.c:35
int i
BlockNumber visibilitymap_prepare_truncate(Relation rel, BlockNumber nheapblocks)
BlockNumber blkno
Definition: storage_xlog.h:48
#define SMGR_TRUNCATE_ALL
Definition: storage_xlog.h:43
void XLogBeginInsert(void)
Definition: xloginsert.c:123
void FreeSpaceMapVacuumRange(Relation rel, BlockNumber start, BlockNumber end)
Definition: freespace.c:354

◆ RelFileNodeSkippingWAL()

bool RelFileNodeSkippingWAL ( RelFileNode  rnode)

Definition at line 496 of file storage.c.

References HASH_FIND, and hash_search().

Referenced by MarkBufferDirtyHint(), RelationInitPhysicalAddr(), and RememberToFreeTupleDescAtEOX().

497 {
498  if (!pendingSyncHash ||
499  hash_search(pendingSyncHash, &rnode, HASH_FIND, NULL) == NULL)
500  return false;
501 
502  return true;
503 }
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:919
HTAB * pendingSyncHash
Definition: storage.c:76

◆ RestorePendingSyncs()

void RestorePendingSyncs ( char *  startAddress)

Definition at line 574 of file storage.c.

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

Referenced by ParallelWorkerMain().

575 {
576  RelFileNode *rnode;
577 
578  Assert(pendingSyncHash == NULL);
579  for (rnode = (RelFileNode *) startAddress; rnode->relNode != 0; rnode++)
580  AddPendingSync(rnode);
581 }
static void AddPendingSync(const RelFileNode *rnode)
Definition: storage.c:84
HTAB * pendingSyncHash
Definition: storage.c:76
#define Assert(condition)
Definition: c.h:746

◆ SerializePendingSyncs()

void SerializePendingSyncs ( Size  maxSize,
char *  startAddress 
)

Definition at line 523 of file storage.c.

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, and PendingRelSync::rnode.

Referenced by InitializeParallelDSM().

524 {
525  HTAB *tmphash;
526  HASHCTL ctl;
527  HASH_SEQ_STATUS scan;
528  PendingRelSync *sync;
529  PendingRelDelete *delete;
530  RelFileNode *src;
531  RelFileNode *dest = (RelFileNode *) startAddress;
532 
533  if (!pendingSyncHash)
534  goto terminate;
535 
536  /* Create temporary hash to collect active relfilenodes */
537  ctl.keysize = sizeof(RelFileNode);
538  ctl.entrysize = sizeof(RelFileNode);
540  tmphash = hash_create("tmp relfilenodes",
543 
544  /* collect all rnodes from pending syncs */
546  while ((sync = (PendingRelSync *) hash_seq_search(&scan)))
547  (void) hash_search(tmphash, &sync->rnode, HASH_ENTER, NULL);
548 
549  /* remove deleted rnodes */
550  for (delete = pendingDeletes; delete != NULL; delete = delete->next)
551  if (delete->atCommit)
552  (void) hash_search(tmphash, (void *) &delete->relnode,
553  HASH_REMOVE, NULL);
554 
555  hash_seq_init(&scan, tmphash);
556  while ((src = (RelFileNode *) hash_seq_search(&scan)))
557  *dest++ = *src;
558 
559  hash_destroy(tmphash);
560 
561 terminate:
562  MemSet(dest, 0, sizeof(RelFileNode));
563 }
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:827
#define HASH_CONTEXT
Definition: hsearch.h:91
#define HASH_ELEM
Definition: hsearch.h:85
MemoryContext hcxt
Definition: hsearch.h:77
Size entrysize
Definition: hsearch.h:72
RelFileNode rnode
Definition: storage.c:71
#define MemSet(start, val, len)
Definition: c.h:950
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1347
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:919
Definition: dynahash.c:218
HTAB * pendingSyncHash
Definition: storage.c:76
struct RelFileNode RelFileNode
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
struct PendingRelDelete * next
Definition: storage.c:66
#define HASH_BLOBS
Definition: hsearch.h:86
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:326
Size keysize
Definition: hsearch.h:71
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1401
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1391
static PendingRelDelete * pendingDeletes
Definition: storage.c:75

◆ smgrDoPendingDeletes()

void smgrDoPendingDeletes ( bool  isCommit)

Definition at line 595 of file storage.c.

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

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

596 {
597  int nestLevel = GetCurrentTransactionNestLevel();
598  PendingRelDelete *pending;
599  PendingRelDelete *prev;
601  int nrels = 0,
602  maxrels = 0;
603  SMgrRelation *srels = NULL;
604 
605  prev = NULL;
606  for (pending = pendingDeletes; pending != NULL; pending = next)
607  {
608  next = pending->next;
609  if (pending->nestLevel < nestLevel)
610  {
611  /* outer-level entries should not be processed yet */
612  prev = pending;
613  }
614  else
615  {
616  /* unlink list entry first, so we don't retry on failure */
617  if (prev)
618  prev->next = next;
619  else
621  /* do deletion if called for */
622  if (pending->atCommit == isCommit)
623  {
624  SMgrRelation srel;
625 
626  srel = smgropen(pending->relnode, pending->backend);
627 
628  /* allocate the initial array, or extend it, if needed */
629  if (maxrels == 0)
630  {
631  maxrels = 8;
632  srels = palloc(sizeof(SMgrRelation) * maxrels);
633  }
634  else if (maxrels <= nrels)
635  {
636  maxrels *= 2;
637  srels = repalloc(srels, sizeof(SMgrRelation) * maxrels);
638  }
639 
640  srels[nrels++] = srel;
641  }
642  /* must explicitly free the list entry */
643  pfree(pending);
644  /* prev does not change */
645  }
646  }
647 
648  if (nrels > 0)
649  {
650  smgrdounlinkall(srels, nrels, false);
651 
652  for (int i = 0; i < nrels; i++)
653  smgrclose(srels[i]);
654 
655  pfree(srels);
656  }
657 }
BackendId backend
Definition: storage.c:63
void smgrclose(SMgrRelation reln)
Definition: smgr.c:257
static int32 next
Definition: blutils.c:219
void smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo)
Definition: smgr.c:385
void pfree(void *pointer)
Definition: mcxt.c:1057
SMgrRelation smgropen(RelFileNode rnode, BackendId backend)
Definition: smgr.c:146
struct PendingRelDelete * next
Definition: storage.c:66
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:857
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1070
static PendingRelDelete * pendingDeletes
Definition: storage.c:75
void * palloc(Size size)
Definition: mcxt.c:950
RelFileNode relnode
Definition: storage.c:62
int i

◆ smgrDoPendingSyncs()

void smgrDoPendingSyncs ( bool  isCommit,
bool  isParallelWorker 
)

Definition at line 663 of file storage.c.

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(), pfree(), PendingRelDelete::relnode, repalloc(), PendingRelSync::rnode, SMgrRelationData::smgr_rnode, smgrdosyncall(), smgrexists(), smgrnblocks(), smgropen(), and wal_skip_threshold.

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

664 {
665  PendingRelDelete *pending;
666  int nrels = 0,
667  maxrels = 0;
668  SMgrRelation *srels = NULL;
669  HASH_SEQ_STATUS scan;
670  PendingRelSync *pendingsync;
671 
673 
674  if (!pendingSyncHash)
675  return; /* no relation needs sync */
676 
677  /* Abort -- just throw away all pending syncs */
678  if (!isCommit)
679  {
680  pendingSyncHash = NULL;
681  return;
682  }
683 
685 
686  /* Parallel worker -- just throw away all pending syncs */
687  if (isParallelWorker)
688  {
689  pendingSyncHash = NULL;
690  return;
691  }
692 
693  /* Skip syncing nodes that smgrDoPendingDeletes() will delete. */
694  for (pending = pendingDeletes; pending != NULL; pending = pending->next)
695  if (pending->atCommit)
696  (void) hash_search(pendingSyncHash, (void *) &pending->relnode,
697  HASH_REMOVE, NULL);
698 
700  while ((pendingsync = (PendingRelSync *) hash_seq_search(&scan)))
701  {
702  ForkNumber fork;
703  BlockNumber nblocks[MAX_FORKNUM + 1];
704  BlockNumber total_blocks = 0;
705  SMgrRelation srel;
706 
707  srel = smgropen(pendingsync->rnode, InvalidBackendId);
708 
709  /*
710  * We emit newpage WAL records for smaller relations.
711  *
712  * Small WAL records have a chance to be emitted along with other
713  * backends' WAL records. We emit WAL records instead of syncing for
714  * files that are smaller than a certain threshold, expecting faster
715  * commit. The threshold is defined by the GUC wal_skip_threshold.
716  */
717  if (!pendingsync->is_truncated)
718  {
719  for (fork = 0; fork <= MAX_FORKNUM; fork++)
720  {
721  if (smgrexists(srel, fork))
722  {
723  BlockNumber n = smgrnblocks(srel, fork);
724 
725  /* we shouldn't come here for unlogged relations */
726  Assert(fork != INIT_FORKNUM);
727  nblocks[fork] = n;
728  total_blocks += n;
729  }
730  else
731  nblocks[fork] = InvalidBlockNumber;
732  }
733  }
734 
735  /*
736  * Sync file or emit WAL records for its contents.
737  *
738  * Although we emit WAL record if the file is small enough, do file
739  * sync regardless of the size if the file has experienced a
740  * truncation. It is because the file would be followed by trailing
741  * garbage blocks after a crash recovery if, while a past longer file
742  * had been flushed out, we omitted syncing-out of the file and
743  * emitted WAL instead. You might think that we could choose WAL if
744  * the current main fork is longer than ever, but there's a case where
745  * main fork is longer than ever but FSM fork gets shorter.
746  */
747  if (pendingsync->is_truncated ||
748  total_blocks * BLCKSZ / 1024 >= wal_skip_threshold)
749  {
750  /* allocate the initial array, or extend it, if needed */
751  if (maxrels == 0)
752  {
753  maxrels = 8;
754  srels = palloc(sizeof(SMgrRelation) * maxrels);
755  }
756  else if (maxrels <= nrels)
757  {
758  maxrels *= 2;
759  srels = repalloc(srels, sizeof(SMgrRelation) * maxrels);
760  }
761 
762  srels[nrels++] = srel;
763  }
764  else
765  {
766  /* Emit WAL records for all blocks. The file is small enough. */
767  for (fork = 0; fork <= MAX_FORKNUM; fork++)
768  {
769  int n = nblocks[fork];
770  Relation rel;
771 
772  if (!BlockNumberIsValid(n))
773  continue;
774 
775  /*
776  * Emit WAL for the whole file. Unfortunately we don't know
777  * what kind of a page this is, so we have to log the full
778  * page including any unused space. ReadBufferExtended()
779  * counts some pgstat events; unfortunately, we discard them.
780  */
782  log_newpage_range(rel, fork, 0, n, false);
784  }
785  }
786  }
787 
788  pendingSyncHash = NULL;
789 
790  if (nrels > 0)
791  {
792  smgrdosyncall(srels, nrels);
793  pfree(srels);
794  }
795 }
bool is_truncated
Definition: storage.c:72
RelFileNode rnode
Definition: storage.c:71
uint32 BlockNumber
Definition: block.h:31
bool smgrexists(SMgrRelation reln, ForkNumber forknum)
Definition: smgr.c:248
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:919
void pfree(void *pointer)
Definition: mcxt.c:1057
HTAB * pendingSyncHash
Definition: storage.c:76
#define AssertPendingSyncs_RelationCache()
Definition: relcache.h:131
RelFileNodeBackend smgr_rnode
Definition: smgr.h:42
Relation CreateFakeRelcacheEntry(RelFileNode rnode)
Definition: xlogutils.c:556
SMgrRelation smgropen(RelFileNode rnode, BackendId backend)
Definition: smgr.c:146
ForkNumber
Definition: relpath.h:40
void FreeFakeRelcacheEntry(Relation fakerel)
Definition: xlogutils.c:599
struct PendingRelDelete * next
Definition: storage.c:66
#define InvalidBackendId
Definition: backendid.h:23
#define BlockNumberIsValid(blockNumber)
Definition: block.h:70
RelFileNode node
Definition: relfilenode.h:74
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:857
BlockNumber smgrnblocks(SMgrRelation reln, ForkNumber forknum)
Definition: smgr.c:549
#define Assert(condition)
Definition: c.h:746
int wal_skip_threshold
Definition: storage.c:38
#define InvalidBlockNumber
Definition: block.h:33
#define MAX_FORKNUM
Definition: relpath.h:55
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1401
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1070
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1391
void log_newpage_range(Relation rel, ForkNumber forkNum, BlockNumber startblk, BlockNumber endblk, bool page_std)
Definition: xloginsert.c:1123
static PendingRelDelete * pendingDeletes
Definition: storage.c:75
void * palloc(Size size)
Definition: mcxt.c:950
RelFileNode relnode
Definition: storage.c:62
void smgrdosyncall(SMgrRelation *rels, int nrels)
Definition: smgr.c:349

◆ smgrGetPendingDeletes()

int smgrGetPendingDeletes ( bool  forCommit,
RelFileNode **  ptr 
)

Definition at line 815 of file storage.c.

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

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

816 {
817  int nestLevel = GetCurrentTransactionNestLevel();
818  int nrels;
819  RelFileNode *rptr;
820  PendingRelDelete *pending;
821 
822  nrels = 0;
823  for (pending = pendingDeletes; pending != NULL; pending = pending->next)
824  {
825  if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit
826  && pending->backend == InvalidBackendId)
827  nrels++;
828  }
829  if (nrels == 0)
830  {
831  *ptr = NULL;
832  return 0;
833  }
834  rptr = (RelFileNode *) palloc(nrels * sizeof(RelFileNode));
835  *ptr = rptr;
836  for (pending = pendingDeletes; pending != NULL; pending = pending->next)
837  {
838  if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit
839  && pending->backend == InvalidBackendId)
840  {
841  *rptr = pending->relnode;
842  rptr++;
843  }
844  }
845  return nrels;
846 }
BackendId backend
Definition: storage.c:63
struct PendingRelDelete * next
Definition: storage.c:66
#define InvalidBackendId
Definition: backendid.h:23
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:857
static PendingRelDelete * pendingDeletes
Definition: storage.c:75
void * palloc(Size size)
Definition: mcxt.c:950
RelFileNode relnode
Definition: storage.c:62

Variable Documentation

◆ wal_skip_threshold

int wal_skip_threshold

Definition at line 38 of file storage.c.

Referenced by smgrDoPendingSyncs().