| File: | blib/lib/OpenSRF/Utils/Cache.pm |
| Coverage: | 19.2% |
| line | stmt | bran | cond | sub | pod | time | code |
|---|---|---|---|---|---|---|---|
| 1 | package OpenSRF::Utils::Cache; | ||||||
| 2 | 1 1 1 1 1 1 | 6 4 7 6 4 5 | use strict; use warnings; | ||||
| 3 | 1 1 1 | 8 3 7 | use base qw/OpenSRF/; | ||||
| 4 | 1 1 1 | 10 4 17 | use Cache::Memcached; | ||||
| 5 | 1 1 1 | 14 4 9 | use OpenSRF::Utils::Logger qw/:level/; | ||||
| 6 | 1 1 1 | 7 3 9 | use OpenSRF::Utils::Config; | ||||
| 7 | 1 1 1 | 14 4 9 | use OpenSRF::Utils::SettingsClient; | ||||
| 8 | 1 1 1 | 7 4 6 | use OpenSRF::EX qw(:try); | ||||
| 9 | 1 1 1 | 7 3 9 | use OpenSRF::Utils::JSON; | ||||
| 10 | |||||||
| 11 | my $log = 'OpenSRF::Utils::Logger'; | ||||||
| 12 | |||||||
| 13 - 31 | =head1 NAME
OpenSRF::Utils::Cache
=head1 SYNOPSIS
This class just subclasses Cache::Memcached.
see Cache::Memcached for more options.
The value passed to the call to current is the cache type
you wish to access. The below example sets/gets data
from the 'user' cache.
my $cache = OpenSRF::Utils::Cache->current("user");
$cache->set( "key1", "value1" [, $expire_secs ] );
my $val = $cache->get( "key1" );
=cut | ||||||
| 32 | |||||||
| 33 | 0 | sub DESTROY {} | |||||
| 34 | |||||||
| 35 | my %caches; | ||||||
| 36 | |||||||
| 37 | # ------------------------------------------------------ | ||||||
| 38 | # Persist methods and method names | ||||||
| 39 | # ------------------------------------------------------ | ||||||
| 40 | my $persist_add_slot; | ||||||
| 41 | my $persist_push_stack; | ||||||
| 42 | my $persist_peek_stack; | ||||||
| 43 | my $persist_destroy_slot; | ||||||
| 44 | my $persist_slot_get_expire; | ||||||
| 45 | my $persist_slot_find; | ||||||
| 46 | |||||||
| 47 | my $max_persist_time; | ||||||
| 48 | my $persist_add_slot_name = "opensrf.persist.slot.create_expirable"; | ||||||
| 49 | my $persist_push_stack_name = "opensrf.persist.stack.push"; | ||||||
| 50 | my $persist_peek_stack_name = "opensrf.persist.stack.peek"; | ||||||
| 51 | my $persist_destroy_slot_name = "opensrf.persist.slot.destroy"; | ||||||
| 52 | my $persist_slot_get_expire_name = "opensrf.persist.slot.get_expire"; | ||||||
| 53 | my $persist_slot_find_name = "opensrf.persist.slot.find";; | ||||||
| 54 | |||||||
| 55 | # ------------------------------------------------------ | ||||||
| 56 | |||||||
| 57 - 63 | =head1 METHODS =head2 current Return a named cache if it exists =cut | ||||||
| 64 | |||||||
| 65 | sub current { | ||||||
| 66 | 0 | 1 | my ( $class, $c_type ) = @_; | ||||
| 67 | 0 | return undef unless $c_type; | |||||
| 68 | 0 | return $caches{$c_type} if exists $caches{$c_type}; | |||||
| 69 | 0 | return $caches{$c_type} = $class->new( $c_type ); | |||||
| 70 | } | ||||||
| 71 | |||||||
| 72 | |||||||
| 73 - 77 | =head2 new Create a new named memcache object. =cut | ||||||
| 78 | |||||||
| 79 | sub new { | ||||||
| 80 | |||||||
| 81 | 0 | 1 | my( $class, $cache_type, $persist ) = @_; | ||||
| 82 | 0 | $cache_type ||= 'global'; | |||||
| 83 | 0 | $class = ref( $class ) || $class; | |||||
| 84 | |||||||
| 85 | 0 | return $caches{$cache_type} if (defined $caches{$cache_type}); | |||||
| 86 | |||||||
| 87 | 0 | my $conf = OpenSRF::Utils::SettingsClient->new; | |||||
| 88 | 0 | my $servers = $conf->config_value( cache => $cache_type => servers => 'server' ); | |||||
| 89 | 0 | $max_persist_time = $conf->config_value( cache => $cache_type => 'max_cache_time' ); | |||||
| 90 | |||||||
| 91 | 0 | $servers = [ $servers ] if(!ref($servers)); | |||||
| 92 | |||||||
| 93 | 0 | my $self = {}; | |||||
| 94 | 0 | $self->{persist} = $persist || 0; | |||||
| 95 | 0 | $self->{memcache} = Cache::Memcached->new( { servers => $servers } ); | |||||
| 96 | 0 | if(!$self->{memcache}) { | |||||
| 97 | 0 | throw OpenSRF::EX::PANIC ("Unable to create a new memcache object for $cache_type"); | |||||
| 98 | } | ||||||
| 99 | |||||||
| 100 | 0 | bless($self, $class); | |||||
| 101 | 0 | $caches{$cache_type} = $self; | |||||
| 102 | 0 | return $self; | |||||
| 103 | } | ||||||
| 104 | |||||||
| 105 | |||||||
| 106 - 108 | =head2 put_cache =cut | ||||||
| 109 | |||||||
| 110 | sub put_cache { | ||||||
| 111 | 0 | 1 | my($self, $key, $value, $expiretime ) = @_; | ||||
| 112 | 0 | return undef unless( defined $key and defined $value ); | |||||
| 113 | |||||||
| 114 | 0 | $value = OpenSRF::Utils::JSON->perl2JSON($value); | |||||
| 115 | |||||||
| 116 | 0 0 | if($self->{persist}){ _load_methods(); } | |||||
| 117 | |||||||
| 118 | 0 | $expiretime ||= $max_persist_time; | |||||
| 119 | |||||||
| 120 | 0 | unless( $self->{memcache}->set( $key, $value, $expiretime ) ) { | |||||
| 121 | 0 | $log->error("Unable to store $key => [".length($value)." bytes] in memcached server" ); | |||||
| 122 | 0 | return undef; | |||||
| 123 | } | ||||||
| 124 | |||||||
| 125 | 0 | $log->debug("Stored $key => $value in memcached server", INTERNAL); | |||||
| 126 | |||||||
| 127 | 0 | if($self->{"persist"}) { | |||||
| 128 | |||||||
| 129 | 0 | my ($slot) = $persist_add_slot->run("_CACHEVAL_$key", $expiretime . "s"); | |||||
| 130 | |||||||
| 131 | 0 | if(!$slot) { | |||||
| 132 | # slot may already exist | ||||||
| 133 | 0 | ($slot) = $persist_slot_find->run("_CACHEVAL_$key"); | |||||
| 134 | 0 | if(!defined($slot)) { | |||||
| 135 | 0 | throw OpenSRF::EX::ERROR ("Unable to create cache slot $key in persist server" ); | |||||
| 136 | } else { | ||||||
| 137 | #XXX destroy the slot and rebuild it to prevent DOS | ||||||
| 138 | } | ||||||
| 139 | } | ||||||
| 140 | |||||||
| 141 | 0 | ($slot) = $persist_push_stack->run("_CACHEVAL_$key", $value); | |||||
| 142 | |||||||
| 143 | 0 | if(!$slot) { | |||||
| 144 | 0 | throw OpenSRF::EX::ERROR ("Unable to push data onto stack in persist slot _CACHEVAL_$key" ); | |||||
| 145 | } | ||||||
| 146 | } | ||||||
| 147 | |||||||
| 148 | 0 | return $key; | |||||
| 149 | } | ||||||
| 150 | |||||||
| 151 | |||||||
| 152 - 154 | =head2 delete_cache =cut | ||||||
| 155 | |||||||
| 156 | sub delete_cache { | ||||||
| 157 | 0 | 1 | my( $self, $key ) = @_; | ||||
| 158 | 0 0 | if(!$key) { return undef; } | |||||
| 159 | 0 0 | if($self->{persist}){ _load_methods(); } | |||||
| 160 | 0 | $self->{memcache}->delete($key); | |||||
| 161 | 0 | if( $self->{persist} ) { | |||||
| 162 | 0 | $persist_destroy_slot->run("_CACHEVAL_$key"); | |||||
| 163 | } | ||||||
| 164 | 0 | return $key; | |||||
| 165 | } | ||||||
| 166 | |||||||
| 167 | |||||||
| 168 - 170 | =head2 get_cache =cut | ||||||
| 171 | |||||||
| 172 | sub get_cache { | ||||||
| 173 | 0 | 1 | my($self, $key ) = @_; | ||||
| 174 | |||||||
| 175 | 0 | my $val = $self->{memcache}->get( $key ); | |||||
| 176 | 0 | return OpenSRF::Utils::JSON->JSON2perl($val) if defined($val); | |||||
| 177 | |||||||
| 178 | 0 0 | if($self->{persist}){ _load_methods(); } | |||||
| 179 | |||||||
| 180 | # if not in memcache but we are persisting, the put it into memcache | ||||||
| 181 | 0 | if( $self->{"persist"} ) { | |||||
| 182 | 0 | $val = $persist_peek_stack->( "_CACHEVAL_$key" ); | |||||
| 183 | 0 | if(defined($val)) { | |||||
| 184 | 0 | my ($expire) = $persist_slot_get_expire->run("_CACHEVAL_$key"); | |||||
| 185 | 0 | if($expire) { | |||||
| 186 | 0 | $self->{memcache}->set( $key, $val, $expire); | |||||
| 187 | } else { | ||||||
| 188 | 0 | $self->{memcache}->set( $key, $val, $max_persist_time); | |||||
| 189 | } | ||||||
| 190 | 0 | return OpenSRF::Utils::JSON->JSON2perl($val); | |||||
| 191 | } | ||||||
| 192 | } | ||||||
| 193 | 0 | return undef; | |||||
| 194 | } | ||||||
| 195 | |||||||
| 196 | |||||||
| 197 - 199 | =head2 _load_methods =cut | ||||||
| 200 | |||||||
| 201 | sub _load_methods { | ||||||
| 202 | |||||||
| 203 | 0 | if(!$persist_add_slot) { | |||||
| 204 | 0 | $persist_add_slot = | |||||
| 205 | OpenSRF::Application->method_lookup($persist_add_slot_name); | ||||||
| 206 | 0 | if(!ref($persist_add_slot)) { | |||||
| 207 | 0 | throw OpenSRF::EX::PANIC ("Unable to retrieve method $persist_add_slot_name"); | |||||
| 208 | } | ||||||
| 209 | } | ||||||
| 210 | |||||||
| 211 | 0 | if(!$persist_push_stack) { | |||||
| 212 | 0 | $persist_push_stack = | |||||
| 213 | OpenSRF::Application->method_lookup($persist_push_stack_name); | ||||||
| 214 | 0 | if(!ref($persist_push_stack)) { | |||||
| 215 | 0 | throw OpenSRF::EX::PANIC ("Unable to retrieve method $persist_push_stack_name"); | |||||
| 216 | } | ||||||
| 217 | } | ||||||
| 218 | |||||||
| 219 | 0 | if(!$persist_peek_stack) { | |||||
| 220 | 0 | $persist_peek_stack = | |||||
| 221 | OpenSRF::Application->method_lookup($persist_peek_stack_name); | ||||||
| 222 | 0 | if(!ref($persist_peek_stack)) { | |||||
| 223 | 0 | throw OpenSRF::EX::PANIC ("Unable to retrieve method $persist_peek_stack_name"); | |||||
| 224 | } | ||||||
| 225 | } | ||||||
| 226 | |||||||
| 227 | 0 | if(!$persist_destroy_slot) { | |||||
| 228 | 0 | $persist_destroy_slot = | |||||
| 229 | OpenSRF::Application->method_lookup($persist_destroy_slot_name); | ||||||
| 230 | 0 | if(!ref($persist_destroy_slot)) { | |||||
| 231 | 0 | throw OpenSRF::EX::PANIC ("Unable to retrieve method $persist_destroy_slot_name"); | |||||
| 232 | } | ||||||
| 233 | } | ||||||
| 234 | 0 | if(!$persist_slot_get_expire) { | |||||
| 235 | 0 | $persist_slot_get_expire = | |||||
| 236 | OpenSRF::Application->method_lookup($persist_slot_get_expire_name); | ||||||
| 237 | 0 | if(!ref($persist_slot_get_expire)) { | |||||
| 238 | 0 | throw OpenSRF::EX::PANIC ("Unable to retrieve method $persist_slot_get_expire_name"); | |||||
| 239 | } | ||||||
| 240 | } | ||||||
| 241 | 0 | if(!$persist_slot_find) { | |||||
| 242 | 0 | $persist_slot_find = | |||||
| 243 | OpenSRF::Application->method_lookup($persist_slot_find_name); | ||||||
| 244 | 0 | if(!ref($persist_slot_find)) { | |||||
| 245 | 0 | throw OpenSRF::EX::PANIC ("Unable to retrieve method $persist_slot_find_name"); | |||||
| 246 | } | ||||||
| 247 | } | ||||||
| 248 | } | ||||||
| 249 | |||||||
| 250 | |||||||
| 251 | |||||||
| 252 | |||||||
| 253 | |||||||
| 254 | |||||||
| 255 | |||||||
| 256 | 1; | ||||||
| 257 | |||||||