I think I got it now. I'll clean up the code now, do multi-threading tests now and then prepare a patch for review.
Just a question in the meantime: What's the purpose of the hash(Object) function in PropertyCache? It seems to just hash a hash code. At any rate, when I made sure that I always worked with the hashed hash code, the whole thing suddenly started working. BTW, I've upped the minimal bucket count to be equals to the segment count so a lock on a segment is always the equivalent of a lock of the set of buckets assigned to the segment. That allows more efficient cleaning code. On 22.08.2008 10:34:44 Jeremias Maerki wrote: > Thanks for looking into it, Andreas! > > On 22.08.2008 00:15:00 Andreas Delmelle wrote: > <snip/> > > So, I was wondering about the role of the reference queue. Calling > > poll() returns the first reference /if/ one is available, so it seems > > likely that cleanSegment() does get called frequently enough, but > > there's always the possibility that it returns without a reference > > being available, yet. Or, as it happens, after throwing away only > > roughly half of the references. > > Maybe it's only those that are also effectively enqueued at the time > > the cleanup is triggered (didn't try adding this to the stats yet). > > Javadoc says about WeakReference that the queueing may happen at some > point after the reference is cleared. But a delay alone doesn't explain > that so many instances weren't cleared. > > I got the impression that the cleaning wasn't done for some cache > segments at all because the threshold never got reached. Just a feeling. > > > In the meantime, I've made some changes, bypassing the > > ReferenceQueue, and simply cleaning all buckets that map to the > > segment in question, and now the behavior already seems more like > > what I had in mind. > > The first runs, each segment corresponds to one bucket, and the > > output now shows the number dropping to 0% for the related bucket. > > Segments: always 32 > Buckets: initially 8, rehash doubles the number of buckets each time > > That doesn't match what you're saying. Initially, 4 segments would share > entries in 1 bucket. After a few rehashes, each segment would have its > entries in a set of buckets. I think that's why in your patch the > segment.count goes down into the negative (i.e. it's wrong). > > Plus, the removal of the reference queue polling just queues up > references which are never cleared. I've fixed that locally. > > I'm going to try to fix the first problem above but I think that might > not be possible without a performance penalty. Let's hope it's negligable. > > > See the attached patch. Still needs some cleanup, and haven't done > > any long-running tests, nor checked the cache for other types. I > > copied some, but not all of the added debug-code. > > > > There are still a few things that bug me about StringProperty's > > cache, since for example, it is used in a lot of cases where not the > > property but its String value is attached to the FOs (reducing the > > benefits of caching somewhat, and probably explaining the large > > number of stale entries here...) > > Stale entries, yes, but at least the String instances are reused because > they come from the canonicalized StringProperty. And we're using > WeakReferences which get claimed very early. I don't think there's much > we can/need to do about that. > > > > > Hope this helps some. > > Yes, it has shown me an aspect that I have missed. > > > Jeremias Maerki > Jeremias Maerki