@ -86,7 +86,7 @@ static void compute_new_xmax_infomask(TransactionId xmax, uint16 old_infomask,
LockTupleMode mode , bool is_update ,
TransactionId * result_xmax , uint16 * result_infomask ,
uint16 * result_infomask2 ) ;
static HTSU _Result heap_lock_updated_tuple ( Relation rel , HeapTuple tuple ,
static TM _Result heap_lock_updated_tuple ( Relation rel , HeapTuple tuple ,
ItemPointer ctid , TransactionId xid ,
LockTupleMode mode ) ;
static void GetMultiXactIdHintBits ( MultiXactId multi , uint16 * new_infomask ,
@ -1389,7 +1389,6 @@ heap_fetch(Relation relation,
Snapshot snapshot ,
HeapTuple tuple ,
Buffer * userbuf ,
bool keep_buf ,
Relation stats_relation )
{
ItemPointer tid = & ( tuple - > t_self ) ;
@ -1419,13 +1418,8 @@ heap_fetch(Relation relation,
if ( offnum < FirstOffsetNumber | | offnum > PageGetMaxOffsetNumber ( page ) )
{
LockBuffer ( buffer , BUFFER_LOCK_UNLOCK ) ;
if ( keep_buf )
* userbuf = buffer ;
else
{
ReleaseBuffer ( buffer ) ;
* userbuf = InvalidBuffer ;
}
ReleaseBuffer ( buffer ) ;
* userbuf = InvalidBuffer ;
tuple - > t_data = NULL ;
return false ;
}
@ -1441,13 +1435,8 @@ heap_fetch(Relation relation,
if ( ! ItemIdIsNormal ( lp ) )
{
LockBuffer ( buffer , BUFFER_LOCK_UNLOCK ) ;
if ( keep_buf )
* userbuf = buffer ;
else
{
ReleaseBuffer ( buffer ) ;
* userbuf = InvalidBuffer ;
}
ReleaseBuffer ( buffer ) ;
* userbuf = InvalidBuffer ;
tuple - > t_data = NULL ;
return false ;
}
@ -1486,14 +1475,9 @@ heap_fetch(Relation relation,
return true ;
}
/* Tuple failed time qual, but maybe caller wants to see it anyway. */
if ( keep_buf )
* userbuf = buffer ;
else
{
ReleaseBuffer ( buffer ) ;
* userbuf = InvalidBuffer ;
}
/* Tuple failed time qual */
ReleaseBuffer ( buffer ) ;
* userbuf = InvalidBuffer ;
return false ;
}
@ -1886,40 +1870,12 @@ ReleaseBulkInsertStatePin(BulkInsertState bistate)
* The new tuple is stamped with current transaction ID and the specified
* command ID .
*
* If the HEAP_INSERT_SKIP_WAL option is specified , the new tuple is not
* logged in WAL , even for a non - temp relation . Safe usage of this behavior
* requires that we arrange that all new tuples go into new pages not
* containing any tuples from other transactions , and that the relation gets
* fsync ' d before commit . ( See also heap_sync ( ) comments )
*
* The HEAP_INSERT_SKIP_FSM option is passed directly to
* RelationGetBufferForTuple , which see for more info .
*
* HEAP_INSERT_FROZEN should only be specified for inserts into
* relfilenodes created during the current subtransaction and when
* there are no prior snapshots or pre - existing portals open .
* This causes rows to be frozen , which is an MVCC violation and
* requires explicit options chosen by user .
*
* HEAP_INSERT_SPECULATIVE is used on so - called " speculative insertions " ,
* which can be backed out afterwards without aborting the whole transaction .
* Other sessions can wait for the speculative insertion to be confirmed ,
* turning it into a regular tuple , or aborted , as if it never existed .
* Speculatively inserted tuples behave as " value locks " of short duration ,
* used to implement INSERT . . ON CONFLICT .
*
* HEAP_INSERT_NO_LOGICAL force - disables the emitting of logical decoding
* information for the tuple . This should solely be used during table rewrites
* where RelationIsLogicallyLogged ( relation ) is not yet accurate for the new
* relation .
*
* Note that most of these options will be applied when inserting into the
* heap ' s TOAST table , too , if the tuple requires any out - of - line data . Only
* HEAP_INSERT_SPECULATIVE is explicitly ignored , as the toast data does not
* partake in speculative insertion .
* See table_insert for comments about most of the input flags , except that
* this routine directly takes a tuple rather than a slot .
*
* The BulkInsertState object ( if any ; bistate can be NULL for default
* behavior ) is also just passed through to RelationGetBufferForTuple .
* There ' s corresponding HEAP_INSERT_ options to all the TABLE_INSERT_
* options , and there additionally is HEAP_INSERT_SPECULATIVE which is used to
* implement table_insert_speculative ( ) .
*
* On return the header fields of * tup are updated to match the stored tuple ;
* in particular tup - > t_self receives the actual TID where the tuple was
@ -2489,36 +2445,20 @@ xmax_infomask_changed(uint16 new_infomask, uint16 old_infomask)
/*
* heap_delete - delete a tuple
*
* NB : do not call this directly unless you are prepared to deal with
* concurrent - update conditions . Use simple_heap_delete instead .
* See table_delete ( ) for an explanation of the parameters , except that this
* routine directly takes a tuple rather than a slot .
*
* relation - table to be modified ( caller must hold suitable lock )
* tid - TID of tuple to be deleted
* cid - delete command ID ( used for visibility test , and stored into
* cmax if successful )
* crosscheck - if not InvalidSnapshot , also check tuple against this
* wait - true if should wait for any conflicting update to commit / abort
* hufd - output parameter , filled in failure cases ( see below )
* changingPart - true iff the tuple is being moved to another partition
* table due to an update of the partition key . Otherwise , false .
*
* Normal , successful return value is HeapTupleMayBeUpdated , which
* actually means we did delete it . Failure return codes are
* HeapTupleSelfUpdated , HeapTupleUpdated , or HeapTupleBeingUpdated
* ( the last only possible if wait = = false ) .
*
* In the failure cases , the routine fills * hufd with the tuple ' s t_ctid ,
* t_xmax ( resolving a possible MultiXact , if necessary ) , and t_cmax
* ( the last only for HeapTupleSelfUpdated , since we
* cannot obtain cmax from a combocid generated by another transaction ) .
* See comments for struct HeapUpdateFailureData for additional info .
* In the failure cases , the routine fills * tmfd with the tuple ' s t_ctid ,
* t_xmax ( resolving a possible MultiXact , if necessary ) , and t_cmax ( the last
* only for TM_SelfModified , since we cannot obtain cmax from a combocid
* generated by another transaction ) .
*/
HTSU _Result
TM_Result
heap_delete ( Relation relation , ItemPointer tid ,
CommandId cid , Snapshot crosscheck , bool wait ,
HeapUpdateFailureData * hu fd, bool changingPart )
TM_FailureData * tmfd , bool changingPart )
{
HTSU_Result result ;
TM_Result result ;
TransactionId xid = GetCurrentTransactionId ( ) ;
ItemId lp ;
HeapTupleData tp ;
@ -2586,14 +2526,14 @@ heap_delete(Relation relation, ItemPointer tid,
l1 :
result = HeapTupleSatisfiesUpdate ( & tp , cid , buffer ) ;
if ( result = = HeapTuple Invisible)
if ( result = = TM_ Invisible)
{
UnlockReleaseBuffer ( buffer ) ;
ereport ( ERROR ,
( errcode ( ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE ) ,
errmsg ( " attempted to delete invisible tuple " ) ) ) ;
}
else if ( result = = HeapTupleBeingUpdat ed & & wait )
else if ( result = = TM_BeingModifi ed & & wait )
{
TransactionId xwait ;
uint16 infomask ;
@ -2687,30 +2627,36 @@ l1:
if ( ( tp . t_data - > t_infomask & HEAP_XMAX_INVALID ) | |
HEAP_XMAX_IS_LOCKED_ONLY ( tp . t_data - > t_infomask ) | |
HeapTupleHeaderIsOnlyLocked ( tp . t_data ) )
result = HeapTupleMayBeUpdated ;
result = TM_Ok ;
else if ( ! ItemPointerEquals ( & tp . t_self , & tp . t_data - > t_ctid ) | |
HeapTupleHeaderIndicatesMovedPartitions ( tp . t_data ) )
result = TM_Updated ;
else
result = HeapTupleUpdated ;
result = TM_Dele ted;
}
if ( crosscheck ! = InvalidSnapshot & & result = = HeapTupleMayBeUpdated )
if ( crosscheck ! = InvalidSnapshot & & result = = TM_Ok )
{
/* Perform additional check for transaction-snapshot mode RI updates */
if ( ! HeapTupleSatisfiesVisibility ( & tp , crosscheck , buffer ) )
result = HeapTuple Updated;
result = TM_ Updated;
}
if ( result ! = HeapTupleMayBeUpdated )
if ( result ! = TM_Ok )
{
Assert ( result = = HeapTupleSelfUpdated | |
result = = HeapTupleUpdated | |
result = = HeapTupleBeingUpdated ) ;
Assert ( result = = TM_SelfModified | |
result = = TM_Updated | |
result = = TM_Deleted | |
result = = TM_BeingModified ) ;
Assert ( ! ( tp . t_data - > t_infomask & HEAP_XMAX_INVALID ) ) ;
hufd - > ctid = tp . t_data - > t_ctid ;
hufd - > xmax = HeapTupleHeaderGetUpdateXid ( tp . t_data ) ;
if ( result = = HeapTupleSelfUpdated )
hufd - > cmax = HeapTupleHeaderGetCmax ( tp . t_data ) ;
Assert ( result ! = TM_Updated | |
! ItemPointerEquals ( & tp . t_self , & tp . t_data - > t_ctid ) ) ;
tmfd - > ctid = tp . t_data - > t_ctid ;
tmfd - > xmax = HeapTupleHeaderGetUpdateXid ( tp . t_data ) ;
if ( result = = TM_SelfModified )
tmfd - > cmax = HeapTupleHeaderGetCmax ( tp . t_data ) ;
else
hufd - > cmax = InvalidCommandId ;
tm fd- > cmax = InvalidCommandId ;
UnlockReleaseBuffer ( buffer ) ;
if ( have_tuple_lock )
UnlockTupleTuplock ( relation , & ( tp . t_self ) , LockTupleExclusive ) ;
@ -2896,7 +2842,7 @@ l1:
if ( old_key_tuple ! = NULL & & old_key_copied )
heap_freetuple ( old_key_tuple ) ;
return HeapTupleMayBeUpdated ;
return TM_Ok ;
}
/*
@ -2910,28 +2856,32 @@ l1:
void
simple_heap_delete ( Relation relation , ItemPointer tid )
{
HTSU_Result result ;
HeapUpdateFailureData hu fd;
TM_Result result ;
TM_FailureData tm fd;
result = heap_delete ( relation , tid ,
GetCurrentCommandId ( true ) , InvalidSnapshot ,
true /* wait for commit */ ,
& hu fd, false /* changingPart */ ) ;
& tm fd, false /* changingPart */ ) ;
switch ( result )
{
case HeapTupleSelfUpdat ed:
case TM_SelfModifi ed:
/* Tuple was already updated in current command? */
elog ( ERROR , " tuple already updated by self " ) ;
break ;
case HeapTupleMayBeUpdated :
case TM_Ok :
/* done successfully */
break ;
case HeapTuple Updated:
case TM_ Updated:
elog ( ERROR , " tuple concurrently updated " ) ;
break ;
case TM_Deleted :
elog ( ERROR , " tuple concurrently deleted " ) ;
break ;
default :
elog ( ERROR , " unrecognized heap_delete status: %u " , result ) ;
break ;
@ -2941,42 +2891,20 @@ simple_heap_delete(Relation relation, ItemPointer tid)
/*
* heap_update - replace a tuple
*
* NB : do not call this directly unless you are prepared to deal with
* concurrent - update conditions . Use simple_heap_update instead .
*
* relation - table to be modified ( caller must hold suitable lock )
* otid - TID of old tuple to be replaced
* newtup - newly constructed tuple data to store
* cid - update command ID ( used for visibility test , and stored into
* cmax / cmin if successful )
* crosscheck - if not InvalidSnapshot , also check old tuple against this
* wait - true if should wait for any conflicting update to commit / abort
* hufd - output parameter , filled in failure cases ( see below )
* lockmode - output parameter , filled with lock mode acquired on tuple
*
* Normal , successful return value is HeapTupleMayBeUpdated , which
* actually means we * did * update it . Failure return codes are
* HeapTupleSelfUpdated , HeapTupleUpdated , or HeapTupleBeingUpdated
* ( the last only possible if wait = = false ) .
* See table_update ( ) for an explanation of the parameters , except that this
* routine directly takes a tuple rather than a slot .
*
* On success , the header fields of * newtup are updated to match the new
* stored tuple ; in particular , newtup - > t_self is set to the TID where the
* new tuple was inserted , and its HEAP_ONLY_TUPLE flag is set iff a HOT
* update was done . However , any TOAST changes in the new tuple ' s
* data are not reflected into * newtup .
*
* In the failure cases , the routine fills * hufd with the tuple ' s t_ctid ,
* t_xmax ( resolving a possible MultiXact , if necessary ) , and t_cmax
* ( the last only for HeapTupleSelfUpdated , since we
* cannot obtain cmax from a combocid generated by another transaction ) .
* See comments for struct HeapUpdateFailureData for additional info .
* In the failure cases , the routine fills * tmfd with the tuple ' s t_ctid ,
* t_xmax ( resolving a possible MultiXact , if necessary ) , and t_cmax ( the last
* only for TM_SelfModified , since we cannot obtain cmax from a combocid
* generated by another transaction ) .
*/
HTSU _Result
TM_Result
heap_update ( Relation relation , ItemPointer otid , HeapTuple newtup ,
CommandId cid , Snapshot crosscheck , bool wait ,
HeapUpdateFailureData * hu fd, LockTupleMode * lockmode )
TM_FailureData * tmfd , LockTupleMode * lockmode )
{
HTSU_Result result ;
TM_Result result ;
TransactionId xid = GetCurrentTransactionId ( ) ;
Bitmapset * hot_attrs ;
Bitmapset * key_attrs ;
@ -3150,16 +3078,16 @@ l2:
result = HeapTupleSatisfiesUpdate ( & oldtup , cid , buffer ) ;
/* see below about the "no wait" case */
Assert ( result ! = HeapTupleBeingUpdat ed | | wait ) ;
Assert ( result ! = TM_BeingModifi ed | | wait ) ;
if ( result = = HeapTuple Invisible)
if ( result = = TM_ Invisible)
{
UnlockReleaseBuffer ( buffer ) ;
ereport ( ERROR ,
( errcode ( ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE ) ,
errmsg ( " attempted to update invisible tuple " ) ) ) ;
}
else if ( result = = HeapTupleBeingUpdat ed & & wait )
else if ( result = = TM_BeingModifi ed & & wait )
{
TransactionId xwait ;
uint16 infomask ;
@ -3250,7 +3178,7 @@ l2:
* MultiXact . In that case , we need to check whether it committed
* or aborted . If it aborted we are safe to update it again ;
* otherwise there is an update conflict , and we have to return
* HeapTupleUpdated below .
* TableTuple { Deleted , Updated } below .
*
* In the LockTupleExclusive case , we still need to preserve the
* surviving members : those would include the tuple locks we had
@ -3322,28 +3250,40 @@ l2:
can_continue = true ;
}
result = can_continue ? HeapTupleMayBeUpdated : HeapTupleUpdated ;
if ( can_continue )
result = TM_Ok ;
else if ( ! ItemPointerEquals ( & oldtup . t_self , & oldtup . t_data - > t_ctid ) | |
HeapTupleHeaderIndicatesMovedPartitions ( oldtup . t_data ) )
result = TM_Updated ;
else
result = TM_Deleted ;
}
if ( crosscheck ! = InvalidSnapshot & & result = = HeapTupleMayBeUpdated )
if ( crosscheck ! = InvalidSnapshot & & result = = TM_Ok )
{
/* Perform additional check for transaction-snapshot mode RI updates */
if ( ! HeapTupleSatisfiesVisibility ( & oldtup , crosscheck , buffer ) )
result = HeapTupleUpdated ;
{
result = TM_Updated ;
Assert ( ! ItemPointerEquals ( & oldtup . t_self , & oldtup . t_data - > t_ctid ) ) ;
}
}
if ( result ! = HeapTupleMayBeUpdated )
if ( result ! = TM_Ok )
{
Assert ( result = = HeapTupleSelfUpdated | |
result = = HeapTupleUpdated | |
result = = HeapTupleBeingUpdated ) ;
Assert ( result = = TM_SelfModified | |
result = = TM_Updated | |
result = = TM_Deleted | |
result = = TM_BeingModified ) ;
Assert ( ! ( oldtup . t_data - > t_infomask & HEAP_XMAX_INVALID ) ) ;
hufd - > ctid = oldtup . t_data - > t_ctid ;
hufd - > xmax = HeapTupleHeaderGetUpdateXid ( oldtup . t_data ) ;
if ( result = = HeapTupleSelfUpdated )
hufd - > cmax = HeapTupleHeaderGetCmax ( oldtup . t_data ) ;
Assert ( result ! = TM_Updated | |
! ItemPointerEquals ( & oldtup . t_self , & oldtup . t_data - > t_ctid ) ) ;
tmfd - > ctid = oldtup . t_data - > t_ctid ;
tmfd - > xmax = HeapTupleHeaderGetUpdateXid ( oldtup . t_data ) ;
if ( result = = TM_SelfModified )
tmfd - > cmax = HeapTupleHeaderGetCmax ( oldtup . t_data ) ;
else
hufd - > cmax = InvalidCommandId ;
tm fd- > cmax = InvalidCommandId ;
UnlockReleaseBuffer ( buffer ) ;
if ( have_tuple_lock )
UnlockTupleTuplock ( relation , & ( oldtup . t_self ) , * lockmode ) ;
@ -3828,7 +3768,7 @@ l2:
bms_free ( modified_attrs ) ;
bms_free ( interesting_attrs ) ;
return HeapTupleMayBeUpdated ;
return TM_Ok ;
}
/*
@ -3948,29 +3888,33 @@ HeapDetermineModifiedColumns(Relation relation, Bitmapset *interesting_cols,
void
simple_heap_update ( Relation relation , ItemPointer otid , HeapTuple tup )
{
HTSU_Result result ;
HeapUpdateFailureData hu fd;
TM_Result result ;
TM_FailureData tm fd;
LockTupleMode lockmode ;
result = heap_update ( relation , otid , tup ,
GetCurrentCommandId ( true ) , InvalidSnapshot ,
true /* wait for commit */ ,
& hu fd, & lockmode ) ;
& tm fd, & lockmode ) ;
switch ( result )
{
case HeapTupleSelfUpdat ed:
case TM_SelfModifi ed:
/* Tuple was already updated in current command? */
elog ( ERROR , " tuple already updated by self " ) ;
break ;
case HeapTupleMayBeUpdated :
case TM_Ok :
/* done successfully */
break ;
case HeapTuple Updated:
case TM_ Updated:
elog ( ERROR , " tuple concurrently updated " ) ;
break ;
case TM_Deleted :
elog ( ERROR , " tuple concurrently deleted " ) ;
break ;
default :
elog ( ERROR , " unrecognized heap_update status: %u " , result ) ;
break ;
@ -4005,7 +3949,7 @@ get_mxact_status_for_lock(LockTupleMode mode, bool is_update)
*
* Input parameters :
* relation : relation containing tuple ( caller must hold suitable lock )
* tuple - > t_self : TID of tuple to lock ( rest of struct need not be valid )
* tid : TID of tuple to lock
* cid : current command ID ( used for visibility test , and stored into
* tuple ' s cmax if lock is successful )
* mode : indicates if shared or exclusive tuple lock is desired
@ -4016,31 +3960,26 @@ get_mxact_status_for_lock(LockTupleMode mode, bool is_update)
* Output parameters :
* * tuple : all fields filled in
* * buffer : set to buffer holding tuple ( pinned but not locked at exit )
* * hu fd: filled in failure cases ( see below )
* * tm fd: filled in failure cases ( see below )
*
* Function result may be :
* HeapTupleMayBeUpdated : lock was successfully acquired
* HeapTupleInvisible : lock failed because tuple was never visible to us
* HeapTupleSelfUpdated : lock failed because tuple updated by self
* HeapTupleUpdated : lock failed because tuple updated by other xact
* HeapTupleWouldBlock : lock couldn ' t be acquired and wait_policy is skip
* Function results are the same as the ones for table_lock_tuple ( ) .
*
* In the failure cases other than HeapTuple Invisible, the routine fills
* * hu fd with the tuple ' s t_ctid , t_xmax ( resolving a possible MultiXact ,
* if necessary ) , and t_cmax ( the last only for HeapTupleSelfUpdat ed,
* In the failure cases other than TM_Invisible , the routine fills
* * tmfd with the tuple ' s t_ctid , t_xmax ( resolving a possible MultiXact ,
* if necessary ) , and t_cmax ( the last only for TM_SelfModified ,
* since we cannot obtain cmax from a combocid generated by another
* transaction ) .
* See comments for struct HeapUpdate FailureData for additional info .
* See comments for struct TM_ FailureData for additional info .
*
* See README . tuplock for a thorough explanation of this mechanism .
*/
HTSU _Result
TM _Result
heap_lock_tuple ( Relation relation , HeapTuple tuple ,
CommandId cid , LockTupleMode mode , LockWaitPolicy wait_policy ,
bool follow_updates ,
Buffer * buffer , HeapUpdateFailureData * hu fd)
Buffer * buffer , TM_FailureData * tm fd)
{
HTSU_Result result ;
TM_Result result ;
ItemPointer tid = & ( tuple - > t_self ) ;
ItemId lp ;
Page page ;
@ -4080,7 +4019,7 @@ heap_lock_tuple(Relation relation, HeapTuple tuple,
l3 :
result = HeapTupleSatisfiesUpdate ( tuple , cid , * buffer ) ;
if ( result = = HeapTuple Invisible)
if ( result = = TM_ Invisible)
{
/*
* This is possible , but only when locking a tuple for ON CONFLICT
@ -4088,10 +4027,12 @@ l3:
* order to give that case the opportunity to throw a more specific
* error .
*/
result = HeapTuple Invisible;
result = TM_ Invisible;
goto out_locked ;
}
else if ( result = = HeapTupleBeingUpdated | | result = = HeapTupleUpdated )
else if ( result = = TM_BeingModified | |
result = = TM_Updated | |
result = = TM_Deleted )
{
TransactionId xwait ;
uint16 infomask ;
@ -4147,7 +4088,7 @@ l3:
if ( TUPLOCK_from_mxstatus ( members [ i ] . status ) > = mode )
{
pfree ( members ) ;
result = HeapTupleMayBeUpdated ;
result = TM_Ok ;
goto out_unlocked ;
}
}
@ -4163,20 +4104,20 @@ l3:
Assert ( HEAP_XMAX_IS_KEYSHR_LOCKED ( infomask ) | |
HEAP_XMAX_IS_SHR_LOCKED ( infomask ) | |
HEAP_XMAX_IS_EXCL_LOCKED ( infomask ) ) ;
result = HeapTupleMayBeUpdated ;
result = TM_Ok ;
goto out_unlocked ;
case LockTupleShare :
if ( HEAP_XMAX_IS_SHR_LOCKED ( infomask ) | |
HEAP_XMAX_IS_EXCL_LOCKED ( infomask ) )
{
result = HeapTupleMayBeUpdated ;
result = TM_Ok ;
goto out_unlocked ;
}
break ;
case LockTupleNoKeyExclusive :
if ( HEAP_XMAX_IS_EXCL_LOCKED ( infomask ) )
{
result = HeapTupleMayBeUpdated ;
result = TM_Ok ;
goto out_unlocked ;
}
break ;
@ -4184,7 +4125,7 @@ l3:
if ( HEAP_XMAX_IS_EXCL_LOCKED ( infomask ) & &
infomask2 & HEAP_KEYS_UPDATED )
{
result = HeapTupleMayBeUpdated ;
result = TM_Ok ;
goto out_unlocked ;
}
break ;
@ -4233,12 +4174,12 @@ l3:
*/
if ( follow_updates & & updated )
{
HTSU_Result res ;
TM_Result res ;
res = heap_lock_updated_tuple ( relation , tuple , & t_ctid ,
GetCurrentTransactionId ( ) ,
mode ) ;
if ( res ! = HeapTupleMayBeUpdated )
if ( res ! = TM_Ok )
{
result = res ;
/* recovery code expects to have buffer lock held */
@ -4363,15 +4304,15 @@ l3:
/*
* Time to sleep on the other transaction / multixact , if necessary .
*
* If the other transaction is an update that ' s already committed ,
* then sleeping cannot possibly do any good : if we ' re required to
* sleep , get out to raise an error instead .
* If the other transaction is an update / delete that ' s already
* committed , then sleeping cannot possibly do any good : if we ' re
* required to sleep , get out to raise an error instead .
*
* By here , we either have already acquired the buffer exclusive lock ,
* or we must wait for the locking transaction or multixact ; so below
* we ensure that we grab buffer lock after the sleep .
*/
if ( require_sleep & & result = = HeapTupleUpdated )
if ( require_sleep & & ( result = = TM_Updated | | result = = TM_Deleted ) )
{
LockBuffer ( * buffer , BUFFER_LOCK_EXCLUSIVE ) ;
goto failed ;
@ -4394,7 +4335,7 @@ l3:
* This can only happen if wait_policy is Skip and the lock
* couldn ' t be obtained .
*/
result = HeapTuple WouldBlock;
result = TM_ WouldBlock;
/* recovery code expects to have buffer lock held */
LockBuffer ( * buffer , BUFFER_LOCK_EXCLUSIVE ) ;
goto failed ;
@ -4420,7 +4361,7 @@ l3:
status , infomask , relation ,
NULL ) )
{
result = HeapTuple WouldBlock;
result = TM_ WouldBlock;
/* recovery code expects to have buffer lock held */
LockBuffer ( * buffer , BUFFER_LOCK_EXCLUSIVE ) ;
goto failed ;
@ -4460,7 +4401,7 @@ l3:
case LockWaitSkip :
if ( ! ConditionalXactLockTableWait ( xwait ) )
{
result = HeapTuple WouldBlock;
result = TM_ WouldBlock;
/* recovery code expects to have buffer lock held */
LockBuffer ( * buffer , BUFFER_LOCK_EXCLUSIVE ) ;
goto failed ;
@ -4479,12 +4420,12 @@ l3:
/* if there are updates, follow the update chain */
if ( follow_updates & & ! HEAP_XMAX_IS_LOCKED_ONLY ( infomask ) )
{
HTSU_Result res ;
TM_Result res ;
res = heap_lock_updated_tuple ( relation , tuple , & t_ctid ,
GetCurrentTransactionId ( ) ,
mode ) ;
if ( res ! = HeapTupleMayBeUpdated )
if ( res ! = TM_Ok )
{
result = res ;
/* recovery code expects to have buffer lock held */
@ -4530,23 +4471,28 @@ l3:
( tuple - > t_data - > t_infomask & HEAP_XMAX_INVALID ) | |
HEAP_XMAX_IS_LOCKED_ONLY ( tuple - > t_data - > t_infomask ) | |
HeapTupleHeaderIsOnlyLocked ( tuple - > t_data ) )
result = HeapTupleMayBeUpdated ;
result = TM_Ok ;
else if ( ! ItemPointerEquals ( & tuple - > t_self , & tuple - > t_data - > t_ctid ) | |
HeapTupleHeaderIndicatesMovedPartitions ( tuple - > t_data ) )
result = TM_Updated ;
else
result = HeapTupleUpdated ;
result = TM_Dele ted;
}
failed :
if ( result ! = HeapTupleMayBeUpdated )
if ( result ! = TM_Ok )
{
Assert ( result = = HeapTupleSelfUpdat ed | | result = = HeapTuple Updated | |
result = = HeapTuple WouldBlock) ;
Assert ( result = = TM_SelfModifi ed | | result = = TM_ Updated | |
result = = TM_Deleted | | result = = TM_ WouldBlock) ;
Assert ( ! ( tuple - > t_data - > t_infomask & HEAP_XMAX_INVALID ) ) ;
hufd - > ctid = tuple - > t_data - > t_ctid ;
hufd - > xmax = HeapTupleHeaderGetUpdateXid ( tuple - > t_data ) ;
if ( result = = HeapTupleSelfUpdated )
hufd - > cmax = HeapTupleHeaderGetCmax ( tuple - > t_data ) ;
Assert ( result ! = TM_Updated | |
! ItemPointerEquals ( & tuple - > t_self , & tuple - > t_data - > t_ctid ) ) ;
tmfd - > ctid = tuple - > t_data - > t_ctid ;
tmfd - > xmax = HeapTupleHeaderGetUpdateXid ( tuple - > t_data ) ;
if ( result = = TM_SelfModified )
tmfd - > cmax = HeapTupleHeaderGetCmax ( tuple - > t_data ) ;
else
hufd - > cmax = InvalidCommandId ;
tm fd- > cmax = InvalidCommandId ;
goto out_locked ;
}
@ -4664,7 +4610,7 @@ failed:
END_CRIT_SECTION ( ) ;
result = HeapTupleMayBeUpdated ;
result = TM_Ok ;
out_locked :
LockBuffer ( * buffer , BUFFER_LOCK_UNLOCK ) ;
@ -5021,19 +4967,19 @@ l5:
* Given a hypothetical multixact status held by the transaction identified
* with the given xid , does the current transaction need to wait , fail , or can
* it continue if it wanted to acquire a lock of the given mode ? " needwait "
* is set to true if waiting is necessary ; if it can continue , then
* HeapTupleMayBeUpdated is returned . If the lock is already held by the
* current transaction , return HeapTupleSelfUpdated . In case of a conflict
* with another transaction , a different HeapTupleSatisfiesUpdate return code
* is returned .
* is set to true if waiting is necessary ; if it can continue , then TM_Ok is
* returned . If the lock is already held by the current transaction , return
* TM_SelfModified . In case of a conflict with another transaction , a
* different HeapTupleSatisfiesUpdate return code is returned .
*
* The held status is said to be hypothetical because it might correspond to a
* lock held by a single Xid , i . e . not a real MultiXactId ; we express it this
* way for simplicity of API .
*/
static HTSU _Result
static TM _Result
test_lockmode_for_conflict ( MultiXactStatus status , TransactionId xid ,
LockTupleMode mode , bool * needwait )
LockTupleMode mode , HeapTuple tup ,
bool * needwait )
{
MultiXactStatus wantedstatus ;
@ -5052,7 +4998,7 @@ test_lockmode_for_conflict(MultiXactStatus status, TransactionId xid,
* very rare but can happen if multiple transactions are trying to
* lock an ancient version of the same tuple .
*/
return HeapTupleSelfUpdat ed;
return TM_SelfModifi ed;
}
else if ( TransactionIdIsInProgress ( xid ) )
{
@ -5072,10 +5018,10 @@ test_lockmode_for_conflict(MultiXactStatus status, TransactionId xid,
* If we set needwait above , then this value doesn ' t matter ;
* otherwise , this value signals to caller that it ' s okay to proceed .
*/
return HeapTupleMayBeUpdated ;
return TM_Ok ;
}
else if ( TransactionIdDidAbort ( xid ) )
return HeapTupleMayBeUpdated ;
return TM_Ok ;
else if ( TransactionIdDidCommit ( xid ) )
{
/*
@ -5094,18 +5040,24 @@ test_lockmode_for_conflict(MultiXactStatus status, TransactionId xid,
* always be checked .
*/
if ( ! ISUPDATE_from_mxstatus ( status ) )
return HeapTupleMayBeUpdated ;
return TM_Ok ;
if ( DoLockModesConflict ( LOCKMODE_from_mxstatus ( status ) ,
LOCKMODE_from_mxstatus ( wantedstatus ) ) )
{
/* bummer */
return HeapTupleUpdated ;
if ( ! ItemPointerEquals ( & tup - > t_self , & tup - > t_data - > t_ctid ) | |
HeapTupleHeaderIndicatesMovedPartitions ( tup - > t_data ) )
return TM_Updated ;
else
return TM_Deleted ;
}
return HeapTupleMayBeUpdated ;
return TM_Ok ;
}
/* Not in progress, not aborted, not committed -- must have crashed */
return HeapTupleMayBeUpdated ;
return TM_Ok ;
}
@ -5116,11 +5068,11 @@ test_lockmode_for_conflict(MultiXactStatus status, TransactionId xid,
* xid with the given mode ; if this tuple is updated , recurse to lock the new
* version as well .
*/
static HTSU _Result
static TM _Result
heap_lock_updated_tuple_rec ( Relation rel , ItemPointer tid , TransactionId xid ,
LockTupleMode mode )
{
HTSU_Result result ;
TM_Result result ;
ItemPointerData tupid ;
HeapTupleData mytup ;
Buffer buf ;
@ -5145,7 +5097,7 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
block = ItemPointerGetBlockNumber ( & tupid ) ;
ItemPointerCopy ( & tupid , & ( mytup . t_self ) ) ;
if ( ! heap_fetch ( rel , SnapshotAny , & mytup , & buf , false , NULL ) )
if ( ! heap_fetch ( rel , SnapshotAny , & mytup , & buf , NULL ) )
{
/*
* if we fail to find the updated version of the tuple , it ' s
@ -5154,7 +5106,7 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
* chain , and there ' s no further tuple to lock : return success to
* caller .
*/
result = HeapTupleMayBeUpdated ;
result = TM_Ok ;
goto out_unlocked ;
}
@ -5203,7 +5155,7 @@ l4:
! TransactionIdEquals ( HeapTupleHeaderGetXmin ( mytup . t_data ) ,
priorXmax ) )
{
result = HeapTupleMayBeUpdated ;
result = TM_Ok ;
goto out_locked ;
}
@ -5214,7 +5166,7 @@ l4:
*/
if ( TransactionIdDidAbort ( HeapTupleHeaderGetXmin ( mytup . t_data ) ) )
{
result = HeapTupleMayBeUpdated ;
result = TM_Ok ;
goto out_locked ;
}
@ -5257,7 +5209,9 @@ l4:
{
result = test_lockmode_for_conflict ( members [ i ] . status ,
members [ i ] . xid ,
mode , & needwait ) ;
mode ,
& mytup ,
& needwait ) ;
/*
* If the tuple was already locked by ourselves in a
@ -5269,7 +5223,7 @@ l4:
* this tuple and continue locking the next version in the
* update chain .
*/
if ( result = = HeapTupleSelfUpdat ed)
if ( result = = TM_SelfModifi ed)
{
pfree ( members ) ;
goto next ;
@ -5284,7 +5238,7 @@ l4:
pfree ( members ) ;
goto l4 ;
}
if ( result ! = HeapTupleMayBeUpdated )
if ( result ! = TM_Ok )
{
pfree ( members ) ;
goto out_locked ;
@ -5334,7 +5288,7 @@ l4:
}
result = test_lockmode_for_conflict ( status , rawxmax , mode ,
& needwait ) ;
& mytup , & needwait ) ;
/*
* If the tuple was already locked by ourselves in a previous
@ -5345,7 +5299,7 @@ l4:
* either . We just need to skip this tuple and continue
* locking the next version in the update chain .
*/
if ( result = = HeapTupleSelfUpdat ed)
if ( result = = TM_SelfModifi ed)
goto next ;
if ( needwait )
@ -5355,7 +5309,7 @@ l4:
XLTW_LockUpdated ) ;
goto l4 ;
}
if ( result ! = HeapTupleMayBeUpdated )
if ( result ! = TM_Ok )
{
goto out_locked ;
}
@ -5415,7 +5369,7 @@ next:
ItemPointerEquals ( & mytup . t_self , & mytup . t_data - > t_ctid ) | |
HeapTupleHeaderIsOnlyLocked ( mytup . t_data ) )
{
result = HeapTupleMayBeUpdated ;
result = TM_Ok ;
goto out_locked ;
}
@ -5425,7 +5379,7 @@ next:
UnlockReleaseBuffer ( buf ) ;
}
result = HeapTupleMayBeUpdated ;
result = TM_Ok ;
out_locked :
UnlockReleaseBuffer ( buf ) ;
@ -5459,7 +5413,7 @@ out_unlocked:
* transaction cannot be using repeatable read or serializable isolation
* levels , because that would lead to a serializability failure .
*/
static HTSU _Result
static TM _Result
heap_lock_updated_tuple ( Relation rel , HeapTuple tuple , ItemPointer ctid ,
TransactionId xid , LockTupleMode mode )
{
@ -5485,7 +5439,7 @@ heap_lock_updated_tuple(Relation rel, HeapTuple tuple, ItemPointer ctid,
}
/* nothing to lock */
return HeapTupleMayBeUpdated ;
return TM_Ok ;
}
/*
@ -5505,7 +5459,7 @@ heap_lock_updated_tuple(Relation rel, HeapTuple tuple, ItemPointer ctid,
* An explicit confirmation WAL record also makes logical decoding simpler .
*/
void
heap_finish_speculative ( Relation relation , HeapTuple tuple )
heap_finish_speculative ( Relation relation , ItemPointer tid )
{
Buffer buffer ;
Page page ;
@ -5513,11 +5467,11 @@ heap_finish_speculative(Relation relation, HeapTuple tuple)
ItemId lp = NULL ;
HeapTupleHeader htup ;
buffer = ReadBuffer ( relation , ItemPointerGetBlockNumber ( & ( tuple - > t_self ) ) ) ;
buffer = ReadBuffer ( relation , ItemPointerGetBlockNumber ( tid ) ) ;
LockBuffer ( buffer , BUFFER_LOCK_EXCLUSIVE ) ;
page = ( Page ) BufferGetPage ( buffer ) ;
offnum = ItemPointerGetOffsetNumber ( & ( tuple - > t_self ) ) ;
offnum = ItemPointerGetOffsetNumber ( tid ) ;
if ( PageGetMaxOffsetNumber ( page ) > = offnum )
lp = PageGetItemId ( page , offnum ) ;
@ -5533,7 +5487,7 @@ heap_finish_speculative(Relation relation, HeapTuple tuple)
/* NO EREPORT(ERROR) from here till changes are logged */
START_CRIT_SECTION ( ) ;
Assert ( HeapTupleHeaderIsSpeculative ( tuple - > t_data ) ) ;
Assert ( HeapTupleHeaderIsSpeculative ( h tup) ) ;
MarkBufferDirty ( buffer ) ;
@ -5541,7 +5495,7 @@ heap_finish_speculative(Relation relation, HeapTuple tuple)
* Replace the speculative insertion token with a real t_ctid , pointing to
* itself like it does on regular tuples .
*/
htup - > t_ctid = tuple - > t_self ;
htup - > t_ctid = * tid ;
/* XLOG stuff */
if ( RelationNeedsWAL ( relation ) )
@ -5549,7 +5503,7 @@ heap_finish_speculative(Relation relation, HeapTuple tuple)
xl_heap_confirm xlrec ;
XLogRecPtr recptr ;
xlrec . offnum = ItemPointerGetOffsetNumber ( & tuple - > t_self ) ;
xlrec . offnum = ItemPointerGetOffsetNumber ( tid ) ;
XLogBeginInsert ( ) ;
@ -5596,10 +5550,9 @@ heap_finish_speculative(Relation relation, HeapTuple tuple)
* confirmation records .
*/
void
heap_abort_speculative ( Relation relation , HeapTuple tuple )
heap_abort_speculative ( Relation relation , ItemPointer tid )
{
TransactionId xid = GetCurrentTransactionId ( ) ;
ItemPointer tid = & ( tuple - > t_self ) ;
ItemId lp ;
HeapTupleData tp ;
Page page ;