Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit f8d7f29

Browse files
committed
Allow lwlocks to be disowned
To implement AIO writes, the backend initiating writes needs to transfer the lock ownership to the AIO subsystem, so the lock held during the write can be released in another backend. Other backends need to be able to "complete" an asynchronously started IO to avoid deadlocks (consider e.g. one backend starting IO for a buffer and then waiting for a heavyweight lock held by another relation followed by the current holder of the heavyweight lock waiting for the IO to complete). To that end, this commit adds LWLockDisown() and LWLockReleaseDisowned(). If code uses LWLockDisown() it's the code's responsibility to ensure that the lock is released in case of errors. Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi> Discussion: https://postgr.es/m/1f6b50a7-38ef-4d87-8246-786d39f46ab9@iki.fi
1 parent 44cbba9 commit f8d7f29

File tree

2 files changed

+71
-6
lines changed

2 files changed

+71
-6
lines changed

src/backend/storage/lmgr/lwlock.c

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1775,14 +1775,25 @@ LWLockUpdateVar(LWLock *lock, pg_atomic_uint64 *valptr, uint64 val)
17751775

17761776

17771777
/*
1778-
* LWLockRelease - release a previously acquired lock
1778+
* Stop treating lock as held by current backend.
1779+
*
1780+
* This is the code that can be shared between actually releasing a lock
1781+
* (LWLockRelease()) and just not tracking ownership of the lock anymore
1782+
* without releasing the lock (LWLockDisown()).
1783+
*
1784+
* Returns the mode in which the lock was held by the current backend.
1785+
*
1786+
* NB: This does not call RESUME_INTERRUPTS(), but leaves that responsibility
1787+
* of the caller.
1788+
*
1789+
* NB: This will leave lock->owner pointing to the current backend (if
1790+
* LOCK_DEBUG is set). This is somewhat intentional, as it makes it easier to
1791+
* debug cases of missing wakeups during lock release.
17791792
*/
1780-
void
1781-
LWLockRelease(LWLock *lock)
1793+
static inline LWLockMode
1794+
LWLockDisownInternal(LWLock *lock)
17821795
{
17831796
LWLockMode mode;
1784-
uint32 oldstate;
1785-
bool check_waiters;
17861797
int i;
17871798

17881799
/*
@@ -1802,7 +1813,18 @@ LWLockRelease(LWLock *lock)
18021813
for (; i < num_held_lwlocks; i++)
18031814
held_lwlocks[i] = held_lwlocks[i + 1];
18041815

1805-
PRINT_LWDEBUG("LWLockRelease", lock, mode);
1816+
return mode;
1817+
}
1818+
1819+
/*
1820+
* Helper function to release lock, shared between LWLockRelease() and
1821+
* LWLockeleaseDisowned().
1822+
*/
1823+
static void
1824+
LWLockReleaseInternal(LWLock *lock, LWLockMode mode)
1825+
{
1826+
uint32 oldstate;
1827+
bool check_waiters;
18061828

18071829
/*
18081830
* Release my hold on lock, after that it can immediately be acquired by
@@ -1840,13 +1862,54 @@ LWLockRelease(LWLock *lock)
18401862
LOG_LWDEBUG("LWLockRelease", lock, "releasing waiters");
18411863
LWLockWakeup(lock);
18421864
}
1865+
}
1866+
1867+
1868+
/*
1869+
* Stop treating lock as held by current backend.
1870+
*
1871+
* After calling this function it's the callers responsibility to ensure that
1872+
* the lock gets released (via LWLockReleaseDisowned()), even in case of an
1873+
* error. This only is desirable if the lock is going to be released in a
1874+
* different process than the process that acquired it.
1875+
*/
1876+
void
1877+
LWLockDisown(LWLock *lock)
1878+
{
1879+
LWLockDisownInternal(lock);
1880+
1881+
RESUME_INTERRUPTS();
1882+
}
1883+
1884+
/*
1885+
* LWLockRelease - release a previously acquired lock
1886+
*/
1887+
void
1888+
LWLockRelease(LWLock *lock)
1889+
{
1890+
LWLockMode mode;
1891+
1892+
mode = LWLockDisownInternal(lock);
1893+
1894+
PRINT_LWDEBUG("LWLockRelease", lock, mode);
1895+
1896+
LWLockReleaseInternal(lock, mode);
18431897

18441898
/*
18451899
* Now okay to allow cancel/die interrupts.
18461900
*/
18471901
RESUME_INTERRUPTS();
18481902
}
18491903

1904+
/*
1905+
* Release lock previously disowned with LWLockDisown().
1906+
*/
1907+
void
1908+
LWLockReleaseDisowned(LWLock *lock, LWLockMode mode)
1909+
{
1910+
LWLockReleaseInternal(lock, mode);
1911+
}
1912+
18501913
/*
18511914
* LWLockReleaseClearVar - release a previously acquired lock, reset variable
18521915
*/

src/include/storage/lwlock.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ extern bool LWLockAcquireOrWait(LWLock *lock, LWLockMode mode);
129129
extern void LWLockRelease(LWLock *lock);
130130
extern void LWLockReleaseClearVar(LWLock *lock, pg_atomic_uint64 *valptr, uint64 val);
131131
extern void LWLockReleaseAll(void);
132+
extern void LWLockDisown(LWLock *l);
133+
extern void LWLockReleaseDisowned(LWLock *l, LWLockMode mode);
132134
extern bool LWLockHeldByMe(LWLock *lock);
133135
extern bool LWLockAnyHeldByMe(LWLock *lock, int nlocks, size_t stride);
134136
extern bool LWLockHeldByMeInMode(LWLock *lock, LWLockMode mode);

0 commit comments

Comments
 (0)