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:49
#define HASH_CONTEXT
Definition: hsearch.h:93
#define HASH_ELEM
Definition: hsearch.h:87
MemoryContext hcxt
Definition: hsearch.h:78
struct PendingRelSync PendingRelSync
bool is_truncated
Definition: storage.c:72
Size entrysize
Definition: hsearch.h:73
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:908
HTAB * pendingSyncHash
Definition: storage.c:76
struct RelFileNode RelFileNode
#define HASH_BLOBS
Definition: hsearch.h:88
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:318
Size keysize
Definition: hsearch.h:72
#define Assert(condition)
Definition: c.h:738

◆ AtSubAbort_smgr()

void AtSubAbort_smgr ( void  )

Definition at line 898 of file storage.c.

References smgrDoPendingDeletes().

Referenced by AbortSubTransaction().

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

◆ AtSubCommit_smgr()

void AtSubCommit_smgr ( void  )

Definition at line 878 of file storage.c.

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

Referenced by CommitSubTransaction().

879 {
880  int nestLevel = GetCurrentTransactionNestLevel();
881  PendingRelDelete *pending;
882 
883  for (pending = pendingDeletes; pending != NULL; pending = pending->next)
884  {
885  if (pending->nestLevel >= nestLevel)
886  pending->nestLevel = nestLevel - 1;
887  }
888 }
struct PendingRelDelete * next
Definition: storage.c:66
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:842
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:1337
HTAB * pendingSyncHash
Definition: storage.c:76
Size mul_size(Size s1, Size s2)
Definition: shmem.c:515

◆ 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:324
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:416
ForkNumber forkNum
Definition: storage_xlog.h:36
void XLogBeginInsert(void)
Definition: xloginsert.c:121
RelFileNode rnode
Definition: storage_xlog.h:35

◆ PostPrepare_smgr()

void PostPrepare_smgr ( void  )

Definition at line 857 of file storage.c.

References PendingRelDelete::next, and pfree().

Referenced by PrepareTransaction().

858 {
859  PendingRelDelete *pending;
861 
862  for (pending = pendingDeletes; pending != NULL; pending = next)
863  {
864  next = pending->next;
866  /* must explicitly free the list entry */
867  pfree(pending);
868  }
869 }
static int32 next
Definition: blutils.c:218
void pfree(void *pointer)
Definition: mcxt.c:1056
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:491
char data[BLCKSZ]
Definition: c.h:1104
#define ERROR
Definition: elog.h:43
RelFileNodeBackend smgr_rnode
Definition: smgr.h:42
static char * buf
Definition: pg_test_fsync.c:67
#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:538
BackendId backend
Definition: relfilenode.h:75
void PageSetChecksumInplace(Page page, BlockNumber blkno)
Definition: bufpage.c:1194
void smgrextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer, bool skipFsync)
Definition: smgr.c:462
int errmsg(const char *fmt,...)
Definition: elog.c:824
XLogRecPtr log_newpage(RelFileNode *rnode, ForkNumber forkNum, BlockNumber blkno, Page page, bool page_std)
Definition: xloginsert.c:977
#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:620
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:191
static void AddPendingSync(const RelFileNode *rnode)
Definition: storage.c:84
bool IsInParallelMode(void)
Definition: xact.c:997
#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:145
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:842
#define Assert(condition)
Definition: c.h:738
static PendingRelDelete * pendingDeletes
Definition: storage.c:75
RelFileNode relnode
Definition: storage.c:62
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:796
#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:842
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:796

◆ 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:218
void pfree(void *pointer)
Definition: mcxt.c:1056
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:908
#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, InvalidBlockNumber, MAIN_FORKNUM, MAX_FORKNUM, RelationData::rd_node, RelationData::rd_smgr, RelationNeedsWAL, RelationOpenSmgr, RelationPreTruncate(), xl_smgr_truncate::rnode, SMgrRelationData::smgr_fsm_nblocks, SMgrRelationData::smgr_targblock, SMGR_TRUNCATE_ALL, SMgrRelationData::smgr_vm_nblocks, 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  */
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 }
BlockNumber smgr_vm_nblocks
Definition: smgr.h:56
#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
BlockNumber smgr_fsm_nblocks
Definition: smgr.h:55
RelFileNode rnode
Definition: storage_xlog.h:49
bool smgrexists(SMgrRelation reln, ForkNumber forknum)
Definition: smgr.c:247
void XLogFlush(XLogRecPtr record)
Definition: xlog.c:2844
#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:324
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:416
void smgrtruncate(SMgrRelation reln, ForkNumber *forknum, int nforks, BlockNumber *nblocks)
Definition: smgr.c:554
#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:54
#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
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:121
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(), RelationBuildDesc(), 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:908
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:738

◆ 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:816
#define HASH_CONTEXT
Definition: hsearch.h:93
#define HASH_ELEM
Definition: hsearch.h:87
MemoryContext hcxt
Definition: hsearch.h:78
Size entrysize
Definition: hsearch.h:73
RelFileNode rnode
Definition: storage.c:71
#define MemSet(start, val, len)
Definition: c.h:971
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1337
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:908
Definition: dynahash.c:210
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:88
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:318
Size keysize
Definition: hsearch.h:72
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1391
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1381
static PendingRelDelete * pendingDeletes
Definition: storage.c:75

◆ smgr_redo()

void smgr_redo ( XLogReaderState record)

Definition at line 904 of file storage.c.

References Assert, xl_smgr_truncate::blkno, BlockNumberIsValid, blocks, 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.

905 {
906  XLogRecPtr lsn = record->EndRecPtr;
907  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
908 
909  /* Backup blocks are not used in smgr records */
910  Assert(!XLogRecHasAnyBlockRefs(record));
911 
912  if (info == XLOG_SMGR_CREATE)
913  {
914  xl_smgr_create *xlrec = (xl_smgr_create *) XLogRecGetData(record);
915  SMgrRelation reln;
916 
917  reln = smgropen(xlrec->rnode, InvalidBackendId);
918  smgrcreate(reln, xlrec->forkNum, true);
919  }
920  else if (info == XLOG_SMGR_TRUNCATE)
921  {
922  xl_smgr_truncate *xlrec = (xl_smgr_truncate *) XLogRecGetData(record);
923  SMgrRelation reln;
924  Relation rel;
925  ForkNumber forks[MAX_FORKNUM];
927  int nforks = 0;
928  bool need_fsm_vacuum = false;
929 
930  reln = smgropen(xlrec->rnode, InvalidBackendId);
931 
932  /*
933  * Forcibly create relation if it doesn't exist (which suggests that
934  * it was dropped somewhere later in the WAL sequence). As in
935  * XLogReadBufferForRedo, we prefer to recreate the rel and replay the
936  * log as best we can until the drop is seen.
937  */
938  smgrcreate(reln, MAIN_FORKNUM, true);
939 
940  /*
941  * Before we perform the truncation, update minimum recovery point to
942  * cover this WAL record. Once the relation is truncated, there's no
943  * going back. The buffer manager enforces the WAL-first rule for
944  * normal updates to relation files, so that the minimum recovery
945  * point is always updated before the corresponding change in the data
946  * file is flushed to disk. We have to do the same manually here.
947  *
948  * Doing this before the truncation means that if the truncation fails
949  * for some reason, you cannot start up the system even after restart,
950  * until you fix the underlying situation so that the truncation will
951  * succeed. Alternatively, we could update the minimum recovery point
952  * after truncation, but that would leave a small window where the
953  * WAL-first rule could be violated.
954  */
955  XLogFlush(lsn);
956 
957  /* Prepare for truncation of MAIN fork */
958  if ((xlrec->flags & SMGR_TRUNCATE_HEAP) != 0)
959  {
960  forks[nforks] = MAIN_FORKNUM;
961  blocks[nforks] = xlrec->blkno;
962  nforks++;
963 
964  /* Also tell xlogutils.c about it */
965  XLogTruncateRelation(xlrec->rnode, MAIN_FORKNUM, xlrec->blkno);
966  }
967 
968  /* Prepare for truncation of FSM and VM too */
969  rel = CreateFakeRelcacheEntry(xlrec->rnode);
970 
971  if ((xlrec->flags & SMGR_TRUNCATE_FSM) != 0 &&
972  smgrexists(reln, FSM_FORKNUM))
973  {
974  blocks[nforks] = FreeSpaceMapPrepareTruncateRel(rel, xlrec->blkno);
975  if (BlockNumberIsValid(blocks[nforks]))
976  {
977  forks[nforks] = FSM_FORKNUM;
978  nforks++;
979  need_fsm_vacuum = true;
980  }
981  }
982  if ((xlrec->flags & SMGR_TRUNCATE_VM) != 0 &&
984  {
985  blocks[nforks] = visibilitymap_prepare_truncate(rel, xlrec->blkno);
986  if (BlockNumberIsValid(blocks[nforks]))
987  {
988  forks[nforks] = VISIBILITYMAP_FORKNUM;
989  nforks++;
990  }
991  }
992 
993  /* Do the real work to truncate relation forks */
994  if (nforks > 0)
995  smgrtruncate(reln, forks, nforks, blocks);
996 
997  /*
998  * Update upper-level FSM pages to account for the truncation. This is
999  * important because the just-truncated pages were likely marked as
1000  * all-free, and would be preferentially selected.
1001  */
1002  if (need_fsm_vacuum)
1003  FreeSpaceMapVacuumRange(rel, xlrec->blkno,
1005 
1006  FreeFakeRelcacheEntry(rel);
1007  }
1008  else
1009  elog(PANIC, "smgr_redo: unknown op code %u", info);
1010 }
void XLogTruncateRelation(RelFileNode rnode, ForkNumber forkNum, BlockNumber nblocks)
Definition: xlogutils.c:645
#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:365
#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:53
void XLogFlush(XLogRecPtr record)
Definition: xlog.c:2844
#define XLOG_SMGR_CREATE
Definition: storage_xlog.h:30
XLogRecPtr EndRecPtr
Definition: xlogreader.h:176
#define XLogRecGetData(decoder)
Definition: xlogreader.h:311
Relation CreateFakeRelcacheEntry(RelFileNode rnode)
Definition: xlogutils.c:557
BlockNumber FreeSpaceMapPrepareTruncateRel(Relation rel, BlockNumber nblocks)
Definition: freespace.c:261
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:307
SMgrRelation smgropen(RelFileNode rnode, BackendId backend)
Definition: smgr.c:145
ForkNumber
Definition: relpath.h:40
#define XLOG_SMGR_TRUNCATE
Definition: storage_xlog.h:31
void FreeFakeRelcacheEntry(Relation fakerel)
Definition: xlogutils.c:600
#define InvalidBackendId
Definition: backendid.h:23
void smgrtruncate(SMgrRelation reln, ForkNumber *forknum, int nforks, BlockNumber *nblocks)
Definition: smgr.c:554
#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:738
#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
static int64 blocks
Definition: pg_checksums.c:35
#define elog(elevel,...)
Definition: elog.h:214
BlockNumber visibilitymap_prepare_truncate(Relation rel, BlockNumber nheapblocks)
#define XLogRecHasAnyBlockRefs(decoder)
Definition: xlogreader.h:313
BlockNumber blkno
Definition: storage_xlog.h:48
void FreeSpaceMapVacuumRange(Relation rel, BlockNumber start, BlockNumber end)
Definition: freespace.c:354
RelFileNode rnode
Definition: storage_xlog.h:35

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

◆ smgrDoPendingSyncs()

void smgrDoPendingSyncs ( bool  isCommit,
bool  isParallelWorker 
)

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

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

817 {
818  int nestLevel = GetCurrentTransactionNestLevel();
819  int nrels;
820  RelFileNode *rptr;
821  PendingRelDelete *pending;
822 
823  nrels = 0;
824  for (pending = pendingDeletes; pending != NULL; pending = pending->next)
825  {
826  if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit
827  && pending->backend == InvalidBackendId)
828  nrels++;
829  }
830  if (nrels == 0)
831  {
832  *ptr = NULL;
833  return 0;
834  }
835  rptr = (RelFileNode *) palloc(nrels * sizeof(RelFileNode));
836  *ptr = rptr;
837  for (pending = pendingDeletes; pending != NULL; pending = pending->next)
838  {
839  if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit
840  && pending->backend == InvalidBackendId)
841  {
842  *rptr = pending->relnode;
843  rptr++;
844  }
845  }
846  return nrels;
847 }
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:842
static PendingRelDelete * pendingDeletes
Definition: storage.c:75
void * palloc(Size size)
Definition: mcxt.c:949
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().