On 27 Nov 2006, at 17:18, Bela Ban wrote:
Manik Surtani wrote:
> Ok, this seems to work, making things a lot more 'correct'. But
> before I roll this into an official release and start making
> changes en-masse, porting this to 1.4.x and 2.0.0, I'd like to
> step back and think about whether this is what we really want.
> Here is what I've effectively done with 1.3.0.SP4, all related to
> pessimistic locking only:
>
> a) Added a mechanism for not removing nodes when remove() is
> called, and instead storing them in a map which can be referenced
> by concurrent threads and locks attempted. (Mutated version of
> Brian's original fix to JBCACHE-871)
> b) When locking nodes in PLI.lock(), added a mechanism to obtain
> a WL on a node if the next node after it needs to be created or
> removed. (JBCACHE-875)
> c) Modified PLI.lock() to start with Fqn.ROOT rather than Fqn.get
> (0), which applies the same cache-wide locking behaviour to the
> root as well. Prior to this, the root never was locked for anything.
> The implications of these, for the sake of accuracy and
> correctness, are possibly:
>
> 1) Performance impact on inspecting nodes in b) to decide on
> whether WLs are needed
> 2) Memory impact on maintaining a map of removed nodes in a)
- Can't we simply mark a node as REMOVED (special attribute in that
node's hashmap), so we don't need an additional list ?
This was the (seemingly) simpler solution at the time, although I may
move away from this. Marking a node as removed will involve clean-up
code for nodes marked as such either on transaction completion or (in
the non-tx case) as the call returns, probably as a part of the PLI.
And I'd use a (transient) boolean member variable rather than a
special attribute though; somehow cleaner.
- What happens if you remove an entire subtree (2000 nodes) in a
TX ? Is the current list a list of Fqns, or a copy of the nodes ?
Child nodes are added to this map as well, as they will be removed
and their locks lost in the same way. The Map is keyed on Fqn, and
the actual Node is the value so all locks, etc. are not lost.
> 3) Reduced concurrency due to overall stronger locks in b)
> 4) Much reduced concurrency because of the locking in c)
Can we resume the discussion initiated by Brian Dueck some time
ago, to provide the concept of 'multiple roots' ? We could create N
buckets, and the hashcode of the first elements of an FQN selects
the bucket (subtree) into which the FQN will go. The N buckets are
NEVER removed, but they are not visible to the user. Therefore, if
we have to lock the root, we never actually lock "/", but e.g.
bucket #24.
Yes, this is something to revisit but not for a patch on 1.3.0 or
even a micro version (1.4.1). Similar in some ways to the hashing I
was suggesting the Hibernate guys use to improve concurrency, except
that we could do it implicitly.
> <SNIP>
>
> One thing here though, in my opinion, another bug in the original
> PLI:
>
> When doing a get on a node that doesn't exist, intermediate nodes
> are created. E.g., cache2.get("/one/two/three", "key1") actually
> ends up creating /one/two/three first, and after the JBCACHE-875
> fix, /, /one and /one/two will be WL'd for a get() on a
> nonexistent node!! Shouldn't the loop just be short-circuited
> such that at any point, if the next node does not exist and the
> lock_type requested is READ, just return a null? Saves us a whole
> bunch of unnecessary WL's ...
Absolutely, this is a bug ! We should never create nodes for GET or
REMOVE !!
http://jira.jboss.com/jira/browse/JBCACHE-881