Create a syscache for pg_database-indexed-by-oid, and make use of it

in various places that were previously doing ad hoc pg_database searches.
This may speed up database-related privilege checks a little bit, but
the main motivation is to eliminate the performance reason for having
ReverifyMyDatabase do such a lot of stuff (viz, avoiding repeat scans
of pg_database during backend startup).  The locking reason for having
that routine is about to go away, and it'd be good to have the option
to break it up.
This commit is contained in:
Tom Lane 2006-05-03 22:45:26 +00:00
parent 5320c6cf6b
commit cb98e6fb8f
8 changed files with 116 additions and 205 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.127 2006/04/30 21:15:33 tgl Exp $
* $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.128 2006/05/03 22:45:26 tgl Exp $
*
* NOTES
* See acl.h.
@ -34,6 +34,7 @@
#include "catalog/pg_proc.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_type.h"
#include "commands/dbcommands.h"
#include "miscadmin.h"
#include "parser/parse_func.h"
#include "utils/acl.h"
@ -412,8 +413,8 @@ objectNamesToOids(GrantObjectType objtype, List *objnames)
case ACL_OBJECT_SEQUENCE:
foreach(cell, objnames)
{
Oid relOid;
RangeVar *relvar = (RangeVar *) lfirst(cell);
Oid relOid;
relOid = RangeVarGetRelid(relvar, false);
objects = lappend_oid(objects, relOid);
@ -423,32 +424,15 @@ objectNamesToOids(GrantObjectType objtype, List *objnames)
foreach(cell, objnames)
{
char *dbname = strVal(lfirst(cell));
ScanKeyData entry[1];
HeapScanDesc scan;
HeapTuple tuple;
Relation relation;
Oid dbid;
relation = heap_open(DatabaseRelationId, AccessShareLock);
/*
* There's no syscache for pg_database, so we must look the
* hard way.
*/
ScanKeyInit(&entry[0],
Anum_pg_database_datname,
BTEqualStrategyNumber, F_NAMEEQ,
CStringGetDatum(dbname));
scan = heap_beginscan(relation, SnapshotNow, 1, entry);
tuple = heap_getnext(scan, ForwardScanDirection);
if (!HeapTupleIsValid(tuple))
dbid = get_database_oid(dbname);
if (!OidIsValid(dbid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_DATABASE),
errmsg("database \"%s\" does not exist", dbname)));
objects = lappend_oid(objects, HeapTupleGetOid(tuple));
heap_close(relation, AccessShareLock);
heap_endscan(scan);
errmsg("database \"%s\" does not exist",
dbname)));
objects = lappend_oid(objects, dbid);
}
break;
case ACL_OBJECT_FUNCTION:
@ -474,7 +458,8 @@ objectNamesToOids(GrantObjectType objtype, List *objnames)
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("language \"%s\" does not exist", langname)));
errmsg("language \"%s\" does not exist",
langname)));
objects = lappend_oid(objects, HeapTupleGetOid(tuple));
@ -493,7 +478,8 @@ objectNamesToOids(GrantObjectType objtype, List *objnames)
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_SCHEMA),
errmsg("schema \"%s\" does not exist", nspname)));
errmsg("schema \"%s\" does not exist",
nspname)));
objects = lappend_oid(objects, HeapTupleGetOid(tuple));
@ -764,22 +750,13 @@ ExecGrant_Database(InternalGrant *istmt)
int nnewmembers;
Oid *oldmembers;
Oid *newmembers;
ScanKeyData entry[1];
SysScanDesc scan;
HeapTuple tuple;
/* There's no syscache for pg_database, so must look the hard way */
ScanKeyInit(&entry[0],
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(datId));
scan = systable_beginscan(relation, DatabaseOidIndexId, true,
SnapshotNow, 1, entry);
tuple = systable_getnext(scan);
tuple = SearchSysCache(DATABASEOID,
ObjectIdGetDatum(datId),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "could not find tuple for database %u", datId);
elog(ERROR, "cache lookup failed for database %u", datId);
pg_database_tuple = (Form_pg_database) GETSTRUCT(tuple);
@ -847,7 +824,7 @@ ExecGrant_Database(InternalGrant *istmt)
noldmembers, oldmembers,
nnewmembers, newmembers);
systable_endscan(scan);
ReleaseSysCache(tuple);
pfree(new_acl);
@ -1657,10 +1634,11 @@ pg_database_aclmask(Oid db_oid, Oid roleid,
AclMode mask, AclMaskHow how)
{
AclMode result;
Relation pg_database;
ScanKeyData entry[1];
SysScanDesc scan;
HeapTuple tuple;
Datum aclDatum;
bool isNull;
Acl *acl;
Oid ownerId;
/* Superusers bypass all permission checking. */
if (superuser_arg(roleid))
@ -1668,50 +1646,19 @@ pg_database_aclmask(Oid db_oid, Oid roleid,
/*
* Get the database's ACL from pg_database
*
* There's no syscache for pg_database, so must look the hard way
*/
pg_database = heap_open(DatabaseRelationId, AccessShareLock);
ScanKeyInit(&entry[0],
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(db_oid));
scan = systable_beginscan(pg_database, DatabaseOidIndexId, true,
SnapshotNow, 1, entry);
tuple = systable_getnext(scan);
tuple = SearchSysCache(DATABASEOID,
ObjectIdGetDatum(db_oid),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_DATABASE),
errmsg("database with OID %u does not exist", db_oid)));
result = pg_database_tuple_aclmask(tuple, RelationGetDescr(pg_database),
roleid, mask, how);
systable_endscan(scan);
heap_close(pg_database, AccessShareLock);
return result;
}
/*
* This is split out so that ReverifyMyDatabase can perform an ACL check
* without a whole extra search of pg_database
*/
AclMode
pg_database_tuple_aclmask(HeapTuple db_tuple, TupleDesc tupdesc,
Oid roleid, AclMode mask, AclMaskHow how)
{
AclMode result;
Datum aclDatum;
bool isNull;
Acl *acl;
Oid ownerId;
ownerId = ((Form_pg_database) GETSTRUCT(db_tuple))->datdba;
aclDatum = heap_getattr(db_tuple, Anum_pg_database_datacl,
tupdesc, &isNull);
ownerId = ((Form_pg_database) GETSTRUCT(tuple))->datdba;
aclDatum = SysCacheGetAttr(DATABASEOID, tuple, Anum_pg_database_datacl,
&isNull);
if (isNull)
{
/* No ACL, so build default ACL */
@ -1730,6 +1677,8 @@ pg_database_tuple_aclmask(HeapTuple db_tuple, TupleDesc tupdesc,
if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
pfree(acl);
ReleaseSysCache(tuple);
return result;
}
@ -2298,36 +2247,24 @@ pg_opclass_ownercheck(Oid opc_oid, Oid roleid)
bool
pg_database_ownercheck(Oid db_oid, Oid roleid)
{
Relation pg_database;
ScanKeyData entry[1];
SysScanDesc scan;
HeapTuple dbtuple;
HeapTuple tuple;
Oid dba;
/* Superusers bypass all permission checking. */
if (superuser_arg(roleid))
return true;
/* There's no syscache for pg_database, so must look the hard way */
pg_database = heap_open(DatabaseRelationId, AccessShareLock);
ScanKeyInit(&entry[0],
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(db_oid));
scan = systable_beginscan(pg_database, DatabaseOidIndexId, true,
SnapshotNow, 1, entry);
dbtuple = systable_getnext(scan);
if (!HeapTupleIsValid(dbtuple))
tuple = SearchSysCache(DATABASEOID,
ObjectIdGetDatum(db_oid),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_DATABASE),
errmsg("database with OID %u does not exist", db_oid)));
dba = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba;
dba = ((Form_pg_database) GETSTRUCT(tuple))->datdba;
systable_endscan(scan);
heap_close(pg_database, AccessShareLock);
ReleaseSysCache(tuple);
return has_privs_of_role(roleid, dba);
}

