Header And Logo

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

Data Structures | Defines | Typedefs | Functions | Variables

inval.c File Reference

#include "postgres.h"
#include "access/htup_details.h"
#include "access/xact.h"
#include "catalog/catalog.h"
#include "miscadmin.h"
#include "storage/sinval.h"
#include "storage/smgr.h"
#include "utils/catcache.h"
#include "utils/inval.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/relmapper.h"
#include "utils/syscache.h"
Include dependency graph for inval.c:

Go to the source code of this file.

Data Structures

struct  InvalidationChunk
struct  InvalidationListHeader
struct  TransInvalidationInfo
struct  SYSCACHECALLBACK
struct  RELCACHECALLBACK

Defines

#define MAX_SYSCACHE_CALLBACKS   32
#define MAX_RELCACHE_CALLBACKS   5
#define FIRSTCHUNKSIZE   32
#define ProcessMessageList(listHdr, codeFragment)
#define ProcessMessageListMulti(listHdr, codeFragment)

Typedefs

typedef struct InvalidationChunk InvalidationChunk
typedef struct
InvalidationListHeader 
InvalidationListHeader
typedef struct
TransInvalidationInfo 
TransInvalidationInfo

Functions

static void AddInvalidationMessage (InvalidationChunk **listHdr, SharedInvalidationMessage *msg)
static void AppendInvalidationMessageList (InvalidationChunk **destHdr, InvalidationChunk **srcHdr)
static void AddCatcacheInvalidationMessage (InvalidationListHeader *hdr, int id, uint32 hashValue, Oid dbId)
static void AddCatalogInvalidationMessage (InvalidationListHeader *hdr, Oid dbId, Oid catId)
static void AddRelcacheInvalidationMessage (InvalidationListHeader *hdr, Oid dbId, Oid relId)
static void AppendInvalidationMessages (InvalidationListHeader *dest, InvalidationListHeader *src)
static void ProcessInvalidationMessages (InvalidationListHeader *hdr, void(*func)(SharedInvalidationMessage *msg))
static void ProcessInvalidationMessagesMulti (InvalidationListHeader *hdr, void(*func)(const SharedInvalidationMessage *msgs, int n))
static void RegisterCatcacheInvalidation (int cacheId, uint32 hashValue, Oid dbId)
static void RegisterCatalogInvalidation (Oid dbId, Oid catId)
static void RegisterRelcacheInvalidation (Oid dbId, Oid relId)
static void LocalExecuteInvalidationMessage (SharedInvalidationMessage *msg)
static void InvalidateSystemCaches (void)
void AcceptInvalidationMessages (void)
void AtStart_Inval (void)
void PostPrepare_Inval (void)
void AtSubStart_Inval (void)
static void MakeSharedInvalidMessagesArray (const SharedInvalidationMessage *msgs, int n)
int xactGetCommittedInvalidationMessages (SharedInvalidationMessage **msgs, bool *RelcacheInitFileInval)
void ProcessCommittedInvalidationMessages (SharedInvalidationMessage *msgs, int nmsgs, bool RelcacheInitFileInval, Oid dbid, Oid tsid)
void AtEOXact_Inval (bool isCommit)
void AtEOSubXact_Inval (bool isCommit)
void CommandEndInvalidationMessages (void)
void CacheInvalidateHeapTuple (Relation relation, HeapTuple tuple, HeapTuple newtuple)
void CacheInvalidateCatalog (Oid catalogId)
void CacheInvalidateRelcache (Relation relation)
void CacheInvalidateRelcacheByTuple (HeapTuple classTuple)
void CacheInvalidateRelcacheByRelid (Oid relid)
void CacheInvalidateSmgr (RelFileNodeBackend rnode)
void CacheInvalidateRelmap (Oid databaseId)
void CacheRegisterSyscacheCallback (int cacheid, SyscacheCallbackFunction func, Datum arg)
void CacheRegisterRelcacheCallback (RelcacheCallbackFunction func, Datum arg)
void CallSyscacheCallbacks (int cacheid, uint32 hashvalue)

Variables

