Skip to content
Snippets Groups Projects
Commit fc299179 authored by Tom Lane's avatar Tom Lane
Browse files

Separate the functions of relcache entry flush and smgr cache entry flush

so that we can get the size of a shared inval message back down to what it
was in 7.4 (and simplify the logic too).  Phase 2 of fixing the
'SMgrRelation hashtable corrupted' problem.
parent 0ce4d569
Branches
Tags
No related merge requests found
...@@ -53,14 +53,14 @@ ...@@ -53,14 +53,14 @@
* *
* Also, whenever we see an operation on a pg_class or pg_attribute tuple, * Also, whenever we see an operation on a pg_class or pg_attribute tuple,
* we register a relcache flush operation for the relation described by that * we register a relcache flush operation for the relation described by that
* tuple. * tuple. pg_class updates trigger an smgr flush operation as well.
* *
* We keep the relcache flush requests in lists separate from the catcache * We keep the relcache and smgr flush requests in lists separate from the
* tuple flush requests. This allows us to issue all the pending catcache * catcache tuple flush requests. This allows us to issue all the pending
* flushes before we issue relcache flushes, which saves us from loading * catcache flushes before we issue relcache flushes, which saves us from
* a catcache tuple during relcache load only to flush it again right away. * loading a catcache tuple during relcache load only to flush it again
* Also, we avoid queuing multiple relcache flush requests for the same * right away. Also, we avoid queuing multiple relcache flush requests for
* relation, since a relcache flush is relatively expensive to do. * the same relation, since a relcache flush is relatively expensive to do.
* (XXX is it worth testing likewise for duplicate catcache flush entries? * (XXX is it worth testing likewise for duplicate catcache flush entries?
* Probably not.) * Probably not.)
* *
...@@ -80,7 +80,7 @@ ...@@ -80,7 +80,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/cache/inval.c,v 1.69 2005/01/10 20:02:23 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/cache/inval.c,v 1.70 2005/01/10 21:57:17 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -115,7 +115,7 @@ typedef struct InvalidationChunk ...@@ -115,7 +115,7 @@ typedef struct InvalidationChunk
typedef struct InvalidationListHeader typedef struct InvalidationListHeader
{ {
InvalidationChunk *cclist; /* list of chunks holding catcache msgs */ InvalidationChunk *cclist; /* list of chunks holding catcache msgs */
InvalidationChunk *rclist; /* list of chunks holding relcache msgs */ InvalidationChunk *rclist; /* list of chunks holding relcache/smgr msgs */
} InvalidationListHeader; } InvalidationListHeader;
/*---------------- /*----------------
...@@ -164,7 +164,7 @@ static TransInvalidationInfo *transInvalInfo = NULL; ...@@ -164,7 +164,7 @@ static TransInvalidationInfo *transInvalInfo = NULL;
static struct CACHECALLBACK static struct CACHECALLBACK
{ {
int16 id; /* cache number or SHAREDINVALRELCACHE_ID */ int16 id; /* cache number or message type id */
CacheCallbackFunction function; CacheCallbackFunction function;
Datum arg; Datum arg;
} cache_callback_list[MAX_CACHE_CALLBACKS]; } cache_callback_list[MAX_CACHE_CALLBACKS];
...@@ -273,7 +273,7 @@ AppendInvalidationMessageList(InvalidationChunk **destHdr, ...@@ -273,7 +273,7 @@ AppendInvalidationMessageList(InvalidationChunk **destHdr,
* Invalidation set support functions * Invalidation set support functions
* *
* These routines understand about the division of a logical invalidation * These routines understand about the division of a logical invalidation
* list into separate physical lists for catcache and relcache entries. * list into separate physical lists for catcache and relcache/smgr entries.
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
...@@ -299,22 +299,42 @@ AddCatcacheInvalidationMessage(InvalidationListHeader *hdr, ...@@ -299,22 +299,42 @@ AddCatcacheInvalidationMessage(InvalidationListHeader *hdr,
*/ */
static void static void
AddRelcacheInvalidationMessage(InvalidationListHeader *hdr, AddRelcacheInvalidationMessage(InvalidationListHeader *hdr,
Oid dbId, Oid relId, RelFileNode physId) Oid dbId, Oid relId)
{ {
SharedInvalidationMessage msg; SharedInvalidationMessage msg;
/* Don't add a duplicate item */ /* Don't add a duplicate item */
/* We assume dbId need not be checked because it will never change */ /* We assume dbId need not be checked because it will never change */
/* relfilenode fields must be checked to support reassignment */
ProcessMessageList(hdr->rclist, ProcessMessageList(hdr->rclist,
if (msg->rc.relId == relId && if (msg->rc.id == SHAREDINVALRELCACHE_ID &&
RelFileNodeEquals(msg->rc.physId, physId)) return); msg->rc.relId == relId)
return);
/* OK, add the item */ /* OK, add the item */
msg.rc.id = SHAREDINVALRELCACHE_ID; msg.rc.id = SHAREDINVALRELCACHE_ID;
msg.rc.dbId = dbId; msg.rc.dbId = dbId;
msg.rc.relId = relId; msg.rc.relId = relId;
msg.rc.physId = physId; AddInvalidationMessage(&hdr->rclist, &msg);
}
/*
* Add an smgr inval entry
*/
static void
AddSmgrInvalidationMessage(InvalidationListHeader *hdr,
RelFileNode rnode)
{
SharedInvalidationMessage msg;
/* Don't add a duplicate item */
ProcessMessageList(hdr->rclist,
if (msg->sm.id == SHAREDINVALSMGR_ID &&
RelFileNodeEquals(msg->sm.rnode, rnode))
return);
/* OK, add the item */
msg.sm.id = SHAREDINVALSMGR_ID;
msg.sm.rnode = rnode;
AddInvalidationMessage(&hdr->rclist, &msg); AddInvalidationMessage(&hdr->rclist, &msg);
} }
...@@ -370,10 +390,10 @@ RegisterCatcacheInvalidation(int cacheId, ...@@ -370,10 +390,10 @@ RegisterCatcacheInvalidation(int cacheId,
* As above, but register a relcache invalidation event. * As above, but register a relcache invalidation event.
*/ */
static void static void
RegisterRelcacheInvalidation(Oid dbId, Oid relId, RelFileNode physId) RegisterRelcacheInvalidation(Oid dbId, Oid relId)
{ {
AddRelcacheInvalidationMessage(&transInvalInfo->CurrentCmdInvalidMsgs, AddRelcacheInvalidationMessage(&transInvalInfo->CurrentCmdInvalidMsgs,
dbId, relId, physId); dbId, relId);
/* /*
* If the relation being invalidated is one of those cached in the * If the relation being invalidated is one of those cached in the
...@@ -383,10 +403,22 @@ RegisterRelcacheInvalidation(Oid dbId, Oid relId, RelFileNode physId) ...@@ -383,10 +403,22 @@ RegisterRelcacheInvalidation(Oid dbId, Oid relId, RelFileNode physId)
transInvalInfo->RelcacheInitFileInval = true; transInvalInfo->RelcacheInitFileInval = true;
} }
/*
* RegisterSmgrInvalidation
*
* As above, but register an smgr invalidation event.
*/
static void
RegisterSmgrInvalidation(RelFileNode rnode)
{
AddSmgrInvalidationMessage(&transInvalInfo->CurrentCmdInvalidMsgs,
rnode);
}
/* /*
* LocalExecuteInvalidationMessage * LocalExecuteInvalidationMessage
* *
* Process a single invalidation message (which could be either type). * Process a single invalidation message (which could be of any type).
* Only the local caches are flushed; this does not transmit the message * Only the local caches are flushed; this does not transmit the message
* to other backends. * to other backends.
*/ */
...@@ -426,17 +458,14 @@ LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg) ...@@ -426,17 +458,14 @@ LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg)
(*ccitem->function) (ccitem->arg, msg->rc.relId); (*ccitem->function) (ccitem->arg, msg->rc.relId);
} }
} }
}
else if (msg->id == SHAREDINVALSMGR_ID)
{
/* /*
* If the message includes a valid relfilenode, we must ensure * We could have smgr entries for relations of other databases,
* the smgr cache entry gets zapped. This might not have happened * so no short-circuit test is possible here.
* above since the relcache entry might not have existed or might
* have been associated with a different relfilenode.
*
* XXX there is no real good reason for rnode inval to be in the
* same message at all. FIXME in 8.1.
*/ */
if (OidIsValid(msg->rc.physId.relNode)) smgrclosenode(msg->sm.rnode);
smgrclosenode(msg->rc.physId);
} }
else else
elog(FATAL, "unrecognized SI message id: %d", msg->id); elog(FATAL, "unrecognized SI message id: %d", msg->id);
...@@ -475,16 +504,11 @@ InvalidateSystemCaches(void) ...@@ -475,16 +504,11 @@ InvalidateSystemCaches(void)
* of catalog/relation cache entries; if so, register inval events. * of catalog/relation cache entries; if so, register inval events.
*/ */
static void static void
PrepareForTupleInvalidation(Relation relation, HeapTuple tuple, PrepareForTupleInvalidation(Relation relation, HeapTuple tuple)
void (*CacheIdRegisterFunc) (int, uint32,
ItemPointer, Oid),
void (*RelationIdRegisterFunc) (Oid, Oid,
RelFileNode))
{ {
Oid tupleRelId; Oid tupleRelId;
Oid databaseId; Oid databaseId;
Oid relationId; Oid relationId;
RelFileNode rnode;
/* Do nothing during bootstrap */ /* Do nothing during bootstrap */
if (IsBootstrapProcessingMode()) if (IsBootstrapProcessingMode())
...@@ -510,7 +534,7 @@ PrepareForTupleInvalidation(Relation relation, HeapTuple tuple, ...@@ -510,7 +534,7 @@ PrepareForTupleInvalidation(Relation relation, HeapTuple tuple,
* First let the catcache do its thing * First let the catcache do its thing
*/ */
PrepareToInvalidateCacheTuple(relation, tuple, PrepareToInvalidateCacheTuple(relation, tuple,
CacheIdRegisterFunc); RegisterCatcacheInvalidation);
/* /*
* Now, is this tuple one of the primary definers of a relcache entry? * Now, is this tuple one of the primary definers of a relcache entry?
...@@ -520,27 +544,36 @@ PrepareForTupleInvalidation(Relation relation, HeapTuple tuple, ...@@ -520,27 +544,36 @@ PrepareForTupleInvalidation(Relation relation, HeapTuple tuple,
if (tupleRelId == RelOid_pg_class) if (tupleRelId == RelOid_pg_class)
{ {
Form_pg_class classtup = (Form_pg_class) GETSTRUCT(tuple); Form_pg_class classtup = (Form_pg_class) GETSTRUCT(tuple);
RelFileNode rnode;
relationId = HeapTupleGetOid(tuple); relationId = HeapTupleGetOid(tuple);
if (classtup->relisshared) if (classtup->relisshared)
databaseId = InvalidOid; databaseId = InvalidOid;
else else
databaseId = MyDatabaseId; databaseId = MyDatabaseId;
if (classtup->reltablespace)
rnode.spcNode = classtup->reltablespace;
else
rnode.spcNode = MyDatabaseTableSpace;
rnode.dbNode = databaseId;
rnode.relNode = classtup->relfilenode;
/* /*
* We need to send out an smgr inval as well as a relcache inval.
* This is needed because other backends might possibly possess
* smgr cache but not relcache entries for the target relation.
*
* Note: during a pg_class row update that assigns a new * Note: during a pg_class row update that assigns a new
* relfilenode or reltablespace value, we will be called on both * relfilenode or reltablespace value, we will be called on both
* the old and new tuples, and thus will broadcast invalidation * the old and new tuples, and thus will broadcast invalidation
* messages showing both the old and new RelFileNode values. This * messages showing both the old and new RelFileNode values. This
* ensures that other backends will close smgr references to the * ensures that other backends will close smgr references to the
* old file. * old file.
*
* XXX possible future cleanup: it might be better to trigger smgr
* flushes explicitly, rather than indirectly from pg_class updates.
*/ */
if (classtup->reltablespace)
rnode.spcNode = classtup->reltablespace;
else
rnode.spcNode = MyDatabaseTableSpace;
rnode.dbNode = databaseId;
rnode.relNode = classtup->relfilenode;
RegisterSmgrInvalidation(rnode);
} }
else if (tupleRelId == RelOid_pg_attribute) else if (tupleRelId == RelOid_pg_attribute)
{ {
...@@ -558,10 +591,6 @@ PrepareForTupleInvalidation(Relation relation, HeapTuple tuple, ...@@ -558,10 +591,6 @@ PrepareForTupleInvalidation(Relation relation, HeapTuple tuple,
* though. * though.
*/ */
databaseId = MyDatabaseId; databaseId = MyDatabaseId;
/* We assume no smgr cache flush is needed, either */
rnode.spcNode = InvalidOid;
rnode.dbNode = InvalidOid;
rnode.relNode = InvalidOid;
} }
else else
return; return;
...@@ -569,7 +598,7 @@ PrepareForTupleInvalidation(Relation relation, HeapTuple tuple, ...@@ -569,7 +598,7 @@ PrepareForTupleInvalidation(Relation relation, HeapTuple tuple,
/* /*
* Yes. We need to register a relcache invalidation event. * Yes. We need to register a relcache invalidation event.
*/ */
(*RelationIdRegisterFunc) (databaseId, relationId, rnode); RegisterRelcacheInvalidation(databaseId, relationId);
} }
...@@ -790,9 +819,7 @@ CommandEndInvalidationMessages(void) ...@@ -790,9 +819,7 @@ CommandEndInvalidationMessages(void)
void void
CacheInvalidateHeapTuple(Relation relation, HeapTuple tuple) CacheInvalidateHeapTuple(Relation relation, HeapTuple tuple)
{ {
PrepareForTupleInvalidation(relation, tuple, PrepareForTupleInvalidation(relation, tuple);
RegisterCatcacheInvalidation,
RegisterRelcacheInvalidation);
} }
/* /*
...@@ -803,7 +830,10 @@ CacheInvalidateHeapTuple(Relation relation, HeapTuple tuple) ...@@ -803,7 +830,10 @@ CacheInvalidateHeapTuple(Relation relation, HeapTuple tuple)
* This is used in places that need to force relcache rebuild but aren't * This is used in places that need to force relcache rebuild but aren't
* changing any of the tuples recognized as contributors to the relcache * changing any of the tuples recognized as contributors to the relcache
* entry by PrepareForTupleInvalidation. (An example is dropping an index.) * entry by PrepareForTupleInvalidation. (An example is dropping an index.)
* We assume in particular that relfilenode isn't changing. * We assume in particular that relfilenode/reltablespace aren't changing
* (so the rd_node value is still good).
*
* XXX most callers of this probably don't need to force an smgr flush.
*/ */
void void
CacheInvalidateRelcache(Relation relation) CacheInvalidateRelcache(Relation relation)
...@@ -817,7 +847,8 @@ CacheInvalidateRelcache(Relation relation) ...@@ -817,7 +847,8 @@ CacheInvalidateRelcache(Relation relation)
else else
databaseId = MyDatabaseId; databaseId = MyDatabaseId;
RegisterRelcacheInvalidation(databaseId, relationId, relation->rd_node); RegisterRelcacheInvalidation(databaseId, relationId);
RegisterSmgrInvalidation(relation->rd_node);
} }
/* /*
...@@ -844,7 +875,8 @@ CacheInvalidateRelcacheByTuple(HeapTuple classTuple) ...@@ -844,7 +875,8 @@ CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
rnode.dbNode = databaseId; rnode.dbNode = databaseId;
rnode.relNode = classtup->relfilenode; rnode.relNode = classtup->relfilenode;
RegisterRelcacheInvalidation(databaseId, relationId, rnode); RegisterRelcacheInvalidation(databaseId, relationId);
RegisterSmgrInvalidation(rnode);
} }
/* /*
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/storage/sinval.h,v 1.39 2004/12/31 22:03:42 pgsql Exp $ * $PostgreSQL: pgsql/src/include/storage/sinval.h,v 1.40 2005/01/10 21:57:19 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -20,22 +20,16 @@ ...@@ -20,22 +20,16 @@
/* /*
* We currently support two types of shared-invalidation messages: one that * We currently support three types of shared-invalidation messages: one that
* invalidates an entry in a catcache, and one that invalidates a relcache * invalidates an entry in a catcache, one that invalidates a relcache entry,
* entry. More types could be added if needed. The message type is * and one that invalidates an smgr cache entry. More types could be added
* identified by the first "int16" field of the message struct. Zero or * if needed. The message type is identified by the first "int16" field of
* positive means a catcache inval message (and also serves as the catcache * the message struct. Zero or positive means a catcache inval message (and
* ID field). -1 means a relcache inval message. Other negative values * also serves as the catcache ID field). -1 means a relcache inval message.
* are available to identify other inval message types. * -2 means an smgr inval message. Other negative values are available to
* identify other inval message types.
* *
* Relcache invalidation messages usually also cause invalidation of entries * Catcache inval events are initially driven by detecting tuple inserts,
* in the smgr's relation cache. This means they must carry both logical
* and physical relation ID info (ie, both dbOID/relOID and RelFileNode).
* In some cases RelFileNode information is not available so the sender fills
* those fields with zeroes --- this is okay so long as no smgr cache flush
* is required.
*
* Shared-inval events are initially driven by detecting tuple inserts,
* updates and deletions in system catalogs (see CacheInvalidateHeapTuple). * updates and deletions in system catalogs (see CacheInvalidateHeapTuple).
* An update generates two inval events, one for the old tuple and one for * An update generates two inval events, one for the old tuple and one for
* the new --- this is needed to get rid of both positive entries for the * the new --- this is needed to get rid of both positive entries for the
...@@ -71,20 +65,22 @@ typedef struct ...@@ -71,20 +65,22 @@ typedef struct
int16 id; /* type field --- must be first */ int16 id; /* type field --- must be first */
Oid dbId; /* database ID, or 0 if a shared relation */ Oid dbId; /* database ID, or 0 if a shared relation */
Oid relId; /* relation ID */ Oid relId; /* relation ID */
RelFileNode physId; /* physical file ID */
/*
* Note: it is likely that RelFileNode will someday be changed to
* include database ID. In that case the dbId field will be redundant
* and should be removed to save space.
*/
} SharedInvalRelcacheMsg; } SharedInvalRelcacheMsg;
#define SHAREDINVALSMGR_ID (-2)
typedef struct
{
int16 id; /* type field --- must be first */
RelFileNode rnode; /* physical file ID */
} SharedInvalSmgrMsg;
typedef union typedef union
{ {
int16 id; /* type field --- must be first */ int16 id; /* type field --- must be first */
SharedInvalCatcacheMsg cc; SharedInvalCatcacheMsg cc;
SharedInvalRelcacheMsg rc; SharedInvalRelcacheMsg rc;
SharedInvalSmgrMsg sm;
} SharedInvalidationMessage; } SharedInvalidationMessage;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment