Header And Logo

PostgreSQL
| The world's most advanced open source database.

Functions

storage.h File Reference

#include "storage/block.h"
#include "storage/relfilenode.h"
#include "utils/relcache.h"
Include dependency graph for storage.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

void RelationCreateStorage (RelFileNode rnode, char relpersistence)
void RelationDropStorage (Relation rel)
void RelationPreserveStorage (RelFileNode rnode, bool atCommit)
void RelationTruncate (Relation rel, BlockNumber nblocks)
void smgrDoPendingDeletes (bool isCommit)
int smgrGetPendingDeletes (bool forCommit, RelFileNode **ptr)
void AtSubCommit_smgr (void)
void AtSubAbort_smgr (void)
void PostPrepare_smgr (void)

Function Documentation

void AtSubAbort_smgr ( void   ) 

Definition at line 470 of file storage.c.

References smgrDoPendingDeletes().

Referenced by AbortSubTransaction().

void AtSubCommit_smgr ( void   ) 

Definition at line 450 of file storage.c.

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

Referenced by CommitSubTransaction().

{
    int         nestLevel = GetCurrentTransactionNestLevel();
    PendingRelDelete *pending;

    for (pending = pendingDeletes; pending != NULL; pending = pending->next)
    {
        if (pending->nestLevel >= nestLevel)
            pending->nestLevel = nestLevel - 1;
    }
}

void PostPrepare_smgr ( void   ) 

Definition at line 429 of file storage.c.

References PendingRelDelete::next, and pfree().

Referenced by PrepareTransaction().

{
    PendingRelDelete *pending;
    PendingRelDelete *next;

    for (pending = pendingDeletes; pending != NULL; pending = next)
    {
        next = pending->next;
        pendingDeletes = next;
        /* must explicitly free the list entry */
        pfree(pending);
    }
}

void RelationCreateStorage ( RelFileNode  rnode,
char  relpersistence 
)

Definition at line 76 of file storage.c.

References PendingRelDelete::atCommit, PendingRelDelete::backend, elog, ERROR, GetCurrentTransactionNestLevel(), log_smgrcreate(), MAIN_FORKNUM, MemoryContextAlloc(), MyBackendId, PendingRelDelete::nestLevel, PendingRelDelete::next, RelFileNodeBackend::node, PendingRelDelete::relnode, RELPERSISTENCE_PERMANENT, RELPERSISTENCE_TEMP, RELPERSISTENCE_UNLOGGED, SMgrRelationData::smgr_rnode, smgrcreate(), smgropen(), and TopMemoryContext.

Referenced by ATExecSetTableSpace(), heap_create(), and RelationSetNewRelfilenode().

{
    PendingRelDelete *pending;
    SMgrRelation srel;
    BackendId   backend;
    bool        needs_wal;

    switch (relpersistence)
    {
        case RELPERSISTENCE_TEMP:
            backend = MyBackendId;
            needs_wal = false;
            break;
        case RELPERSISTENCE_UNLOGGED:
            backend = InvalidBackendId;
            needs_wal = false;
            break;
        case RELPERSISTENCE_PERMANENT:
            backend = InvalidBackendId;
            needs_wal = true;
            break;
        default:
            elog(ERROR, "invalid relpersistence: %c", relpersistence);
            return;             /* placate compiler */
    }

    srel = smgropen(rnode, backend);
    smgrcreate(srel, MAIN_FORKNUM, false);

    if (needs_wal)
        log_smgrcreate(&srel->smgr_rnode.node, MAIN_FORKNUM);

    /* Add the relation to the list of stuff to delete at abort */
    pending = (PendingRelDelete *)
        MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
    pending->relnode = rnode;
    pending->backend = backend;
    pending->atCommit = false;  /* delete if abort */
    pending->nestLevel = GetCurrentTransactionNestLevel();
    pending->next = pendingDeletes;
    pendingDeletes = pending;
}

void RelationDropStorage ( Relation  rel  ) 

Definition at line 147 of file storage.c.

References PendingRelDelete::atCommit, PendingRelDelete::backend, GetCurrentTransactionNestLevel(), MemoryContextAlloc(), PendingRelDelete::nestLevel, PendingRelDelete::next, RelationData::rd_backend, RelationData::rd_node, RelationCloseSmgr, PendingRelDelete::relnode, and TopMemoryContext.

Referenced by ATExecSetTableSpace(), DefineQueryRewrite(), heap_drop_with_catalog(), index_drop(), and RelationSetNewRelfilenode().

{
    PendingRelDelete *pending;

    /* Add the relation to the list of stuff to delete at commit */
    pending = (PendingRelDelete *)
        MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
    pending->relnode = rel->rd_node;
    pending->backend = rel->rd_backend;
    pending->atCommit = true;   /* delete if commit */
    pending->nestLevel = GetCurrentTransactionNestLevel();
    pending->next = pendingDeletes;
    pendingDeletes = pending;

    /*
     * NOTE: if the relation was created in this transaction, it will now be
     * present in the pending-delete list twice, once with atCommit true and
     * once with atCommit false.  Hence, it will be physically deleted at end
     * of xact in either case (and the other entry will be ignored by
     * smgrDoPendingDeletes, so no error will occur).  We could instead remove
     * the existing list entry and delete the physical file immediately, but
     * for now I'll keep the logic simple.
     */

    RelationCloseSmgr(rel);
}

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

{
    PendingRelDelete *pending;
    PendingRelDelete *prev;
    PendingRelDelete *next;

    prev = NULL;
    for (pending = pendingDeletes; pending != NULL; pending = next)
    {
        next = pending->next;
        if (RelFileNodeEquals(rnode, pending->relnode)
            && pending->atCommit == atCommit)
        {
            /* unlink and delete list entry */
            if (prev)
                prev->next = next;
            else
                pendingDeletes = next;
            pfree(pending);
            /* prev does not change */
        }
        else
        {
            /* unrelated entry, don't touch it */
            prev = pending;
        }
    }
}

void RelationTruncate ( Relation  rel,
BlockNumber  nblocks 
)

Definition at line 229 of file storage.c.

References xl_smgr_truncate::blkno, XLogRecData::buffer, XLogRecData::data, FreeSpaceMapTruncateRel(), FSM_FORKNUM, XLogRecData::len, MAIN_FORKNUM, XLogRecData::next, RelationData::rd_node, RelationData::rd_smgr, RelationNeedsWAL, RelationOpenSmgr, xl_smgr_truncate::rnode, SMgrRelationData::smgr_fsm_nblocks, SMgrRelationData::smgr_targblock, SMgrRelationData::smgr_vm_nblocks, smgrexists(), smgrtruncate(), VISIBILITYMAP_FORKNUM, visibilitymap_truncate(), XLOG_SMGR_TRUNCATE, XLogFlush(), and XLogInsert().

Referenced by heap_truncate_one_rel(), lazy_truncate_heap(), RelationTruncateIndexes(), and spgvacuumscan().

