PostgreSQL Source Code  git master
storage.c File Reference
#include "postgres.h"
#include "access/parallel.h"
#include "access/visibilitymap.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "access/xloginsert.h"
#include "access/xlogutils.h"
#include "catalog/storage.h"
#include "catalog/storage_xlog.h"
#include "miscadmin.h"
#include "storage/freespace.h"
#include "storage/smgr.h"
#include "utils/hsearch.h"
#include "utils/memutils.h"
#include "utils/rel.h"
Include dependency graph for storage.c:

Go to the source code of this file.

Data Structures

struct  PendingRelDelete
 
struct  PendingRelSync
 

Typedefs

typedef struct PendingRelDelete PendingRelDelete
 
typedef struct PendingRelSync PendingRelSync
 

Functions

static void AddPendingSync (const RelFileNode *rnode)
 
SMgrRelation RelationCreateStorage (RelFileNode rnode, char relpersistence)
 
void log_smgrcreate (const RelFileNode *rnode, ForkNumber forkNum)
 
void RelationDropStorage (Relation rel)
 
void RelationPreserveStorage (RelFileNode rnode, bool atCommit)
 
void RelationTruncate (Relation rel, BlockNumber nblocks)
 
void RelationPreTruncate (Relation rel)
 
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 PostPrepare_smgr (void)
 
void AtSubCommit_smgr (void)
 
void AtSubAbort_smgr (void)
 
void smgr_redo (XLogReaderState *record)
 

Variables

int wal_skip_threshold = 2048
 
static PendingRelDeletependingDeletes = NULL
 
HTABpendingSyncHash = NULL
 

Typedef Documentation

◆ PendingRelDelete

◆ PendingRelSync

Function Documentation

◆ AddPendingSync()

static void AddPendingSync ( const RelFileNode rnode)
static

Definition at line 84 of file storage.c.

References Assert, HASHCTL::entrysize, HASH_BLOBS, HASH_CONTEXT, hash_create(), HASH_ELEM, HASH_ENTER, hash_search(), HASHCTL::hcxt, PendingRelSync::is_truncated, HASHCTL::keysize, and TopTransactionContext.

Referenced by RelationCreateStorage(), and RestorePendingSyncs().

