Atomic replace and append operations
Gregory Block
gblock at ctoforaday.com
Fri Mar 18 06:40:54 PST 2005
I'd second these additions - I've been waiting with a similar kind of
need for some time, and would be very happy to see this added.
On 18 Mar 2005, at 13:55, Richard Cameron wrote:
>
> I'm interested in implementing two extra storage commands "areplace"
> and "append" for memcached. The former would behave exactly like
> "replace", but would return the object's value before it performs the
> replace operation; the latter would simply string append the new value
> onto the old one.
>
> The motivation is not purely to add extra bloat to memcached but
> rather to provide the minimal extra operations I'd need to be able to
> keep track of dependency trees in the cached data.
>
> For instance, if I want to cache objects A and B (the results of two
> SQL query, say) which depends on some "thing" in the database (like a
> particular user U's account), I'd like to be able keep track of my
> dependencies like this:
>
> U -> A,B
>
> Memcached itself seems like a good choice to store this list. So, when
> user U does something to his account, I'll want to delete the newly
> defunct objects from the cache. I think the best I can do at the
> moment is:
>
> my_deps := [get U]
> foreach dep $my_deps:
> [delete $dep]
> [set U ""]
>
> Also, if I perform another cacheable operation C which depends on U,
> I'd like to be able to add this dependency to my list. The existing
> protocol lets me say:
>
> old_deps := "get U"
> new_deps := append(old_deps, C)
> [set U $new_deps]
>
> The trouble, of course, is that there are race conditions in both
> cases where multi-threaded code could execute in a way which would
> corrupt the dependency list.
>
> On a single machine, I can simply guard the critical section in the
> client code with a mutex, but this won't work on a distributed server
> farm. It would be possible to use memcached's existing "incr" and
> "decr" operations to produce a "global" mutex, but this is a) not
> terribly efficient, and b) dangerous if one server incr's the
> semaphore on entry to the critical section but crashes before it
> exists - this would break things such that no machine could
> subsequently update the dependency and we'd be stuck in that state for
> good.
>
> So, my proposed solution is to implement an "areplace" (atomic
> replace) operation which looks like this:
>
> my_deps = [areplace U ""]
>
> and and append operation which looks like this:
>
> [append U " C"]
>
> I could then keep most of the bloat in the client library, not the
> server. This approach also has the advantage of being able to track
> dependencies over multiple memcached instances.
>
> This is probably bending memcached's intended use slightly, but I
> think it still adheres to the basic principle that it's a cache: all
> the data can be regenerated from the database if required. The
> advantage is that I can immediately tell when data should be marked as
> being invalid, which means I can use much longer cache times which, in
> turn, means that the cached items in the "long tail" (object which get
> accessed infrequently but are expensive to compute) can have much
> higher hit rates.
>
> Seem at all sensible? I'd be interested in any comments before I go
> away and code this up.
>
> Richard.
>
More information about the memcached
mailing list