{
    bool        fsm;
    bool        vm;

    /* Open it at the smgr level if not already done */
    RelationOpenSmgr(rel);

    /*
     * Make sure smgr_targblock etc aren't pointing somewhere past new end
     */
    rel->rd_smgr->smgr_targblock = InvalidBlockNumber;
    rel->rd_smgr->smgr_fsm_nblocks = InvalidBlockNumber;
    rel->rd_smgr->smgr_vm_nblocks = InvalidBlockNumber;

    /* Truncate the FSM first if it exists */
    fsm = smgrexists(rel->rd_smgr, FSM_FORKNUM);
    if (fsm)
        FreeSpaceMapTruncateRel(rel, nblocks);

    /* Truncate the visibility map too if it exists. */
    vm = smgrexists(rel->rd_smgr, VISIBILITYMAP_FORKNUM);
    if (vm)
        visibilitymap_truncate(rel, nblocks);

    /*
     * We WAL-log the truncation before actually truncating, which means
     * trouble if the truncation fails. If we then crash, the WAL replay
     * likely isn't going to succeed in the truncation either, and cause a
     * PANIC. It's tempting to put a critical section here, but that cure
     * would be worse than the disease. It would turn a usually harmless
     * failure to truncate, that might spell trouble at WAL replay, into a
     * certain PANIC.
     */
    if (RelationNeedsWAL(rel))
    {
        /*
         * Make an XLOG entry reporting the file truncation.
         */
        XLogRecPtr  lsn;
        XLogRecData rdata;
        xl_smgr_truncate xlrec;

        xlrec.blkno = nblocks;
        xlrec.rnode = rel->rd_node;

        rdata.data = (char *) &xlrec;
        rdata.len = sizeof(xlrec);
        rdata.buffer = InvalidBuffer;
        rdata.next = NULL;

        lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_TRUNCATE, &rdata);

        /*
         * Flush, because otherwise the truncation of the main relation might
         * hit the disk before the WAL record, and the truncation of the FSM
         * or visibility map. If we crashed during that window, we'd be left
         * with a truncated heap, but the FSM or visibility map would still
         * contain entries for the non-existent heap pages.
         */
        if (fsm || vm)
            XLogFlush(lsn);
    }

    /* Do the real work */
    smgrtruncate(rel->rd_smgr, MAIN_FORKNUM, nblocks);
}

void smgrDoPendingDeletes ( bool  isCommit  ) 

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

{
    int         nestLevel = GetCurrentTransactionNestLevel();
    PendingRelDelete *pending;
    PendingRelDelete *prev;
    PendingRelDelete *next;
    int         nrels = 0,
                i = 0,
                maxrels = 8;
    SMgrRelation *srels = palloc(maxrels * sizeof(SMgrRelation));

    prev = NULL;
    for (pending = pendingDeletes; pending != NULL; pending = next)
    {
        next = pending->next;
        if (pending->nestLevel < nestLevel)
        {
            /* outer-level entries should not be processed yet */
            prev = pending;
        }
        else
        {
            /* unlink list entry first, so we don't retry on failure */
            if (prev)
                prev->next = next;
            else
                pendingDeletes = next;
            /* do deletion if called for */
            if (pending->atCommit == isCommit)
            {
                SMgrRelation srel;

                srel = smgropen(pending->relnode, pending->backend);

                /* extend the array if needed (double the size) */
                if (maxrels <= nrels)
                {
                    maxrels *= 2;
                    srels = repalloc(srels, sizeof(SMgrRelation) * maxrels);
                }

                srels[nrels++] = srel;
            }
            /* must explicitly free the list entry */
            pfree(pending);
            /* prev does not change */
        }
    }

    if (nrels > 0)
    {
        smgrdounlinkall(srels, nrels, false);

        for (i = 0; i < nrels; i++)
            smgrclose(srels[i]);
    }

    pfree(srels);

}

int smgrGetPendingDeletes ( bool  forCommit,
RelFileNode **  ptr 
)

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

{
    int         nestLevel = GetCurrentTransactionNestLevel();
    int         nrels;
    RelFileNode *rptr;
    PendingRelDelete *pending;

    nrels = 0;
    for (pending = pendingDeletes; pending != NULL; pending = pending->next)
    {
        if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit
            && pending->backend == InvalidBackendId)
            nrels++;
    }
    if (nrels == 0)
    {
        *ptr = NULL;
        return 0;
    }
    rptr = (RelFileNode *) palloc(nrels * sizeof(RelFileNode));
    *ptr = rptr;
    for (pending = pendingDeletes; pending != NULL; pending = pending->next)
    {
        if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit
            && pending->backend == InvalidBackendId)
        {
            *rptr = pending->relnode;
            rptr++;
        }
    }
    return nrels;
}