]> granicus.if.org Git - postgresql/blob - src/backend/utils/mmgr/portalmem.c
Renaming cleanup, no pgindent yet.
[postgresql] / src / backend / utils / mmgr / portalmem.c
1 /*-------------------------------------------------------------------------
2  *
3  * portalmem.c--
4  *        backend portal memory context management stuff
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.13 1998/09/01 03:27:08 momjian Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 /*
15  * NOTES
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.
20  *
21  *              A "Portal" is a structure used to keep track of queries of the
22  *              form:
23  *                              retrieve portal FOO ( blah... ) where blah...
24  *
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
28  *              sees a
29  *                              fetch 1 into FOO
30  *
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.
37  *
38  *              Having said all that, here is what a PortalD currently looks like:
39  *
40  * struct PortalD {
41  *              char*                                                   name;
42  *              classObj(PortalVariableMemory)  variable;
43  *              classObj(PortalHeapMemory)              heap;
44  *              List                                                    queryDesc;
45  *              EState                                                  state;
46  *              void                                                    (*cleanup) ARGS((Portal portal));
47  * };
48  *
49  *              I hope this makes things clearer to whoever reads this -cim 2/22/91
50  *
51  *              Here is an old comment taken from nodes/memnodes.h
52  *
53  * MemoryContext --
54  *              A logical context in which memory allocations occur.
55  *
56  * The types of memory contexts can be thought of as members of the
57  * following inheritance hierarchy with properties summarized below.
58  *
59  *                                              Node
60  *                                              |
61  *                              MemoryContext___
62  *                              /                               \
63  *              GlobalMemory    PortalMemoryContext
64  *                                              /                               \
65  *              PortalVariableMemory    PortalHeapMemory
66  *
67  *                                              Flushed at              Flushed at              Checkpoints
68  *                                              Transaction             Portal
69  *                                              Commit                  Close
70  *
71  * GlobalMemory                                 n                               n                               n
72  * PortalVariableMemory                 n                               y                               n
73  * PortalHeapMemory                             y                               y                               y *
74  *
75  */
76 #include <stdio.h>                              /* for sprintf() */
77 #include <string.h>                             /* for strlen, strncpy */
78
79 #include "postgres.h"
80
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"
86
87 #include "nodes/memnodes.h"
88 #include "nodes/nodes.h"
89 #include "nodes/pg_list.h"
90 #include "nodes/execnodes.h"    /* for EState */
91
92 #include "utils/portal.h"
93
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);
99
100 /* ----------------
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
104  * ----------------
105  */
106 #undef ALLOCFREE_ERROR_ABORT
107
108 /* ----------------
109  *              Global state
110  * ----------------
111  */
112
113 static int      PortalManagerEnableCount = 0;
114
115 #define MAX_PORTALNAME_LEN              64              /* XXX LONGALIGNable value */
116
117 typedef struct portalhashent
118 {
119         char            portalname[MAX_PORTALNAME_LEN];
120         Portal          portal;
121 } PortalHashEnt;
122
123 #define PortalManagerEnabled    (PortalManagerEnableCount >= 1)
124
125 static HTAB *PortalHashTable = NULL;
126
127 #define PortalHashTableLookup(NAME, PORTAL) \
128 do { \
129         PortalHashEnt *hentry; bool found; char key[MAX_PORTALNAME_LEN]; \
130         \
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"); \
137         if (found) \
138                 PORTAL = hentry->portal; \
139         else \
140                 PORTAL = NULL; \
141 } while(0)
142
143 #define PortalHashTableInsert(PORTAL) \
144 do { \
145         PortalHashEnt *hentry; bool found; char key[MAX_PORTALNAME_LEN]; \
146         \
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"); \
153         if (found) \
154                 elog(NOTICE, "trying to insert a portal name that exists."); \
155         hentry->portal = PORTAL; \
156 } while(0)
157
158 #define PortalHashTableDelete(PORTAL) \
159 { \
160         PortalHashEnt *hentry; bool found; char key[MAX_PORTALNAME_LEN]; \
161         \
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"); \
168         if (!found) \
169                 elog(NOTICE, "trying to delete portal name that does not exist."); \
170 } while(0)
171
172 static GlobalMemory PortalMemory = NULL;
173 static char PortalMemoryName[] = "Portal";
174
175 static Portal BlankPortal = NULL;
176
177 /* ----------------
178  *              Internal class definitions
179  * ----------------
180  */
181 typedef struct HeapMemoryBlockData
182 {
183         AllocSetData setData;
184         FixedItemData itemData;
185 } HeapMemoryBlockData;
186
187 typedef HeapMemoryBlockData *HeapMemoryBlock;
188
189 #define HEAPMEMBLOCK(context) \
190         ((HeapMemoryBlock)(context)->block)
191
192 /* ----------------------------------------------------------------
193  *                                Variable and heap memory methods
194  * ----------------------------------------------------------------
195  */
196 /* ----------------
197  *              PortalVariableMemoryAlloc
198  * ----------------
199  */
200 static Pointer
201 PortalVariableMemoryAlloc(PortalVariableMemory this,
202                                                   Size size)
203 {
204         return AllocSetAlloc(&this->setData, size);
205 }
206
207 /* ----------------
208  *              PortalVariableMemoryFree
209  * ----------------
210  */
211 static void
212 PortalVariableMemoryFree(PortalVariableMemory this,
213                                                  Pointer pointer)
214 {
215         AllocSetFree(&this->setData, pointer);
216 }
217
218 /* ----------------
219  *              PortalVariableMemoryRealloc
220  * ----------------
221  */
222 static Pointer
223 PortalVariableMemoryRealloc(PortalVariableMemory this,
224                                                         Pointer pointer,
225                                                         Size size)
226 {
227         return AllocSetRealloc(&this->setData, pointer, size);
228 }
229
230 /* ----------------
231  *              PortalVariableMemoryGetName
232  * ----------------
233  */
234 static char *
235 PortalVariableMemoryGetName(PortalVariableMemory this)
236 {
237         return form("%s-var", PortalVariableMemoryGetPortal(this)->name);
238 }
239
240 /* ----------------
241  *              PortalVariableMemoryDump
242  * ----------------
243  */
244 static void
245 PortalVariableMemoryDump(PortalVariableMemory this)
246 {
247         printf("--\n%s:\n", PortalVariableMemoryGetName(this));
248
249         AllocSetDump(&this->setData);           /* XXX is this the right interface */
250 }
251
252 /* ----------------
253  *              PortalHeapMemoryAlloc
254  * ----------------
255  */
256 static Pointer
257 PortalHeapMemoryAlloc(PortalHeapMemory this,
258                                           Size size)
259 {
260         HeapMemoryBlock block = HEAPMEMBLOCK(this);
261
262         AssertState(PointerIsValid(block));
263
264         return AllocSetAlloc(&block->setData, size);
265 }
266
267 /* ----------------
268  *              PortalHeapMemoryFree
269  * ----------------
270  */
271 static void
272 PortalHeapMemoryFree(PortalHeapMemory this,
273                                          Pointer pointer)
274 {
275         HeapMemoryBlock block = HEAPMEMBLOCK(this);
276
277         AssertState(PointerIsValid(block));
278
279         if (AllocSetContains(&block->setData, pointer))
280                 AllocSetFree(&block->setData, pointer);
281         else
282         {
283                 elog(NOTICE,
284                          "PortalHeapMemoryFree: 0x%x not in alloc set!",
285                          pointer);
286 #ifdef ALLOCFREE_ERROR_ABORT
287                 Assert(AllocSetContains(&block->setData, pointer));
288 #endif                                                  /* ALLOCFREE_ERROR_ABORT */
289         }
290 }
291
292 /* ----------------
293  *              PortalHeapMemoryRealloc
294  * ----------------
295  */
296 static Pointer
297 PortalHeapMemoryRealloc(PortalHeapMemory this,
298                                                 Pointer pointer,
299                                                 Size size)
300 {
301         HeapMemoryBlock block = HEAPMEMBLOCK(this);
302
303         AssertState(PointerIsValid(block));
304
305         return AllocSetRealloc(&block->setData, pointer, size);
306 }
307
308 /* ----------------
309  *              PortalHeapMemoryGetName
310  * ----------------
311  */
312 static char *
313 PortalHeapMemoryGetName(PortalHeapMemory this)
314 {
315         return form("%s-heap", PortalHeapMemoryGetPortal(this)->name);
316 }
317
318 /* ----------------
319  *              PortalHeapMemoryDump
320  * ----------------
321  */
322 static void
323 PortalHeapMemoryDump(PortalHeapMemory this)
324 {
325         HeapMemoryBlock block;
326
327         printf("--\n%s:\n", PortalHeapMemoryGetName(this));
328
329         /* XXX is this the right interface */
330         if (PointerIsValid(this->block))
331                 AllocSetDump(&HEAPMEMBLOCK(this)->setData);
332
333         /* dump the stack too */
334         for (block = (HeapMemoryBlock) FixedStackGetTop(&this->stackData);
335                  PointerIsValid(block);
336                  block = (HeapMemoryBlock)
337                  FixedStackGetNext(&this->stackData, (Pointer) block))
338         {
339
340                 printf("--\n");
341                 AllocSetDump(&block->setData);
342         }
343 }
344
345 /* ----------------------------------------------------------------
346  *                              variable / heap context method tables
347  * ----------------------------------------------------------------
348  */
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 */
355 };
356
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 */
363 };
364
365
366 /* ----------------------------------------------------------------
367  *                                private internal support routines
368  * ----------------------------------------------------------------
369  */
370 /* ----------------
371  *              CreateNewBlankPortal
372  * ----------------
373  */
374 static void
375 CreateNewBlankPortal()
376 {
377         Portal          portal;
378
379         AssertState(!PortalIsValid(BlankPortal));
380
381         /*
382          * make new portal structure
383          */
384         portal = (Portal)
385                 MemoryContextAlloc((MemoryContext) PortalMemory, sizeof *portal);
386
387         /*
388          * initialize portal variable context
389          */
390         NodeSetTag((Node *) &portal->variable, T_PortalVariableMemory);
391         AllocSetInit(&portal->variable.setData, DynamicAllocMode, (Size) 0);
392         portal->variable.method = &PortalVariableContextMethodsData;
393
394         /*
395          * initialize portal heap context
396          */
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;
402
403         /*
404          * set bogus portal name
405          */
406         portal->name = "** Blank Portal **";
407
408         /* initialize portal query */
409         portal->queryDesc = NULL;
410         portal->attinfo = NULL;
411         portal->state = NULL;
412         portal->cleanup = NULL;
413
414         /*
415          * install blank portal
416          */
417         BlankPortal = portal;
418 }
419
420 bool
421 PortalNameIsSpecial(char *pname)
422 {
423         if (strcmp(pname, VACPNAME) == 0)
424                 return true;
425         return false;
426 }
427
428 /*
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
435  */
436 static void
437 CollectNamedPortals(Portal *portalP, int destroy)
438 {
439         static Portal *portalList = (Portal *) NULL;
440         static int      listIndex = 0;
441         static int      maxIndex = 9;
442
443         if (portalList == (Portal *) NULL)
444                 portalList = (Portal *) malloc(10 * sizeof(Portal));
445
446         if (destroy != 0)
447         {
448                 int                     i;
449
450                 for (i = 0; i < listIndex; i++)
451                         PortalDestroy(&portalList[i]);
452                 listIndex = 0;
453         }
454         else
455         {
456                 Assert(portalP);
457                 Assert(*portalP);
458
459                 /*
460                  * Don't delete special portals, up to portal creator to do this
461                  */
462                 if (PortalNameIsSpecial((*portalP)->name))
463                         return;
464
465                 portalList[listIndex] = *portalP;
466                 listIndex++;
467                 if (listIndex == maxIndex)
468                 {
469                         portalList = (Portal *)
470                                 realloc(portalList, (maxIndex + 11) * sizeof(Portal));
471                         maxIndex += 10;
472                 }
473         }
474         return;
475 }
476
477 void
478 AtEOXact_portals()
479 {
480         HashTableWalk(PortalHashTable, CollectNamedPortals, 0);
481         CollectNamedPortals(NULL, 1);
482 }
483
484 /* ----------------
485  *              PortalDump
486  * ----------------
487  */
488 #ifdef NOT_USED
489 static void
490 PortalDump(Portal *thisP)
491 {
492         /* XXX state/argument checking here */
493
494         PortalVariableMemoryDump(PortalGetVariableMemory(*thisP));
495         PortalHeapMemoryDump(PortalGetHeapMemory(*thisP));
496 }
497
498 #endif
499
500 /* ----------------
501  *              DumpPortals
502  * ----------------
503  */
504 #ifdef NOT_USED
505 static void
506 DumpPortals()
507 {
508         /* XXX state checking here */
509
510         HashTableWalk(PortalHashTable, PortalDump, 0);
511 }
512
513 #endif
514
515 /* ----------------------------------------------------------------
516  *                                 public portal interface functions
517  * ----------------------------------------------------------------
518  */
519 /*
520  * EnablePortalManager --
521  *              Enables/disables the portal management module.
522  */
523 void
524 EnablePortalManager(bool on)
525 {
526         static bool processing = false;
527         HASHCTL         ctl;
528
529         AssertState(!processing);
530         AssertArg(BoolIsValid(on));
531
532         if (BypassEnable(&PortalManagerEnableCount, on))
533                 return;
534
535         processing = true;
536
537         if (on)
538         {                                                       /* initialize */
539                 EnableMemoryContext(true);
540
541                 PortalMemory = CreateGlobalMemory(PortalMemoryName);
542
543                 ctl.keysize = MAX_PORTALNAME_LEN;
544                 ctl.datasize = sizeof(Portal);
545
546                 /*
547                  * use PORTALS_PER_USER, defined in utils/portal.h as a guess of
548                  * how many hash table entries to create, initially
549                  */
550                 PortalHashTable = hash_create(PORTALS_PER_USER * 3, &ctl, HASH_ELEM);
551
552                 CreateNewBlankPortal();
553
554         }
555         else
556         {                                                       /* cleanup */
557                 if (PortalIsValid(BlankPortal))
558                 {
559                         PortalDestroy(&BlankPortal);
560                         MemoryContextFree((MemoryContext) PortalMemory,
561                                                           (Pointer) BlankPortal);
562                         BlankPortal = NULL;
563                 }
564
565                 /*
566                  * Each portal must free its non-memory resources specially.
567                  */
568                 HashTableWalk(PortalHashTable, PortalDestroy, 0);
569                 hash_destroy(PortalHashTable);
570                 PortalHashTable = NULL;
571
572                 GlobalMemoryDestroy(PortalMemory);
573                 PortalMemory = NULL;
574
575                 EnableMemoryContext(true);
576         }
577
578         processing = false;
579 }
580
581 /*
582  * GetPortalByName --
583  *              Returns a portal given a portal name; returns blank portal given
584  * NULL; returns invalid portal if portal not found.
585  *
586  * Exceptions:
587  *              BadState if called when disabled.
588  */
589 Portal
590 GetPortalByName(char *name)
591 {
592         Portal          portal;
593
594         AssertState(PortalManagerEnabled);
595
596         if (PointerIsValid(name))
597                 PortalHashTableLookup(name, portal);
598         else
599         {
600                 if (!PortalIsValid(BlankPortal))
601                         CreateNewBlankPortal();
602                 portal = BlankPortal;
603         }
604
605         return portal;
606 }
607
608 /*
609  * BlankPortalAssignName --
610  *              Returns former blank portal as portal with given name.
611  *
612  * Side effect:
613  *              All references to the former blank portal become incorrect.
614  *
615  * Exceptions:
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.
620  */
621 Portal
622 BlankPortalAssignName(char *name)               /* XXX PortalName */
623 {
624         Portal          portal;
625         uint16          length;
626
627         AssertState(PortalManagerEnabled);
628         AssertState(PortalIsValid(BlankPortal));
629         AssertArg(PointerIsValid(name));        /* XXX PortalName */
630
631         portal = GetPortalByName(name);
632         if (PortalIsValid(portal))
633         {
634                 elog(NOTICE, "BlankPortalAssignName: portal %s already exists", name);
635                 return portal;
636         }
637
638         /*
639          * remove blank portal
640          */
641         portal = BlankPortal;
642         BlankPortal = NULL;
643
644         /*
645          * initialize portal name
646          */
647         length = 1 + strlen(name);
648         portal->name = (char *)
649                 MemoryContextAlloc((MemoryContext) &portal->variable, length);
650
651         strncpy(portal->name, name, length);
652
653         /*
654          * put portal in table
655          */
656         PortalHashTableInsert(portal);
657
658         return portal;
659 }
660
661 /*
662  * PortalSetQuery --
663  *              Attaches a "query" to portal.
664  *
665  * Exceptions:
666  *              BadState if called when disabled.
667  *              BadArg if portal is invalid.
668  *              BadArg if queryDesc is "invalid."
669  *              BadArg if state is "invalid."
670  */
671 void
672 PortalSetQuery(Portal portal,
673                            QueryDesc *queryDesc,
674                            TupleDesc attinfo,
675                            EState *state,
676                            void (*cleanup) (Portal portal))
677 {
678         AssertState(PortalManagerEnabled);
679         AssertArg(PortalIsValid(portal));
680         AssertArg(IsA((Node *) state, EState));
681
682         portal->queryDesc = queryDesc;
683         portal->state = state;
684         portal->attinfo = attinfo;
685         portal->cleanup = cleanup;
686 }
687
688 /*
689  * PortalGetQueryDesc --
690  *              Returns query attached to portal.
691  *
692  * Exceptions:
693  *              BadState if called when disabled.
694  *              BadArg if portal is invalid.
695  */
696 QueryDesc  *
697 PortalGetQueryDesc(Portal portal)
698 {
699         AssertState(PortalManagerEnabled);
700         AssertArg(PortalIsValid(portal));
701
702         return portal->queryDesc;
703 }
704
705 /*
706  * PortalGetState --
707  *              Returns state attached to portal.
708  *
709  * Exceptions:
710  *              BadState if called when disabled.
711  *              BadArg if portal is invalid.
712  */
713 EState *
714 PortalGetState(Portal portal)
715 {
716         AssertState(PortalManagerEnabled);
717         AssertArg(PortalIsValid(portal));
718
719         return portal->state;
720 }
721
722 /*
723  * CreatePortal --
724  *              Returns a new portal given a name.
725  *
726  * Note:
727  *              This is expected to be of very limited usability.  See instead,
728  * BlankPortalAssignName.
729  *
730  * Exceptions:
731  *              BadState if called when disabled.
732  *              BadArg if portal name is invalid.
733  *              "WARN" if portal name is in use.
734  */
735 Portal
736 CreatePortal(char *name)                /* XXX PortalName */
737 {
738         Portal          portal;
739         uint16          length;
740
741         AssertState(PortalManagerEnabled);
742         AssertArg(PointerIsValid(name));        /* XXX PortalName */
743
744         portal = GetPortalByName(name);
745         if (PortalIsValid(portal))
746         {
747                 elog(NOTICE, "CreatePortal: portal %s already exists", name);
748                 return portal;
749         }
750
751         /* make new portal structure */
752         portal = (Portal)
753                 MemoryContextAlloc((MemoryContext) PortalMemory, sizeof *portal);
754
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;
759
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;
766
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);
772
773         /* initialize portal query */
774         portal->queryDesc = NULL;
775         portal->attinfo = NULL;
776         portal->state = NULL;
777         portal->cleanup = NULL;
778
779         /* put portal in table */
780         PortalHashTableInsert(portal);
781
782         /* Trap(PointerIsValid(name), Unimplemented); */
783         return portal;
784 }
785
786 /*
787  * PortalDestroy --
788  *              Destroys portal.
789  *
790  * Exceptions:
791  *              BadState if called when disabled.
792  *              BadArg if portal is invalid.
793  */
794 void
795 PortalDestroy(Portal *portalP)
796 {
797         Portal          portal = *portalP;
798
799         AssertState(PortalManagerEnabled);
800         AssertArg(PortalIsValid(portal));
801
802         /* remove portal from table if not blank portal */
803         if (portal != BlankPortal)
804                 PortalHashTableDelete(portal);
805
806         /* reset portal */
807         if (PointerIsValid(portal->cleanup))
808                 (*portal->cleanup) (portal);
809
810         PortalResetHeapMemory(portal);
811         MemoryContextFree((MemoryContext) &portal->variable,
812                                           (Pointer) portal->name);
813         AllocSetReset(&portal->variable.setData);       /* XXX log */
814
815         if (portal != BlankPortal)
816                 MemoryContextFree((MemoryContext) PortalMemory, (Pointer) portal);
817 }
818
819 /* ----------------
820  *              PortalResetHeapMemory --
821  *                              Resets portal's heap memory context.
822  *
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
825  * and End be fast.
826  *
827  * Exceptions:
828  *              BadState if called when disabled.
829  *              BadState if called when not in PortalHeapMemory context.
830  *              BadArg if mode is invalid.
831  * ----------------
832  */
833 static void
834 PortalResetHeapMemory(Portal portal)
835 {
836         PortalHeapMemory context;
837         MemoryContext currentContext;
838
839         context = PortalGetHeapMemory(portal);
840
841         if (PointerIsValid(context->block))
842         {
843                 /* save present context */
844                 currentContext = MemoryContextSwitchTo((MemoryContext) context);
845
846                 do
847                 {
848                         EndPortalAllocMode();
849                 } while (PointerIsValid(context->block));
850
851                 /* restore context */
852                 MemoryContextSwitchTo(currentContext);
853         }
854 }
855
856 /*
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.
860  *
861  * Note:
862  *              Note blocks may be stacked and restored arbitarily.
863  *              The semantics of mode and limit are described in aset.h.
864  *
865  * Exceptions:
866  *              BadState if called when disabled.
867  *              BadState if called when not in PortalHeapMemory context.
868  *              BadArg if mode is invalid.
869  */
870 void
871 StartPortalAllocMode(AllocMode mode, Size limit)
872 {
873         PortalHeapMemory context;
874
875         AssertState(PortalManagerEnabled);
876         AssertState(IsA(CurrentMemoryContext, PortalHeapMemory));
877         /* AssertArg(AllocModeIsValid); */
878
879         context = (PortalHeapMemory) CurrentMemoryContext;
880
881         /* stack current mode */
882         if (PointerIsValid(context->block))
883                 FixedStackPush(&context->stackData, context->block);
884
885         /* allocate and initialize new block */
886         context->block =
887                 MemoryContextAlloc(
888                           (MemoryContext) PortalHeapMemoryGetVariableMemory(context),
889                                                    sizeof(HeapMemoryBlockData));
890
891         /* XXX careful, context->block has never been stacked => bad state */
892
893         AllocSetInit(&HEAPMEMBLOCK(context)->setData, mode, limit);
894 }
895
896 /*
897  * EndPortalAllocMode --
898  *              Ends current block of portal heap allocation; previous block is
899  *              reenabled.
900  *
901  * Note:
902  *              Note blocks may be stacked and restored arbitarily.
903  *
904  * Exceptions:
905  *              BadState if called when disabled.
906  *              BadState if called when not in PortalHeapMemory context.
907  */
908 void
909 EndPortalAllocMode()
910 {
911         PortalHeapMemory context;
912
913         AssertState(PortalManagerEnabled);
914         AssertState(IsA(CurrentMemoryContext, PortalHeapMemory));
915
916         context = (PortalHeapMemory) CurrentMemoryContext;
917         AssertState(PointerIsValid(context->block));            /* XXX Trap(...) */
918
919         /* free current mode */
920         AllocSetReset(&HEAPMEMBLOCK(context)->setData);
921         MemoryContextFree((MemoryContext) PortalHeapMemoryGetVariableMemory(context),
922                                           context->block);
923
924         /* restore previous mode */
925         context->block = FixedStackPop(&context->stackData);
926 }
927
928 /*
929  * PortalGetVariableMemory --
930  *              Returns variable memory context for a given portal.
931  *
932  * Exceptions:
933  *              BadState if called when disabled.
934  *              BadArg if portal is invalid.
935  */
936 PortalVariableMemory
937 PortalGetVariableMemory(Portal portal)
938 {
939         return &portal->variable;
940 }
941
942 /*
943  * PortalGetHeapMemory --
944  *              Returns heap memory context for a given portal.
945  *
946  * Exceptions:
947  *              BadState if called when disabled.
948  *              BadArg if portal is invalid.
949  */
950 PortalHeapMemory
951 PortalGetHeapMemory(Portal portal)
952 {
953         return &portal->heap;
954 }
955
956 /*
957  * PortalVariableMemoryGetPortal --
958  *              Returns portal containing given variable memory context.
959  *
960  * Exceptions:
961  *              BadState if called when disabled.
962  *              BadArg if context is invalid.
963  */
964 static Portal
965 PortalVariableMemoryGetPortal(PortalVariableMemory context)
966 {
967         return (Portal) ((char *) context - offsetof(PortalD, variable));
968 }
969
970 /*
971  * PortalHeapMemoryGetPortal --
972  *              Returns portal containing given heap memory context.
973  *
974  * Exceptions:
975  *              BadState if called when disabled.
976  *              BadArg if context is invalid.
977  */
978 static Portal
979 PortalHeapMemoryGetPortal(PortalHeapMemory context)
980 {
981         return (Portal) ((char *) context - offsetof(PortalD, heap));
982 }
983
984 /*
985  * PortalVariableMemoryGetHeapMemory --
986  *              Returns heap memory context associated with given variable memory.
987  *
988  * Exceptions:
989  *              BadState if called when disabled.
990  *              BadArg if context is invalid.
991  */
992 #ifdef NOT_USED
993 PortalHeapMemory
994 PortalVariableMemoryGetHeapMemory(PortalVariableMemory context)
995 {
996         return ((PortalHeapMemory) ((char *) context
997                                                                 - offsetof(PortalD, variable)
998                                                                 +offsetof(PortalD, heap)));
999 }
1000
1001 #endif
1002
1003 /*
1004  * PortalHeapMemoryGetVariableMemory --
1005  *              Returns variable memory context associated with given heap memory.
1006  *
1007  * Exceptions:
1008  *              BadState if called when disabled.
1009  *              BadArg if context is invalid.
1010  */
1011 static PortalVariableMemory
1012 PortalHeapMemoryGetVariableMemory(PortalHeapMemory context)
1013 {
1014         return ((PortalVariableMemory) ((char *) context
1015                                                                         - offsetof(PortalD, heap)
1016                                                                         +offsetof(PortalD, variable)));
1017 }