diff -cprN head/src/backend/access/transam/twophase.c dblink2/src/backend/access/transam/twophase.c *** head/src/backend/access/transam/twophase.c 2009-06-26 04:05:52.000000000 +0900 --- dblink2/src/backend/access/transam/twophase.c 2009-08-20 11:18:35.852151624 +0900 *************** typedef struct TwoPhaseStateData *** 138,143 **** --- 138,155 ---- static TwoPhaseStateData *TwoPhaseState; + /* + * List of add-on for twophase commit callbacks + */ + typedef struct TwoPhaseCallbackItem + { + struct TwoPhaseCallbackItem *next; + TwoPhaseEventCallback callback; + void *arg; + } TwoPhaseCallbackItem; + + static TwoPhaseCallbackItem *TwoPhase_callbacks = NULL; + static void RecordTransactionCommitPrepared(TransactionId xid, int nchildren, *************** EndPrepare(GlobalTransaction gxact) *** 944,949 **** --- 956,964 ---- errmsg("could not seek in two-phase state file: %m"))); } + /* Fire pre-commit callbacks */ + CallTwoPhaseCallbacks(TWOPHASE_EVENT_PRE_COMMIT, gxact); + /* * The state file isn't valid yet, because we haven't written the correct * CRC yet. Before we do that, insert entry in WAL and flush it to disk. *************** FinishPreparedTransaction(const char *gi *** 1248,1256 **** --- 1263,1277 ---- /* And now do the callbacks */ if (isCommit) + { ProcessRecords(bufptr, xid, twophase_postcommit_callbacks); + CallTwoPhaseCallbacks(TWOPHASE_EVENT_POST_COMMIT, gxact); + } else + { ProcessRecords(bufptr, xid, twophase_postabort_callbacks); + CallTwoPhaseCallbacks(TWOPHASE_EVENT_POST_ABORT, gxact); + } /* Count the prepared xact as committed or aborted */ AtEOXact_PgStat(isCommit); *************** RecoverPreparedTransactions(void) *** 1687,1692 **** --- 1708,1714 ---- * Recover other state (notably locks) using resource managers */ ProcessRecords(bufptr, xid, twophase_recover_callbacks); + CallTwoPhaseCallbacks(TWOPHASE_EVENT_RECOVER, gxact); pfree(buf); } *************** RecordTransactionAbortPrepared(Transacti *** 1839,1841 **** --- 1861,1906 ---- END_CRIT_SECTION(); } + + void + RegisterTwoPhaseCallback(TwoPhaseEventCallback callback, void *arg) + { + TwoPhaseCallbackItem *item; + + item = (TwoPhaseCallbackItem *) + MemoryContextAlloc(TopMemoryContext, sizeof(TwoPhaseCallbackItem)); + item->callback = callback; + item->arg = arg; + item->next = TwoPhase_callbacks; + TwoPhase_callbacks = item; + } + + void + UnregisterTwoPhaseCallback(TwoPhaseEventCallback callback, void *arg) + { + TwoPhaseCallbackItem *item; + TwoPhaseCallbackItem *prev; + + prev = NULL; + for (item = TwoPhase_callbacks; item; prev = item, item = item->next) + { + if (item->callback == callback && item->arg == arg) + { + if (prev) + prev->next = item->next; + else + TwoPhase_callbacks = item->next; + pfree(item); + break; + } + } + } + + void + CallTwoPhaseCallbacks(TwoPhaseEvent event, GlobalTransaction gxact) + { + TwoPhaseCallbackItem *item; + + for (item = TwoPhase_callbacks; item; item = item->next) + (*item->callback) (event, gxact, item->arg); + } diff -cprN head/src/backend/access/transam/xact.c dblink2/src/backend/access/transam/xact.c *** head/src/backend/access/transam/xact.c 2009-06-11 23:48:54.000000000 +0900 --- dblink2/src/backend/access/transam/xact.c 2009-08-20 11:14:22.576185055 +0900 *************** CommitTransaction(void) *** 1593,1598 **** --- 1593,1601 ---- /* Now we can shut down the deferred-trigger manager */ AfterTriggerEndXact(true); + /* Fire pre-commit callbacks */ + CallTwoPhaseCallbacks(TWOPHASE_EVENT_PRE_COMMIT, NULL); + /* Close any open regular cursors */ AtCommit_Portals(); diff -cprN head/src/include/access/twophase.h dblink2/src/include/access/twophase.h *** head/src/include/access/twophase.h 2009-01-02 02:23:56.000000000 +0900 --- dblink2/src/include/access/twophase.h 2009-08-20 11:06:06.572168421 +0900 *************** *** 24,29 **** --- 24,40 ---- */ typedef struct GlobalTransactionData *GlobalTransaction; + typedef enum + { + TWOPHASE_EVENT_PRE_COMMIT, + TWOPHASE_EVENT_POST_COMMIT, + TWOPHASE_EVENT_POST_ABORT, + TWOPHASE_EVENT_RECOVER, + } TwoPhaseEvent; + + typedef void (*TwoPhaseEventCallback) (TwoPhaseEvent event, + GlobalTransaction gxact, void *arg); + /* GUC variable */ extern int max_prepared_xacts; *************** extern void CheckPointTwoPhase(XLogRecPt *** 49,52 **** --- 60,67 ---- extern void FinishPreparedTransaction(const char *gid, bool isCommit); + extern void RegisterTwoPhaseCallback(TwoPhaseEventCallback callback, void *arg); + extern void UnregisterTwoPhaseCallback(TwoPhaseEventCallback callback, void *arg); + extern void CallTwoPhaseCallbacks(TwoPhaseEvent event, GlobalTransaction gxact); + #endif /* TWOPHASE_H */