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.
REL8_2_STABLE
Tom Lane 20 years ago
parent 5320c6cf6b
commit cb98e6fb8f
  1. 137
      src/backend/catalog/aclchk.c
  2. 59
      src/backend/commands/dbcommands.c
  3. 25
      src/backend/commands/vacuum.c
  4. 29
      src/backend/postmaster/autovacuum.c
  5. 13
      src/backend/utils/cache/syscache.c
  6. 17
      src/backend/utils/init/postinit.c
  7. 6
      src/include/utils/acl.h
  8. 35
      src/include/utils/syscache.h

@ -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;
relation = heap_open(DatabaseRelationId, AccessShareLock);
Oid dbid;
/*
* 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);
}

@ -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;
}

@ -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);

@ -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" : "");

@ -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,

@ -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.")));
/*

@ -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,

@ -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);

Loading…
Cancel
Save