mirror of
https://github.com/postgres/postgres.git
synced 2025-08-19 23:22:23 +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:
@@ -1,11 +1,11 @@
|
||||
/*
|
||||
* dbsize.c
|
||||
* object size functions
|
||||
* Database object size functions, and related inquiries
|
||||
*
|
||||
* Copyright (c) 2002-2010, PostgreSQL Global Development Group
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/dbsize.c,v 1.28 2010/01/23 21:29:00 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/dbsize.c,v 1.29 2010/02/07 20:48:10 tgl Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "utils/acl.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/rel.h"
|
||||
#include "utils/relmapper.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
|
||||
@@ -507,3 +508,121 @@ pg_size_pretty(PG_FUNCTION_ARGS)
|
||||
|
||||
PG_RETURN_TEXT_P(cstring_to_text(buf));
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the filenode of a relation
|
||||
*
|
||||
* This is expected to be used in queries like
|
||||
* SELECT pg_relation_filenode(oid) FROM pg_class;
|
||||
* That leads to a couple of choices. We work from the pg_class row alone
|
||||
* rather than actually opening each relation, for efficiency. We don't
|
||||
* fail if we can't find the relation --- some rows might be visible in
|
||||
* the query's MVCC snapshot but already dead according to SnapshotNow.
|
||||
* (Note: we could avoid using the catcache, but there's little point
|
||||
* because the relation mapper also works "in the now".) We also don't
|
||||
* fail if the relation doesn't have storage. In all these cases it
|
||||
* seems better to quietly return NULL.
|
||||
*/
|
||||
Datum
|
||||
pg_relation_filenode(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid relid = PG_GETARG_OID(0);
|
||||
Oid result;
|
||||
HeapTuple tuple;
|
||||
Form_pg_class relform;
|
||||
|
||||
tuple = SearchSysCache(RELOID,
|
||||
ObjectIdGetDatum(relid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
PG_RETURN_NULL();
|
||||
relform = (Form_pg_class) GETSTRUCT(tuple);
|
||||
|
||||
switch (relform->relkind)
|
||||
{
|
||||
case RELKIND_RELATION:
|
||||
case RELKIND_INDEX:
|
||||
case RELKIND_SEQUENCE:
|
||||
case RELKIND_TOASTVALUE:
|
||||
/* okay, these have storage */
|
||||
if (relform->relfilenode)
|
||||
result = relform->relfilenode;
|
||||
else /* Consult the relation mapper */
|
||||
result = RelationMapOidToFilenode(relid,
|
||||
relform->relisshared);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* no storage, return NULL */
|
||||
result = InvalidOid;
|
||||
break;
|
||||
}
|
||||
|
||||
ReleaseSysCache(tuple);
|
||||
|
||||
if (!OidIsValid(result))
|
||||
PG_RETURN_NULL();
|
||||
|
||||
PG_RETURN_OID(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the pathname (relative to $PGDATA) of a relation
|
||||
*
|
||||
* See comments for pg_relation_filenode.
|
||||
*/
|
||||
Datum
|
||||
pg_relation_filepath(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid relid = PG_GETARG_OID(0);
|
||||
HeapTuple tuple;
|
||||
Form_pg_class relform;
|
||||
RelFileNode rnode;
|
||||
char *path;
|
||||
|
||||
tuple = SearchSysCache(RELOID,
|
||||
ObjectIdGetDatum(relid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
PG_RETURN_NULL();
|
||||
relform = (Form_pg_class) GETSTRUCT(tuple);
|
||||
|
||||
switch (relform->relkind)
|
||||
{
|
||||
case RELKIND_RELATION:
|
||||
case RELKIND_INDEX:
|
||||
case RELKIND_SEQUENCE:
|
||||
case RELKIND_TOASTVALUE:
|
||||
/* okay, these have storage */
|
||||
|
||||
/* This logic should match RelationInitPhysicalAddr */
|
||||
if (relform->reltablespace)
|
||||
rnode.spcNode = relform->reltablespace;
|
||||
else
|
||||
rnode.spcNode = MyDatabaseTableSpace;
|
||||
if (rnode.spcNode == GLOBALTABLESPACE_OID)
|
||||
rnode.dbNode = InvalidOid;
|
||||
else
|
||||
rnode.dbNode = MyDatabaseId;
|
||||
if (relform->relfilenode)
|
||||
rnode.relNode = relform->relfilenode;
|
||||
else /* Consult the relation mapper */
|
||||
rnode.relNode = RelationMapOidToFilenode(relid,
|
||||
relform->relisshared);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* no storage, return NULL */
|
||||
rnode.relNode = InvalidOid;
|
||||
break;
|
||||
}
|
||||
|
||||
ReleaseSysCache(tuple);
|
||||
|
||||
if (!OidIsValid(rnode.relNode))
|
||||
PG_RETURN_NULL();
|
||||
|
||||
path = relpath(rnode, MAIN_FORKNUM);
|
||||
|
||||
PG_RETURN_TEXT_P(cstring_to_text(path));
|
||||
}
|
||||
|
Reference in New Issue
Block a user