portalmem.c
来自「PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统」· C语言 代码 · 共 759 行 · 第 1/2 页
C
759 行
/*------------------------------------------------------------------------- * * portalmem.c * backend portal memory management * * Portals are objects representing the execution state of a query. * This module provides memory management services for portals, but it * doesn't actually run the executor for them. * * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION * $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.82.2.1 2005/11/22 18:23:25 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "miscadmin.h"#include "commands/portalcmds.h"#include "executor/executor.h"#include "utils/hsearch.h"#include "utils/memutils.h"#include "utils/portal.h"/* * Estimate of the maximum number of open portals a user would have, * used in initially sizing the PortalHashTable in EnablePortalManager(). * Since the hash table can expand, there's no need to make this overly * generous, and keeping it small avoids unnecessary overhead in the * hash_seq_search() calls executed during transaction end. */#define PORTALS_PER_USER 16/* ---------------- * Global state * ---------------- */#define MAX_PORTALNAME_LEN NAMEDATALENtypedef struct portalhashent{ char portalname[MAX_PORTALNAME_LEN]; Portal portal;} PortalHashEnt;static HTAB *PortalHashTable = NULL;#define PortalHashTableLookup(NAME, PORTAL) \do { \ PortalHashEnt *hentry; char key[MAX_PORTALNAME_LEN]; \ \ MemSet(key, 0, MAX_PORTALNAME_LEN); \ StrNCpy(key, NAME, MAX_PORTALNAME_LEN); \ hentry = (PortalHashEnt*)hash_search(PortalHashTable, \ key, HASH_FIND, NULL); \ if (hentry) \ PORTAL = hentry->portal; \ else \ PORTAL = NULL; \} while(0)#define PortalHashTableInsert(PORTAL, NAME) \do { \ PortalHashEnt *hentry; bool found; char key[MAX_PORTALNAME_LEN]; \ \ MemSet(key, 0, MAX_PORTALNAME_LEN); \ StrNCpy(key, NAME, MAX_PORTALNAME_LEN); \ hentry = (PortalHashEnt*)hash_search(PortalHashTable, \ key, HASH_ENTER, &found); \ if (found) \ elog(ERROR, "duplicate portal name"); \ hentry->portal = PORTAL; \ /* To avoid duplicate storage, make PORTAL->name point to htab entry */ \ PORTAL->name = hentry->portalname; \} while(0)#define PortalHashTableDelete(PORTAL) \do { \ PortalHashEnt *hentry; char key[MAX_PORTALNAME_LEN]; \ \ MemSet(key, 0, MAX_PORTALNAME_LEN); \ StrNCpy(key, PORTAL->name, MAX_PORTALNAME_LEN); \ hentry = (PortalHashEnt*)hash_search(PortalHashTable, \ key, HASH_REMOVE, NULL); \ if (hentry == NULL) \ elog(WARNING, "trying to delete portal name that does not exist"); \} while(0)static MemoryContext PortalMemory = NULL;/* ---------------------------------------------------------------- * public portal interface functions * ---------------------------------------------------------------- *//* * EnablePortalManager * Enables the portal management module at backend startup. */voidEnablePortalManager(void){ HASHCTL ctl; Assert(PortalMemory == NULL); PortalMemory = AllocSetContextCreate(TopMemoryContext, "PortalMemory", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); ctl.keysize = MAX_PORTALNAME_LEN; ctl.entrysize = sizeof(PortalHashEnt); /* * use PORTALS_PER_USER as a guess of how many hash table entries to * create, initially */ PortalHashTable = hash_create("Portal hash", PORTALS_PER_USER, &ctl, HASH_ELEM);}/* * GetPortalByName * Returns a portal given a portal name, or NULL if name not found. */PortalGetPortalByName(const char *name){ Portal portal; if (PointerIsValid(name)) PortalHashTableLookup(name, portal); else portal = NULL; return portal;}/* * CreatePortal * Returns a new portal given a name. * * allowDup: if true, automatically drop any pre-existing portal of the * same name (if false, an error is raised). * * dupSilent: if true, don't even emit a WARNING. */PortalCreatePortal(const char *name, bool allowDup, bool dupSilent){ Portal portal; AssertArg(PointerIsValid(name)); portal = GetPortalByName(name); if (PortalIsValid(portal)) { if (!allowDup) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_CURSOR), errmsg("cursor \"%s\" already exists", name))); if (!dupSilent) ereport(WARNING, (errcode(ERRCODE_DUPLICATE_CURSOR), errmsg("closing existing cursor \"%s\"", name))); PortalDrop(portal, false); } /* make new portal structure */ portal = (Portal) MemoryContextAllocZero(PortalMemory, sizeof *portal); /* initialize portal heap context; typically it won't store much */ portal->heap = AllocSetContextCreate(PortalMemory, "PortalHeapMemory", ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE); /* create a resource owner for the portal */ portal->resowner = ResourceOwnerCreate(CurTransactionResourceOwner, "Portal"); /* initialize portal fields that don't start off zero */ portal->cleanup = PortalCleanup; portal->createSubid = GetCurrentSubTransactionId(); portal->strategy = PORTAL_MULTI_QUERY; portal->cursorOptions = CURSOR_OPT_NO_SCROLL; portal->atStart = true; portal->atEnd = true; /* disallow fetches until query is set */ /* put portal in table (sets portal->name) */ PortalHashTableInsert(portal, name); return portal;}/* * CreateNewPortal * Create a new portal, assigning it a random nonconflicting name. */PortalCreateNewPortal(void){ static unsigned int unnamed_portal_count = 0; char portalname[MAX_PORTALNAME_LEN]; /* Select a nonconflicting name */ for (;;) { unnamed_portal_count++; sprintf(portalname, "<unnamed portal %u>", unnamed_portal_count); if (GetPortalByName(portalname) == NULL) break; } return CreatePortal(portalname, false, false);}/* * PortalDefineQuery * A simple subroutine to establish a portal's query. * * Notes: commandTag shall be NULL if and only if the original query string * (before rewriting) was an empty string. Also, the passed commandTag must * be a pointer to a constant string, since it is not copied. The caller is * responsible for ensuring that the passed sourceText (if any), parse and * plan trees have adequate lifetime. Also, queryContext must accurately * describe the location of the parse and plan trees. */voidPortalDefineQuery(Portal portal, const char *sourceText, const char *commandTag, List *parseTrees, List *planTrees, MemoryContext queryContext){ AssertArg(PortalIsValid(portal)); AssertState(portal->queryContext == NULL); /* else defined already */ Assert(list_length(parseTrees) == list_length(planTrees)); Assert(commandTag != NULL || parseTrees == NIL); portal->sourceText = sourceText; portal->commandTag = commandTag; portal->parseTrees = parseTrees; portal->planTrees = planTrees; portal->queryContext = queryContext;}/* * PortalCreateHoldStore * Create the tuplestore for a portal. */voidPortalCreateHoldStore(Portal portal){ MemoryContext oldcxt; Assert(portal->holdContext == NULL); Assert(portal->holdStore == NULL); /* * Create the memory context that is used for storage of the tuple set. * Note this is NOT a child of the portal's heap memory. */ portal->holdContext = AllocSetContextCreate(PortalMemory, "PortalHoldContext", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); /* Create the tuple store, selecting cross-transaction temp files. */ oldcxt = MemoryContextSwitchTo(portal->holdContext); /* XXX: Should maintenance_work_mem be used for the portal size? */ portal->holdStore = tuplestore_begin_heap(true, true, work_mem); MemoryContextSwitchTo(oldcxt);}/* * PortalDrop * Destroy the portal. */voidPortalDrop(Portal portal, bool isTopCommit){ AssertArg(PortalIsValid(portal)); /* Not sure if this case can validly happen or not... */ if (portal->status == PORTAL_ACTIVE) elog(ERROR, "cannot drop active portal"); /* * Remove portal from hash table. Because we do this first, we will not * come back to try to remove the portal again if there's any error in the * subsequent steps. Better to leak a little memory than to get into an * infinite error-recovery loop. */ PortalHashTableDelete(portal); /* let portalcmds.c clean up the state it knows about */ if (PointerIsValid(portal->cleanup)) (*portal->cleanup) (portal); /* * Release any resources still attached to the portal. There are several * cases being covered here: * * Top transaction commit (indicated by isTopCommit): normally we should * do nothing here and let the regular end-of-transaction resource * releasing mechanism handle these resources too. However, if we have a * FAILED portal (eg, a cursor that got an error), we'd better clean up * its resources to avoid resource-leakage warning messages. * * Sub transaction commit: never comes here at all, since we don't kill * any portals in AtSubCommit_Portals(). * * Main or sub transaction abort: we will do nothing here because * portal->resowner was already set NULL; the resources were already * cleaned up in transaction abort. * * Ordinary portal drop: must release resources. However, if the portal * is not FAILED then we do not release its locks. The locks become the * responsibility of the transaction's ResourceOwner (since it is the * parent of the portal's owner) and will be released when the transaction * eventually ends. */ if (portal->resowner && (!isTopCommit || portal->status == PORTAL_FAILED)) { bool isCommit = (portal->status != PORTAL_FAILED); ResourceOwnerRelease(portal->resowner, RESOURCE_RELEASE_BEFORE_LOCKS, isCommit, false); ResourceOwnerRelease(portal->resowner, RESOURCE_RELEASE_LOCKS, isCommit, false); ResourceOwnerRelease(portal->resowner, RESOURCE_RELEASE_AFTER_LOCKS, isCommit, false); ResourceOwnerDelete(portal->resowner); } portal->resowner = NULL; /* * Delete tuplestore if present. We should do this even under error * conditions; since the tuplestore would have been using cross- * transaction storage, its temp files need to be explicitly deleted. */ if (portal->holdStore) { MemoryContext oldcontext; oldcontext = MemoryContextSwitchTo(portal->holdContext); tuplestore_end(portal->holdStore); MemoryContextSwitchTo(oldcontext); portal->holdStore = NULL; } /* delete tuplestore storage, if any */ if (portal->holdContext) MemoryContextDelete(portal->holdContext); /* release subsidiary storage */ MemoryContextDelete(PortalGetHeapMemory(portal));
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?