mirror of
https://github.com/postgres/postgres.git
synced 2025-06-23 14:01:44 +03:00
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.
This commit is contained in:
133
src/backend/utils/cache/inval.c
vendored
133
src/backend/utils/cache/inval.c
vendored
@ -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"
|
||||
|
||||
|
||||
@ -325,6 +326,21 @@ AddCatcacheInvalidationMessage(InvalidationListHeader *hdr,
|
||||
AddInvalidationMessage(&hdr->cclist, &msg);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
@ -406,6 +422,18 @@ RegisterCatcacheInvalidation(int cacheId,
|
||||
cacheId, hashValue, tuplePtr, dbId);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
@ -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.
|
||||
*/
|
||||
@ -1182,6 +1220,30 @@ CacheInvalidateHeapTuple(Relation relation, HeapTuple tuple)
|
||||
PrepareForTupleInvalidation(relation, 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
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user