preload.diff
application/octet-stream
Filename: preload.diff
Type: application/octet-stream
Part: 0
Message:
WIP: preloading of 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 | + | − |
|---|---|---|
| contrib/dict_preload/dict_preload.c | 186 | 0 |
| contrib/dict_preload/dict_preload.sql.in | 19 | 0 |
| contrib/dict_preload/uninstall_dict_preload.sql | 10 | 0 |
| doc/src/sgml/contrib.sgml | 1 | 0 |
| doc/src/sgml/dict-preload.sgml | 56 | 0 |
| doc/src/sgml/filelist.sgml | 1 | 0 |
| src/backend/tsearch/regis.c | 8 | 7 |
| 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/regis.h | 1 | 1 |
| src/include/utils/memutils.h | 9 | 0 |
*** ./contrib/dict_preload/dict_preload.c.orig 2010-03-18 17:00:33.281409707 +0100
--- ./contrib/dict_preload/dict_preload.c 2010-03-19 11:09:29.870831600 +0100
***************
*** 0 ****
--- 1,186 ----
+ /*-------------------------------------------------------------------------
+ *
+ * dict_preload.c
+ * preloaded dictionary
+ *
+ * Copyright (c) 2007-2010, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * $PostgreSQL: pgsql/contrib/dict_preload/dict_preload.c,v 1.6 2010/01/02 16:57:32 momjian Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+ #include "postgres.h"
+
+ #include "commands/defrem.h"
+ #include "fmgr.h"
+ #include "miscadmin.h"
+ #include "nodes/makefuncs.h"
+ #include "nodes/value.h"
+ #include "tsearch/ts_public.h"
+ #include "tsearch/ts_utils.h"
+ #include "tsearch/dicts/spell.h"
+ #include "utils/guc.h"
+ #include "utils/memutils.h"
+
+ PG_MODULE_MAGIC;
+
+ char *preload_dictfile = NULL;
+ char *preload_afffile = NULL;
+ char *preload_stopwords = NULL;
+
+ typedef struct
+ {
+ StopList stoplist;
+ IspellDict obj;
+ } DictISpell;
+
+ MemoryContext preload_ctx = NULL;
+
+ DictISpell *preload_dict = NULL;
+
+ PG_FUNCTION_INFO_V1(dpreloaddict_init);
+ Datum dpreloaddict_init(PG_FUNCTION_ARGS);
+
+ PG_FUNCTION_INFO_V1(dpreloaddict_lexize);
+ Datum dpreloaddict_lexize(PG_FUNCTION_ARGS);
+
+ void _PG_init(void);
+ void _PG_fini(void);
+
+ static DictISpell *
+ load_dictionary(void)
+ {
+ List *dictopt = NIL;
+ FunctionCallInfoData fcinfo;
+
+ /*
+ * read parameters for preloaded dictionary
+ */
+ if (preload_dictfile != NULL)
+ dictopt = lappend(dictopt, makeDefElem("DictFile",
+ (Node *) makeString(preload_dictfile)));
+ if (preload_afffile != NULL)
+ dictopt = lappend(dictopt, makeDefElem("AffFile",
+ (Node *) makeString(preload_afffile)));
+ if (preload_stopwords != NULL)
+ dictopt = lappend(dictopt, makeDefElem("StopWords",
+ (Node *) makeString(preload_stopwords)));
+
+ /*
+ * Initialise ispell dictionary
+ */
+ InitFunctionCallInfoData(fcinfo, NULL, 1, NULL, NULL);
+ fcinfo.arg[0] = PointerGetDatum(dictopt);
+ fcinfo.argnull[0] = false;
+
+ return (DictISpell *) DatumGetPointer(dispell_init(&fcinfo));
+ }
+
+ Datum
+ dpreloaddict_init(PG_FUNCTION_ARGS)
+ {
+ static bool firsttime = true;
+
+ /*
+ * dpreloaddict_init can be called more times:
+ * CREATE TEXT SEARCH DICTIONARY
+ * DROP TEXT SEARCH DICTIONARY
+ * CREATE TEXT SEARCH DICTIONARY
+ * ...
+ */
+ if (firsttime)
+ {
+ /* In this moment, dictionary have to be loaded */
+ Assert(MemoryContextIsValid(preload_ctx));
+ Assert(preload_dict != NULL);
+
+ /* join preloaded context to current context */
+ preload_ctx->parent = CurrentMemoryContext;
+ preload_ctx->nextchild = CurrentMemoryContext->firstchild;
+ CurrentMemoryContext->firstchild = preload_ctx;
+ preload_ctx = NULL;
+ firsttime = false;
+
+ return PointerGetDatum(preload_dict);
+ }
+ else
+ return PointerGetDatum(load_dictionary());
+ }
+
+ Datum
+ dpreloaddict_lexize(PG_FUNCTION_ARGS)
+ {
+ return dispell_lexize(fcinfo);
+ }
+
+ /*
+ * Module load callback
+ */
+ void
+ _PG_init()
+ {
+ MemoryContext oldctx;
+ static bool inited = false;
+ GucContext guc_ctx;
+
+ if (inited)
+ return;
+ else
+ inited = true;
+
+ guc_ctx = process_shared_preload_libraries_in_progress ?
+ PGC_POSTMASTER : PGC_SUSET;
+
+ /* Define custom GUC variables. */
+ DefineCustomStringVariable("dict_preload.dictfile",
+ "name of file of preloaded ispell dictionary",
+ NULL,
+ &preload_dictfile,
+ NULL,
+ guc_ctx, 0,
+ NULL, NULL);
+
+ /* Define custom GUC variables. */
+ DefineCustomStringVariable("dict_preload.afffile",
+ "name of file of preloaded ispell affix",
+ NULL,
+ &preload_afffile,
+ NULL,
+ guc_ctx, 0,
+ NULL, NULL);
+
+ /* Define custom GUC variables. */
+ DefineCustomStringVariable("dict_preload.stopwords",
+ "name of file of preloaded ispell stopwords",
+ NULL,
+ &preload_stopwords,
+ NULL,
+ guc_ctx, 0,
+ NULL, NULL);
+
+ /* preload dictionary */
+ Assert(preload_ctx == NULL);
+ Assert(preload_dict == NULL);
+
+ preload_ctx = AllocSetContextCreate(NULL, "Ispell dictionary preload context",
+ ALLOCSET_DEFAULT_MINSIZE,
+ ALLOCSET_DEFAULT_INITSIZE,
+ ALLOCSET_DEFAULT_MAXSIZE);
+ oldctx = MemoryContextSwitchTo(preload_ctx);
+
+ preload_dict = load_dictionary();
+
+ MemoryContextSwitchTo(oldctx);
+ }
+
+ /*
+ * Module unload callback
+ */
+ void
+ _PG_fini(void)
+ {
+ /* when preload context exists still delete it */
+ if (preload_ctx != NULL)
+ MemoryContextDelete(preload_ctx);
+ }
*** ./contrib/dict_preload/dict_preload.sql.in.orig 2010-03-18 17:00:52.317502927 +0100
--- ./contrib/dict_preload/dict_preload.sql.in 2010-03-19 08:24:33.195954842 +0100
***************
*** 0 ****
--- 1,19 ----
+ /* $PostgreSQL: pgsql/contrib/dict_int/dict_int.sql.in,v 1.3 2007/11/13 04:24:27 momjian Exp $ */
+
+ -- Adjust this setting to control where the objects get created.
+ SET search_path = public;
+
+ CREATE OR REPLACE FUNCTION dpreloaddict_init(internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT;
+
+ CREATE OR REPLACE FUNCTION dpreloaddict_lexize(internal, internal, internal, internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT;
+
+ CREATE TEXT SEARCH TEMPLATE preloaddict(
+ LEXIZE = dpreloaddict_lexize,
+ INIT = dpreloaddict_init
+ );
*** ./contrib/dict_preload/uninstall_dict_preload.sql.orig 2010-03-18 17:00:58.039409567 +0100
--- ./contrib/dict_preload/uninstall_dict_preload.sql 2010-03-18 13:52:49.064472194 +0100
***************
*** 0 ****
--- 1,10 ----
+ /* $PostgreSQL: pgsql/contrib/dict_int/uninstall_dict_int.sql,v 1.3 2007/11/13 04:24:27 momjian Exp $ */
+
+ -- Adjust this setting to control where the objects get dropped.
+ SET search_path = public;
+
+ DROP TEXT SEARCH TEMPLATE preloaddict_template CASCADE;
+
+ DROP FUNCTION dpreloaddict_init(internal);
+
+ DROP FUNCTION dpreloaddict_lexize(internal,internal,internal,internal);
*** ./doc/src/sgml/contrib.sgml.orig 2010-01-29 00:59:52.000000000 +0100
--- ./doc/src/sgml/contrib.sgml 2010-03-19 10:35:50.203430470 +0100
***************
*** 89,94 ****
--- 89,95 ----
&cube;
&dblink;
&dict-int;
+ &dict-preload
&dict-xsyn;
&earthdistance;
&fuzzystrmatch;
*** ./doc/src/sgml/dict-preload.sgml.orig 2010-03-19 10:19:04.557472568 +0100
--- ./doc/src/sgml/dict-preload.sgml 2010-03-19 10:42:29.856554695 +0100
***************
*** 0 ****
--- 1,56 ----
+ <!-- $PostgreSQL: pgsql/doc/src/sgml/dict-int.sgml,v 1.2 2007/12/06 04:12:10 tgl Exp $ -->
+
+ <sect1 id="dict-preload">
+ <title>dict_preload</title>
+
+ <indexterm zone="dict-preload">
+ <primary>dict_preload</primary>
+ </indexterm>
+
+ <para>
+ <filename>dict_preload</> is an example of an add-on dictionary template
+ for full-text search. The motivation for this example dictionary is to
+ allow preloading some ispell dictionary.
+ </para>
+
+ <sect2>
+ <title>Configuration</title>
+
+ <para>
+ you have to modify <literal>custom_variable_classes</> and specify
+ <literal>dict_preload.dictfile</>, <literal>dict_preload.afffile</>
+ and <literal>dict_preload.stopwords</>. Ensure <literal>shared_preload_libraries</>
+ contains <literal>dict_preload</>.
+
+ <programlisting>
+ postgres=# CREATE TEXT SEARCH DICTIONARY cspell (template=preloaddict);
+ CREATE TEXT SEARCH DICTIONARY
+
+ postgres=# CREATE TEXT SEARCH CONFIGURATION cs (copy=english);
+ CREATE TEXT SEARCH CONFIGURATION
+ Time: 18,915 ms
+
+ postgres=# ALTER TEXT SEARCH CONFIGURATION cs
+ postgres-# ALTER MAPPING FOR word, asciiword WITH cspell, simple;
+ ALTER TEXT SEARCH CONFIGURATION
+
+ postgres=# select * from ts_debug('cs','vody');
+ alias | description | token | dictionaries | dictionary | lexemes
+ -----------+-------------------+-------+-----------------+------------+---------
+ asciiword | Word, all ASCII | vody | {cspell,simple} | cspell | {voda}
+ (9 rows)
+ </programlisting>
+
+ <programlisting>
+ postgres=# SHOW ALL;
+ ...
+ dict_preload.afffile | czech
+ dict_preload.dictfile | czech
+ dict_preload.stopwords | czech
+ ...
+ </programlisting>
+
+ </para>
+ </sect2>
+
+ </sect1>
*** ./doc/src/sgml/filelist.sgml.orig 2010-02-22 12:47:30.000000000 +0100
--- ./doc/src/sgml/filelist.sgml 2010-03-19 10:36:59.340555069 +0100
***************
*** 101,106 ****
--- 101,107 ----
<!entity cube SYSTEM "cube.sgml">
<!entity dblink SYSTEM "dblink.sgml">
<!entity dict-int SYSTEM "dict-int.sgml">
+ <!entity dict-preload SYSTEM "dict-preload.sgml">
<!entity dict-xsyn SYSTEM "dict-xsyn.sgml">
<!entity earthdistance SYSTEM "earthdistance.sgml">
<!entity fuzzystrmatch SYSTEM "fuzzystrmatch.sgml">
*** ./src/backend/tsearch/regis.c.orig 2010-01-02 17:57:53.000000000 +0100
--- ./src/backend/tsearch/regis.c 2010-03-18 16:41:03.027708600 +0100
***************
*** 71,88 ****
}
static RegisNode *
! newRegisNode(RegisNode *prev, int len)
{
RegisNode *ptr;
! ptr = (RegisNode *) palloc0(RNHDRSZ + len + 1);
if (prev)
prev->next = ptr;
return ptr;
}
void
! RS_compile(Regis *r, bool issuffix, const char *str)
{
int len = strlen(str);
int state = RS_IN_WAIT;
--- 71,89 ----
}
static RegisNode *
! newRegisNode(RegisNode *prev, int len, MemoryContext simple_ctx)
{
RegisNode *ptr;
! ptr = (RegisNode *) MemoryContextAllocZero(simple_ctx,
! RNHDRSZ + len + 1);
if (prev)
prev->next = ptr;
return ptr;
}
void
! RS_compile(Regis *r, bool issuffix, const char *str, MemoryContext simple_ctx)
{
int len = strlen(str);
int state = RS_IN_WAIT;
***************
*** 99,107 ****
if (t_isalpha(c))
{
if (ptr)
! ptr = newRegisNode(ptr, len);
else
! ptr = r->node = newRegisNode(NULL, len);
COPYCHAR(ptr->data, c);
ptr->type = RSF_ONEOF;
ptr->len = pg_mblen(c);
--- 100,108 ----
if (t_isalpha(c))
{
if (ptr)
! ptr = newRegisNode(ptr, len, simple_ctx);
else
! ptr = r->node = newRegisNode(NULL, len, simple_ctx);
COPYCHAR(ptr->data, c);
ptr->type = RSF_ONEOF;
ptr->len = pg_mblen(c);
***************
*** 109,117 ****
else if (t_iseq(c, '['))
{
if (ptr)
! ptr = newRegisNode(ptr, len);
else
! ptr = r->node = newRegisNode(NULL, len);
ptr->type = RSF_ONEOF;
state = RS_IN_ONEOF;
}
--- 110,118 ----
else if (t_iseq(c, '['))
{
if (ptr)
! ptr = newRegisNode(ptr, len, simple_ctx);
else
! ptr = r->node = newRegisNode(NULL, len, simple_ctx);
ptr->type = RSF_ONEOF;
state = RS_IN_ONEOF;
}
*** ./src/backend/utils/mmgr/Makefile.orig 2010-03-18 15:15:23.063794982 +0100
--- ./src/backend/utils/mmgr/Makefile 2010-03-18 15:15:29.040796648 +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-18 15:14:59.593793406 +0100
--- ./src/backend/utils/mmgr/simple_alloc.c 2010-03-18 11:10:26.000000000 +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-18 15:18:55.349792968 +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-03-18 15:21:26.328793052 +0100
--- ./src/include/nodes/nodes.h 2010-03-18 15:21:37.257794503 +0100
***************
*** 234,239 ****
--- 234,240 ----
*/
T_MemoryContext = 600,
T_AllocSetContext,
+ T_SimpleAllocContext,
/*
* TAGS FOR VALUE NODES (value.h)
*** ./src/include/tsearch/dicts/regis.h.orig 2010-03-18 16:40:41.584584472 +0100
--- ./src/include/tsearch/dicts/regis.h 2010-03-18 16:40:13.428708569 +0100
***************
*** 40,46 ****
bool RS_isRegis(const char *str);
! void RS_compile(Regis *r, bool issuffix, const char *str);
void RS_free(Regis *r);
/*returns true if matches */
--- 40,46 ----
bool RS_isRegis(const char *str);
! void RS_compile(Regis *r, bool issuffix, const char *str, MemoryContext simple_ctx);
void RS_free(Regis *r);
/*returns true if matches */
*** ./src/include/utils/memutils.h.orig 2010-01-02 17:58:10.000000000 +0100
--- ./src/include/utils/memutils.h 2010-03-18 15:20:48.889794704 +0100
***************
*** 136,139 ****
--- 136,148 ----
#define ALLOCSET_SMALL_INITSIZE (1 * 1024)
#define ALLOCSET_SMALL_MAXSIZE (8 * 1024)
+ /* simple_alloc.c */
+ 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 */