PostgreSQL Source Code  git master
storage.c File Reference
#include "postgres.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/memutils.h"
#include "utils/rel.h"
Include dependency graph for storage.c:

Go to the source code of this file.

Data Structures

struct  PendingRelDelete
 

Typedefs

typedef struct PendingRelDelete PendingRelDelete
 

Functions

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 RelationCopyStorage (SMgrRelation src, SMgrRelation dst, ForkNumber forkNum, char relpersistence)
 
void smgrDoPendingDeletes (bool isCommit)
 
int smgrGetPendingDeletes (bool forCommit, RelFileNode **ptr)
 
void PostPrepare_smgr (void)
 
void AtSubCommit_smgr (void)
 
void AtSubAbort_smgr (void)
 
void smgr_redo (XLogReaderState *record)
 

Variables

static PendingRelDeletependingDeletes = NULL
 

Typedef Documentation

◆ PendingRelDelete

Function Documentation

◆ AtSubAbort_smgr()

void AtSubAbort_smgr ( void  )

Definition at line 595 of file storage.c.

References smgrDoPendingDeletes().

Referenced by AbortSubTransaction().

596 {
597  smgrDoPendingDeletes(false);
598 }
void smgrDoPendingDeletes(bool isCommit)
Definition: storage.c:430

◆ AtSubCommit_smgr()

void AtSubCommit_smgr ( void  )

Definition at line 575 of file storage.c.

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

Referenced by CommitSubTransaction().

576 {
577  int nestLevel = GetCurrentTransactionNestLevel();
578  PendingRelDelete *pending;
579 
580  for (pending = pendingDeletes; pending != NULL; pending = pending->next)
581  {
582  if (pending->nestLevel >= nestLevel)
583  pending->nestLevel = nestLevel - 1;
584  }
585 }
struct PendingRelDelete * next
Definition: storage.c:61
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:841
static PendingRelDelete * pendingDeletes
Definition: storage.c:64

◆ log_smgrcreate()

void log_smgrcreate ( const RelFileNode rnode,
ForkNumber  forkNum 
)

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

128 {
129  xl_smgr_create xlrec;
130 
131  /*
132  * Make an XLOG entry reporting the file creation.
133  */
134  xlrec.rnode = *rnode;
135  xlrec.forkNum = forkNum;
136 
137  XLogBeginInsert();
138  XLogRegisterData((char *) &xlrec, sizeof(xlrec));
140 }
#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:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
ForkNumber forkNum
Definition: storage_xlog.h:36
void XLogBeginInsert(void)
Definition: xloginsert.c:120
RelFileNode rnode
Definition: storage_xlog.h:35

◆ PostPrepare_smgr()

void PostPrepare_smgr ( void  )

Definition at line 554 of file storage.c.

References PendingRelDelete::next, and pfree().

Referenced by PrepareTransaction().

555 {
556  PendingRelDelete *pending;
558 
559  for (pending = pendingDeletes; pending != NULL; pending = next)
560  {
561  next = pending->next;
563  /* must explicitly free the list entry */
564  pfree(pending);
565  }
566 }
static int32 next
Definition: blutils.c:213
void pfree(void *pointer)
Definition: mcxt.c:1056
struct PendingRelDelete * next
Definition: storage.c:61
static PendingRelDelete * pendingDeletes
Definition: storage.c:64

◆ RelationCopyStorage()

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

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

