119
121
* Per-backend data starts here. We have two arrays stored in the area
120
122
* immediately following the MultiXactStateData struct. Each is indexed by
121
* BackendId. (Note: valid BackendIds run from 1 to MaxBackends; element
122
* zero of each array is never used.)
125
* In both arrays, there's a slot for all normal backends (1..MaxBackends)
126
* followed by a slot for max_prepared_xacts prepared transactions. Valid
127
* BackendIds start from 1; element zero of each array is never used.
124
129
* OldestMemberMXactId[k] is the oldest MultiXactId each backend's current
125
130
* transaction(s) could possibly be a member of, or InvalidMultiXactId
1290
* AtPrepare_MultiXact
1291
* Save multixact state at 2PC tranasction prepare
1293
* In this phase, we only store our OldestMemberMXactId value in the two-phase
1297
AtPrepare_MultiXact(void)
1299
MultiXactId myOldestMember = OldestMemberMXactId[MyBackendId];
1301
if (MultiXactIdIsValid(myOldestMember))
1302
RegisterTwoPhaseRecord(TWOPHASE_RM_MULTIXACT_ID, 0,
1303
&myOldestMember, sizeof(MultiXactId));
1307
* PostPrepare_MultiXact
1308
* Clean up after successful PREPARE TRANSACTION
1311
PostPrepare_MultiXact(TransactionId xid)
1313
MultiXactId myOldestMember;
1316
* Transfer our OldestMemberMXactId value to the slot reserved for the
1317
* prepared transaction.
1319
myOldestMember = OldestMemberMXactId[MyBackendId];
1320
if (MultiXactIdIsValid(myOldestMember))
1322
BackendId dummyBackendId = TwoPhaseGetDummyBackendId(xid);
1325
* Even though storing MultiXactId is atomic, acquire lock to make sure
1326
* others see both changes, not just the reset of the slot of the
1327
* current backend. Using a volatile pointer might suffice, but this
1330
LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
1332
OldestMemberMXactId[dummyBackendId] = myOldestMember;
1333
OldestMemberMXactId[MyBackendId] = InvalidMultiXactId;
1335
LWLockRelease(MultiXactGenLock);
1339
* We don't need to transfer OldestVisibleMXactId value, because the
1340
* transaction is not going to be looking at any more multixacts once
1343
* We assume that storing a MultiXactId is atomic and so we need not take
1344
* MultiXactGenLock to do this.
1346
OldestVisibleMXactId[MyBackendId] = InvalidMultiXactId;
1349
* Discard the local MultiXactId cache like in AtEOX_MultiXact
1351
MXactContext = NULL;
1356
* multixact_twophase_recover
1357
* Recover the state of a prepared transaction at startup
1360
multixact_twophase_recover(TransactionId xid, uint16 info,
1361
void *recdata, uint32 len)
1363
BackendId dummyBackendId = TwoPhaseGetDummyBackendId(xid);
1364
MultiXactId oldestMember;
1367
* Get the oldest member XID from the state file record, and set it in
1368
* the OldestMemberMXactId slot reserved for this prepared transaction.
1370
Assert(len == sizeof(MultiXactId));
1371
oldestMember = *((MultiXactId *)recdata);
1373
OldestMemberMXactId[dummyBackendId] = oldestMember;
1377
* multixact_twophase_postcommit
1378
* Similar to AtEOX_MultiXact but for COMMIT PREPARED
1381
multixact_twophase_postcommit(TransactionId xid, uint16 info,
1382
void *recdata, uint32 len)
1384
BackendId dummyBackendId = TwoPhaseGetDummyBackendId(xid);
1386
Assert(len == sizeof(MultiXactId));
1388
OldestMemberMXactId[dummyBackendId] = InvalidMultiXactId;
1392
* multixact_twophase_postabort
1393
* This is actually just the same as the COMMIT case.
1396
multixact_twophase_postabort(TransactionId xid, uint16 info,
1397
void *recdata, uint32 len)
1399
multixact_twophase_postcommit(xid, info, recdata, len);
1279
1403
* Initialization of shared memory for MultiXact. We use two SLRU areas,
1280
1404
* thus double memory. Also, reserve space for the shared MultiXactState
1281
1405
* struct and the per-backend MultiXactId arrays (two of those, too).