Commit fc299179 authored by Tom Lane's avatar Tom Lane

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
...@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment