some questions about fast-path-lock

Started by Alexover 6 years ago2 messages
#1Alex
zhihui.fan1213@gmail.com

I got some idea from the README under storage/lmgr and read some code of
LockAcquireExtended , but I still have some questions now.

LWLockAcquire(&MyProc->backendLock, LW_EXCLUSIVE);
if (FastPathStrongRelationLocks->count[fasthashcode] != 0)
acquired = false;
else
acquired = FastPathGrantRelationLock(locktag->locktag_field2,
lockmode);

1. In the README, it says: "A key point of this algorithm is that it
must be possible to verify the
absence of possibly conflicting locks without fighting over a shared LWLock
or
spinlock. Otherwise, this effort would simply move the contention
bottleneck
from one place to another."

but in the code, there is LWLockAcquire in the above code. Actually I
can't think out how can we proceed without a lock.

2. Why does the MyProc->backendLock work? it is MyProc not a global
lock.

3. for the line, acquired =
FastPathGrantRelationLock(locktag->locktag_field2,
lockmode); I think it should be able to replaced with "acquired =
true" (but obviously I'm wrong) . I read "FastPathGrantRelationLock" but
can't understand it.

Any hint will be helpful. thanks!

#2Robert Haas
robertmhaas@gmail.com
In reply to: Alex (#1)
Re: some questions about fast-path-lock

On Mon, May 27, 2019 at 2:01 AM Alex <zhihui.fan1213@gmail.com> wrote:

I got some idea from the README under storage/lmgr and read some code of LockAcquireExtended , but I still have some questions now.

LWLockAcquire(&MyProc->backendLock, LW_EXCLUSIVE);
if (FastPathStrongRelationLocks->count[fasthashcode] != 0)
acquired = false;
else
acquired = FastPathGrantRelationLock(locktag->locktag_field2,
lockmode);

1. In the README, it says: "A key point of this algorithm is that it must be possible to verify the
absence of possibly conflicting locks without fighting over a shared LWLock or
spinlock. Otherwise, this effort would simply move the contention bottleneck
from one place to another."

but in the code, there is LWLockAcquire in the above code. Actually I can't think out how can we proceed without a lock.

The per-backend lock is not heavily contended, because under normal
circumstances it is only accessed by a single backend. If there is a
potential lock conflict that must be analyzed then another backend may
acquire it and that might lead to a little bit of contention, but it
happens quite rarely -- so the overall contention is still much less
than if everyone is fighting over the lock manager partition locks.

2. Why does the MyProc->backendLock work? it is MyProc not a global lock.

It's still an LWLock. Putting it inside of MyProc doesn't make it
magically stop working. MyProc is in shared memory, not backend-local
memory, if that's what you are confused about.

3. for the line, acquired = FastPathGrantRelationLock(locktag->locktag_field2,
lockmode); I think it should be able to replaced with "acquired = true" (but obviously I'm wrong) . I read "FastPathGrantRelationLock" but can't understand it.

It can't say 'acquired = true' because each backend can only acquire a
maximum of 16 relation locks via the fast-path mechanism. If a
process acquires more than 16 relation locks, at least some of them
will have to be acquired without benefit of the fast-path. This value
could be changed by changing the value of the constant
FP_LOCK_SLOTS_PER_BACKEND, but since we scan the array linearly,
making it too big will lead to other problems. I don't quite
understand what about FastPathGrantRelationLock you don't understand -
it's a pretty straightforwardly-coded search for either (a) an
existing fastpath slot for the specified relid or failing that (b) an
unused fastpath slot.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company