From: Simon Riggs Date: Thu, 1 Oct 2009 15:37:59 +0000 (+0100) Subject: When we ExpireOldKnownAssignedTransactionIds() we must also remove any locks that... X-Git-Url: http://git.postgresql.org/gitweb/static/gitweb.js?a=commitdiff_plain;h=486bcdf1f9a6e2ccfec71e095e1260bcf967dc8e;p=users%2Fsimon%2Fpostgres.git When we ExpireOldKnownAssignedTransactionIds() we must also remove any locks that may have been held by those stale transactions. We now call RelationReleaseOldRecoveryLocks() to ensure locks are cleared up. --- diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index 61d63d37d8..cc552d81b5 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -448,6 +448,7 @@ ProcArrayApplyRecoveryInfo(XLogRecPtr lsn, xl_xact_running_xacts *xlrec) * Remove stale transactions, if any. */ ExpireOldKnownAssignedTransactionIds(xlrec->oldestRunningXid); + RelationReleaseOldRecoveryLocks(xlrec->oldestRunningXid); /* * If our snapshot is already valid, nothing else to do... diff --git a/src/backend/utils/cache/inval.c b/src/backend/utils/cache/inval.c index 9241f8a873..b1d546ce8d 100644 --- a/src/backend/utils/cache/inval.c +++ b/src/backend/utils/cache/inval.c @@ -1767,6 +1767,50 @@ RelationReleaseAllRecoveryLocks(void) RelationReleaseRecoveryLocks(InvalidTransactionId); } +void +RelationReleaseOldRecoveryLocks(TransactionId removeXid) +{ + ListCell *l; + LOCKTAG locktag; + List *deletionList = NIL; + + /* + * Release all matching locks and identify list elements to remove + */ + foreach(l, RecoveryLockList) + { + xl_rel_lock *lock = (xl_rel_lock *) lfirst(l); + + + if (TransactionIdPrecedes(removeXid, lock->xid)) + { + elog(trace_recovery(DEBUG4), + "releasing recovery lock: xid %u db %d rel %d", + lock->xid, lock->dbOid, lock->relOid); + SET_LOCKTAG_RELATION(locktag, lock->dbOid, lock->relOid); + if (!LockRelease(&locktag, AccessExclusiveLock, true)) + elog(trace_recovery(LOG), + "RecoveryLockList contains entry for lock " + "no longer recorded by lock manager " + "xid %u database %d relation %d", + lock->xid, lock->dbOid, lock->relOid); + deletionList = lappend(deletionList, lock); + } + } + + /* + * Now remove the elements from RecoveryLockList. We can't navigate + * the list at the same time as deleting multiple elements from it. + */ + foreach(l, deletionList) + { + xl_rel_lock *lock = (xl_rel_lock *) lfirst(l); + + RecoveryLockList = list_delete_ptr(RecoveryLockList, lock); + pfree(lock); + } +} + /* * -------------------------------------------------- * Recovery handling for Rmgr RM_RELATION_ID diff --git a/src/include/storage/sinval.h b/src/include/storage/sinval.h index 46e4243433..850bed66b4 100644 --- a/src/include/storage/sinval.h +++ b/src/include/storage/sinval.h @@ -113,6 +113,8 @@ extern int xactGetCommittedInvalidationMessages(SharedInvalidationMessage **msgs extern void RelationReleaseRecoveryLockTree(TransactionId xid, int nsubxids, TransactionId *subxids); extern void RelationReleaseAllRecoveryLocks(void); +extern void RelationReleaseOldRecoveryLocks(TransactionId removeXid); + /* Recovery handlers for the Relation Rmgr (RM_RELATION_ID) */ extern void relation_redo(XLogRecPtr lsn, XLogRecord *record);