Add a mechanism to let dynamically loaded modules register post-commit/

post-abort cleanup hooks.  I'm surprised that we have not needed this
already, but I need it now to fix a plpgsql problem, and the usefulness
for other dynamically loaded modules seems obvious.
This commit is contained in:
Tom Lane 2003-09-28 23:26:20 +00:00
parent a15207f8d6
commit 8934790052
2 changed files with 82 additions and 5 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.154 2003/09/25 06:57:57 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.155 2003/09/28 23:26:20 tgl Exp $
*
* NOTES
* Transaction aborts can now occur two ways:
@ -183,6 +183,7 @@ static void AtCommit_Memory(void);
static void AtStart_Cache(void);
static void AtStart_Locks(void);
static void AtStart_Memory(void);
static void CallEOXactCallbacks(bool isCommit);
static void CleanupTransaction(void);
static void CommitTransaction(void);
static void RecordTransactionAbort(void);
@ -217,6 +218,18 @@ int CommitSiblings = 5; /* number of concurrent xacts needed to
* sleep */
/*
* List of add-on end-of-xact callbacks
*/
typedef struct EOXactCallbackItem
{
struct EOXactCallbackItem *next;
EOXactCallback callback;
void *arg;
} EOXactCallbackItem;
static EOXactCallbackItem *EOXact_callbacks = NULL;
static void (*_RollbackFunc) (void *) = NULL;
static void *_RollbackData = NULL;
@ -964,6 +977,7 @@ CommitTransaction(void)
AtCommit_Locks();
CallEOXactCallbacks(true);
AtEOXact_GUC(true);
AtEOXact_SPI();
AtEOXact_gist();
@ -1073,6 +1087,7 @@ AbortTransaction(void)
AtAbort_Locks();
CallEOXactCallbacks(false);
AtEOXact_GUC(false);
AtEOXact_SPI();
AtEOXact_gist();
@ -1430,6 +1445,62 @@ RequireTransactionChain(void *stmtNode, const char *stmtType)
}
/*
* Register or deregister callback functions for end-of-xact cleanup
*
* These functions are intended for use by dynamically loaded modules.
* For built-in modules we generally just hardwire the appropriate calls
* (mainly because it's easier to control the order that way, where needed).
*
* Note that the callback occurs post-commit or post-abort, so the callback
* functions can only do noncritical cleanup.
*/
void
RegisterEOXactCallback(EOXactCallback callback, void *arg)
{
EOXactCallbackItem *item;
item = (EOXactCallbackItem *)
MemoryContextAlloc(TopMemoryContext, sizeof(EOXactCallbackItem));
item->callback = callback;
item->arg = arg;
item->next = EOXact_callbacks;
EOXact_callbacks = item;
}
void
UnregisterEOXactCallback(EOXactCallback callback, void *arg)
{
EOXactCallbackItem *item;
EOXactCallbackItem *prev;
prev = NULL;
for (item = EOXact_callbacks; item; prev = item, item = item->next)
{
if (item->callback == callback && item->arg == arg)
{
if (prev)
prev->next = item->next;
else
EOXact_callbacks = item->next;
pfree(item);
break;
}
}
}
static void
CallEOXactCallbacks(bool isCommit)
{
EOXactCallbackItem *item;
for (item = EOXact_callbacks; item; item = item->next)
{
(*item->callback) (isCommit, item->arg);
}
}
/* ----------------------------------------------------------------
* transaction block support
* ----------------------------------------------------------------

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: xact.h,v 1.55 2003/08/08 21:42:32 momjian Exp $
* $Id: xact.h,v 1.56 2003/09/28 23:26:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -59,9 +59,13 @@ typedef enum TBlockState
TBLOCK_ENDABORT
} TBlockState;
/* ----------------
* transaction state structure
* ----------------
/*
* end-of-transaction cleanup callbacks for dynamically loaded modules
*/
typedef void (*EOXactCallback) (bool isCommit, void *arg);
/*
* transaction state structure
*/
typedef struct TransactionStateData
{
@ -130,6 +134,8 @@ extern void UserAbortTransactionBlock(void);
extern void AbortOutOfAnyTransaction(void);
extern void PreventTransactionChain(void *stmtNode, const char *stmtType);
extern void RequireTransactionChain(void *stmtNode, const char *stmtType);
extern void RegisterEOXactCallback(EOXactCallback callback, void *arg);
extern void UnregisterEOXactCallback(EOXactCallback callback, void *arg);
extern void RecordTransactionCommit(void);