85 {
86  PendingRelSync *pending;
87  bool found;
88 
89  /* create the hash if not yet */
90  if (!pendingSyncHash)
91  {
92  HASHCTL ctl;
93 
94  ctl.keysize = sizeof(RelFileNode);
95  ctl.entrysize = sizeof(PendingRelSync);
97  pendingSyncHash = hash_create("pending sync hash", 16, &ctl,
99  }
100 
101  pending = hash_search(pendingSyncHash, rnode, HASH_ENTER, &found);
102  Assert(!found);
103  pending->is_truncated = false;
104 }
MemoryContext TopTransactionContext
Definition: mcxt.c:53
#define HASH_CONTEXT
Definition: hsearch.h:102
#define HASH_ELEM
Definition: hsearch.h:95
MemoryContext hcxt
Definition: hsearch.h:86
struct PendingRelSync PendingRelSync
bool is_truncated
Definition: storage.c:72
Size entrysize
Definition: hsearch.h:76
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
HTAB * pendingSyncHash
Definition: storage.c:76
struct RelFileNode RelFileNode
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:349
#define HASH_BLOBS
Definition: hsearch.h:97
Size keysize
Definition: hsearch.h:75
#define Assert(condition)
Definition: c.h:804

◆ AtSubAbort_smgr()

void AtSubAbort_smgr ( void  )

Definition at line 914 of file storage.c.

References smgrDoPendingDeletes().

Referenced by AbortSubTransaction().

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

◆ AtSubCommit_smgr()

void AtSubCommit_smgr ( void  )

Definition at line 894 of file storage.c.

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

Referenced by CommitSubTransaction().

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

References hash_get_num_entries(), and mul_size().

Referenced by InitializeParallelDSM().

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
HTAB * pendingSyncHash
Definition: storage.c:76
Size mul_size(Size s1, Size s2)
Definition: shmem.c:519

◆ log_smgrcreate()

void log_smgrcreate ( const RelFileNode rnode,
ForkNumber  forkNum 
)

Definition at line 175 of file storage.c.

References xl_smgr_create::forkNum, xl_smgr_create::rnode, XLOG_SMGR_CREATE, XLogBeginInsert(), XLogInsert(), XLogRegisterData(), and XLR_SPECIAL_REL_UPDATE.

Referenced by heapam_relation_copy_data(), heapam_relation_set_new_filenode(), index_copy_data(), and RelationCreateStorage().

176 {
177  xl_smgr_create xlrec;
178 
179  /*
180  * Make an XLOG entry reporting the file creation.
181  */
182  xlrec.rnode = *rnode;
183  xlrec.forkNum = forkNum;
184 
185  XLogBeginInsert();
186  XLogRegisterData((char *) &xlrec, sizeof(xlrec));
188 }
#define XLR_SPECIAL_REL_UPDATE
Definition: xlogrecord.h:71
#define XLOG_SMGR_CREATE
Definition: storage_xlog.h:30
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:340
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:432
ForkNumber forkNum
Definition: storage_xlog.h:36
void XLogBeginInsert(void)
Definition: xloginsert.c:135
RelFileNode rnode
Definition: storage_xlog.h:35

◆ PostPrepare_smgr()

void PostPrepare_smgr ( void  )

Definition at line 873 of file storage.c.

References PendingRelDelete::next, and pfree().

Referenced by PrepareTransaction().

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

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 }
#define XLogIsNeeded()
Definition: xlog.h:166
int errcode(int sqlerrcode)
Definition: elog.c:698
uint32 BlockNumber
Definition: block.h:31
void smgrread(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer)
Definition: smgr.c:501
char data[BLCKSZ]
Definition: c.h:1141
#define ERROR
Definition: elog.h:46
#define PIV_LOG_WARNING
Definition: bufpage.h:413
RelFileNodeBackend smgr_rnode
Definition: smgr.h:42
static char * buf
Definition: pg_test_fsync.c:68
#define PIV_REPORT_STAT
Definition: bufpage.h:414
bool PageIsVerifiedExtended(Page page, BlockNumber blkno, int flags)
Definition: bufpage.c:88
#define ERRCODE_DATA_CORRUPTED
Definition: pg_basebackup.c:47
#define ereport(elevel,...)
Definition: elog.h:157
RelFileNode node
Definition: relfilenode.h:74
BlockNumber smgrnblocks(SMgrRelation reln, ForkNumber forknum)
Definition: smgr.c:548
BackendId backend
Definition: relfilenode.h:75
void PageSetChecksumInplace(Page page, BlockNumber blkno)
Definition: bufpage.c:1532
void smgrextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer, bool skipFsync)
Definition: smgr.c:462
int errmsg(const char *fmt,...)
Definition: elog.c:909
XLogRecPtr log_newpage(RelFileNode *rnode, ForkNumber forkNum, BlockNumber blkno, Page page, bool page_std)
Definition: xloginsert.c:1048
#define relpath(rnode, forknum)
Definition: relpath.h:87
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:120
#define relpathbackend(rnode, backend, forknum)
Definition: relpath.h:78
void smgrimmedsync(SMgrRelation reln, ForkNumber forknum)
Definition: smgr.c:660
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:333
#define XLogIsNeeded()
Definition: xlog.h:166
static void AddPendingSync(const RelFileNode *rnode)
Definition: storage.c:84
bool IsInParallelMode(void)
Definition: xact.c:1012
#define ERROR
Definition: elog.h:46
RelFileNodeBackend smgr_rnode
Definition: smgr.h:42
#define BackendIdForTempRelations()
Definition: backendid.h:34
MemoryContext TopMemoryContext
Definition: mcxt.c:48
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:804
static PendingRelDelete * pendingDeletes
Definition: storage.c:75
RelFileNode relnode
Definition: storage.c:62
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:863
#define elog(elevel,...)
Definition: elog.h:232
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(), reindex_index(), 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:557
MemoryContext TopMemoryContext
Definition: mcxt.c:48
struct PendingRelDelete * next
Definition: storage.c:66
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:857
RelFileNode rd_node
Definition: rel.h:56
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:863