static TransInvalidationInfotransInvalInfo = NULL
static SharedInvalidationMessageSharedInvalidMessagesArray
static int numSharedInvalidMessagesArray
static int maxSharedInvalidMessagesArray
static struct SYSCACHECALLBACK syscache_callback_list [MAX_SYSCACHE_CALLBACKS]
static int syscache_callback_count = 0
static struct RELCACHECALLBACK relcache_callback_list [MAX_RELCACHE_CALLBACKS]
static int relcache_callback_count = 0

Define Documentation

#define FIRSTCHUNKSIZE   32

Referenced by AddInvalidationMessage().

#define MAX_RELCACHE_CALLBACKS   5

Definition at line 180 of file inval.c.

Referenced by CacheRegisterRelcacheCallback().

#define MAX_SYSCACHE_CALLBACKS   32

Definition at line 179 of file inval.c.

Referenced by CacheRegisterSyscacheCallback().

#define ProcessMessageList (   listHdr,
  codeFragment 
)
Value:
do { \
        InvalidationChunk *_chunk; \
        for (_chunk = (listHdr); _chunk != NULL; _chunk = _chunk->next) \
        { \
            int     _cindex; \
            for (_cindex = 0; _cindex < _chunk->nitems; _cindex++) \
            { \
                SharedInvalidationMessage *msg = &_chunk->msgs[_cindex]; \
                codeFragment; \
            } \
        } \
    } while (0)

Definition at line 281 of file inval.c.

Referenced by AddRelcacheInvalidationMessage(), and ProcessInvalidationMessages().

#define ProcessMessageListMulti (   listHdr,
  codeFragment 
)
Value:
do { \
        InvalidationChunk *_chunk; \
        for (_chunk = (listHdr); _chunk != NULL; _chunk = _chunk->next) \
        { \
            SharedInvalidationMessage *msgs = _chunk->msgs; \
            int     n = _chunk->nitems; \
            codeFragment; \
        } \
    } while (0)

Definition at line 301 of file inval.c.

Referenced by ProcessInvalidationMessagesMulti().


Typedef Documentation


Function Documentation

void AcceptInvalidationMessages ( void   ) 

Definition at line 588 of file inval.c.

References InvalidateSystemCaches(), LocalExecuteInvalidationMessage(), and ReceiveSharedInvalidMessages().

Referenced by AtStart_Cache(), ConditionalLockRelation(), ConditionalLockRelationOid(), LockDatabaseObject(), LockRelation(), LockRelationOid(), LockSharedObject(), ProcessCatchupEvent(), RangeVarGetRelidExtended(), relation_openrv(), relation_openrv_extended(), RemoveRelations(), and write_relcache_init_file().

{
    ReceiveSharedInvalidMessages(LocalExecuteInvalidationMessage,
                                 InvalidateSystemCaches);

    /*
     * Test code to force cache flushes anytime a flush could happen.
     *
     * If used with CLOBBER_FREED_MEMORY, CLOBBER_CACHE_ALWAYS provides a
     * fairly thorough test that the system contains no cache-flush hazards.
     * However, it also makes the system unbelievably slow --- the regression
     * tests take about 100 times longer than normal.
     *
     * If you're a glutton for punishment, try CLOBBER_CACHE_RECURSIVELY. This
     * slows things by at least a factor of 10000, so I wouldn't suggest
     * trying to run the entire regression tests that way.  It's useful to try
     * a few simple tests, to make sure that cache reload isn't subject to
     * internal cache-flush hazards, but after you've done a few thousand
     * recursive reloads it's unlikely you'll learn more.
     */
#if defined(CLOBBER_CACHE_ALWAYS)
    {
        static bool in_recursion = false;

        if (!in_recursion)
        {
            in_recursion = true;
            InvalidateSystemCaches();
            in_recursion = false;
        }
    }
#elif defined(CLOBBER_CACHE_RECURSIVELY)
    InvalidateSystemCaches();
#endif
}

static void AddCatalogInvalidationMessage ( InvalidationListHeader hdr,
Oid  dbId,
Oid  catId 
) [static]
static void AddCatcacheInvalidationMessage ( InvalidationListHeader hdr,
int  id,
uint32  hashValue,
Oid  dbId 
) [static]
static void AddInvalidationMessage ( InvalidationChunk **  listHdr,
SharedInvalidationMessage msg 
) [static]

