From: Arthur Zakirov Date: Thu, 17 Jan 2019 15:05:44 +0300 Subject: [PATCH 2/4] Change-tmplinit-argument --- contrib/dict_int/dict_int.c | 4 +- contrib/dict_xsyn/dict_xsyn.c | 4 +- contrib/unaccent/unaccent.c | 4 +- src/backend/commands/tsearchcmds.c | 10 ++++- src/backend/snowball/dict_snowball.c | 4 +- src/backend/tsearch/dict_ispell.c | 4 +- src/backend/tsearch/dict_simple.c | 4 +- src/backend/tsearch/dict_synonym.c | 4 +- src/backend/tsearch/dict_thesaurus.c | 4 +- src/backend/utils/cache/ts_cache.c | 13 +++++- src/include/tsearch/ts_cache.h | 4 ++ src/include/tsearch/ts_public.h | 67 ++++++++++++++++++++++++++-- 12 files changed, 105 insertions(+), 21 deletions(-) diff --git a/contrib/dict_int/dict_int.c b/contrib/dict_int/dict_int.c index 628b9769c3..ddde55eee4 100644 --- a/contrib/dict_int/dict_int.c +++ b/contrib/dict_int/dict_int.c @@ -30,7 +30,7 @@ PG_FUNCTION_INFO_V1(dintdict_lexize); Datum dintdict_init(PG_FUNCTION_ARGS) { - List *dictoptions = (List *) PG_GETARG_POINTER(0); + DictInitData *init_data = (DictInitData *) PG_GETARG_POINTER(0); DictInt *d; ListCell *l; @@ -38,7 +38,7 @@ dintdict_init(PG_FUNCTION_ARGS) d->maxlen = 6; d->rejectlong = false; - foreach(l, dictoptions) + foreach(l, init_data->dict_options) { DefElem *defel = (DefElem *) lfirst(l); diff --git a/contrib/dict_xsyn/dict_xsyn.c b/contrib/dict_xsyn/dict_xsyn.c index 509e14aee0..15b1a0033a 100644 --- a/contrib/dict_xsyn/dict_xsyn.c +++ b/contrib/dict_xsyn/dict_xsyn.c @@ -140,7 +140,7 @@ read_dictionary(DictSyn *d, const char *filename) Datum dxsyn_init(PG_FUNCTION_ARGS) { - List *dictoptions = (List *) PG_GETARG_POINTER(0); + DictInitData *init_data = (DictInitData *) PG_GETARG_POINTER(0); DictSyn *d; ListCell *l; char *filename = NULL; @@ -153,7 +153,7 @@ dxsyn_init(PG_FUNCTION_ARGS) d->matchsynonyms = false; d->keepsynonyms = true; - foreach(l, dictoptions) + foreach(l, init_data->dict_options) { DefElem *defel = (DefElem *) lfirst(l); diff --git a/contrib/unaccent/unaccent.c b/contrib/unaccent/unaccent.c index fc5176e338..f3663cefd0 100644 --- a/contrib/unaccent/unaccent.c +++ b/contrib/unaccent/unaccent.c @@ -270,12 +270,12 @@ PG_FUNCTION_INFO_V1(unaccent_init); Datum unaccent_init(PG_FUNCTION_ARGS) { - List *dictoptions = (List *) PG_GETARG_POINTER(0); + DictInitData *init_data = (DictInitData *) PG_GETARG_POINTER(0); TrieChar *rootTrie = NULL; bool fileloaded = false; ListCell *l; - foreach(l, dictoptions) + foreach(l, init_data->dict_options) { DefElem *defel = (DefElem *) lfirst(l); diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c index 8e5eec22b5..30c5eb72a2 100644 --- a/src/backend/commands/tsearchcmds.c +++ b/src/backend/commands/tsearchcmds.c @@ -389,17 +389,25 @@ verify_dictoptions(Oid tmplId, List *dictoptions) } else { + DictInitData init_data; + /* * Copy the options just in case init method thinks it can scribble on * them ... */ dictoptions = copyObject(dictoptions); + init_data.dict_options = dictoptions; + init_data.dict.id = InvalidOid; + init_data.dict.xmin = InvalidTransactionId; + init_data.dict.xmax = InvalidTransactionId; + ItemPointerSetInvalid(&init_data.dict.tid); + /* * Call the init method and see if it complains. We don't worry about * it leaking memory, since our command will soon be over anyway. */ - (void) OidFunctionCall1(initmethod, PointerGetDatum(dictoptions)); + (void) OidFunctionCall1(initmethod, PointerGetDatum(&init_data)); } ReleaseSysCache(tup); diff --git a/src/backend/snowball/dict_snowball.c b/src/backend/snowball/dict_snowball.c index 5166738310..f30f29865c 100644 --- a/src/backend/snowball/dict_snowball.c +++ b/src/backend/snowball/dict_snowball.c @@ -201,14 +201,14 @@ locate_stem_module(DictSnowball *d, const char *lang) Datum dsnowball_init(PG_FUNCTION_ARGS) { - List *dictoptions = (List *) PG_GETARG_POINTER(0); + DictInitData *init_data = (DictInitData *) PG_GETARG_POINTER(0); DictSnowball *d; bool stoploaded = false; ListCell *l; d = (DictSnowball *) palloc0(sizeof(DictSnowball)); - foreach(l, dictoptions) + foreach(l, init_data->dict_options) { DefElem *defel = (DefElem *) lfirst(l); diff --git a/src/backend/tsearch/dict_ispell.c b/src/backend/tsearch/dict_ispell.c index 8b05a477f1..fc9a96abca 100644 --- a/src/backend/tsearch/dict_ispell.c +++ b/src/backend/tsearch/dict_ispell.c @@ -29,7 +29,7 @@ typedef struct Datum dispell_init(PG_FUNCTION_ARGS) { - List *dictoptions = (List *) PG_GETARG_POINTER(0); + DictInitData *init_data = (DictInitData *) PG_GETARG_POINTER(0); DictISpell *d; bool affloaded = false, dictloaded = false, @@ -40,7 +40,7 @@ dispell_init(PG_FUNCTION_ARGS) NIStartBuild(&(d->obj)); - foreach(l, dictoptions) + foreach(l, init_data->dict_options) { DefElem *defel = (DefElem *) lfirst(l); diff --git a/src/backend/tsearch/dict_simple.c b/src/backend/tsearch/dict_simple.c index 2f62ef00c8..c92744641b 100644 --- a/src/backend/tsearch/dict_simple.c +++ b/src/backend/tsearch/dict_simple.c @@ -29,7 +29,7 @@ typedef struct Datum dsimple_init(PG_FUNCTION_ARGS) { - List *dictoptions = (List *) PG_GETARG_POINTER(0); + DictInitData *init_data = (DictInitData *) PG_GETARG_POINTER(0); DictSimple *d = (DictSimple *) palloc0(sizeof(DictSimple)); bool stoploaded = false, acceptloaded = false; @@ -37,7 +37,7 @@ dsimple_init(PG_FUNCTION_ARGS) d->accept = true; /* default */ - foreach(l, dictoptions) + foreach(l, init_data->dict_options) { DefElem *defel = (DefElem *) lfirst(l); diff --git a/src/backend/tsearch/dict_synonym.c b/src/backend/tsearch/dict_synonym.c index b6226df940..d3f5f0da3f 100644 --- a/src/backend/tsearch/dict_synonym.c +++ b/src/backend/tsearch/dict_synonym.c @@ -91,7 +91,7 @@ compareSyn(const void *a, const void *b) Datum dsynonym_init(PG_FUNCTION_ARGS) { - List *dictoptions = (List *) PG_GETARG_POINTER(0); + DictInitData *init_data = (DictInitData *) PG_GETARG_POINTER(0); DictSyn *d; ListCell *l; char *filename = NULL; @@ -104,7 +104,7 @@ dsynonym_init(PG_FUNCTION_ARGS) char *line = NULL; uint16 flags = 0; - foreach(l, dictoptions) + foreach(l, init_data->dict_options) { DefElem *defel = (DefElem *) lfirst(l); diff --git a/src/backend/tsearch/dict_thesaurus.c b/src/backend/tsearch/dict_thesaurus.c index 75f8deef6a..8962e252e0 100644 --- a/src/backend/tsearch/dict_thesaurus.c +++ b/src/backend/tsearch/dict_thesaurus.c @@ -604,7 +604,7 @@ compileTheSubstitute(DictThesaurus *d) Datum thesaurus_init(PG_FUNCTION_ARGS) { - List *dictoptions = (List *) PG_GETARG_POINTER(0); + DictInitData *init_data = (DictInitData *) PG_GETARG_POINTER(0); DictThesaurus *d; char *subdictname = NULL; bool fileloaded = false; @@ -612,7 +612,7 @@ thesaurus_init(PG_FUNCTION_ARGS) d = (DictThesaurus *) palloc0(sizeof(DictThesaurus)); - foreach(l, dictoptions) + foreach(l, init_data->dict_options) { DefElem *defel = (DefElem *) lfirst(l); diff --git a/src/backend/utils/cache/ts_cache.c b/src/backend/utils/cache/ts_cache.c index 0545efc75b..8bc8d82c76 100644 --- a/src/backend/utils/cache/ts_cache.c +++ b/src/backend/utils/cache/ts_cache.c @@ -39,6 +39,7 @@ #include "catalog/pg_ts_template.h" #include "commands/defrem.h" #include "tsearch/ts_cache.h" +#include "tsearch/ts_public.h" #include "utils/builtins.h" #include "utils/catcache.h" #include "utils/fmgroids.h" @@ -311,11 +312,15 @@ lookup_ts_dictionary_cache(Oid dictId) MemSet(entry, 0, sizeof(TSDictionaryCacheEntry)); entry->dictId = dictId; entry->dictCtx = saveCtx; + entry->dict_xmin = HeapTupleHeaderGetRawXmin(tpdict->t_data); + entry->dict_xmax = HeapTupleHeaderGetRawXmax(tpdict->t_data); + entry->dict_tid = tpdict->t_self; entry->lexizeOid = template->tmpllexize; if (OidIsValid(template->tmplinit)) { + DictInitData init_data; List *dictoptions; Datum opt; bool isnull; @@ -335,9 +340,15 @@ lookup_ts_dictionary_cache(Oid dictId) else dictoptions = deserialize_deflist(opt); + init_data.dict_options = dictoptions; + init_data.dict.id = dictId; + init_data.dict.xmin = entry->dict_xmin; + init_data.dict.xmax = entry->dict_xmax; + init_data.dict.tid = entry->dict_tid; + entry->dictData = DatumGetPointer(OidFunctionCall1(template->tmplinit, - PointerGetDatum(dictoptions))); + PointerGetDatum(&init_data))); MemoryContextSwitchTo(oldcontext); } diff --git a/src/include/tsearch/ts_cache.h b/src/include/tsearch/ts_cache.h index 77e325d101..2298e0a275 100644 --- a/src/include/tsearch/ts_cache.h +++ b/src/include/tsearch/ts_cache.h @@ -54,6 +54,10 @@ typedef struct TSDictionaryCacheEntry Oid dictId; bool isvalid; + TransactionId dict_xmin; /* XMIN of the dictionary's tuple */ + TransactionId dict_xmax; /* XMAX of the dictionary's tuple */ + ItemPointerData dict_tid; /* TID of the dictionary's tuple */ + /* most frequent fmgr call */ Oid lexizeOid; FmgrInfo lexize; diff --git a/src/include/tsearch/ts_public.h b/src/include/tsearch/ts_public.h index b325fa122c..db028ed6ad 100644 --- a/src/include/tsearch/ts_public.h +++ b/src/include/tsearch/ts_public.h @@ -13,6 +13,8 @@ #ifndef _PG_TS_PUBLIC_H_ #define _PG_TS_PUBLIC_H_ +#include "nodes/pg_list.h" +#include "storage/itemptr.h" #include "tsearch/ts_type.h" /* @@ -81,10 +83,69 @@ extern void readstoplist(const char *fname, StopList *s, extern bool searchstoplist(StopList *s, char *key); /* - * Interface with dictionaries + * API for text search dictionaries. + * + * API functions to manage a text search dictionary are defined by a text search + * template. Currently an existing template cannot be altered in order to use + * different functions. API consists of the following functions: + * + * init function + * ------------- + * - optional function which initializes internal structures of the dictionary + * - accepts DictInitData structure as an argument and must return a custom + * palloc'd structure which stores content of the processed dictionary and + * is used by lexize function + * + * lexize function + * --------------- + * - normalizes a single word (token) using specific dictionary + * - returns a palloc'd array of TSLexeme, with a terminating NULL entry + * - accepts the following arguments: + * + * - dictData - pointer to a structure returned by init function or NULL if + * init function wasn't defined by the template + * - token - string to normalize (not null-terminated) + * - length - length of the token + * - dictState - pointer to a DictSubState structure storing current + * state of a set of tokens processing and allows to normalize phrases + */ + +/* + * A preprocessed dictionary can be stored in shared memory using DSM - this is + * decided in the init function. A DSM segment is released after altering or + * dropping the dictionary. The segment may still leak, when a backend uses the + * dictionary right before dropping - in that case the backend will hold the DSM + * untill it disconnects or calls lookup_ts_dictionary_cache(). + * + * DictEntryData represents DSM segment with a preprocessed dictionary. We need + * to ensure the content of the DSM segment is still valid, which is what xmin, + * xmax and tid are for. + */ +typedef struct +{ + Oid id; /* OID of the dictionary */ + TransactionId xmin; /* XMIN of the dictionary's tuple */ + TransactionId xmax; /* XMAX of the dictionary's tuple */ + ItemPointerData tid; /* TID of the dictionary's tuple */ +} DictEntryData; + +/* + * API structure for a dictionary initialization. It is passed as an argument + * to a template's init function. */ +typedef struct +{ + /* List of options for a template's init method */ + List *dict_options; + + /* Data used to allocate, search and release the DSM segment */ + DictEntryData dict; +} DictInitData; -/* return struct for any lexize function */ +/* + * Return struct for any lexize function. They are combined into an array, the + * last entry is the terminating entry. + */ typedef struct { /*---------- @@ -108,7 +169,7 @@ typedef struct uint16 flags; /* See flag bits below */ - char *lexeme; /* C string */ + char *lexeme; /* C string (NULL for terminating entry) */ } TSLexeme; /* Flag bits that can appear in TSLexeme.flags */ -- 2.20.1 --------------9E285E8AF9A980CD1515771F Content-Type: text/x-patch; name="0003-Retrieve-shared-location-for-dict-v18.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="0003-Retrieve-shared-location-for-dict-v18.patch"