338 {
340  Page page;
341  bool use_wal;
342  bool copying_initfork;
343  BlockNumber nblocks;
344  BlockNumber blkno;
345 
346  page = (Page) buf.data;
347 
348  /*
349  * The init fork for an unlogged relation in many respects has to be
350  * treated the same as normal relation, changes need to be WAL logged and
351  * it needs to be synced to disk.
352  */
353  copying_initfork = relpersistence == RELPERSISTENCE_UNLOGGED &&
354  forkNum == INIT_FORKNUM;
355 
356  /*
357  * We need to log the copied data in WAL iff WAL archiving/streaming is
358  * enabled AND it's a permanent relation.
359  */
360  use_wal = XLogIsNeeded() &&
361  (relpersistence == RELPERSISTENCE_PERMANENT || copying_initfork);
362 
363  nblocks = smgrnblocks(src, forkNum);
364 
365  for (blkno = 0; blkno < nblocks; blkno++)
366  {
367  /* If we got a cancel signal during the copy of the data, quit */
369 
370  smgrread(src, forkNum, blkno, buf.data);
371 
372  if (!PageIsVerified(page, blkno))
373  ereport(ERROR,
375  errmsg("invalid page in block %u of relation %s",
376  blkno,
378  src->smgr_rnode.backend,
379  forkNum))));
380 
381  /*
382  * WAL-log the copied page. Unfortunately we don't know what kind of a
383  * page this is, so we have to log the full page including any unused
384  * space.
385  */
386  if (use_wal)
387  log_newpage(&dst->smgr_rnode.node, forkNum, blkno, page, false);
388 
389  PageSetChecksumInplace(page, blkno);
390 
391  /*
392  * Now write the page. We say skipFsync = true because there's no
393  * need for smgr to schedule an fsync for this write; we'll do it
394  * ourselves below.
395  */
396  smgrextend(dst, forkNum, blkno, buf.data, true);
397  }
398 
399  /*
400  * If the rel is WAL-logged, must fsync before commit. We use heap_sync
401  * to ensure that the toast table gets fsync'd too. (For a temp or
402  * unlogged rel we don't care since the data will be gone after a crash
403  * anyway.)
404  *
405  * It's obvious that we must do this when not WAL-logging the copy. It's
406  * less obvious that we have to do it even if we did WAL-log the copied
407  * pages. The reason is that since we're copying outside shared buffers, a
408  * CHECKPOINT occurring during the copy has no way to flush the previously
409  * written data to disk (indeed it won't know the new rel even exists). A
410  * crash later on would replay WAL from the checkpoint, therefore it
411  * wouldn't replay our earlier WAL entries. If we do not fsync those pages
412  * here, they might still not be on disk when the crash occurs.
413  */
414  if (relpersistence == RELPERSISTENCE_PERMANENT || copying_initfork)
415  smgrimmedsync(dst, forkNum);
416 }
bool PageIsVerified(Page page, BlockNumber blkno)
Definition: bufpage.c:82
#define XLogIsNeeded()
Definition: xlog.h:181
int errcode(int sqlerrcode)
Definition: elog.c:608
uint32 BlockNumber
Definition: block.h:31
void smgrread(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer)
Definition: smgr.c:508
char data[BLCKSZ]
Definition: c.h:1091
#define ERROR
Definition: elog.h:43
char relpersistence
Definition: pg_class.h:78
RelFileNodeBackend smgr_rnode
Definition: smgr.h:42
static char * buf
Definition: pg_test_fsync.c:67
#define ereport(elevel, rest)
Definition: elog.h:141
#define ERRCODE_DATA_CORRUPTED
Definition: pg_basebackup.c:45
RelFileNode node
Definition: relfilenode.h:74
BlockNumber smgrnblocks(SMgrRelation reln, ForkNumber forknum)
Definition: smgr.c:555
BackendId backend
Definition: relfilenode.h:75
void PageSetChecksumInplace(Page page, BlockNumber blkno)
Definition: bufpage.c:1198
void smgrextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer, bool skipFsync)
Definition: smgr.c:483
int errmsg(const char *fmt,...)
Definition: elog.c:822
XLogRecPtr log_newpage(RelFileNode *rnode, ForkNumber forkNum, BlockNumber blkno, Page page, bool page_std)
Definition: xloginsert.c:972
#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:637
Pointer Page
Definition: bufpage.h:78

◆ RelationCreateStorage()

SMgrRelation RelationCreateStorage ( RelFileNode  rnode,
char  relpersistence 
)

Definition at line 78 of file storage.c.

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

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