Definition at line 215 of file inval.c.

References CurTransactionContext, FIRSTCHUNKSIZE, InvalidationChunk::maxitems, MemoryContextAlloc(), InvalidationChunk::msgs, InvalidationChunk::next, InvalidationChunk::nitems, and NULL.

Referenced by AddCatalogInvalidationMessage(), AddCatcacheInvalidationMessage(), and AddRelcacheInvalidationMessage().

{
    InvalidationChunk *chunk = *listHdr;

    if (chunk == NULL)
    {
        /* First time through; create initial chunk */
#define FIRSTCHUNKSIZE 32
        chunk = (InvalidationChunk *)
            MemoryContextAlloc(CurTransactionContext,
                               sizeof(InvalidationChunk) +
                    (FIRSTCHUNKSIZE - 1) *sizeof(SharedInvalidationMessage));
        chunk->nitems = 0;
        chunk->maxitems = FIRSTCHUNKSIZE;
        chunk->next = *listHdr;
        *listHdr = chunk;
    }
    else if (chunk->nitems >= chunk->maxitems)
    {
        /* Need another chunk; double size of last chunk */
        int         chunksize = 2 * chunk->maxitems;

        chunk = (InvalidationChunk *)
            MemoryContextAlloc(CurTransactionContext,
                               sizeof(InvalidationChunk) +
                         (chunksize - 1) *sizeof(SharedInvalidationMessage));
        chunk->nitems = 0;
        chunk->maxitems = chunksize;
        chunk->next = *listHdr;
        *listHdr = chunk;
    }
    /* Okay, add message to current chunk */
    chunk->msgs[chunk->nitems] = *msg;
    chunk->nitems++;
}

static void AddRelcacheInvalidationMessage ( InvalidationListHeader hdr,
Oid  dbId,
Oid  relId 
) [static]

Definition at line 356 of file inval.c.

References AddInvalidationMessage(), SharedInvalRelcacheMsg::dbId, SharedInvalRelcacheMsg::id, ProcessMessageList, SharedInvalidationMessage::rc, InvalidationListHeader::rclist, SharedInvalRelcacheMsg::relId, and SHAREDINVALRELCACHE_ID.

Referenced by RegisterRelcacheInvalidation().

{
    SharedInvalidationMessage msg;

    /* Don't add a duplicate item */
    /* We assume dbId need not be checked because it will never change */
    ProcessMessageList(hdr->rclist,
                       if (msg->rc.id == SHAREDINVALRELCACHE_ID &&
                           msg->rc.relId == relId)
                       return);

    /* OK, add the item */
    msg.rc.id = SHAREDINVALRELCACHE_ID;
    msg.rc.dbId = dbId;
    msg.rc.relId = relId;
    AddInvalidationMessage(&hdr->rclist, &msg);
}

static void AppendInvalidationMessageList ( InvalidationChunk **  destHdr,
InvalidationChunk **  srcHdr 
) [static]

Definition at line 257 of file inval.c.

References InvalidationChunk::next, and NULL.

Referenced by AppendInvalidationMessages().

{
    InvalidationChunk *chunk = *srcHdr;

    if (chunk == NULL)
        return;                 /* nothing to do */

    while (chunk->next != NULL)
        chunk = chunk->next;

    chunk->next = *destHdr;

    *destHdr = *srcHdr;

    *srcHdr = NULL;
}

static void AppendInvalidationMessages ( InvalidationListHeader dest,
InvalidationListHeader src 
) [static]
void AtEOSubXact_Inval ( bool  isCommit  ) 

Definition at line 890 of file inval.c.

References AppendInvalidationMessages(), Assert, CommandEndInvalidationMessages(), GetCurrentTransactionNestLevel(), LocalExecuteInvalidationMessage(), TransInvalidationInfo::my_level, NULL, TransInvalidationInfo::parent, pfree(), TransInvalidationInfo::PriorCmdInvalidMsgs, ProcessInvalidationMessages(), and TransInvalidationInfo::RelcacheInitFileInval.

Referenced by AbortSubTransaction(), and CommitSubTransaction().