◆ 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:1169
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, SMgrRelationData::node, and RelationGetSmgr().

Referenced by RelationTruncate().

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 }
bool is_truncated
Definition: storage.c:72
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
HTAB * pendingSyncHash
Definition: storage.c:76
static SMgrRelation RelationGetSmgr(Relation rel)
Definition: rel.h:544
dlist_node node
Definition: smgr.h:72

◆ RelationTruncate()

void RelationTruncate ( Relation  rel,
BlockNumber  nblocks 
)

Definition at line 277 of file storage.c.

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

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 XLR_SPECIAL_REL_UPDATE
Definition: xlogrecord.h:71
void RelationPreTruncate(Relation rel)
Definition: storage.c:386
uint32 BlockNumber
Definition: block.h:31
RelFileNode rnode
Definition: storage_xlog.h:49
bool smgrexists(SMgrRelation reln, ForkNumber forknum)
Definition: smgr.c:247
void XLogFlush(XLogRecPtr record)
Definition: xlog.c:2860
BlockNumber smgr_cached_nblocks[MAX_FORKNUM+1]
Definition: smgr.h:54
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:340
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:432
void smgrtruncate(SMgrRelation reln, ForkNumber *forknum, int nforks, BlockNumber *nblocks)
Definition: smgr.c:595
#define BlockNumberIsValid(blockNumber)
Definition: block.h:70
RelFileNode rd_node
Definition: rel.h:56
uint64 XLogRecPtr
Definition: xlogdefs.h:21
BlockNumber smgr_targblock
Definition: smgr.h:53
static SMgrRelation RelationGetSmgr(Relation rel)
Definition: rel.h:544
#define InvalidBlockNumber
Definition: block.h:33
#define MAX_FORKNUM
Definition: relpath.h:55
#define RelationNeedsWAL(relation)
Definition: rel.h:601
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:135
void FreeSpaceMapVacuumRange(Relation rel, BlockNumber start, BlockNumber end)
Definition: freespace.c:352

◆ RelFileNodeSkippingWAL()

bool RelFileNodeSkippingWAL ( RelFileNode  rnode)

Definition at line 513 of file storage.c.

References HASH_FIND, and hash_search().

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

514 {
515  if (!pendingSyncHash ||
516  hash_search(pendingSyncHash, &rnode, HASH_FIND, NULL) == NULL)
517  return false;
518 
519  return true;
520 }
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
HTAB * pendingSyncHash
Definition: storage.c:76

◆ RestorePendingSyncs()

void RestorePendingSyncs ( char *  startAddress)

Definition at line 591 of file storage.c.

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

Referenced by ParallelWorkerMain().

592 {
593  RelFileNode *rnode;
594 
595  Assert(pendingSyncHash == NULL);
596  for (rnode = (RelFileNode *) startAddress; rnode->relNode != 0; rnode++)
597  AddPendingSync(rnode);
598 }
static void AddPendingSync(const RelFileNode *rnode)
Definition: storage.c:84
HTAB * pendingSyncHash
Definition: storage.c:76
#define Assert(condition)
Definition: c.h:804

◆ SerializePendingSyncs()

void SerializePendingSyncs ( Size  maxSize,
char *  startAddress 
)

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

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 }
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:862
#define HASH_CONTEXT
Definition: hsearch.h:102
#define HASH_ELEM
Definition: hsearch.h:95
MemoryContext hcxt
Definition: hsearch.h:86
Size entrysize
Definition: hsearch.h:76
RelFileNode rnode
Definition: storage.c:71
#define MemSet(start, val, len)
Definition: c.h:1008
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1382
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
Definition: dynahash.c:219
HTAB * pendingSyncHash
Definition: storage.c:76
struct RelFileNode RelFileNode
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:349
MemoryContext CurrentMemoryContext
Definition: mcxt.c:42
struct PendingRelDelete * next
Definition: storage.c:66
#define HASH_BLOBS
Definition: hsearch.h:97
Size keysize
Definition: hsearch.h:75
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
static PendingRelDelete * pendingDeletes
Definition: storage.c:75

◆ smgr_redo()

void smgr_redo ( XLogReaderState record)

Definition at line 920 of file storage.c.

References Assert, xl_smgr_truncate::blkno, BlockNumberIsValid, CreateFakeRelcacheEntry(), elog, XLogReaderState::EndRecPtr, xl_smgr_truncate::flags, xl_smgr_create::forkNum, FreeFakeRelcacheEntry(), FreeSpaceMapPrepareTruncateRel(), FreeSpaceMapVacuumRange(), FSM_FORKNUM, InvalidBackendId, InvalidBlockNumber, MAIN_FORKNUM, MAX_FORKNUM, PANIC, xl_smgr_create::rnode, xl_smgr_truncate::rnode, SMGR_TRUNCATE_FSM, SMGR_TRUNCATE_HEAP, SMGR_TRUNCATE_VM, smgrcreate(), smgrexists(), smgropen(), smgrtruncate(), VISIBILITYMAP_FORKNUM, visibilitymap_prepare_truncate(), XLOG_SMGR_CREATE, XLOG_SMGR_TRUNCATE, XLogFlush(), XLogRecGetData, XLogRecGetInfo, XLogRecHasAnyBlockRefs, XLogTruncateRelation(), and XLR_INFO_MASK.

