* syscache.c
* System cache management routines
*
- * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.111 2007/02/14 01:58:57 tgl Exp $
+ * src/backend/utils/cache/syscache.c
*
* NOTES
* These routines allow the parser/planner/executor to perform
* rapid lookups on the contents of the system catalogs.
*
- * see catalog/syscache.h for a list of the cache id's
+ * see utils/syscache.h for a list of the cache IDs
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
-#include "access/heapam.h"
+#include "access/htup_details.h"
+#include "access/sysattr.h"
#include "catalog/indexing.h"
#include "catalog/pg_aggregate.h"
+#include "catalog/pg_am.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_auth_members.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_cast.h"
+#include "catalog/pg_collation.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_conversion.h"
#include "catalog/pg_database.h"
+#include "catalog/pg_db_role_setting.h"
+#include "catalog/pg_default_acl.h"
+#include "catalog/pg_depend.h"
+#include "catalog/pg_description.h"
+#include "catalog/pg_enum.h"
+#include "catalog/pg_event_trigger.h"
+#include "catalog/pg_foreign_data_wrapper.h"
+#include "catalog/pg_foreign_server.h"
+#include "catalog/pg_foreign_table.h"
#include "catalog/pg_language.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
+#include "catalog/pg_partitioned_table.h"
#include "catalog/pg_proc.h"
+#include "catalog/pg_publication.h"
+#include "catalog/pg_publication_rel.h"
+#include "catalog/pg_range.h"
#include "catalog/pg_rewrite.h"
+#include "catalog/pg_seclabel.h"
+#include "catalog/pg_sequence.h"
+#include "catalog/pg_shdepend.h"
+#include "catalog/pg_shdescription.h"
+#include "catalog/pg_shseclabel.h"
+#include "catalog/pg_replication_origin.h"
#include "catalog/pg_statistic.h"
+#include "catalog/pg_statistic_ext.h"
+#include "catalog/pg_subscription.h"
+#include "catalog/pg_subscription_rel.h"
+#include "catalog/pg_tablespace.h"
+#include "catalog/pg_transform.h"
+#include "catalog/pg_ts_config.h"
+#include "catalog/pg_ts_config_map.h"
+#include "catalog/pg_ts_dict.h"
+#include "catalog/pg_ts_parser.h"
+#include "catalog/pg_ts_template.h"
#include "catalog/pg_type.h"
+#include "catalog/pg_user_mapping.h"
+#include "utils/rel.h"
+#include "utils/catcache.h"
#include "utils/syscache.h"
Adding system caches:
- Add your new cache to the list in include/utils/syscache.h. Keep
- the list sorted alphabetically and adjust the cache numbers
- accordingly.
+ Add your new cache to the list in include/utils/syscache.h.
+ Keep the list sorted alphabetically.
Add your entry to the cacheinfo[] array below. All cache lists are
alphabetical, so add it in the proper place. Specify the relation OID,
- index OID, number of keys, key attribute numbers, and number of hash
- buckets. If the relation contains tuples that are associated with a
- particular relation (for example, its attributes, rules, triggers, etc)
- then specify the attribute number that contains the OID of the associated
- relation. This is used by CatalogCacheFlushRelation() to remove the
- correct tuples during a table drop or relcache invalidation event.
+ index OID, number of keys, key attribute numbers, and initial number of
+ hash buckets.
The number of hash buckets must be a power of 2. It's reasonable to
set this to the number of entries that might be in the particular cache
adding/deleting caches only requires a recompile.)
Finally, any place your relation gets heap_insert() or
- heap_update() calls, make sure there is a CatalogUpdateIndexes() or
- similar call. The heap_* calls do not update indexes.
-
- bjm 1999/11/22
+ heap_update() calls, use CatalogTupleInsert() or CatalogTupleUpdate()
+ instead, which also update indexes. The heap_* calls do not do that.
*---------------------------------------------------------------------------
*/
{
Oid reloid; /* OID of the relation being cached */
Oid indoid; /* OID of index relation for this cache */
- int reloidattr; /* attr number of rel OID reference, or 0 */
int nkeys; /* # of keys needed for cache lookup */
int key[4]; /* attribute numbers of key attrs */
int nbuckets; /* number of hash buckets for this cache */
static const struct cachedesc cacheinfo[] = {
{AggregateRelationId, /* AGGFNOID */
AggregateFnoidIndexId,
- 0,
1,
{
Anum_pg_aggregate_aggfnoid,
0,
0
},
- 32
+ 16
},
{AccessMethodRelationId, /* AMNAME */
AmNameIndexId,
- 0,
1,
{
Anum_pg_am_amname,
},
{AccessMethodRelationId, /* AMOID */
AmOidIndexId,
- 0,
1,
{
ObjectIdAttributeNumber,
},
{AccessMethodOperatorRelationId, /* AMOPOPID */
AccessMethodOperatorIndexId,
- 0,
- 2,
+ 3,
{
Anum_pg_amop_amopopr,
+ Anum_pg_amop_amoppurpose,
Anum_pg_amop_amopfamily,
- 0,
0
},
64
},
{AccessMethodOperatorRelationId, /* AMOPSTRATEGY */
AccessMethodStrategyIndexId,
- 0,
4,
{
Anum_pg_amop_amopfamily,
},
{AccessMethodProcedureRelationId, /* AMPROCNUM */
AccessMethodProcedureIndexId,
- 0,
4,
{
Anum_pg_amproc_amprocfamily,
Anum_pg_amproc_amprocrighttype,
Anum_pg_amproc_amprocnum
},
- 64
+ 16
},
{AttributeRelationId, /* ATTNAME */
AttributeRelidNameIndexId,
- Anum_pg_attribute_attrelid,
2,
{
Anum_pg_attribute_attrelid,
0,
0
},
- 2048
+ 32
},
{AttributeRelationId, /* ATTNUM */
AttributeRelidNumIndexId,
- Anum_pg_attribute_attrelid,
2,
{
Anum_pg_attribute_attrelid,
0,
0
},
- 2048
+ 128
},
{AuthMemRelationId, /* AUTHMEMMEMROLE */
AuthMemMemRoleIndexId,
- 0,
2,
{
Anum_pg_auth_members_member,
0,
0
},
- 128
+ 8
},
{AuthMemRelationId, /* AUTHMEMROLEMEM */
AuthMemRoleMemIndexId,
- 0,
2,
{
Anum_pg_auth_members_roleid,
0,
0
},
- 128
+ 8
},
{AuthIdRelationId, /* AUTHNAME */
AuthIdRolnameIndexId,
- 0,
1,
{
Anum_pg_authid_rolname,
0,
0
},
- 128
+ 8
},
{AuthIdRelationId, /* AUTHOID */
AuthIdOidIndexId,
- 0,
1,
{
ObjectIdAttributeNumber,
0,
0
},
- 128
+ 8
},
{
CastRelationId, /* CASTSOURCETARGET */
CastSourceTargetIndexId,
- 0,
2,
{
Anum_pg_cast_castsource,
},
{OperatorClassRelationId, /* CLAAMNAMENSP */
OpclassAmNameNspIndexId,
- 0,
3,
{
Anum_pg_opclass_opcmethod,
Anum_pg_opclass_opcnamespace,
0
},
- 64
+ 8
},
{OperatorClassRelationId, /* CLAOID */
OpclassOidIndexId,
- 0,
1,
{
ObjectIdAttributeNumber,
0,
0
},
- 64
+ 8
+ },
+ {CollationRelationId, /* COLLNAMEENCNSP */
+ CollationNameEncNspIndexId,
+ 3,
+ {
+ Anum_pg_collation_collname,
+ Anum_pg_collation_collencoding,
+ Anum_pg_collation_collnamespace,
+ 0
+ },
+ 8
+ },
+ {CollationRelationId, /* COLLOID */
+ CollationOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 8
},
{ConversionRelationId, /* CONDEFAULT */
ConversionDefaultIndexId,
- 0,
4,
{
Anum_pg_conversion_connamespace,
Anum_pg_conversion_contoencoding,
ObjectIdAttributeNumber,
},
- 128
+ 8
},
{ConversionRelationId, /* CONNAMENSP */
ConversionNameNspIndexId,
- 0,
2,
{
Anum_pg_conversion_conname,
0,
0
},
- 128
+ 8
},
{ConstraintRelationId, /* CONSTROID */
ConstraintOidIndexId,
- 0,
1,
{
ObjectIdAttributeNumber,
0,
0
},
- 1024
+ 16
},
{ConversionRelationId, /* CONVOID */
ConversionOidIndexId,
- 0,
1,
{
ObjectIdAttributeNumber,
0,
0
},
- 128
+ 8
},
{DatabaseRelationId, /* DATABASEOID */
DatabaseOidIndexId,
- 0,
1,
{
ObjectIdAttributeNumber,
},
4
},
+ {DefaultAclRelationId, /* DEFACLROLENSPOBJ */
+ DefaultAclRoleNspObjIndexId,
+ 3,
+ {
+ Anum_pg_default_acl_defaclrole,
+ Anum_pg_default_acl_defaclnamespace,
+ Anum_pg_default_acl_defaclobjtype,
+ 0
+ },
+ 8
+ },
+ {EnumRelationId, /* ENUMOID */
+ EnumOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 8
+ },
+ {EnumRelationId, /* ENUMTYPOIDNAME */
+ EnumTypIdLabelIndexId,
+ 2,
+ {
+ Anum_pg_enum_enumtypid,
+ Anum_pg_enum_enumlabel,
+ 0,
+ 0
+ },
+ 8
+ },
+ {EventTriggerRelationId, /* EVENTTRIGGERNAME */
+ EventTriggerNameIndexId,
+ 1,
+ {
+ Anum_pg_event_trigger_evtname,
+ 0,
+ 0,
+ 0
+ },
+ 8
+ },
+ {EventTriggerRelationId, /* EVENTTRIGGEROID */
+ EventTriggerOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 8
+ },
+ {ForeignDataWrapperRelationId, /* FOREIGNDATAWRAPPERNAME */
+ ForeignDataWrapperNameIndexId,
+ 1,
+ {
+ Anum_pg_foreign_data_wrapper_fdwname,
+ 0,
+ 0,
+ 0
+ },
+ 2
+ },
+ {ForeignDataWrapperRelationId, /* FOREIGNDATAWRAPPEROID */
+ ForeignDataWrapperOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 2
+ },
+ {ForeignServerRelationId, /* FOREIGNSERVERNAME */
+ ForeignServerNameIndexId,
+ 1,
+ {
+ Anum_pg_foreign_server_srvname,
+ 0,
+ 0,
+ 0
+ },
+ 2
+ },
+ {ForeignServerRelationId, /* FOREIGNSERVEROID */
+ ForeignServerOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 2
+ },
+ {ForeignTableRelationId, /* FOREIGNTABLEREL */
+ ForeignTableRelidIndexId,
+ 1,
+ {
+ Anum_pg_foreign_table_ftrelid,
+ 0,
+ 0,
+ 0
+ },
+ 4
+ },
{IndexRelationId, /* INDEXRELID */
IndexRelidIndexId,
- Anum_pg_index_indrelid,
1,
{
Anum_pg_index_indexrelid,
0,
0
},
- 1024
+ 64
},
{LanguageRelationId, /* LANGNAME */
LanguageNameIndexId,
- 0,
1,
{
Anum_pg_language_lanname,
},
{LanguageRelationId, /* LANGOID */
LanguageOidIndexId,
- 0,
1,
{
ObjectIdAttributeNumber,
},
{NamespaceRelationId, /* NAMESPACENAME */
NamespaceNameIndexId,
- 0,
1,
{
Anum_pg_namespace_nspname,
0,
0
},
- 256
+ 4
},
{NamespaceRelationId, /* NAMESPACEOID */
NamespaceOidIndexId,
- 0,
1,
{
ObjectIdAttributeNumber,
0,
0
},
- 256
+ 16
},
{OperatorRelationId, /* OPERNAMENSP */
OperatorNameNspIndexId,
- 0,
4,
{
Anum_pg_operator_oprname,
Anum_pg_operator_oprright,
Anum_pg_operator_oprnamespace
},
- 1024
+ 256
},
{OperatorRelationId, /* OPEROID */
OperatorOidIndexId,
- 0,
1,
{
ObjectIdAttributeNumber,
0,
0
},
- 1024
+ 32
},
{OperatorFamilyRelationId, /* OPFAMILYAMNAMENSP */
OpfamilyAmNameNspIndexId,
- 0,
3,
{
Anum_pg_opfamily_opfmethod,
Anum_pg_opfamily_opfnamespace,
0
},
- 64
+ 8
},
{OperatorFamilyRelationId, /* OPFAMILYOID */
OpfamilyOidIndexId,
- 0,
1,
{
ObjectIdAttributeNumber,
0,
0
},
- 64
+ 8
+ },
+ {PartitionedRelationId, /* PARTRELID */
+ PartitionedRelidIndexId,
+ 1,
+ {
+ Anum_pg_partitioned_table_partrelid,
+ 0,
+ 0,
+ 0
+ },
+ 32
},
{ProcedureRelationId, /* PROCNAMEARGSNSP */
ProcedureNameArgsNspIndexId,
- 0,
3,
{
Anum_pg_proc_proname,
Anum_pg_proc_pronamespace,
0
},
- 2048
+ 128
},
{ProcedureRelationId, /* PROCOID */
ProcedureOidIndexId,
- 0,
1,
{
ObjectIdAttributeNumber,
0,
0
},
- 2048
+ 128
+ },
+ {RangeRelationId, /* RANGETYPE */
+ RangeTypidIndexId,
+ 1,
+ {
+ Anum_pg_range_rngtypid,
+ 0,
+ 0,
+ 0
+ },
+ 4
},
{RelationRelationId, /* RELNAMENSP */
ClassNameNspIndexId,
- ObjectIdAttributeNumber,
2,
{
Anum_pg_class_relname,
0,
0
},
- 1024
+ 128
},
{RelationRelationId, /* RELOID */
ClassOidIndexId,
- ObjectIdAttributeNumber,
1,
{
ObjectIdAttributeNumber,
0,
0
},
- 1024
+ 128
+ },
+ {ReplicationOriginRelationId, /* REPLORIGIDENT */
+ ReplicationOriginIdentIndex,
+ 1,
+ {
+ Anum_pg_replication_origin_roident,
+ 0,
+ 0,
+ 0
+ },
+ 16
+ },
+ {ReplicationOriginRelationId, /* REPLORIGNAME */
+ ReplicationOriginNameIndex,
+ 1,
+ {
+ Anum_pg_replication_origin_roname,
+ 0,
+ 0,
+ 0
+ },
+ 16
+ },
+ {PublicationRelationId, /* PUBLICATIONOID */
+ PublicationObjectIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 8
+ },
+ {PublicationRelationId, /* PUBLICATIONNAME */
+ PublicationNameIndexId,
+ 1,
+ {
+ Anum_pg_publication_pubname,
+ 0,
+ 0,
+ 0
+ },
+ 8
+ },
+ {PublicationRelRelationId, /* PUBLICATIONREL */
+ PublicationRelObjectIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 64
+ },
+ {PublicationRelRelationId, /* PUBLICATIONRELMAP */
+ PublicationRelPrrelidPrpubidIndexId,
+ 2,
+ {
+ Anum_pg_publication_rel_prrelid,
+ Anum_pg_publication_rel_prpubid,
+ 0,
+ 0
+ },
+ 64
},
{RewriteRelationId, /* RULERELNAME */
RewriteRelRulenameIndexId,
- Anum_pg_rewrite_ev_class,
2,
{
Anum_pg_rewrite_ev_class,
0,
0
},
- 1024
+ 8
},
- {StatisticRelationId, /* STATRELATT */
- StatisticRelidAttnumIndexId,
- Anum_pg_statistic_starelid,
+ {SequenceRelationId, /* SEQRELID */
+ SequenceRelidIndexId,
+ 1,
+ {
+ Anum_pg_sequence_seqrelid,
+ 0,
+ 0,
+ 0
+ },
+ 32
+ },
+ {StatisticExtRelationId, /* STATEXTNAMENSP */
+ StatisticExtNameIndexId,
2,
+ {
+ Anum_pg_statistic_ext_stxname,
+ Anum_pg_statistic_ext_stxnamespace,
+ 0,
+ 0
+ },
+ 4
+ },
+ {StatisticExtRelationId, /* STATEXTOID */
+ StatisticExtOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 4
+ },
+ {StatisticRelationId, /* STATRELATTINH */
+ StatisticRelidAttnumInhIndexId,
+ 3,
{
Anum_pg_statistic_starelid,
Anum_pg_statistic_staattnum,
+ Anum_pg_statistic_stainherit,
+ 0
+ },
+ 128
+ },
+ {SubscriptionRelationId, /* SUBSCRIPTIONOID */
+ SubscriptionObjectIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 4
+ },
+ {SubscriptionRelationId, /* SUBSCRIPTIONNAME */
+ SubscriptionNameIndexId,
+ 2,
+ {
+ Anum_pg_subscription_subdbid,
+ Anum_pg_subscription_subname,
+ 0,
+ 0
+ },
+ 4
+ },
+ {SubscriptionRelRelationId, /* SUBSCRIPTIONRELMAP */
+ SubscriptionRelSrrelidSrsubidIndexId,
+ 2,
+ {
+ Anum_pg_subscription_rel_srrelid,
+ Anum_pg_subscription_rel_srsubid,
+ 0,
+ 0
+ },
+ 64
+ },
+ {TableSpaceRelationId, /* TABLESPACEOID */
+ TablespaceOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0,
+ },
+ 4
+ },
+ {TransformRelationId, /* TRFOID */
+ TransformOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0,
+ },
+ 16
+ },
+ {TransformRelationId, /* TRFTYPELANG */
+ TransformTypeLangIndexId,
+ 2,
+ {
+ Anum_pg_transform_trftype,
+ Anum_pg_transform_trflang,
+ 0,
+ 0,
+ },
+ 16
+ },
+ {TSConfigMapRelationId, /* TSCONFIGMAP */
+ TSConfigMapIndexId,
+ 3,
+ {
+ Anum_pg_ts_config_map_mapcfg,
+ Anum_pg_ts_config_map_maptokentype,
+ Anum_pg_ts_config_map_mapseqno,
+ 0
+ },
+ 2
+ },
+ {TSConfigRelationId, /* TSCONFIGNAMENSP */
+ TSConfigNameNspIndexId,
+ 2,
+ {
+ Anum_pg_ts_config_cfgname,
+ Anum_pg_ts_config_cfgnamespace,
+ 0,
+ 0
+ },
+ 2
+ },
+ {TSConfigRelationId, /* TSCONFIGOID */
+ TSConfigOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 2
+ },
+ {TSDictionaryRelationId, /* TSDICTNAMENSP */
+ TSDictionaryNameNspIndexId,
+ 2,
+ {
+ Anum_pg_ts_dict_dictname,
+ Anum_pg_ts_dict_dictnamespace,
+ 0,
+ 0
+ },
+ 2
+ },
+ {TSDictionaryRelationId, /* TSDICTOID */
+ TSDictionaryOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
0,
0
},
- 1024
+ 2
+ },
+ {TSParserRelationId, /* TSPARSERNAMENSP */
+ TSParserNameNspIndexId,
+ 2,
+ {
+ Anum_pg_ts_parser_prsname,
+ Anum_pg_ts_parser_prsnamespace,
+ 0,
+ 0
+ },
+ 2
+ },
+ {TSParserRelationId, /* TSPARSEROID */
+ TSParserOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 2
+ },
+ {TSTemplateRelationId, /* TSTEMPLATENAMENSP */
+ TSTemplateNameNspIndexId,
+ 2,
+ {
+ Anum_pg_ts_template_tmplname,
+ Anum_pg_ts_template_tmplnamespace,
+ 0,
+ 0
+ },
+ 2
+ },
+ {TSTemplateRelationId, /* TSTEMPLATEOID */
+ TSTemplateOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 2
},
{TypeRelationId, /* TYPENAMENSP */
TypeNameNspIndexId,
- Anum_pg_type_typrelid,
2,
{
Anum_pg_type_typname,
0,
0
},
- 1024
+ 64
},
{TypeRelationId, /* TYPEOID */
TypeOidIndexId,
- Anum_pg_type_typrelid,
1,
{
ObjectIdAttributeNumber,
0,
0
},
- 1024
+ 64
+ },
+ {UserMappingRelationId, /* USERMAPPINGOID */
+ UserMappingOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 2
+ },
+ {UserMappingRelationId, /* USERMAPPINGUSERSERVER */
+ UserMappingUserServerIndexId,
+ 2,
+ {
+ Anum_pg_user_mapping_umuser,
+ Anum_pg_user_mapping_umserver,
+ 0,
+ 0
+ },
+ 2
}
};
-static CatCache *SysCache[
- lengthof(cacheinfo)];
-static int SysCacheSize = lengthof(cacheinfo);
+static CatCache *SysCache[SysCacheSize];
+
static bool CacheInitialized = false;
+/* Sorted array of OIDs of tables that have caches on them */
+static Oid SysCacheRelationOid[SysCacheSize];
+static int SysCacheRelationOidSize;
+
+/* Sorted array of OIDs of tables and indexes used by caches */
+static Oid SysCacheSupportingRelOid[SysCacheSize * 2];
+static int SysCacheSupportingRelOidSize;
+
+static int oid_compare(const void *a, const void *b);
+
/*
* InitCatalogCache - initialize the caches
*
* Note that no database access is done here; we only allocate memory
- * and initialize the cache structure. Interrogation of the database
+ * and initialize the cache structure. Interrogation of the database
* to complete initialization of a cache happens upon first use
* of that cache.
*/
InitCatalogCache(void)
{
int cacheId;
+ int i,
+ j;
+
+ StaticAssertStmt(SysCacheSize == (int) lengthof(cacheinfo),
+ "SysCacheSize does not match syscache.c's array");
Assert(!CacheInitialized);
- MemSet(SysCache, 0, sizeof(SysCache));
+ SysCacheRelationOidSize = SysCacheSupportingRelOidSize = 0;
for (cacheId = 0; cacheId < SysCacheSize; cacheId++)
{
SysCache[cacheId] = InitCatCache(cacheId,
cacheinfo[cacheId].reloid,
cacheinfo[cacheId].indoid,
- cacheinfo[cacheId].reloidattr,
cacheinfo[cacheId].nkeys,
cacheinfo[cacheId].key,
cacheinfo[cacheId].nbuckets);
if (!PointerIsValid(SysCache[cacheId]))
elog(ERROR, "could not initialize cache %u (%d)",
cacheinfo[cacheId].reloid, cacheId);
+ /* Accumulate data for OID lists, too */
+ SysCacheRelationOid[SysCacheRelationOidSize++] =
+ cacheinfo[cacheId].reloid;
+ SysCacheSupportingRelOid[SysCacheSupportingRelOidSize++] =
+ cacheinfo[cacheId].reloid;
+ SysCacheSupportingRelOid[SysCacheSupportingRelOidSize++] =
+ cacheinfo[cacheId].indoid;
+ /* see comments for RelationInvalidatesSnapshotsOnly */
+ Assert(!RelationInvalidatesSnapshotsOnly(cacheinfo[cacheId].reloid));
}
+
+ Assert(SysCacheRelationOidSize <= lengthof(SysCacheRelationOid));
+ Assert(SysCacheSupportingRelOidSize <= lengthof(SysCacheSupportingRelOid));
+
+ /* Sort and de-dup OID arrays, so we can use binary search. */
+ pg_qsort(SysCacheRelationOid, SysCacheRelationOidSize,
+ sizeof(Oid), oid_compare);
+ for (i = 1, j = 0; i < SysCacheRelationOidSize; i++)
+ {
+ if (SysCacheRelationOid[i] != SysCacheRelationOid[j])
+ SysCacheRelationOid[++j] = SysCacheRelationOid[i];
+ }
+ SysCacheRelationOidSize = j + 1;
+
+ pg_qsort(SysCacheSupportingRelOid, SysCacheSupportingRelOidSize,
+ sizeof(Oid), oid_compare);
+ for (i = 1, j = 0; i < SysCacheSupportingRelOidSize; i++)
+ {
+ if (SysCacheSupportingRelOid[i] != SysCacheSupportingRelOid[j])
+ SysCacheSupportingRelOid[++j] = SysCacheSupportingRelOid[i];
+ }
+ SysCacheSupportingRelOidSize = j + 1;
+
CacheInitialized = true;
}
-
/*
* InitCatalogCachePhase2 - finish initializing the caches
*
{
if (cacheId < 0 || cacheId >= SysCacheSize ||
!PointerIsValid(SysCache[cacheId]))
- elog(ERROR, "invalid cache id: %d", cacheId);
+ elog(ERROR, "invalid cache ID: %d", cacheId);
return SearchCatCache(SysCache[cacheId], key1, key2, key3, key4);
}
{
HeapTuple tuple;
- tuple = SearchSysCache(ATTNAME,
- ObjectIdGetDatum(relid),
- CStringGetDatum(attname),
- 0, 0);
+ tuple = SearchSysCache2(ATTNAME,
+ ObjectIdGetDatum(relid),
+ CStringGetDatum(attname));
if (!HeapTupleIsValid(tuple))
return NULL;
if (((Form_pg_attribute) GETSTRUCT(tuple))->attisdropped)
* extract a specific attribute.
*
* This is equivalent to using heap_getattr() on a tuple fetched
- * from a non-cached relation. Usually, this is only used for attributes
+ * from a non-cached relation. Usually, this is only used for attributes
* that could be NULL or variable length; the fixed-size attributes in
* a system table are accessed just by mapping the tuple onto the C struct
* declarations from include/catalog/.
*/
if (cacheId < 0 || cacheId >= SysCacheSize ||
!PointerIsValid(SysCache[cacheId]))
- elog(ERROR, "invalid cache id: %d", cacheId);
+ elog(ERROR, "invalid cache ID: %d", cacheId);
if (!PointerIsValid(SysCache[cacheId]->cc_tupdesc))
{
InitCatCachePhase2(SysCache[cacheId], false);
isNull);
}
+/*
+ * GetSysCacheHashValue
+ *
+ * Get the hash value that would be used for a tuple in the specified cache
+ * with the given search keys.
+ *
+ * The reason for exposing this as part of the API is that the hash value is
+ * exposed in cache invalidation operations, so there are places outside the
+ * catcache code that need to be able to compute the hash values.
+ */
+uint32
+GetSysCacheHashValue(int cacheId,
+ Datum key1,
+ Datum key2,
+ Datum key3,
+ Datum key4)
+{
+ if (cacheId < 0 || cacheId >= SysCacheSize ||
+ !PointerIsValid(SysCache[cacheId]))
+ elog(ERROR, "invalid cache ID: %d", cacheId);
+
+ return GetCatCacheHashValue(SysCache[cacheId], key1, key2, key3, key4);
+}
+
/*
* List-search interface
*/
{
if (cacheId < 0 || cacheId >= SysCacheSize ||
!PointerIsValid(SysCache[cacheId]))
- elog(ERROR, "invalid cache id: %d", cacheId);
+ elog(ERROR, "invalid cache ID: %d", cacheId);
return SearchCatCacheList(SysCache[cacheId], nkeys,
key1, key2, key3, key4);
}
+
+/*
+ * SysCacheInvalidate
+ *
+ * Invalidate entries in the specified cache, given a hash value.
+ * See CatCacheInvalidate() for more info.
+ *
+ * This routine is only quasi-public: it should only be used by inval.c.
+ */
+void
+SysCacheInvalidate(int cacheId, uint32 hashValue)
+{
+ if (cacheId < 0 || cacheId >= SysCacheSize)
+ elog(ERROR, "invalid cache ID: %d", cacheId);
+
+ /* if this cache isn't initialized yet, no need to do anything */
+ if (!PointerIsValid(SysCache[cacheId]))
+ return;
+
+ CatCacheInvalidate(SysCache[cacheId], hashValue);
+}
+
+/*
+ * Certain relations that do not have system caches send snapshot invalidation
+ * messages in lieu of catcache messages. This is for the benefit of
+ * GetCatalogSnapshot(), which can then reuse its existing MVCC snapshot
+ * for scanning one of those catalogs, rather than taking a new one, if no
+ * invalidation has been received.
+ *
+ * Relations that have syscaches need not (and must not) be listed here. The
+ * catcache invalidation messages will also flush the snapshot. If you add a
+ * syscache for one of these relations, remove it from this list.
+ */
+bool
+RelationInvalidatesSnapshotsOnly(Oid relid)
+{
+ switch (relid)
+ {
+ case DbRoleSettingRelationId:
+ case DependRelationId:
+ case SharedDependRelationId:
+ case DescriptionRelationId:
+ case SharedDescriptionRelationId:
+ case SecLabelRelationId:
+ case SharedSecLabelRelationId:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+/*
+ * Test whether a relation has a system cache.
+ */
+bool
+RelationHasSysCache(Oid relid)
+{
+ int low = 0,
+ high = SysCacheRelationOidSize - 1;
+
+ while (low <= high)
+ {
+ int middle = low + (high - low) / 2;
+
+ if (SysCacheRelationOid[middle] == relid)
+ return true;
+ if (SysCacheRelationOid[middle] < relid)
+ low = middle + 1;
+ else
+ high = middle - 1;
+ }
+
+ return false;
+}
+
+/*
+ * Test whether a relation supports a system cache, ie it is either a
+ * cached table or the index used for a cache.
+ */
+bool
+RelationSupportsSysCache(Oid relid)
+{
+ int low = 0,
+ high = SysCacheSupportingRelOidSize - 1;
+
+ while (low <= high)
+ {
+ int middle = low + (high - low) / 2;
+
+ if (SysCacheSupportingRelOid[middle] == relid)
+ return true;
+ if (SysCacheSupportingRelOid[middle] < relid)
+ low = middle + 1;
+ else
+ high = middle - 1;
+ }
+
+ return false;
+}
+
+
+/*
+ * OID comparator for pg_qsort
+ */
+static int
+oid_compare(const void *a, const void *b)
+{
+ Oid oa = *((const Oid *) a);
+ Oid ob = *((const Oid *) b);
+
+ if (oa == ob)
+ return 0;
+ return (oa > ob) ? 1 : -1;
+}