{
    int         my_level = GetCurrentTransactionNestLevel();
    TransInvalidationInfo *myInfo = transInvalInfo;

    if (isCommit)
    {
        /* Must be at non-top of stack */
        Assert(myInfo != NULL && myInfo->parent != NULL);
        Assert(myInfo->my_level == my_level);

        /* If CurrentCmdInvalidMsgs still has anything, fix it */
        CommandEndInvalidationMessages();

        /* Pass up my inval messages to parent */
        AppendInvalidationMessages(&myInfo->parent->PriorCmdInvalidMsgs,
                                   &myInfo->PriorCmdInvalidMsgs);

        /* Pending relcache inval becomes parent's problem too */
        if (myInfo->RelcacheInitFileInval)
            myInfo->parent->RelcacheInitFileInval = true;

        /* Pop the transaction state stack */
        transInvalInfo = myInfo->parent;

        /* Need not free anything else explicitly */
        pfree(myInfo);
    }
    else if (myInfo != NULL && myInfo->my_level == my_level)
    {
        /* Must be at non-top of stack */
        Assert(myInfo->parent != NULL);

        ProcessInvalidationMessages(&myInfo->PriorCmdInvalidMsgs,
                                    LocalExecuteInvalidationMessage);

        /* Pop the transaction state stack */
        transInvalInfo = myInfo->parent;

        /* Need not free anything else explicitly */
        pfree(myInfo);
    }
}

void AtEOXact_Inval ( bool  isCommit  ) 
void AtStart_Inval ( void   ) 
void AtSubStart_Inval ( void   ) 
void CacheInvalidateCatalog ( Oid  catalogId  ) 

Definition at line 1082 of file inval.c.

References IsSharedRelation(), MyDatabaseId, and RegisterCatalogInvalidation().

Referenced by finish_heap_swap().

{
    Oid         databaseId;

    if (IsSharedRelation(catalogId))
        databaseId = InvalidOid;
    else
        databaseId = MyDatabaseId;

    RegisterCatalogInvalidation(databaseId, catalogId);
}

void CacheInvalidateHeapTuple ( Relation  relation,
HeapTuple  tuple,
HeapTuple  newtuple 
)

Definition at line 979 of file inval.c.

References AttributeRelationId, GETSTRUCT, HeapTupleGetOid, IndexRelationId, IsBootstrapProcessingMode, IsSystemRelation(), IsToastRelation(), MyDatabaseId, PrepareToInvalidateCacheTuple(), RegisterCatcacheInvalidation(), RegisterRelcacheInvalidation(), RelationGetRelid, and RelationRelationId.

Referenced by heap_delete(), heap_inplace_update(), heap_insert(), heap_multi_insert(), and heap_update().

{
    Oid         tupleRelId;
    Oid         databaseId;
    Oid         relationId;

    /* Do nothing during bootstrap */
    if (IsBootstrapProcessingMode())
        return;

    /*
     * We only need to worry about invalidation for tuples that are in system
     * relations; user-relation tuples are never in catcaches and can't affect
     * the relcache either.
     */
    if (!IsSystemRelation(relation))
        return;

    /*
     * TOAST tuples can likewise be ignored here. Note that TOAST tables are
     * considered system relations so they are not filtered by the above test.
     */
    if (IsToastRelation(relation))
        return;

    /*
     * First let the catcache do its thing
     */
    PrepareToInvalidateCacheTuple(relation, tuple, newtuple,
                                  RegisterCatcacheInvalidation);

    /*
     * Now, is this tuple one of the primary definers of a relcache entry?
     *
     * Note we ignore newtuple here; we assume an update cannot move a tuple
     * from being part of one relcache entry to being part of another.
     */
    tupleRelId = RelationGetRelid(relation);

    if (tupleRelId == RelationRelationId)
    {
        Form_pg_class classtup = (Form_pg_class) GETSTRUCT(tuple);

        relationId = HeapTupleGetOid(tuple);
        if (classtup->relisshared)
            databaseId = InvalidOid;
        else
            databaseId = MyDatabaseId;
    }
    else if (tupleRelId == AttributeRelationId)
    {
        Form_pg_attribute atttup = (Form_pg_attribute) GETSTRUCT(tuple);

        relationId = atttup->attrelid;

        /*
         * KLUGE ALERT: we always send the relcache event with MyDatabaseId,
         * even if the rel in question is shared (which we can't easily tell).
         * This essentially means that only backends in this same database
         * will react to the relcache flush request.  This is in fact
         * appropriate, since only those backends could see our pg_attribute
         * change anyway.  It looks a bit ugly though.  (In practice, shared
         * relations can't have schema changes after bootstrap, so we should
         * never come here for a shared rel anyway.)
         */
        databaseId = MyDatabaseId;
    }
    else if (tupleRelId == IndexRelationId)
    {
        Form_pg_index indextup = (Form_pg_index) GETSTRUCT(tuple);

        /*
         * When a pg_index row is updated, we should send out a relcache inval
         * for the index relation.  As above, we don't know the shared status
         * of the index, but in practice it doesn't matter since indexes of
         * shared catalogs can't have such updates.
         */
        relationId = indextup->indexrelid;
        databaseId = MyDatabaseId;
    }
    else
        return;

    /*
     * Yes.  We need to register a relcache invalidation event.
     */
    RegisterRelcacheInvalidation(databaseId, relationId);
}

