Skip to content

Lock in update

-- psql 1
select pg_backend_pid(); -- 4840

-- psql 2
select * from pg_locks where pid = 4840;

pg_locks

-- psql 1
update tb set a = 1;

0. exec_simple_query

exec_simple_query
    start_xact_command
    pg_analyze_and_rewrite_fixedparams
    PortalRun | PortalRunMulti | ProcessQuery
    finish_xact_command

1. vxid lock

start_xact_command
    StartTransaction
        GetNextLocalTransactionId
        VirtualXactLockTableInsert /* Take vxid lock via the fast-path */

2. RowExclusiveLock

pg_analyze_and_rewrite_fixedparams
    parse_analyze_fixedparams | transformTopLevelStmt | transformOptionalSelectInto
        transformStmt | transformUpdateStmt
            setTargetTable | parserOpenTable(pstate, relation, RowExclusiveLock)
                table_openrv_extended | relation_openrv_extended | RangeVarGetRelidExtended
                    LockRelationOid /* lmgr.c */
                        LockAcquireExtended /* lock.c */

3. transactionid lock

PortalRun | PortalRunMulti | ProcessQuery
    ExecutorRun | standard_ExecutorRun | ExecutePlan | ...
        heap_update
            GetCurrentTransactionId | AssignTransactionId
                XactLockTableInsert
                    LockAcquire /* sleep if conflict found, set lock if/when no conflicts.*/
                        LockAcquireExtended
                            partitionLock = LockHashPartitionLock(hashcode);
                            LWLockAcquire(partitionLock, LW_EXCLUSIVE);
                            proclock = SetupLockInTable
                            LockCheckConflicts
                            GrantLock(lock, proclock, lockmode);
                            GrantLockLocal(locallock, owner);
                            LWLockRelease(partitionLock);
                            return LOCKACQUIRE_OK;

4. tuple lock

heap_update
    GetCurrentTransactionId | AssignTransactionId
        XactLockTableInsert
    HeapTupleSatisfiesUpdate
    compute_new_xmax_infomask
    CheckForSerializableConflictIn

    START_CRIT_SECTION();

    PageSetPrunable(page, xid);
    HeapTupleSetHotUpdated(&oldtup); /* Mark the old tuple as HOT-updated */
    HeapTupleSetHeapOnly(heaptup); /* And mark the new tuple as heap-only */
    HeapTupleSetHeapOnly(newtup); /* Mark the caller's copy too, in case different from heaptup */
    RelationPutHeapTuple

    oldtup.t_data->t_ctid = heaptup->t_self; /* record address of new tuple in t_ctid of old one */
    MarkBufferDirty(buffer);

    /* XLOG stuff */
    log_heap_update
    PageSetLSN

    END_CRIT_SECTION();

    return TM_Ok;

5. finish_xact_command

finish_xact_command
    CommitTransactionCommand
        CommitTransaction
            ResourceOwnerRelease
                ResourceOwnerReleaseInternal
                    ProcReleaseLocks
                        LockReleaseAll
                            VirtualXactLockTableCleanup

完整过程

exec_simple_query
    start_xact_command
        StartTransaction
            GetNextLocalTransactionId
            VirtualXactLockTableInsert /* Take vxid lock via the fast-path */
    pg_analyze_and_rewrite_fixedparams
        parse_analyze_fixedparams | transformTopLevelStmt | transformOptionalSelectInto
            transformStmt | transformUpdateStmt
                setTargetTable | parserOpenTable(pstate, relation, RowExclusiveLock)
                    table_openrv_extended | relation_openrv_extended | RangeVarGetRelidExtended
                        LockRelationOid /* Lock a relation given only its OID */
    PortalRun | PortalRunMulti | ProcessQuery
        ExecutorRun | standard_ExecutorRun | ExecutePlan | ...
            heap_update
                GetCurrentTransactionId | AssignTransactionId
                    XactLockTableInsert
                        LockAcquire /* sleep if conflict found, set lock if/when no conflicts.*/
                            LockAcquireExtended
                                partitionLock = LockHashPartitionLock(hashcode);
                                LWLockAcquire(partitionLock, LW_EXCLUSIVE);
                                proclock = SetupLockInTable
                                LockCheckConflicts
                                GrantLock(lock, proclock, lockmode);
                                GrantLockLocal(locallock, owner);
                                LWLockRelease(partitionLock);
                                return LOCKACQUIRE_OK;
                HeapTupleSatisfiesUpdate
                compute_new_xmax_infomask
                CheckForSerializableConflictIn

                START_CRIT_SECTION();

                PageSetPrunable(page, xid);
                HeapTupleSetHotUpdated(&oldtup); /* Mark the old tuple as HOT-updated */
                HeapTupleSetHeapOnly(heaptup); /* And mark the new tuple as heap-only */
                HeapTupleSetHeapOnly(newtup); /* Mark the caller's copy too, in case different from heaptup */
                RelationPutHeapTuple

                oldtup.t_data->t_ctid = heaptup->t_self; /* record address of new tuple in t_ctid of old one */
                MarkBufferDirty(buffer);

                /* XLOG stuff */
                log_heap_update
                PageSetLSN

                END_CRIT_SECTION();

                return TM_Ok;
    finish_xact_command
        CommitTransactionCommand
            CommitTransaction
                ResourceOwnerRelease
                    ResourceOwnerReleaseInternal
                        ProcReleaseLocks
                            LockReleaseAll
                                VirtualXactLockTableCleanup