PostgreSQL Source Code  git master
storage.c File Reference
#include "postgres.h"
#include "miscadmin.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 "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 596 of file storage.c.

References smgrDoPendingDeletes().

Referenced by AbortSubTransaction().

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

◆ AtSubCommit_smgr()

void AtSubCommit_smgr ( void  )

Definition at line 576 of file storage.c.

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

Referenced by CommitSubTransaction().

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

◆ log_smgrcreate()

void log_smgrcreate ( const RelFileNode rnode,
ForkNumber  forkNum 
)

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

129 {
130  xl_smgr_create xlrec;
131 
132  /*
133  * Make an XLOG entry reporting the file creation.
134  */
135  xlrec.rnode = *rnode;
136  xlrec.forkNum = forkNum;
137 
138  XLogBeginInsert();
139  XLogRegisterData((char *) &xlrec, sizeof(xlrec));
141 }
#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 555 of file storage.c.

References PendingRelDelete::next, and pfree().

Referenced by PrepareTransaction().

556 {
557  PendingRelDelete *pending;
559 
560  for (pending = pendingDeletes; pending != NULL; pending = next)
561  {
562  next = pending->next;
564  /* must explicitly free the list entry */
565  pfree(pending);
566  }
567 }
static int32 next
Definition: blutils.c:215
void pfree(void *pointer)
Definition: mcxt.c:1056
struct PendingRelDelete * next
Definition: storage.c:62
static PendingRelDelete * pendingDeletes
Definition: storage.c:65

◆ RelationCopyStorage()

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

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

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

80 {
81  PendingRelDelete *pending;
82  SMgrRelation srel;
83  BackendId backend;
84  bool needs_wal;
85 
86  switch (relpersistence)
87  {
88  case RELPERSISTENCE_TEMP:
89  backend = BackendIdForTempRelations();
90  needs_wal = false;
91  break;
92  case RELPERSISTENCE_UNLOGGED:
93  backend = InvalidBackendId;
94  needs_wal = false;
95  break;
96  case RELPERSISTENCE_PERMANENT:
97  backend = InvalidBackendId;
98  needs_wal = true;
99  break;
100  default:
101  elog(ERROR, "invalid relpersistence: %c", relpersistence);
102  return NULL; /* placate compiler */
103  }
104 
105  srel = smgropen(rnode, backend);
106  smgrcreate(srel, MAIN_FORKNUM, false);
107 
108  if (needs_wal)
110 
111  /* Add the relation to the list of stuff to delete at abort */
112  pending = (PendingRelDelete *)
114  pending->relnode = rnode;
115  pending->backend = backend;
116  pending->atCommit = false; /* delete if abort */
118  pending->next = pendingDeletes;
119  pendingDeletes = pending;
120 
121  return srel;
122 }
BackendId backend
Definition: storage.c:59
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:62
#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
static PendingRelDelete * pendingDeletes
Definition: storage.c:65
RelFileNode relnode
Definition: storage.c:58
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:796
#define elog(elevel,...)
Definition: elog.h:226
void log_smgrcreate(const RelFileNode *rnode, ForkNumber forkNum)
Definition: storage.c:128

◆ RelationDropStorage()

void RelationDropStorage ( Relation  rel)

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

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

◆ RelationPreserveStorage()

void RelationPreserveStorage ( RelFileNode  rnode,
bool  atCommit 
)

Definition at line 193 of file storage.c.

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

Referenced by ATExecAddIndex(), and write_relmap_file().

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

◆ RelationTruncate()

void RelationTruncate ( Relation  rel,
BlockNumber  nblocks 
)

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

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

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

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

◆ smgrGetPendingDeletes()

int smgrGetPendingDeletes ( bool  forCommit,
RelFileNode **  ptr 
)

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

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

Variable Documentation

◆ pendingDeletes

PendingRelDelete* pendingDeletes = NULL
static

Definition at line 65 of file storage.c.

Referenced by RelationCreateStorage(), and RelationDropStorage().