7
7
* Portions Copyright (c) 1994, Regents of the University of California
8
8
*
9
9
* IDENTIFICATION
10
- * $PostgreSQL: pgsql/src/backend/access/transam/twophase.c,v 1.2 2005/06/18 05:21:09 tgl Exp $
10
+ * $PostgreSQL: pgsql/src/backend/access/transam/twophase.c,v 1.3 2005/06/18 19:33:41 tgl Exp $
11
11
*
12
12
* NOTES
13
13
* Each global transaction is associated with a global transaction
@@ -104,6 +104,7 @@ int max_prepared_xacts = 50;
104
104
typedef struct GlobalTransactionData
105
105
{
106
106
PGPROC proc ; /* dummy proc */
107
+ TimestampTz prepared_at ; /* time of preparation */
107
108
AclId owner ; /* ID of user that executed the xact */
108
109
TransactionId locking_xid ; /* top-level XID of backend working on xact */
109
110
bool valid ; /* TRUE if fully prepared */
@@ -202,7 +203,8 @@ TwoPhaseShmemInit(void)
202
203
* assuming that we can use very much backend context.
203
204
*/
204
205
GlobalTransaction
205
- MarkAsPreparing (TransactionId xid , Oid databaseid , char * gid , AclId owner )
206
+ MarkAsPreparing (TransactionId xid , const char * gid ,
207
+ TimestampTz prepared_at , AclId owner , Oid databaseid )
206
208
{
207
209
GlobalTransaction gxact ;
208
210
int i ;
@@ -278,6 +280,7 @@ MarkAsPreparing(TransactionId xid, Oid databaseid, char *gid, AclId owner)
278
280
gxact -> proc .subxids .overflowed = false;
279
281
gxact -> proc .subxids .nxids = 0 ;
280
282
283
+ gxact -> prepared_at = prepared_at ;
281
284
gxact -> owner = owner ;
282
285
gxact -> locking_xid = xid ;
283
286
gxact -> valid = false;
@@ -342,7 +345,7 @@ MarkAsPrepared(GlobalTransaction gxact)
342
345
* Locate the prepared transaction and mark it busy for COMMIT or PREPARE.
343
346
*/
344
347
static GlobalTransaction
345
- LockGXact (char * gid , AclId user )
348
+ LockGXact (const char * gid , AclId user )
346
349
{
347
350
int i ;
348
351
@@ -509,14 +512,16 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
509
512
510
513
/* build tupdesc for result tuples */
511
514
/* this had better match pg_prepared_xacts view in system_views.sql */
512
- tupdesc = CreateTemplateTupleDesc (4 , false);
515
+ tupdesc = CreateTemplateTupleDesc (5 , false);
513
516
TupleDescInitEntry (tupdesc , (AttrNumber ) 1 , "transaction" ,
514
517
XIDOID , -1 , 0 );
515
518
TupleDescInitEntry (tupdesc , (AttrNumber ) 2 , "gid" ,
516
519
TEXTOID , -1 , 0 );
517
- TupleDescInitEntry (tupdesc , (AttrNumber ) 3 , "ownerid" ,
520
+ TupleDescInitEntry (tupdesc , (AttrNumber ) 3 , "prepared" ,
521
+ TIMESTAMPTZOID , -1 , 0 );
522
+ TupleDescInitEntry (tupdesc , (AttrNumber ) 4 , "ownerid" ,
518
523
INT4OID , -1 , 0 );
519
- TupleDescInitEntry (tupdesc , (AttrNumber ) 4 , "dbid" ,
524
+ TupleDescInitEntry (tupdesc , (AttrNumber ) 5 , "dbid" ,
520
525
OIDOID , -1 , 0 );
521
526
522
527
funcctx -> tuple_desc = BlessTupleDesc (tupdesc );
@@ -540,8 +545,8 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
540
545
while (status -> array != NULL && status -> currIdx < status -> ngxacts )
541
546
{
542
547
GlobalTransaction gxact = & status -> array [status -> currIdx ++ ];
543
- Datum values [4 ];
544
- bool nulls [4 ];
548
+ Datum values [5 ];
549
+ bool nulls [5 ];
545
550
HeapTuple tuple ;
546
551
Datum result ;
547
552
@@ -556,8 +561,9 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
556
561
557
562
values [0 ] = TransactionIdGetDatum (gxact -> proc .xid );
558
563
values [1 ] = DirectFunctionCall1 (textin , CStringGetDatum (gxact -> gid ));
559
- values [2 ] = Int32GetDatum (gxact -> owner );
560
- values [3 ] = ObjectIdGetDatum (gxact -> proc .databaseId );
564
+ values [2 ] = TimestampTzGetDatum (gxact -> prepared_at );
565
+ values [3 ] = Int32GetDatum (gxact -> owner );
566
+ values [4 ] = ObjectIdGetDatum (gxact -> proc .databaseId );
561
567
562
568
tuple = heap_form_tuple (funcctx -> tuple_desc , values , nulls );
563
569
result = HeapTupleGetDatum (tuple );
@@ -636,14 +642,15 @@ TwoPhaseGetDummyProc(TransactionId xid)
636
642
/*
637
643
* Header for a 2PC state file
638
644
*/
639
- #define TWOPHASE_MAGIC 0x57F94530 /* format identifier */
645
+ #define TWOPHASE_MAGIC 0x57F94531 /* format identifier */
640
646
641
647
typedef struct TwoPhaseFileHeader
642
648
{
643
649
uint32 magic ; /* format identifier */
644
650
uint32 total_len ; /* actual file length */
645
651
TransactionId xid ; /* original transaction XID */
646
652
Oid database ; /* OID of database it was in */
653
+ TimestampTz prepared_at ; /* time of preparation */
647
654
AclId owner ; /* user running the transaction */
648
655
int32 nsubxacts ; /* number of following subxact XIDs */
649
656
int32 ncommitrels ; /* number of delete-on-commit rels */
@@ -741,8 +748,9 @@ StartPrepare(GlobalTransaction gxact)
741
748
hdr .magic = TWOPHASE_MAGIC ;
742
749
hdr .total_len = 0 ; /* EndPrepare will fill this in */
743
750
hdr .xid = xid ;
744
- hdr .database = MyDatabaseId ;
745
- hdr .owner = GetUserId ();
751
+ hdr .database = gxact -> proc .databaseId ;
752
+ hdr .prepared_at = gxact -> prepared_at ;
753
+ hdr .owner = gxact -> owner ;
746
754
hdr .nsubxacts = xactGetCommittedChildren (& children );
747
755
hdr .ncommitrels = smgrGetPendingDeletes (true, & commitrels );
748
756
hdr .nabortrels = smgrGetPendingDeletes (false, & abortrels );
@@ -1046,7 +1054,7 @@ ReadTwoPhaseFile(TransactionId xid)
1046
1054
* FinishPreparedTransaction: execute COMMIT PREPARED or ROLLBACK PREPARED
1047
1055
*/
1048
1056
void
1049
- FinishPreparedTransaction (char * gid , bool isCommit )
1057
+ FinishPreparedTransaction (const char * gid , bool isCommit )
1050
1058
{
1051
1059
GlobalTransaction gxact ;
1052
1060
TransactionId xid ;
@@ -1474,15 +1482,20 @@ RecoverPreparedTransactions(void)
1474
1482
1475
1483
/*
1476
1484
* Reconstruct subtrans state for the transaction --- needed
1477
- * because pg_subtrans is not preserved over a restart
1485
+ * because pg_subtrans is not preserved over a restart. Note
1486
+ * that we are linking all the subtransactions directly to the
1487
+ * top-level XID; there may originally have been a more complex
1488
+ * hierarchy, but there's no need to restore that exactly.
1478
1489
*/
1479
1490
for (i = 0 ; i < hdr -> nsubxacts ; i ++ )
1480
1491
SubTransSetParent (subxids [i ], xid );
1481
1492
1482
1493
/*
1483
1494
* Recreate its GXACT and dummy PGPROC
1484
1495
*/
1485
- gxact = MarkAsPreparing (xid , hdr -> database , hdr -> gid , hdr -> owner );
1496
+ gxact = MarkAsPreparing (xid , hdr -> gid ,
1497
+ hdr -> prepared_at ,
1498
+ hdr -> owner , hdr -> database );
1486
1499
GXactLoadSubxactData (gxact , hdr -> nsubxacts , subxids );
1487
1500
MarkAsPrepared (gxact );
1488
1501
0 commit comments