LCOV - code coverage report
Current view: top level - src/backend/catalog - storage.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 205 212 96.7 %
Date: 2019-11-22 06:06:53 Functions: 12 12 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * storage.c
       4             :  *    code to create and destroy physical storage for relations
       5             :  *
       6             :  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/catalog/storage.c
      12             :  *
      13             :  * NOTES
      14             :  *    Some of this code used to be in storage/smgr/smgr.c, and the
      15             :  *    function names still reflect that.
      16             :  *
      17             :  *-------------------------------------------------------------------------
      18             :  */
      19             : 
      20             : #include "postgres.h"
      21             : 
      22             : #include "access/visibilitymap.h"
      23             : #include "access/xact.h"
      24             : #include "access/xlog.h"
      25             : #include "access/xloginsert.h"
      26             : #include "access/xlogutils.h"
      27             : #include "catalog/storage.h"
      28             : #include "catalog/storage_xlog.h"
      29             : #include "miscadmin.h"
      30             : #include "storage/freespace.h"
      31             : #include "storage/smgr.h"
      32             : #include "utils/memutils.h"
      33             : #include "utils/rel.h"
      34             : 
      35             : /*
      36             :  * We keep a list of all relations (represented as RelFileNode values)
      37             :  * that have been created or deleted in the current transaction.  When
      38             :  * a relation is created, we create the physical file immediately, but
      39             :  * remember it so that we can delete the file again if the current
      40             :  * transaction is aborted.  Conversely, a deletion request is NOT
      41             :  * executed immediately, but is just entered in the list.  When and if
      42             :  * the transaction commits, we can delete the physical file.
      43             :  *
      44             :  * To handle subtransactions, every entry is marked with its transaction
      45             :  * nesting level.  At subtransaction commit, we reassign the subtransaction's
      46             :  * entries to the parent nesting level.  At subtransaction abort, we can
      47             :  * immediately execute the abort-time actions for all entries of the current
      48             :  * nesting level.
      49             :  *
      50             :  * NOTE: the list is kept in TopMemoryContext to be sure it won't disappear
      51             :  * unbetimes.  It'd probably be OK to keep it in TopTransactionContext,
      52             :  * but I'm being paranoid.
      53             :  */
      54             : 
      55             : typedef struct PendingRelDelete
      56             : {
      57             :     RelFileNode relnode;        /* relation that may need to be deleted */
      58             :     BackendId   backend;        /* InvalidBackendId if not a temp rel */
      59             :     bool        atCommit;       /* T=delete at commit; F=delete at abort */
      60             :     int         nestLevel;      /* xact nesting level of request */
      61             :     struct PendingRelDelete *next;  /* linked-list link */
      62             : } PendingRelDelete;
      63             : 
      64             : static PendingRelDelete *pendingDeletes = NULL; /* head of linked list */
      65             : 
      66             : /*
      67             :  * RelationCreateStorage
      68             :  *      Create physical storage for a relation.
      69             :  *
      70             :  * Create the underlying disk file storage for the relation. This only
      71             :  * creates the main fork; additional forks are created lazily by the
      72             :  * modules that need them.
      73             :  *
      74             :  * This function is transactional. The creation is WAL-logged, and if the
      75             :  * transaction aborts later on, the storage will be destroyed.
      76             :  */
      77             : SMgrRelation
      78      135082 : RelationCreateStorage(RelFileNode rnode, char relpersistence)
      79             : {
      80             :     PendingRelDelete *pending;
      81             :     SMgrRelation srel;
      82             :     BackendId   backend;
      83             :     bool        needs_wal;
      84             : 
      85      135082 :     switch (relpersistence)
      86             :     {
      87             :         case RELPERSISTENCE_TEMP:
      88        4796 :             backend = BackendIdForTempRelations();
      89        4796 :             needs_wal = false;
      90        4796 :             break;
      91             :         case RELPERSISTENCE_UNLOGGED:
      92         212 :             backend = InvalidBackendId;
      93         212 :             needs_wal = false;
      94         212 :             break;
      95             :         case RELPERSISTENCE_PERMANENT:
      96      130074 :             backend = InvalidBackendId;
      97      130074 :             needs_wal = true;
      98      130074 :             break;
      99             :         default:
     100           0 :             elog(ERROR, "invalid relpersistence: %c", relpersistence);
     101             :             return NULL;        /* placate compiler */
     102             :     }
     103             : 
     104      135082 :     srel = smgropen(rnode, backend);
     105      135082 :     smgrcreate(srel, MAIN_FORKNUM, false);
     106             : 
     107      135082 :     if (needs_wal)
     108      130074 :         log_smgrcreate(&srel->smgr_rnode.node, MAIN_FORKNUM);
     109             : 
     110             :     /* Add the relation to the list of stuff to delete at abort */
     111      135082 :     pending = (PendingRelDelete *)
     112      135082 :         MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
     113      135082 :     pending->relnode = rnode;
     114      135082 :     pending->backend = backend;
     115      135082 :     pending->atCommit = false;   /* delete if abort */
     116      135082 :     pending->nestLevel = GetCurrentTransactionNestLevel();
     117      135082 :     pending->next = pendingDeletes;
     118      135082 :     pendingDeletes = pending;
     119             : 
     120      135082 :     return srel;
     121             : }
     122             : 
     123             : /*
     124             :  * Perform XLogInsert of an XLOG_SMGR_CREATE record to WAL.
     125             :  */
     126             : void
     127      130194 : log_smgrcreate(const RelFileNode *rnode, ForkNumber forkNum)
     128             : {
     129             :     xl_smgr_create xlrec;
     130             : 
     131             :     /*
     132             :      * Make an XLOG entry reporting the file creation.
     133             :      */
     134      130194 :     xlrec.rnode = *rnode;
     135      130194 :     xlrec.forkNum = forkNum;
     136             : 
     137      130194 :     XLogBeginInsert();
     138      130194 :     XLogRegisterData((char *) &xlrec, sizeof(xlrec));
     139      130194 :     XLogInsert(RM_SMGR_ID, XLOG_SMGR_CREATE | XLR_SPECIAL_REL_UPDATE);
     140      130194 : }
     141             : 
     142             : /*
     143             :  * RelationDropStorage
     144             :  *      Schedule unlinking of physical storage at transaction commit.
     145             :  */
     146             : void
     147       40890 : RelationDropStorage(Relation rel)
     148             : {
     149             :     PendingRelDelete *pending;
     150             : 
     151             :     /* Add the relation to the list of stuff to delete at commit */
     152       40890 :     pending = (PendingRelDelete *)
     153       40890 :         MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
     154       40890 :     pending->relnode = rel->rd_node;
     155       40890 :     pending->backend = rel->rd_backend;
     156       40890 :     pending->atCommit = true;    /* delete if commit */
     157       40890 :     pending->nestLevel = GetCurrentTransactionNestLevel();
     158       40890 :     pending->next = pendingDeletes;
     159       40890 :     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       40890 :     RelationCloseSmgr(rel);
     172       40890 : }
     173             : 
     174             : /*
     175             :  * RelationPreserveStorage
     176             :  *      Mark a relation as not to be deleted after all.
     177             :  *
     178             :  * We need this function because relation mapping changes are committed
     179             :  * separately from commit of the whole transaction, so it's still possible
     180             :  * for the transaction to abort after the mapping update is done.
     181             :  * When a new physical relation is installed in the map, it would be
     182             :  * scheduled for delete-on-abort, so we'd delete it, and be in trouble.
     183             :  * The relation mapper fixes this by telling us to not delete such relations
     184             :  * after all as part of its commit.
     185             :  *
     186             :  * We also use this to reuse an old build of an index during ALTER TABLE, this
     187             :  * time removing the delete-at-commit entry.
     188             :  *
     189             :  * No-op if the relation is not among those scheduled for deletion.
     190             :  */
     191             : void
     192       19642 : RelationPreserveStorage(RelFileNode rnode, bool atCommit)
     193             : {
     194             :     PendingRelDelete *pending;
     195             :     PendingRelDelete *prev;
     196             :     PendingRelDelete *next;
     197             : 
     198       19642 :     prev = NULL;
     199      107400 :     for (pending = pendingDeletes; pending != NULL; pending = next)
     200             :     {
     201       87758 :         next = pending->next;
     202       87758 :         if (RelFileNodeEquals(rnode, pending->relnode)
     203        1448 :             && pending->atCommit == atCommit)
     204             :         {
     205             :             /* unlink and delete list entry */
     206        1448 :             if (prev)
     207         972 :                 prev->next = next;
     208             :             else
     209         476 :                 pendingDeletes = next;
     210        1448 :             pfree(pending);
     211             :             /* prev does not change */
     212             :         }
     213             :         else
     214             :         {
     215             :             /* unrelated entry, don't touch it */
     216       86310 :             prev = pending;
     217             :         }
     218             :     }
     219       19642 : }
     220             : 
     221             : /*
     222             :  * RelationTruncate
     223             :  *      Physically truncate a relation to the specified number of blocks.
     224             :  *
     225             :  * This includes getting rid of any buffers for the blocks that are to be
     226             :  * dropped.
     227             :  */
     228             : void
     229         440 : RelationTruncate(Relation rel, BlockNumber nblocks)
     230             : {
     231             :     bool        fsm;
     232             :     bool        vm;
     233         440 :     bool        need_fsm_vacuum = false;
     234             :     ForkNumber  forks[MAX_FORKNUM];
     235             :     BlockNumber blocks[MAX_FORKNUM];
     236         440 :     int     nforks = 0;
     237             : 
     238             :     /* Open it at the smgr level if not already done */
     239         440 :     RelationOpenSmgr(rel);
     240             : 
     241             :     /*
     242             :      * Make sure smgr_targblock etc aren't pointing somewhere past new end
     243             :      */
     244         440 :     rel->rd_smgr->smgr_targblock = InvalidBlockNumber;
     245         440 :     rel->rd_smgr->smgr_fsm_nblocks = InvalidBlockNumber;
     246         440 :     rel->rd_smgr->smgr_vm_nblocks = InvalidBlockNumber;
     247             : 
     248             :     /* Prepare for truncation of MAIN fork of the relation */
     249         440 :     forks[nforks] = MAIN_FORKNUM;
     250         440 :     blocks[nforks] = nblocks;
     251         440 :     nforks++;
     252             : 
     253             :     /*  Prepare for truncation of the FSM if it exists */
     254         440 :     fsm = smgrexists(rel->rd_smgr, FSM_FORKNUM);
     255         440 :     if (fsm)
     256             :     {
     257         124 :         blocks[nforks] = FreeSpaceMapPrepareTruncateRel(rel, nblocks);
     258         124 :         if (BlockNumberIsValid(blocks[nforks]))
     259             :         {
     260         124 :             forks[nforks] = FSM_FORKNUM;
     261         124 :             nforks++;
     262         124 :             need_fsm_vacuum = true;
     263             :         }
     264             :     }
     265             : 
     266             :     /* Prepare for truncation of the visibility map too if it exists */
     267         440 :     vm = smgrexists(rel->rd_smgr, VISIBILITYMAP_FORKNUM);
     268         440 :     if (vm)
     269             :     {
     270         124 :         blocks[nforks] = visibilitymap_prepare_truncate(rel, nblocks);
     271         124 :         if (BlockNumberIsValid(blocks[nforks]))
     272             :         {
     273          50 :             forks[nforks] = VISIBILITYMAP_FORKNUM;
     274          50 :             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         440 :     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         236 :         xlrec.blkno = nblocks;
     296         236 :         xlrec.rnode = rel->rd_node;
     297         236 :         xlrec.flags = SMGR_TRUNCATE_ALL;
     298             : 
     299         236 :         XLogBeginInsert();
     300         236 :         XLogRegisterData((char *) &xlrec, sizeof(xlrec));
     301             : 
     302         236 :         lsn = XLogInsert(RM_SMGR_ID,
     303             :                          XLOG_SMGR_TRUNCATE | XLR_SPECIAL_REL_UPDATE);
     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         236 :         if (fsm || vm)
     313         124 :             XLogFlush(lsn);
     314             :     }
     315             : 
     316             :     /* Do the real work to truncate relation forks */
     317         440 :     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         440 :     if (need_fsm_vacuum)
     325         124 :         FreeSpaceMapVacuumRange(rel, nblocks, InvalidBlockNumber);
     326         440 : }
     327             : 
     328             : /*
     329             :  * Copy a fork's data, block by block.
     330             :  *
     331             :  * Note that this requires that there is no dirty data in shared buffers. If
     332             :  * it's possible that there are, callers need to flush those using
     333             :  * e.g. FlushRelationBuffers(rel).
     334             :  */
     335             : void
     336          46 : RelationCopyStorage(SMgrRelation src, SMgrRelation dst,
     337             :                     ForkNumber forkNum, char relpersistence)
     338             : {
     339             :     PGAlignedBlock buf;
     340             :     Page        page;
     341             :     bool        use_wal;
     342             :     bool        copying_initfork;
     343             :     BlockNumber nblocks;
     344             :     BlockNumber blkno;
     345             : 
     346          46 :     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          46 :     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          90 :     use_wal = XLogIsNeeded() &&
     361           0 :         (relpersistence == RELPERSISTENCE_PERMANENT || copying_initfork);
     362             : 
     363          46 :     nblocks = smgrnblocks(src, forkNum);
     364             : 
     365         192 :     for (blkno = 0; blkno < nblocks; blkno++)
     366             :     {
     367             :         /* If we got a cancel signal during the copy of the data, quit */
     368         146 :         CHECK_FOR_INTERRUPTS();
     369             : 
     370         146 :         smgrread(src, forkNum, blkno, buf.data);
     371             : 
     372         146 :         if (!PageIsVerified(page, blkno))
     373           0 :             ereport(ERROR,
     374             :                     (errcode(ERRCODE_DATA_CORRUPTED),
     375             :                      errmsg("invalid page in block %u of relation %s",
     376             :                             blkno,
     377             :                             relpathbackend(src->smgr_rnode.node,
     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         146 :         if (use_wal)
     387          56 :             log_newpage(&dst->smgr_rnode.node, forkNum, blkno, page, false);
     388             : 
     389         146 :         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         146 :         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          46 :     if (relpersistence == RELPERSISTENCE_PERMANENT || copying_initfork)
     415          46 :         smgrimmedsync(dst, forkNum);
     416          46 : }
     417             : 
     418             : /*
     419             :  *  smgrDoPendingDeletes() -- Take care of relation deletes at end of xact.
     420             :  *
     421             :  * This also runs when aborting a subxact; we want to clean up a failed
     422             :  * subxact immediately.
     423             :  *
     424             :  * Note: It's possible that we're being asked to remove a relation that has
     425             :  * no physical storage in any fork. In particular, it's possible that we're
     426             :  * cleaning up an old temporary relation for which RemovePgTempFiles has
     427             :  * already recovered the physical storage.
     428             :  */
     429             : void
     430      461756 : smgrDoPendingDeletes(bool isCommit)
     431             : {
     432      461756 :     int         nestLevel = GetCurrentTransactionNestLevel();
     433             :     PendingRelDelete *pending;
     434             :     PendingRelDelete *prev;
     435             :     PendingRelDelete *next;
     436      461756 :     int         nrels = 0,
     437      461756 :                 i = 0,
     438      461756 :                 maxrels = 0;
     439      461756 :     SMgrRelation *srels = NULL;
     440             : 
     441      461756 :     prev = NULL;
     442      639490 :     for (pending = pendingDeletes; pending != NULL; pending = next)
     443             :     {
     444      177734 :         next = pending->next;
     445      177734 :         if (pending->nestLevel < nestLevel)
     446             :         {
     447             :             /* outer-level entries should not be processed yet */
     448        3250 :             prev = pending;
     449             :         }
     450             :         else
     451             :         {
     452             :             /* unlink list entry first, so we don't retry on failure */
     453      174484 :             if (prev)
     454           0 :                 prev->next = next;
     455             :             else
     456      174484 :                 pendingDeletes = next;
     457             :             /* do deletion if called for */
     458      174484 :             if (pending->atCommit == isCommit)
     459             :             {
     460             :                 SMgrRelation srel;
     461             : 
     462       42036 :                 srel = smgropen(pending->relnode, pending->backend);
     463             : 
     464             :                 /* allocate the initial array, or extend it, if needed */
     465       42036 :                 if (maxrels == 0)
     466             :                 {
     467       12292 :                     maxrels = 8;
     468       12292 :                     srels = palloc(sizeof(SMgrRelation) * maxrels);
     469             :                 }
     470       29744 :                 else if (maxrels <= nrels)
     471             :                 {
     472         868 :                     maxrels *= 2;
     473         868 :                     srels = repalloc(srels, sizeof(SMgrRelation) * maxrels);
     474             :                 }
     475             : 
     476       42036 :                 srels[nrels++] = srel;
     477             :             }
     478             :             /* must explicitly free the list entry */
     479      174484 :             pfree(pending);
     480             :             /* prev does not change */
     481             :         }
     482             :     }
     483             : 
     484      461756 :     if (nrels > 0)
     485             :     {
     486       12292 :         smgrdounlinkall(srels, nrels, false);
     487             : 
     488       54328 :         for (i = 0; i < nrels; i++)
     489       42036 :             smgrclose(srels[i]);
     490             : 
     491       12292 :         pfree(srels);
     492             :     }
     493      461756 : }
     494             : 
     495             : /*
     496             :  * smgrGetPendingDeletes() -- Get a list of non-temp relations to be deleted.
     497             :  *
     498             :  * The return value is the number of relations scheduled for termination.
     499             :  * *ptr is set to point to a freshly-palloc'd array of RelFileNodes.
     500             :  * If there are no relations to be deleted, *ptr is set to NULL.
     501             :  *
     502             :  * Only non-temporary relations are included in the returned list.  This is OK
     503             :  * because the list is used only in contexts where temporary relations don't
     504             :  * matter: we're either writing to the two-phase state file (and transactions
     505             :  * that have touched temp tables can't be prepared) or we're writing to xlog
     506             :  * (and all temporary files will be zapped if we restart anyway, so no need
     507             :  * for redo to do it also).
     508             :  *
     509             :  * Note that the list does not include anything scheduled for termination
     510             :  * by upper-level transactions.
     511             :  */
     512             : int
     513      443610 : smgrGetPendingDeletes(bool forCommit, RelFileNode **ptr)
     514             : {
     515      443610 :     int         nestLevel = GetCurrentTransactionNestLevel();
     516             :     int         nrels;
     517             :     RelFileNode *rptr;
     518             :     PendingRelDelete *pending;
     519             : 
     520      443610 :     nrels = 0;
     521      619134 :     for (pending = pendingDeletes; pending != NULL; pending = pending->next)
     522             :     {
     523      175524 :         if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit
     524       42076 :             && pending->backend == InvalidBackendId)
     525       37280 :             nrels++;
     526             :     }
     527      443610 :     if (nrels == 0)
     528             :     {
     529      432640 :         *ptr = NULL;
     530      432640 :         return 0;
     531             :     }
     532       10970 :     rptr = (RelFileNode *) palloc(nrels * sizeof(RelFileNode));
     533       10970 :     *ptr = rptr;
     534       57938 :     for (pending = pendingDeletes; pending != NULL; pending = pending->next)
     535             :     {
     536       46968 :         if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit
     537       37314 :             && pending->backend == InvalidBackendId)
     538             :         {
     539       37280 :             *rptr = pending->relnode;
     540       37280 :             rptr++;
     541             :         }
     542             :     }
     543       10970 :     return nrels;
     544             : }
     545             : 
     546             : /*
     547             :  *  PostPrepare_smgr -- Clean up after a successful PREPARE
     548             :  *
     549             :  * What we have to do here is throw away the in-memory state about pending
     550             :  * relation deletes.  It's all been recorded in the 2PC state file and
     551             :  * it's no longer smgr's job to worry about it.
     552             :  */
     553             : void
     554          56 : PostPrepare_smgr(void)
     555             : {
     556             :     PendingRelDelete *pending;
     557             :     PendingRelDelete *next;
     558             : 
     559          96 :     for (pending = pendingDeletes; pending != NULL; pending = next)
     560             :     {
     561          40 :         next = pending->next;
     562          40 :         pendingDeletes = next;
     563             :         /* must explicitly free the list entry */
     564          40 :         pfree(pending);
     565             :     }
     566          56 : }
     567             : 
     568             : 
     569             : /*
     570             :  * AtSubCommit_smgr() --- Take care of subtransaction commit.
     571             :  *
     572             :  * Reassign all items in the pending-deletes list to the parent transaction.
     573             :  */
     574             : void
     575        4428 : AtSubCommit_smgr(void)
     576             : {
     577        4428 :     int         nestLevel = GetCurrentTransactionNestLevel();
     578             :     PendingRelDelete *pending;
     579             : 
     580        4672 :     for (pending = pendingDeletes; pending != NULL; pending = pending->next)
     581             :     {
     582         244 :         if (pending->nestLevel >= nestLevel)
     583         118 :             pending->nestLevel = nestLevel - 1;
     584             :     }
     585        4428 : }
     586             : 
     587             : /*
     588             :  * AtSubAbort_smgr() --- Take care of subtransaction abort.
     589             :  *
     590             :  * Delete created relations and forget about deleted relations.
     591             :  * We can execute these operations immediately because we know this
     592             :  * subtransaction will not commit.
     593             :  */
     594             : void
     595        2914 : AtSubAbort_smgr(void)
     596             : {
     597        2914 :     smgrDoPendingDeletes(false);
     598        2914 : }
     599             : 
     600             : void
     601         112 : smgr_redo(XLogReaderState *record)
     602             : {
     603         112 :     XLogRecPtr  lsn = record->EndRecPtr;
     604         112 :     uint8       info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
     605             : 
     606             :     /* Backup blocks are not used in smgr records */
     607             :     Assert(!XLogRecHasAnyBlockRefs(record));
     608             : 
     609         112 :     if (info == XLOG_SMGR_CREATE)
     610             :     {
     611         108 :         xl_smgr_create *xlrec = (xl_smgr_create *) XLogRecGetData(record);
     612             :         SMgrRelation reln;
     613             : 
     614         108 :         reln = smgropen(xlrec->rnode, InvalidBackendId);
     615         108 :         smgrcreate(reln, xlrec->forkNum, true);
     616             :     }
     617           4 :     else if (info == XLOG_SMGR_TRUNCATE)
     618             :     {
     619           4 :         xl_smgr_truncate *xlrec = (xl_smgr_truncate *) XLogRecGetData(record);
     620             :         SMgrRelation reln;
     621             :         Relation    rel;
     622             :         ForkNumber  forks[MAX_FORKNUM];
     623             :         BlockNumber blocks[MAX_FORKNUM];
     624           4 :         int     nforks = 0;
     625           4 :         bool        need_fsm_vacuum = false;
     626             : 
     627           4 :         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           4 :         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           4 :         XLogFlush(lsn);
     653             : 
     654             :         /* Prepare for truncation of MAIN fork */
     655           4 :         if ((xlrec->flags & SMGR_TRUNCATE_HEAP) != 0)
     656             :         {
     657           4 :             forks[nforks] = MAIN_FORKNUM;
     658           4 :             blocks[nforks] = xlrec->blkno;
     659           4 :             nforks++;
     660             : 
     661             :             /* Also tell xlogutils.c about it */
     662           4 :             XLogTruncateRelation(xlrec->rnode, MAIN_FORKNUM, xlrec->blkno);
     663             :         }
     664             : 
     665             :         /* Prepare for truncation of FSM and VM too */
     666           4 :         rel = CreateFakeRelcacheEntry(xlrec->rnode);
     667             : 
     668           8 :         if ((xlrec->flags & SMGR_TRUNCATE_FSM) != 0 &&
     669           4 :             smgrexists(reln, FSM_FORKNUM))
     670             :         {
     671           4 :             blocks[nforks] = FreeSpaceMapPrepareTruncateRel(rel, xlrec->blkno);
     672           4 :             if (BlockNumberIsValid(blocks[nforks]))
     673             :             {
     674           4 :                 forks[nforks] = FSM_FORKNUM;
     675           4 :                 nforks++;
     676           4 :                 need_fsm_vacuum = true;
     677             :             }
     678             :         }
     679           8 :         if ((xlrec->flags & SMGR_TRUNCATE_VM) != 0 &&
     680           4 :             smgrexists(reln, VISIBILITYMAP_FORKNUM))
     681             :         {
     682           4 :             blocks[nforks] = visibilitymap_prepare_truncate(rel, xlrec->blkno);
     683           4 :             if (BlockNumberIsValid(blocks[nforks]))
     684             :             {
     685           0 :                 forks[nforks] = VISIBILITYMAP_FORKNUM;
     686           0 :                 nforks++;
     687             :             }
     688             :         }
     689             : 
     690             :         /* Do the real work to truncate relation forks */
     691           4 :         if (nforks > 0)
     692           4 :             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           4 :         if (need_fsm_vacuum)
     700           4 :             FreeSpaceMapVacuumRange(rel, xlrec->blkno,
     701             :                                     InvalidBlockNumber);
     702             : 
     703           4 :         FreeFakeRelcacheEntry(rel);
     704             :     }
     705             :     else
     706           0 :         elog(PANIC, "smgr_redo: unknown op code %u", info);
     707         112 : }

Generated by: LCOV version 1.13