void CacheInvalidateRelcache ( Relation  relation  ) 
void CacheInvalidateRelcacheByRelid ( Oid  relid  ) 

Definition at line 1144 of file inval.c.

References CacheInvalidateRelcacheByTuple(), elog, ERROR, HeapTupleIsValid, ObjectIdGetDatum, ReleaseSysCache(), RELOID, and SearchSysCache1.

Referenced by DefineIndex().

{
    HeapTuple   tup;

    tup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
    if (!HeapTupleIsValid(tup))
        elog(ERROR, "cache lookup failed for relation %u", relid);
    CacheInvalidateRelcacheByTuple(tup);
    ReleaseSysCache(tup);
}

void CacheInvalidateRelcacheByTuple ( HeapTuple  classTuple  ) 

Definition at line 1123 of file inval.c.

References GETSTRUCT, HeapTupleGetOid, MyDatabaseId, and RegisterRelcacheInvalidation().

Referenced by CacheInvalidateRelcacheByRelid(), index_update_stats(), SetRelationHasSubclass(), SetRelationRuleStatus(), and swap_relation_files().

{
    Form_pg_class classtup = (Form_pg_class) GETSTRUCT(classTuple);
    Oid         databaseId;
    Oid         relationId;

    relationId = HeapTupleGetOid(classTuple);
    if (classtup->relisshared)
        databaseId = InvalidOid;
    else
        databaseId = MyDatabaseId;
    RegisterRelcacheInvalidation(databaseId, relationId);
}

void CacheInvalidateRelmap ( Oid  databaseId  ) 

Definition at line 1209 of file inval.c.

References SharedInvalRelmapMsg::dbId, SharedInvalRelmapMsg::id, SharedInvalidationMessage::rm, and SendSharedInvalidMessages().

Referenced by write_relmap_file().

{
    SharedInvalidationMessage msg;

    msg.rm.id = SHAREDINVALRELMAP_ID;
    msg.rm.dbId = databaseId;
    SendSharedInvalidMessages(&msg, 1);
}

void CacheInvalidateSmgr ( RelFileNodeBackend  rnode  ) 
void CacheRegisterRelcacheCallback ( RelcacheCallbackFunction  func,
Datum  arg 
)
void CacheRegisterSyscacheCallback ( int  cacheid,
SyscacheCallbackFunction  func,
Datum  arg 
)
void CallSyscacheCallbacks ( int  cacheid,
uint32  hashvalue 
)

Definition at line 1276 of file inval.c.

References SYSCACHECALLBACK::arg, SYSCACHECALLBACK::function, i, SYSCACHECALLBACK::id, syscache_callback_count, and syscache_callback_list.

Referenced by CatalogCacheFlushCatalog(), and LocalExecuteInvalidationMessage().

{
    int         i;

    for (i = 0; i < syscache_callback_count; i++)
    {
        struct SYSCACHECALLBACK *ccitem = syscache_callback_list + i;

        if (ccitem->id == cacheid)
            (*ccitem->function) (ccitem->arg, cacheid, hashvalue);
    }
}

