| TM documentation | Contained in the TM distribution. |
TM::ResourceAble::MemCached - Topic Maps, Memcached server backend
use TM::ResourceAble::MemCached;
use Fcntl;
# create/reset new map
my $tm = new TM::ResourceAble::MemCached (
baseuri => 'http://whereever/',
servers => [ localhost:11211 ],
mode => O_TRUNC | O_CREAT,
);
# use TM interface
# open existing map
my $tm = new TM::ResourceAble::MemCached (
baseuri => 'http://whereever/',
servers => [ localhost:11211 ],
);
This package implements TM using a memcached server farm as backend. You should be able (without much testing, mind you, so it is EXPERIMENTAL) to perform all operations according to the TM interface.
NOTE: The implementation is using the TIE technique (perltie via Tie::StdHash), so maybe there are problems lurking.
Of course, a set of memcacheds can store any number of maps. To keep them separate, the baseuri is used, so make sure every map gets its own baseuri.
The constructor expects a hash with the following keys:
The value must be a reference to an array of strings, each of the form host:port. If there is no such list, then the constructor will fail.
The value must be a value from Fcntl to control
whether the map should be created (O_CREAT) when it does not exist, and/or
whether the map should be cleared (O_TRUNC) when it existed before.
All other options are passed to the constructor chain of traits (TM::ResourceAble) and superclasses (TM).
Copyright 2010, Robert Barta <drrho@cpan.org>, All rights reserved.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. http://www.perl.com/perl/misc/Artistic.html
| TM documentation | Contained in the TM distribution. |
package TM::ResourceAble::MemCached::mid2iid; use Tie::Hash; use base qw(Tie::StdHash); sub TIEHASH { my $class = shift; my $memd = shift; # warn "TIEHASH toplet"; my $self = bless { memd => $memd }, $class; $self->{mid2iid} = $self->{memd}->get ("mid2iid_all"); return $self; } sub STORE { my ($self, $key, $val) = @_; # warn "STORE toplet $key"; $self->{memd}->set ("mid2iid:$key", $val); $self->{mid2iid}->{$key}++; } sub FETCH { my ($self, $key) = @_; # warn "FETCH toplet $key"; return $self->{memd}->get ("mid2iid:$key"); } sub FIRSTKEY { my ($self) = @_; # warn "FIRSTKEY toplet"; my $a = keys %{$self->{mid2iid}}; # reset each() iterator each %{$self->{mid2iid}} } sub NEXTKEY { my ($self, $key) = @_; # warn "NEXTKEY toplet $key"; return each %{$self->{mid2iid}} } sub DESTROY { my ($self) = @_; # warn "DESTROYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"; # warn Dumper $self->{assertions}; $self->{memd}->set ("mid2iid_all", $self->{mid2iid}); } 1; package TM::ResourceAble::MemCached::assertions; use Tie::Hash; use base qw(Tie::StdHash); use Data::Dumper; sub TIEHASH { my $class = shift; my $memd = shift; # warn "TIEHASH assert"; my $self = bless { memd => $memd }, $class; $self->{assertions} = $self->{memd}->get ("assertions_all"); # warn "after tie ".Dumper $self->{assertions}; return $self; } sub STORE { my ($self, $key, $val) = @_; # warn "STORE assert $key"; $self->{memd}->set ("assertions:$key", $val); $self->{assertions}->{$key}++; } sub FETCH { my ($self, $key) = @_; # warn "FETCH assert $key"; return $self->{memd}->get ("assertions:$key"); } sub FIRSTKEY { my ($self) = @_; # warn "FIRSTKEY assert"; my $a = keys %{$self->{assertions}}; # reset each() iterator each %{$self->{assertions}} } sub NEXTKEY { my ($self, $key) = @_; # warn "NEXTKEY assert $key"; return each %{$self->{assertions}} } sub DESTROY { my ($self) = @_; # warn "DESTROYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"; # warn Dumper $self->{assertions}; $self->{memd}->set ("assertions_all", $self->{assertions}); } 1; package TM::ResourceAble::MemCached::main; use Tie::Hash; use base qw(Tie::StdHash); use Data::Dumper; sub TIEHASH { my $class = shift; my $memd = shift; # warn "TIEHASH main"; return bless { memd => $memd }, $class; } sub FETCH { my ($self, $key) = @_; # warn "main FETCH $key"; if ($key eq 'assertions') { $self->{__assertions} ||= {}; return $self->{__assertions}; } elsif ($key eq 'mid2iid') { $self->{__mid2iid} ||= {}; return $self->{__mid2iid}; } else { return $self->{memd}->get ($key); } } sub STORE { my ($self, $key, $val) = @_; # warn "main STORE $key"; if ($key eq 'assertions') { $self->{__assertions} = $val; } elsif ($key eq 'mid2iid') { $self->{__mid2iid} = $val; } else { $self->{memd}->set ($key, $val); } } 1; package TM::ResourceAble::MemCached; use strict; use warnings; use Data::Dumper; use TM; use base qw(TM); use Class::Trait qw(TM::ResourceAble);
sub new { my $class = shift; my %options = @_; my $servers = delete $options{servers} || die "no servers specified"; use Fcntl; my $mode = delete $options{mode} || O_CREAT; my $tmp = bless $class->SUPER::new (%options), $class; use Cache::Memcached; my $memd = new Cache::Memcached { 'servers' => $servers, 'namespace' => $tmp->baseuri, }; my %self; tie %self, 'TM::ResourceAble::MemCached::main', $memd; tie %{ $self{assertions} }, 'TM::ResourceAble::MemCached::assertions', $memd; tie %{ $self{mid2iid} }, 'TM::ResourceAble::MemCached::mid2iid', $memd; # warn "in new ".Dumper \%self; if ($self{baseuri}) { # there are already values there if ($mode & O_TRUNC) { # if we want an empty slate $self{assertions} = {}; map { $self{assertions}->{$_} = $tmp->{assertions}->{$_} } keys %{ $tmp->{assertions} }; $self{mid2iid} = {}; map { $self{mid2iid}->{$_} = $tmp->{mid2iid}->{$_} } keys %{ $tmp->{mid2iid} }; } } elsif ($mode & O_CREAT) { # careful cloning from prototypical TM foreach my $k (keys %$tmp) { if ($k eq 'assertions') { map { $self{assertions}->{$_} = $tmp->{assertions}->{$_} } keys %{ $tmp->{assertions} }; } elsif ($k eq 'mid2iid') { map { $self{mid2iid}->{$_} = $tmp->{mid2iid}->{$_} } keys %{ $tmp->{mid2iid} }; } else { $self{$k} = $tmp->{$k}; } } } else { die "no map on servers"; } return bless \%self, $class; }
our $VERSION = '0.02'; 1; __END__