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