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.11 1998/06/15 18:39:44 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))
598 PortalHashTableLookup(name, portal);
602 if (!PortalIsValid(BlankPortal))
603 CreateNewBlankPortal();
604 portal = BlankPortal;
611 * BlankPortalAssignName --
612 * Returns former blank portal as portal with given name.
615 * All references to the former blank portal become incorrect.
618 * BadState if called when disabled.
619 * BadState if called without an intervening call to GetPortalByName(NULL).
620 * BadArg if portal name is invalid.
621 * "WARN" if portal name is in use.
624 BlankPortalAssignName(char *name) /* XXX PortalName */
629 AssertState(PortalManagerEnabled);
630 AssertState(PortalIsValid(BlankPortal));
631 AssertArg(PointerIsValid(name)); /* XXX PortalName */
633 portal = GetPortalByName(name);
634 if (PortalIsValid(portal))
636 elog(NOTICE, "BlankPortalAssignName: portal %s already exists", name);
641 * remove blank portal
643 portal = BlankPortal;
647 * initialize portal name
649 length = 1 + strlen(name);
650 portal->name = (char *)
651 MemoryContextAlloc((MemoryContext) &portal->variable, length);
653 strncpy(portal->name, name, length);
656 * put portal in table
658 PortalHashTableInsert(portal);
665 * Attaches a "query" to portal.
668 * BadState if called when disabled.
669 * BadArg if portal is invalid.
670 * BadArg if queryDesc is "invalid."
671 * BadArg if state is "invalid."
674 PortalSetQuery(Portal portal,
675 QueryDesc *queryDesc,
678 void (*cleanup) (Portal portal))
680 AssertState(PortalManagerEnabled);
681 AssertArg(PortalIsValid(portal));
682 AssertArg(IsA((Node *) state, EState));
684 portal->queryDesc = queryDesc;
685 portal->state = state;
686 portal->attinfo = attinfo;
687 portal->cleanup = cleanup;
691 * PortalGetQueryDesc --
692 * Returns query attached to portal.
695 * BadState if called when disabled.
696 * BadArg if portal is invalid.
699 PortalGetQueryDesc(Portal portal)
701 AssertState(PortalManagerEnabled);
702 AssertArg(PortalIsValid(portal));
704 return (portal->queryDesc);
709 * Returns state attached to portal.
712 * BadState if called when disabled.
713 * BadArg if portal is invalid.
716 PortalGetState(Portal portal)
718 AssertState(PortalManagerEnabled);
719 AssertArg(PortalIsValid(portal));
721 return (portal->state);
726 * Returns a new portal given a name.
729 * This is expected to be of very limited usability. See instead,
730 * BlankPortalAssignName.
733 * BadState if called when disabled.
734 * BadArg if portal name is invalid.
735 * "WARN" if portal name is in use.
738 CreatePortal(char *name) /* XXX PortalName */
743 AssertState(PortalManagerEnabled);
744 AssertArg(PointerIsValid(name)); /* XXX PortalName */
746 portal = GetPortalByName(name);
747 if (PortalIsValid(portal))
749 elog(NOTICE, "CreatePortal: portal %s already exists", name);
753 /* make new portal structure */
755 MemoryContextAlloc((MemoryContext) PortalMemory, sizeof *portal);
757 /* initialize portal variable context */
758 NodeSetTag((Node *) &portal->variable, T_PortalVariableMemory);
759 AllocSetInit(&portal->variable.setData, DynamicAllocMode, (Size) 0);
760 portal->variable.method = &PortalVariableContextMethodsData;
762 /* initialize portal heap context */
763 NodeSetTag((Node *) &portal->heap, T_PortalHeapMemory);
764 portal->heap.block = NULL;
765 FixedStackInit(&portal->heap.stackData,
766 offsetof(HeapMemoryBlockData, itemData));
767 portal->heap.method = &PortalHeapContextMethodsData;
769 /* initialize portal name */
770 length = 1 + strlen(name);
771 portal->name = (char *)
772 MemoryContextAlloc((MemoryContext) &portal->variable, length);
773 strncpy(portal->name, name, length);
775 /* initialize portal query */
776 portal->queryDesc = NULL;
777 portal->attinfo = NULL;
778 portal->state = NULL;
779 portal->cleanup = NULL;
781 /* put portal in table */
782 PortalHashTableInsert(portal);
784 /* Trap(PointerIsValid(name), Unimplemented); */
793 * BadState if called when disabled.
794 * BadArg if portal is invalid.
797 PortalDestroy(Portal *portalP)
799 Portal portal = *portalP;
801 AssertState(PortalManagerEnabled);
802 AssertArg(PortalIsValid(portal));
804 /* remove portal from table if not blank portal */
805 if (portal != BlankPortal)
806 PortalHashTableDelete(portal);
809 if (PointerIsValid(portal->cleanup))
810 (*portal->cleanup) (portal);
812 PortalResetHeapMemory(portal);
813 MemoryContextFree((MemoryContext) &portal->variable,
814 (Pointer) portal->name);
815 AllocSetReset(&portal->variable.setData); /* XXX log */
817 if (portal != BlankPortal)
818 MemoryContextFree((MemoryContext) PortalMemory, (Pointer) portal);
822 * PortalResetHeapMemory --
823 * Resets portal's heap memory context.
825 * Someday, Reset, Start, and End can be optimized by keeping a global
826 * portal module stack of free HeapMemoryBlock's. This will make Start
830 * BadState if called when disabled.
831 * BadState if called when not in PortalHeapMemory context.
832 * BadArg if mode is invalid.
836 PortalResetHeapMemory(Portal portal)
838 PortalHeapMemory context;
839 MemoryContext currentContext;
841 context = PortalGetHeapMemory(portal);
843 if (PointerIsValid(context->block))
845 /* save present context */
846 currentContext = MemoryContextSwitchTo((MemoryContext) context);
850 EndPortalAllocMode();
851 } while (PointerIsValid(context->block));
853 /* restore context */
854 MemoryContextSwitchTo(currentContext);
859 * StartPortalAllocMode --
860 * Starts a new block of portal heap allocation using mode and limit;
861 * the current block is disabled until EndPortalAllocMode is called.
864 * Note blocks may be stacked and restored arbitarily.
865 * The semantics of mode and limit are described in aset.h.
868 * BadState if called when disabled.
869 * BadState if called when not in PortalHeapMemory context.
870 * BadArg if mode is invalid.
873 StartPortalAllocMode(AllocMode mode, Size limit)
875 PortalHeapMemory context;
877 AssertState(PortalManagerEnabled);
878 AssertState(IsA(CurrentMemoryContext, PortalHeapMemory));
879 /* AssertArg(AllocModeIsValid); */
881 context = (PortalHeapMemory) CurrentMemoryContext;
883 /* stack current mode */
884 if (PointerIsValid(context->block))
885 FixedStackPush(&context->stackData, context->block);
887 /* allocate and initialize new block */
890 (MemoryContext) PortalHeapMemoryGetVariableMemory(context),
891 sizeof(HeapMemoryBlockData));
893 /* XXX careful, context->block has never been stacked => bad state */
895 AllocSetInit(&HEAPMEMBLOCK(context)->setData, mode, limit);
899 * EndPortalAllocMode --
900 * Ends current block of portal heap allocation; previous block is
904 * Note blocks may be stacked and restored arbitarily.
907 * BadState if called when disabled.
908 * BadState if called when not in PortalHeapMemory context.
913 PortalHeapMemory context;
915 AssertState(PortalManagerEnabled);
916 AssertState(IsA(CurrentMemoryContext, PortalHeapMemory));
918 context = (PortalHeapMemory) CurrentMemoryContext;
919 AssertState(PointerIsValid(context->block)); /* XXX Trap(...) */
921 /* free current mode */
922 AllocSetReset(&HEAPMEMBLOCK(context)->setData);
923 MemoryContextFree((MemoryContext) PortalHeapMemoryGetVariableMemory(context),
926 /* restore previous mode */
927 context->block = FixedStackPop(&context->stackData);
931 * PortalGetVariableMemory --
932 * Returns variable memory context for a given portal.
935 * BadState if called when disabled.
936 * BadArg if portal is invalid.
939 PortalGetVariableMemory(Portal portal)
941 return (&portal->variable);
945 * PortalGetHeapMemory --
946 * Returns heap memory context for a given portal.
949 * BadState if called when disabled.
950 * BadArg if portal is invalid.
953 PortalGetHeapMemory(Portal portal)
955 return (&portal->heap);
959 * PortalVariableMemoryGetPortal --
960 * Returns portal containing given variable memory context.
963 * BadState if called when disabled.
964 * BadArg if context is invalid.
967 PortalVariableMemoryGetPortal(PortalVariableMemory context)
969 return ((Portal) ((char *) context - offsetof(PortalD, variable)));
973 * PortalHeapMemoryGetPortal --
974 * Returns portal containing given heap memory context.
977 * BadState if called when disabled.
978 * BadArg if context is invalid.
981 PortalHeapMemoryGetPortal(PortalHeapMemory context)
983 return ((Portal) ((char *) context - offsetof(PortalD, heap)));
987 * PortalVariableMemoryGetHeapMemory --
988 * Returns heap memory context associated with given variable memory.
991 * BadState if called when disabled.
992 * BadArg if context is invalid.
996 PortalVariableMemoryGetHeapMemory(PortalVariableMemory context)
998 return ((PortalHeapMemory) ((char *) context
999 - offsetof(PortalD, variable)
1000 +offsetof(PortalD, heap)));
1006 * PortalHeapMemoryGetVariableMemory --
1007 * Returns variable memory context associated with given heap memory.
1010 * BadState if called when disabled.
1011 * BadArg if context is invalid.
1013 static PortalVariableMemory
1014 PortalHeapMemoryGetVariableMemory(PortalHeapMemory context)
1016 return ((PortalVariableMemory) ((char *) context
1017 - offsetof(PortalD, heap)
1018 +offsetof(PortalD, variable)));