void CommandEndInvalidationMessages ( void   ) 

Definition at line 950 of file inval.c.

References AppendInvalidationMessages(), TransInvalidationInfo::CurrentCmdInvalidMsgs, LocalExecuteInvalidationMessage(), NULL, TransInvalidationInfo::PriorCmdInvalidMsgs, and ProcessInvalidationMessages().

Referenced by AtCCI_LocalCache(), and AtEOSubXact_Inval().

{
    /*
     * You might think this shouldn't be called outside any transaction, but
     * bootstrap does it, and also ABORT issued when not in a transaction. So
     * just quietly return if no state to work on.
     */
    if (transInvalInfo == NULL)
        return;

    ProcessInvalidationMessages(&transInvalInfo->CurrentCmdInvalidMsgs,
                                LocalExecuteInvalidationMessage);
    AppendInvalidationMessages(&transInvalInfo->PriorCmdInvalidMsgs,
                               &transInvalInfo->CurrentCmdInvalidMsgs);
}

static void InvalidateSystemCaches ( void   )  [static]
static void LocalExecuteInvalidationMessage ( SharedInvalidationMessage msg  )  [static]

Definition at line 479 of file inval.c.

References RELCACHECALLBACK::arg, RelFileNodeBackend::backend, SharedInvalSmgrMsg::backend_hi, SharedInvalSmgrMsg::backend_lo, CallSyscacheCallbacks(), SharedInvalidationMessage::cat, CatalogCacheFlushCatalog(), CatalogCacheIdInvalidate(), SharedInvalCatalogMsg::catId, SharedInvalidationMessage::cc, SharedInvalRelmapMsg::dbId, SharedInvalRelcacheMsg::dbId, SharedInvalCatalogMsg::dbId, SharedInvalCatcacheMsg::dbId, elog, FATAL, RELCACHECALLBACK::function, SharedInvalCatcacheMsg::hashValue, i, SharedInvalCatcacheMsg::id, SharedInvalidationMessage::id, InvalidOid, MyDatabaseId, RelFileNodeBackend::node, SharedInvalidationMessage::rc, RelationCacheInvalidateEntry(), RelationMapInvalidate(), relcache_callback_count, relcache_callback_list, SharedInvalRelcacheMsg::relId, SharedInvalidationMessage::rm, SharedInvalSmgrMsg::rnode, SHAREDINVALCATALOG_ID, SHAREDINVALRELCACHE_ID, SHAREDINVALRELMAP_ID, SHAREDINVALSMGR_ID, SharedInvalidationMessage::sm, and smgrclosenode().

Referenced by AcceptInvalidationMessages(), AtEOSubXact_Inval(), AtEOXact_Inval(), and CommandEndInvalidationMessages().

{
    if (msg->id >= 0)
    {
        if (msg->cc.dbId == MyDatabaseId || msg->cc.dbId == InvalidOid)
        {
            CatalogCacheIdInvalidate(msg->cc.id, msg->cc.hashValue);

            CallSyscacheCallbacks(msg->cc.id, msg->cc.hashValue);
        }
    }
    else if (msg->id == SHAREDINVALCATALOG_ID)
    {
        if (msg->cat.dbId == MyDatabaseId || msg->cat.dbId == InvalidOid)
        {
            CatalogCacheFlushCatalog(msg->cat.catId);

            /* CatalogCacheFlushCatalog calls CallSyscacheCallbacks as needed */
        }
    }
    else if (msg->id == SHAREDINVALRELCACHE_ID)
    {
        if (msg->rc.dbId == MyDatabaseId || msg->rc.dbId == InvalidOid)
        {
            int         i;

            RelationCacheInvalidateEntry(msg->rc.relId);

            for (i = 0; i < relcache_callback_count; i++)
            {
                struct RELCACHECALLBACK *ccitem = relcache_callback_list + i;

                (*ccitem->function) (ccitem->arg, msg->rc.relId);
            }
        }
    }
    else if (msg->id == SHAREDINVALSMGR_ID)
    {
        /*
         * We could have smgr entries for relations of other databases, so no
         * short-circuit test is possible here.
         */
        RelFileNodeBackend rnode;

        rnode.node = msg->sm.rnode;
        rnode.backend = (msg->sm.backend_hi << 16) | (int) msg->sm.backend_lo;
        smgrclosenode(rnode);
    }
    else if (msg->id == SHAREDINVALRELMAP_ID)
    {
        /* We only care about our own database and shared catalogs */
        if (msg->rm.dbId == InvalidOid)
            RelationMapInvalidate(true);
        else if (msg->rm.dbId == MyDatabaseId)
            RelationMapInvalidate(false);
    }
    else
        elog(FATAL, "unrecognized SI message ID: %d", msg->id);
}

static void MakeSharedInvalidMessagesArray ( const SharedInvalidationMessage msgs,
int  n 
) [static]

Definition at line 680 of file inval.c.

References maxSharedInvalidMessagesArray, NULL, numSharedInvalidMessagesArray, palloc(), and repalloc().

Referenced by xactGetCommittedInvalidationMessages().

{
    /*
     * Initialise array first time through in each commit
     */
    if (SharedInvalidMessagesArray == NULL)
    {
        maxSharedInvalidMessagesArray = FIRSTCHUNKSIZE;
        numSharedInvalidMessagesArray = 0;

        /*
         * Although this is being palloc'd we don't actually free it directly.
         * We're so close to EOXact that we now we're going to lose it anyhow.
         */
        SharedInvalidMessagesArray = palloc(maxSharedInvalidMessagesArray
                                        * sizeof(SharedInvalidationMessage));
    }

    if ((numSharedInvalidMessagesArray + n) > maxSharedInvalidMessagesArray)
    {
        while ((numSharedInvalidMessagesArray + n) > maxSharedInvalidMessagesArray)
            maxSharedInvalidMessagesArray *= 2;

        SharedInvalidMessagesArray = repalloc(SharedInvalidMessagesArray,
                                              maxSharedInvalidMessagesArray
                                        * sizeof(SharedInvalidationMessage));
    }

    /*
     * Append the next chunk onto the array
     */
    memcpy(SharedInvalidMessagesArray + numSharedInvalidMessagesArray,
           msgs, n * sizeof(SharedInvalidationMessage));
    numSharedInvalidMessagesArray += n;
}

void PostPrepare_Inval ( void   ) 

Definition at line 653 of file inval.c.

References AtEOXact_Inval().

Referenced by PrepareTransaction().

{
    AtEOXact_Inval(false);
}

void ProcessCommittedInvalidationMessages ( SharedInvalidationMessage msgs,
int  nmsgs,
bool  RelcacheInitFileInval,
Oid  dbid,
Oid  tsid 
)

Definition at line 777 of file inval.c.

References DatabasePath, DEBUG4, elog, GetDatabasePath(), pfree(), RelationCacheInitFilePostInvalidate(), RelationCacheInitFilePreInvalidate(), SendSharedInvalidMessages(), and trace_recovery().

Referenced by xact_redo_commit_internal().

{
    if (nmsgs <= 0)
        return;

    elog(trace_recovery(DEBUG4), "replaying commit with %d messages%s", nmsgs,
         (RelcacheInitFileInval ? " and relcache file invalidation" : ""));

    if (RelcacheInitFileInval)
    {
        /*
         * RelationCacheInitFilePreInvalidate requires DatabasePath to be set,
         * but we should not use SetDatabasePath during recovery, since it is
         * intended to be used only once by normal backends.  Hence, a quick
         * hack: set DatabasePath directly then unset after use.
         */
        DatabasePath = GetDatabasePath(dbid, tsid);
        elog(trace_recovery(DEBUG4), "removing relcache init file in \"%s\"",
             DatabasePath);
        RelationCacheInitFilePreInvalidate();
        pfree(DatabasePath);
        DatabasePath = NULL;
    }

    SendSharedInvalidMessages(msgs, nmsgs);

    if (RelcacheInitFileInval)
        RelationCacheInitFilePostInvalidate();
}

