shared_dictionary_02.diff
application/octet-stream
Filename: shared_dictionary_02.diff
Type: application/octet-stream
Part: 0
Message:
WIP: shared ispell dictionary
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: context
| File | + | − |
|---|---|---|
| src/backend/storage/ipc/ipci.c | 5 | 0 |
| src/backend/tsearch/dict_ispell.c | 146 | 6 |
| src/backend/tsearch/spell.c | 108 | 76 |
| src/backend/tsearch/ts_utils.c | 16 | 0 |
| src/backend/utils/cache/ts_cache.c | 3 | 2 |
| src/backend/utils/misc/guc.c | 12 | 0 |
| src/backend/utils/misc/postgresql.conf.sample | 2 | 0 |
| src/backend/utils/mmgr/Makefile | 1 | 1 |
| src/backend/utils/mmgr/simple_alloc.c | 348 | 0 |
| src/include/nodes/memnodes.h | 1 | 1 |
| src/include/nodes/nodes.h | 1 | 0 |
| src/include/tsearch/dicts/spell.h | 6 | 4 |
| src/include/tsearch/ts_public.h | 1 | 0 |
| src/include/utils/memutils.h | 8 | 0 |
*** ./src/backend/storage/ipc/ipci.c.orig 2010-03-17 18:36:47.332657055 +0100
--- ./src/backend/storage/ipc/ipci.c 2010-03-18 07:48:42.559964237 +0100
***************
*** 43,48 ****
--- 43,50 ----
static Size total_addin_request = 0;
static bool addin_request_allowed = true;
+ extern int shared_data;
+
/*
* RequestAddinShmemSpace
***************
*** 132,137 ****
--- 134,142 ----
addin_request_allowed = false;
size = add_size(size, total_addin_request);
+ /* reserve shared memory for possible common data as ispell dictionaries */
+ size = add_size(size, shared_data * 1024);
+
/* might as well round it off to a multiple of a typical page size */
size = add_size(size, 8192 - (size % 8192));
*** ./src/backend/tsearch/dict_ispell.c.orig 2010-03-15 15:10:31.997321968 +0100
--- ./src/backend/tsearch/dict_ispell.c 2010-03-18 11:07:14.991697973 +0100
***************
*** 14,19 ****
--- 14,21 ----
#include "postgres.h"
#include "commands/defrem.h"
+ #include "storage/lwlock.h"
+ #include "storage/shmem.h"
#include "tsearch/dicts/spell.h"
#include "tsearch/ts_locale.h"
#include "tsearch/ts_public.h"
***************
*** 21,26 ****
--- 23,29 ----
#include "utils/builtins.h"
#include "utils/memutils.h"
+ #define MAX_SHARED_DICTIONARIES 32
typedef struct
{
***************
*** 28,33 ****
--- 31,51 ----
IspellDict obj;
} DictISpell;
+ typedef struct
+ {
+ Oid oid;
+ DictISpell spell;
+ } IndexedDict;
+
+ typedef struct
+ {
+ LWLockId lock;
+ int nspells;
+ IndexedDict dicts[MAX_SHARED_DICTIONARIES];
+ } ISpellCache;
+
+ static ISpellCache *cache = NULL;
+
Datum
dispell_init(PG_FUNCTION_ARGS)
{
***************
*** 37,44 ****
dictloaded = false,
stoploaded = false;
ListCell *l;
! d = (DictISpell *) palloc0(sizeof(DictISpell));
foreach(l, dictoptions)
{
--- 55,166 ----
dictloaded = false,
stoploaded = false;
ListCell *l;
+ MemoryContext target_ctx = NULL;
+ MemoryContext work_ctx = NULL;
+ MemoryContext oldctx;
+ bool share = false;
+ Oid requested_oid = PG_GETARG_OID(1);
! /* search possible share flag */
! foreach(l, dictoptions)
! {
! DefElem *defel = (DefElem *) lfirst(l);
!
! if (pg_strcasecmp(defel->defname, "share") == 0)
! {
! if (pg_strcasecmp(defGetString(defel), "yes") == 0)
! share = true;
! else if (pg_strcasecmp(defGetString(defel), "on") == 0)
! share = true;
! else if (pg_strcasecmp(defGetString(defel), "no") == 0)
! share = false;
! else if (pg_strcasecmp(defGetString(defel), "off") == 0)
! share = false;
! else
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! errmsg("unsupported value of \"share\" option"),
! errhint("Use yes, no, on or off.")));
! break;
! }
! }
!
! if (share)
! {
! bool found;
! int i;
!
! if (cache == NULL)
! {
! LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
!
! /* try to take access to cache memory */
! cache = ShmemInitStruct("Shared ispell dictionaries ",
! sizeof(ISpellCache),
! &found);
! if (!cache)
! elog(ERROR, "out of shared memory");
!
! if (!found)
! {
! /* initialise cache */
! memset(cache, 0, sizeof(ISpellCache));
! cache->lock = LWLockAssign();
! }
!
! LWLockRelease(AddinShmemInitLock);
! }
!
! LWLockAcquire(cache->lock, LW_EXCLUSIVE);
!
! /*
! * try to find dictionary in cache.
! */
! for (i = 0; i < cache->nspells; i++)
! {
! if (cache->dicts[i].oid == requested_oid)
! {
! d = &(cache->dicts[i].spell);
! LWLockRelease(cache->lock);
!
! PG_RETURN_POINTER(d);
! }
! }
!
! if (cache->nspells >= MAX_SHARED_DICTIONARIES)
! elog(ERROR, "too much shered dictionaries");
!
! cache->dicts[cache->nspells].oid = requested_oid;
! d = &(cache->dicts[cache->nspells++].spell);
!
! /*
! * target is inside shared memory
! */
! target_ctx = SimpleAllocContextCreate(CurrentMemoryContext,
! "Ispell dictionary target context (simple allocator)",
! SIMPLEALLOC_LARGE_INITSIZE,
! ShmemAlloc,
! NULL);
! }
! else
! {
! /*
! * Create simple alloc context, but in process mem.
! */
! target_ctx = SimpleAllocContextCreate(CurrentMemoryContext,
! "Ispell dictionary target context (simple allocator)",
! SIMPLEALLOC_LARGE_INITSIZE,
! malloc,
! free);
! d = (DictISpell *) palloc0(sizeof(DictISpell));
! }
!
! work_ctx = AllocSetContextCreate(CurrentMemoryContext, "Ispell dictionary temporary context",
! ALLOCSET_DEFAULT_MINSIZE,
! ALLOCSET_DEFAULT_INITSIZE,
! ALLOCSET_DEFAULT_MAXSIZE);
!
! oldctx = MemoryContextSwitchTo(work_ctx);
foreach(l, dictoptions)
{
***************
*** 52,58 ****
errmsg("multiple DictFile parameters")));
NIImportDictionary(&(d->obj),
get_tsearch_config_filename(defGetString(defel),
! "dict"));
dictloaded = true;
}
else if (pg_strcasecmp(defel->defname, "AffFile") == 0)
--- 174,181 ----
errmsg("multiple DictFile parameters")));
NIImportDictionary(&(d->obj),
get_tsearch_config_filename(defGetString(defel),
! "dict"),
! target_ctx);
dictloaded = true;
}
else if (pg_strcasecmp(defel->defname, "AffFile") == 0)
***************
*** 63,69 ****
errmsg("multiple AffFile parameters")));
NIImportAffixes(&(d->obj),
get_tsearch_config_filename(defGetString(defel),
! "affix"));
affloaded = true;
}
else if (pg_strcasecmp(defel->defname, "StopWords") == 0)
--- 186,193 ----
errmsg("multiple AffFile parameters")));
NIImportAffixes(&(d->obj),
get_tsearch_config_filename(defGetString(defel),
! "affix"),
! target_ctx);
affloaded = true;
}
else if (pg_strcasecmp(defel->defname, "StopWords") == 0)
***************
*** 74,79 ****
--- 198,209 ----
errmsg("multiple StopWords parameters")));
readstoplist(defGetString(defel), &(d->stoplist), lowerstr);
stoploaded = true;
+
+ PersistStoplist(&d->stoplist, target_ctx);
+ }
+ else if (pg_strcasecmp(defel->defname, "share") == 0)
+ {
+ /* do nothing */
}
else
{
***************
*** 86,93 ****
if (affloaded && dictloaded)
{
! NISortDictionary(&(d->obj));
! NISortAffixes(&(d->obj));
}
else if (!affloaded)
{
--- 216,225 ----
if (affloaded && dictloaded)
{
! NISortDictionary(&(d->obj), target_ctx);
! NISortAffixes(&(d->obj), target_ctx);
!
! PersistAffixes(&(d->obj), target_ctx);
}
else if (!affloaded)
{
***************
*** 102,108 ****
errmsg("missing DictFile parameter")));
}
! MemoryContextDeleteChildren(CurrentMemoryContext);
PG_RETURN_POINTER(d);
}
--- 234,248 ----
errmsg("missing DictFile parameter")));
}
!
! MemoryContextSwitchTo(oldctx);
! MemoryContextDelete(work_ctx);
!
! if (share)
! {
! /* unlock share memory */
! LWLockRelease(cache->lock);
! }
PG_RETURN_POINTER(d);
}
*** ./src/backend/tsearch/spell.c.orig 2010-01-02 17:57:53.000000000 +0100
--- ./src/backend/tsearch/spell.c 2010-03-17 18:37:39.524782011 +0100
***************
*** 19,35 ****
#include "utils/memutils.h"
! /*
! * Initialization requires a lot of memory that's not needed
! * after the initialization is done. In init function,
! * CurrentMemoryContext is a long lived memory context associated
! * with the dictionary cache entry, so we use a temporary context
! * for the short-lived stuff.
! */
! static MemoryContext tmpCtx = NULL;
! #define tmpalloc(sz) MemoryContextAlloc(tmpCtx, (sz))
! #define tmpalloc0(sz) MemoryContextAllocZero(tmpCtx, (sz))
static void
checkTmpCtx(void)
--- 19,28 ----
#include "utils/memutils.h"
! static MemoryContext simple_ctx = NULL;
! #define simple_alloc(sz) MemoryContextAlloc(simple_ctx, (sz))
! #define simple_alloc0(sz) MemoryContextAllocZero(simple_ctx, (sz))
static void
checkTmpCtx(void)
***************
*** 38,66 ****
* XXX: This assumes that CurrentMemoryContext doesn't have any children
* other than the one we create here.
*/
! if (CurrentMemoryContext->firstchild == NULL)
{
! tmpCtx = AllocSetContextCreate(CurrentMemoryContext,
! "Ispell dictionary init context",
! ALLOCSET_DEFAULT_MINSIZE,
! ALLOCSET_DEFAULT_INITSIZE,
! ALLOCSET_DEFAULT_MAXSIZE);
}
else
! tmpCtx = CurrentMemoryContext->firstchild;
! }
!
! static char *
! lowerstr_ctx(char *src)
! {
! MemoryContext saveCtx;
! char *dst;
!
! saveCtx = MemoryContextSwitchTo(tmpCtx);
! dst = lowerstr(src);
! MemoryContextSwitchTo(saveCtx);
!
! return dst;
}
#define MAX_NORM 1024
--- 31,46 ----
* XXX: This assumes that CurrentMemoryContext doesn't have any children
* other than the one we create here.
*/
! if (CurrentMemoryContext->firstchild == NULL)
{
! simple_ctx = SimpleAllocContextCreate(CurrentMemoryContext,
! "Ispell dictionary temporary context (simple allocator)",
! SIMPLEALLOC_LARGE_INITSIZE,
! malloc,
! free);
}
else
! simple_ctx = CurrentMemoryContext->firstchild;
}
#define MAX_NORM 1024
***************
*** 176,185 ****
else
{
Conf->mspell = 1024 * 20;
! Conf->Spell = (SPELL **) tmpalloc(Conf->mspell * sizeof(SPELL *));
}
}
! Conf->Spell[Conf->nspell] = (SPELL *) tmpalloc(SPELLHDRSZ + strlen(word) + 1);
strcpy(Conf->Spell[Conf->nspell]->word, word);
strncpy(Conf->Spell[Conf->nspell]->p.flag, flag, MAXFLAGLEN);
Conf->nspell++;
--- 156,165 ----
else
{
Conf->mspell = 1024 * 20;
! Conf->Spell = (SPELL **) palloc(Conf->mspell * sizeof(SPELL *));
}
}
! Conf->Spell[Conf->nspell] = (SPELL *) simple_alloc(SPELLHDRSZ + strlen(word) + 1);
strcpy(Conf->Spell[Conf->nspell]->word, word);
strncpy(Conf->Spell[Conf->nspell]->p.flag, flag, MAXFLAGLEN);
Conf->nspell++;
***************
*** 191,197 ****
* Note caller must already have applied get_tsearch_config_filename
*/
void
! NIImportDictionary(IspellDict *Conf, const char *filename)
{
tsearch_readline_state trst;
char *line;
--- 171,177 ----
* Note caller must already have applied get_tsearch_config_filename
*/
void
! NIImportDictionary(IspellDict *Conf, const char *filename, MemoryContext target_ctx)
{
tsearch_readline_state trst;
char *line;
***************
*** 242,252 ****
}
s += pg_mblen(s);
}
! pstr = lowerstr_ctx(line);
NIAddSpell(Conf, pstr, flag);
pfree(pstr);
-
pfree(line);
}
tsearch_readline_end(&trst);
--- 222,231 ----
}
s += pg_mblen(s);
}
! pstr = lowerstr(line);
NIAddSpell(Conf, pstr, flag);
pfree(pstr);
pfree(line);
}
tsearch_readline_end(&trst);
***************
*** 302,308 ****
}
static void
! NIAddAffix(IspellDict *Conf, int flag, char flagflags, const char *mask, const char *find, const char *repl, int type)
{
AFFIX *Affix;
--- 281,291 ----
}
static void
! NIAddAffix(IspellDict *Conf, int flag, char flagflags, const char *mask,
! const char *find,
! const char *repl,
! int type,
! MemoryContext target_ctx)
{
AFFIX *Affix;
***************
*** 332,338 ****
Affix->issimple = 0;
Affix->isregis = 1;
RS_compile(&(Affix->reg.regis), (type == FF_SUFFIX) ? true : false,
! (mask && *mask) ? mask : VoidString);
}
else
{
--- 315,321 ----
Affix->issimple = 0;
Affix->isregis = 1;
RS_compile(&(Affix->reg.regis), (type == FF_SUFFIX) ? true : false,
! (mask && *mask) ? mask : VoidString, target_ctx);
}
else
{
***************
*** 341,357 ****
int err;
pg_wchar *wmask;
char *tmask;
!
Affix->issimple = 0;
Affix->isregis = 0;
! tmask = (char *) tmpalloc(strlen(mask) + 3);
if (type == FF_SUFFIX)
sprintf(tmask, "%s$", mask);
else
sprintf(tmask, "^%s", mask);
masklen = strlen(tmask);
! wmask = (pg_wchar *) tmpalloc((masklen + 1) * sizeof(pg_wchar));
wmasklen = pg_mb2wchar_with_len(tmask, wmask, masklen);
err = pg_regcomp(&(Affix->reg.regex), wmask, wmasklen, REG_ADVANCED | REG_NOSUB);
--- 324,346 ----
int err;
pg_wchar *wmask;
char *tmask;
!
! /*
! * ToDo: Have to store compiled result to simple alloc context
! *
! * Pavel St
! */
!
Affix->issimple = 0;
Affix->isregis = 0;
! tmask = (char *) simple_alloc(strlen(mask) + 3);
if (type == FF_SUFFIX)
sprintf(tmask, "%s$", mask);
else
sprintf(tmask, "^%s", mask);
masklen = strlen(tmask);
! wmask = (pg_wchar *) simple_alloc((masklen + 1) * sizeof(pg_wchar));
wmasklen = pg_mb2wchar_with_len(tmask, wmask, masklen);
err = pg_regcomp(&(Affix->reg.regex), wmask, wmasklen, REG_ADVANCED | REG_NOSUB);
***************
*** 375,383 ****
Affix->flag = flag;
Affix->type = type;
! Affix->find = (find && *find) ? pstrdup(find) : VoidString;
if ((Affix->replen = strlen(repl)) > 0)
! Affix->repl = pstrdup(repl);
else
Affix->repl = VoidString;
Conf->naffixes++;
--- 364,372 ----
Affix->flag = flag;
Affix->type = type;
! Affix->find = (find && *find) ? MemoryContextStrdup(target_ctx,find) : VoidString;
if ((Affix->replen = strlen(repl)) > 0)
! Affix->repl = MemoryContextStrdup(target_ctx, repl);
else
Affix->repl = VoidString;
Conf->naffixes++;
***************
*** 526,532 ****
}
static void
! NIImportOOAffixes(IspellDict *Conf, const char *filename)
{
char type[BUFSIZ],
*ptype = NULL;
--- 515,521 ----
}
static void
! NIImportOOAffixes(IspellDict *Conf, const char *filename, MemoryContext target_ctx)
{
char type[BUFSIZ],
*ptype = NULL;
***************
*** 624,630 ****
if (ptype)
pfree(ptype);
! ptype = lowerstr_ctx(type);
if (scanread < 4 || (STRNCMP(ptype, "sfx") && STRNCMP(ptype, "pfx")))
goto nextline;
--- 613,619 ----
if (ptype)
pfree(ptype);
! ptype = lowerstr(type);
if (scanread < 4 || (STRNCMP(ptype, "sfx") && STRNCMP(ptype, "pfx")))
goto nextline;
***************
*** 646,652 ****
if (strlen(sflag) != 1 || flag != *sflag || flag == 0)
goto nextline;
! prepl = lowerstr_ctx(repl);
/* affix flag */
if ((ptr = strchr(prepl, '/')) != NULL)
{
--- 635,641 ----
if (strlen(sflag) != 1 || flag != *sflag || flag == 0)
goto nextline;
! prepl = lowerstr(repl);
/* affix flag */
if ((ptr = strchr(prepl, '/')) != NULL)
{
***************
*** 658,672 ****
ptr++;
}
}
! pfind = lowerstr_ctx(find);
! pmask = lowerstr_ctx(mask);
if (t_iseq(find, '0'))
*pfind = '\0';
if (t_iseq(repl, '0'))
*prepl = '\0';
NIAddAffix(Conf, flag, flagflags | aflg, pmask, pfind, prepl,
! isSuffix ? FF_SUFFIX : FF_PREFIX);
pfree(prepl);
pfree(pfind);
pfree(pmask);
--- 647,661 ----
ptr++;
}
}
! pfind = lowerstr(find);
! pmask = lowerstr(mask);
if (t_iseq(find, '0'))
*pfind = '\0';
if (t_iseq(repl, '0'))
*prepl = '\0';
NIAddAffix(Conf, flag, flagflags | aflg, pmask, pfind, prepl,
! isSuffix ? FF_SUFFIX : FF_PREFIX, target_ctx);
pfree(prepl);
pfree(pfind);
pfree(pmask);
***************
*** 687,693 ****
* Note caller must already have applied get_tsearch_config_filename
*/
void
! NIImportAffixes(IspellDict *Conf, const char *filename)
{
char *pstr = NULL;
char mask[BUFSIZ];
--- 676,682 ----
* Note caller must already have applied get_tsearch_config_filename
*/
void
! NIImportAffixes(IspellDict *Conf, const char *filename, MemoryContext target_ctx)
{
char *pstr = NULL;
char mask[BUFSIZ];
***************
*** 802,808 ****
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("wrong affix file format for flag")));
tsearch_readline_end(&trst);
! NIImportOOAffixes(Conf, filename);
return;
}
if ((!suffixes) && (!prefixes))
--- 791,797 ----
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("wrong affix file format for flag")));
tsearch_readline_end(&trst);
! NIImportOOAffixes(Conf, filename, target_ctx);
return;
}
if ((!suffixes) && (!prefixes))
***************
*** 811,817 ****
if (!parse_affentry(pstr, mask, find, repl))
goto nextline;
! NIAddAffix(Conf, flag, flagflags, mask, find, repl, suffixes ? FF_SUFFIX : FF_PREFIX);
nextline:
pfree(recoded);
--- 800,806 ----
if (!parse_affentry(pstr, mask, find, repl))
goto nextline;
! NIAddAffix(Conf, flag, flagflags, mask, find, repl, suffixes ? FF_SUFFIX : FF_PREFIX, target_ctx);
nextline:
pfree(recoded);
***************
*** 859,865 ****
}
static SPNode *
! mkSPNode(IspellDict *Conf, int low, int high, int level)
{
int i;
int nchar = 0;
--- 848,854 ----
}
static SPNode *
! mkSPNode(IspellDict *Conf, int low, int high, int level, MemoryContext target_ctx)
{
int i;
int nchar = 0;
***************
*** 878,884 ****
if (!nchar)
return NULL;
! rs = (SPNode *) palloc0(SPNHDRSZ + nchar * sizeof(SPNodeData));
rs->length = nchar;
data = rs->data;
--- 867,874 ----
if (!nchar)
return NULL;
! rs = (SPNode *) MemoryContextAllocZero(target_ctx,
! SPNHDRSZ + nchar * sizeof(SPNodeData));
rs->length = nchar;
data = rs->data;
***************
*** 890,896 ****
{
if (lastchar)
{
! data->node = mkSPNode(Conf, lownew, i, level + 1);
lownew = i;
data++;
}
--- 880,886 ----
{
if (lastchar)
{
! data->node = mkSPNode(Conf, lownew, i, level + 1, target_ctx);
lownew = i;
data++;
}
***************
*** 929,935 ****
}
}
! data->node = mkSPNode(Conf, lownew, high, level + 1);
return rs;
}
--- 919,925 ----
}
}
! data->node = mkSPNode(Conf, lownew, high, level + 1, target_ctx);
return rs;
}
***************
*** 939,945 ****
* and affixes.
*/
void
! NISortDictionary(IspellDict *Conf)
{
int i;
int naffix = 0;
--- 929,935 ----
* and affixes.
*/
void
! NISortDictionary(IspellDict *Conf, MemoryContext target_ctx)
{
int i;
int naffix = 0;
***************
*** 959,971 ****
if (i == 0 || strncmp(Conf->Spell[i]->p.flag, Conf->Spell[i - 1]->p.flag, MAXFLAGLEN))
naffix++;
}
!
/*
* Fill in Conf->AffixData with the affixes that were used in the
* dictionary. Replace textual flag-field of Conf->Spell entries with
* indexes into Conf->AffixData array.
*/
! Conf->AffixData = (char **) palloc0(naffix * sizeof(char *));
curaffix = -1;
for (i = 0; i < Conf->nspell; i++)
--- 949,961 ----
if (i == 0 || strncmp(Conf->Spell[i]->p.flag, Conf->Spell[i - 1]->p.flag, MAXFLAGLEN))
naffix++;
}
!
/*
* Fill in Conf->AffixData with the affixes that were used in the
* dictionary. Replace textual flag-field of Conf->Spell entries with
* indexes into Conf->AffixData array.
*/
! Conf->AffixData = (char **) palloc0(naffix * sizeof(char *));
curaffix = -1;
for (i = 0; i < Conf->nspell; i++)
***************
*** 984,996 ****
Conf->lenAffixData = Conf->nAffixData = naffix;
qsort((void *) Conf->Spell, Conf->nspell, sizeof(SPELL *), cmpspell);
! Conf->Dictionary = mkSPNode(Conf, 0, Conf->nspell, 0);
Conf->Spell = NULL;
}
static AffixNode *
! mkANode(IspellDict *Conf, int low, int high, int level, int type)
{
int i;
int nchar = 0;
--- 974,986 ----
Conf->lenAffixData = Conf->nAffixData = naffix;
qsort((void *) Conf->Spell, Conf->nspell, sizeof(SPELL *), cmpspell);
! Conf->Dictionary = mkSPNode(Conf, 0, Conf->nspell, 0, target_ctx);
Conf->Spell = NULL;
}
static AffixNode *
! mkANode(IspellDict *Conf, int low, int high, int level, int type, MemoryContext target_ctx)
{
int i;
int nchar = 0;
***************
*** 1011,1020 ****
if (!nchar)
return NULL;
! aff = (AFFIX **) tmpalloc(sizeof(AFFIX *) * (high - low + 1));
naff = 0;
! rs = (AffixNode *) palloc0(ANHRDSZ + nchar * sizeof(AffixNodeData));
rs->length = nchar;
data = rs->data;
--- 1001,1012 ----
if (!nchar)
return NULL;
! aff = (AFFIX **) palloc(sizeof(AFFIX *) * (high - low + 1));
naff = 0;
! rs = (AffixNode *) MemoryContextAllocZero(target_ctx,
! ANHRDSZ + nchar * sizeof(AffixNodeData));
!
rs->length = nchar;
data = rs->data;
***************
*** 1026,1036 ****
{
if (lastchar)
{
! data->node = mkANode(Conf, lownew, i, level + 1, type);
if (naff)
{
data->naff = naff;
! data->aff = (AFFIX **) palloc(sizeof(AFFIX *) * naff);
memcpy(data->aff, aff, sizeof(AFFIX *) * naff);
naff = 0;
}
--- 1018,1028 ----
{
if (lastchar)
{
! data->node = mkANode(Conf, lownew, i, level + 1, type, target_ctx);
if (naff)
{
data->naff = naff;
! data->aff = (AFFIX **) MemoryContextAlloc(target_ctx, sizeof(AFFIX *) * naff);
memcpy(data->aff, aff, sizeof(AFFIX *) * naff);
naff = 0;
}
***************
*** 1046,1056 ****
}
}
! data->node = mkANode(Conf, lownew, high, level + 1, type);
if (naff)
{
data->naff = naff;
! data->aff = (AFFIX **) palloc(sizeof(AFFIX *) * naff);
memcpy(data->aff, aff, sizeof(AFFIX *) * naff);
naff = 0;
}
--- 1038,1048 ----
}
}
! data->node = mkANode(Conf, lownew, high, level + 1, type, target_ctx);
if (naff)
{
data->naff = naff;
! data->aff = (AFFIX **) MemoryContextAlloc(target_ctx, sizeof(AFFIX *) * naff);
memcpy(data->aff, aff, sizeof(AFFIX *) * naff);
naff = 0;
}
***************
*** 1061,1073 ****
}
static void
! mkVoidAffix(IspellDict *Conf, bool issuffix, int startsuffix)
{
int i,
cnt = 0;
int start = (issuffix) ? startsuffix : 0;
int end = (issuffix) ? Conf->naffixes : startsuffix;
! AffixNode *Affix = (AffixNode *) palloc0(ANHRDSZ + sizeof(AffixNodeData));
Affix->length = 1;
Affix->isvoid = 1;
--- 1053,1066 ----
}
static void
! mkVoidAffix(IspellDict *Conf, bool issuffix, int startsuffix, MemoryContext target_ctx)
{
int i,
cnt = 0;
int start = (issuffix) ? startsuffix : 0;
int end = (issuffix) ? Conf->naffixes : startsuffix;
!
! AffixNode *Affix = (AffixNode *) MemoryContextAllocZero(target_ctx, ANHRDSZ + sizeof(AffixNodeData));
Affix->length = 1;
Affix->isvoid = 1;
***************
*** 1091,1097 ****
if (cnt == 0)
return;
! Affix->data->aff = (AFFIX **) palloc(sizeof(AFFIX *) * cnt);
Affix->data->naff = (uint32) cnt;
cnt = 0;
--- 1084,1090 ----
if (cnt == 0)
return;
! Affix->data->aff = (AFFIX **) MemoryContextAllocZero(target_ctx, sizeof(AFFIX *) * cnt);
Affix->data->naff = (uint32) cnt;
cnt = 0;
***************
*** 1115,1135 ****
return false;
}
void
! NISortAffixes(IspellDict *Conf)
{
AFFIX *Affix;
size_t i;
CMPDAffix *ptr;
int firstsuffix = Conf->naffixes;
checkTmpCtx();
if (Conf->naffixes == 0)
return;
if (Conf->naffixes > 1)
qsort((void *) Conf->Affix, Conf->naffixes, sizeof(AFFIX), cmpaffix);
Conf->CompoundAffix = ptr = (CMPDAffix *) palloc(sizeof(CMPDAffix) * Conf->naffixes);
ptr->affix = NULL;
--- 1108,1163 ----
return false;
}
+ /*
+ * I would to move all static data to separate context. This context
+ * can be simply created in shared memory later. So it is step to
+ * sharing dictionaries.
+ */
+ void
+ PersistAffixes(IspellDict *Conf, MemoryContext target_ctx)
+ {
+ int i;
+ char **ptr;
+
+ /*
+ * Doesn't deallocate memory, because this stage is final,
+ * and temporary context will be dropped soon.
+ */
+ ptr = (char **) MemoryContextAlloc(target_ctx,
+ Conf->nAffixData * sizeof(char*));
+ for (i = 0; i < Conf->nAffixData; i++)
+ ptr[i] = MemoryContextStrdup(target_ctx, Conf->AffixData[i]);
+
+ Conf->AffixData = ptr;
+ }
+
void
! NISortAffixes(IspellDict *Conf, MemoryContext target_ctx)
{
AFFIX *Affix;
size_t i;
CMPDAffix *ptr;
int firstsuffix = Conf->naffixes;
+
+ CMPDAffix *buffer;
checkTmpCtx();
if (Conf->naffixes == 0)
return;
+ /*
+ * store to simple alloc context
+ */
+ Affix = (AFFIX *) MemoryContextAllocZero(target_ctx,
+ Conf->naffixes * sizeof(AFFIX));
+ memcpy(Affix, Conf->Affix, Conf->naffixes * sizeof(AFFIX));
+ pfree(Conf->Affix);
+ Conf->Affix = Affix;
+
if (Conf->naffixes > 1)
qsort((void *) Conf->Affix, Conf->naffixes, sizeof(AFFIX), cmpaffix);
+
Conf->CompoundAffix = ptr = (CMPDAffix *) palloc(sizeof(CMPDAffix) * Conf->naffixes);
ptr->affix = NULL;
***************
*** 1157,1168 ****
}
}
ptr->affix = NULL;
! Conf->CompoundAffix = (CMPDAffix *) repalloc(Conf->CompoundAffix, sizeof(CMPDAffix) * (ptr - Conf->CompoundAffix + 1));
!
! Conf->Prefix = mkANode(Conf, 0, firstsuffix, 0, FF_PREFIX);
! Conf->Suffix = mkANode(Conf, firstsuffix, Conf->naffixes, 0, FF_SUFFIX);
! mkVoidAffix(Conf, true, firstsuffix);
! mkVoidAffix(Conf, false, firstsuffix);
}
static AffixNodeData *
--- 1185,1200 ----
}
}
ptr->affix = NULL;
!
! buffer = (CMPDAffix *) MemoryContextAllocZero(target_ctx, sizeof(CMPDAffix) * (ptr - Conf->CompoundAffix + 1));
! memcpy(buffer, Conf->CompoundAffix, sizeof(CMPDAffix) * (ptr - Conf->CompoundAffix + 1));
! pfree(Conf->CompoundAffix);
! Conf->CompoundAffix = buffer;
!
! Conf->Prefix = mkANode(Conf, 0, firstsuffix, 0, FF_PREFIX, target_ctx);
! Conf->Suffix = mkANode(Conf, firstsuffix, Conf->naffixes, 0, FF_SUFFIX, target_ctx);
! mkVoidAffix(Conf, true, firstsuffix, target_ctx);
! mkVoidAffix(Conf, false, firstsuffix, target_ctx);
}
static AffixNodeData *
*** ./src/backend/tsearch/ts_utils.c.orig 2010-03-17 15:49:48.248656967 +0100
--- ./src/backend/tsearch/ts_utils.c 2010-03-17 15:54:11.505781913 +0100
***************
*** 153,155 ****
--- 153,171 ----
sizeof(char *), comparestr)) ? true : false;
}
+ void
+ PersistStoplist(StopList *s, MemoryContext target_ctx)
+ {
+ char **stop;
+ int i;
+
+ stop = (char **) MemoryContextAlloc(target_ctx,
+ s->len * sizeof(char *));
+ /*
+ * Doesn't deallocate memory, because this stage is final,
+ * and temporary context will be dropped soon.
+ */
+ for (i = 0; i < s->len; i++)
+ stop[i] = MemoryContextStrdup(target_ctx, s->stop[i]);
+ s->stop = stop;
+ }
*** ./src/backend/utils/cache/ts_cache.c.orig 2010-02-14 19:42:17.000000000 +0100
--- ./src/backend/utils/cache/ts_cache.c 2010-03-18 10:45:02.419054339 +0100
***************
*** 337,344 ****
dictoptions = deserialize_deflist(opt);
entry->dictData =
! DatumGetPointer(OidFunctionCall1(template->tmplinit,
! PointerGetDatum(dictoptions)));
MemoryContextSwitchTo(oldcontext);
}
--- 337,345 ----
dictoptions = deserialize_deflist(opt);
entry->dictData =
! DatumGetPointer(OidFunctionCall2(template->tmplinit,
! PointerGetDatum(dictoptions),
! ObjectIdGetDatum(dictId)));
MemoryContextSwitchTo(oldcontext);
}
*** ./src/backend/utils/misc/guc.c.orig 2010-02-26 03:01:14.000000000 +0100
--- ./src/backend/utils/misc/guc.c 2010-03-18 07:41:44.114089845 +0100
***************
*** 390,395 ****
--- 390,397 ----
int tcp_keepalives_interval;
int tcp_keepalives_count;
+ int shared_data; /* space reserved for data inside shared memory */
+
/*
* These variables are all dummies that don't do anything, except in some
* cases provide the value for SHOW to display. The real state is elsewhere
***************
*** 1405,1410 ****
--- 1407,1422 ----
},
{
+ {"shared_data", PGC_POSTMASTER, RESOURCES_MEM,
+ gettext_noop("Sets the size of memory reserved for shared data."),
+ NULL,
+ GUC_UNIT_KB
+ },
+ &shared_data,
+ 0, 0, MAX_KILOBYTES, NULL, NULL
+ },
+
+ {
{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
gettext_noop("Sets the maximum number of temporary buffers used by each session."),
NULL,
*** ./src/backend/utils/misc/postgresql.conf.sample.orig 2010-02-25 14:26:16.000000000 +0100
--- ./src/backend/utils/misc/postgresql.conf.sample 2010-03-18 07:43:58.260962487 +0100
***************
*** 108,113 ****
--- 108,115 ----
#shared_buffers = 32MB # min 128kB
# (change requires restart)
+ #shared_data = 0MB # reserved for data saved to shared memory
+ # (change requires restart)
#temp_buffers = 8MB # min 800kB
#max_prepared_transactions = 0 # zero disables the feature
# (change requires restart)
*** ./src/backend/utils/mmgr/Makefile.orig 2008-02-19 11:30:09.000000000 +0100
--- ./src/backend/utils/mmgr/Makefile 2010-03-15 11:03:16.738323659 +0100
***************
*** 12,17 ****
top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global
! OBJS = aset.o mcxt.o portalmem.o
include $(top_srcdir)/src/backend/common.mk
--- 12,17 ----
top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global
! OBJS = aset.o mcxt.o portalmem.o simple_alloc.o
include $(top_srcdir)/src/backend/common.mk
*** ./src/backend/utils/mmgr/simple_alloc.c.orig 2010-03-15 11:02:48.741323741 +0100
--- ./src/backend/utils/mmgr/simple_alloc.c 2010-03-18 11:10:26.662699831 +0100
***************
*** 0 ****
--- 1,348 ----
+ #include "postgres.h"
+
+ #include "utils/memutils.h"
+
+ typedef struct AllocBlockData *AllocBlock; /* forward reference */
+
+
+ typedef struct SimpleAllocContextData
+ {
+ MemoryContextData header; /* Standard memory-context fields */
+ AllocBlock blocks; /* head of list of standard blocks */
+ AllocBlock bigblocks; /* head of list of blocks larger than initBlockSize */
+ bool isReset;
+ /* Allocation parameters for this context */
+ Size initBlockSize;
+ void *(*external_alloc) (Size size); /* allocate memory */
+ void (*external_free) (void *); /* deallocate memory */
+ } SimpleAllocContextData;
+
+ typedef SimpleAllocContextData *SimpleAlloc;
+
+ typedef struct AllocBlockData
+ {
+ AllocBlock next;
+ Size freesize;
+ char *freeptr;
+ char data[1];
+ } AllocBlockData;
+
+ #define SimpleAllocCtxIsValid(ctx) PointerIsValid(ctx)
+
+ #define ALLOC_BLOCKHDRSZ MAXALIGN(sizeof(AllocBlockData))
+
+ static void SimpleAllocInit(MemoryContext context);
+ static void SimpleAllocReset(MemoryContext context);
+ static void SimpleAllocDelete(MemoryContext context);
+ static void *SimpleAllocAlloc(MemoryContext context, Size size);
+ static void SimpleAllocStats(MemoryContext context, int level);
+ static void *SimpleAllocRealloc(MemoryContext context, void *pointer, Size size);
+ static void SimpleAllocFree(MemoryContext context, void *pointer);
+ static bool SimpleAllocIsEmpty(MemoryContext context);
+ static Size SimpleAllocGetChunkSpace(MemoryContext context, void *pointer);
+
+ #ifdef MEMORY_CONTEXT_CHECKING
+ static void SimpleAllocCheck(MemoryContext context);
+ #endif
+
+ /*
+ * This is the virtual function table for SimpleAlloc context
+ */
+ static MemoryContextMethods SimpleAllocMethods = {
+ SimpleAllocAlloc,
+ SimpleAllocFree, /* not supported */
+ SimpleAllocRealloc, /* not supported */
+ SimpleAllocInit,
+ SimpleAllocReset,
+ SimpleAllocDelete,
+ SimpleAllocGetChunkSpace, /* not supported */
+ SimpleAllocIsEmpty,
+ SimpleAllocStats
+ #ifdef MEMORY_CONTEXT_CHECKING
+ , SimpleAllocCheck
+ #endif
+ };
+
+ #ifdef RANDOMIZE_ALLOCATED_MEMORY
+
+ /*
+ * Fill a just-allocated piece of memory with "random" data. It's not really
+ * very random, just a repeating sequence with a length that's prime. What
+ * we mainly want out of it is to have a good probability that two palloc's
+ * of the same number of bytes start out containing different data.
+ */
+ static void
+ randomize_mem(char *ptr, size_t size)
+ {
+ static int save_ctr = 1;
+ int ctr;
+
+ ctr = save_ctr;
+ while (size-- > 0)
+ {
+ *ptr++ = ctr;
+ if (++ctr > 251)
+ ctr = 1;
+ }
+ save_ctr = ctr;
+ }
+ #endif /* RANDOMIZE_ALLOCATED_MEMORY */
+
+ /*
+ * SimpleAllocContextCreate
+ *
+ *
+ */
+ MemoryContext
+ SimpleAllocContextCreate(MemoryContext parent,
+ const char *name,
+ Size initBlockSize,
+ void *(*external_alloc) (Size size),
+ void (*external_free) (void *))
+ {
+ SimpleAlloc context;
+
+ context = (SimpleAlloc) MemoryContextCreate(T_SimpleAllocContext,
+ sizeof(SimpleAllocContextData),
+ &SimpleAllocMethods,
+ parent,
+ name);
+ context->initBlockSize = MAXALIGN(initBlockSize);
+ context->external_alloc = external_alloc;
+ context->external_free = external_free;
+
+ context->blocks = NULL;
+ context->bigblocks = NULL;
+ context->isReset = true;
+
+ return (MemoryContext) context;
+ }
+
+ /*
+ * Context type methods
+ */
+ static void
+ SimpleAllocInit(MemoryContext context)
+ {
+ /*
+ * do nothing
+ */
+ }
+
+ static void
+ SimpleAllocReset(MemoryContext context)
+ {
+ AllocBlock block;
+ AllocBlock next;
+ SimpleAlloc simple_ctx = (SimpleAlloc) context;
+
+ Assert(SimpleAllocCtxIsValid(simple_ctx));
+
+ /*
+ * because simple alloc context doesn't support operation free
+ * we don't need to implement keeper block.
+ */
+ block = simple_ctx->blocks;
+ while (block != NULL)
+ {
+ next = block->next;
+ #ifdef CLOBBER_FREED_MEMORY
+ memset(block->data, 0x7F, simple_ctx->initBlockSize);
+ #endif
+
+ if (simple_ctx->external_free != NULL)
+ simple_ctx->external_free(block);
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot release allocated memory")));
+ block = next;
+ }
+
+ block = simple_ctx->bigblocks;
+ while (block != NULL)
+ {
+ next = block->next;
+
+ #ifdef CLOBBER_FREED_MEMORY
+ memset(block->data, 0x7F, simple_ctx->initBlockSize);
+ #endif
+
+ if (simple_ctx->external_free != NULL)
+ simple_ctx->external_free(block);
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot release allocated memory")));
+ block = next;
+ }
+
+ simple_ctx->isReset = true;
+ simple_ctx->blocks = NULL;
+ simple_ctx->bigblocks = NULL;
+ }
+
+ static void
+ SimpleAllocDelete(MemoryContext context)
+ {
+ SimpleAllocReset(context);
+ }
+
+ static void *
+ SimpleAllocAlloc(MemoryContext context, Size size)
+ {
+ SimpleAlloc simple_ctx = (SimpleAlloc) context;
+ AllocBlock block;
+ void *newPointer;
+ Size allocSize;
+ bool isBigBlock;
+
+ Assert(SimpleAllocCtxIsValid(simple_ctx));
+
+ /*
+ * Allocate separate block for allocation larger than 1/2 of initBlockSize
+ */
+ size = MAXALIGN(size);
+ if (size > (simple_ctx->initBlockSize/3*2))
+ {
+ /*
+ * we will allocate a big block - block only for current
+ * allocation - these blocks are is separete list.
+ */
+ allocSize = size;
+ isBigBlock = true;
+ }
+ else
+ {
+ allocSize = simple_ctx->initBlockSize;
+ isBigBlock = false;
+ }
+
+ /*
+ * Allocate a new block if there are no allocated or is big
+ * or isn't enought space.
+ */
+ if (simple_ctx->blocks == NULL || isBigBlock ||
+ (!isBigBlock && simple_ctx->blocks && simple_ctx->blocks->freesize < size))
+ {
+ /* alloc a new block */
+
+ block = simple_ctx->external_alloc(MAXALIGN(allocSize + sizeof(AllocBlockData) - 1));
+ if (block == NULL)
+ {
+ MemoryContextStats(TopMemoryContext);
+ ereport(ERROR,
+ (errcode(ERRCODE_OUT_OF_MEMORY),
+ errmsg("out of memory"),
+ errdetail("Failed on request of size %lu.",
+ (unsigned long) allocSize + sizeof(AllocBlockData) - 1)));
+ }
+
+ block->freesize = allocSize;
+ block->freeptr = block->data;
+ if (!isBigBlock)
+ {
+ block->next = simple_ctx->blocks;
+ simple_ctx->blocks = block;
+ }
+ else
+ {
+ block->next = simple_ctx->bigblocks;
+ simple_ctx->bigblocks = block;
+ }
+ }
+ else
+ block = simple_ctx->blocks;
+
+ Assert(size <= block->freesize);
+ newPointer = block->freeptr;
+
+ if (!isBigBlock)
+ {
+ block->freeptr += size;
+ block->freesize -= size;
+ }
+
+ #ifdef RANDOMIZE_ALLOCATED_MEMORY
+ randomize_mem((char *) newPointer, size);
+ #endif
+ simple_ctx->isReset = false;
+
+ return newPointer;
+ }
+
+ /*
+ * SimpleAllocStats
+ */
+ static void
+ SimpleAllocStats(MemoryContext context, int level)
+ {
+ SimpleAlloc simple_ctx = (SimpleAlloc) context;
+ AllocBlock block;
+ long nblocks = 0;
+ long totalspace = 0;
+ long freespace = 0;
+ int i;
+
+ for (block = simple_ctx->blocks; block != NULL; block = block->next)
+ {
+ nblocks++;
+ totalspace += MAXALIGN(simple_ctx->initBlockSize + sizeof(AllocBlockData) - 1);
+ freespace += block->freesize;
+ }
+
+ for (block = simple_ctx->bigblocks; block != NULL; block = block->next)
+ {
+ nblocks++;
+ totalspace += block->freesize + sizeof(AllocBlockData) - 1;
+ }
+
+ for (i = 0; i < level; i++)
+ fprintf(stderr, " ");
+
+ fprintf(stderr,
+ "%s: %lu total in %ld blocks; %lu free; %lu used\n",
+ simple_ctx->header.name, totalspace, nblocks, freespace,
+ totalspace - freespace);
+ }
+
+ static void *
+ SimpleAllocRealloc(MemoryContext context, void *pointer, Size size)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("simple allocator can't realloc memory")));
+ return NULL; /* be compiler quite */
+ }
+
+ static void
+ SimpleAllocFree(MemoryContext context, void *pointer)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("simple allocator can't release memory")));
+ }
+
+ static bool
+ SimpleAllocIsEmpty(MemoryContext context)
+ {
+ return ((SimpleAlloc) context)->isReset;
+ }
+
+ static Size
+ SimpleAllocGetChunkSpace(MemoryContext context, void *pointer)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("simple allocator has not chunks")));
+ return 0; /* be compile quite */
+ }
+
+ #ifdef MEMORY_CONTEXT_CHECKING
+ static void
+ SimpleAllocCheck(MemoryContext context)
+ {
+ /* do nothing */
+ }
+
+ #endif
*** ./src/include/nodes/memnodes.h.orig 2010-01-02 17:58:04.000000000 +0100
--- ./src/include/nodes/memnodes.h 2010-03-15 14:07:38.597323708 +0100
***************
*** 72,77 ****
*/
#define MemoryContextIsValid(context) \
((context) != NULL && \
! (IsA((context), AllocSetContext)))
#endif /* MEMNODES_H */
--- 72,77 ----
*/
#define MemoryContextIsValid(context) \
((context) != NULL && \
! (IsA((context), AllocSetContext) || IsA((context), SimpleAllocContext)))
#endif /* MEMNODES_H */
*** ./src/include/nodes/nodes.h.orig 2010-01-05 22:53:59.000000000 +0100
--- ./src/include/nodes/nodes.h 2010-03-15 14:06:20.021447204 +0100
***************
*** 234,239 ****
--- 234,240 ----
*/
T_MemoryContext = 600,
T_AllocSetContext,
+ T_SimpleAllocContext,
/*
* TAGS FOR VALUE NODES (value.h)
*** ./src/include/tsearch/dicts/spell.h.orig 2010-01-02 17:58:09.000000000 +0100
--- ./src/include/tsearch/dicts/spell.h 2010-03-17 15:22:17.252656966 +0100
***************
*** 161,169 ****
} IspellDict;
extern TSLexeme *NINormalizeWord(IspellDict *Conf, char *word);
! extern void NIImportAffixes(IspellDict *Conf, const char *filename);
! extern void NIImportDictionary(IspellDict *Conf, const char *filename);
! extern void NISortDictionary(IspellDict *Conf);
! extern void NISortAffixes(IspellDict *Conf);
#endif
--- 161,171 ----
} IspellDict;
extern TSLexeme *NINormalizeWord(IspellDict *Conf, char *word);
! extern void NIImportAffixes(IspellDict *Conf, const char *filename, MemoryContext target_ctx);
! extern void NIImportDictionary(IspellDict *Conf, const char *filename, MemoryContext target_ctx);
! extern void NISortDictionary(IspellDict *Conf, MemoryContext target_ctx);
! extern void NISortAffixes(IspellDict *Conf, MemoryContext target_ctx);
!
! void PersistAffixes(IspellDict *Conf, MemoryContext target_ctx);
#endif
*** ./src/include/tsearch/ts_public.h.orig 2010-01-02 17:58:09.000000000 +0100
--- ./src/include/tsearch/ts_public.h 2010-03-17 15:22:38.692656994 +0100
***************
*** 77,82 ****
--- 77,83 ----
extern void readstoplist(const char *fname, StopList *s,
char *(*wordop) (const char *));
extern bool searchstoplist(StopList *s, char *key);
+ extern void PersistStoplist(StopList *s, MemoryContext target_ctx);
/*
* Interface with dictionaries
*** ./src/include/utils/memutils.h.orig 2010-03-15 14:33:58.000000000 +0100
--- ./src/include/utils/memutils.h 2010-03-15 16:20:24.280321906 +0100
***************
*** 136,139 ****
--- 136,147 ----
#define ALLOCSET_SMALL_INITSIZE (1 * 1024)
#define ALLOCSET_SMALL_MAXSIZE (8 * 1024)
+ extern MemoryContext SimpleAllocContextCreate(MemoryContext parent,
+ const char *name,
+ Size initBlockSize,
+ void *(*external_alloc) (Size size),
+ void (*external_free) (void *));
+
+ #define SIMPLEALLOC_LARGE_INITSIZE (1024 * 128)
+
#endif /* MEMUTILS_H */