1 /*-------------------------------------------------------------------------
4 * backend portal memory context management stuff
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.14 1998/09/01 04:33:39 momjian Exp $
12 *-------------------------------------------------------------------------
16 * Do not confuse "Portal" with "PortalEntry" (or "PortalBuffer").
17 * When a PQexec() routine is run, the resulting tuples
18 * find their way into a "PortalEntry". The contents of the resulting
19 * "PortalEntry" can then be inspected by other PQxxx functions.
21 * A "Portal" is a structure used to keep track of queries of the
23 * retrieve portal FOO ( blah... ) where blah...
25 * When the backend sees a "retrieve portal" query, it allocates
26 * a "PortalD" structure, plans the query and then stores the query
27 * in the portal without executing it. Later, when the backend
31 * the system looks up the portal named "FOO" in the portal table,
32 * gets the planned query and then calls the executor with a feature of
33 * '(EXEC_FOR 1). The executor then runs the query and returns a single
34 * tuple. The problem is that we have to hold onto the state of the
35 * portal query until we see a "close p". This means we have to be
36 * careful about memory management.
38 * Having said all that, here is what a PortalD currently looks like:
42 * classObj(PortalVariableMemory) variable;
43 * classObj(PortalHeapMemory) heap;
46 * void (*cleanup) ARGS((Portal portal));
49 * I hope this makes things clearer to whoever reads this -cim 2/22/91
51 * Here is an old comment taken from nodes/memnodes.h
54 * A logical context in which memory allocations occur.
56 * The types of memory contexts can be thought of as members of the
57 * following inheritance hierarchy with properties summarized below.
63 * GlobalMemory PortalMemoryContext
65 * PortalVariableMemory PortalHeapMemory
67 * Flushed at Flushed at Checkpoints
72 * PortalVariableMemory n y n
73 * PortalHeapMemory y y y *
76 #include <stdio.h> /* for sprintf() */
77 #include <string.h> /* for strlen, strncpy */
81 #include "lib/hasht.h"
82 #include "utils/module.h"
83 #include "utils/excid.h" /* for Unimplemented */
84 #include "utils/mcxt.h"
85 #include "utils/hsearch.h"
87 #include "nodes/memnodes.h"
88 #include "nodes/nodes.h"
89 #include "nodes/pg_list.h"
90 #include "nodes/execnodes.h" /* for EState */
92 #include "utils/portal.h"
94 static void CollectNamedPortals(Portal *portalP, int destroy);
95 static Portal PortalHeapMemoryGetPortal(PortalHeapMemory context);
96 static PortalVariableMemory PortalHeapMemoryGetVariableMemory(PortalHeapMemory context);
97 static void PortalResetHeapMemory(Portal portal);
98 static Portal PortalVariableMemoryGetPortal(PortalVariableMemory context);
101 * ALLOCFREE_ERROR_ABORT
102 * define this if you want a core dump when you try to
103 * free memory already freed -cim 2/9/91
106 #undef ALLOCFREE_ERROR_ABORT
113 static int PortalManagerEnableCount = 0;
115 #define MAX_PORTALNAME_LEN 64 /* XXX LONGALIGNable value */
117 typedef struct portalhashent
119 char portalname[MAX_PORTALNAME_LEN];
123 #define PortalManagerEnabled (PortalManagerEnableCount >= 1)
125 static HTAB *PortalHashTable = NULL;
127 #define PortalHashTableLookup(NAME, PORTAL) \
129 PortalHashEnt *hentry; bool found; char key[MAX_PORTALNAME_LEN]; \
131 MemSet(key, 0, MAX_PORTALNAME_LEN); \
132 sprintf(key, "%s", NAME); \
133 hentry = (PortalHashEnt*)hash_search(PortalHashTable, \
134 key, HASH_FIND, &found); \
135 if (hentry == NULL) \
136 elog(FATAL, "error in PortalHashTable"); \
138 PORTAL = hentry->portal; \
143 #define PortalHashTableInsert(PORTAL) \
145 PortalHashEnt *hentry; bool found; char key[MAX_PORTALNAME_LEN]; \
147 MemSet(key, 0, MAX_PORTALNAME_LEN); \
148 sprintf(key, "%s", PORTAL->name); \
149 hentry = (PortalHashEnt*)hash_search(PortalHashTable, \
150 key, HASH_ENTER, &found); \
151 if (hentry == NULL) \
152 elog(FATAL, "error in PortalHashTable"); \
154 elog(NOTICE, "trying to insert a portal name that exists."); \
155 hentry->portal = PORTAL; \
158 #define PortalHashTableDelete(PORTAL) \
160 PortalHashEnt *hentry; bool found; char key[MAX_PORTALNAME_LEN]; \
162 MemSet(key, 0, MAX_PORTALNAME_LEN); \
163 sprintf(key, "%s", PORTAL->name); \
164 hentry = (PortalHashEnt*)hash_search(PortalHashTable, \
165 key, HASH_REMOVE, &found); \
166 if (hentry == NULL) \
167 elog(FATAL, "error in PortalHashTable"); \
169 elog(NOTICE, "trying to delete portal name that does not exist."); \
172 static GlobalMemory PortalMemory = NULL;
173 static char PortalMemoryName[] = "Portal";
175 static Portal BlankPortal = NULL;
178 * Internal class definitions
181 typedef struct HeapMemoryBlockData
183 AllocSetData setData;
184 FixedItemData itemData;
185 } HeapMemoryBlockData;
187 typedef HeapMemoryBlockData *HeapMemoryBlock;
189 #define HEAPMEMBLOCK(context) \
190 ((HeapMemoryBlock)(context)->block)
192 /* ----------------------------------------------------------------
193 * Variable and heap memory methods
194 * ----------------------------------------------------------------
197 * PortalVariableMemoryAlloc
201 PortalVariableMemoryAlloc(PortalVariableMemory this,
204 return AllocSetAlloc(&this->setData, size);
208 * PortalVariableMemoryFree
212 PortalVariableMemoryFree(PortalVariableMemory this,
215 AllocSetFree(&this->setData, pointer);
219 * PortalVariableMemoryRealloc
223 PortalVariableMemoryRealloc(PortalVariableMemory this,
227 return AllocSetRealloc(&this->setData, pointer, size);
231 * PortalVariableMemoryGetName
235 PortalVariableMemoryGetName(PortalVariableMemory this)
237 return form("%s-var", PortalVariableMemoryGetPortal(this)->name);
241 * PortalVariableMemoryDump
245 PortalVariableMemoryDump(PortalVariableMemory this)
247 printf("--\n%s:\n", PortalVariableMemoryGetName(this));
249 AllocSetDump(&this->setData); /* XXX is this the right interface */
253 * PortalHeapMemoryAlloc
257 PortalHeapMemoryAlloc(PortalHeapMemory this,
260 HeapMemoryBlock block = HEAPMEMBLOCK(this);
262 AssertState(PointerIsValid(block));
264 return AllocSetAlloc(&block->setData, size);
268 * PortalHeapMemoryFree
272 PortalHeapMemoryFree(PortalHeapMemory this,
275 HeapMemoryBlock block = HEAPMEMBLOCK(this);
277 AssertState(PointerIsValid(block));
279 if (AllocSetContains(&block->setData, pointer))
280 AllocSetFree(&block->setData, pointer);
284 "PortalHeapMemoryFree: 0x%x not in alloc set!",
286 #ifdef ALLOCFREE_ERROR_ABORT
287 Assert(AllocSetContains(&block->setData, pointer));
288 #endif /* ALLOCFREE_ERROR_ABORT */
293 * PortalHeapMemoryRealloc
297 PortalHeapMemoryRealloc(PortalHeapMemory this,
301 HeapMemoryBlock block = HEAPMEMBLOCK(this);
303 AssertState(PointerIsValid(block));
305 return AllocSetRealloc(&block->setData, pointer, size);
309 * PortalHeapMemoryGetName
313 PortalHeapMemoryGetName(PortalHeapMemory this)
315 return form("%s-heap", PortalHeapMemoryGetPortal(this)->name);
319 * PortalHeapMemoryDump
323 PortalHeapMemoryDump(PortalHeapMemory this)
325 HeapMemoryBlock block;
327 printf("--\n%s:\n", PortalHeapMemoryGetName(this));
329 /* XXX is this the right interface */
330 if (PointerIsValid(this->block))
331 AllocSetDump(&HEAPMEMBLOCK(this)->setData);
333 /* dump the stack too */
334 for (block = (HeapMemoryBlock) FixedStackGetTop(&this->stackData);
335 PointerIsValid(block);
336 block = (HeapMemoryBlock)
337 FixedStackGetNext(&this->stackData, (Pointer) block))
341 AllocSetDump(&block->setData);
345 /* ----------------------------------------------------------------
346 * variable / heap context method tables
347 * ----------------------------------------------------------------
349 static struct MemoryContextMethodsData PortalVariableContextMethodsData = {
350 PortalVariableMemoryAlloc, /* Pointer (*)(this, uint32) palloc */
351 PortalVariableMemoryFree, /* void (*)(this, Pointer) pfree */
352 PortalVariableMemoryRealloc,/* Pointer (*)(this, Pointer) repalloc */
353 PortalVariableMemoryGetName,/* char* (*)(this) getName */
354 PortalVariableMemoryDump /* void (*)(this) dump */
357 static struct MemoryContextMethodsData PortalHeapContextMethodsData = {
358 PortalHeapMemoryAlloc, /* Pointer (*)(this, uint32) palloc */
359 PortalHeapMemoryFree, /* void (*)(this, Pointer) pfree */
360 PortalHeapMemoryRealloc, /* Pointer (*)(this, Pointer) repalloc */
361 PortalHeapMemoryGetName, /* char* (*)(this) getName */
362 PortalHeapMemoryDump /* void (*)(this) dump */
366 /* ----------------------------------------------------------------
367 * private internal support routines
368 * ----------------------------------------------------------------
371 * CreateNewBlankPortal
375 CreateNewBlankPortal()
379 AssertState(!PortalIsValid(BlankPortal));
382 * make new portal structure
385 MemoryContextAlloc((MemoryContext) PortalMemory, sizeof *portal);
388 * initialize portal variable context
390 NodeSetTag((Node *) &portal->variable, T_PortalVariableMemory);
391 AllocSetInit(&portal->variable.setData, DynamicAllocMode, (Size) 0);
392 portal->variable.method = &PortalVariableContextMethodsData;
395 * initialize portal heap context
397 NodeSetTag((Node *) &portal->heap, T_PortalHeapMemory);
398 portal->heap.block = NULL;
399 FixedStackInit(&portal->heap.stackData,
400 offsetof(HeapMemoryBlockData, itemData));
401 portal->heap.method = &PortalHeapContextMethodsData;
404 * set bogus portal name
406 portal->name = "** Blank Portal **";
408 /* initialize portal query */
409 portal->queryDesc = NULL;
410 portal->attinfo = NULL;
411 portal->state = NULL;
412 portal->cleanup = NULL;
415 * install blank portal
417 BlankPortal = portal;
421 PortalNameIsSpecial(char *pname)
423 if (strcmp(pname, VACPNAME) == 0)
429 * This routine is used to collect all portals created in this xaction
430 * and then destroy them. There is a little trickiness required as a
431 * result of the dynamic hashing interface to getting every hash entry
432 * sequentially. Its use of static variables requires that we get every
433 * entry *before* we destroy anything (destroying updates the hashtable
434 * and screws up the sequential walk of the table). -mer 17 Aug 1992
437 CollectNamedPortals(Portal *portalP, int destroy)
439 static Portal *portalList = (Portal *) NULL;
440 static int listIndex = 0;
441 static int maxIndex = 9;
443 if (portalList == (Portal *) NULL)
444 portalList = (Portal *) malloc(10 * sizeof(Portal));
450 for (i = 0; i < listIndex; i++)
451 PortalDestroy(&portalList[i]);
460 * Don't delete special portals, up to portal creator to do this
462 if (PortalNameIsSpecial((*portalP)->name))
465 portalList[listIndex] = *portalP;
467 if (listIndex == maxIndex)
469 portalList = (Portal *)
470 realloc(portalList, (maxIndex + 11) * sizeof(Portal));
480 HashTableWalk(PortalHashTable, CollectNamedPortals, 0);
481 CollectNamedPortals(NULL, 1);
490 PortalDump(Portal *thisP)
492 /* XXX state/argument checking here */
494 PortalVariableMemoryDump(PortalGetVariableMemory(*thisP));
495 PortalHeapMemoryDump(PortalGetHeapMemory(*thisP));
508 /* XXX state checking here */
510 HashTableWalk(PortalHashTable, PortalDump, 0);
515 /* ----------------------------------------------------------------
516 * public portal interface functions
517 * ----------------------------------------------------------------
520 * EnablePortalManager --
521 * Enables/disables the portal management module.
524 EnablePortalManager(bool on)
526 static bool processing = false;
529 AssertState(!processing);
530 AssertArg(BoolIsValid(on));
532 if (BypassEnable(&PortalManagerEnableCount, on))
539 EnableMemoryContext(true);
541 PortalMemory = CreateGlobalMemory(PortalMemoryName);
543 ctl.keysize = MAX_PORTALNAME_LEN;
544 ctl.datasize = sizeof(Portal);
547 * use PORTALS_PER_USER, defined in utils/portal.h as a guess of
548 * how many hash table entries to create, initially
550 PortalHashTable = hash_create(PORTALS_PER_USER * 3, &ctl, HASH_ELEM);
552 CreateNewBlankPortal();
557 if (PortalIsValid(BlankPortal))
559 PortalDestroy(&BlankPortal);
560 MemoryContextFree((MemoryContext) PortalMemory,
561 (Pointer) BlankPortal);
566 * Each portal must free its non-memory resources specially.
568 HashTableWalk(PortalHashTable, PortalDestroy, 0);
569 hash_destroy(PortalHashTable);
570 PortalHashTable = NULL;
572 GlobalMemoryDestroy(PortalMemory);
575 EnableMemoryContext(true);
583 * Returns a portal given a portal name; returns blank portal given
584 * NULL; returns invalid portal if portal not found.
587 * BadState if called when disabled.
590 GetPortalByName(char *name)
594 AssertState(PortalManagerEnabled);
596 if (PointerIsValid(name))
597 PortalHashTableLookup(name, portal);
600 if (!PortalIsValid(BlankPortal))
601 CreateNewBlankPortal();
602 portal = BlankPortal;
609 * BlankPortalAssignName --
610 * Returns former blank portal as portal with given name.
613 * All references to the former blank portal become incorrect.
616 * BadState if called when disabled.
617 * BadState if called without an intervening call to GetPortalByName(NULL).
618 * BadArg if portal name is invalid.
619 * "WARN" if portal name is in use.
622 BlankPortalAssignName(char *name) /* XXX PortalName */
627 AssertState(PortalManagerEnabled);
628 AssertState(PortalIsValid(BlankPortal));
629 AssertArg(PointerIsValid(name)); /* XXX PortalName */
631 portal = GetPortalByName(name);
632 if (PortalIsValid(portal))
634 elog(NOTICE, "BlankPortalAssignName: portal %s already exists", name);
639 * remove blank portal
641 portal = BlankPortal;
645 * initialize portal name
647 length = 1 + strlen(name);
648 portal->name = (char *)
649 MemoryContextAlloc((MemoryContext) &portal->variable, length);
651 strncpy(portal->name, name, length);
654 * put portal in table
656 PortalHashTableInsert(portal);
663 * Attaches a "query" to portal.
666 * BadState if called when disabled.
667 * BadArg if portal is invalid.
668 * BadArg if queryDesc is "invalid."
669 * BadArg if state is "invalid."
672 PortalSetQuery(Portal portal,
673 QueryDesc *queryDesc,
676 void (*cleanup) (Portal portal))
678 AssertState(PortalManagerEnabled);
679 AssertArg(PortalIsValid(portal));
680 AssertArg(IsA((Node *) state, EState));
682 portal->queryDesc = queryDesc;
683 portal->state = state;
684 portal->attinfo = attinfo;
685 portal->cleanup = cleanup;
689 * PortalGetQueryDesc --
690 * Returns query attached to portal.
693 * BadState if called when disabled.
694 * BadArg if portal is invalid.
697 PortalGetQueryDesc(Portal portal)
699 AssertState(PortalManagerEnabled);
700 AssertArg(PortalIsValid(portal));
702 return portal->queryDesc;
707 * Returns state attached to portal.
710 * BadState if called when disabled.
711 * BadArg if portal is invalid.
714 PortalGetState(Portal portal)
716 AssertState(PortalManagerEnabled);
717 AssertArg(PortalIsValid(portal));
719 return portal->state;
724 * Returns a new portal given a name.
727 * This is expected to be of very limited usability. See instead,
728 * BlankPortalAssignName.
731 * BadState if called when disabled.
732 * BadArg if portal name is invalid.
733 * "WARN" if portal name is in use.
736 CreatePortal(char *name) /* XXX PortalName */
741 AssertState(PortalManagerEnabled);
742 AssertArg(PointerIsValid(name)); /* XXX PortalName */
744 portal = GetPortalByName(name);
745 if (PortalIsValid(portal))
747 elog(NOTICE, "CreatePortal: portal %s already exists", name);
751 /* make new portal structure */
753 MemoryContextAlloc((MemoryContext) PortalMemory, sizeof *portal);
755 /* initialize portal variable context */
756 NodeSetTag((Node *) &portal->variable, T_PortalVariableMemory);
757 AllocSetInit(&portal->variable.setData, DynamicAllocMode, (Size) 0);
758 portal->variable.method = &PortalVariableContextMethodsData;
760 /* initialize portal heap context */
761 NodeSetTag((Node *) &portal->heap, T_PortalHeapMemory);
762 portal->heap.block = NULL;
763 FixedStackInit(&portal->heap.stackData,
764 offsetof(HeapMemoryBlockData, itemData));
765 portal->heap.method = &PortalHeapContextMethodsData;
767 /* initialize portal name */
768 length = 1 + strlen(name);
769 portal->name = (char *)
770 MemoryContextAlloc((MemoryContext) &portal->variable, length);
771 strncpy(portal->name, name, length);
773 /* initialize portal query */
774 portal->queryDesc = NULL;
775 portal->attinfo = NULL;
776 portal->state = NULL;
777 portal->cleanup = NULL;
779 /* put portal in table */
780 PortalHashTableInsert(portal);
782 /* Trap(PointerIsValid(name), Unimplemented); */
791 * BadState if called when disabled.
792 * BadArg if portal is invalid.
795 PortalDestroy(Portal *portalP)
797 Portal portal = *portalP;
799 AssertState(PortalManagerEnabled);
800 AssertArg(PortalIsValid(portal));
802 /* remove portal from table if not blank portal */
803 if (portal != BlankPortal)
804 PortalHashTableDelete(portal);
807 if (PointerIsValid(portal->cleanup))
808 (*portal->cleanup) (portal);
810 PortalResetHeapMemory(portal);
811 MemoryContextFree((MemoryContext) &portal->variable,
812 (Pointer) portal->name);
813 AllocSetReset(&portal->variable.setData); /* XXX log */
815 if (portal != BlankPortal)
816 MemoryContextFree((MemoryContext) PortalMemory, (Pointer) portal);
820 * PortalResetHeapMemory --
821 * Resets portal's heap memory context.
823 * Someday, Reset, Start, and End can be optimized by keeping a global
824 * portal module stack of free HeapMemoryBlock's. This will make Start
828 * BadState if called when disabled.
829 * BadState if called when not in PortalHeapMemory context.
830 * BadArg if mode is invalid.
834 PortalResetHeapMemory(Portal portal)
836 PortalHeapMemory context;
837 MemoryContext currentContext;
839 context = PortalGetHeapMemory(portal);
841 if (PointerIsValid(context->block))
843 /* save present context */
844 currentContext = MemoryContextSwitchTo((MemoryContext) context);
848 EndPortalAllocMode();
849 } while (PointerIsValid(context->block));
851 /* restore context */
852 MemoryContextSwitchTo(currentContext);
857 * StartPortalAllocMode --
858 * Starts a new block of portal heap allocation using mode and limit;
859 * the current block is disabled until EndPortalAllocMode is called.
862 * Note blocks may be stacked and restored arbitarily.
863 * The semantics of mode and limit are described in aset.h.
866 * BadState if called when disabled.
867 * BadState if called when not in PortalHeapMemory context.
868 * BadArg if mode is invalid.
871 StartPortalAllocMode(AllocMode mode, Size limit)
873 PortalHeapMemory context;
875 AssertState(PortalManagerEnabled);
876 AssertState(IsA(CurrentMemoryContext, PortalHeapMemory));
877 /* AssertArg(AllocModeIsValid); */
879 context = (PortalHeapMemory) CurrentMemoryContext;
881 /* stack current mode */
882 if (PointerIsValid(context->block))
883 FixedStackPush(&context->stackData, context->block);
885 /* allocate and initialize new block */
888 (MemoryContext) PortalHeapMemoryGetVariableMemory(context),
889 sizeof(HeapMemoryBlockData));
891 /* XXX careful, context->block has never been stacked => bad state */
893 AllocSetInit(&HEAPMEMBLOCK(context)->setData, mode, limit);
897 * EndPortalAllocMode --
898 * Ends current block of portal heap allocation; previous block is
902 * Note blocks may be stacked and restored arbitarily.
905 * BadState if called when disabled.
906 * BadState if called when not in PortalHeapMemory context.
911 PortalHeapMemory context;
913 AssertState(PortalManagerEnabled);
914 AssertState(IsA(CurrentMemoryContext, PortalHeapMemory));
916 context = (PortalHeapMemory) CurrentMemoryContext;
917 AssertState(PointerIsValid(context->block)); /* XXX Trap(...) */
919 /* free current mode */
920 AllocSetReset(&HEAPMEMBLOCK(context)->setData);
921 MemoryContextFree((MemoryContext) PortalHeapMemoryGetVariableMemory(context),
924 /* restore previous mode */
925 context->block = FixedStackPop(&context->stackData);
929 * PortalGetVariableMemory --
930 * Returns variable memory context for a given portal.
933 * BadState if called when disabled.
934 * BadArg if portal is invalid.
937 PortalGetVariableMemory(Portal portal)
939 return &portal->variable;
943 * PortalGetHeapMemory --
944 * Returns heap memory context for a given portal.
947 * BadState if called when disabled.
948 * BadArg if portal is invalid.
951 PortalGetHeapMemory(Portal portal)
953 return &portal->heap;
957 * PortalVariableMemoryGetPortal --
958 * Returns portal containing given variable memory context.
961 * BadState if called when disabled.
962 * BadArg if context is invalid.
965 PortalVariableMemoryGetPortal(PortalVariableMemory context)
967 return (Portal) ((char *) context - offsetof(PortalD, variable));
971 * PortalHeapMemoryGetPortal --
972 * Returns portal containing given heap memory context.
975 * BadState if called when disabled.
976 * BadArg if context is invalid.
979 PortalHeapMemoryGetPortal(PortalHeapMemory context)
981 return (Portal) ((char *) context - offsetof(PortalD, heap));
985 * PortalVariableMemoryGetHeapMemory --
986 * Returns heap memory context associated with given variable memory.
989 * BadState if called when disabled.
990 * BadArg if context is invalid.
994 PortalVariableMemoryGetHeapMemory(PortalVariableMemory context)
996 return ((PortalHeapMemory) ((char *) context
997 - offsetof(PortalD, variable)
998 +offsetof(PortalD, heap)));
1004 * PortalHeapMemoryGetVariableMemory --
1005 * Returns variable memory context associated with given heap memory.
1008 * BadState if called when disabled.
1009 * BadArg if context is invalid.
1011 static PortalVariableMemory
1012 PortalHeapMemoryGetVariableMemory(PortalHeapMemory context)
1014 return ((PortalVariableMemory) ((char *) context
1015 - offsetof(PortalD, heap)
1016 +offsetof(PortalD, variable)));