static void ProcessInvalidationMessages ( InvalidationListHeader hdr,
void(*)(SharedInvalidationMessage *msg)  func 
) [static]
static void ProcessInvalidationMessagesMulti ( InvalidationListHeader hdr,
void(*)(const SharedInvalidationMessage *msgs, int n)  func 
) [static]
static void RegisterCatalogInvalidation ( Oid  dbId,
Oid  catId 
) [static]
static void RegisterCatcacheInvalidation ( int  cacheId,
uint32  hashValue,
Oid  dbId 
) [static]
static void RegisterRelcacheInvalidation ( Oid  dbId,
Oid  relId 
) [static]

Definition at line 450 of file inval.c.

References AddRelcacheInvalidationMessage(), TransInvalidationInfo::CurrentCmdInvalidMsgs, GetCurrentCommandId(), RelationIdIsInInitFile(), and TransInvalidationInfo::RelcacheInitFileInval.

Referenced by CacheInvalidateHeapTuple(), CacheInvalidateRelcache(), and CacheInvalidateRelcacheByTuple().

{
    AddRelcacheInvalidationMessage(&transInvalInfo->CurrentCmdInvalidMsgs,
                                   dbId, relId);

    /*
     * Most of the time, relcache invalidation is associated with system
     * catalog updates, but there are a few cases where it isn't.  Quick hack
     * to ensure that the next CommandCounterIncrement() will think that we
     * need to do CommandEndInvalidationMessages().
     */
    (void) GetCurrentCommandId(true);

    /*
     * If the relation being invalidated is one of those cached in the
     * relcache init file, mark that we need to zap that file at commit.
     */
    if (RelationIdIsInInitFile(relId))
        transInvalInfo->RelcacheInitFileInval = true;
}

int xactGetCommittedInvalidationMessages ( SharedInvalidationMessage **  msgs,
bool RelcacheInitFileInval 
)

Definition at line 730 of file inval.c.

References Assert, TransInvalidationInfo::CurrentCmdInvalidMsgs, CurTransactionContext, MakeSharedInvalidMessagesArray(), MemoryContextSwitchTo(), NULL, numSharedInvalidMessagesArray, TransInvalidationInfo::parent, TransInvalidationInfo::PriorCmdInvalidMsgs, ProcessInvalidationMessagesMulti(), and TransInvalidationInfo::RelcacheInitFileInval.

Referenced by RecordTransactionCommit(), and StartPrepare().

{
    MemoryContext oldcontext;

    /* Must be at top of stack */
    Assert(transInvalInfo != NULL && transInvalInfo->parent == NULL);

    /*
     * Relcache init file invalidation requires processing both before and
     * after we send the SI messages.  However, we need not do anything unless
     * we committed.
     */
    *RelcacheInitFileInval = transInvalInfo->RelcacheInitFileInval;

    /*
     * Walk through TransInvalidationInfo to collect all the messages into a
     * single contiguous array of invalidation messages. It must be contiguous
     * so we can copy directly into WAL message. Maintain the order that they
     * would be processed in by AtEOXact_Inval(), to ensure emulated behaviour
     * in redo is as similar as possible to original. We want the same bugs,
     * if any, not new ones.
     */
    oldcontext = MemoryContextSwitchTo(CurTransactionContext);

    ProcessInvalidationMessagesMulti(&transInvalInfo->CurrentCmdInvalidMsgs,
                                     MakeSharedInvalidMessagesArray);
    ProcessInvalidationMessagesMulti(&transInvalInfo->PriorCmdInvalidMsgs,
                                     MakeSharedInvalidMessagesArray);
    MemoryContextSwitchTo(oldcontext);

    Assert(!(numSharedInvalidMessagesArray > 0 &&
             SharedInvalidMessagesArray == NULL));

    *msgs = SharedInvalidMessagesArray;

    return numSharedInvalidMessagesArray;
}


Variable Documentation

Definition at line 171 of file inval.c.

Referenced by MakeSharedInvalidMessagesArray().

int relcache_callback_count = 0 [static]
struct RELCACHECALLBACK relcache_callback_list[MAX_RELCACHE_CALLBACKS] [static]

Definition at line 169 of file inval.c.

int syscache_callback_count = 0 [static]
struct SYSCACHECALLBACK syscache_callback_list[MAX_SYSCACHE_CALLBACKS] [static]

Definition at line 167 of file inval.c.