Bug 116593
Summary: | Path#get(String) may deadlock as of //core-platform/dev/src/com/redhat/persistence/common/Path.java#6 | ||||||
---|---|---|---|---|---|---|---|
Product: | [Retired] Red Hat Web Application Framework | Reporter: | Vadim Nasardinov <vnasardinov> | ||||
Component: | persistence | Assignee: | Vadim Nasardinov <vnasardinov> | ||||
Status: | CLOSED CURRENTRELEASE | QA Contact: | Jon Orris <jorris> | ||||
Severity: | medium | Docs Contact: | |||||
Priority: | medium | ||||||
Version: | nightly | ||||||
Target Milestone: | --- | ||||||
Target Release: | --- | ||||||
Hardware: | All | ||||||
OS: | Linux | ||||||
URL: | http://post-office.corp.redhat.com/archives/ccm-engineering-list/2004-February/msg00068.html | ||||||
Whiteboard: | |||||||
Fixed In Version: | Doc Type: | Bug Fix | |||||
Doc Text: | Story Points: | --- | |||||
Clone Of: | Environment: | ||||||
Last Closed: | 2004-02-23 22:20:46 UTC | Type: | --- | ||||
Regression: | --- | Mount Type: | --- | ||||
Documentation: | --- | CRM: | |||||
Verified Versions: | Category: | --- | |||||
oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |||||
Cloudforms Team: | --- | Target Upstream Version: | |||||
Embargoed: | |||||||
Attachments: |
|
Description
Vadim Nasardinov
2004-02-23 16:24:31 UTC
Created attachment 97952 [details]
hopefully eliminates the possibility of deadlocking
The fundamental reason why the current implementation of
Path#get(String) may deadlock is because this method may needs to
obtain two or more locks in order to succeed. This is because
(b) This method may recurse.
(c) Different invocations of this method may require different locks.
So, if an invocation of Path#get(String) requires locks #1 and #2 when
performed from thread A, while a concurrent invocation from thread B
requires locks #2 and #1 (in that order), the method may deadlock.
The attached patch makes Path#get(String) non-recursive. This is
essentially achieved by deferring the initialization of the m_parent
field until it is really needed. The only place where m_parent is
needed in the new implementation is in Path#getParent(). Note that
the new implementation of Path#getParent() may require up to two locks
in order to succeed. So, why doesn't this lead to the same problems
as Path#get(String)?
Here are the differences between locking strategies of the old
implementation of Path#get(String) and the proposed new implementation
of Path#getParent().
1. Path#get(String) may require two or more locks. These locks come
from the pre-allocated pool of 64 objects. It is possible that
one thread may require locks #1 and #2, while the other requires
number #2 and #1, in that order. In other words, there is no
ordering among locks.
2. Path#getParent() draws its locks from two distinct pools. The
first pool is the set of all Path objects (which typically
measures in the thousands). The getParent() method synchronizes
on the "this" object.
The second pool is the same as above -- it's the array of 64
pre-allocated maps. The getParent() method always synchronizes on
the Path object, before optionally synchronizing on one of the 64
maps. This imposes an ordering on the entire set of locks. The
first pool always comes before the second. It is impossible for
one thread to require locks P and M, while for another thread to
require locks M and P, in that order. We always synchronize on a
Path object, before potentially synchronizing on the Map object.
I think this eliminates the possibility of deadlocking.
That looks fine to me. And, it still significantly reduces lock contention. Thanks. Applied on the trunk in change 40731. |