postgresql/src/backend/utils/cache/inval.c

945 lines
24 KiB
C

/*-------------------------------------------------------------------------
*
* inval.c
* POSTGRES cache invalidation dispatcher code.
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/inval.c,v 1.37 2000/06/08 19:51:03 momjian Exp $
*
* Note - this code is real crufty...
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "catalog/catalog.h"
#include "miscadmin.h"
#include "storage/sinval.h"
#include "utils/catcache.h"
#include "utils/inval.h"
#include "utils/relcache.h"
/* ----------------
* private invalidation structures
* ----------------
*/
typedef struct InvalidationUserData
{
struct InvalidationUserData *dataP[1]; /* VARIABLE LENGTH */
} InvalidationUserData; /* VARIABLE LENGTH STRUCTURE */
typedef struct InvalidationEntryData
{
InvalidationUserData *nextP;
InvalidationUserData userData; /* VARIABLE LENGTH ARRAY */
} InvalidationEntryData; /* VARIABLE LENGTH STRUCTURE */
typedef Pointer InvalidationEntry;
typedef InvalidationEntry LocalInvalid;
#define EmptyLocalInvalid NULL
typedef struct CatalogInvalidationData
{
Index cacheId;
Index hashIndex;
ItemPointerData pointerData;
} CatalogInvalidationData;
typedef struct RelationInvalidationData
{
Oid relationId;
Oid objectId;
} RelationInvalidationData;
typedef union AnyInvalidation
{
CatalogInvalidationData catalog;
RelationInvalidationData relation;
} AnyInvalidation;
typedef struct InvalidationMessageData
{
char kind;
AnyInvalidation any;
} InvalidationMessageData;
typedef InvalidationMessageData *InvalidationMessage;
/* ----------------
* variables and macros
* ----------------
*/
/*
* ----------------
* Invalidation info was devided into three parts.
* 1) shared invalidation to be registerd for all backends
* 2) local invalidation for the transaction itself
* 3) rollback information for the transaction itself
* ----------------
*/
/*
* head of invalidation linked list for all backends
* eaten by AtCommit_Cache() in CommitTransaction()
*/
static LocalInvalid InvalidForall = EmptyLocalInvalid;
/*
* head of invalidation linked list for the backend itself
* eaten by AtCommit_LocalCache() in CommandCounterIncrement()
*/
static LocalInvalid InvalidLocal = EmptyLocalInvalid;
/*
* head of rollback linked list for the backend itself
* eaten by AtAbort_Cache() in AbortTransaction()
*/
static LocalInvalid RollbackStack = EmptyLocalInvalid;
static InvalidationEntry InvalidationEntryAllocate(uint16 size);
static void LocalInvalidInvalidate(LocalInvalid invalid, void (*function) (), bool freemember);
static LocalInvalid LocalInvalidRegister(LocalInvalid invalid,
InvalidationEntry entry);
static void DiscardInvalidStack(LocalInvalid *invalid);
static void InvalidationMessageRegisterSharedInvalid(InvalidationMessage message);
/* ----------------------------------------------------------------
* "local" invalidation support functions
* ----------------------------------------------------------------
*/
/* --------------------------------
* InvalidationEntryAllocate
* Allocates an invalidation entry.
* --------------------------------
*/
static InvalidationEntry
InvalidationEntryAllocate(uint16 size)
{
InvalidationEntryData *entryDataP;
entryDataP = (InvalidationEntryData *)
malloc(sizeof(char *) + size); /* XXX alignment */
entryDataP->nextP = NULL;
return (Pointer) &entryDataP->userData;
}
/* --------------------------------
* LocalInvalidRegister
* Link an invalidation entry into a chain of them. Really ugly
* coding here.
* --------------------------------
*/
static LocalInvalid
LocalInvalidRegister(LocalInvalid invalid,
InvalidationEntry entry)
{
Assert(PointerIsValid(entry));
((InvalidationUserData *) entry)->dataP[-1] =
(InvalidationUserData *) invalid;
return entry;
}
/* --------------------------------
* LocalInvalidInvalidate
* Processes, then frees all entries in a local cache
* invalidation list unless freemember parameter is false.
* --------------------------------
*/
static void
LocalInvalidInvalidate(LocalInvalid invalid, void (*function) (), bool freemember)
{
InvalidationEntryData *entryDataP;
while (PointerIsValid(invalid))
{
entryDataP = (InvalidationEntryData *)
&((InvalidationUserData *) invalid)->dataP[-1];
if (PointerIsValid(function))
(*function) ((Pointer) &entryDataP->userData);
invalid = (Pointer) entryDataP->nextP;
if (!freemember)
continue;
/* help catch errors */
entryDataP->nextP = (InvalidationUserData *) NULL;
free((Pointer) entryDataP);
}
}
static void
DiscardInvalidStack(LocalInvalid *invalid)
{
LocalInvalid locinv;
locinv = *invalid;
*invalid = EmptyLocalInvalid;
if (locinv)
LocalInvalidInvalidate(locinv, (void (*) ()) NULL, true);
}
/* ----------------------------------------------------------------
* private support functions
* ----------------------------------------------------------------
*/
/* --------------------------------
* CacheIdRegister.......
* RelationIdRegister....
* --------------------------------
*/
#ifdef INVALIDDEBUG
#define CacheIdRegisterSpecifiedLocalInvalid_DEBUG1 \
elog(DEBUG, "CacheIdRegisterSpecifiedLocalInvalid(%d, %d, [%d, %d])", \
cacheId, hashIndex, ItemPointerGetBlockNumber(pointer), \
ItemPointerGetOffsetNumber(pointer))
#define CacheIdRegisterLocalInvalid_DEBUG1 \
elog(DEBUG, "CacheIdRegisterLocalInvalid(%d, %d, [%d, %d])", \
cacheId, hashIndex, ItemPointerGetBlockNumber(pointer), \
ItemPointerGetOffsetNumber(pointer))
#define CacheIdRegisterLocalRollback_DEBUG1 \
elog(DEBUG, "CacheIdRegisterLocalRollback(%d, %d, [%d, %d])", \
cacheId, hashIndex, ItemPointerGetBlockNumber(pointer), \
ItemPointerGetOffsetNumber(pointer))
#define CacheIdImmediateRegisterSharedInvalid_DEBUG1 \
elog(DEBUG, "CacheIdImmediateRegisterSharedInvalid(%d, %d, [%d, %d])", \
cacheId, hashIndex, ItemPointerGetBlockNumber(pointer), \
ItemPointerGetOffsetNumber(pointer))
#else
#define CacheIdRegisterSpecifiedLocalInvalid_DEBUG1
#define CacheIdRegisterLocalInvalid_DEBUG1
#define CacheIdRegisterLocalRollback_DEBUG1
#define CacheIdImmediateRegisterSharedInvalid_DEBUG1
#endif /* INVALIDDEBUG */
/* --------------------------------
* CacheIdRegisterSpecifiedLocalInvalid
* --------------------------------
*/
static LocalInvalid
CacheIdRegisterSpecifiedLocalInvalid(LocalInvalid invalid,
Index cacheId, Index hashIndex, ItemPointer pointer)
{
InvalidationMessage message;
/* ----------------
* debugging stuff
* ----------------
*/
CacheIdRegisterSpecifiedLocalInvalid_DEBUG1;
/* ----------------
* create a message describing the system catalog tuple
* we wish to invalidate.
* ----------------
*/
message = (InvalidationMessage)
InvalidationEntryAllocate(sizeof(InvalidationMessageData));
message->kind = 'c';
message->any.catalog.cacheId = cacheId;
message->any.catalog.hashIndex = hashIndex;
ItemPointerCopy(pointer, &message->any.catalog.pointerData);
/* ----------------
* Add message to linked list of unprocessed messages.
* ----------------
*/
invalid = LocalInvalidRegister(invalid, (InvalidationEntry) message);
return invalid;
}
/* --------------------------------
* CacheIdRegisterLocalInvalid
* --------------------------------
*/
static void
CacheIdRegisterLocalInvalid(Index cacheId,
Index hashIndex,
ItemPointer pointer)
{
/* ----------------
* debugging stuff
* ----------------
*/
CacheIdRegisterLocalInvalid_DEBUG1;
/* ----------------
* Add message to InvalidForall linked list.
* ----------------
*/
InvalidForall = CacheIdRegisterSpecifiedLocalInvalid(InvalidForall,
cacheId, hashIndex, pointer);
/* ----------------
* Add message to InvalidLocal linked list.
* ----------------
*/
InvalidLocal = CacheIdRegisterSpecifiedLocalInvalid(InvalidLocal,
cacheId, hashIndex, pointer);
}
/* --------------------------------
* CacheIdRegisterLocalRollback
* --------------------------------
*/
static void
CacheIdRegisterLocalRollback(Index cacheId, Index hashIndex,
ItemPointer pointer)
{
/* ----------------
* debugging stuff
* ----------------
*/
CacheIdRegisterLocalRollback_DEBUG1;
/* ----------------
* Add message to RollbackStack linked list.
* ----------------
*/
RollbackStack = CacheIdRegisterSpecifiedLocalInvalid(
RollbackStack, cacheId, hashIndex, pointer);
}
/* --------------------------------
* CacheIdImmediateRegisterSharedInvalid
* --------------------------------
*/
static void
CacheIdImmediateRegisterSharedInvalid(Index cacheId, Index hashIndex,
ItemPointer pointer)
{
InvalidationMessage message;
/* ----------------
* debugging stuff
* ----------------
*/
CacheIdImmediateRegisterSharedInvalid_DEBUG1;
/* ----------------
* create a message describing the system catalog tuple
* we wish to invalidate.
* ----------------
*/
message = (InvalidationMessage)
InvalidationEntryAllocate(sizeof(InvalidationMessageData));
message->kind = 'c';
message->any.catalog.cacheId = cacheId;
message->any.catalog.hashIndex = hashIndex;
ItemPointerCopy(pointer, &message->any.catalog.pointerData);
/* ----------------
* Register a shared catalog cache invalidation.
* ----------------
*/
InvalidationMessageRegisterSharedInvalid(message);
free((Pointer) &((InvalidationUserData *) message)->dataP[-1]);
}
/* --------------------------------
* RelationIdRegisterSpecifiedLocalInvalid
* --------------------------------
*/
static LocalInvalid
RelationIdRegisterSpecifiedLocalInvalid(LocalInvalid invalid,
Oid relationId, Oid objectId)
{
InvalidationMessage message;
/* ----------------
* debugging stuff
* ----------------
*/
#ifdef INVALIDDEBUG
elog(DEBUG, "RelationRegisterSpecifiedLocalInvalid(%u, %u)", relationId,
objectId);
#endif /* defined(INVALIDDEBUG) */
/* ----------------
* create a message describing the relation descriptor
* we wish to invalidate.
* ----------------
*/
message = (InvalidationMessage)
InvalidationEntryAllocate(sizeof(InvalidationMessageData));
message->kind = 'r';
message->any.relation.relationId = relationId;
message->any.relation.objectId = objectId;
/* ----------------
* Add message to linked list of unprocessed messages.
* ----------------
*/
invalid = LocalInvalidRegister(invalid, (InvalidationEntry) message);
return invalid;
}
/* --------------------------------
* RelationIdRegisterLocalInvalid
* --------------------------------
*/
static void
RelationIdRegisterLocalInvalid(Oid relationId, Oid objectId)
{
/* ----------------
* debugging stuff
* ----------------
*/
#ifdef INVALIDDEBUG
elog(DEBUG, "RelationRegisterLocalInvalid(%u, %u)", relationId,
objectId);
#endif /* defined(INVALIDDEBUG) */
/* ----------------
* Add message to InvalidForall linked list.
* ----------------
*/
InvalidForall = RelationIdRegisterSpecifiedLocalInvalid(InvalidForall,
relationId, objectId);
/* ----------------
* Add message to InvalidLocal linked list.
* ----------------
*/
InvalidLocal = RelationIdRegisterSpecifiedLocalInvalid(InvalidLocal,
relationId, objectId);
}
/* --------------------------------
* RelationIdRegisterLocalRollback
* --------------------------------
*/
static void
RelationIdRegisterLocalRollback(Oid relationId, Oid objectId)
{
/* ----------------
* debugging stuff
* ----------------
*/
#ifdef INVALIDDEBUG
elog(DEBUG, "RelationRegisterLocalRollback(%u, %u)", relationId,
objectId);
#endif /* defined(INVALIDDEBUG) */
/* ----------------
* Add message to RollbackStack linked list.
* ----------------
*/
RollbackStack = RelationIdRegisterSpecifiedLocalInvalid(
RollbackStack, relationId, objectId);
}
/* --------------------------------
* RelationIdImmediateRegisterSharedInvalid
* --------------------------------
*/
static void
RelationIdImmediateRegisterSharedInvalid(Oid relationId, Oid objectId)
{
InvalidationMessage message;
/* ----------------
* debugging stuff
* ----------------
*/
#ifdef INVALIDDEBUG
elog(DEBUG, "RelationImmediateRegisterSharedInvalid(%u, %u)", relationId,
objectId);
#endif /* defined(INVALIDDEBUG) */
/* ----------------
* create a message describing the relation descriptor
* we wish to invalidate.
* ----------------
*/
message = (InvalidationMessage)
InvalidationEntryAllocate(sizeof(InvalidationMessageData));
message->kind = 'r';
message->any.relation.relationId = relationId;
message->any.relation.objectId = objectId;
/* ----------------
* Register a shared catalog cache invalidation.
* ----------------
*/
InvalidationMessageRegisterSharedInvalid(message);
free((Pointer) &((InvalidationUserData *) message)->dataP[-1]);
}
/* --------------------------------
* CacheIdInvalidate
*
* This routine can invalidate a tuple in a system catalog cache
* or a cached relation descriptor. You pay your money and you
* take your chances...
* --------------------------------
*/
#ifdef INVALIDDEBUG
#define CacheIdInvalidate_DEBUG1 \
elog(DEBUG, "CacheIdInvalidate(%d, %d, 0x%x[%d])", cacheId, hashIndex,\
pointer, ItemPointerIsValid(pointer))
#else
#define CacheIdInvalidate_DEBUG1
#endif /* defined(INVALIDDEBUG) */
static void
CacheIdInvalidate(Index cacheId,
Index hashIndex,
ItemPointer pointer)
{
/* ----------------
* assume that if the item pointer is valid, then we are
* invalidating an item in the specified system catalog cache.
* ----------------
*/
if (ItemPointerIsValid(pointer))
{
CatalogCacheIdInvalidate(cacheId, hashIndex, pointer);
return;
}
CacheIdInvalidate_DEBUG1;
/* ----------------
* if the cacheId is the oid of any of the following system relations,
* then assume we are invalidating a relation descriptor
* ----------------
*/
if (cacheId == RelOid_pg_class)
{
RelationIdInvalidateRelationCacheByRelationId(hashIndex);
return;
}
if (cacheId == RelOid_pg_attribute)
{
RelationIdInvalidateRelationCacheByRelationId(hashIndex);
return;
}
/* ----------------
* Yow! the caller asked us to invalidate something else.
* ----------------
*/
elog(FATAL, "CacheIdInvalidate: cacheId=%d relation id?", cacheId);
}
/* --------------------------------
* ResetSystemCaches
*
* This blows away all tuples in the system catalog caches and
* all the cached relation descriptors (and closes their files too).
* Relation descriptors that have positive refcounts are then rebuilt.
* --------------------------------
*/
static void
ResetSystemCaches()
{
ResetSystemCache();
RelationCacheInvalidate();
}
/* --------------------------------
* InvalidationMessageRegisterSharedInvalid
* --------------------------------
*/
#ifdef INVALIDDEBUG
#define InvalidationMessageRegisterSharedInvalid_DEBUG1 \
elog(DEBUG,\
"InvalidationMessageRegisterSharedInvalid(c, %d, %d, [%d, %d])",\
message->any.catalog.cacheId,\
message->any.catalog.hashIndex,\
ItemPointerGetBlockNumber(&message->any.catalog.pointerData),\
ItemPointerGetOffsetNumber(&message->any.catalog.pointerData))
#define InvalidationMessageRegisterSharedInvalid_DEBUG2 \
elog(DEBUG, \
"InvalidationMessageRegisterSharedInvalid(r, %u, %u)", \
message->any.relation.relationId, \
message->any.relation.objectId)
#else
#define InvalidationMessageRegisterSharedInvalid_DEBUG1
#define InvalidationMessageRegisterSharedInvalid_DEBUG2
#endif /* INVALIDDEBUG */
static void
InvalidationMessageRegisterSharedInvalid(InvalidationMessage message)
{
Assert(PointerIsValid(message));
switch (message->kind)
{
case 'c': /* cached system catalog tuple */
InvalidationMessageRegisterSharedInvalid_DEBUG1;
RegisterSharedInvalid(message->any.catalog.cacheId,
message->any.catalog.hashIndex,
&message->any.catalog.pointerData);
break;
case 'r': /* cached relation descriptor */
InvalidationMessageRegisterSharedInvalid_DEBUG2;
RegisterSharedInvalid(message->any.relation.relationId,
message->any.relation.objectId,
(ItemPointer) NULL);
break;
default:
elog(FATAL,
"InvalidationMessageRegisterSharedInvalid: `%c' kind",
message->kind);
}
}
/* --------------------------------
* InvalidationMessageCacheInvalidate
* --------------------------------
*/
#ifdef INVALIDDEBUG
#define InvalidationMessageCacheInvalidate_DEBUG1 \
elog(DEBUG, "InvalidationMessageCacheInvalidate(c, %d, %d, [%d, %d])",\
message->any.catalog.cacheId,\
message->any.catalog.hashIndex,\
ItemPointerGetBlockNumber(&message->any.catalog.pointerData),\
ItemPointerGetOffsetNumber(&message->any.catalog.pointerData))
#define InvalidationMessageCacheInvalidate_DEBUG2 \
elog(DEBUG, "InvalidationMessageCacheInvalidate(r, %u, %u)", \
message->any.relation.relationId, \
message->any.relation.objectId)
#else
#define InvalidationMessageCacheInvalidate_DEBUG1
#define InvalidationMessageCacheInvalidate_DEBUG2
#endif /* defined(INVALIDDEBUG) */
static void
InvalidationMessageCacheInvalidate(InvalidationMessage message)
{
Assert(PointerIsValid(message));
switch (message->kind)
{
case 'c': /* cached system catalog tuple */
InvalidationMessageCacheInvalidate_DEBUG1;
CacheIdInvalidate(message->any.catalog.cacheId,
message->any.catalog.hashIndex,
&message->any.catalog.pointerData);
break;
case 'r': /* cached relation descriptor */
InvalidationMessageCacheInvalidate_DEBUG2;
CacheIdInvalidate(message->any.relation.relationId,
message->any.relation.objectId,
(ItemPointer) NULL);
break;
default:
elog(FATAL, "InvalidationMessageCacheInvalidate: `%c' kind",
message->kind);
}
}
/* --------------------------------
* RelationInvalidateRelationCache
* --------------------------------
*/
static void
RelationInvalidateRelationCache(Relation relation,
HeapTuple tuple,
void (*function) ())
{
Oid relationId;
Oid objectId;
/* ----------------
* get the relation object id
* ----------------
*/
relationId = RelationGetRelid(relation);
/* ----------------
* is it one of the ones we need to send an SI message for?
* ----------------
*/
if (relationId == RelOid_pg_class)
objectId = tuple->t_data->t_oid;
else if (relationId == RelOid_pg_attribute)
objectId = ((Form_pg_attribute) GETSTRUCT(tuple))->attrelid;
else
return;
/* ----------------
* can't handle immediate relation descriptor invalidation
* ----------------
*/
Assert(PointerIsValid(function));
(*function) (relationId, objectId);
}
/*
* DiscardInvalid
* Causes the invalidated cache state to be discarded.
*
* Note:
* This should be called as the first step in processing a transaction.
* This should be called while waiting for a query from the front end
* when other backends are active.
*/
void
DiscardInvalid()
{
/* ----------------
* debugging stuff
* ----------------
*/
#ifdef INVALIDDEBUG
elog(DEBUG, "DiscardInvalid called");
#endif /* defined(INVALIDDEBUG) */
InvalidateSharedInvalid(CacheIdInvalidate, ResetSystemCaches);
}
/*
* RegisterInvalid
* Causes registration of invalidated state with other backends iff true.
*
* Note:
* This should be called as the last step in processing a transaction.
*/
void
RegisterInvalid(bool send)
{
LocalInvalid invalid;
/* ----------------
* debugging stuff
* ----------------
*/
#ifdef INVALIDDEBUG
elog(DEBUG, "RegisterInvalid(%d) called", send);
#endif /* defined(INVALIDDEBUG) */
/* ----------------
* Process and free the current list of inval messages.
* ----------------
*/
DiscardInvalidStack(&InvalidLocal);
if (send)
{
DiscardInvalidStack(&RollbackStack);
invalid = InvalidForall;
InvalidForall = EmptyLocalInvalid; /* clear InvalidForall */
LocalInvalidInvalidate(invalid, InvalidationMessageRegisterSharedInvalid, true);
}
else
{
DiscardInvalidStack(&InvalidForall);
invalid = RollbackStack;
RollbackStack = EmptyLocalInvalid; /* clear RollbackStack */
LocalInvalidInvalidate(invalid, InvalidationMessageCacheInvalidate, true);
}
}
/*
* ImmediateLocalInvalidation
* Causes invalidation immediately for the next command of the transaction.
*
* Note:
* This should be called in time of CommandCounterIncrement().
*/
void
ImmediateLocalInvalidation(bool send)
{
LocalInvalid invalid;
/* ----------------
* debugging stuff
* ----------------
*/
#ifdef INVALIDDEBUG
elog(DEBUG, "ImmediateLocalInvalidation(%d) called", send);
#endif /* defined(INVALIDDEBUG) */
/* ----------------
* Process and free the local list of inval messages.
* ----------------
*/
if (send)
{
invalid = InvalidLocal;
InvalidLocal = EmptyLocalInvalid; /* clear InvalidLocal */
LocalInvalidInvalidate(invalid, InvalidationMessageCacheInvalidate, true);
}
else
{
/*
* This may be used for rollback to a savepoint. Don't clear
* InvalidForall and RollbackStack here.
*/
DiscardInvalidStack(&InvalidLocal);
invalid = RollbackStack;
LocalInvalidInvalidate(invalid, InvalidationMessageCacheInvalidate, false);
}
}
/*
* InvokeHeapTupleInvalidation
* Invoke functions for the tuple which register invalidation
* of catalog/relation cache.
* Note:
* Assumes object id is valid.
* Assumes tuple is valid.
*/
#ifdef INVALIDDEBUG
#define InvokeHeapTupleInvalidation_DEBUG1 \
elog(DEBUG, "%s(%s, [%d,%d])", \
funcname,\
RelationGetPhysicalRelationName(relation), \
ItemPointerGetBlockNumber(&tuple->t_self), \
ItemPointerGetOffsetNumber(&tuple->t_self))
#else
#define InvokeHeapTupleInvalidation_DEBUG1
#endif /* defined(INVALIDDEBUG) */
static void
InvokeHeapTupleInvalidation(Relation relation, HeapTuple tuple,
void (*CacheIdRegisterFunc) (),
void (*RelationIdRegisterFunc) (),
const char *funcname)
{
/* ----------------
* sanity checks
* ----------------
*/
Assert(RelationIsValid(relation));
Assert(HeapTupleIsValid(tuple));
if (IsBootstrapProcessingMode())
return;
/* ----------------
* this only works for system relations now
* ----------------
*/
if (!IsSystemRelationName(NameStr(RelationGetForm(relation)->relname)))
return;
/* ----------------
* debugging stuff
* ----------------
*/
InvokeHeapTupleInvalidation_DEBUG1;
RelationInvalidateCatalogCacheTuple(relation, tuple,
CacheIdRegisterFunc);
RelationInvalidateRelationCache(relation, tuple,
RelationIdRegisterFunc);
}
/*
* RelationInvalidateHeapTuple
* Causes the given tuple in a relation to be invalidated.
*/
void
RelationInvalidateHeapTuple(Relation relation, HeapTuple tuple)
{
InvokeHeapTupleInvalidation(relation, tuple,
CacheIdRegisterLocalInvalid,
RelationIdRegisterLocalInvalid,
"RelationInvalidateHeapTuple");
}
/*
* RelationMark4RollbackHeapTuple
* keep the given tuple in a relation to be invalidated
* in case of abort.
*/
void
RelationMark4RollbackHeapTuple(Relation relation, HeapTuple tuple)
{
InvokeHeapTupleInvalidation(relation, tuple,
CacheIdRegisterLocalRollback,
RelationIdRegisterLocalRollback,
"RelationMark4RollbackHeapTuple");
}
/*
* ImmediateInvalidateSharedHeapTuple
* Different from RelationInvalidateHeapTuple()
* this function queues shared invalidation info immediately.
*/
void
ImmediateInvalidateSharedHeapTuple(Relation relation, HeapTuple tuple)
{
InvokeHeapTupleInvalidation(relation, tuple,
CacheIdImmediateRegisterSharedInvalid,
RelationIdImmediateRegisterSharedInvalid,
"ImmediateInvalidateSharedHeapTuple");
}
#ifdef NOT_USED
/*
* ImmediateSharedRelationCacheInvalidate
* Register shared relation cache invalidation immediately
*
* This is needed for smgrunlink()/smgrtruncate().
* Those functions unlink/truncate the base file immediately
* and couldn't be rollbacked in case of abort/crash.
* So relation cache invalidation must be registerd immediately.
* Note:
* Assumes Relation is valid.
*/
void
ImmediateSharedRelationCacheInvalidate(Relation relation)
{
/* ----------------
* sanity checks
* ----------------
*/
Assert(RelationIsValid(relation));
if (IsBootstrapProcessingMode())
return;
/* ----------------
* debugging stuff
* ----------------
*/
#ifdef INVALIDDEBUG
elog(DEBUG, "ImmediateSharedRelationCacheInvalidate(%s)", \
RelationGetPhysicalRelationName(relation));
#endif /* defined(INVALIDDEBUG) */
RelationIdImmediateRegisterSharedInvalid(
RelOid_pg_class, RelationGetRelid(relation));
}
#endif