921 {
922  XLogRecPtr lsn = record->EndRecPtr;
923  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
924 
925  /* Backup blocks are not used in smgr records */
926  Assert(!XLogRecHasAnyBlockRefs(record));
927 
928  if (info == XLOG_SMGR_CREATE)
929  {
930  xl_smgr_create *xlrec = (xl_smgr_create *) XLogRecGetData(record);
931  SMgrRelation reln;
932 
933  reln = smgropen(xlrec->rnode, InvalidBackendId);
934  smgrcreate(reln, xlrec->forkNum, true);
935  }
936  else if (info == XLOG_SMGR_TRUNCATE)
937  {
938  xl_smgr_truncate *xlrec = (xl_smgr_truncate *) XLogRecGetData(record);
939  SMgrRelation reln;
940  Relation rel;
941  ForkNumber forks[MAX_FORKNUM];
942  BlockNumber blocks[MAX_FORKNUM];
943  int nforks = 0;
944  bool need_fsm_vacuum = false;
945 
946  reln = smgropen(xlrec->rnode, InvalidBackendId);
947 
948  /*
949  * Forcibly create relation if it doesn't exist (which suggests that
950  * it was dropped somewhere later in the WAL sequence). As in
951  * XLogReadBufferForRedo, we prefer to recreate the rel and replay the
952  * log as best we can until the drop is seen.
953  */
954  smgrcreate(reln, MAIN_FORKNUM, true);
955 
956  /*
957  * Before we perform the truncation, update minimum recovery point to
958  * cover this WAL record. Once the relation is truncated, there's no
959  * going back. The buffer manager enforces the WAL-first rule for
960  * normal updates to relation files, so that the minimum recovery
961  * point is always updated before the corresponding change in the data
962  * file is flushed to disk. We have to do the same manually here.
963  *
964  * Doing this before the truncation means that if the truncation fails
965  * for some reason, you cannot start up the system even after restart,
966  * until you fix the underlying situation so that the truncation will
967  * succeed. Alternatively, we could update the minimum recovery point
968  * after truncation, but that would leave a small window where the
969  * WAL-first rule could be violated.
970  */
971  XLogFlush(lsn);
972 
973  /* Prepare for truncation of MAIN fork */
974  if ((xlrec->flags & SMGR_TRUNCATE_HEAP) != 0)
975  {
976  forks[nforks] = MAIN_FORKNUM;
977  blocks[nforks] = xlrec->blkno;
978  nforks++;
979 
980  /* Also tell xlogutils.c about it */
981  XLogTruncateRelation(xlrec->rnode, MAIN_FORKNUM, xlrec->blkno);
982  }
983 
984  /* Prepare for truncation of FSM and VM too */
985  rel = CreateFakeRelcacheEntry(xlrec->rnode);
986 
987  if ((xlrec->flags & SMGR_TRUNCATE_FSM) != 0 &&
988  smgrexists(reln, FSM_FORKNUM))
989  {
990  blocks[nforks] = FreeSpaceMapPrepareTruncateRel(rel, xlrec->blkno);
991  if (BlockNumberIsValid(blocks[nforks]))
992  {
993  forks[nforks] = FSM_FORKNUM;
994  nforks++;
995  need_fsm_vacuum = true;
996  }
997  }
998  if ((xlrec->flags & SMGR_TRUNCATE_VM) != 0 &&
1000  {
1001  blocks[nforks] = visibilitymap_prepare_truncate(rel, xlrec->blkno);
1002  if (BlockNumberIsValid(blocks[nforks]))
1003  {
1004  forks[nforks] = VISIBILITYMAP_FORKNUM;
1005  nforks++;
1006  }
1007  }
1008 
1009  /* Do the real work to truncate relation forks */
1010  if (nforks > 0)
1011  smgrtruncate(reln, forks, nforks, blocks);
1012 
1013  /*
1014  * Update upper-level FSM pages to account for the truncation. This is
1015  * important because the just-truncated pages were likely marked as
1016  * all-free, and would be preferentially selected.
1017  */
1018  if (need_fsm_vacuum)
1019  FreeSpaceMapVacuumRange(rel, xlrec->blkno,
1021 
1022  FreeFakeRelcacheEntry(rel);
1023  }
1024  else
1025  elog(PANIC, "smgr_redo: unknown op code %u", info);
1026 }
void XLogTruncateRelation(RelFileNode rnode, ForkNumber forkNum, BlockNumber nblocks)
Definition: xlogutils.c:662
#define SMGR_TRUNCATE_HEAP
Definition: storage_xlog.h:40
void smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
Definition: smgr.c:333
unsigned char uint8
Definition: c.h:439
#define SMGR_TRUNCATE_FSM
Definition: storage_xlog.h:42
uint32 BlockNumber
Definition: block.h:31
RelFileNode rnode
Definition: storage_xlog.h:49
bool smgrexists(SMgrRelation reln, ForkNumber forknum)
Definition: smgr.c:247
#define PANIC
Definition: elog.h:50
void XLogFlush(XLogRecPtr record)
Definition: xlog.c:2860
#define XLOG_SMGR_CREATE
Definition: storage_xlog.h:30
XLogRecPtr EndRecPtr
Definition: xlogreader.h:176
#define XLogRecGetData(decoder)
Definition: xlogreader.h:310
Relation CreateFakeRelcacheEntry(RelFileNode rnode)
Definition: xlogutils.c:574
BlockNumber FreeSpaceMapPrepareTruncateRel(Relation rel, BlockNumber nblocks)
Definition: freespace.c:261
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:305
SMgrRelation smgropen(RelFileNode rnode, BackendId backend)
Definition: smgr.c:146
ForkNumber
Definition: relpath.h:40
#define XLOG_SMGR_TRUNCATE
Definition: storage_xlog.h:31
void FreeFakeRelcacheEntry(Relation fakerel)
Definition: xlogutils.c:617
#define InvalidBackendId
Definition: backendid.h:23
void smgrtruncate(SMgrRelation reln, ForkNumber *forknum, int nforks, BlockNumber *nblocks)
Definition: smgr.c:595
#define BlockNumberIsValid(blockNumber)
Definition: block.h:70
ForkNumber forkNum
Definition: storage_xlog.h:36
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:804
#define XLR_INFO_MASK
Definition: xlogrecord.h:62
#define InvalidBlockNumber
Definition: block.h:33
#define SMGR_TRUNCATE_VM
Definition: storage_xlog.h:41
#define MAX_FORKNUM
Definition: relpath.h:55
#define elog(elevel,...)
Definition: elog.h:232
BlockNumber visibilitymap_prepare_truncate(Relation rel, BlockNumber nheapblocks)
#define XLogRecHasAnyBlockRefs(decoder)
Definition: xlogreader.h:312
BlockNumber blkno
Definition: storage_xlog.h:48
void FreeSpaceMapVacuumRange(Relation rel, BlockNumber start, BlockNumber end)
Definition: freespace.c:352
RelFileNode rnode
Definition: storage_xlog.h:35

◆ smgrDoPendingDeletes()

void smgrDoPendingDeletes ( bool  isCommit)

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

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 }
BackendId backend
Definition: storage.c:63
void smgrclose(SMgrRelation reln)
Definition: smgr.c:256
static int32 next
Definition: blutils.c:219
void smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo)
Definition: smgr.c:384
void pfree(void *pointer)
Definition: mcxt.c:1169
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:1182
static PendingRelDelete * pendingDeletes
Definition: storage.c:75
void * palloc(Size size)
Definition: mcxt.c:1062
RelFileNode relnode
Definition: storage.c:62
int i

