*** ./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 */