79 {
80  PendingRelDelete *pending;
81  SMgrRelation srel;
82  BackendId backend;
83  bool needs_wal;
84 
85  switch (relpersistence)
86  {
87  case RELPERSISTENCE_TEMP:
88  backend = BackendIdForTempRelations();
89  needs_wal = false;
90  break;
91  case RELPERSISTENCE_UNLOGGED:
92  backend = InvalidBackendId;
93  needs_wal = false;
94  break;
95  case RELPERSISTENCE_PERMANENT:
96  backend = InvalidBackendId;
97  needs_wal = true;
98  break;
99  default:
100  elog(ERROR, "invalid relpersistence: %c", relpersistence);
101  return NULL; /* placate compiler */
102  }
103 
104  srel = smgropen(rnode, backend);
105  smgrcreate(srel, MAIN_FORKNUM, false);
106 
107  if (needs_wal)
109 
110  /* Add the relation to the list of stuff to delete at abort */
111  pending = (PendingRelDelete *)
113  pending->relnode = rnode;
114  pending->backend = backend;
115  pending->atCommit = false; /* delete if abort */
117  pending->next = pendingDeletes;
118  pendingDeletes = pending;
119 
120  return srel;
121 }
BackendId backend
Definition: storage.c:58
void smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
Definition: smgr.c:333
#define ERROR
Definition: elog.h:43
char relpersistence
Definition: pg_class.h:78
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:61
#define InvalidBackendId
Definition: backendid.h:23
int BackendId
Definition: backendid.h:21
RelFileNode node
Definition: relfilenode.h:74
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:841
static PendingRelDelete * pendingDeletes
Definition: storage.c:64
RelFileNode relnode
Definition: storage.c:57
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:796
#define elog(elevel,...)
Definition: elog.h:228
void log_smgrcreate(const RelFileNode *rnode, ForkNumber forkNum)
Definition: storage.c:127

◆ RelationDropStorage()

void RelationDropStorage ( Relation  rel)

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

148 {
149  PendingRelDelete *pending;
150 
151  /* Add the relation to the list of stuff to delete at commit */
152  pending = (PendingRelDelete *)
154  pending->relnode = rel->rd_node;
155  pending->backend = rel->rd_backend;
156  pending->atCommit = true; /* delete if commit */
158  pending->next = pendingDeletes;
159  pendingDeletes = pending;
160 
161  /*
162  * NOTE: if the relation was created in this transaction, it will now be
163  * present in the pending-delete list twice, once with atCommit true and
164  * once with atCommit false. Hence, it will be physically deleted at end
165  * of xact in either case (and the other entry will be ignored by
166  * smgrDoPendingDeletes, so no error will occur). We could instead remove
167  * the existing list entry and delete the physical file immediately, but
168  * for now I'll keep the logic simple.
169  */
170 
171  RelationCloseSmgr(rel);
172 }
BackendId backend
Definition: storage.c:58
#define RelationCloseSmgr(relation)
Definition: rel.h:491
MemoryContext TopMemoryContext
Definition: mcxt.c:44
struct PendingRelDelete * next
Definition: storage.c:61
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:841
RelFileNode rd_node
Definition: rel.h:54
BackendId rd_backend
Definition: rel.h:58
static PendingRelDelete * pendingDeletes
Definition: storage.c:64
RelFileNode relnode
Definition: storage.c:57
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:796

◆ RelationPreserveStorage()

void RelationPreserveStorage ( RelFileNode  rnode,
bool  atCommit 
)

Definition at line 192 of file storage.c.

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

Referenced by ATExecAddIndex(), and write_relmap_file().

193 {
194  PendingRelDelete *pending;
195  PendingRelDelete *prev;
197 
198  prev = NULL;
199  for (pending = pendingDeletes; pending != NULL; pending = next)
200  {
201  next = pending->next;
202  if (RelFileNodeEquals(rnode, pending->relnode)
203  && pending->atCommit == atCommit)
204  {
205  /* unlink and delete list entry */
206  if (prev)
207  prev->next = next;
208  else
210  pfree(pending);
211  /* prev does not change */
212  }
213  else
214  {
215  /* unrelated entry, don't touch it */
216  prev = pending;
217  }
218  }
219 }
static int32 next
Definition: blutils.c:213
void pfree(void *pointer)
Definition: mcxt.c:1056
struct PendingRelDelete * next
Definition: storage.c:61
static PendingRelDelete * pendingDeletes
Definition: storage.c:64
RelFileNode relnode
Definition: storage.c:57
#define RelFileNodeEquals(node1, node2)
Definition: relfilenode.h:88

◆ RelationTruncate()

void RelationTruncate ( Relation  rel,
BlockNumber  nblocks 
)

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

