I’ve been using Memcached for a few weeks, trying to offload some VERY heavy database load. It’s nice and blazing fast, but the implementation is sort of clunky. If I have this simple bit of code:

$key = "foobar";
$val = calculate_val($key);

It turns into this:

$key = "foobar";
$val = $memd->get($key);
if(! defined($val)) {
  $val = calculate_val($key);
  $memd->set($key, $val);
}

Repeatedly I came back to the idea of a get_or_set method that would handle this stuff, but until the obvious solution hit me, I couldn’t get it:

$key = "foobar";
$val = $memd->get_or_set($key, sub { calculate_val($key) });

A simple closure around the actual calculation block which is then passed to the get_or_set method as a callback. If the lookup finds a value the method returns it, otherwise it returns the result of calling the callback function.

The only change to Cache::Memcached is adding the get_or_set function. The easiest way is to just subclass Cache::Memcached:

package My::Memcached
use base qw(Cache::Memcached);
sub get_or_set {
  my $self = shift;
  my($key, $callback) = @_;
  my $val = $self->get($key);
  unless(defined $val) {
    $val = &$callback;
    $self->set($key, $val);
  }
  return $val;
}

1;

Now you have this simple interface:

use My::Memcached;

my $memd = new My::Memcached { servers => [...] };
my $foo = $memd->get_or_set("bar", sub { get_val("bar") });