On Sat, 9 Aug 2003 10:22:13 +0900
Tim Bates <tim / bates.id.au> wrote:

> Hi all,
> I'm trying to build a caching mechanism into a library I'm writing. I
> want to do it using weakrefs. It will look something like this:
>
<snip>

Funny, I was just working on this. ;-)

<snip> 
> It seems, though, that the WeakRef implementation is such that if you
> refer to an object other than via its weakref, the weakref-ness is
> destroyed and the object never gets GC'd. Can anyone explain why and/or
> offer a way around this?

Here's what I did.  The idea was that the system would be addressing an
indeterminate number of persistant objects, in a transparent (to the
user/developer) manner.  Thus, the problem was twofold:

   *  We need one unique reference for each object, so reloading objects
      from the object store doesn't create copies and we have sync
      problems

   *  Reading from the disk all the time is slow

Keeping everything in memory is also out, since the system needs to
scale.

This gives you an idea what the cache was _for_.  To accomplish this, I
keep _two_ caches: a "strong" cache and a "weak" cache.  The "strong"
holds objects until it's determined that they've expired---the strong
cache limit is reached, and they're written to disk and removed from the
strong cache.

When an object is referred to, first I check the strong cache, then I
check the weak cache.  If it's found in the strong cache, I return it
normally.  If it's in the weak cache, I put it in the strong cache, and
return it.  (This solves the multiple-references problem.)  If it's not
found in either, load it from disk and put it in both.

The garbage collector does its stuff to keep things within limits.

Unfortunately this isn't perfect---I'd like to expire stuff from the
cache based on size, so I could set a memory limit, but Ruby has no way
for querying object size (*).  Also, there's some further evil magic
required to make sure things get written to the disk as appropriate.
(For instance, if an object which has a reference changes the object
after it's expired from the strong cache, it needs written again.)  Not
having destructors makes this slightly painful, and finalizers don't
work here.

Depending on what you're doing, this scheme ought to work---I'm not sure
how you're adding and removing objects, but it's probably similar if
you're wanting to cache them---just make sure you've got all the cases
covered.  ;)

(If you need a fully-functional transparently persistant object system
with this sort of thing already implemented, lemme know, I can give you
the code.)

hth,

-- 
Ryan Pavlik <rpav / users.sf.net>

"The fact that you believe in something called a
 'Babedar' *alone* leads me to conclude that it's
 always wrong." - 8BT