230 {
231  bool fsm;
232  bool vm;
233  bool need_fsm_vacuum = false;
234  ForkNumber forks[MAX_FORKNUM];
236  int nforks = 0;
237 
238  /* Open it at the smgr level if not already done */
239  RelationOpenSmgr(rel);
240 
241  /*
242  * Make sure smgr_targblock etc aren't pointing somewhere past new end
243  */
247 
248  /* Prepare for truncation of MAIN fork of the relation */
249  forks[nforks] = MAIN_FORKNUM;
250  blocks[nforks] = nblocks;
251  nforks++;
252 
253  /* Prepare for truncation of the FSM if it exists */
254  fsm = smgrexists(rel->rd_smgr, FSM_FORKNUM);
255  if (fsm)
256  {
257  blocks[nforks] = FreeSpaceMapPrepareTruncateRel(rel, nblocks);
258  if (BlockNumberIsValid(blocks[nforks]))
259  {
260  forks[nforks] = FSM_FORKNUM;
261  nforks++;
262  need_fsm_vacuum = true;
263  }
264  }
265 
266  /* Prepare for truncation of the visibility map too if it exists */
268  if (vm)
269  {
270  blocks[nforks] = visibilitymap_prepare_truncate(rel, nblocks);
271  if (BlockNumberIsValid(blocks[nforks]))
272  {
273  forks[nforks] = VISIBILITYMAP_FORKNUM;
274  nforks++;
275  }
276  }
277 
278  /*
279  * We WAL-log the truncation before actually truncating, which means
280  * trouble if the truncation fails. If we then crash, the WAL replay
281  * likely isn't going to succeed in the truncation either, and cause a
282  * PANIC. It's tempting to put a critical section here, but that cure
283  * would be worse than the disease. It would turn a usually harmless
284  * failure to truncate, that might spell trouble at WAL replay, into a
285  * certain PANIC.
286  */
287  if (RelationNeedsWAL(rel))
288  {
289  /*
290  * Make an XLOG entry reporting the file truncation.
291  */
292  XLogRecPtr lsn;
293  xl_smgr_truncate xlrec;
294 
295  xlrec.blkno = nblocks;
296  xlrec.rnode = rel->rd_node;
297  xlrec.flags = SMGR_TRUNCATE_ALL;
298 
299  XLogBeginInsert();
300  XLogRegisterData((char *) &xlrec, sizeof(xlrec));
301 
302  lsn = XLogInsert(RM_SMGR_ID,
304 
305  /*
306  * Flush, because otherwise the truncation of the main relation might
307  * hit the disk before the WAL record, and the truncation of the FSM
308  * or visibility map. If we crashed during that window, we'd be left
309  * with a truncated heap, but the FSM or visibility map would still
310  * contain entries for the non-existent heap pages.
311  */
312  if (fsm || vm)
313  XLogFlush(lsn);
314  }
315 
316  /* Do the real work to truncate relation forks */
317  smgrtruncate(rel->rd_smgr, forks, nforks, blocks);
318 
319  /*
320  * Update upper-level FSM pages to account for the truncation.
321  * This is important because the just-truncated pages were likely
322  * marked as all-free, and would be preferentially selected.
323  */
324  if (need_fsm_vacuum)
326 }
BlockNumber smgr_vm_nblocks
Definition: smgr.h:56
#define XLR_SPECIAL_REL_UPDATE
Definition: xlogrecord.h:71
struct SMgrRelationData * rd_smgr
Definition: rel.h:56
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:2805
#define RelationOpenSmgr(relation)
Definition: rel.h:479
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:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
void smgrtruncate(SMgrRelation reln, ForkNumber *forknum, int nforks, BlockNumber *nblocks)
Definition: smgr.c:571
#define BlockNumberIsValid(blockNumber)
Definition: block.h:70
RelFileNode rd_node
Definition: rel.h:54
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:524
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:120
void FreeSpaceMapVacuumRange(Relation rel, BlockNumber start, BlockNumber end)
Definition: freespace.c:352

◆ smgr_redo()

void smgr_redo ( XLogReaderState record)

Definition at line 601 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.

602 {
603  XLogRecPtr lsn = record->EndRecPtr;
604  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
605 
606  /* Backup blocks are not used in smgr records */
607  Assert(!XLogRecHasAnyBlockRefs(record));
608 
609  if (info == XLOG_SMGR_CREATE)
610  {
611  xl_smgr_create *xlrec = (xl_smgr_create *) XLogRecGetData(record);
612  SMgrRelation reln;
613 
614  reln = smgropen(xlrec->rnode, InvalidBackendId);
615  smgrcreate(reln, xlrec->forkNum, true);
616  }
617  else if (info == XLOG_SMGR_TRUNCATE)
618  {
619  xl_smgr_truncate *xlrec = (xl_smgr_truncate *) XLogRecGetData(record);
620  SMgrRelation reln;
621  Relation rel;
622  ForkNumber forks[MAX_FORKNUM];
624  int nforks = 0;
625  bool need_fsm_vacuum = false;
626 
627  reln = smgropen(xlrec->rnode, InvalidBackendId);
628 
629  /*
630  * Forcibly create relation if it doesn't exist (which suggests that
631  * it was dropped somewhere later in the WAL sequence). As in
632  * XLogReadBufferForRedo, we prefer to recreate the rel and replay the
633  * log as best we can until the drop is seen.
634  */
635  smgrcreate(reln, MAIN_FORKNUM, true);
636 
637  /*
638  * Before we perform the truncation, update minimum recovery point to
639  * cover this WAL record. Once the relation is truncated, there's no
640  * going back. The buffer manager enforces the WAL-first rule for
641  * normal updates to relation files, so that the minimum recovery
642  * point is always updated before the corresponding change in the data
643  * file is flushed to disk. We have to do the same manually here.
644  *
645  * Doing this before the truncation means that if the truncation fails
646  * for some reason, you cannot start up the system even after restart,
647  * until you fix the underlying situation so that the truncation will
648  * succeed. Alternatively, we could update the minimum recovery point
649  * after truncation, but that would leave a small window where the
650  * WAL-first rule could be violated.
651  */
652  XLogFlush(lsn);
653 
654  /* Prepare for truncation of MAIN fork */
655  if ((xlrec->flags & SMGR_TRUNCATE_HEAP) != 0)
656  {
657  forks[nforks] = MAIN_FORKNUM;
658  blocks[nforks] = xlrec->blkno;
659  nforks++;
660 
661  /* Also tell xlogutils.c about it */
662  XLogTruncateRelation(xlrec->rnode, MAIN_FORKNUM, xlrec->blkno);
663  }
664 
665  /* Prepare for truncation of FSM and VM too */
666  rel = CreateFakeRelcacheEntry(xlrec->rnode);
667 
668  if ((xlrec->flags & SMGR_TRUNCATE_FSM) != 0 &&
669  smgrexists(reln, FSM_FORKNUM))
670  {
671  blocks[nforks] = FreeSpaceMapPrepareTruncateRel(rel, xlrec->blkno);
672  if (BlockNumberIsValid(blocks[nforks]))
673  {
674  forks[nforks] = FSM_FORKNUM;
675  nforks++;
676  need_fsm_vacuum = true;
677  }
678  }
679  if ((xlrec->flags & SMGR_TRUNCATE_VM) != 0 &&
681  {
682  blocks[nforks] = visibilitymap_prepare_truncate(rel, xlrec->blkno);
683  if (BlockNumberIsValid(blocks[nforks]))
684  {
685  forks[nforks] = VISIBILITYMAP_FORKNUM;
686  nforks++;
687  }
688  }
689 
690  /* Do the real work to truncate relation forks */
691  if (nforks > 0)
692  smgrtruncate(reln, forks, nforks, blocks);
693 
694  /*
695  * Update upper-level FSM pages to account for the truncation.
696  * This is important because the just-truncated pages were likely
697  * marked as all-free, and would be preferentially selected.
698  */
699  if (need_fsm_vacuum)
700  FreeSpaceMapVacuumRange(rel, xlrec->blkno,
702 
704  }
705  else
706  elog(PANIC, "smgr_redo: unknown op code %u", info);
707 }
void XLogTruncateRelation(RelFileNode rnode, ForkNumber forkNum, BlockNumber nblocks)
Definition: xlogutils.c:636
#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:357
#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:2805
#define XLOG_SMGR_CREATE
Definition: storage_xlog.h:30
XLogRecPtr EndRecPtr
Definition: xlogreader.h:132
#define XLogRecGetData(decoder)
Definition: xlogreader.h:283
Relation CreateFakeRelcacheEntry(RelFileNode rnode)
Definition: xlogutils.c:550
BlockNumber FreeSpaceMapPrepareTruncateRel(Relation rel, BlockNumber nblocks)
Definition: freespace.c:261
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:279
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:591
#define InvalidBackendId
Definition: backendid.h:23
void smgrtruncate(SMgrRelation reln, ForkNumber *forknum, int nforks, BlockNumber *nblocks)
Definition: smgr.c:571
#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:739
#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:228
BlockNumber visibilitymap_prepare_truncate(Relation rel, BlockNumber nheapblocks)
#define XLogRecHasAnyBlockRefs(decoder)
Definition: xlogreader.h:285
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 430 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().

431 {
432  int nestLevel = GetCurrentTransactionNestLevel();
433  PendingRelDelete *pending;
434  PendingRelDelete *prev;
436  int nrels = 0,
437  i = 0,
438  maxrels = 0;
439  SMgrRelation *srels = NULL;
440 
441  prev = NULL;
442  for (pending = pendingDeletes; pending != NULL; pending = next)
443  {
444  next = pending->next;
445  if (pending->nestLevel < nestLevel)
446  {
447  /* outer-level entries should not be processed yet */
448  prev = pending;
449  }
450  else
451  {
452  /* unlink list entry first, so we don't retry on failure */
453  if (prev)
454  prev->next = next;
455  else
457  /* do deletion if called for */
458  if (pending->atCommit == isCommit)
459  {
460  SMgrRelation srel;
461 
462  srel = smgropen(pending->relnode, pending->backend);
463 
464  /* allocate the initial array, or extend it, if needed */
465  if (maxrels == 0)
466  {
467  maxrels = 8;
468  srels = palloc(sizeof(SMgrRelation) * maxrels);
469  }
470  else if (maxrels <= nrels)
471  {
472  maxrels *= 2;
473  srels = repalloc(srels, sizeof(SMgrRelation) * maxrels);
474  }
475 
476  srels[nrels++] = srel;
477  }
478  /* must explicitly free the list entry */
479  pfree(pending);
480  /* prev does not change */
481  }
482  }
483 
484  if (nrels > 0)
485  {
486  smgrdounlinkall(srels, nrels, false);
487 
488  for (i = 0; i < nrels; i++)
489  smgrclose(srels[i]);
490 
491  pfree(srels);
492  }
493 }
BackendId backend
Definition: storage.c:58
void smgrclose(SMgrRelation reln)
Definition: smgr.c:256
static int32 next
Definition: blutils.c:213
void smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo)
Definition: smgr.c:405
void pfree(void *pointer)
Definition: mcxt.c:1056
SMgrRelation smgropen(RelFileNode rnode, BackendId backend)
Definition: smgr.c:145
struct PendingRelDelete * next
Definition: storage.c:61
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:841
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1069
static PendingRelDelete * pendingDeletes
Definition: storage.c:64
void * palloc(Size size)
Definition: mcxt.c:949
RelFileNode relnode
Definition: storage.c:57
int i

◆ smgrGetPendingDeletes()

int smgrGetPendingDeletes ( bool  forCommit,
RelFileNode **  ptr 
)

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

514 {
515  int nestLevel = GetCurrentTransactionNestLevel();
516  int nrels;
517  RelFileNode *rptr;
518  PendingRelDelete *pending;
519 
520  nrels = 0;
521  for (pending = pendingDeletes; pending != NULL; pending = pending->next)
522  {
523  if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit
524  && pending->backend == InvalidBackendId)
525  nrels++;
526  }
527  if (nrels == 0)
528  {
529  *ptr = NULL;
530  return 0;
531  }
532  rptr = (RelFileNode *) palloc(nrels * sizeof(RelFileNode));
533  *ptr = rptr;
534  for (pending = pendingDeletes; pending != NULL; pending = pending->next)
535  {
536  if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit
537  && pending->backend == InvalidBackendId)
538  {
539  *rptr = pending->relnode;
540  rptr++;
541  }
542  }
543  return nrels;
544 }
BackendId backend
Definition: storage.c:58
struct PendingRelDelete * next
Definition: storage.c:61
#define InvalidBackendId
Definition: backendid.h:23
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:841
static PendingRelDelete * pendingDeletes
Definition: storage.c:64
void * palloc(Size size)
Definition: mcxt.c:949
RelFileNode relnode
Definition: storage.c:57

Variable Documentation

◆ pendingDeletes

PendingRelDelete* pendingDeletes = NULL
static

Definition at line 64 of file storage.c.

Referenced by RelationCreateStorage(), and RelationDropStorage().