File Coverage

blib/lib/Cache/Memcached/Fast/Safe.pm
Criterion Covered Total %
statement 36 103 34.9
branch 0 12 0.0
condition 0 3 0.0
subroutine 12 20 60.0
pod 2 2 100.0
total 50 140 35.7


line stmt bran cond sub pod time code
1             package Cache::Memcached::Fast::Safe;
2              
3 3     3   307206 use strict;
  3         6  
  3         78  
4 3     3   15 use warnings;
  3         5  
  3         88  
5 3     3   1080 use Cache::Memcached::Fast 0.19;
  3         6837  
  3         111  
6 3     3   1030 use Digest::SHA qw/sha1_hex/;
  3         6836  
  3         236  
7 3     3   333 use parent qw/Cache::Memcached::Fast/;
  3         284  
  3         20  
8 3     3   839 use POSIX::AtFork;
  3         1157  
  3         124  
9 3     3   18 use Scalar::Util qw/weaken/;
  3         6  
  3         201  
10              
11             our $VERSION = '0.06';
12             our $SANITIZE_METHOD = \&_sanitize_method;
13              
14             {
15 3     3   1006 use bytes;
  3         35  
  3         12  
16             my %escapes = map { chr($_) => sprintf('%%%02X', $_) } (0x00..0x20, 0x7f..0xff);
17             sub _sanitize_method {
18 0     0     my $key = shift;
19 0           $key =~ s/([\x00-\x20\x7f-\xff])/$escapes{$1}/ge;
  0            
20 0 0         if ( length $key > 200 ) {
21 0           $key = sha1_hex($key);
22             }
23 0           $key;
24             }
25             }
26              
27             sub new {
28 0     0 1   my $class = shift;
29 0 0         my %args = ref $_[0] ? %{$_[0]} : @_;
  0            
30 0           my $mem = $class->SUPER::new(\%args);
31             # fork safe
32 0           weaken(my $mem_weaken = $mem);
33             POSIX::AtFork->add_to_child(sub {
34 0     0     eval { $mem_weaken->disconnect_all };
  0            
35 0           });
36 0           $mem;
37             }
38              
39             for my $method ( qw/set cas add replace append prepend incr decr delete touch/ ) {
40 3     3   792 no strict 'refs';
  3         6  
  3         368  
41             my $super = 'SUPER::'.$method;
42             *{$method} = sub {
43 0     0     my $self = shift;
44 0           my $key = shift;
45 0           $self->$super($SANITIZE_METHOD->($key), @_);
46             };
47             }
48             for my $method (qw/set_multi cas_multi add_multi replace_multi append_multi prepend_multi incr_multi decr_multi delete_multi touch_multi/ ) {
49 3     3   27 no strict 'refs';
  3         6  
  3         751  
50             my $super = 'SUPER::'.$method;
51             *{$method} = sub {
52 0     0     my $self = shift;
53 0           my @request = @_;
54 0           my @request_keys;
55             my %sanitized_keys;
56 0           my @sanitized_request;
57 0           for my $keyval (@request) {
58 0           my $key;
59             my $sanitized_key;
60 0           my $sanitized_keyval;
61 0 0         if ( ref $keyval ) {
62 0           my @keyval = @$keyval;
63 0           $key = shift @keyval;
64 0           $sanitized_key = $SANITIZE_METHOD->($key);
65 0           $sanitized_keyval = [$sanitized_key, @keyval];
66             }
67             else {
68 0           $key = $keyval;
69 0           $sanitized_key = $SANITIZE_METHOD->($key);
70 0           $sanitized_keyval = $sanitized_key
71             }
72 0           $sanitized_keys{$sanitized_key} = $key;
73 0           push @request_keys, $key;
74 0           push @sanitized_request, $sanitized_keyval;
75             }
76 0           my $sanitized_result = $self->$super(@sanitized_request);
77 0           my %result;
78 0           for my $key ( keys %$sanitized_result ) {
79 0           $result{$sanitized_keys{$key}} = $sanitized_result->{$key};
80             }
81 0 0         if ( wantarray ) {
82 0           my @result;
83 0           for my $key ( @request_keys ) {
84 0           push @result, $result{$key};
85             }
86 0           return @result;
87             }
88 0           \%result;
89             }
90             }
91              
92             *remove = \&delete;
93              
94             for my $method (qw/get gets/) {
95 3     3   22 no strict 'refs';
  3         6  
  3         260  
96             my $super = 'SUPER::'.$method;
97             *{$method} = sub {
98 0     0     my $self = shift;
99 0           my $key = shift;
100 0           $self->$super($SANITIZE_METHOD->($key));
101             };
102             }
103             for my $method (qw/get_multi gets_multi/) {
104 3     3   19 no strict 'refs';
  3         7  
  3         645  
105             my $super = 'SUPER::'.$method;
106             *{$method} = sub {
107 0     0     my $self = shift;
108 0           my @request;
109             my %sanitized_keys;
110 0           for my $key (@_) {
111 0           my $sanitized_key = $SANITIZE_METHOD->($key);
112 0           $sanitized_keys{$sanitized_key} = $key;
113 0           push @request, $sanitized_key;
114             }
115 0 0         return {} if ! @request;
116 0           my $sanitized_result = $self->$super(@request);
117 0           my %result;
118 0           for my $key ( keys %$sanitized_result ) {
119 0           $result{$sanitized_keys{$key}} = $sanitized_result->{$key};
120             }
121 0           \%result;
122             }
123             }
124              
125             sub get_or_set {
126 0     0 1   my($self, $key, $sub, $expire) = @_;
127 0 0         if (my $value = $self->get($key)) {
128 0           return $value;
129             }
130 0           my ($value, $ret_expire) = $sub->();
131 0   0       $self->set($key, $value, $expire || $ret_expire);
132 0           $value;
133             }
134              
135             1;
136              
137             __END__