◆ smgrDoPendingSyncs()

void smgrDoPendingSyncs ( bool  isCommit,
bool  isParallelWorker 
)

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

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 }
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:247
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
void pfree(void *pointer)
Definition: mcxt.c:1169
HTAB * pendingSyncHash
Definition: storage.c:76
#define AssertPendingSyncs_RelationCache()
Definition: relcache.h:133
RelFileNodeBackend smgr_rnode
Definition: smgr.h:42
Relation CreateFakeRelcacheEntry(RelFileNode rnode)
Definition: xlogutils.c:574
SMgrRelation smgropen(RelFileNode rnode, BackendId backend)
Definition: smgr.c:146
ForkNumber
Definition: relpath.h:40
void FreeFakeRelcacheEntry(Relation fakerel)
Definition: xlogutils.c:617
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:548
#define Assert(condition)
Definition: c.h:804
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:1436
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1182
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
void log_newpage_range(Relation rel, ForkNumber forkNum, BlockNumber startblk, BlockNumber endblk, bool page_std)
Definition: xloginsert.c:1175
static PendingRelDelete * pendingDeletes
Definition: storage.c:75
void * palloc(Size size)
Definition: mcxt.c:1062
RelFileNode relnode
Definition: storage.c:62
void smgrdosyncall(SMgrRelation *rels, int nrels)
Definition: smgr.c:348

◆ smgrGetPendingDeletes()

int smgrGetPendingDeletes ( bool  forCommit,
RelFileNode **  ptr 
)

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

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 }
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:1062
RelFileNode relnode
Definition: storage.c:62

Variable Documentation

◆ pendingDeletes

PendingRelDelete* pendingDeletes = NULL
static

Definition at line 75 of file storage.c.

Referenced by RelationCreateStorage(), and RelationDropStorage().

◆ pendingSyncHash

HTAB* pendingSyncHash = NULL

Definition at line 76 of file storage.c.

◆ wal_skip_threshold

int wal_skip_threshold = 2048

Definition at line 38 of file storage.c.

Referenced by smgrDoPendingSyncs().