View File

@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.179 2006/03/29 21:17:38 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.180 2006/05/03 22:45:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -556,8 +556,6 @@ dropdb(const char *dbname, bool missing_ok)
Oid db_id;
bool db_istemplate;
Relation pgdbrel;
SysScanDesc pgdbscan;
ScanKeyData key;
HeapTuple tup;
PreventTransactionChain((void *) dbname, "DROP DATABASE");
@ -629,31 +627,17 @@ dropdb(const char *dbname, bool missing_ok)
dbname)));
/*
* Find the database's tuple by OID (should be unique).
* Remove the database's tuple from pg_database.
*/
ScanKeyInit(&key,
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(db_id));
pgdbscan = systable_beginscan(pgdbrel, DatabaseOidIndexId, true,
SnapshotNow, 1, &key);
tup = systable_getnext(pgdbscan);
tup = SearchSysCache(DATABASEOID,
ObjectIdGetDatum(db_id),
0, 0, 0);
if (!HeapTupleIsValid(tup))
{
/*
* This error should never come up since the existence of the database
* is checked earlier
*/
elog(ERROR, "database \"%s\" doesn't exist despite earlier reports to the contrary",
dbname);
}
elog(ERROR, "cache lookup failed for database %u", db_id);
/* Remove the database's tuple from pg_database */
simple_heap_delete(pgdbrel, &tup->t_self);
systable_endscan(pgdbscan);
ReleaseSysCache(tup);
/*
* Delete any comments associated with the database
@ -1262,7 +1246,10 @@ get_database_oid(const char *dbname)
HeapTuple dbtuple;
Oid oid;
/* There's no syscache for pg_database, so must look the hard way */
/*
* There's no syscache for pg_database indexed by name,
* so we must look the hard way.
*/
pg_database = heap_open(DatabaseRelationId, AccessShareLock);
ScanKeyInit(&entry[0],
Anum_pg_database_datname,
@ -1296,32 +1283,20 @@ get_database_oid(const char *dbname)
char *
get_database_name(Oid dbid)
{
Relation pg_database;
ScanKeyData entry[1];
SysScanDesc scan;
HeapTuple dbtuple;
char *result;
/* There's no syscache for pg_database, so must look the hard way */
pg_database = heap_open(DatabaseRelationId, AccessShareLock);
ScanKeyInit(&entry[0],
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(dbid));
scan = systable_beginscan(pg_database, DatabaseOidIndexId, true,
SnapshotNow, 1, entry);
dbtuple = systable_getnext(scan);
/* We assume that there can be at most one matching tuple */
dbtuple = SearchSysCache(DATABASEOID,
ObjectIdGetDatum(dbid),
0, 0, 0);
if (HeapTupleIsValid(dbtuple))
{
result = pstrdup(NameStr(((Form_pg_database) GETSTRUCT(dbtuple))->datname));
ReleaseSysCache(dbtuple);
}
else
result = NULL;
systable_endscan(scan);
heap_close(pg_database, AccessShareLock);
return result;
}

View File

@ -13,7 +13,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.328 2006/05/02 22:25:10 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.329 2006/05/03 22:45:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -28,6 +28,7 @@
#include "access/subtrans.h"
#include "access/xlog.h"
#include "catalog/catalog.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_database.h"
#include "catalog/pg_index.h"
@ -767,27 +768,33 @@ vac_update_dbstats(Oid dbid,
{
Relation relation;
ScanKeyData entry[1];
HeapScanDesc scan;
SysScanDesc scan;
HeapTuple tuple;
Buffer buf;
Form_pg_database dbform;
relation = heap_open(DatabaseRelationId, RowExclusiveLock);
/* Must use a heap scan, since there's no syscache for pg_database */
ScanKeyInit(&entry[0],
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(dbid));
scan = heap_beginscan(relation, SnapshotNow, 1, entry);
scan = systable_beginscan(relation, DatabaseOidIndexId, true,
SnapshotNow, 1, entry);
tuple = heap_getnext(scan, ForwardScanDirection);
tuple = systable_getnext(scan);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "could not find tuple for database %u", dbid);
if (scan->irel)
buf = scan->iscan->xs_cbuf;
else
buf = scan->scan->rs_cbuf;
/* ensure no one else does this at the same time */
LockBuffer(scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
dbform = (Form_pg_database) GETSTRUCT(tuple);
@ -795,14 +802,14 @@ vac_update_dbstats(Oid dbid,
dbform->datvacuumxid = vacuumXID;
dbform->datfrozenxid = frozenXID;
MarkBufferDirty(scan->rs_cbuf);
MarkBufferDirty(buf);
LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
LockBuffer(buf, BUFFER_LOCK_UNLOCK);
/* invalidate the tuple in the cache so we'll see the change in cache */
CacheInvalidateHeapTuple(relation, tuple);
heap_endscan(scan);
systable_endscan(scan);
heap_close(relation, RowExclusiveLock);

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.17 2006/04/27 15:57:10 momjian Exp $
* $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.18 2006/05/03 22:45:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -46,6 +46,7 @@
#include "utils/memutils.h"
#include "utils/ps_status.h"
#include "utils/relcache.h"
#include "utils/syscache.h"
/*
@ -493,9 +494,6 @@ autovac_get_database_list(void)
static void
process_whole_db(void)
{
Relation dbRel;
ScanKeyData entry[1];
SysScanDesc scan;
HeapTuple tup;
Form_pg_database dbForm;
bool freeze;
@ -511,21 +509,12 @@ process_whole_db(void)
*/
pgstat_vacuum_tabstat();
dbRel = heap_open(DatabaseRelationId, AccessShareLock);
/* Must use a table scan, since there's no syscache for pg_database */
ScanKeyInit(&entry[0],
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(MyDatabaseId));
scan = systable_beginscan(dbRel, DatabaseOidIndexId, true,
SnapshotNow, 1, entry);
tup = systable_getnext(scan);
/* Look up the pg_database entry and decide whether to FREEZE */
tup = SearchSysCache(DATABASEOID,
ObjectIdGetDatum(MyDatabaseId),
0, 0, 0);
if (!HeapTupleIsValid(tup))
elog(ERROR, "could not find tuple for database %u", MyDatabaseId);
elog(ERROR, "cache lookup failed for database %u", MyDatabaseId);
dbForm = (Form_pg_database) GETSTRUCT(tup);
@ -534,9 +523,7 @@ process_whole_db(void)
else
freeze = false;
systable_endscan(scan);
heap_close(dbRel, AccessShareLock);
ReleaseSysCache(tup);
elog(DEBUG2, "autovacuum: VACUUM%s whole database",
(freeze) ? " FREEZE" : "");

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.102 2006/03/05 15:58:45 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.103 2006/05/03 22:45:26 tgl Exp $
*
* NOTES
* These routines allow the parser/planner/executor to perform
@ -31,6 +31,7 @@
#include "catalog/pg_auth_members.h"
#include "catalog/pg_cast.h"
#include "catalog/pg_conversion.h"
#include "catalog/pg_database.h"
#include "catalog/pg_index.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_language.h"
@ -273,6 +274,16 @@ static const struct cachedesc cacheinfo[] = {
0,
0
}},
{DatabaseRelationId, /* DATABASEOID */
DatabaseOidIndexId,
0,
1,
{
ObjectIdAttributeNumber,
0,
0,
0
}},
{IndexRelationId, /* INDEXRELID */
IndexRelidIndexId,
Anum_pg_index_indrelid,

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.164 2006/04/30 21:15:33 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.165 2006/05/03 22:45:26 tgl Exp $
*
*
*-------------------------------------------------------------------------
@ -195,19 +195,16 @@ ReverifyMyDatabase(const char *name, bool am_superuser)
name)));
/*
* Check privilege to connect to the database. To avoid making
* a whole extra search of pg_database here, we don't go through
* pg_database_aclcheck, but instead use a lower-level routine
* that we can pass the pg_database tuple to.
* Check privilege to connect to the database. (The am_superuser
* test is redundant, but since we have the flag, might as well
* check it and save a few cycles.)
*/
if (!am_superuser &&
pg_database_tuple_aclmask(tup, RelationGetDescr(pgdbrel),
GetUserId(),
ACL_CONNECT, ACLMASK_ANY) == 0)
pg_database_aclcheck(MyDatabaseId, GetUserId(),
ACL_CONNECT) != ACLCHECK_OK)
ereport(FATAL,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied for database %s",
NameStr(dbform->datname)),
errmsg("permission denied for database \"%s\"", name),
errdetail("User does not have CONNECT privilege.")));
/*

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.95 2006/04/30 21:15:33 tgl Exp $
* $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.96 2006/05/03 22:45:26 tgl Exp $
*
* NOTES
* An ACL array is simply an array of AclItems, representing the union
@ -24,8 +24,6 @@
#ifndef ACL_H
#define ACL_H
#include "access/htup.h"
#include "access/tupdesc.h"
#include "nodes/parsenodes.h"
#include "utils/array.h"
@ -252,8 +250,6 @@ extern AclMode pg_class_aclmask(Oid table_oid, Oid roleid,
AclMode mask, AclMaskHow how);
extern AclMode pg_database_aclmask(Oid db_oid, Oid roleid,
AclMode mask, AclMaskHow how);
extern AclMode pg_database_tuple_aclmask(HeapTuple db_tuple, TupleDesc tupdesc,
Oid roleid, AclMode mask, AclMaskHow how);
extern AclMode pg_proc_aclmask(Oid proc_oid, Oid roleid,
AclMode mask, AclMaskHow how);
extern AclMode pg_language_aclmask(Oid lang_oid, Oid roleid,

View File

@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/syscache.h,v 1.62 2006/03/05 15:59:08 momjian Exp $
* $PostgreSQL: pgsql/src/include/utils/syscache.h,v 1.63 2006/05/03 22:45:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -46,22 +46,23 @@
#define CONDEFAULT 15
#define CONNAMENSP 16
#define CONOID 17
#define INDEXRELID 18
#define INHRELID 19
#define LANGNAME 20
#define LANGOID 21
#define NAMESPACENAME 22
#define NAMESPACEOID 23
#define OPERNAMENSP 24
#define OPEROID 25
#define PROCNAMEARGSNSP 26
#define PROCOID 27
#define RELNAMENSP 28
#define RELOID 29
#define RULERELNAME 30
#define STATRELATT 31
#define TYPENAMENSP 32
#define TYPEOID 33
#define DATABASEOID 18
#define INDEXRELID 19
#define INHRELID 20
#define LANGNAME 21
#define LANGOID 22
#define NAMESPACENAME 23
#define NAMESPACEOID 24
#define OPERNAMENSP 25
#define OPEROID 26
#define PROCNAMEARGSNSP 27
#define PROCOID 28
#define RELNAMENSP 29
#define RELOID 30
#define RULERELNAME 31
#define STATRELATT 32
#define TYPENAMENSP 33
#define TYPEOID 34
extern void InitCatalogCache(void);
extern void InitCatalogCachePhase2(void);