← Index
NYTProf Performance Profile   « block view • line view • sub view »
For 05.Domain_and_Item.t
  Run on Tue May 4 17:21:41 2010
Reported on Tue May 4 17:22:20 2010

File /data/SimpleDB-Class/author.t/../lib/SimpleDB/Class/Cache.pm
Statements Executed 511
Statement Execution Time 17.6ms
Subroutines — ordered by exclusive time
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
24221.16ms25.3msSimpleDB::Class::Cache::::getSimpleDB::Class::Cache::get
1733809µs8.44msSimpleDB::Class::Cache::::setSimpleDB::Class::Cache::set
111538µs9.28msSimpleDB::Class::Cache::::BEGIN@32SimpleDB::Class::Cache::BEGIN@32
111440µs2.45msSimpleDB::Class::Cache::::BEGIN@31SimpleDB::Class::Cache::BEGIN@31
4121371µs832µsSimpleDB::Class::Cache::::fix_keySimpleDB::Class::Cache::fix_key
111283µs1.35msSimpleDB::Class::Cache::::BEGIN@33SimpleDB::Class::Cache::BEGIN@33
111187µs7.65msSimpleDB::Class::Cache::::BEGIN@30SimpleDB::Class::Cache::BEGIN@30
331123µs1.93msSimpleDB::Class::Cache::::flushSimpleDB::Class::Cache::flush
4112110µs461µsSimpleDB::Class::Cache::::CORE:substSimpleDB::Class::Cache::CORE:subst (opcode)
11138µs2.22msSimpleDB::Class::Cache::::BEGIN@29SimpleDB::Class::Cache::BEGIN@29
11126µs112µsSimpleDB::Class::Cache::::__ANON__[../lib/SimpleDB/Class/Cache.pm:106]SimpleDB::Class::Cache::__ANON__[../lib/SimpleDB/Class/Cache.pm:106]
11111µs134µsSimpleDB::Class::Cache::::BEGIN@448SimpleDB::Class::Cache::BEGIN@448
0000s0sSimpleDB::Class::Cache::::__ANON__[../lib/SimpleDB/Class/Cache.pm:38]SimpleDB::Class::Cache::__ANON__[../lib/SimpleDB/Class/Cache.pm:38]
0000s0sSimpleDB::Class::Cache::::deleteSimpleDB::Class::Cache::delete
0000s0sSimpleDB::Class::Cache::::mgetSimpleDB::Class::Cache::mget
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1package SimpleDB::Class::Cache;
2
3
4=head1 NAME
5
6SimpleDB::Class::Cache - Memcached interface for SimpleDB.
7
8=head1 DESCRIPTION
9
10An API that allows you to cache item data to a memcached server. Technically I should be storing the item itself, but since the item has a reference to the domain, and the domain has a reference to the simpledb object, it could cause all sorts of problems, so it's just safer to store just the item's data.
11
12=head1 SYNOPSIS
13
14 use SimpleDB::Class::Cache;
15
16 my $cache = SimpleDB::Class::Cache->new(servers=>[{host=>'127.0.0.1', port=>11211}]);
17
18 $cache->set($domain->name, $id, $value);
19
20 my $value = $cache->get($domain->name, $id);
21 my ($val1, $val2) = @{$cache->mget([[$domain->name, $id1], [$domain->name, $id2]])};
22
23 $cache->delete($domain->name, $id);
24
25 $cache->flush;
26
27=cut
28
29336µs24.40ms
# spent 2.22ms (38µs+2.18) within SimpleDB::Class::Cache::BEGIN@29 which was called # once (38µs+2.18ms) by SimpleDB::Class::BEGIN@139 at line 29
use Moose;
# spent 2.22ms making 1 call to SimpleDB::Class::Cache::BEGIN@29 # spent 2.18ms making 1 call to Moose::Exporter::__ANON__[Moose/Exporter.pm:389]
303127µs17.65ms
# spent 7.65ms (187µs+7.46) within SimpleDB::Class::Cache::BEGIN@30 which was called # once (187µs+7.46ms) by SimpleDB::Class::BEGIN@139 at line 30
use SimpleDB::Class::Exception;
# spent 7.65ms making 1 call to SimpleDB::Class::Cache::BEGIN@30
313125µs22.47ms
# spent 2.45ms (440µs+2.01) within SimpleDB::Class::Cache::BEGIN@31 which was called # once (440µs+2.01ms) by SimpleDB::Class::BEGIN@139 at line 31
use Memcached::libmemcached;
# spent 2.45ms making 1 call to SimpleDB::Class::Cache::BEGIN@31 # spent 21µs making 1 call to Exporter::import
323151µs19.28ms
# spent 9.28ms (538µs+8.74) within SimpleDB::Class::Cache::BEGIN@32 which was called # once (538µs+8.74ms) by SimpleDB::Class::BEGIN@139 at line 32
use Storable ();
# spent 9.28ms making 1 call to SimpleDB::Class::Cache::BEGIN@32
3331.21ms21.55ms
# spent 1.35ms (283µs+1.07) within SimpleDB::Class::Cache::BEGIN@33 which was called # once (283µs+1.07ms) by SimpleDB::Class::BEGIN@139 at line 33
use Params::Validate qw(:all);
# spent 1.35ms making 1 call to SimpleDB::Class::Cache::BEGIN@33 # spent 197µs making 1 call to Exporter::import
34Params::Validate::validation_options( on_fail => sub {
35 my $error = shift;
36 warn "Error in Cache params: ".$error;
37 SimpleDB::Class::Exception::InvalidParam->throw( error => $error );
3814µs112µs } );
# spent 12µs making 1 call to Params::Validate::validation_options
39
40
41
42=head1 METHODS
43
44These methods are available from this class:
45
46=cut
47
48#-------------------------------------------------------------------
49
50=head2 new ( params )
51
52Constructor.
53
54=head3 params
55
56A hash containing configuration params to connect to memcached.
57
58=head4 servers
59
60An array reference of servers (sockets and/or hosts). It should look similar to:
61
62 [
63 { host => '127.0.0.1', port=> '11211' },
64 { socket => '/path/to/unix/socket' },
65 ]
66
67=cut
68
69#-------------------------------------------------------------------
70
71=head2 servers ( )
72
73Returns the array reference of servers passed into the constructor.
74
75=cut
76
7712µs11.77mshas 'servers' => (
# spent 1.77ms making 1 call to Moose::has
78 is => 'ro',
79 required => 1,
80);
81
82#-------------------------------------------------------------------
83
84=head2 memcached ( )
85
86Returns a L<Memcached::libmemcached> object, which is constructed using the information passed into the constructor.
87
88=cut
89
90has 'memcached' => (
91 is => 'ro',
92 lazy => 1,
93 clearer => 'clear_memcached',
94
# spent 112µs (26+85) within SimpleDB::Class::Cache::__ANON__[../lib/SimpleDB/Class/Cache.pm:106] which was called # once (26µs+85µs) by Class::MOP::Mixin::AttributeCore::default at line 53 of Class/MOP/Mixin/AttributeCore.pm
default => sub {
956106µs my $self = shift;
96 my $memcached = Memcached::libmemcached::memcached_create();
# spent 57µs making 1 call to Memcached::libmemcached::memcached_create
97 foreach my $server (@{$self->servers}) {
# spent 4µs making 1 call to SimpleDB::Class::Cache::servers
98 if (exists $server->{socket}) {
99 Memcached::libmemcached::memcached_server_add_unix_socket($memcached, $server->{socket});
100 }
101 else {
102 Memcached::libmemcached::memcached_server_add($memcached, $server->{host}, $server->{port});
# spent 24µs making 1 call to Memcached::libmemcached::memcached_server_add
103 }
104 }
105 return $memcached;
106 },
10714µs11.42ms);
# spent 1.42ms making 1 call to Moose::has
108
109
110#-------------------------------------------------------------------
111
112=head2 fix_key ( domain, id )
113
114Returns a key after it's been processed for completeness. Merges a domain name and a key name with a colon. Keys cannot have any spaces in them, and this fixes that. However, it means that "foo bar" and "foo_bar" are the same thing.
115
116=head3 domain
117
118They domain name to process.
119
120=head3 id
121
122They id name to process.
123
124=cut
125
126
# spent 832µs (371+461) within SimpleDB::Class::Cache::fix_key which was called 41 times, avg 20µs/call: # 24 times (224µs+433µs) by SimpleDB::Class::Cache::get at line 255, avg 27µs/call # 17 times (147µs+28µs) by SimpleDB::Class::Cache::set at line 380, avg 10µs/call
sub fix_key {
127164469µs my ($self, $domain, $id) = @_;
128 my $key = $domain.":".$id;
129110µs42813µs $key =~ s/\s+/_/g;
# spent 461µs making 41 calls to SimpleDB::Class::Cache::CORE:subst, avg 11µs/call # spent 352µs making 1 call to utf8::SWASHNEW
130 return $key;
131}
132
133#-------------------------------------------------------------------
134
135=head2 delete ( domain, id )
136
137Delete a key from the cache.
138
139Throws SimpleDB::Class::Exception::InvalidParam, SimpleDB::Class::Exception::Connection and SimpleDB::Class::Exception.
140
141=head3 domain
142
143The domain name to delete from.
144
145=head3 id
146
147The key to delete.
148
149=cut
150
151sub delete {
152 my $self = shift;
153 my ($domain, $id, $retry) = validate_pos(@_, { type => SCALAR }, { type => SCALAR }, { optional => 1 } );
154 my $key = $self->fix_key($domain, $id);
155 my $memcached = $self->memcached;
156 Memcached::libmemcached::memcached_delete($memcached, $key);
157 if ($memcached->errstr eq 'SYSTEM ERROR Unknown error: 0') {
158 SimpleDB::Class::Exception::Connection->throw(
159 error => "Cannot connect to memcached server."
160 );
161 }
162 elsif ($memcached->errstr eq 'UNKNOWN READ FAILURE' ) {
163 if ($retry) {
164 SimpleDB::Class::Exception::Connection->throw(
165 error => "Cannot connect to memcached server."
166 );
167 }
168 else {
169 warn "Memcached went away, reconnecting.";
170 $self->clear_memcached;
171 $self->delete($domain, $id, 1);
172 }
173 }
174 elsif ($memcached->errstr eq 'NOT FOUND' ) {
175 SimpleDB::Class::Exception::ObjectNotFound->throw(
176 error => "The cache key $key has no value.",
177 id => $key,
178 );
179 }
180 elsif ($memcached->errstr eq 'NO SERVERS DEFINED') {
181 SimpleDB::Class::Exception->throw(
182 error => "No memcached servers specified."
183 );
184 }
185 elsif ($memcached->errstr ne 'SUCCESS' # deleted
186 && $memcached->errstr ne 'PROTOCOL ERROR' # doesn't exist to delete
187 ) {
188 SimpleDB::Class::Exception->throw(
189 error => "Couldn't delete $key from cache because ".$memcached->errstr
190 );
191 }
192}
193
194#-------------------------------------------------------------------
195
196=head2 flush ( )
197
198Empties the caching system.
199
200Throws SimpleDB::Class::Exception::Connection and SimpleDB::Class::Exception.
201
202=cut
203
204
# spent 1.93ms (123µs+1.80) within SimpleDB::Class::Cache::flush which was called 3 times, avg 642µs/call: # once (41µs+1.06ms) by main::RUNTIME at line 19 of 05.Domain_and_Item.t # once (44µs+414µs) by main::RUNTIME at line 105 of 05.Domain_and_Item.t # once (38µs+326µs) by main::RUNTIME at line 128 of 05.Domain_and_Item.t
sub flush {
205121.79ms my ($self, $retry) = @_;
206 my $memcached = $self->memcached;
# spent 143µs making 3 calls to SimpleDB::Class::Cache::memcached, avg 48µs/call
207 Memcached::libmemcached::memcached_flush($memcached);
# spent 1.63ms making 3 calls to Memcached::libmemcached::memcached_flush, avg 542µs/call
208 if ($memcached->errstr eq 'SYSTEM ERROR Unknown error: 0') {
# spent 34µs making 12 calls to Memcached::libmemcached::errstr, avg 3µs/call
209 SimpleDB::Class::Exception::Connection->throw(
210 error => "Cannot connect to memcached server."
211 );
212 }
213 elsif ($memcached->errstr eq 'UNKNOWN READ FAILURE' ) {
214 SimpleDB::Class::Exception::Connection->throw(
215 error => "Cannot connect to memcached server."
216 ) if $retry;
217
218 warn "Memcached went away, reconnecting.";
219 $self->clear_memcached;
220 return $self->flush(1);
221 }
222 elsif ($memcached->errstr eq 'NO SERVERS DEFINED') {
223 SimpleDB::Class::Exception->throw(
224 error => "No memcached servers specified."
225 );
226 }
227 elsif ($memcached->errstr ne 'SUCCESS') {
228 SimpleDB::Class::Exception->throw(
229 error => "Couldn't flush cache because ".$memcached->errstr
230 );
231 }
232}
233
234#-------------------------------------------------------------------
235
236=head2 get ( domain, id )
237
238Retrieves a key value from the cache.
239
240Throws SimpleDB::Class::Exception::InvalidObject, SimpleDB::Class::Exception::InvalidParam, SimpleDB::Class::Exception::ObjectNotFound, SimpleDB::Class::Exception::Connection and SimpleDB::Class::Exception.
241
242=head3 domain
243
244The domain name to retrieve from.
245
246=head3 id
247
248The key to retrieve.
249
250=cut
251
252
# spent 25.3ms (1.16+24.1) within SimpleDB::Class::Cache::get which was called 24 times, avg 1.05ms/call: # 18 times (791µs+17.6ms) by SimpleDB::Class::ResultSet::next at line 464 of ../lib/SimpleDB/Class/ResultSet.pm, avg 1.02ms/call # 6 times (371µs+6.53ms) by SimpleDB::Class::Domain::find at line 155 of ../lib/SimpleDB/Class/Domain.pm, avg 1.15ms/call
sub get {
2531687.11ms my $self = shift;
2541660µs241.36ms my ($domain, $id, $retry) = validate_pos(@_, { type => SCALAR }, { type => SCALAR }, { optional => 1 });
# spent 1.36ms making 24 calls to Params::Validate::_validate_pos, avg 57µs/call
255 my $key = $self->fix_key($domain, $id);
# spent 657µs making 24 calls to SimpleDB::Class::Cache::fix_key, avg 27µs/call
256 my $memcached = $self->memcached;
# spent 117µs making 24 calls to SimpleDB::Class::Cache::memcached, avg 5µs/call
257 my $content = Memcached::libmemcached::memcached_get($memcached, $key);
# spent 5.18ms making 24 calls to Memcached::libmemcached::memcached_get, avg 216µs/call
258 $content = Storable::thaw($content);
# spent 12.8ms making 23 calls to Storable::thaw, avg 556µs/call # spent 467µs making 1 call to AutoLoader::AUTOLOAD
259 if ($memcached->errstr eq 'SUCCESS') {
# spent 2.26ms making 5 calls to Exception::Class::Base::throw, avg 451µs/call # spent 97µs making 29 calls to Memcached::libmemcached::errstr, avg 3µs/call
260 if (ref $content) {
261 return $content;
262 }
263 else {
264 SimpleDB::Class::Exception::InvalidObject->throw(
265 error => "Couldn't thaw value for $key."
266 );
267 }
268 }
269 elsif ($memcached->errstr eq 'NOT FOUND' ) {
270 SimpleDB::Class::Exception::ObjectNotFound->throw(
271 error => "The cache key $key has no value.",
272 id => $key,
273 );
274 }
275 elsif ($memcached->errstr eq 'NO SERVERS DEFINED') {
276 SimpleDB::Class::Exception->throw(
277 error => "No memcached servers specified."
278 );
279 }
280 elsif ($memcached->errstr eq 'SYSTEM ERROR Unknown error: 0' || $retry) {
281 SimpleDB::Class::Exception::Connection->throw(
282 error => "Cannot connect to memcached server."
283 );
284 }
285 elsif ($memcached->errstr eq 'UNKNOWN READ FAILURE' ) {
286 warn "Memcached went away, reconnecting.";
287 $self->clear_memcached;
288 return $self->get($domain, $id, 1);
289 }
290 SimpleDB::Class::Exception->throw(
291 error => "Couldn't get $key from cache because ".$memcached->errstr
292 );
293}
294
295#-------------------------------------------------------------------
296
297=head2 mget ( keys )
298
299Retrieves multiple values from cache at once, which is much faster than retrieving one at a time. Returns an array reference containing the values in the order they were requested.
300
301Throws SimpleDB::Class::Exception::InvalidParam, SimpleDB::Class::Exception::Connection and SimpleDB::Class::Exception.
302
303=head3 keys
304
305An array reference of domain names and ids to retrieve.
306
307=cut
308
309sub mget {
310 my $self = shift;
311 my ($names) = validate_pos(@_, { type => ARRAYREF });
312 my $retry = shift;
313 my @keys = map { $self->fix_key(@{$_}) } @{ $names };
314 my %result;
315 my $memcached = $self->memcached;
316 $memcached->mget_into_hashref(\@keys, \%result);
317 if ($memcached->errstr eq 'SYSTEM ERROR Unknown error: 0') {
318 SimpleDB::Class::Exception::Connection->throw(
319 error => "Cannot connect to memcached server."
320 );
321 }
322 elsif ($memcached->errstr eq 'UNKNOWN READ FAILURE' ) {
323 SimpleDB::Class::Exception::Connection->throw(
324 error => "Cannot connect to memcached server."
325 ) if $retry;
326 warn "Memcached went away, reconnecting.";
327 $self->clear_memcached;
328 return $self->get($names, 1);
329 }
330 elsif ($memcached->errstr eq 'NO SERVERS DEFINED') {
331 SimpleDB::Class::Exception->throw(
332 error => "No memcached servers specified."
333 );
334 }
335 # no other useful status messages are returned
336 my @values;
337 foreach my $key (@keys) {
338 my $content = Storable::thaw($result{$key});
339 unless (ref $content) {
340 SimpleDB::Class::Exception::InvalidObject->throw(
341 id => $key,
342 error => "Can't thaw object returned from memcache for $key.",
343 );
344 next;
345 }
346 push @values, $content;
347 }
348 return \@values;
349}
350
351#-------------------------------------------------------------------
352
353=head2 set ( domain, id, value [, ttl] )
354
355Sets a key value to the cache.
356
357Throws SimpleDB::Class::Exception::InvalidParam, SimpleDB::Class::Exception::Connection, and SimpleDB::Class::Exception.
358
359=head3 domain
360
361The name of the domain to set the info into.
362
363=head3 id
364
365The name of the key to set.
366
367=head3 value
368
369A hash reference to store.
370
371=head3 ttl
372
373A time in seconds for the cache to exist. Default is 3600 seconds (1 hour).
374
375=cut
376
377
# spent 8.44ms (809µs+7.63) within SimpleDB::Class::Cache::set which was called 17 times, avg 496µs/call: # 12 times (608µs+6.05ms) by SimpleDB::Class::Item::put at line 497 of ../lib/SimpleDB/Class/Item.pm, avg 555µs/call # 3 times (119µs+891µs) by SimpleDB::Class::ResultSet::next at line 470 of ../lib/SimpleDB/Class/ResultSet.pm, avg 336µs/call # 2 times (83µs+687µs) by SimpleDB::Class::Domain::find at line 168 of ../lib/SimpleDB/Class/Domain.pm, avg 385µs/call
sub set {
3781365.34ms my $self = shift;
3791418µs17714µs my ($domain, $id, $value, $ttl, $retry) = validate_pos(@_, { type => SCALAR }, { type => SCALAR }, { type => HASHREF }, { type => SCALAR | UNDEF, optional => 1 }, { optional => 1 });
# spent 714µs making 17 calls to Params::Validate::_validate_pos, avg 42µs/call
380 my $key = $self->fix_key($domain, $id);
# spent 175µs making 17 calls to SimpleDB::Class::Cache::fix_key, avg 10µs/call
381 $ttl ||= 60;
382 my $frozenValue = Storable::nfreeze($value);
# spent 1.72ms making 16 calls to Storable::nfreeze, avg 108µs/call # spent 337µs making 1 call to AutoLoader::AUTOLOAD
383 my $memcached = $self->memcached;
# spent 90µs making 17 calls to SimpleDB::Class::Cache::memcached, avg 5µs/call
384 Memcached::libmemcached::memcached_set($memcached, $key, $frozenValue, $ttl);
# spent 4.16ms making 17 calls to Memcached::libmemcached::memcached_set, avg 245µs/call
385 if ($memcached->errstr eq 'SUCCESS') {
# spent 76µs making 17 calls to Memcached::libmemcached::errstr, avg 4µs/call
386 return $value;
387 }
388 elsif ($memcached->errstr eq 'SYSTEM ERROR Unknown error: 0' || $retry) {
389 SimpleDB::Class::Exception::Connection->throw(
390 error => "Cannot connect to memcached server."
391 );
392 }
393 elsif ($memcached->errstr eq 'UNKNOWN READ FAILURE' ) {
394 warn "Memcached went away, reconnecting.";
395 $self->clear_memcached;
396 return $self->set($domain, $id, $value, $ttl, 1);
397 }
398 elsif ($memcached->errstr eq 'NO SERVERS DEFINED') {
399 SimpleDB::Class::Exception->throw(
400 error => "No memcached servers specified."
401 );
402 }
403 SimpleDB::Class::Exception->throw(
404 error => "Couldn't set $key to cache because ".$memcached->errstr
405 );
406 return $value;
407}
408
409
410=head1 EXCEPTIONS
411
412This class throws a lot of inconvenient, but useful exceptions. If you just want to avoid them you could:
413
414 my $value = eval { $cache->get($key) };
415 if (SimpleDB::Class::Exception::ObjectNotFound->caught) {
416 $value = $db->fetchValueFromTheDatabase;
417 }
418
419The exceptions that can be thrown are:
420
421=head2 SimpleDB::Class::Exception
422
423When an uknown exception happens, or there are no configured memcahed servers in the cacheServers directive in your config file.
424
425=head2 SimpleDB::Class::Exception::Connection
426
427When it can't connect to the memcached servers that are configured.
428
429=head2 SimpleDB::Class::Exception::InvalidParam
430
431When you pass in the wrong arguments.
432
433=head2 SimpleDB::Class::Exception::ObjectNotFound
434
435When you request a cache key that doesn't exist on any configured memcached server.
436
437=head2 SimpleDB::Class::Exception::InvalidObject
438
439When an object can't be thawed from cache due to corruption of some sort.
440
441=head1 LEGAL
442
443SimpleDB::Class is Copyright 2009-2010 Plain Black Corporation (L<http://www.plainblack.com/>) and is licensed under the same terms as Perl itself.
444
445=cut
446
447
448345µs2257µs
# spent 134µs (11+123) within SimpleDB::Class::Cache::BEGIN@448 which was called # once (11µs+123µs) by SimpleDB::Class::BEGIN@139 at line 448
no Moose;
# spent 134µs making 1 call to SimpleDB::Class::Cache::BEGIN@448 # spent 123µs making 1 call to Moose::Exporter::__ANON__[Moose/Exporter.pm:478]
449148µs215.3ms__PACKAGE__->meta->make_immutable;
# spent 15.3ms making 1 call to Class::MOP::Class::make_immutable # spent 14µs making 1 call to SimpleDB::Class::Cache::meta
450
# spent 461µs (110+352) within SimpleDB::Class::Cache::CORE:subst which was called 41 times, avg 11µs/call: # 41 times (110µs+352µs) by SimpleDB::Class::Cache::fix_key at line 129 of ../lib/SimpleDB/Class/Cache.pm, avg 11µs/call
sub SimpleDB::Class::Cache::CORE:subst; # xsub