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/adt/dbsize.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/adt/dbsize.c')
-rw-r--r-- | src/backend/utils/adt/dbsize.c | 123 |
1 files changed, 121 insertions, 2 deletions
diff --git a/src/backend/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c index d2d91975872..d894e8906c8 100644 --- a/src/backend/utils/adt/dbsize.c +++ b/src/backend/utils/adt/dbsize.c @@ -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)); +} |