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 + -
显示快捷键?