diff options
-rw-r--r-- | src/backend/access/transam/multixact.c | 140 | ||||
-rw-r--r-- | src/backend/access/transam/twophase.c | 33 | ||||
-rw-r--r-- | src/backend/access/transam/twophase_rmgr.c | 12 | ||||
-rw-r--r-- | src/backend/access/transam/xact.c | 5 | ||||
-rw-r--r-- | src/include/access/multixact.h | 11 | ||||
-rw-r--r-- | src/include/access/twophase.h | 4 | ||||
-rw-r--r-- | src/include/access/twophase_rmgr.h | 5 |
7 files changed, 191 insertions, 19 deletions
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c index dda3d03b14..025219e092 100644 --- a/src/backend/access/transam/multixact.c +++ b/src/backend/access/transam/multixact.c @@ -42,7 +42,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/access/transam/multixact.c,v 1.31 2009/06/26 20:29:04 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/transam/multixact.c,v 1.31.2.1 2009/11/23 09:58:51 heikki Exp $ * *------------------------------------------------------------------------- */ @@ -51,6 +51,8 @@ #include "access/multixact.h" #include "access/slru.h" #include "access/transam.h" +#include "access/twophase.h" +#include "access/twophase_rmgr.h" #include "access/xact.h" #include "miscadmin.h" #include "pg_trace.h" @@ -118,8 +120,11 @@ typedef struct MultiXactStateData /* * Per-backend data starts here. We have two arrays stored in the area * immediately following the MultiXactStateData struct. Each is indexed by - * BackendId. (Note: valid BackendIds run from 1 to MaxBackends; element - * zero of each array is never used.) + * BackendId. + * + * In both arrays, there's a slot for all normal backends (1..MaxBackends) + * followed by a slot for max_prepared_xacts prepared transactions. Valid + * BackendIds start from 1; element zero of each array is never used. * * OldestMemberMXactId[k] is the oldest MultiXactId each backend's current * transaction(s) could possibly be a member of, or InvalidMultiXactId @@ -152,6 +157,12 @@ typedef struct MultiXactStateData MultiXactId perBackendXactIds[1]; /* VARIABLE LENGTH ARRAY */ } MultiXactStateData; +/* + * Last element of OldestMemberMXactID and OldestVisibleMXactId arrays. + * Valid elements are (1..MaxOldestSlot); element 0 is never used. + */ +#define MaxOldestSlot (MaxBackends + max_prepared_xacts) + /* Pointers to the state data in shared memory */ static MultiXactStateData *MultiXactState; static MultiXactId *OldestMemberMXactId; @@ -539,7 +550,7 @@ MultiXactIdSetOldestVisible(void) if (oldestMXact < FirstMultiXactId) oldestMXact = FirstMultiXactId; - for (i = 1; i <= MaxBackends; i++) + for (i = 1; i <= MaxOldestSlot; i++) { MultiXactId thisoldest = OldestMemberMXactId[i]; @@ -1276,6 +1287,119 @@ AtEOXact_MultiXact(void) } /* + * AtPrepare_MultiXact + * Save multixact state at 2PC tranasction prepare + * + * In this phase, we only store our OldestMemberMXactId value in the two-phase + * state file. + */ +void +AtPrepare_MultiXact(void) +{ + MultiXactId myOldestMember = OldestMemberMXactId[MyBackendId]; + + if (MultiXactIdIsValid(myOldestMember)) + RegisterTwoPhaseRecord(TWOPHASE_RM_MULTIXACT_ID, 0, + &myOldestMember, sizeof(MultiXactId)); +} + +/* + * PostPrepare_MultiXact + * Clean up after successful PREPARE TRANSACTION + */ +void +PostPrepare_MultiXact(TransactionId xid) +{ + MultiXactId myOldestMember; + + /* + * Transfer our OldestMemberMXactId value to the slot reserved for the + * prepared transaction. + */ + myOldestMember = OldestMemberMXactId[MyBackendId]; + if (MultiXactIdIsValid(myOldestMember)) + { + BackendId dummyBackendId = TwoPhaseGetDummyBackendId(xid); + + /* + * Even though storing MultiXactId is atomic, acquire lock to make sure + * others see both changes, not just the reset of the slot of the + * current backend. Using a volatile pointer might suffice, but this + * isn't a hot spot. + */ + LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE); + + OldestMemberMXactId[dummyBackendId] = myOldestMember; + OldestMemberMXactId[MyBackendId] = InvalidMultiXactId; + + LWLockRelease(MultiXactGenLock); + } + + /* + * We don't need to transfer OldestVisibleMXactId value, because the + * transaction is not going to be looking at any more multixacts once + * it's prepared. + * + * We assume that storing a MultiXactId is atomic and so we need not take + * MultiXactGenLock to do this. + */ + OldestVisibleMXactId[MyBackendId] = InvalidMultiXactId; + + /* + * Discard the local MultiXactId cache like in AtEOX_MultiXact + */ + MXactContext = NULL; + MXactCache = NULL; +} + +/* + * multixact_twophase_recover + * Recover the state of a prepared transaction at startup + */ +void +multixact_twophase_recover(TransactionId xid, uint16 info, + void *recdata, uint32 len) +{ + BackendId dummyBackendId = TwoPhaseGetDummyBackendId(xid); + MultiXactId oldestMember; + + /* + * Get the oldest member XID from the state file record, and set it in + * the OldestMemberMXactId slot reserved for this prepared transaction. + */ + Assert(len == sizeof(MultiXactId)); + oldestMember = *((MultiXactId *)recdata); + + OldestMemberMXactId[dummyBackendId] = oldestMember; +} + +/* + * multixact_twophase_postcommit + * Similar to AtEOX_MultiXact but for COMMIT PREPARED + */ +void +multixact_twophase_postcommit(TransactionId xid, uint16 info, + void *recdata, uint32 len) +{ + BackendId dummyBackendId = TwoPhaseGetDummyBackendId(xid); + + Assert(len == sizeof(MultiXactId)); + + OldestMemberMXactId[dummyBackendId] = InvalidMultiXactId; +} + +/* + * multixact_twophase_postabort + * This is actually just the same as the COMMIT case. + */ +void +multixact_twophase_postabort(TransactionId xid, uint16 info, + void *recdata, uint32 len) +{ + multixact_twophase_postcommit(xid, info, recdata, len); +} + +/* * Initialization of shared memory for MultiXact. We use two SLRU areas, * thus double memory. Also, reserve space for the shared MultiXactState * struct and the per-backend MultiXactId arrays (two of those, too). @@ -1287,7 +1411,7 @@ MultiXactShmemSize(void) #define SHARED_MULTIXACT_STATE_SIZE \ add_size(sizeof(MultiXactStateData), \ - mul_size(sizeof(MultiXactId) * 2, MaxBackends)) + mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot)) size = SHARED_MULTIXACT_STATE_SIZE; size = add_size(size, SimpleLruShmemSize(NUM_MXACTOFFSET_BUFFERS, 0)); @@ -1329,10 +1453,10 @@ MultiXactShmemInit(void) /* * Set up array pointers. Note that perBackendXactIds[0] is wasted space - * since we only use indexes 1..MaxBackends in each array. + * since we only use indexes 1..MaxOldestSlot in each array. */ OldestMemberMXactId = MultiXactState->perBackendXactIds; - OldestVisibleMXactId = OldestMemberMXactId + MaxBackends; + OldestVisibleMXactId = OldestMemberMXactId + MaxOldestSlot; } /* @@ -1702,7 +1826,7 @@ TruncateMultiXact(void) nextMXact = FirstMultiXactId; oldestMXact = nextMXact; - for (i = 1; i <= MaxBackends; i++) + for (i = 1; i <= MaxOldestSlot; i++) { MultiXactId thisoldest; diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c index 6de9c73f6e..0d94697084 100644 --- a/src/backend/access/transam/twophase.c +++ b/src/backend/access/transam/twophase.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/transam/twophase.c,v 1.54 2009/06/25 19:05:52 heikki Exp $ + * $PostgreSQL: pgsql/src/backend/access/transam/twophase.c,v 1.54.2.1 2009/11/23 09:58:51 heikki Exp $ * * NOTES * Each global transaction is associated with a global transaction @@ -109,6 +109,7 @@ int max_prepared_xacts = 0; typedef struct GlobalTransactionData { PGPROC proc; /* dummy proc */ + BackendId dummyBackendId; /* similar to backend id for backends */ TimestampTz prepared_at; /* time of preparation */ XLogRecPtr prepare_lsn; /* XLOG offset of prepare record */ Oid owner; /* ID of user that executed the xact */ @@ -200,6 +201,20 @@ TwoPhaseShmemInit(void) { gxacts[i].proc.links.next = (SHM_QUEUE *) TwoPhaseState->freeGXacts; TwoPhaseState->freeGXacts = &gxacts[i]; + + /* + * Assign a unique ID for each dummy proc, so that the range of + * dummy backend IDs immediately follows the range of normal + * backend IDs. We don't dare to assign a real backend ID to + * dummy procs, because prepared transactions don't take part in + * cache invalidation like a real backend ID would imply, but + * having a unique ID for them is nevertheless handy. This + * arrangement allows you to allocate an array of size + * (MaxBackends + max_prepared_xacts + 1), and have a slot for + * every backend and prepared transaction. Currently multixact.c + * uses that technique. + */ + gxacts[i].dummyBackendId = MaxBackends + 1 + i; } } else @@ -649,6 +664,22 @@ pg_prepared_xact(PG_FUNCTION_ARGS) /* * TwoPhaseGetDummyProc + * Get the dummy backend ID for prepared transaction specified by XID + * + * Dummy backend IDs are similar to real backend IDs of real backends. + * They start at MaxBackends + 1, and are unique across all currently active + * real backends and prepared transactions. + */ +BackendId +TwoPhaseGetDummyBackendId(TransactionId xid) +{ + PGPROC *proc = TwoPhaseGetDummyProc(xid); + + return ((GlobalTransaction) proc)->dummyBackendId; +} + +/* + * TwoPhaseGetDummyProc * Get the PGPROC that represents a prepared transaction specified by XID */ PGPROC * diff --git a/src/backend/access/transam/twophase_rmgr.c b/src/backend/access/transam/twophase_rmgr.c index c8564468bc..447ccaf0a1 100644 --- a/src/backend/access/transam/twophase_rmgr.c +++ b/src/backend/access/transam/twophase_rmgr.c @@ -8,12 +8,13 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/transam/twophase_rmgr.c,v 1.8 2009/01/01 17:23:36 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/access/transam/twophase_rmgr.c,v 1.8.2.1 2009/11/23 09:58:51 heikki Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" +#include "access/multixact.h" #include "access/twophase_rmgr.h" #include "commands/async.h" #include "pgstat.h" @@ -29,7 +30,8 @@ const TwoPhaseCallback twophase_recover_callbacks[TWOPHASE_RM_MAX_ID + 1] = NULL, /* Inval */ NULL, /* flat file update */ NULL, /* notify/listen */ - NULL /* pgstat */ + NULL, /* pgstat */ + multixact_twophase_recover /* MultiXact */ }; const TwoPhaseCallback twophase_postcommit_callbacks[TWOPHASE_RM_MAX_ID + 1] = @@ -39,7 +41,8 @@ const TwoPhaseCallback twophase_postcommit_callbacks[TWOPHASE_RM_MAX_ID + 1] = inval_twophase_postcommit, /* Inval */ flatfile_twophase_postcommit, /* flat file update */ notify_twophase_postcommit, /* notify/listen */ - pgstat_twophase_postcommit /* pgstat */ + pgstat_twophase_postcommit, /* pgstat */ + multixact_twophase_postcommit /* MultiXact */ }; const TwoPhaseCallback twophase_postabort_callbacks[TWOPHASE_RM_MAX_ID + 1] = @@ -49,5 +52,6 @@ const TwoPhaseCallback twophase_postabort_callbacks[TWOPHASE_RM_MAX_ID + 1] = NULL, /* Inval */ NULL, /* flat file update */ NULL, /* notify/listen */ - pgstat_twophase_postabort /* pgstat */ + pgstat_twophase_postabort, /* pgstat */ + multixact_twophase_postabort /* MultiXact */ }; diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 2b6a222477..941b4e3815 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.274 2009/06/11 14:48:54 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.274.2.1 2009/11/23 09:58:51 heikki Exp $ * *------------------------------------------------------------------------- */ @@ -1864,6 +1864,7 @@ PrepareTransaction(void) AtPrepare_Inval(); AtPrepare_Locks(); AtPrepare_PgStat(); + AtPrepare_MultiXact(); /* * Here is where we really truly prepare. @@ -1917,7 +1918,7 @@ PrepareTransaction(void) PostPrepare_smgr(); - AtEOXact_MultiXact(); + PostPrepare_MultiXact(xid); PostPrepare_Locks(xid); diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h index 0836e032e0..317ec4f454 100644 --- a/src/include/access/multixact.h +++ b/src/include/access/multixact.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/access/multixact.h,v 1.14 2009/01/01 17:23:56 momjian Exp $ + * $PostgreSQL: pgsql/src/include/access/multixact.h,v 1.14.2.1 2009/11/23 09:58:51 heikki Exp $ */ #ifndef MULTIXACT_H #define MULTIXACT_H @@ -52,6 +52,8 @@ extern void MultiXactIdSetOldestMember(void); extern int GetMultiXactIdMembers(MultiXactId multi, TransactionId **xids); extern void AtEOXact_MultiXact(void); +extern void AtPrepare_MultiXact(void); +extern void PostPrepare_MultiXact(TransactionId xid); extern Size MultiXactShmemSize(void); extern void MultiXactShmemInit(void); @@ -67,6 +69,13 @@ extern void MultiXactSetNextMXact(MultiXactId nextMulti, extern void MultiXactAdvanceNextMXact(MultiXactId minMulti, MultiXactOffset minMultiOffset); +extern void multixact_twophase_recover(TransactionId xid, uint16 info, + void *recdata, uint32 len); +extern void multixact_twophase_postcommit(TransactionId xid, uint16 info, + void *recdata, uint32 len); +extern void multixact_twophase_postabort(TransactionId xid, uint16 info, + void *recdata, uint32 len); + extern void multixact_redo(XLogRecPtr lsn, XLogRecord *record); extern void multixact_desc(StringInfo buf, uint8 xl_info, char *rec); diff --git a/src/include/access/twophase.h b/src/include/access/twophase.h index 0a39bad4ec..997bd71669 100644 --- a/src/include/access/twophase.h +++ b/src/include/access/twophase.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/access/twophase.h,v 1.11 2009/01/01 17:23:56 momjian Exp $ + * $PostgreSQL: pgsql/src/include/access/twophase.h,v 1.11.2.1 2009/11/23 09:58:51 heikki Exp $ * *------------------------------------------------------------------------- */ @@ -15,6 +15,7 @@ #define TWOPHASE_H #include "access/xlogdefs.h" +#include "storage/backendid.h" #include "storage/proc.h" #include "utils/timestamp.h" @@ -31,6 +32,7 @@ extern Size TwoPhaseShmemSize(void); extern void TwoPhaseShmemInit(void); extern PGPROC *TwoPhaseGetDummyProc(TransactionId xid); +extern BackendId TwoPhaseGetDummyBackendId(TransactionId xid); extern GlobalTransaction MarkAsPreparing(TransactionId xid, const char *gid, TimestampTz prepared_at, diff --git a/src/include/access/twophase_rmgr.h b/src/include/access/twophase_rmgr.h index dc018005ae..f1aec439fc 100644 --- a/src/include/access/twophase_rmgr.h +++ b/src/include/access/twophase_rmgr.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/access/twophase_rmgr.h,v 1.7 2009/01/01 17:23:56 momjian Exp $ + * $PostgreSQL: pgsql/src/include/access/twophase_rmgr.h,v 1.7.2.1 2009/11/23 09:58:51 heikki Exp $ * *------------------------------------------------------------------------- */ @@ -27,7 +27,8 @@ typedef uint8 TwoPhaseRmgrId; #define TWOPHASE_RM_FLATFILES_ID 3 #define TWOPHASE_RM_NOTIFY_ID 4 #define TWOPHASE_RM_PGSTAT_ID 5 -#define TWOPHASE_RM_MAX_ID TWOPHASE_RM_PGSTAT_ID +#define TWOPHASE_RM_MULTIXACT_ID 6 +#define TWOPHASE_RM_MAX_ID TWOPHASE_RM_MULTIXACT_ID extern const TwoPhaseCallback twophase_recover_callbacks[]; extern const TwoPhaseCallback twophase_postcommit_callbacks[]; |