@ -105,7 +105,7 @@ int synchronous_commit = SYNCHRONOUS_COMMIT_ON;
* The XIDs are stored sorted in numerical order ( not logical order ) to make
* lookups as fast as possible .
*/
TransactionId XactTopTransactionId = InvalidTransactionId ;
Full TransactionId XactTopFull TransactionId = { InvalidTransactionId } ;
int nParallelCurrentXids = 0 ;
TransactionId * ParallelCurrentXids ;
@ -171,7 +171,7 @@ typedef enum TBlockState
*/
typedef struct TransactionStateData
{
TransactionId transactionId ; /* my XID, or Invalid if none */
FullTransactionId fullTransactionId ; /* my FullTransactionId */
SubTransactionId subTransactionId ; /* my subxact ID */
char * name ; /* savepoint name, if any */
int savepointLevel ; /* savepoint level */
@ -196,6 +196,25 @@ typedef struct TransactionStateData
typedef TransactionStateData * TransactionState ;
/*
* Serialized representation used to transmit transaction state to parallel
* workers though shared memory .
*/
typedef struct SerializedTransactionState
{
int xactIsoLevel ;
bool xactDeferrable ;
FullTransactionId topFullTransactionId ;
FullTransactionId currentFullTransactionId ;
CommandId currentCommandId ;
int nParallelCurrentXids ;
TransactionId parallelCurrentXids [ FLEXIBLE_ARRAY_MEMBER ] ;
} SerializedTransactionState ;
/* The size of SerializedTransactionState, not including the final array. */
# define SerializedTransactionStateHeaderSize \
offsetof ( SerializedTransactionState , parallelCurrentXids )
/*
* CurrentTransactionState always points to the current transaction state
* block . It will point to TopTransactionStateData when not in a
@ -372,9 +391,9 @@ IsAbortedTransactionBlockState(void)
TransactionId
GetTopTransactionId ( void )
{
if ( ! TransactionIdIsValid ( XactTopTransactionId ) )
if ( ! Full TransactionIdIsValid( XactTopFull TransactionId ) )
AssignTransactionId ( & TopTransactionStateData ) ;
return XactTopTransactionId ;
return XidFromFullTransactionId ( XactTopFull TransactionId ) ;
}
/*
@ -387,7 +406,7 @@ GetTopTransactionId(void)
TransactionId
GetTopTransactionIdIfAny ( void )
{
return XactTopTransactionId ;
return XidFromFullTransactionId ( XactTopFull TransactionId ) ;
}
/*
@ -402,9 +421,9 @@ GetCurrentTransactionId(void)
{
TransactionState s = CurrentTransactionState ;
if ( ! TransactionIdIsValid ( s - > t ransactionId) )
if ( ! Full TransactionIdIsValid( s - > fullT ransactionId) )
AssignTransactionId ( s ) ;
return s - > transactionId ;
return XidFromFullTransactionId ( s - > fullTransactionId ) ;
}
/*
@ -417,7 +436,66 @@ GetCurrentTransactionId(void)
TransactionId
GetCurrentTransactionIdIfAny ( void )
{
return CurrentTransactionState - > transactionId ;
return XidFromFullTransactionId ( CurrentTransactionState - > fullTransactionId ) ;
}
/*
* GetTopFullTransactionId
*
* This will return the FullTransactionId of the main transaction , assigning
* one if it ' s not yet set . Be careful to call this only inside a valid xact .
*/
FullTransactionId
GetTopFullTransactionId ( void )
{
if ( ! FullTransactionIdIsValid ( XactTopFullTransactionId ) )
AssignTransactionId ( & TopTransactionStateData ) ;
return XactTopFullTransactionId ;
}
/*
* GetTopFullTransactionIdIfAny
*
* This will return the FullTransactionId of the main transaction , if one is
* assigned . It will return InvalidFullTransactionId if we are not currently
* inside a transaction , or inside a transaction that hasn ' t yet been assigned
* one .
*/
FullTransactionId
GetTopFullTransactionIdIfAny ( void )
{
return XactTopFullTransactionId ;
}
/*
* GetCurrentFullTransactionId
*
* This will return the FullTransactionId of the current transaction ( main or
* sub transaction ) , assigning one if it ' s not yet set . Be careful to call
* this only inside a valid xact .
*/
FullTransactionId
GetCurrentFullTransactionId ( void )
{
TransactionState s = CurrentTransactionState ;
if ( ! FullTransactionIdIsValid ( s - > fullTransactionId ) )
AssignTransactionId ( s ) ;
return s - > fullTransactionId ;
}
/*
* GetCurrentFullTransactionIdIfAny
*
* This will return the FullTransactionId of the current sub xact , if one is
* assigned . It will return InvalidFullTransactionId if we are not currently
* inside a transaction , or inside a transaction that hasn ' t been assigned one
* yet .
*/
FullTransactionId
GetCurrentFullTransactionIdIfAny ( void )
{
return CurrentTransactionState - > fullTransactionId ;
}
/*
@ -428,7 +506,7 @@ GetCurrentTransactionIdIfAny(void)
void
MarkCurrentTransactionIdLoggedIfAny ( void )
{
if ( TransactionIdIsValid ( CurrentTransactionState - > t ransactionId) )
if ( Full TransactionIdIsValid( CurrentTransactionState - > fullT ransactionId) )
CurrentTransactionState - > didLogXid = true ;
}
@ -463,7 +541,7 @@ GetStableLatestTransactionId(void)
/*
* AssignTransactionId
*
* Assigns a new permanent XID to the given TransactionState .
* Assigns a new permanent FullTransactionId to the given TransactionState .
* We do not assign XIDs to transactions until / unless this is called .
* Also , any parent TransactionStates that don ' t yet have XIDs are assigned
* one ; this maintains the invariant that a child transaction has an XID
@ -477,7 +555,7 @@ AssignTransactionId(TransactionState s)
bool log_unknown_top = false ;
/* Assert that caller didn't screw up */
Assert ( ! TransactionIdIsValid ( s - > t ransactionId) ) ;
Assert ( ! Full TransactionIdIsValid( s - > fullT ransactionId) ) ;
Assert ( s - > state = = TRANS_INPROGRESS ) ;
/*
@ -493,14 +571,14 @@ AssignTransactionId(TransactionState s)
* if we ' re at the bottom of a huge stack of subtransactions none of which
* have XIDs yet .
*/
if ( isSubXact & & ! TransactionIdIsValid ( s - > parent - > t ransactionId) )
if ( isSubXact & & ! Full TransactionIdIsValid( s - > parent - > fullT ransactionId) )
{
TransactionState p = s - > parent ;
TransactionState * parents ;
size_t parentOffset = 0 ;
parents = palloc ( sizeof ( TransactionState ) * s - > nestingLevel ) ;
while ( p ! = NULL & & ! TransactionIdIsValid ( p - > t ransactionId) )
while ( p ! = NULL & & ! Full TransactionIdIsValid( p - > fullT ransactionId) )
{
parents [ parentOffset + + ] = p ;
p = p - > parent ;
@ -531,26 +609,28 @@ AssignTransactionId(TransactionState s)
log_unknown_top = true ;
/*
* Generate a new Xid and record it in PG_PROC and pg_subtrans .
* Generate a new FullTransactionId and record its xid in PG_PROC and
* pg_subtrans .
*
* NB : we must make the subtrans entry BEFORE the Xid appears anywhere in
* shared storage other than PG_PROC ; because if there ' s no room for it in
* PG_PROC , the subtrans entry is needed to ensure that other backends see
* the Xid as " running " . See GetNewTransactionId .
*/
s - > t ransactionId = GetNewTransactionId ( isSubXact ) ;
s - > fullT ransactionId = GetNewTransactionId ( isSubXact ) ;
if ( ! isSubXact )
XactTopTransactionId = s - > t ransactionId;
XactTopFull TransactionId = s - > fullT ransactionId;
if ( isSubXact )
SubTransSetParent ( s - > transactionId , s - > parent - > transactionId ) ;
SubTransSetParent ( XidFromFullTransactionId ( s - > fullTransactionId ) ,
XidFromFullTransactionId ( s - > parent - > fullTransactionId ) ) ;
/*
* If it ' s a top - level transaction , the predicate locking system needs to
* be told about it too .
*/
if ( ! isSubXact )
RegisterPredicateLockingXid ( s - > transactionId ) ;
RegisterPredicateLockingXid ( XidFromFullTransactionId ( s - > fullTransactionId ) ) ;
/*
* Acquire lock on the transaction XID . ( We assume this cannot block . ) We
@ -560,7 +640,7 @@ AssignTransactionId(TransactionState s)
currentOwner = CurrentResourceOwner ;
CurrentResourceOwner = s - > curTransactionOwner ;
XactLockTableInsert ( s - > transactionId ) ;
XactLockTableInsert ( XidFromFullTransactionId ( s - > fullTransactionId ) ) ;
CurrentResourceOwner = currentOwner ;
@ -584,7 +664,7 @@ AssignTransactionId(TransactionState s)
*/
if ( isSubXact & & XLogStandbyInfoActive ( ) )
{
unreportedXids [ nUnreportedXids ] = s - > transactionId ;
unreportedXids [ nUnreportedXids ] = XidFromFullTransactionId ( s - > fullTransactionId ) ;
nUnreportedXids + + ;
/*
@ -832,9 +912,9 @@ TransactionIdIsCurrentTransactionId(TransactionId xid)
if ( s - > state = = TRANS_ABORT )
continue ;
if ( ! TransactionIdIsValid ( s - > t ransactionId) )
if ( ! Full TransactionIdIsValid( s - > fullT ransactionId) )
continue ; /* it can't have any child XIDs either */
if ( TransactionIdEquals ( xid , s - > transactionId ) )
if ( TransactionIdEquals ( xid , XidFromFullTransactionId ( s - > fullTransactionId ) ) )
return true ;
/* As the childXids array is ordered, we can use binary search */
low = 0 ;
@ -1495,7 +1575,7 @@ AtSubCommit_childXids(void)
* all XIDs already in the array belong to subtransactions started and
* subcommitted before us , so their XIDs must precede ours .
*/
s - > parent - > childXids [ s - > parent - > nChildXids ] = s - > transactionId ;
s - > parent - > childXids [ s - > parent - > nChildXids ] = XidFromFullTransactionId ( s - > fullTransactionId ) ;
if ( s - > nChildXids > 0 )
memcpy ( & s - > parent - > childXids [ s - > parent - > nChildXids + 1 ] ,
@ -1809,7 +1889,7 @@ StartTransaction(void)
s = & TopTransactionStateData ;
CurrentTransactionState = s ;
Assert ( XactTopTransactionId = = InvalidTransactionId ) ;
Assert ( ! FullTransactionIdIsValid ( XactTopFullTransactionId ) ) ;
/* check the current transaction state */
Assert ( s - > state = = TRANS_DEFAULT ) ;
@ -1821,7 +1901,7 @@ StartTransaction(void)
* flags are fetched below .
*/
s - > state = TRANS_START ;
s - > t ransactionId = InvalidTransactionId ; /* until assigned */
s - > fullT ransactionId = InvalidFull TransactionId ; /* until assigned */
/*
* initialize current transaction state fields
@ -2165,7 +2245,7 @@ CommitTransaction(void)
AtCommit_Memory ( ) ;
s - > t ransactionId = InvalidTransactionId ;
s - > fullT ransactionId = InvalidFull TransactionId ;
s - > subTransactionId = InvalidSubTransactionId ;
s - > nestingLevel = 0 ;
s - > gucNestLevel = 0 ;
@ -2173,7 +2253,7 @@ CommitTransaction(void)
s - > nChildXids = 0 ;
s - > maxChildXids = 0 ;
XactTopTransactionId = InvalidTransactionId ;
XactTopFull TransactionId = InvalidFull TransactionId ;
nParallelCurrentXids = 0 ;
/*
@ -2448,7 +2528,7 @@ PrepareTransaction(void)
AtCommit_Memory ( ) ;
s - > t ransactionId = InvalidTransactionId ;
s - > fullT ransactionId = InvalidFull TransactionId ;
s - > subTransactionId = InvalidSubTransactionId ;
s - > nestingLevel = 0 ;
s - > gucNestLevel = 0 ;
@ -2456,7 +2536,7 @@ PrepareTransaction(void)
s - > nChildXids = 0 ;
s - > maxChildXids = 0 ;
XactTopTransactionId = InvalidTransactionId ;
XactTopFull TransactionId = InvalidFull TransactionId ;
nParallelCurrentXids = 0 ;
/*
@ -2686,7 +2766,7 @@ CleanupTransaction(void)
AtCleanup_Memory ( ) ; /* and transaction memory */
s - > t ransactionId = InvalidTransactionId ;
s - > fullT ransactionId = InvalidFull TransactionId ;
s - > subTransactionId = InvalidSubTransactionId ;
s - > nestingLevel = 0 ;
s - > gucNestLevel = 0 ;
@ -2695,7 +2775,7 @@ CleanupTransaction(void)
s - > maxChildXids = 0 ;
s - > parallelModeLevel = 0 ;
XactTopTransactionId = InvalidTransactionId ;
XactTopFull TransactionId = InvalidFull TransactionId ;
nParallelCurrentXids = 0 ;
/*
@ -4693,7 +4773,7 @@ CommitSubTransaction(void)
*/
/* Post-commit cleanup */
if ( TransactionIdIsValid ( s - > t ransactionId) )
if ( Full TransactionIdIsValid( s - > fullT ransactionId) )
AtSubCommit_childXids ( ) ;
AfterTriggerEndSubXact ( true ) ;
AtSubCommit_Portals ( s - > subTransactionId ,
@ -4718,8 +4798,8 @@ CommitSubTransaction(void)
* The only lock we actually release here is the subtransaction XID lock .
*/
CurrentResourceOwner = s - > curTransactionOwner ;
if ( TransactionIdIsValid ( s - > t ransactionId) )
XactLockTableDelete ( s - > transactionId ) ;
if ( Full TransactionIdIsValid( s - > fullT ransactionId) )
XactLockTableDelete ( XidFromFullTransactionId ( s - > fullTransactionId ) ) ;
/*
* Other locks should get transferred to their parent resource owner .
@ -4872,7 +4952,7 @@ AbortSubTransaction(void)
( void ) RecordTransactionAbort ( true ) ;
/* Post-abort cleanup */
if ( TransactionIdIsValid ( s - > t ransactionId) )
if ( Full TransactionIdIsValid( s - > fullT ransactionId) )
AtSubAbort_childXids ( ) ;
CallSubXactCallbacks ( SUBXACT_EVENT_ABORT_SUB , s - > subTransactionId ,
@ -4985,7 +5065,7 @@ PushTransaction(void)
* We can now stack a minimally valid subtransaction without fear of
* failure .
*/
s - > t ransactionId = InvalidTransactionId ; /* until assigned */
s - > fullT ransactionId = InvalidFull TransactionId ; /* until assigned */
s - > subTransactionId = currentSubTransactionId ;
s - > parent = p ;
s - > nestingLevel = p - > nestingLevel + 1 ;
@ -5052,18 +5132,17 @@ Size
EstimateTransactionStateSpace ( void )
{
TransactionState s ;
Size nxids = 6 ; /* iso level, deferrable, top & current XID,
* command counter , XID count */
Size nxids = 0 ;
Size size = SerializedTransactionStateHeaderSize ;
for ( s = CurrentTransactionState ; s ! = NULL ; s = s - > parent )
{
if ( TransactionIdIsValid ( s - > t ransactionId) )
if ( Full TransactionIdIsValid( s - > fullT ransactionId) )
nxids = add_size ( nxids , 1 ) ;
nxids = add_size ( nxids , s - > nChildXids ) ;
}
nxids = add_size ( nxids , nParallelCurrentXids ) ;
return mul_size ( nxids , sizeof ( TransactionId ) ) ;
return add_size ( size , sizeof ( SerializedTransactionState ) * nxids ) ;
}
/*
@ -5072,14 +5151,10 @@ EstimateTransactionStateSpace(void)
* needed by a parallel worker .
*
* We need to save and restore XactDeferrable , XactIsoLevel , and the XIDs
* associated with this transaction . The first eight bytes of the result
* contain XactDeferrable and XactIsoLevel ; the next twelve bytes contain the
* XID of the top - level transaction , the XID of the current transaction
* ( or , in each case , InvalidTransactionId if none ) , and the current command
* counter . After that , the next 4 bytes contain a count of how many
* additional XIDs follow ; this is followed by all of those XIDs one after
* another . We emit the XIDs in sorted order for the convenience of the
* receiving process .
* associated with this transaction . These are serialized into a
* caller - supplied buffer big enough to hold the number of bytes reported by
* EstimateTransactionStateSpace ( ) . We emit the XIDs in sorted order for the
* convenience of the receiving process .
*/
void
SerializeTransactionState ( Size maxsize , char * start_address )
@ -5087,16 +5162,17 @@ SerializeTransactionState(Size maxsize, char *start_address)
TransactionState s ;
Size nxids = 0 ;
Size i = 0 ;
Size c = 0 ;
TransactionId * workspace ;
TransactionId * result = ( TransactionId * ) start_address ;
SerializedTransactionState * result ;
result = ( SerializedTransactionState * ) start_address ;
result [ c + + ] = ( TransactionId ) XactIsoLevel ;
result [ c + + ] = ( TransactionId ) XactDeferrable ;
result [ c + + ] = XactTopTransactionId ;
result [ c + + ] = CurrentTransactionState - > transactionId ;
result [ c + + ] = ( TransactionId ) currentCommand Id;
Assert ( maxsize > = c * sizeof ( TransactionId ) ) ;
result - > xactIsoLevel = XactIsoLevel ;
result - > xactDeferrable = XactDeferrable ;
result - > topFullTransactionId = XactTopFull TransactionId ;
result - > currentFullTransactionId =
CurrentTransactionState - > fullTransaction Id ;
result - > currentCommandId = currentCommandId ;
/*
* If we ' re running in a parallel worker and launching a parallel worker
@ -5105,9 +5181,8 @@ SerializeTransactionState(Size maxsize, char *start_address)
*/
if ( nParallelCurrentXids > 0 )
{
result [ c + + ] = nParallelCurrentXids ;
Assert ( maxsize > = ( nParallelCurrentXids + c ) * sizeof ( TransactionId ) ) ;
memcpy ( & result [ c ] , ParallelCurrentXids ,
result - > nParallelCurrentXids = nParallelCurrentXids ;
memcpy ( & result - > parallelCurrentXids [ 0 ] , ParallelCurrentXids ,
nParallelCurrentXids * sizeof ( TransactionId ) ) ;
return ;
}
@ -5118,18 +5193,19 @@ SerializeTransactionState(Size maxsize, char *start_address)
*/
for ( s = CurrentTransactionState ; s ! = NULL ; s = s - > parent )
{
if ( TransactionIdIsValid ( s - > t ransactionId) )
if ( Full TransactionIdIsValid( s - > fullT ransactionId) )
nxids = add_size ( nxids , 1 ) ;
nxids = add_size ( nxids , s - > nChildXids ) ;
}
Assert ( ( c + 1 + nxids ) * sizeof ( TransactionId ) < = maxsize ) ;
Assert ( SerializedTransactionStateHeaderSize + nxids * sizeof ( TransactionId )
< = maxsize ) ;
/* Copy them to our scratch space. */
workspace = palloc ( nxids * sizeof ( TransactionId ) ) ;
for ( s = CurrentTransactionState ; s ! = NULL ; s = s - > parent )
{
if ( TransactionIdIsValid ( s - > t ransactionId) )
workspace [ i + + ] = s - > transactionId ;
if ( Full TransactionIdIsValid( s - > fullT ransactionId) )
workspace [ i + + ] = XidFromFullTransactionId ( s - > fullTransactionId ) ;
memcpy ( & workspace [ i ] , s - > childXids ,
s - > nChildXids * sizeof ( TransactionId ) ) ;
i + = s - > nChildXids ;
@ -5140,8 +5216,9 @@ SerializeTransactionState(Size maxsize, char *start_address)
qsort ( workspace , nxids , sizeof ( TransactionId ) , xidComparator ) ;
/* Copy data into output area. */
result [ c + + ] = ( TransactionId ) nxids ;
memcpy ( & result [ c ] , workspace , nxids * sizeof ( TransactionId ) ) ;
result - > nParallelCurrentXids = nxids ;
memcpy ( & result - > parallelCurrentXids [ 0 ] , workspace ,
nxids * sizeof ( TransactionId ) ) ;
}
/*
@ -5152,18 +5229,20 @@ SerializeTransactionState(Size maxsize, char *start_address)
void
StartParallelWorkerTransaction ( char * tstatespace )
{
TransactionId * tstate = ( TransactionId * ) tstatespac e;
SerializedTransactionState * tstat e;
Assert ( CurrentTransactionState - > blockState = = TBLOCK_DEFAULT ) ;
StartTransaction ( ) ;
XactIsoLevel = ( int ) tstate [ 0 ] ;
XactDeferrable = ( bool ) tstate [ 1 ] ;
XactTopTransactionId = tstate [ 2 ] ;
CurrentTransactionState - > transactionId = tstate [ 3 ] ;
currentCommandId = tstate [ 4 ] ;
nParallelCurrentXids = ( int ) tstate [ 5 ] ;
ParallelCurrentXids = & tstate [ 6 ] ;
tstate = ( SerializedTransactionState * ) tstatespace ;
XactIsoLevel = tstate - > xactIsoLevel ;
XactDeferrable = tstate - > xactDeferrable ;
XactTopFullTransactionId = tstate - > topFullTransactionId ;
CurrentTransactionState - > fullTransactionId =
tstate - > currentFullTransactionId ;
currentCommandId = tstate - > currentCommandId ;
nParallelCurrentXids = tstate - > nParallelCurrentXids ;
ParallelCurrentXids = & tstate - > parallelCurrentXids [ 0 ] ;
CurrentTransactionState - > blockState = TBLOCK_PARALLEL_INPROGRESS ;
}
@ -5222,7 +5301,7 @@ ShowTransactionStateRec(const char *str, TransactionState s)
PointerIsValid ( s - > name ) ? s - > name : " unnamed " ,
BlockStateAsString ( s - > blockState ) ,
TransStateAsString ( s - > state ) ,
( unsigned int ) s - > transactionId ,
( unsigned int ) XidFromFullTransactionId ( s - > fullTransactionId ) ,
( unsigned int ) s - > subTransactionId ,
( unsigned int ) currentCommandId ,
currentCommandIdUsed ? " (used) " : " " ,