ts_cache.c

来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 643 行 · 第 1/2 页

C
643
字号
/*------------------------------------------------------------------------- * * ts_cache.c *	  Tsearch related object caches. * * Tsearch performance is very sensitive to performance of parsers, * dictionaries and mapping, so lookups should be cached as much * as possible. * * Once a backend has created a cache entry for a particular TS object OID, * the cache entry will exist for the life of the backend; hence it is * safe to hold onto a pointer to the cache entry while doing things that * might result in recognizing a cache invalidation.  Beware however that * subsidiary information might be deleted and reallocated somewhere else * if a cache inval and reval happens!	This does not look like it will be * a big problem as long as parser and dictionary methods do not attempt * any database access. * * * Copyright (c) 2006-2008, PostgreSQL Global Development Group * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/utils/cache/ts_cache.c,v 1.5 2008/01/01 19:45:53 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/genam.h"#include "access/heapam.h"#include "access/xact.h"#include "catalog/indexing.h"#include "catalog/namespace.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 "commands/defrem.h"#include "miscadmin.h"#include "tsearch/ts_cache.h"#include "utils/array.h"#include "utils/builtins.h"#include "utils/catcache.h"#include "utils/fmgroids.h"#include "utils/inval.h"#include "utils/lsyscache.h"#include "utils/memutils.h"#include "utils/syscache.h"/* * MAXTOKENTYPE/MAXDICTSPERTT are arbitrary limits on the workspace size * used in lookup_ts_config_cache().  We could avoid hardwiring a limit * by making the workspace dynamically enlargeable, but it seems unlikely * to be worth the trouble. */#define MAXTOKENTYPE	256#define MAXDICTSPERTT	100static HTAB *TSParserCacheHash = NULL;static TSParserCacheEntry *lastUsedParser = NULL;static HTAB *TSDictionaryCacheHash = NULL;static TSDictionaryCacheEntry *lastUsedDictionary = NULL;static HTAB *TSConfigCacheHash = NULL;static TSConfigCacheEntry *lastUsedConfig = NULL;/* * GUC default_text_search_config, and a cache of the current config's OID */char	   *TSCurrentConfig = NULL;static Oid	TSCurrentConfigCache = InvalidOid;/* * We use this catcache callback to detect when a visible change to a TS * catalog entry has been made, by either our own backend or another one. * We don't get enough information to know *which* specific catalog row * changed, so we have to invalidate all related cache entries.  Fortunately, * it seems unlikely that TS configuration changes will occur often enough * for this to be a performance problem. * * We can use the same function for all TS caches by passing the hash * table address as the "arg". */static voidInvalidateTSCacheCallBack(Datum arg, Oid relid){	HTAB	   *hash = (HTAB *) DatumGetPointer(arg);	HASH_SEQ_STATUS status;	TSAnyCacheEntry *entry;	hash_seq_init(&status, hash);	while ((entry = (TSAnyCacheEntry *) hash_seq_search(&status)) != NULL)		entry->isvalid = false;	/* Also invalidate the current-config cache if it's pg_ts_config */	if (hash == TSConfigCacheHash)		TSCurrentConfigCache = InvalidOid;}/* * Fetch parser cache entry */TSParserCacheEntry *lookup_ts_parser_cache(Oid prsId){	TSParserCacheEntry *entry;	if (TSParserCacheHash == NULL)	{		/* First time through: initialize the hash table */		HASHCTL		ctl;		if (!CacheMemoryContext)			CreateCacheMemoryContext();		MemSet(&ctl, 0, sizeof(ctl));		ctl.keysize = sizeof(Oid);		ctl.entrysize = sizeof(TSParserCacheEntry);		ctl.hash = oid_hash;		TSParserCacheHash = hash_create("Tsearch parser cache", 4,										&ctl, HASH_ELEM | HASH_FUNCTION);		/* Flush cache on pg_ts_parser changes */		CacheRegisterSyscacheCallback(TSPARSEROID, InvalidateTSCacheCallBack,									  PointerGetDatum(TSParserCacheHash));	}	/* Check single-entry cache */	if (lastUsedParser && lastUsedParser->prsId == prsId &&		lastUsedParser->isvalid)		return lastUsedParser;	/* Try to look up an existing entry */	entry = (TSParserCacheEntry *) hash_search(TSParserCacheHash,											   (void *) &prsId,											   HASH_FIND, NULL);	if (entry == NULL || !entry->isvalid)	{		/*		 * If we didn't find one, we want to make one. But first look up the		 * object to be sure the OID is real.		 */		HeapTuple	tp;		Form_pg_ts_parser prs;		tp = SearchSysCache(TSPARSEROID,							ObjectIdGetDatum(prsId),							0, 0, 0);		if (!HeapTupleIsValid(tp))			elog(ERROR, "cache lookup failed for text search parser %u",				 prsId);		prs = (Form_pg_ts_parser) GETSTRUCT(tp);		/*		 * Sanity checks		 */		if (!OidIsValid(prs->prsstart))			elog(ERROR, "text search parser %u has no prsstart method", prsId);		if (!OidIsValid(prs->prstoken))			elog(ERROR, "text search parser %u has no prstoken method", prsId);		if (!OidIsValid(prs->prsend))			elog(ERROR, "text search parser %u has no prsend method", prsId);		if (entry == NULL)		{			bool		found;			/* Now make the cache entry */			entry = (TSParserCacheEntry *)				hash_search(TSParserCacheHash,							(void *) &prsId,							HASH_ENTER, &found);			Assert(!found);		/* it wasn't there a moment ago */		}		MemSet(entry, 0, sizeof(TSParserCacheEntry));		entry->prsId = prsId;		entry->startOid = prs->prsstart;		entry->tokenOid = prs->prstoken;		entry->endOid = prs->prsend;		entry->headlineOid = prs->prsheadline;		entry->lextypeOid = prs->prslextype;		ReleaseSysCache(tp);		fmgr_info_cxt(entry->startOid, &entry->prsstart, CacheMemoryContext);		fmgr_info_cxt(entry->tokenOid, &entry->prstoken, CacheMemoryContext);		fmgr_info_cxt(entry->endOid, &entry->prsend, CacheMemoryContext);		if (OidIsValid(entry->headlineOid))			fmgr_info_cxt(entry->headlineOid, &entry->prsheadline,						  CacheMemoryContext);		entry->isvalid = true;	}	lastUsedParser = entry;	return entry;}/* * Fetch dictionary cache entry */TSDictionaryCacheEntry *lookup_ts_dictionary_cache(Oid dictId){	TSDictionaryCacheEntry *entry;	if (TSDictionaryCacheHash == NULL)	{		/* First time through: initialize the hash table */		HASHCTL		ctl;		if (!CacheMemoryContext)			CreateCacheMemoryContext();		MemSet(&ctl, 0, sizeof(ctl));		ctl.keysize = sizeof(Oid);		ctl.entrysize = sizeof(TSDictionaryCacheEntry);		ctl.hash = oid_hash;		TSDictionaryCacheHash = hash_create("Tsearch dictionary cache", 8,											&ctl, HASH_ELEM | HASH_FUNCTION);		/* Flush cache on pg_ts_dict and pg_ts_template changes */		CacheRegisterSyscacheCallback(TSDICTOID, InvalidateTSCacheCallBack,									  PointerGetDatum(TSDictionaryCacheHash));		CacheRegisterSyscacheCallback(TSTEMPLATEOID, InvalidateTSCacheCallBack,									  PointerGetDatum(TSDictionaryCacheHash));	}	/* Check single-entry cache */	if (lastUsedDictionary && lastUsedDictionary->dictId == dictId &&		lastUsedDictionary->isvalid)		return lastUsedDictionary;	/* Try to look up an existing entry */	entry = (TSDictionaryCacheEntry *) hash_search(TSDictionaryCacheHash,												   (void *) &dictId,												   HASH_FIND, NULL);	if (entry == NULL || !entry->isvalid)	{		/*		 * If we didn't find one, we want to make one. But first look up the		 * object to be sure the OID is real.		 */		HeapTuple	tpdict,					tptmpl;		Form_pg_ts_dict dict;		Form_pg_ts_template template;		MemoryContext saveCtx;		tpdict = SearchSysCache(TSDICTOID,								ObjectIdGetDatum(dictId),								0, 0, 0);		if (!HeapTupleIsValid(tpdict))			elog(ERROR, "cache lookup failed for text search dictionary %u",				 dictId);		dict = (Form_pg_ts_dict) GETSTRUCT(tpdict);		/*		 * Sanity checks		 */		if (!OidIsValid(dict->dicttemplate))			elog(ERROR, "text search dictionary %u has no template", dictId);		/*		 * Retrieve dictionary's template		 */		tptmpl = SearchSysCache(TSTEMPLATEOID,								ObjectIdGetDatum(dict->dicttemplate),								0, 0, 0);		if (!HeapTupleIsValid(tptmpl))			elog(ERROR, "cache lookup failed for text search template %u",				 dict->dicttemplate);		template = (Form_pg_ts_template) GETSTRUCT(tptmpl);		/*		 * Sanity checks		 */		if (!OidIsValid(template->tmpllexize))			elog(ERROR, "text search template %u has no lexize method",				 template->tmpllexize);		if (entry == NULL)		{			bool		found;			/* Now make the cache entry */			entry = (TSDictionaryCacheEntry *)				hash_search(TSDictionaryCacheHash,							(void *) &dictId,							HASH_ENTER, &found);			Assert(!found);		/* it wasn't there a moment ago */			/* Create private memory context the first time through */			saveCtx = AllocSetContextCreate(CacheMemoryContext,											NameStr(dict->dictname),											ALLOCSET_SMALL_MINSIZE,											ALLOCSET_SMALL_INITSIZE,											ALLOCSET_SMALL_MAXSIZE);		}		else		{			/* Clear the existing entry's private context */			saveCtx = entry->dictCtx;			MemoryContextResetAndDeleteChildren(saveCtx);		}		MemSet(entry, 0, sizeof(TSDictionaryCacheEntry));		entry->dictId = dictId;		entry->dictCtx = saveCtx;		entry->lexizeOid = template->tmpllexize;		if (OidIsValid(template->tmplinit))		{			List	   *dictoptions;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?