Commit fe548629 authored by Tom Lane's avatar Tom Lane

Invent ResourceOwner mechanism as per my recent proposal, and use it to

keep track of portal-related resources separately from transaction-related
resources.  This allows cursors to work in a somewhat sane fashion with
nested transactions.  For now, cursor behavior is non-subtransactional,
that is a cursor's state does not roll back if you abort a subtransaction
that fetched from the cursor.  We might want to change that later.
parent f4c069ca
...@@ -75,7 +75,7 @@ user_write_unlock_oid(Oid oid) ...@@ -75,7 +75,7 @@ user_write_unlock_oid(Oid oid)
int int
user_unlock_all(void) user_unlock_all(void)
{ {
return LockReleaseAll(USER_LOCKMETHOD, MyProc, ReleaseAll, 0, NULL); return LockReleaseAll(USER_LOCKMETHOD, MyProc, true);
} }
/* end of file */ /* end of file */
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gist/gistscan.c,v 1.52 2004/07/01 00:49:27 tgl Exp $ * $PostgreSQL: pgsql/src/backend/access/gist/gistscan.c,v 1.53 2004/07/17 03:27:20 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "access/genam.h" #include "access/genam.h"
#include "access/gist.h" #include "access/gist.h"
#include "access/gistscan.h" #include "access/gistscan.h"
#include "utils/resowner.h"
/* routines defined and used here */ /* routines defined and used here */
...@@ -41,7 +42,7 @@ static void adjustiptr(IndexScanDesc s, ItemPointer iptr, ...@@ -41,7 +42,7 @@ static void adjustiptr(IndexScanDesc s, ItemPointer iptr,
typedef struct GISTScanListData typedef struct GISTScanListData
{ {
IndexScanDesc gsl_scan; IndexScanDesc gsl_scan;
TransactionId gsl_creatingXid; ResourceOwner gsl_owner;
struct GISTScanListData *gsl_next; struct GISTScanListData *gsl_next;
} GISTScanListData; } GISTScanListData;
...@@ -224,7 +225,7 @@ gistregscan(IndexScanDesc s) ...@@ -224,7 +225,7 @@ gistregscan(IndexScanDesc s)
l = (GISTScanList) palloc(sizeof(GISTScanListData)); l = (GISTScanList) palloc(sizeof(GISTScanListData));
l->gsl_scan = s; l->gsl_scan = s;
l->gsl_creatingXid = GetCurrentTransactionId(); l->gsl_owner = CurrentResourceOwner;
l->gsl_next = GISTScans; l->gsl_next = GISTScans;
GISTScans = l; GISTScans = l;
} }
...@@ -253,52 +254,28 @@ gistdropscan(IndexScanDesc s) ...@@ -253,52 +254,28 @@ gistdropscan(IndexScanDesc s)
} }
/* /*
* AtEOXact_gist() --- clean up gist subsystem at xact abort or commit. * ReleaseResources_gist() --- clean up gist subsystem resources.
* *
* This is here because it needs to touch this module's static var GISTScans. * This is here because it needs to touch this module's static var GISTScans.
*/ */
void void
AtEOXact_gist(void) ReleaseResources_gist(void)
{
/*
* Note: these actions should only be necessary during xact abort; but
* they can't hurt during a commit.
*/
/*
* Reset the active-scans list to empty. We do not need to free the
* list elements, because they're all palloc()'d, so they'll go away
* at end of transaction anyway.
*/
GISTScans = NULL;
}
/*
* AtEOSubXact_gist() --- clean up gist subsystem at subxact abort or commit.
*
* This is here because it needs to touch this module's static var GISTScans.
*/
void
AtEOSubXact_gist(TransactionId childXid)
{ {
GISTScanList l; GISTScanList l;
GISTScanList prev; GISTScanList prev;
GISTScanList next; GISTScanList next;
/* /*
* Note: these actions should only be necessary during xact abort; but * Note: this should be a no-op during normal query shutdown.
* they can't hurt during a commit. * However, in an abort situation ExecutorEnd is not called and so
*/ * there may be open index scans to clean up.
/*
* Forget active scans that were started in this subtransaction.
*/ */
prev = NULL; prev = NULL;
for (l = GISTScans; l != NULL; l = next) for (l = GISTScans; l != NULL; l = next)
{ {
next = l->gsl_next; next = l->gsl_next;
if (l->gsl_creatingXid == childXid) if (l->gsl_owner == CurrentResourceOwner)
{ {
if (prev == NULL) if (prev == NULL)
GISTScans = next; GISTScans = next;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/hash/hashscan.c,v 1.34 2004/07/01 00:49:29 tgl Exp $ * $PostgreSQL: pgsql/src/backend/access/hash/hashscan.c,v 1.35 2004/07/17 03:27:40 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -16,12 +16,13 @@ ...@@ -16,12 +16,13 @@
#include "postgres.h" #include "postgres.h"
#include "access/hash.h" #include "access/hash.h"
#include "utils/resowner.h"
typedef struct HashScanListData typedef struct HashScanListData
{ {
IndexScanDesc hashsl_scan; IndexScanDesc hashsl_scan;
TransactionId hashsl_creatingXid; ResourceOwner hashsl_owner;
struct HashScanListData *hashsl_next; struct HashScanListData *hashsl_next;
} HashScanListData; } HashScanListData;
...@@ -31,52 +32,28 @@ static HashScanList HashScans = NULL; ...@@ -31,52 +32,28 @@ static HashScanList HashScans = NULL;
/* /*
* AtEOXact_hash() --- clean up hash subsystem at xact abort or commit. * ReleaseResources_hash() --- clean up hash subsystem resources.
* *
* This is here because it needs to touch this module's static var HashScans. * This is here because it needs to touch this module's static var HashScans.
*/ */
void void
AtEOXact_hash(void) ReleaseResources_hash(void)
{
/*
* Note: these actions should only be necessary during xact abort; but
* they can't hurt during a commit.
*/
/*
* Reset the active-scans list to empty. We do not need to free the
* list elements, because they're all palloc()'d, so they'll go away
* at end of transaction anyway.
*/
HashScans = NULL;
}
/*
* AtEOSubXact_hash() --- clean up hash subsystem at subxact abort or commit.
*
* This is here because it needs to touch this module's static var HashScans.
*/
void
AtEOSubXact_hash(TransactionId childXid)
{ {
HashScanList l; HashScanList l;
HashScanList prev; HashScanList prev;
HashScanList next; HashScanList next;
/* /*
* Note: these actions should only be necessary during xact abort; but * Note: this should be a no-op during normal query shutdown.
* they can't hurt during a commit. * However, in an abort situation ExecutorEnd is not called and so
*/ * there may be open index scans to clean up.
/*
* Forget active scans that were started in this subtransaction.
*/ */
prev = NULL; prev = NULL;
for (l = HashScans; l != NULL; l = next) for (l = HashScans; l != NULL; l = next)
{ {
next = l->hashsl_next; next = l->hashsl_next;
if (l->hashsl_creatingXid == childXid) if (l->hashsl_owner == CurrentResourceOwner)
{ {
if (prev == NULL) if (prev == NULL)
HashScans = next; HashScans = next;
...@@ -101,7 +78,7 @@ _hash_regscan(IndexScanDesc scan) ...@@ -101,7 +78,7 @@ _hash_regscan(IndexScanDesc scan)
new_el = (HashScanList) palloc(sizeof(HashScanListData)); new_el = (HashScanList) palloc(sizeof(HashScanListData));
new_el->hashsl_scan = scan; new_el->hashsl_scan = scan;
new_el->hashsl_creatingXid = GetCurrentTransactionId(); new_el->hashsl_owner = CurrentResourceOwner;
new_el->hashsl_next = HashScans; new_el->hashsl_next = HashScans;
HashScans = new_el; HashScans = new_el;
} }
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.118 2004/06/05 19:48:07 tgl Exp $ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.119 2004/07/17 03:27:59 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -58,16 +58,6 @@ static void btbuildCallback(Relation index, ...@@ -58,16 +58,6 @@ static void btbuildCallback(Relation index,
void *state); void *state);
/*
* AtEOXact_nbtree() --- clean up nbtree subsystem at xact abort or commit.
*/
void
AtEOXact_nbtree(void)
{
/* nothing to do at the moment */
}
/* /*
* btbuild() -- build a new btree index. * btbuild() -- build a new btree index.
* *
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/rtree/rtscan.c,v 1.52 2004/07/01 00:49:31 tgl Exp $ * $PostgreSQL: pgsql/src/backend/access/rtree/rtscan.c,v 1.53 2004/07/17 03:28:17 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "access/genam.h" #include "access/genam.h"
#include "access/rtree.h" #include "access/rtree.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/resowner.h"
/* routines defined and used here */ /* routines defined and used here */
...@@ -42,7 +43,7 @@ static void adjustiptr(IndexScanDesc s, ItemPointer iptr, ...@@ -42,7 +43,7 @@ static void adjustiptr(IndexScanDesc s, ItemPointer iptr,
typedef struct RTScanListData typedef struct RTScanListData
{ {
IndexScanDesc rtsl_scan; IndexScanDesc rtsl_scan;
TransactionId rtsl_creatingXid; ResourceOwner rtsl_owner;
struct RTScanListData *rtsl_next; struct RTScanListData *rtsl_next;
} RTScanListData; } RTScanListData;
...@@ -241,7 +242,7 @@ rtregscan(IndexScanDesc s) ...@@ -241,7 +242,7 @@ rtregscan(IndexScanDesc s)
l = (RTScanList) palloc(sizeof(RTScanListData)); l = (RTScanList) palloc(sizeof(RTScanListData));
l->rtsl_scan = s; l->rtsl_scan = s;
l->rtsl_creatingXid = GetCurrentTransactionId(); l->rtsl_owner = CurrentResourceOwner;
l->rtsl_next = RTScans; l->rtsl_next = RTScans;
RTScans = l; RTScans = l;
} }
...@@ -272,52 +273,28 @@ rtdropscan(IndexScanDesc s) ...@@ -272,52 +273,28 @@ rtdropscan(IndexScanDesc s)
} }
/* /*
* AtEOXact_rtree() --- clean up rtree subsystem at xact abort or commit. * ReleaseResources_rtree() --- clean up rtree subsystem resources.
* *
* This is here because it needs to touch this module's static var RTScans. * This is here because it needs to touch this module's static var RTScans.
*/ */
void void
AtEOXact_rtree(void) ReleaseResources_rtree(void)
{
/*
* Note: these actions should only be necessary during xact abort; but
* they can't hurt during a commit.
*/
/*
* Reset the active-scans list to empty. We do not need to free the
* list elements, because they're all palloc()'d, so they'll go away
* at end of transaction anyway.
*/
RTScans = NULL;
}
/*
* AtEOSubXact_rtree() --- clean up rtree subsystem at subxact abort or commit.
*
* This is here because it needs to touch this module's static var RTScans.
*/
void
AtEOSubXact_rtree(TransactionId childXid)
{ {
RTScanList l; RTScanList l;
RTScanList prev; RTScanList prev;
RTScanList next; RTScanList next;
/* /*
* Note: these actions should only be necessary during xact abort; but * Note: this should be a no-op during normal query shutdown.
* they can't hurt during a commit. * However, in an abort situation ExecutorEnd is not called and so
*/ * there may be open index scans to clean up.
/*
* Forget active scans that were started in this subtransaction.
*/ */
prev = NULL; prev = NULL;
for (l = RTScans; l != NULL; l = next) for (l = RTScans; l != NULL; l = next)
{ {
next = l->rtsl_next; next = l->rtsl_next;
if (l->rtsl_creatingXid == childXid) if (l->rtsl_owner == CurrentResourceOwner)
{ {
if (prev == NULL) if (prev == NULL)
RTScans = next; RTScans = next;
......
This diff is collapsed.
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/bootstrap/bootparse.y,v 1.70 2004/06/18 06:13:17 tgl Exp $ * $PostgreSQL: pgsql/src/backend/bootstrap/bootparse.y,v 1.71 2004/07/17 03:28:37 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -269,7 +269,12 @@ Boot_DeclareUniqueIndexStmt: ...@@ -269,7 +269,12 @@ Boot_DeclareUniqueIndexStmt:
; ;
Boot_BuildIndsStmt: Boot_BuildIndsStmt:
XBUILD INDICES { build_indices(); } XBUILD INDICES
{
do_start();
build_indices();
do_end();
}
; ;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.186 2004/07/11 00:18:43 momjian Exp $ * $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.187 2004/07/17 03:28:37 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -54,7 +54,6 @@ static void usage(void); ...@@ -54,7 +54,6 @@ static void usage(void);
static void bootstrap_signals(void); static void bootstrap_signals(void);
static hashnode *AddStr(char *str, int strlength, int mderef); static hashnode *AddStr(char *str, int strlength, int mderef);
static Form_pg_attribute AllocateAttribute(void); static Form_pg_attribute AllocateAttribute(void);
static bool BootstrapAlreadySeen(Oid id);
static int CompHash(char *str, int len); static int CompHash(char *str, int len);
static hashnode *FindStr(char *str, int length, hashnode *mderef); static hashnode *FindStr(char *str, int length, hashnode *mderef);
static Oid gettype(char *type); static Oid gettype(char *type);
...@@ -880,34 +879,6 @@ InsertOneNull(int i) ...@@ -880,34 +879,6 @@ InsertOneNull(int i)
Blanks[i] = 'n'; Blanks[i] = 'n';
} }
#define MORE_THAN_THE_NUMBER_OF_CATALOGS 256
static bool
BootstrapAlreadySeen(Oid id)
{
static Oid seenArray[MORE_THAN_THE_NUMBER_OF_CATALOGS];
static int nseen = 0;
bool seenthis;
int i;
seenthis = false;
for (i = 0; i < nseen; i++)
{
if (seenArray[i] == id)
{
seenthis = true;
break;
}
}
if (!seenthis)
{
seenArray[nseen] = id;
nseen++;
}
return seenthis;
}
/* ---------------- /* ----------------
* cleanup * cleanup
* ---------------- * ----------------
...@@ -1270,25 +1241,6 @@ build_indices(void) ...@@ -1270,25 +1241,6 @@ build_indices(void)
* index, but in bootstrap mode it will not. * index, but in bootstrap mode it will not.
*/ */
/*
* All of the rest of this routine is needed only because in
* bootstrap processing we don't increment xact id's. The normal
* DefineIndex code replaces a pg_class tuple with updated info
* including the relhasindex flag (which we need to have updated).
* Unfortunately, there are always two indices defined on each
* catalog causing us to update the same pg_class tuple twice for
* each catalog getting an index during bootstrap resulting in the
* ghost tuple problem (see heap_update). To get around this we
* change the relhasindex field ourselves in this routine keeping
* track of what catalogs we already changed so that we don't
* modify those tuples twice. The normal mechanism for updating
* pg_class is disabled during bootstrap.
*
* -mer
*/
if (!BootstrapAlreadySeen(RelationGetRelid(heap)))
UpdateStats(RelationGetRelid(heap), 0);
/* XXX Probably we ought to close the heap and index here? */ /* XXX Probably we ought to close the heap and index here? */
} }
} }
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.116 2004/05/26 04:41:08 neilc Exp $ * $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.117 2004/07/17 03:28:43 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -847,7 +847,7 @@ function_parse_error_transpose(const char *prosrc) ...@@ -847,7 +847,7 @@ function_parse_error_transpose(const char *prosrc)
} }
/* We can get the original query text from the active portal (hack...) */ /* We can get the original query text from the active portal (hack...) */
Assert(ActivePortal && ActivePortal->portalActive); Assert(ActivePortal && ActivePortal->status == PORTAL_ACTIVE);
queryText = ActivePortal->sourceText; queryText = ActivePortal->sourceText;
/* Try to locate the prosrc in the original text */ /* Try to locate the prosrc in the original text */
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.28 2004/06/11 01:08:37 tgl Exp $ * $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.29 2004/07/17 03:28:47 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -233,7 +233,7 @@ PerformPortalClose(const char *name) ...@@ -233,7 +233,7 @@ PerformPortalClose(const char *name)
* for portals. * for portals.
*/ */
void void
PortalCleanup(Portal portal, bool isError) PortalCleanup(Portal portal)
{ {
QueryDesc *queryDesc; QueryDesc *queryDesc;
...@@ -253,8 +253,16 @@ PortalCleanup(Portal portal, bool isError) ...@@ -253,8 +253,16 @@ PortalCleanup(Portal portal, bool isError)
if (queryDesc) if (queryDesc)
{ {
portal->queryDesc = NULL; portal->queryDesc = NULL;
if (!isError) if (portal->status != PORTAL_FAILED)
{
ResourceOwner saveResourceOwner;
/* We must make the portal's resource owner current */
saveResourceOwner = CurrentResourceOwner;
CurrentResourceOwner = portal->resowner;
ExecutorEnd(queryDesc); ExecutorEnd(queryDesc);
CurrentResourceOwner = saveResourceOwner;
}
} }
} }
...@@ -271,6 +279,7 @@ PersistHoldablePortal(Portal portal) ...@@ -271,6 +279,7 @@ PersistHoldablePortal(Portal portal)
{ {
QueryDesc *queryDesc = PortalGetQueryDesc(portal); QueryDesc *queryDesc = PortalGetQueryDesc(portal);
Portal saveActivePortal; Portal saveActivePortal;
ResourceOwner saveResourceOwner;
MemoryContext savePortalContext; MemoryContext savePortalContext;
MemoryContext saveQueryContext; MemoryContext saveQueryContext;
MemoryContext oldcxt; MemoryContext oldcxt;
...@@ -281,8 +290,6 @@ PersistHoldablePortal(Portal portal) ...@@ -281,8 +290,6 @@ PersistHoldablePortal(Portal portal)
*/ */
Assert(portal->createXact == GetCurrentTransactionId()); Assert(portal->createXact == GetCurrentTransactionId());
Assert(queryDesc != NULL); Assert(queryDesc != NULL);
Assert(portal->portalReady);
Assert(!portal->portalDone);
/* /*
* Caller must have created the tuplestore already. * Caller must have created the tuplestore already.
...@@ -303,17 +310,19 @@ PersistHoldablePortal(Portal portal) ...@@ -303,17 +310,19 @@ PersistHoldablePortal(Portal portal)
/* /*
* Check for improper portal use, and mark portal active. * Check for improper portal use, and mark portal active.
*/ */
if (portal->portalActive) if (portal->status != PORTAL_READY)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OBJECT_IN_USE), (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("portal \"%s\" already active", portal->name))); errmsg("portal \"%s\" cannot be run", portal->name)));
portal->portalActive = true; portal->status = PORTAL_ACTIVE;
/* /*
* Set global portal context pointers. * Set global portal context pointers.
*/ */
saveActivePortal = ActivePortal; saveActivePortal = ActivePortal;
ActivePortal = portal; ActivePortal = portal;
saveResourceOwner = CurrentResourceOwner;
CurrentResourceOwner = portal->resowner;
savePortalContext = PortalContext; savePortalContext = PortalContext;
PortalContext = PortalGetHeapMemory(portal); PortalContext = PortalGetHeapMemory(portal);
saveQueryContext = QueryContext; saveQueryContext = QueryContext;
...@@ -342,13 +351,6 @@ PersistHoldablePortal(Portal portal) ...@@ -342,13 +351,6 @@ PersistHoldablePortal(Portal portal)
portal->queryDesc = NULL; /* prevent double shutdown */ portal->queryDesc = NULL; /* prevent double shutdown */
ExecutorEnd(queryDesc); ExecutorEnd(queryDesc);
/* Mark portal not active */
portal->portalActive = false;
ActivePortal = saveActivePortal;
PortalContext = savePortalContext;
QueryContext = saveQueryContext;
/* /*
* Reset the position in the result set: ideally, this could be * Reset the position in the result set: ideally, this could be
* implemented by just skipping straight to the tuple # that we need * implemented by just skipping straight to the tuple # that we need
...@@ -394,4 +396,12 @@ PersistHoldablePortal(Portal portal) ...@@ -394,4 +396,12 @@ PersistHoldablePortal(Portal portal)
* portal's heap via PortalContext. * portal's heap via PortalContext.
*/ */
MemoryContextDeleteChildren(PortalGetHeapMemory(portal)); MemoryContextDeleteChildren(PortalGetHeapMemory(portal));
/* Mark portal not active */
portal->status = PORTAL_READY;
ActivePortal = saveActivePortal;
CurrentResourceOwner = saveResourceOwner;
PortalContext = savePortalContext;
QueryContext = saveQueryContext;
} }
This diff is collapsed.
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/buffer/localbuf.c,v 1.56 2004/06/18 06:13:33 tgl Exp $ * $PostgreSQL: pgsql/src/backend/storage/buffer/localbuf.c,v 1.57 2004/07/17 03:28:49 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "storage/bufmgr.h" #include "storage/bufmgr.h"
#include "storage/smgr.h" #include "storage/smgr.h"
#include "utils/relcache.h" #include "utils/relcache.h"
#include "utils/resowner.h"
/*#define LBDEBUG*/ /*#define LBDEBUG*/
...@@ -62,6 +63,8 @@ LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr) ...@@ -62,6 +63,8 @@ LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr)
#endif #endif
LocalRefCount[i]++; LocalRefCount[i]++;
ResourceOwnerRememberBuffer(CurrentResourceOwner,
BufferDescriptorGetBuffer(bufHdr));
if (bufHdr->flags & BM_VALID) if (bufHdr->flags & BM_VALID)
*foundPtr = TRUE; *foundPtr = TRUE;
else else
...@@ -88,6 +91,8 @@ LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr) ...@@ -88,6 +91,8 @@ LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr)
{ {
bufHdr = &LocalBufferDescriptors[b]; bufHdr = &LocalBufferDescriptors[b];
LocalRefCount[b]++; LocalRefCount[b]++;
ResourceOwnerRememberBuffer(CurrentResourceOwner,
BufferDescriptorGetBuffer(bufHdr));
nextFreeLocalBuf = (b + 1) % NLocBuffer; nextFreeLocalBuf = (b + 1) % NLocBuffer;
break; break;
} }
...@@ -179,6 +184,7 @@ WriteLocalBuffer(Buffer buffer, bool release) ...@@ -179,6 +184,7 @@ WriteLocalBuffer(Buffer buffer, bool release)
{ {
Assert(LocalRefCount[bufid] > 0); Assert(LocalRefCount[bufid] > 0);
LocalRefCount[bufid]--; LocalRefCount[bufid]--;
ResourceOwnerForgetBuffer(CurrentResourceOwner, buffer);
} }
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.134 2004/07/01 00:50:59 tgl Exp $ * $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.135 2004/07/17 03:28:51 tgl Exp $
* *
* NOTES * NOTES
* Outside modules can create a lock table and acquire/release * Outside modules can create a lock table and acquire/release
...@@ -30,14 +30,15 @@ ...@@ -30,14 +30,15 @@
*/ */
#include "postgres.h" #include "postgres.h"
#include <unistd.h>
#include <signal.h> #include <signal.h>
#include <unistd.h>
#include "access/xact.h" #include "access/xact.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "storage/proc.h" #include "storage/proc.h"
#include "utils/memutils.h" #include "utils/memutils.h"
#include "utils/ps_status.h" #include "utils/ps_status.h"
#include "utils/resowner.h"
/* This configuration variable is used to set the lock table size */ /* This configuration variable is used to set the lock table size */
...@@ -424,6 +425,9 @@ LockAcquire(LOCKMETHODID lockmethodid, LOCKTAG *locktag, ...@@ -424,6 +425,9 @@ LockAcquire(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
/* ???????? This must be changed when short term locks will be used */ /* ???????? This must be changed when short term locks will be used */
locktag->lockmethodid = lockmethodid; locktag->lockmethodid = lockmethodid;
/* Prepare to record the lock in the current resource owner */
ResourceOwnerEnlargeLocks(CurrentResourceOwner);
Assert(lockmethodid < NumLockMethods); Assert(lockmethodid < NumLockMethods);
lockMethodTable = LockMethods[lockmethodid]; lockMethodTable = LockMethods[lockmethodid];
if (!lockMethodTable) if (!lockMethodTable)
...@@ -567,6 +571,8 @@ LockAcquire(LOCKMETHODID lockmethodid, LOCKTAG *locktag, ...@@ -567,6 +571,8 @@ LockAcquire(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
if (proclock->holding[lockmode] > 0) if (proclock->holding[lockmode] > 0)
{ {
GrantLock(lock, proclock, lockmode); GrantLock(lock, proclock, lockmode);
ResourceOwnerRememberLock(CurrentResourceOwner, locktag, xid,
lockmode);
PROCLOCK_PRINT("LockAcquire: owning", proclock); PROCLOCK_PRINT("LockAcquire: owning", proclock);
LWLockRelease(masterLock); LWLockRelease(masterLock);
return TRUE; return TRUE;
...@@ -580,6 +586,8 @@ LockAcquire(LOCKMETHODID lockmethodid, LOCKTAG *locktag, ...@@ -580,6 +586,8 @@ LockAcquire(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
if (myHolding[lockmode] > 0) if (myHolding[lockmode] > 0)
{ {
GrantLock(lock, proclock, lockmode); GrantLock(lock, proclock, lockmode);
ResourceOwnerRememberLock(CurrentResourceOwner, locktag, xid,
lockmode);
PROCLOCK_PRINT("LockAcquire: my other XID owning", proclock); PROCLOCK_PRINT("LockAcquire: my other XID owning", proclock);
LWLockRelease(masterLock); LWLockRelease(masterLock);
return TRUE; return TRUE;
...@@ -601,6 +609,8 @@ LockAcquire(LOCKMETHODID lockmethodid, LOCKTAG *locktag, ...@@ -601,6 +609,8 @@ LockAcquire(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
{ {
/* No conflict with held or previously requested locks */ /* No conflict with held or previously requested locks */
GrantLock(lock, proclock, lockmode); GrantLock(lock, proclock, lockmode);
ResourceOwnerRememberLock(CurrentResourceOwner, locktag, xid,
lockmode);
} }
else else
{ {
...@@ -803,6 +813,9 @@ LockCountMyLocks(SHMEM_OFFSET lockOffset, PGPROC *proc, int *myHolding) ...@@ -803,6 +813,9 @@ LockCountMyLocks(SHMEM_OFFSET lockOffset, PGPROC *proc, int *myHolding)
* *
* NOTE: if proc was blocked, it also needs to be removed from the wait list * NOTE: if proc was blocked, it also needs to be removed from the wait list
* and have its waitLock/waitHolder fields cleared. That's not done here. * and have its waitLock/waitHolder fields cleared. That's not done here.
*
* NOTE: the lock also has to be recorded in the current ResourceOwner;
* but since we may be awaking some other process, we can't do that here.
*/ */
void void
GrantLock(LOCK *lock, PROCLOCK *proclock, LOCKMODE lockmode) GrantLock(LOCK *lock, PROCLOCK *proclock, LOCKMODE lockmode)
...@@ -964,6 +977,9 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag, ...@@ -964,6 +977,9 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
/* ???????? This must be changed when short term locks will be used */ /* ???????? This must be changed when short term locks will be used */
locktag->lockmethodid = lockmethodid; locktag->lockmethodid = lockmethodid;
/* Record release of the lock in the current resource owner */
ResourceOwnerForgetLock(CurrentResourceOwner, locktag, xid, lockmode);
Assert(lockmethodid < NumLockMethods); Assert(lockmethodid < NumLockMethods);
lockMethodTable = LockMethods[lockmethodid]; lockMethodTable = LockMethods[lockmethodid];
if (!lockMethodTable) if (!lockMethodTable)
...@@ -1134,20 +1150,15 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag, ...@@ -1134,20 +1150,15 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
* *
* Well, not necessarily *all* locks. The available behaviors are: * Well, not necessarily *all* locks. The available behaviors are:
* *
* which == ReleaseAll: release all locks regardless of transaction * allxids == true: release all locks regardless of transaction
* affiliation. * affiliation.
* *
* which == ReleaseAllExceptSession: release all locks with Xid != 0 * allxids == false: release all locks with Xid != 0
* (zero is the Xid used for "session" locks). * (zero is the Xid used for "session" locks).
*
* which == ReleaseGivenXids: release only locks whose Xids appear in
* the xids[] array (of length nxids).
*
* xids/nxids are ignored when which != ReleaseGivenXids.
*/ */
bool bool
LockReleaseAll(LOCKMETHODID lockmethodid, PGPROC *proc, LockReleaseAll(LOCKMETHODID lockmethodid, PGPROC *proc,
LockReleaseWhich which, int nxids, TransactionId *xids) bool allxids)
{ {
SHM_QUEUE *procHolders = &(proc->procHolders); SHM_QUEUE *procHolders = &(proc->procHolders);
PROCLOCK *proclock; PROCLOCK *proclock;
...@@ -1196,25 +1207,9 @@ LockReleaseAll(LOCKMETHODID lockmethodid, PGPROC *proc, ...@@ -1196,25 +1207,9 @@ LockReleaseAll(LOCKMETHODID lockmethodid, PGPROC *proc,
if (LOCK_LOCKMETHOD(*lock) != lockmethodid) if (LOCK_LOCKMETHOD(*lock) != lockmethodid)
goto next_item; goto next_item;
if (which == ReleaseGivenXids) /* Ignore locks with Xid=0 unless we are asked to release all locks */
{ if (TransactionIdEquals(proclock->tag.xid, InvalidTransactionId)
/* Ignore locks with an Xid not in the list */ && !allxids)
bool release = false;
for (i = 0; i < nxids; i++)
{
if (TransactionIdEquals(proclock->tag.xid, xids[i]))
{
release = true;
break;
}
}
if (!release)
goto next_item;
}
/* Ignore locks with Xid=0 unless we are asked to release All locks */
else if (TransactionIdEquals(proclock->tag.xid, InvalidTransactionId)
&& which != ReleaseAll)
goto next_item; goto next_item;
PROCLOCK_PRINT("LockReleaseAll", proclock); PROCLOCK_PRINT("LockReleaseAll", proclock);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.149 2004/07/01 00:50:59 tgl Exp $ * $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.150 2004/07/17 03:28:51 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -40,7 +40,6 @@ ...@@ -40,7 +40,6 @@
*/ */
#include "postgres.h" #include "postgres.h"
#include <errno.h>
#include <signal.h> #include <signal.h>
#include <unistd.h> #include <unistd.h>
#include <sys/time.h> #include <sys/time.h>
...@@ -51,6 +50,8 @@ ...@@ -51,6 +50,8 @@
#include "storage/proc.h" #include "storage/proc.h"
#include "storage/sinval.h" #include "storage/sinval.h"
#include "storage/spin.h" #include "storage/spin.h"
#include "utils/resowner.h"
/* GUC variables */ /* GUC variables */
int DeadlockTimeout = 1000; int DeadlockTimeout = 1000;
...@@ -75,6 +76,11 @@ static PGPROC *DummyProcs = NULL; ...@@ -75,6 +76,11 @@ static PGPROC *DummyProcs = NULL;
static bool waitingForLock = false; static bool waitingForLock = false;
static bool waitingForSignal = false; static bool waitingForSignal = false;
/* Auxiliary state, valid when waitingForLock is true */
static LOCKTAG waitingForLockTag;
static TransactionId waitingForLockXid;
static LOCKMODE waitingForLockMode;
/* Mark these volatile because they can be changed by signal handler */ /* Mark these volatile because they can be changed by signal handler */
static volatile bool statement_timeout_active = false; static volatile bool statement_timeout_active = false;
static volatile bool deadlock_timeout_active = false; static volatile bool deadlock_timeout_active = false;
...@@ -234,7 +240,7 @@ InitProcess(void) ...@@ -234,7 +240,7 @@ InitProcess(void)
* prepared for us by InitProcGlobal. * prepared for us by InitProcGlobal.
*/ */
SHMQueueElemInit(&(MyProc->links)); SHMQueueElemInit(&(MyProc->links));
MyProc->errType = STATUS_OK; MyProc->waitStatus = STATUS_OK;
MyProc->xid = InvalidTransactionId; MyProc->xid = InvalidTransactionId;
MyProc->xmin = InvalidTransactionId; MyProc->xmin = InvalidTransactionId;
MyProc->pid = MyProcPid; MyProc->pid = MyProcPid;
...@@ -308,7 +314,7 @@ InitDummyProcess(int proctype) ...@@ -308,7 +314,7 @@ InitDummyProcess(int proctype)
*/ */
MyProc->pid = MyProcPid; /* marks dummy proc as in use by me */ MyProc->pid = MyProcPid; /* marks dummy proc as in use by me */
SHMQueueElemInit(&(MyProc->links)); SHMQueueElemInit(&(MyProc->links));
MyProc->errType = STATUS_OK; MyProc->waitStatus = STATUS_OK;
MyProc->xid = InvalidTransactionId; MyProc->xid = InvalidTransactionId;
MyProc->xmin = InvalidTransactionId; MyProc->xmin = InvalidTransactionId;
MyProc->databaseId = MyDatabaseId; MyProc->databaseId = MyDatabaseId;
...@@ -348,15 +354,40 @@ LockWaitCancel(void) ...@@ -348,15 +354,40 @@ LockWaitCancel(void)
if (!waitingForLock) if (!waitingForLock)
return false; return false;
waitingForLock = false;
/* Turn off the deadlock timer, if it's still running (see ProcSleep) */ /* Turn off the deadlock timer, if it's still running (see ProcSleep) */
disable_sig_alarm(false); disable_sig_alarm(false);
/* Unlink myself from the wait queue, if on it (might not be anymore!) */ /* Unlink myself from the wait queue, if on it (might not be anymore!) */
LWLockAcquire(LockMgrLock, LW_EXCLUSIVE); LWLockAcquire(LockMgrLock, LW_EXCLUSIVE);
if (MyProc->links.next != INVALID_OFFSET) if (MyProc->links.next != INVALID_OFFSET)
{
/* We could not have been granted the lock yet */
Assert(MyProc->waitStatus == STATUS_ERROR);
RemoveFromWaitQueue(MyProc); RemoveFromWaitQueue(MyProc);
}
else
{
/*
* Somebody kicked us off the lock queue already. Perhaps they
* granted us the lock, or perhaps they detected a deadlock.
* If they did grant us the lock, we'd better remember it in
* CurrentResourceOwner.
*
* Exception: if CurrentResourceOwner is NULL then we can't do
* anything. This could only happen when we are invoked from ProcKill
* or some similar place, where all our locks are about to be released
* anyway.
*/
if (MyProc->waitStatus == STATUS_OK && CurrentResourceOwner != NULL)
ResourceOwnerRememberLock(CurrentResourceOwner,
&waitingForLockTag,
waitingForLockXid,
waitingForLockMode);
}
waitingForLock = false;
LWLockRelease(LockMgrLock); LWLockRelease(LockMgrLock);
/* /*
...@@ -380,34 +411,29 @@ LockWaitCancel(void) ...@@ -380,34 +411,29 @@ LockWaitCancel(void)
/* /*
* ProcReleaseLocks() -- release locks associated with current transaction * ProcReleaseLocks() -- release locks associated with current transaction
* at main transaction and subtransaction commit or abort * at main transaction commit or abort
*
* The options for which locks to release are the same as for the underlying
* LockReleaseAll() function.
*
* Notes:
* *
* At main transaction commit, we release all locks except session locks. * At main transaction commit, we release all locks except session locks.
* At main transaction abort, we release all locks including session locks; * At main transaction abort, we release all locks including session locks;
* this lets us clean up after a VACUUM FULL failure. * this lets us clean up after a VACUUM FULL failure.
* *
* At subtransaction commit, we don't release any locks (so this func is not * At subtransaction commit, we don't release any locks (so this func is not
* called at all); we will defer the releasing to the parent transaction. * needed at all); we will defer the releasing to the parent transaction.
* At subtransaction abort, we release all locks held by the subtransaction; * At subtransaction abort, we release all locks held by the subtransaction;
* this is implemented by passing in the Xids of the failed subxact and its * this is implemented by retail releasing of the locks under control of
* children in the xids[] array. * the ResourceOwner mechanism.
* *
* Note that user locks are not released in any case. * Note that user locks are not released in any case.
*/ */
void void
ProcReleaseLocks(LockReleaseWhich which, int nxids, TransactionId *xids) ProcReleaseLocks(bool isCommit)
{ {
if (!MyProc) if (!MyProc)
return; return;
/* If waiting, get off wait queue (should only be needed after error) */ /* If waiting, get off wait queue (should only be needed after error) */
LockWaitCancel(); LockWaitCancel();
/* Release locks */ /* Release locks */
LockReleaseAll(DEFAULT_LOCKMETHOD, MyProc, which, nxids, xids); LockReleaseAll(DEFAULT_LOCKMETHOD, MyProc, !isCommit);
} }
...@@ -440,11 +466,11 @@ ProcKill(int code, Datum arg) ...@@ -440,11 +466,11 @@ ProcKill(int code, Datum arg)
LockWaitCancel(); LockWaitCancel();
/* Remove from the standard lock table */ /* Remove from the standard lock table */
LockReleaseAll(DEFAULT_LOCKMETHOD, MyProc, ReleaseAll, 0, NULL); LockReleaseAll(DEFAULT_LOCKMETHOD, MyProc, true);
#ifdef USER_LOCKS #ifdef USER_LOCKS
/* Remove from the user lock table */ /* Remove from the user lock table */
LockReleaseAll(USER_LOCKMETHOD, MyProc, ReleaseAll, 0, NULL); LockReleaseAll(USER_LOCKMETHOD, MyProc, true);
#endif #endif
SpinLockAcquire(ProcStructLock); SpinLockAcquire(ProcStructLock);
...@@ -618,6 +644,10 @@ ProcSleep(LockMethod lockMethodTable, ...@@ -618,6 +644,10 @@ ProcSleep(LockMethod lockMethodTable,
{ {
/* Skip the wait and just grant myself the lock. */ /* Skip the wait and just grant myself the lock. */
GrantLock(lock, proclock, lockmode); GrantLock(lock, proclock, lockmode);
ResourceOwnerRememberLock(CurrentResourceOwner,
&lock->tag,
proclock->tag.xid,
lockmode);
return STATUS_OK; return STATUS_OK;
} }
/* Break out of loop to put myself before him */ /* Break out of loop to put myself before him */
...@@ -653,7 +683,7 @@ ProcSleep(LockMethod lockMethodTable, ...@@ -653,7 +683,7 @@ ProcSleep(LockMethod lockMethodTable,
MyProc->waitHolder = proclock; MyProc->waitHolder = proclock;
MyProc->waitLockMode = lockmode; MyProc->waitLockMode = lockmode;
MyProc->errType = STATUS_OK; /* initialize result for success */ MyProc->waitStatus = STATUS_ERROR; /* initialize result for error */
/* /*
* If we detected deadlock, give up without waiting. This must agree * If we detected deadlock, give up without waiting. This must agree
...@@ -663,11 +693,13 @@ ProcSleep(LockMethod lockMethodTable, ...@@ -663,11 +693,13 @@ ProcSleep(LockMethod lockMethodTable,
if (early_deadlock) if (early_deadlock)
{ {
RemoveFromWaitQueue(MyProc); RemoveFromWaitQueue(MyProc);
MyProc->errType = STATUS_ERROR;
return STATUS_ERROR; return STATUS_ERROR;
} }
/* mark that we are waiting for a lock */ /* mark that we are waiting for a lock */
waitingForLockTag = lock->tag;
waitingForLockXid = proclock->tag.xid;
waitingForLockMode = lockmode;
waitingForLock = true; waitingForLock = true;
/* /*
...@@ -683,7 +715,7 @@ ProcSleep(LockMethod lockMethodTable, ...@@ -683,7 +715,7 @@ ProcSleep(LockMethod lockMethodTable,
/* /*
* Set timer so we can wake up after awhile and check for a deadlock. * Set timer so we can wake up after awhile and check for a deadlock.
* If a deadlock is detected, the handler releases the process's * If a deadlock is detected, the handler releases the process's
* semaphore and sets MyProc->errType = STATUS_ERROR, allowing us to * semaphore and sets MyProc->waitStatus = STATUS_ERROR, allowing us to
* know that we must report failure rather than success. * know that we must report failure rather than success.
* *
* By delaying the check until we've waited for a bit, we can avoid * By delaying the check until we've waited for a bit, we can avoid
...@@ -703,8 +735,10 @@ ProcSleep(LockMethod lockMethodTable, ...@@ -703,8 +735,10 @@ ProcSleep(LockMethod lockMethodTable,
* We pass interruptOK = true, which eliminates a window in which * We pass interruptOK = true, which eliminates a window in which
* cancel/die interrupts would be held off undesirably. This is a * cancel/die interrupts would be held off undesirably. This is a
* promise that we don't mind losing control to a cancel/die interrupt * promise that we don't mind losing control to a cancel/die interrupt
* here. We don't, because we have no state-change work to do after * here. We don't, because we have no shared-state-change work to do
* being granted the lock (the grantor did it all). * after being granted the lock (the grantor did it all). We do have
* to worry about updating the local CurrentResourceOwner, but if we
* lose control to an error, LockWaitCancel will fix that up.
*/ */
PGSemaphoreLock(&MyProc->sem, true); PGSemaphoreLock(&MyProc->sem, true);
...@@ -715,20 +749,32 @@ ProcSleep(LockMethod lockMethodTable, ...@@ -715,20 +749,32 @@ ProcSleep(LockMethod lockMethodTable,
elog(FATAL, "could not disable timer for process wakeup"); elog(FATAL, "could not disable timer for process wakeup");
/* /*
* Now there is nothing for LockWaitCancel to do. * Re-acquire the locktable's masterLock. We have to do this to hold
* off cancel/die interrupts before we can mess with waitingForLock
* (else we might have a missed or duplicated CurrentResourceOwner
* update).
*/
LWLockAcquire(masterLock, LW_EXCLUSIVE);
/*
* We no longer want LockWaitCancel to do anything.
*/ */
waitingForLock = false; waitingForLock = false;
/* /*
* Re-acquire the locktable's masterLock. * If we got the lock, be sure to remember it in CurrentResourceOwner.
*/ */
LWLockAcquire(masterLock, LW_EXCLUSIVE); if (MyProc->waitStatus == STATUS_OK)
ResourceOwnerRememberLock(CurrentResourceOwner,
&lock->tag,
proclock->tag.xid,
lockmode);
/* /*
* We don't have to do anything else, because the awaker did all the * We don't have to do anything else, because the awaker did all the
* necessary update of the lock table and MyProc. * necessary update of the lock table and MyProc.
*/ */
return MyProc->errType; return MyProc->waitStatus;
} }
...@@ -743,7 +789,7 @@ ProcSleep(LockMethod lockMethodTable, ...@@ -743,7 +789,7 @@ ProcSleep(LockMethod lockMethodTable,
* to twiddle the lock's request counts too --- see RemoveFromWaitQueue. * to twiddle the lock's request counts too --- see RemoveFromWaitQueue.
*/ */
PGPROC * PGPROC *
ProcWakeup(PGPROC *proc, int errType) ProcWakeup(PGPROC *proc, int waitStatus)
{ {
PGPROC *retProc; PGPROC *retProc;
...@@ -764,7 +810,7 @@ ProcWakeup(PGPROC *proc, int errType) ...@@ -764,7 +810,7 @@ ProcWakeup(PGPROC *proc, int errType)
/* Clean up process' state and pass it the ok/fail signal */ /* Clean up process' state and pass it the ok/fail signal */
proc->waitLock = NULL; proc->waitLock = NULL;
proc->waitHolder = NULL; proc->waitHolder = NULL;
proc->errType = errType; proc->waitStatus = waitStatus;
/* And awaken it */ /* And awaken it */
PGSemaphoreUnlock(&proc->sem); PGSemaphoreUnlock(&proc->sem);
...@@ -891,10 +937,10 @@ CheckDeadLock(void) ...@@ -891,10 +937,10 @@ CheckDeadLock(void)
RemoveFromWaitQueue(MyProc); RemoveFromWaitQueue(MyProc);
/* /*
* Set MyProc->errType to STATUS_ERROR so that ProcSleep will report * Set MyProc->waitStatus to STATUS_ERROR so that ProcSleep will report
* an error after we return from the signal handler. * an error after we return from the signal handler.
*/ */
MyProc->errType = STATUS_ERROR; MyProc->waitStatus = STATUS_ERROR;
/* /*
* Unlock my semaphore so that the interrupted ProcSleep() call can * Unlock my semaphore so that the interrupted ProcSleep() call can
......
...@@ -11,12 +11,13 @@ ...@@ -11,12 +11,13 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/smgr/smgr.c,v 1.76 2004/07/11 19:52:51 tgl Exp $ * $PostgreSQL: pgsql/src/backend/storage/smgr/smgr.c,v 1.77 2004/07/17 03:28:55 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h" #include "postgres.h"
#include "access/xact.h"
#include "commands/tablespace.h" #include "commands/tablespace.h"
#include "storage/bufmgr.h" #include "storage/bufmgr.h"
#include "storage/freespace.h" #include "storage/freespace.h"
...@@ -81,10 +82,15 @@ static HTAB *SMgrRelationHash = NULL; ...@@ -81,10 +82,15 @@ static HTAB *SMgrRelationHash = NULL;
* executed immediately, but is just entered in the list. When and if * executed immediately, but is just entered in the list. When and if
* the transaction commits, we can delete the physical file. * the transaction commits, we can delete the physical file.
* *
* The list is kept in CurTransactionContext. In subtransactions, each * To handle subtransactions, every entry is marked with its transaction
* subtransaction has its own list in its own CurTransactionContext, but * nesting level. At subtransaction commit, we reassign the subtransaction's
* successful subtransactions attach their lists to their parent's list. * entries to the parent nesting level. At subtransaction abort, we can
* Failed subtransactions can immediately execute the abort-time actions. * immediately execute the abort-time actions for all entries of the current
* nesting level.
*
* NOTE: the list is kept in TopMemoryContext to be sure it won't disappear
* unbetimes. It'd probably be OK to keep it in TopTransactionContext,
* but I'm being paranoid.
*/ */
typedef struct PendingRelDelete typedef struct PendingRelDelete
...@@ -93,11 +99,11 @@ typedef struct PendingRelDelete ...@@ -93,11 +99,11 @@ typedef struct PendingRelDelete
int which; /* which storage manager? */ int which; /* which storage manager? */
bool isTemp; /* is it a temporary relation? */ bool isTemp; /* is it a temporary relation? */
bool atCommit; /* T=delete at commit; F=delete at abort */ bool atCommit; /* T=delete at commit; F=delete at abort */
int nestLevel; /* xact nesting level of request */
struct PendingRelDelete *next; /* linked-list link */
} PendingRelDelete; } PendingRelDelete;
static List *pendingDeletes = NIL; /* head of linked list */ static PendingRelDelete *pendingDeletes = NULL; /* head of linked list */
static List *upperPendingDeletes = NIL; /* list of upper-xact lists */
/* /*
...@@ -308,7 +314,6 @@ smgrcreate(SMgrRelation reln, bool isTemp, bool isRedo) ...@@ -308,7 +314,6 @@ smgrcreate(SMgrRelation reln, bool isTemp, bool isRedo)
XLogRecData rdata; XLogRecData rdata;
xl_smgr_create xlrec; xl_smgr_create xlrec;
PendingRelDelete *pending; PendingRelDelete *pending;
MemoryContext old_cxt;
/* /*
* We may be using the target table space for the first time in this * We may be using the target table space for the first time in this
...@@ -349,17 +354,15 @@ smgrcreate(SMgrRelation reln, bool isTemp, bool isRedo) ...@@ -349,17 +354,15 @@ smgrcreate(SMgrRelation reln, bool isTemp, bool isRedo)
lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_CREATE | XLOG_NO_TRAN, &rdata); lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_CREATE | XLOG_NO_TRAN, &rdata);
/* Add the relation to the list of stuff to delete at abort */ /* Add the relation to the list of stuff to delete at abort */
old_cxt = MemoryContextSwitchTo(CurTransactionContext); pending = (PendingRelDelete *)
MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
pending = (PendingRelDelete *) palloc(sizeof(PendingRelDelete));
pending->relnode = reln->smgr_rnode; pending->relnode = reln->smgr_rnode;
pending->which = reln->smgr_which; pending->which = reln->smgr_which;
pending->isTemp = isTemp; pending->isTemp = isTemp;
pending->atCommit = false; /* delete if abort */ pending->atCommit = false; /* delete if abort */
pending->nestLevel = GetCurrentTransactionNestLevel();
pendingDeletes = lcons(pending, pendingDeletes); pending->next = pendingDeletes;
pendingDeletes = pending;
MemoryContextSwitchTo(old_cxt);
} }
/* /*
...@@ -374,20 +377,17 @@ void ...@@ -374,20 +377,17 @@ void
smgrscheduleunlink(SMgrRelation reln, bool isTemp) smgrscheduleunlink(SMgrRelation reln, bool isTemp)
{ {
PendingRelDelete *pending; PendingRelDelete *pending;
MemoryContext old_cxt;
/* Add the relation to the list of stuff to delete at commit */ /* Add the relation to the list of stuff to delete at commit */
old_cxt = MemoryContextSwitchTo(CurTransactionContext); pending = (PendingRelDelete *)
MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
pending = (PendingRelDelete *) palloc(sizeof(PendingRelDelete));
pending->relnode = reln->smgr_rnode; pending->relnode = reln->smgr_rnode;
pending->which = reln->smgr_which; pending->which = reln->smgr_which;
pending->isTemp = isTemp; pending->isTemp = isTemp;
pending->atCommit = true; /* delete if commit */ pending->atCommit = true; /* delete if commit */
pending->nestLevel = GetCurrentTransactionNestLevel();
pendingDeletes = lcons(pending, pendingDeletes); pending->next = pendingDeletes;
pendingDeletes = pending;
MemoryContextSwitchTo(old_cxt);
/* /*
* NOTE: if the relation was created in this transaction, it will now * NOTE: if the relation was created in this transaction, it will now
...@@ -647,25 +647,45 @@ smgrimmedsync(SMgrRelation reln) ...@@ -647,25 +647,45 @@ smgrimmedsync(SMgrRelation reln)
/* /*
* smgrDoPendingDeletes() -- Take care of relation deletes at end of xact. * smgrDoPendingDeletes() -- Take care of relation deletes at end of xact.
*
* This also runs when aborting a subxact; we want to clean up a failed
* subxact immediately.
*/ */
void void
smgrDoPendingDeletes(bool isCommit) smgrDoPendingDeletes(bool isCommit)
{ {
ListCell *p; int nestLevel = GetCurrentTransactionNestLevel();
PendingRelDelete *pending;
PendingRelDelete *prev;
PendingRelDelete *next;
foreach(p, pendingDeletes) prev = NULL;
for (pending = pendingDeletes; pending != NULL; pending = next)
{ {
PendingRelDelete *pending = lfirst(p); next = pending->next;
if (pending->nestLevel < nestLevel)
if (pending->atCommit == isCommit) {
smgr_internal_unlink(pending->relnode, /* outer-level entries should not be processed yet */
pending->which, prev = pending;
pending->isTemp, }
false); else
{
/* unlink list entry first, so we don't retry on failure */
if (prev)
prev->next = next;
else
pendingDeletes = next;
/* do deletion if called for */
if (pending->atCommit == isCommit)
smgr_internal_unlink(pending->relnode,
pending->which,
pending->isTemp,
false);
/* must explicitly free the list entry */
pfree(pending);
/* prev does not change */
}
} }
/* We needn't free the cells since they are in CurTransactionContext */
pendingDeletes = NIL;
} }
/* /*
...@@ -681,16 +701,15 @@ smgrDoPendingDeletes(bool isCommit) ...@@ -681,16 +701,15 @@ smgrDoPendingDeletes(bool isCommit)
int int
smgrGetPendingDeletes(bool forCommit, RelFileNode **ptr) smgrGetPendingDeletes(bool forCommit, RelFileNode **ptr)
{ {
int nestLevel = GetCurrentTransactionNestLevel();
int nrels; int nrels;
RelFileNode *rptr; RelFileNode *rptr;
ListCell *p; PendingRelDelete *pending;
nrels = 0; nrels = 0;
foreach(p, pendingDeletes) for (pending = pendingDeletes; pending != NULL; pending = pending->next)
{ {
PendingRelDelete *pending = lfirst(p); if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit)
if (pending->atCommit == forCommit)
nrels++; nrels++;
} }
if (nrels == 0) if (nrels == 0)
...@@ -700,50 +719,30 @@ smgrGetPendingDeletes(bool forCommit, RelFileNode **ptr) ...@@ -700,50 +719,30 @@ smgrGetPendingDeletes(bool forCommit, RelFileNode **ptr)
} }
rptr = (RelFileNode *) palloc(nrels * sizeof(RelFileNode)); rptr = (RelFileNode *) palloc(nrels * sizeof(RelFileNode));
*ptr = rptr; *ptr = rptr;
foreach(p, pendingDeletes) for (pending = pendingDeletes; pending != NULL; pending = pending->next)
{ {
PendingRelDelete *pending = lfirst(p); if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit)
if (pending->atCommit == forCommit)
*rptr++ = pending->relnode; *rptr++ = pending->relnode;
} }
return nrels; return nrels;
} }
/*
* AtSubStart_smgr() --- Take care of subtransaction start.
*
* Push empty state for the new subtransaction.
*/
void
AtSubStart_smgr(void)
{
MemoryContext old_cxt;
/* Keep the list-of-lists in TopTransactionContext for simplicity */
old_cxt = MemoryContextSwitchTo(TopTransactionContext);
upperPendingDeletes = lcons(pendingDeletes, upperPendingDeletes);
pendingDeletes = NIL;
MemoryContextSwitchTo(old_cxt);
}
/* /*
* AtSubCommit_smgr() --- Take care of subtransaction commit. * AtSubCommit_smgr() --- Take care of subtransaction commit.
* *
* Reassign all items in the pending deletes list to the parent transaction. * Reassign all items in the pending-deletes list to the parent transaction.
*/ */
void void
AtSubCommit_smgr(void) AtSubCommit_smgr(void)
{ {
List *parentPendingDeletes; int nestLevel = GetCurrentTransactionNestLevel();
PendingRelDelete *pending;
parentPendingDeletes = (List *) linitial(upperPendingDeletes);
upperPendingDeletes = list_delete_first(upperPendingDeletes);
pendingDeletes = list_concat(parentPendingDeletes, pendingDeletes); for (pending = pendingDeletes; pending != NULL; pending = pending->next)
{
if (pending->nestLevel >= nestLevel)
pending->nestLevel = nestLevel - 1;
}
} }
/* /*
...@@ -757,10 +756,6 @@ void ...@@ -757,10 +756,6 @@ void
AtSubAbort_smgr(void) AtSubAbort_smgr(void)
{ {
smgrDoPendingDeletes(false); smgrDoPendingDeletes(false);
/* Must pop the stack, too */
pendingDeletes = (List *) linitial(upperPendingDeletes);
upperPendingDeletes = list_delete_first(upperPendingDeletes);
} }
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.423 2004/07/11 00:18:44 momjian Exp $ * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.424 2004/07/17 03:29:00 tgl Exp $
* *
* NOTES * NOTES
* this is the "main" module of the postgres backend and * this is the "main" module of the postgres backend and
...@@ -2796,6 +2796,12 @@ PostgresMain(int argc, char *argv[], const char *username) ...@@ -2796,6 +2796,12 @@ PostgresMain(int argc, char *argv[], const char *username)
DisableCatchupInterrupt(); DisableCatchupInterrupt();
debug_query_string = NULL; debug_query_string = NULL;
/*
* If there's an active portal, mark it as failed
*/
if (ActivePortal)
ActivePortal->status = PORTAL_FAILED;
/* /*
* Make sure we are in a valid memory context during recovery. * Make sure we are in a valid memory context during recovery.
* *
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/pquery.c,v 1.80 2004/06/05 19:48:08 tgl Exp $ * $PostgreSQL: pgsql/src/backend/tcop/pquery.c,v 1.81 2004/07/17 03:29:00 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -235,12 +235,25 @@ ChoosePortalStrategy(List *parseTrees) ...@@ -235,12 +235,25 @@ ChoosePortalStrategy(List *parseTrees)
void void
PortalStart(Portal portal, ParamListInfo params) PortalStart(Portal portal, ParamListInfo params)
{ {
Portal saveActivePortal;
ResourceOwner saveResourceOwner;
MemoryContext savePortalContext;
MemoryContext oldContext; MemoryContext oldContext;
QueryDesc *queryDesc; QueryDesc *queryDesc;
AssertArg(PortalIsValid(portal)); AssertArg(PortalIsValid(portal));
AssertState(portal->queryContext != NULL); /* query defined? */ AssertState(portal->queryContext != NULL); /* query defined? */
AssertState(!portal->portalReady); /* else extra PortalStart */ AssertState(portal->status == PORTAL_NEW); /* else extra PortalStart */
/*
* Set global portal context pointers. (Should we set QueryContext?)
*/
saveActivePortal = ActivePortal;
ActivePortal = portal;
saveResourceOwner = CurrentResourceOwner;
CurrentResourceOwner = portal->resowner;
savePortalContext = PortalContext;
PortalContext = PortalGetHeapMemory(portal);
oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal)); oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
...@@ -324,7 +337,11 @@ PortalStart(Portal portal, ParamListInfo params) ...@@ -324,7 +337,11 @@ PortalStart(Portal portal, ParamListInfo params)
MemoryContextSwitchTo(oldContext); MemoryContextSwitchTo(oldContext);
portal->portalReady = true; ActivePortal = saveActivePortal;
CurrentResourceOwner = saveResourceOwner;
PortalContext = savePortalContext;
portal->status = PORTAL_READY;
} }
/* /*
...@@ -403,12 +420,12 @@ PortalRun(Portal portal, long count, ...@@ -403,12 +420,12 @@ PortalRun(Portal portal, long count,
{ {
bool result; bool result;
Portal saveActivePortal; Portal saveActivePortal;
ResourceOwner saveResourceOwner;
MemoryContext savePortalContext; MemoryContext savePortalContext;
MemoryContext saveQueryContext; MemoryContext saveQueryContext;
MemoryContext oldContext; MemoryContext oldContext;
AssertArg(PortalIsValid(portal)); AssertArg(PortalIsValid(portal));
AssertState(portal->portalReady); /* else no PortalStart */
/* Initialize completion tag to empty string */ /* Initialize completion tag to empty string */
if (completionTag) if (completionTag)
...@@ -425,21 +442,19 @@ PortalRun(Portal portal, long count, ...@@ -425,21 +442,19 @@ PortalRun(Portal portal, long count,
/* /*
* Check for improper portal use, and mark portal active. * Check for improper portal use, and mark portal active.
*/ */
if (portal->portalDone) if (portal->status != PORTAL_READY)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("portal \"%s\" cannot be run anymore", portal->name))); errmsg("portal \"%s\" cannot be run", portal->name)));
if (portal->portalActive) portal->status = PORTAL_ACTIVE;
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("portal \"%s\" already active", portal->name)));
portal->portalActive = true;
/* /*
* Set global portal context pointers. * Set global portal context pointers.
*/ */
saveActivePortal = ActivePortal; saveActivePortal = ActivePortal;
ActivePortal = portal; ActivePortal = portal;
saveResourceOwner = CurrentResourceOwner;
CurrentResourceOwner = portal->resowner;
savePortalContext = PortalContext; savePortalContext = PortalContext;
PortalContext = PortalGetHeapMemory(portal); PortalContext = PortalGetHeapMemory(portal);
saveQueryContext = QueryContext; saveQueryContext = QueryContext;
...@@ -455,6 +470,9 @@ PortalRun(Portal portal, long count, ...@@ -455,6 +470,9 @@ PortalRun(Portal portal, long count,
if (completionTag && portal->commandTag) if (completionTag && portal->commandTag)
strcpy(completionTag, portal->commandTag); strcpy(completionTag, portal->commandTag);
/* Mark portal not active */
portal->status = PORTAL_READY;
/* /*
* Since it's a forward fetch, say DONE iff atEnd is now true. * Since it's a forward fetch, say DONE iff atEnd is now true.
*/ */
...@@ -491,6 +509,9 @@ PortalRun(Portal portal, long count, ...@@ -491,6 +509,9 @@ PortalRun(Portal portal, long count,
if (completionTag && portal->commandTag) if (completionTag && portal->commandTag)
strcpy(completionTag, portal->commandTag); strcpy(completionTag, portal->commandTag);
/* Mark portal not active */
portal->status = PORTAL_READY;
/* /*
* Since it's a forward fetch, say DONE iff atEnd is now true. * Since it's a forward fetch, say DONE iff atEnd is now true.
*/ */
...@@ -499,6 +520,10 @@ PortalRun(Portal portal, long count, ...@@ -499,6 +520,10 @@ PortalRun(Portal portal, long count,
case PORTAL_MULTI_QUERY: case PORTAL_MULTI_QUERY:
PortalRunMulti(portal, dest, altdest, completionTag); PortalRunMulti(portal, dest, altdest, completionTag);
/* Prevent portal's commands from being re-executed */
portal->status = PORTAL_DONE;
/* Always complete at end of RunMulti */ /* Always complete at end of RunMulti */
result = true; result = true;
break; break;
...@@ -512,10 +537,8 @@ PortalRun(Portal portal, long count, ...@@ -512,10 +537,8 @@ PortalRun(Portal portal, long count,
MemoryContextSwitchTo(oldContext); MemoryContextSwitchTo(oldContext);
/* Mark portal not active */
portal->portalActive = false;
ActivePortal = saveActivePortal; ActivePortal = saveActivePortal;
CurrentResourceOwner = saveResourceOwner;
PortalContext = savePortalContext; PortalContext = savePortalContext;
QueryContext = saveQueryContext; QueryContext = saveQueryContext;
...@@ -914,9 +937,6 @@ PortalRunMulti(Portal portal, ...@@ -914,9 +937,6 @@ PortalRunMulti(Portal portal,
else if (strcmp(completionTag, "DELETE") == 0) else if (strcmp(completionTag, "DELETE") == 0)
strcpy(completionTag, "DELETE 0"); strcpy(completionTag, "DELETE 0");
} }
/* Prevent portal's commands from being re-executed */
portal->portalDone = true;
} }
/* /*
...@@ -933,31 +953,29 @@ PortalRunFetch(Portal portal, ...@@ -933,31 +953,29 @@ PortalRunFetch(Portal portal,
{ {
long result; long result;
Portal saveActivePortal; Portal saveActivePortal;
ResourceOwner saveResourceOwner;
MemoryContext savePortalContext; MemoryContext savePortalContext;
MemoryContext saveQueryContext; MemoryContext saveQueryContext;
MemoryContext oldContext; MemoryContext oldContext;
AssertArg(PortalIsValid(portal)); AssertArg(PortalIsValid(portal));
AssertState(portal->portalReady); /* else no PortalStart */
/* /*
* Check for improper portal use, and mark portal active. * Check for improper portal use, and mark portal active.
*/ */
if (portal->portalDone) if (portal->status != PORTAL_READY)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("portal \"%s\" cannot be run anymore", portal->name)));
if (portal->portalActive)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("portal \"%s\" already active", portal->name))); errmsg("portal \"%s\" cannot be run", portal->name)));
portal->portalActive = true; portal->status = PORTAL_ACTIVE;
/* /*
* Set global portal context pointers. * Set global portal context pointers.
*/ */
saveActivePortal = ActivePortal; saveActivePortal = ActivePortal;
ActivePortal = portal; ActivePortal = portal;
saveResourceOwner = CurrentResourceOwner;
CurrentResourceOwner = portal->resowner;
savePortalContext = PortalContext; savePortalContext = PortalContext;
PortalContext = PortalGetHeapMemory(portal); PortalContext = PortalGetHeapMemory(portal);
saveQueryContext = QueryContext; saveQueryContext = QueryContext;
...@@ -980,9 +998,10 @@ PortalRunFetch(Portal portal, ...@@ -980,9 +998,10 @@ PortalRunFetch(Portal portal,
MemoryContextSwitchTo(oldContext); MemoryContextSwitchTo(oldContext);
/* Mark portal not active */ /* Mark portal not active */
portal->portalActive = false; portal->status = PORTAL_READY;
ActivePortal = saveActivePortal; ActivePortal = saveActivePortal;
CurrentResourceOwner = saveResourceOwner;
PortalContext = savePortalContext; PortalContext = savePortalContext;
QueryContext = saveQueryContext; QueryContext = saveQueryContext;
......
# #
# Makefile for utils # Makefile for utils
# #
# $PostgreSQL: pgsql/src/backend/utils/Makefile,v 1.22 2004/01/04 05:57:21 tgl Exp $ # $PostgreSQL: pgsql/src/backend/utils/Makefile,v 1.23 2004/07/17 03:29:15 tgl Exp $
# #
subdir = src/backend/utils/ subdir = src/backend/utils/
top_builddir = ../../.. top_builddir = ../../..
include $(top_builddir)/src/Makefile.global include $(top_builddir)/src/Makefile.global
SUBDIRS := adt cache error fmgr hash init misc mmgr sort time mb SUBDIRS := adt cache error fmgr hash init mb misc mmgr resowner sort time
SUBDIROBJS := $(SUBDIRS:%=%/SUBSYS.o) SUBDIROBJS := $(SUBDIRS:%=%/SUBSYS.o)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#-------------------------------------------------------------------------
#
# Makefile--
# Makefile for utils/resowner
#
# IDENTIFICATION
# $PostgreSQL: pgsql/src/backend/utils/resowner/Makefile,v 1.1 2004/07/17 03:30:10 tgl Exp $
#
#-------------------------------------------------------------------------
subdir = src/backend/utils/resowner
top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global
OBJS = resowner.o
all: SUBSYS.o
SUBSYS.o: $(OBJS)
$(LD) $(LDREL) $(LDOUT) SUBSYS.o $(OBJS)
depend dep:
$(CC) -MM $(CFLAGS) *.c >depend
clean:
rm -f SUBSYS.o $(OBJS)
ifeq (depend,$(wildcard depend))
include depend
endif
$PostgreSQL: pgsql/src/backend/utils/resowner/README,v 1.1 2004/07/17 03:30:10 tgl Exp $
Notes about resource owners
---------------------------
ResourceOwner objects are a concept invented to simplify management of
query-related resources, such as buffer pins and table locks. These
resources need to be tracked in a reliable way to ensure that they will
be released at query end, even if the query fails due to an error.
Rather than expecting the entire executor to have bulletproof data
structures, we localize the tracking of such resources into a single
module.
The design of the ResourceOwner API is modeled on our MemoryContext API,
which has proven very flexible and successful in preventing memory leaks.
In particular we allow ResourceOwners to have child ResourceOwner objects
so that there can be forests of the things; releasing a parent
ResourceOwner acts on all its direct and indirect children as well.
(It is tempting to consider unifying ResourceOwners and MemoryContexts
into a single object type, but their usage patterns are sufficiently
different that this is probably not really a helpful thing to do.)
We create a ResourceOwner for each transaction or subtransaction as
well as one for each Portal. During execution of a Portal, the global
variable CurrentResourceOwner points to the Portal's ResourceOwner.
This causes operations such as ReadBuffer and LockAcquire to record
ownership of the acquired resources in that ResourceOwner object.
When a Portal is closed, any remaining resources (typically only locks)
become the responsibility of the current transaction. This is represented
by making the Portal's ResourceOwner a child of the current transaction's
ResourceOwner. Similarly, subtransaction ResourceOwners are children of
their immediate parent.
We need transaction-related ResourceOwners as well as Portal-related ones
because transactions may initiate operations that require resources (such
as query parsing) when no associated Portal exists yet.
API overview
------------
The basic operations on a ResourceOwner are:
* create a ResourceOwner
* associate or deassociate some resource with a ResourceOwner
* release a ResourceOwner's assets (free all owned resources, but not the
owner object itself)
* delete a ResourceOwner (including child owner objects); all resources
must have been released beforehand
Currently, ResourceOwners contain direct support for recording ownership
of buffer pins, lmgr locks, and catcache and relcache references. Other
objects can be associated with a ResourceOwner by recording the address of
the owning ResourceOwner in such an object. There is an API for other
modules to get control during ResourceOwner release, so that they can scan
their own data structures to find the objects that need to be deleted.
Whenever we are inside a transaction, the global variable
CurrentResourceOwner shows which resource owner should be assigned
ownership of acquired resources. Note however that CurrentResourceOwner
is NULL when not inside any transaction (or when inside a failed
transaction). In this case it is not valid to acquire query-lifespan
resources.
When unpinning a buffer or releasing a lock or cache reference,
CurrentResourceOwner must point to the same resource owner that was current
when the buffer, lock, or cache reference was acquired. It would be possible
to relax this restriction given additional bookkeeping effort, but at present
there seems no need.
This diff is collapsed.
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/access/gistscan.h,v 1.23 2004/07/01 00:51:38 tgl Exp $ * $PostgreSQL: pgsql/src/include/access/gistscan.h,v 1.24 2004/07/17 03:30:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -22,7 +22,6 @@ extern Datum gistmarkpos(PG_FUNCTION_ARGS); ...@@ -22,7 +22,6 @@ extern Datum gistmarkpos(PG_FUNCTION_ARGS);
extern Datum gistrestrpos(PG_FUNCTION_ARGS); extern Datum gistrestrpos(PG_FUNCTION_ARGS);
extern Datum gistendscan(PG_FUNCTION_ARGS); extern Datum gistendscan(PG_FUNCTION_ARGS);
extern void gistadjscans(Relation r, int op, BlockNumber blkno, OffsetNumber offnum); extern void gistadjscans(Relation r, int op, BlockNumber blkno, OffsetNumber offnum);
extern void AtEOXact_gist(void); extern void ReleaseResources_gist(void);
extern void AtEOSubXact_gist(TransactionId childXid);
#endif /* GISTSCAN_H */ #endif /* GISTSCAN_H */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/access/hash.h,v 1.55 2004/07/01 00:51:38 tgl Exp $ * $PostgreSQL: pgsql/src/include/access/hash.h,v 1.56 2004/07/17 03:30:38 tgl Exp $
* *
* NOTES * NOTES
* modeled after Margo Seltzer's hash implementation for unix. * modeled after Margo Seltzer's hash implementation for unix.
...@@ -292,8 +292,7 @@ extern void _hash_expandtable(Relation rel, Buffer metabuf); ...@@ -292,8 +292,7 @@ extern void _hash_expandtable(Relation rel, Buffer metabuf);
extern void _hash_regscan(IndexScanDesc scan); extern void _hash_regscan(IndexScanDesc scan);
extern void _hash_dropscan(IndexScanDesc scan); extern void _hash_dropscan(IndexScanDesc scan);
extern bool _hash_has_active_scan(Relation rel, Bucket bucket); extern bool _hash_has_active_scan(Relation rel, Bucket bucket);
extern void AtEOXact_hash(void); extern void ReleaseResources_hash(void);
extern void AtEOSubXact_hash(TransactionId childXid);
/* hashsearch.c */ /* hashsearch.c */
extern bool _hash_next(IndexScanDesc scan, ScanDirection dir); extern bool _hash_next(IndexScanDesc scan, ScanDirection dir);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/access/nbtree.h,v 1.79 2004/07/11 18:01:45 tgl Exp $ * $PostgreSQL: pgsql/src/include/access/nbtree.h,v 1.80 2004/07/17 03:30:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -402,8 +402,6 @@ typedef BTScanOpaqueData *BTScanOpaque; ...@@ -402,8 +402,6 @@ typedef BTScanOpaqueData *BTScanOpaque;
/* /*
* prototypes for functions in nbtree.c (external entry points for btree) * prototypes for functions in nbtree.c (external entry points for btree)
*/ */
extern void AtEOXact_nbtree(void);
extern Datum btbuild(PG_FUNCTION_ARGS); extern Datum btbuild(PG_FUNCTION_ARGS);
extern Datum btinsert(PG_FUNCTION_ARGS); extern Datum btinsert(PG_FUNCTION_ARGS);
extern Datum btgettuple(PG_FUNCTION_ARGS); extern Datum btgettuple(PG_FUNCTION_ARGS);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/access/rtree.h,v 1.33 2004/07/01 00:51:38 tgl Exp $ * $PostgreSQL: pgsql/src/include/access/rtree.h,v 1.34 2004/07/17 03:30:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -129,8 +129,7 @@ extern void rtree_desc(char *buf, uint8 xl_info, char *rec); ...@@ -129,8 +129,7 @@ extern void rtree_desc(char *buf, uint8 xl_info, char *rec);
/* rtscan.c */ /* rtscan.c */
extern void rtadjscans(Relation r, int op, BlockNumber blkno, extern void rtadjscans(Relation r, int op, BlockNumber blkno,
OffsetNumber offnum); OffsetNumber offnum);
extern void AtEOXact_rtree(void); extern void ReleaseResources_rtree(void);
extern void AtEOSubXact_rtree(TransactionId childXid);
/* rtstrat.c */ /* rtstrat.c */
extern StrategyNumber RTMapToInternalOperator(StrategyNumber strat); extern StrategyNumber RTMapToInternalOperator(StrategyNumber strat);
......
...@@ -7,17 +7,16 @@ ...@@ -7,17 +7,16 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/access/xact.h,v 1.64 2004/07/01 00:51:38 tgl Exp $ * $PostgreSQL: pgsql/src/include/access/xact.h,v 1.65 2004/07/17 03:30:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#ifndef XACT_H #ifndef XACT_H
#define XACT_H #define XACT_H
#include "access/transam.h"
#include "access/xlog.h" #include "access/xlog.h"
#include "utils/nabstime.h" #include "utils/nabstime.h"
#include "utils/timestamp.h"
/* /*
* Xact isolation levels * Xact isolation levels
...@@ -40,63 +39,11 @@ extern int XactIsoLevel; ...@@ -40,63 +39,11 @@ extern int XactIsoLevel;
extern bool DefaultXactReadOnly; extern bool DefaultXactReadOnly;
extern bool XactReadOnly; extern bool XactReadOnly;
/*
* transaction states - transaction state from server perspective
*/
typedef enum TransState
{
TRANS_DEFAULT,
TRANS_START,
TRANS_INPROGRESS,
TRANS_COMMIT,
TRANS_ABORT
} TransState;
/*
* transaction block states - transaction state of client queries
*/
typedef enum TBlockState
{
TBLOCK_DEFAULT,
TBLOCK_STARTED,
TBLOCK_BEGIN,
TBLOCK_INPROGRESS,
TBLOCK_END,
TBLOCK_ABORT,
TBLOCK_ENDABORT,
TBLOCK_SUBBEGIN,
TBLOCK_SUBBEGINABORT,
TBLOCK_SUBINPROGRESS,
TBLOCK_SUBEND,
TBLOCK_SUBABORT,
TBLOCK_SUBENDABORT_OK,
TBLOCK_SUBENDABORT_ERROR
} TBlockState;
/* /*
* end-of-transaction cleanup callbacks for dynamically loaded modules * end-of-transaction cleanup callbacks for dynamically loaded modules
*/ */
typedef void (*EOXactCallback) (bool isCommit, void *arg); typedef void (*EOXactCallback) (bool isCommit, void *arg);
/*
* transaction state structure
*/
typedef struct TransactionStateData
{
TransactionId transactionIdData; /* my XID */
CommandId commandId; /* current CID */
TransState state; /* low-level state */
TBlockState blockState; /* high-level state */
int nestingLevel; /* nest depth */
MemoryContext curTransactionContext; /* my xact-lifetime context */
List *childXids; /* subcommitted child XIDs */
AclId currentUser; /* subxact start current_user */
struct TransactionStateData *parent; /* back link to parent */
} TransactionStateData;
typedef TransactionStateData *TransactionState;
/* ---------------- /* ----------------
* transaction-related XLOG entries * transaction-related XLOG entries
...@@ -168,7 +115,7 @@ extern void UnregisterEOXactCallback(EOXactCallback callback, void *arg); ...@@ -168,7 +115,7 @@ extern void UnregisterEOXactCallback(EOXactCallback callback, void *arg);
extern void RecordTransactionCommit(void); extern void RecordTransactionCommit(void);
extern int xactGetCommittedChildren(TransactionId **ptr, bool metoo); extern int xactGetCommittedChildren(TransactionId **ptr);
extern void XactPushRollback(void (*func) (void *), void *data); extern void XactPushRollback(void (*func) (void *), void *data);
extern void XactPopRollback(void); extern void XactPopRollback(void);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/commands/portalcmds.h,v 1.14 2003/11/29 22:40:59 pgsql Exp $ * $PostgreSQL: pgsql/src/include/commands/portalcmds.h,v 1.15 2004/07/17 03:30:56 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -24,7 +24,7 @@ extern void PerformPortalFetch(FetchStmt *stmt, DestReceiver *dest, ...@@ -24,7 +24,7 @@ extern void PerformPortalFetch(FetchStmt *stmt, DestReceiver *dest,
extern void PerformPortalClose(const char *name); extern void PerformPortalClose(const char *name);
extern void PortalCleanup(Portal portal, bool isError); extern void PortalCleanup(Portal portal);
extern void PersistHoldablePortal(Portal portal); extern void PersistHoldablePortal(Portal portal);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/storage/bufmgr.h,v 1.83 2004/07/01 00:51:43 tgl Exp $ * $PostgreSQL: pgsql/src/include/storage/bufmgr.h,v 1.84 2004/07/17 03:31:26 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -92,31 +92,6 @@ extern int32 *LocalRefCount; ...@@ -92,31 +92,6 @@ extern int32 *LocalRefCount;
) \ ) \
) )
/*
* IncrBufferRefCount
* Increment the pin count on a buffer that we have *already* pinned
* at least once.
*
* This macro cannot be used on a buffer we do not have pinned,
* because it doesn't change the shared buffer state. Therefore the
* Assert checks are for refcount > 0. Someone got this wrong once...
*/
#define IncrBufferRefCount(buffer) \
( \
BufferIsLocal(buffer) ? \
( \
(void) AssertMacro((buffer) >= -NLocBuffer), \
(void) AssertMacro(LocalRefCount[-(buffer) - 1] > 0), \
(void) LocalRefCount[-(buffer) - 1]++ \
) \
: \
( \
(void) AssertMacro(!BAD_BUFFER_ID(buffer)), \
(void) AssertMacro(PrivateRefCount[(buffer) - 1] > 0), \
(void) PrivateRefCount[(buffer) - 1]++ \
) \
)
/* /*
* BufferGetBlock * BufferGetBlock
* Returns a reference to a disk page image associated with a buffer. * Returns a reference to a disk page image associated with a buffer.
...@@ -138,6 +113,7 @@ extern int32 *LocalRefCount; ...@@ -138,6 +113,7 @@ extern int32 *LocalRefCount;
*/ */
extern Buffer ReadBuffer(Relation reln, BlockNumber blockNum); extern Buffer ReadBuffer(Relation reln, BlockNumber blockNum);
extern void ReleaseBuffer(Buffer buffer); extern void ReleaseBuffer(Buffer buffer);
extern void IncrBufferRefCount(Buffer buffer);
extern void WriteBuffer(Buffer buffer); extern void WriteBuffer(Buffer buffer);
extern void WriteNoReleaseBuffer(Buffer buffer); extern void WriteNoReleaseBuffer(Buffer buffer);
extern Buffer ReleaseAndReadBuffer(Buffer buffer, Relation relation, extern Buffer ReleaseAndReadBuffer(Buffer buffer, Relation relation,
...@@ -148,8 +124,6 @@ extern void InitBufferPoolAccess(void); ...@@ -148,8 +124,6 @@ extern void InitBufferPoolAccess(void);
extern char *ShowBufferUsage(void); extern char *ShowBufferUsage(void);
extern void ResetBufferUsage(void); extern void ResetBufferUsage(void);
extern void AtEOXact_Buffers(bool isCommit); extern void AtEOXact_Buffers(bool isCommit);
extern void AtSubStart_Buffers(void);
extern void AtEOSubXact_Buffers(bool isCommit);
extern void FlushBufferPool(void); extern void FlushBufferPool(void);
extern BlockNumber BufferGetBlockNumber(Buffer buffer); extern BlockNumber BufferGetBlockNumber(Buffer buffer);
extern BlockNumber RelationGetNumberOfBlocks(Relation relation); extern BlockNumber RelationGetNumberOfBlocks(Relation relation);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/storage/lock.h,v 1.78 2004/07/01 00:51:43 tgl Exp $ * $PostgreSQL: pgsql/src/include/storage/lock.h,v 1.79 2004/07/17 03:31:26 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -26,14 +26,6 @@ typedef struct PROC_QUEUE ...@@ -26,14 +26,6 @@ typedef struct PROC_QUEUE
int size; /* number of entries in list */ int size; /* number of entries in list */
} PROC_QUEUE; } PROC_QUEUE;
/* Release options for LockReleaseAll */
typedef enum
{
ReleaseAll, /* All my locks */
ReleaseAllExceptSession, /* All except session locks (Xid = 0) */
ReleaseGivenXids /* Only locks with Xids in given array */
} LockReleaseWhich;
/* struct PGPROC is declared in storage/proc.h, but must forward-reference it */ /* struct PGPROC is declared in storage/proc.h, but must forward-reference it */
typedef struct PGPROC PGPROC; typedef struct PGPROC PGPROC;
...@@ -248,7 +240,7 @@ extern bool LockAcquire(LOCKMETHODID lockmethodid, LOCKTAG *locktag, ...@@ -248,7 +240,7 @@ extern bool LockAcquire(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
extern bool LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag, extern bool LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
TransactionId xid, LOCKMODE lockmode); TransactionId xid, LOCKMODE lockmode);
extern bool LockReleaseAll(LOCKMETHODID lockmethodid, PGPROC *proc, extern bool LockReleaseAll(LOCKMETHODID lockmethodid, PGPROC *proc,
LockReleaseWhich which, int nxids, TransactionId *xids); bool allxids);
extern int LockCheckConflicts(LockMethod lockMethodTable, extern int LockCheckConflicts(LockMethod lockMethodTable,
LOCKMODE lockmode, LOCKMODE lockmode,
LOCK *lock, PROCLOCK *proclock, PGPROC *proc, LOCK *lock, PROCLOCK *proclock, PGPROC *proc,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/storage/proc.h,v 1.68 2004/07/01 00:51:43 tgl Exp $ * $PostgreSQL: pgsql/src/include/storage/proc.h,v 1.69 2004/07/17 03:31:26 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -34,7 +34,7 @@ struct PGPROC ...@@ -34,7 +34,7 @@ struct PGPROC
SHM_QUEUE links; /* list link if process is in a list */ SHM_QUEUE links; /* list link if process is in a list */
PGSemaphoreData sem; /* ONE semaphore to sleep on */ PGSemaphoreData sem; /* ONE semaphore to sleep on */
int errType; /* STATUS_OK or STATUS_ERROR after wakeup */ int waitStatus; /* STATUS_OK or STATUS_ERROR after wakeup */
TransactionId xid; /* transaction currently being executed by TransactionId xid; /* transaction currently being executed by
* this proc */ * this proc */
...@@ -103,13 +103,12 @@ extern int ProcGlobalSemas(int maxBackends); ...@@ -103,13 +103,12 @@ extern int ProcGlobalSemas(int maxBackends);
extern void InitProcGlobal(int maxBackends); extern void InitProcGlobal(int maxBackends);
extern void InitProcess(void); extern void InitProcess(void);
extern void InitDummyProcess(int proctype); extern void InitDummyProcess(int proctype);
extern void ProcReleaseLocks(LockReleaseWhich which, extern void ProcReleaseLocks(bool isCommit);
int nxids, TransactionId *xids);
extern void ProcQueueInit(PROC_QUEUE *queue); extern void ProcQueueInit(PROC_QUEUE *queue);
extern int ProcSleep(LockMethod lockMethodTable, LOCKMODE lockmode, extern int ProcSleep(LockMethod lockMethodTable, LOCKMODE lockmode,
LOCK *lock, PROCLOCK *proclock); LOCK *lock, PROCLOCK *proclock);
extern PGPROC *ProcWakeup(PGPROC *proc, int errType); extern PGPROC *ProcWakeup(PGPROC *proc, int waitStatus);
extern void ProcLockWakeup(LockMethod lockMethodTable, LOCK *lock); extern void ProcLockWakeup(LockMethod lockMethodTable, LOCK *lock);
extern bool LockWaitCancel(void); extern bool LockWaitCancel(void);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/storage/smgr.h,v 1.45 2004/07/01 00:51:43 tgl Exp $ * $PostgreSQL: pgsql/src/include/storage/smgr.h,v 1.46 2004/07/17 03:31:26 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -66,7 +66,6 @@ extern BlockNumber smgrtruncate(SMgrRelation reln, BlockNumber nblocks, ...@@ -66,7 +66,6 @@ extern BlockNumber smgrtruncate(SMgrRelation reln, BlockNumber nblocks,
extern void smgrimmedsync(SMgrRelation reln); extern void smgrimmedsync(SMgrRelation reln);
extern void smgrDoPendingDeletes(bool isCommit); extern void smgrDoPendingDeletes(bool isCommit);
extern int smgrGetPendingDeletes(bool forCommit, RelFileNode **ptr); extern int smgrGetPendingDeletes(bool forCommit, RelFileNode **ptr);
extern void AtSubStart_smgr(void);
extern void AtSubCommit_smgr(void); extern void AtSubCommit_smgr(void);
extern void AtSubAbort_smgr(void); extern void AtSubAbort_smgr(void);
extern void smgrcommit(void); extern void smgrcommit(void);
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/utils/catcache.h,v 1.49 2004/07/01 00:51:44 tgl Exp $ * $PostgreSQL: pgsql/src/include/utils/catcache.h,v 1.50 2004/07/17 03:31:47 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -101,9 +101,6 @@ typedef struct catctup ...@@ -101,9 +101,6 @@ typedef struct catctup
* and negative entries is identical. * and negative entries is identical.
*/ */
int refcount; /* number of active references */ int refcount; /* number of active references */
int *prev_refcount; /* refcounts for upper subtransactions */
int numpushes; /* number of used refcounts in the array */
int numalloc; /* allocated size of array */
bool dead; /* dead but not yet removed? */ bool dead; /* dead but not yet removed? */
bool negative; /* negative cache entry? */ bool negative; /* negative cache entry? */
uint32 hash_value; /* hash value for this tuple's keys */ uint32 hash_value; /* hash value for this tuple's keys */
...@@ -142,9 +139,6 @@ typedef struct catclist ...@@ -142,9 +139,6 @@ typedef struct catclist
*/ */
Dlelem cache_elem; /* list member of per-catcache list */ Dlelem cache_elem; /* list member of per-catcache list */
int refcount; /* number of active references */ int refcount; /* number of active references */
int *prev_refcount; /* refcounts for upper subtransactions */
int numpushes; /* number of used refcounts in the array */
int numalloc; /* allocated size of array */
bool dead; /* dead but not yet removed? */ bool dead; /* dead but not yet removed? */
bool ordered; /* members listed in index order? */ bool ordered; /* members listed in index order? */
short nkeys; /* number of lookup keys specified */ short nkeys; /* number of lookup keys specified */
...@@ -169,8 +163,6 @@ extern DLLIMPORT MemoryContext CacheMemoryContext; ...@@ -169,8 +163,6 @@ extern DLLIMPORT MemoryContext CacheMemoryContext;
extern void CreateCacheMemoryContext(void); extern void CreateCacheMemoryContext(void);
extern void AtEOXact_CatCache(bool isCommit); extern void AtEOXact_CatCache(bool isCommit);
extern void AtSubStart_CatCache(void);
extern void AtEOSubXact_CatCache(bool isCommit);
extern CatCache *InitCatCache(int id, const char *relname, const char *indname, extern CatCache *InitCatCache(int id, const char *relname, const char *indname,
int reloidattr, int reloidattr,
......
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/utils/portal.h,v 1.49 2004/07/01 00:51:44 tgl Exp $ * $PostgreSQL: pgsql/src/include/utils/portal.h,v 1.50 2004/07/17 03:31:47 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
#include "executor/execdesc.h" #include "executor/execdesc.h"
#include "nodes/memnodes.h" #include "nodes/memnodes.h"
#include "utils/resowner.h"
#include "utils/tuplestore.h" #include "utils/tuplestore.h"
...@@ -79,6 +80,20 @@ typedef enum PortalStrategy ...@@ -79,6 +80,20 @@ typedef enum PortalStrategy
PORTAL_MULTI_QUERY PORTAL_MULTI_QUERY
} PortalStrategy; } PortalStrategy;
/*
* A portal is always in one of these states. It is possible to transit
* from ACTIVE back to READY if the query is not run to completion;
* otherwise we never back up in status.
*/
typedef enum PortalStatus
{
PORTAL_NEW, /* in process of creation */
PORTAL_READY, /* PortalStart complete, can run it */
PORTAL_ACTIVE, /* portal is running (can't delete it) */
PORTAL_DONE, /* portal is finished (don't re-run it) */
PORTAL_FAILED /* portal got error (can't re-run it) */
} PortalStatus;
/* /*
* Note: typedef Portal is declared in tcop/dest.h as * Note: typedef Portal is declared in tcop/dest.h as
* typedef struct PortalData *Portal; * typedef struct PortalData *Portal;
...@@ -89,7 +104,8 @@ typedef struct PortalData ...@@ -89,7 +104,8 @@ typedef struct PortalData
/* Bookkeeping data */ /* Bookkeeping data */
const char *name; /* portal's name */ const char *name; /* portal's name */
MemoryContext heap; /* subsidiary memory for portal */ MemoryContext heap; /* subsidiary memory for portal */
void (*cleanup) (Portal portal, bool isError); /* cleanup hook */ ResourceOwner resowner; /* resources owned by portal */
void (*cleanup) (Portal portal); /* cleanup hook */
TransactionId createXact; /* the xid of the creating xact */ TransactionId createXact; /* the xid of the creating xact */
/* The query or queries the portal will execute */ /* The query or queries the portal will execute */
...@@ -113,10 +129,8 @@ typedef struct PortalData ...@@ -113,10 +129,8 @@ typedef struct PortalData
int cursorOptions; /* DECLARE CURSOR option bits */ int cursorOptions; /* DECLARE CURSOR option bits */
/* Status data */ /* Status data */
bool portalReady; /* PortalStart complete? */ PortalStatus status; /* see above */
bool portalUtilReady; /* PortalRunUtility complete? */ bool portalUtilReady; /* PortalRunUtility complete? */
bool portalActive; /* portal is running (can't delete it) */
bool portalDone; /* portal is finished (don't re-run it) */
/* If not NULL, Executor is active; call ExecutorEnd eventually: */ /* If not NULL, Executor is active; call ExecutorEnd eventually: */
QueryDesc *queryDesc; /* info needed for executor invocation */ QueryDesc *queryDesc; /* info needed for executor invocation */
...@@ -167,12 +181,14 @@ extern void EnablePortalManager(void); ...@@ -167,12 +181,14 @@ extern void EnablePortalManager(void);
extern void AtCommit_Portals(void); extern void AtCommit_Portals(void);
extern void AtAbort_Portals(void); extern void AtAbort_Portals(void);
extern void AtCleanup_Portals(void); extern void AtCleanup_Portals(void);
extern void AtSubCommit_Portals(TransactionId parentXid); extern void AtSubCommit_Portals(TransactionId parentXid,
extern void AtSubAbort_Portals(void); ResourceOwner parentXactOwner);
extern void AtSubAbort_Portals(TransactionId parentXid,
ResourceOwner parentXactOwner);
extern void AtSubCleanup_Portals(void); extern void AtSubCleanup_Portals(void);
extern Portal CreatePortal(const char *name, bool allowDup, bool dupSilent); extern Portal CreatePortal(const char *name, bool allowDup, bool dupSilent);
extern Portal CreateNewPortal(void); extern Portal CreateNewPortal(void);
extern void PortalDrop(Portal portal, bool isError); extern void PortalDrop(Portal portal, bool isTopCommit);
extern void DropDependentPortals(MemoryContext queryContext); extern void DropDependentPortals(MemoryContext queryContext);
extern Portal GetPortalByName(const char *name); extern Portal GetPortalByName(const char *name);
extern void PortalDefineQuery(Portal portal, extern void PortalDefineQuery(Portal portal,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.75 2004/07/01 00:51:44 tgl Exp $ * $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.76 2004/07/17 03:31:47 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -110,9 +110,6 @@ typedef struct RelationData ...@@ -110,9 +110,6 @@ typedef struct RelationData
BlockNumber rd_targblock; /* current insertion target block, or BlockNumber rd_targblock; /* current insertion target block, or
* InvalidBlockNumber */ * InvalidBlockNumber */
int rd_refcnt; /* reference count */ int rd_refcnt; /* reference count */
int *rd_prevrefcnt; /* reference count stack */
int rd_numalloc; /* stack allocated size */
int rd_numpushed; /* stack used size */
bool rd_isnew; /* rel was created in current xact */ bool rd_isnew; /* rel was created in current xact */
/* /*
...@@ -190,28 +187,6 @@ typedef Relation *RelationPtr; ...@@ -190,28 +187,6 @@ typedef Relation *RelationPtr;
#define RelationHasReferenceCountZero(relation) \ #define RelationHasReferenceCountZero(relation) \
((bool)((relation)->rd_refcnt == 0)) ((bool)((relation)->rd_refcnt == 0))
/*
* RelationSetReferenceCount
* Sets relation reference count.
*/
#define RelationSetReferenceCount(relation,count) \
((relation)->rd_refcnt = (count))
/*
* RelationIncrementReferenceCount
* Increments relation reference count.
*/
#define RelationIncrementReferenceCount(relation) \
((relation)->rd_refcnt += 1)
/*
* RelationDecrementReferenceCount
* Decrements relation reference count.
*/
#define RelationDecrementReferenceCount(relation) \
(AssertMacro((relation)->rd_refcnt > 0), \
(relation)->rd_refcnt -= 1)
/* /*
* RelationGetForm * RelationGetForm
* Returns pg_class tuple for a relation. * Returns pg_class tuple for a relation.
...@@ -255,4 +230,8 @@ typedef Relation *RelationPtr; ...@@ -255,4 +230,8 @@ typedef Relation *RelationPtr;
#define RelationGetNamespace(relation) \ #define RelationGetNamespace(relation) \
((relation)->rd_rel->relnamespace) ((relation)->rd_rel->relnamespace)
/* routines in utils/cache/relcache.c */
extern void RelationIncrementReferenceCount(Relation rel);
extern void RelationDecrementReferenceCount(Relation rel);
#endif /* REL_H */ #endif /* REL_H */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/utils/relcache.h,v 1.41 2004/07/01 00:51:45 tgl Exp $ * $PostgreSQL: pgsql/src/include/utils/relcache.h,v 1.42 2004/07/17 03:31:47 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -66,8 +66,6 @@ extern void RelationCacheInvalidateEntry(Oid relationId, RelFileNode *rnode); ...@@ -66,8 +66,6 @@ extern void RelationCacheInvalidateEntry(Oid relationId, RelFileNode *rnode);
extern void RelationCacheInvalidate(void); extern void RelationCacheInvalidate(void);
extern void AtEOXact_RelationCache(bool isCommit); extern void AtEOXact_RelationCache(bool isCommit);
extern void AtSubStart_RelationCache(void);
extern void AtEOSubXact_RelationCache(bool isCommit);
/* /*
* Routines to help manage rebuilding of relcache init file * Routines to help manage rebuilding of relcache init file
......
This diff is collapsed.
This diff is collapsed.
...@@ -127,6 +127,28 @@ BEGIN; ...@@ -127,6 +127,28 @@ BEGIN;
COMMIT; COMMIT;
SELECT 1; -- this should work SELECT 1; -- this should work
-- check non-transactional behavior of cursors
BEGIN;
DECLARE c CURSOR FOR SELECT unique2 FROM tenk1;
BEGIN;
FETCH 10 FROM c;
ROLLBACK;
BEGIN;
FETCH 10 FROM c;
COMMIT;
FETCH 10 FROM c;
CLOSE c;
DECLARE c CURSOR FOR SELECT unique2/0 FROM tenk1;
BEGIN;
FETCH 10 FROM c;
ROLLBACK;
-- c is now dead to the world ...
BEGIN;
FETCH 10 FROM c;
ROLLBACK;
FETCH 10 FROM c;
COMMIT;
DROP TABLE foo; DROP TABLE foo;
DROP TABLE baz; DROP TABLE baz;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment