Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit35750a3

Browse files
committed
Move RecoveryLockList into a hash table.
Standbys frequently need to release all locks held by a given xid.Instead of searching one big list linearly, let's create one listper xid and put them in a hash table, so we can find what we needin O(1) time.Earlier analysis and a prototype were done by David Rowley, thoughthis isn't his patch.Back-patch all the way.Author: Thomas MunroDiagnosed-by: David Rowley, Andres FreundReviewed-by: Andres Freund, Tom Lane, Robert HaasDiscussion:https://postgr.es/m/CAEepm%3D1mL0KiQ2KJ4yuPpLGX94a4Ns_W6TL4EGRouxWibu56pA%40mail.gmail.comDiscussion:https://postgr.es/m/CAKJS1f9vJ841HY%3DwonnLVbfkTWGYWdPN72VMxnArcGCjF3SywA%40mail.gmail.com
1 parent7fdf56b commit35750a3

File tree

1 file changed

+87
-77
lines changed

1 file changed

+87
-77
lines changed

‎src/backend/storage/ipc/standby.c

Lines changed: 87 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#include"storage/procarray.h"
2929
#include"storage/sinvaladt.h"
3030
#include"storage/standby.h"
31+
#include"utils/hsearch.h"
32+
#include"utils/memutils.h"
3133
#include"utils/ps_status.h"
3234
#include"utils/timeout.h"
3335
#include"utils/timestamp.h"
@@ -37,14 +39,22 @@ intvacuum_defer_cleanup_age;
3739
intmax_standby_archive_delay=30*1000;
3840
intmax_standby_streaming_delay=30*1000;
3941

40-
staticList*RecoveryLockList;
42+
staticHTAB*RecoveryLockLists;
4143

4244
staticvoidResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId*waitlist,
4345
ProcSignalReasonreason);
4446
staticvoidSendRecoveryConflictWithBufferPin(ProcSignalReasonreason);
4547
staticXLogRecPtrLogCurrentRunningXacts(RunningTransactionsCurrRunningXacts);
4648
staticvoidLogAccessExclusiveLocks(intnlocks,xl_standby_lock*locks);
4749

50+
/*
51+
* Keep track of all the locks owned by a given transaction.
52+
*/
53+
typedefstructRecoveryLockListsEntry
54+
{
55+
TransactionIdxid;
56+
List*locks;
57+
}RecoveryLockListsEntry;
4858

4959
/*
5060
* InitRecoveryTransactionEnvironment
@@ -62,6 +72,19 @@ void
6272
InitRecoveryTransactionEnvironment(void)
6373
{
6474
VirtualTransactionIdvxid;
75+
HASHCTLhash_ctl;
76+
77+
/*
78+
* Initialize the hash table for tracking the list of locks held by each
79+
* transaction.
80+
*/
81+
memset(&hash_ctl,0,sizeof(hash_ctl));
82+
hash_ctl.keysize=sizeof(TransactionId);
83+
hash_ctl.entrysize=sizeof(RecoveryLockListsEntry);
84+
RecoveryLockLists=hash_create("RecoveryLockLists",
85+
64,
86+
&hash_ctl,
87+
HASH_ELEM |HASH_BLOBS);
6588

6689
/*
6790
* Initialize shared invalidation management for Startup process, being
@@ -106,6 +129,10 @@ ShutdownRecoveryTransactionEnvironment(void)
106129
/* Release all locks the tracked transactions were holding */
107130
StandbyReleaseAllLocks();
108131

132+
/* Destroy the hash table of locks. */
133+
hash_destroy(RecoveryLockLists);
134+
RecoveryLockLists=NULL;
135+
109136
/* Cleanup our VirtualTransaction */
110137
VirtualXactLockTableCleanup();
111138
}
@@ -585,8 +612,8 @@ StandbyLockTimeoutHandler(void)
585612
* We only keep track of AccessExclusiveLocks, which are only ever held by
586613
* one transaction on one relation.
587614
*
588-
* We keep asingle dynamically expandible list of locks in local memory,
589-
*RecoveryLockList, so we can keep track of the various entries made by
615+
* We keep ahash table of lists of locks in local memory keyed by xid,
616+
*RecoveryLockLists, so we can keep track of the various entries made by
590617
* the Startup process's virtual xid in the shared lock table.
591618
*
592619
* We record the lock against the top-level xid, rather than individual
@@ -604,8 +631,10 @@ StandbyLockTimeoutHandler(void)
604631
void
605632
StandbyAcquireAccessExclusiveLock(TransactionIdxid,OiddbOid,OidrelOid)
606633
{
634+
RecoveryLockListsEntry*entry;
607635
xl_standby_lock*newlock;
608636
LOCKTAGlocktag;
637+
boolfound;
609638

610639
/* Already processed? */
611640
if (!TransactionIdIsValid(xid)||
@@ -619,58 +648,68 @@ StandbyAcquireAccessExclusiveLock(TransactionId xid, Oid dbOid, Oid relOid)
619648
/* dbOid is InvalidOid when we are locking a shared relation. */
620649
Assert(OidIsValid(relOid));
621650

651+
/* Create a new list for this xid, if we don't have one already. */
652+
entry=hash_search(RecoveryLockLists,&xid,HASH_ENTER,&found);
653+
if (!found)
654+
{
655+
entry->xid=xid;
656+
entry->locks=NIL;
657+
}
658+
622659
newlock=palloc(sizeof(xl_standby_lock));
623660
newlock->xid=xid;
624661
newlock->dbOid=dbOid;
625662
newlock->relOid=relOid;
626-
RecoveryLockList=lappend(RecoveryLockList,newlock);
663+
entry->locks=lappend(entry->locks,newlock);
627664

628665
SET_LOCKTAG_RELATION(locktag,newlock->dbOid,newlock->relOid);
629666

630667
LockAcquireExtended(&locktag,AccessExclusiveLock, true, false, false);
631668
}
632669

633670
staticvoid
634-
StandbyReleaseLocks(TransactionIdxid)
671+
StandbyReleaseLockList(List*locks)
635672
{
636-
ListCell*cell,
637-
*prev,
638-
*next;
639-
640-
/*
641-
* Release all matching locks and remove them from list
642-
*/
643-
prev=NULL;
644-
for (cell=list_head(RecoveryLockList);cell;cell=next)
673+
while (locks)
645674
{
646-
xl_standby_lock*lock= (xl_standby_lock*)lfirst(cell);
675+
xl_standby_lock*lock= (xl_standby_lock*)linitial(locks);
676+
LOCKTAGlocktag;
677+
elog(trace_recovery(DEBUG4),
678+
"releasing recovery lock: xid %u db %u rel %u",
679+
lock->xid,lock->dbOid,lock->relOid);
680+
SET_LOCKTAG_RELATION(locktag,lock->dbOid,lock->relOid);
681+
if (!LockRelease(&locktag,AccessExclusiveLock, true))
682+
{
683+
elog(LOG,
684+
"RecoveryLockLists contains entry for lock no longer recorded by lock manager: xid %u database %u relation %u",
685+
lock->xid,lock->dbOid,lock->relOid);
686+
Assert(false);
687+
}
688+
pfree(lock);
689+
locks=list_delete_first(locks);
690+
}
691+
}
647692

648-
next=lnext(cell);
693+
staticvoid
694+
StandbyReleaseLocks(TransactionIdxid)
695+
{
696+
RecoveryLockListsEntry*entry;
649697

650-
if (!TransactionIdIsValid(xid)||lock->xid==xid)
698+
if (TransactionIdIsValid(xid))
699+
{
700+
if ((entry=hash_search(RecoveryLockLists,&xid,HASH_FIND,NULL)))
651701
{
652-
LOCKTAGlocktag;
653-
654-
elog(trace_recovery(DEBUG4),
655-
"releasing recovery lock: xid %u db %u rel %u",
656-
lock->xid,lock->dbOid,lock->relOid);
657-
SET_LOCKTAG_RELATION(locktag,lock->dbOid,lock->relOid);
658-
if (!LockRelease(&locktag,AccessExclusiveLock, true))
659-
elog(LOG,
660-
"RecoveryLockList contains entry for lock no longer recorded by lock manager: xid %u database %u relation %u",
661-
lock->xid,lock->dbOid,lock->relOid);
662-
663-
RecoveryLockList=list_delete_cell(RecoveryLockList,cell,prev);
664-
pfree(lock);
702+
StandbyReleaseLockList(entry->locks);
703+
hash_search(RecoveryLockLists,entry,HASH_REMOVE,NULL);
665704
}
666-
else
667-
prev=cell;
668705
}
706+
else
707+
StandbyReleaseAllLocks();
669708
}
670709

671710
/*
672711
* Release locks for a transaction tree, starting at xid down, from
673-
*RecoveryLockList.
712+
*RecoveryLockLists.
674713
*
675714
* Called during WAL replay of COMMIT/ROLLBACK when in hot standby mode,
676715
* to remove any AccessExclusiveLocks requested by a transaction.
@@ -692,30 +731,16 @@ StandbyReleaseLockTree(TransactionId xid, int nsubxids, TransactionId *subxids)
692731
void
693732
StandbyReleaseAllLocks(void)
694733
{
695-
ListCell*cell,
696-
*prev,
697-
*next;
698-
LOCKTAGlocktag;
734+
HASH_SEQ_STATUSstatus;
735+
RecoveryLockListsEntry*entry;
699736

700737
elog(trace_recovery(DEBUG2),"release all standby locks");
701738

702-
prev=NULL;
703-
for (cell=list_head(RecoveryLockList);cell;cell=next)
739+
hash_seq_init(&status,RecoveryLockLists);
740+
while ((entry=hash_seq_search(&status)))
704741
{
705-
xl_standby_lock*lock= (xl_standby_lock*)lfirst(cell);
706-
707-
next=lnext(cell);
708-
709-
elog(trace_recovery(DEBUG4),
710-
"releasing recovery lock: xid %u db %u rel %u",
711-
lock->xid,lock->dbOid,lock->relOid);
712-
SET_LOCKTAG_RELATION(locktag,lock->dbOid,lock->relOid);
713-
if (!LockRelease(&locktag,AccessExclusiveLock, true))
714-
elog(LOG,
715-
"RecoveryLockList contains entry for lock no longer recorded by lock manager: xid %u database %u relation %u",
716-
lock->xid,lock->dbOid,lock->relOid);
717-
RecoveryLockList=list_delete_cell(RecoveryLockList,cell,prev);
718-
pfree(lock);
742+
StandbyReleaseLockList(entry->locks);
743+
hash_search(RecoveryLockLists,entry,HASH_REMOVE,NULL);
719744
}
720745
}
721746

@@ -727,22 +752,17 @@ StandbyReleaseAllLocks(void)
727752
void
728753
StandbyReleaseOldLocks(intnxids,TransactionId*xids)
729754
{
730-
ListCell*cell,
731-
*prev,
732-
*next;
733-
LOCKTAGlocktag;
755+
HASH_SEQ_STATUSstatus;
756+
RecoveryLockListsEntry*entry;
734757

735-
prev=NULL;
736-
for (cell=list_head(RecoveryLockList);cell;cell=next)
758+
hash_seq_init(&status,RecoveryLockLists);
759+
while ((entry=hash_seq_search(&status)))
737760
{
738-
xl_standby_lock*lock= (xl_standby_lock*)lfirst(cell);
739761
boolremove= false;
740762

741-
next=lnext(cell);
763+
Assert(TransactionIdIsValid(entry->xid));
742764

743-
Assert(TransactionIdIsValid(lock->xid));
744-
745-
if (StandbyTransactionIdIsPrepared(lock->xid))
765+
if (StandbyTransactionIdIsPrepared(entry->xid))
746766
remove= false;
747767
else
748768
{
@@ -751,7 +771,7 @@ StandbyReleaseOldLocks(int nxids, TransactionId *xids)
751771

752772
for (i=0;i<nxids;i++)
753773
{
754-
if (lock->xid==xids[i])
774+
if (entry->xid==xids[i])
755775
{
756776
found= true;
757777
break;
@@ -767,19 +787,9 @@ StandbyReleaseOldLocks(int nxids, TransactionId *xids)
767787

768788
if (remove)
769789
{
770-
elog(trace_recovery(DEBUG4),
771-
"releasing recovery lock: xid %u db %u rel %u",
772-
lock->xid,lock->dbOid,lock->relOid);
773-
SET_LOCKTAG_RELATION(locktag,lock->dbOid,lock->relOid);
774-
if (!LockRelease(&locktag,AccessExclusiveLock, true))
775-
elog(LOG,
776-
"RecoveryLockList contains entry for lock no longer recorded by lock manager: xid %u database %u relation %u",
777-
lock->xid,lock->dbOid,lock->relOid);
778-
RecoveryLockList=list_delete_cell(RecoveryLockList,cell,prev);
779-
pfree(lock);
790+
StandbyReleaseLockList(entry->locks);
791+
hash_search(RecoveryLockLists,entry,HASH_REMOVE,NULL);
780792
}
781-
else
782-
prev=cell;
783793
}
784794
}
785795

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp