[Jifty-commit] r657 - Jifty-DBI/trunk/lib/Jifty/DBI/Record Jifty-DBI/trunk/t

jifty-commit at lists.jifty.org jifty-commit at lists.jifty.org
Sat Mar 4 21:09:45 EST 2006


Author: jesse
Date: Sat Mar  4 21:09:44 2006
New Revision: 657

Added:
   Jifty-DBI/trunk/lib/Jifty/DBI/Record/Memcached.pm   (contents, props changed)
Modified:
   /   (props changed)
   Jifty-DBI/trunk/Changes
   Jifty-DBI/trunk/t/00.load.t

Log:
 r25549 at truegrounds:  jesse | 2006-03-04 17:49:50 -0800
 * Memcached support


Modified: Jifty-DBI/trunk/Changes
==============================================================================
--- Jifty-DBI/trunk/Changes	(original)
+++ Jifty-DBI/trunk/Changes	Sat Mar  4 21:09:44 2006
@@ -1,5 +1,8 @@
+
+
 Revision history for Perl extension Jifty::DBI.
 
+* Added support for Memcached
 * Updated record docs to show hooks
 
 0.09 Thu Dec 29 07:56:30 EST 2005

Added: Jifty-DBI/trunk/lib/Jifty/DBI/Record/Memcached.pm
==============================================================================
--- (empty file)
+++ Jifty-DBI/trunk/lib/Jifty/DBI/Record/Memcached.pm	Sat Mar  4 21:09:44 2006
@@ -0,0 +1,302 @@
+use warnings;
+use strict;
+
+package Jifty::DBI::Record::Memcached;
+
+use Jifty::DBI::Record;
+use Jifty::DBI::Handle;
+use base qw (Jifty::DBI::Record);
+
+use Cache::Memcached;
+
+
+=head1 NAME
+
+Jifty::DBI::Record::Cachable - records with caching behavior
+
+=head1 SYNOPSIS
+
+  package Myrecord;
+  use base qw/Jifty::DBI::Record::Cachable/;
+
+=head1 DESCRIPTION
+
+This module subclasses the main L<Jifty::DBI::Record> package to add a
+caching layer.
+
+The public interface remains the same, except that records which have
+been loaded in the last few seconds may be reused by subsequent get
+or load methods without retrieving them from the database.
+
+=head1 METHODS
+
+=cut
+
+
+use vars qw/$MEMCACHED/;
+
+
+
+
+# Function: new
+# Type    : class ctor
+# Args    : see Jifty::DBI::Record::new
+# Lvalue  : Jifty::DBI::Record::Cachable
+
+sub _init () {
+    my ( $self, @args ) = @_;
+    $MEMCACHED ||= $self->_setup_cache();
+    $self->SUPER::_init(@_);
+}
+
+sub _setup_cache {
+    my $self  = shift;
+    my $cache = Cache::Memcached->new( {$self->memcached_config} );
+    return $cache;
+}
+
+sub load_from_hash {
+    my $self = shift;
+
+    # Blow away the primary cache key since we're loading.
+    $self->{'_jifty_cache_pkey'} = undef;
+    my ( $rvalue, $msg ) = $self->SUPER::load_from_hash(@_);
+
+    my $cache_key = $self->_primary_cache_key();
+
+    ## Check the return value, if its good, cache it!
+    if ($rvalue) {
+        $self->_store();
+    }
+
+    return ( $rvalue, $msg );
+}
+
+sub load_by_cols {
+    my ( $self, %attr ) = @_;
+
+    ## Generate the cache key
+    my $alt_key = $self->_gen_alternate_cache_key(%attr);
+    if ( $self->_get($alt_key) 
+            or  $self->_get( $self->_lookup_primary_cache_key($alt_key) ) ) {
+        return ( 1, "Fetched from cache" );
+    }
+
+    # Blow away the primary cache key since we're loading.
+    $self->{'_jifty_cache_pkey'} = undef;
+
+    ## Fetch from the DB!
+    my ( $rvalue, $msg ) = $self->SUPER::load_by_cols(%attr);
+    ## Check the return value, if its good, cache it!
+    if ($rvalue) {
+        $self->_store();
+        $MEMCACHED->set( $alt_key, $self->_primary_cache_key, $self->_cache_config->{'cache_for_sec'} );
+        $self->{'loaded_by_cols'} = $alt_key;
+    }
+    return ( $rvalue, $msg );
+
+}
+
+# Function: __set
+# Type    : (overloaded) public instance
+# Args    : see Jifty::DBI::Record::_Set
+# Lvalue  : ?
+
+sub __set () {
+    my ( $self, %attr ) = @_;
+    $self->_expire();
+    return $self->SUPER::__set(%attr);
+
+}
+
+# Function: Delete
+# Type    : (overloaded) public instance
+# Args    : nil
+# Lvalue  : ?
+
+sub __delete () {
+    my ($self) = @_;
+    $self->_expire();
+    return $self->SUPER::__delete();
+}
+
+# Function: _expire
+# Type    : private instance
+# Args    : string(cache_key)
+# Lvalue  : 1
+# Desc    : Removes this object from the cache.
+
+sub _expire (\$) {
+    my $self = shift;
+    $MEMCACHED->delete( $self->_primary_cache_key);
+    $MEMCACHED->delete($self->{'loaded_by_cols'}) if ($self->{'loaded_by_cols'});
+
+}
+
+# Function: _get
+# Type    : private instance
+# Args    : string(cache_key)
+# Lvalue  : 1
+# Desc    : Get an object from the cache, and make this object that.
+
+sub _get () {
+    my ( $self, $cache_key ) = @_;
+    my $data = $MEMCACHED->get($cache_key) or return;
+    @{$self}{ keys %$data } = values %$data;    # deserialize
+}
+
+sub __value {
+    my $self   = shift;
+    my $column = shift;
+    return ( $self->SUPER::__value($column) );
+}
+
+# Function: _store
+# Type    : private instance
+# Args    : string(cache_key)
+# Lvalue  : 1
+# Desc    : Stores this object in the cache.
+
+sub _store (\$) {
+    my $self = shift;
+    $MEMCACHED->set( $self->_primary_cache_key,
+        {   values  => $self->{'values'},
+            table   => $self->table,
+            geted => $self->{'fetched'}
+        },
+        $self->_cache_config->{'cache_for_sec'}
+    );
+}
+
+
+# Function: _gen_alternate_cache_key
+# Type    : private instance
+# Args    : hash (attr)
+# Lvalue  : 1
+# Desc    : Takes a perl hash and generates a key from it.
+
+sub _gen_alternate_cache_key {
+    my ( $self, %attr ) = @_;
+
+    my $cache_key = $self->table() . ':';
+    while ( my ( $key, $value ) = each %attr ) {
+        $key   ||= '__undef';
+        $value ||= '__undef';
+
+        if ( ref($value) eq "HASH" ) {
+            $value = ( $value->{operator} || '=' ) . $value->{value};
+        } else {
+            $value = "=" . $value;
+        }
+        $cache_key .= $key . $value . ',';
+    }
+    chop($cache_key);
+    return ($cache_key);
+}
+
+# Function: _get_cache_key
+# Type    : private instance
+# Args    : nil
+# Lvalue  : 1
+
+sub _get_cache_key {
+    my ($self) = @_;
+    my $cache_key = $$self->_cache_config->{'cache_key'};
+    return ($cache_key);
+}
+
+# Function: _primary_cache_key
+# Type    : private instance
+# Args    : none
+# Lvalue: : 1
+# Desc    : generate a primary-key based variant of this object's cache key
+#           primary keys is in the cache
+
+sub _primary_cache_key {
+    my ($self) = @_;
+
+    return undef unless ( $self->id );
+
+    unless ( $self->{'_jifty_cache_pkey'} ) {
+
+        my $primary_cache_key = $self->table() . ':';
+        my @attributes;
+        foreach my $key ( @{ $self->_primary_keys } ) {
+            push @attributes, $key . '=' . $self->SUPER::__value($key);
+        }
+
+        $primary_cache_key .= join( ',', @attributes );
+
+        $self->{'_jifty_cache_pkey'} = $primary_cache_key;
+    }
+    return ( $self->{'_jifty_cache_pkey'} );
+
+}
+
+# Function: lookup_primary_cache_key
+# Type    : private class
+# Args    : string(alternate cache id)
+# Lvalue  : string(cache id)
+sub _lookup_primary_cache_key {
+    my $self          = shift;
+    my $alternate_key = shift;
+    return undef unless ($alternate_key);
+
+    my $primary_key = $MEMCACHED->get($alternate_key);
+    if ($primary_key) {
+        return ($primary_key);
+    }
+
+    # If the alternate key is really the primary one
+    elsif ( $MEMCACHED->get($alternate_key) ) {
+        return ($alternate_key);
+    } else {    # empty!
+        return (undef);
+    }
+
+}
+
+=head2 _cache_config 
+
+You can override this method to change the duration of the caching
+from the default of 5 seconds.
+
+For example, to cache records for up to 30 seconds, add the following
+method to your class:
+
+  sub _cache_config {
+      { 'cache_for_sec' => 30 }
+  }
+
+=cut
+
+sub _cache_config {
+    {   
+        'cache_for_sec' => 180,
+    };
+}
+
+
+sub memcached_config {
+    servers => ['127.0.0.1:11211'],
+    debug => 0
+
+}
+
+
+1;
+
+__END__
+
+
+=head1 AUTHOR
+
+Matt Knopp <mhat at netlag.com>
+
+=head1 SEE ALSO
+
+L<Jifty::DBI>, L<Jifty::DBI::Record>
+
+=cut
+
+

Modified: Jifty-DBI/trunk/t/00.load.t
==============================================================================
--- Jifty-DBI/trunk/t/00.load.t	(original)
+++ Jifty-DBI/trunk/t/00.load.t	Sat Mar  4 21:09:44 2006
@@ -1,4 +1,4 @@
-use Test::More tests => 12;
+use Test::More tests => 13;
 
 BEGIN { use_ok("Jifty::DBI::Collection"); }
 BEGIN { use_ok("Jifty::DBI::Handle"); }
@@ -19,6 +19,7 @@
 BEGIN { use_ok("Jifty::DBI::Handle::SQLite"); }
 BEGIN { use_ok("Jifty::DBI::Record"); }
 BEGIN { use_ok("Jifty::DBI::Record::Cachable"); }
+BEGIN { use_ok("Jifty::DBI::Record::Memcached"); }
 
 # Commented out until ruslan sends code.
 #BEGIN {


More information about the Jifty-commit mailing list