diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2010-02-07 20:48:13 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2010-02-07 20:48:13 +0000 |
commit | b9b8831ad60f6e4bd580fe6dbe9749359298a3c4 (patch) | |
tree | af6948498f13a43edd982b05808ed89b5b8191ab /src/backend/utils/cache/inval.c | |
parent | 7fc30c488fc6e9674564206193c29b1a657a818f (diff) | |
download | postgresql-b9b8831ad60f6e4bd580fe6dbe9749359298a3c4.tar.gz postgresql-b9b8831ad60f6e4bd580fe6dbe9749359298a3c4.zip |
Create a "relation mapping" infrastructure to support changing the relfilenodes
of shared or nailed system catalogs. This has two key benefits:
* The new CLUSTER-based VACUUM FULL can be applied safely to all catalogs.
* We no longer have to use an unsafe reindex-in-place approach for reindexing
shared catalogs.
CLUSTER on nailed catalogs now works too, although I left it disabled on
shared catalogs because the resulting pg_index.indisclustered update would
only be visible in one database.
Since reindexing shared system catalogs is now fully transactional and
crash-safe, the former special cases in REINDEX behavior have been removed;
shared catalogs are treated the same as non-shared.
This commit does not do anything about the recently-discussed problem of
deadlocks between VACUUM FULL/CLUSTER on a system catalog and other
concurrent queries; will address that in a separate patch. As a stopgap,
parallel_schedule has been tweaked to run vacuum.sql by itself, to avoid
such failures during the regression tests.
Diffstat (limited to 'src/backend/utils/cache/inval.c')
-rw-r--r-- | src/backend/utils/cache/inval.c | 133 |
1 files changed, 120 insertions, 13 deletions
diff --git a/src/backend/utils/cache/inval.c b/src/backend/utils/cache/inval.c index 99aad752bb3..96439fda18a 100644 --- a/src/backend/utils/cache/inval.c +++ b/src/backend/utils/cache/inval.c @@ -80,7 +80,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/cache/inval.c,v 1.93 2010/02/03 01:14:17 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/cache/inval.c,v 1.94 2010/02/07 20:48:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -96,6 +96,7 @@ #include "utils/inval.h" #include "utils/memutils.h" #include "utils/rel.h" +#include "utils/relmapper.h" #include "utils/syscache.h" @@ -326,6 +327,21 @@ AddCatcacheInvalidationMessage(InvalidationListHeader *hdr, } /* + * Add a whole-catalog inval entry + */ +static void +AddCatalogInvalidationMessage(InvalidationListHeader *hdr, + Oid dbId, Oid catId) +{ + SharedInvalidationMessage msg; + + msg.cat.id = SHAREDINVALCATALOG_ID; + msg.cat.dbId = dbId; + msg.cat.catId = catId; + AddInvalidationMessage(&hdr->cclist, &msg); +} + +/* * Add a relcache inval entry */ static void @@ -407,6 +423,18 @@ RegisterCatcacheInvalidation(int cacheId, } /* + * RegisterCatalogInvalidation + * + * Register an invalidation event for all catcache entries from a catalog. + */ +static void +RegisterCatalogInvalidation(Oid dbId, Oid catId) +{ + AddCatalogInvalidationMessage(&transInvalInfo->CurrentCmdInvalidMsgs, + dbId, catId); +} + +/* * RegisterRelcacheInvalidation * * As above, but register a relcache invalidation event. @@ -443,30 +471,32 @@ RegisterRelcacheInvalidation(Oid dbId, Oid relId) static void LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg) { - int i; - if (msg->id >= 0) { - if (msg->cc.dbId == MyDatabaseId || msg->cc.dbId == 0) + if (msg->cc.dbId == MyDatabaseId || msg->cc.dbId == InvalidOid) { CatalogCacheIdInvalidate(msg->cc.id, msg->cc.hashValue, &msg->cc.tuplePtr); - for (i = 0; i < syscache_callback_count; i++) - { - struct SYSCACHECALLBACK *ccitem = syscache_callback_list + i; + CallSyscacheCallbacks(msg->cc.id, &msg->cc.tuplePtr); + } + } + else if (msg->id == SHAREDINVALCATALOG_ID) + { + if (msg->cat.dbId == MyDatabaseId || msg->cat.dbId == InvalidOid) + { + CatalogCacheFlushCatalog(msg->cat.catId); - if (ccitem->id == msg->cc.id) - (*ccitem->function) (ccitem->arg, - msg->cc.id, &msg->cc.tuplePtr); - } + /* 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++) @@ -485,6 +515,14 @@ LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg) */ smgrclosenode(msg->sm.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); } @@ -506,7 +544,7 @@ InvalidateSystemCaches(void) int i; ResetCatalogCaches(); - RelationCacheInvalidate(); /* gets smgr cache too */ + RelationCacheInvalidate(); /* gets smgr and relmap too */ for (i = 0; i < syscache_callback_count; i++) { @@ -874,7 +912,7 @@ ProcessCommittedInvalidationMessages(SharedInvalidationMessage *msgs, else { /* - * Invalidation message is a SHAREDINVALSMGR_ID + * Invalidation message is a catalog or nontransactional inval, * which never cause relcache file invalidation, * so we ignore them, no matter which db they're for. */ @@ -1183,6 +1221,30 @@ CacheInvalidateHeapTuple(Relation relation, HeapTuple tuple) } /* + * CacheInvalidateCatalog + * Register invalidation of the whole content of a system catalog. + * + * This is normally used in VACUUM FULL/CLUSTER, where we haven't so much + * changed any tuples as moved them around. Some uses of catcache entries + * expect their TIDs to be correct, so we have to blow away the entries. + * + * Note: we expect caller to verify that the rel actually is a system + * catalog. If it isn't, no great harm is done, just a wasted sinval message. + */ +void +CacheInvalidateCatalog(Oid catalogId) +{ + Oid databaseId; + + if (IsSharedRelation(catalogId)) + databaseId = InvalidOid; + else + databaseId = MyDatabaseId; + + RegisterCatalogInvalidation(databaseId, catalogId); +} + +/* * CacheInvalidateRelcache * Register invalidation of the specified relation's relcache entry * at end of command. @@ -1277,6 +1339,31 @@ CacheInvalidateSmgr(RelFileNode rnode) SendSharedInvalidMessages(&msg, 1); } +/* + * CacheInvalidateRelmap + * Register invalidation of the relation mapping for a database, + * or for the shared catalogs if databaseId is zero. + * + * Sending this type of invalidation msg forces other backends to re-read + * the indicated relation mapping file. It is also necessary to send a + * relcache inval for the specific relations whose mapping has been altered, + * else the relcache won't get updated with the new filenode data. + * + * Note: because these messages are nontransactional, they won't be captured + * in commit/abort WAL entries. Instead, calls to CacheInvalidateRelmap() + * should happen in low-level relmapper.c routines, which are executed while + * replaying WAL as well as when creating it. + */ +void +CacheInvalidateRelmap(Oid databaseId) +{ + SharedInvalidationMessage msg; + + msg.rm.id = SHAREDINVALRELMAP_ID; + msg.rm.dbId = databaseId; + SendSharedInvalidMessages(&msg, 1); +} + /* * CacheRegisterSyscacheCallback @@ -1323,3 +1410,23 @@ CacheRegisterRelcacheCallback(RelcacheCallbackFunction func, ++relcache_callback_count; } + +/* + * CallSyscacheCallbacks + * + * This is exported so that CatalogCacheFlushCatalog can call it, saving + * this module from knowing which catcache IDs correspond to which catalogs. + */ +void +CallSyscacheCallbacks(int cacheid, ItemPointer tuplePtr) +{ + 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, tuplePtr); + } +} |