line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package MemcacheDBI; |
2
|
3
|
|
|
3
|
|
2826
|
use strict; |
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
126
|
|
3
|
3
|
|
|
3
|
|
17
|
use warnings; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
93
|
|
4
|
3
|
|
|
3
|
|
11601
|
use DBI; |
|
3
|
|
|
|
|
73863
|
|
|
3
|
|
|
|
|
245
|
|
5
|
3
|
|
|
3
|
|
2838
|
use Clone; |
|
3
|
|
|
|
|
9640
|
|
|
3
|
|
|
|
|
170
|
|
6
|
3
|
|
|
3
|
|
23
|
use vars qw( $AUTOLOAD $VERSION ); |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
2705
|
|
7
|
|
|
|
|
|
|
$VERSION = '0.07'; |
8
|
|
|
|
|
|
|
require 5.10.0; |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
our $DEBUG; |
11
|
|
|
|
|
|
|
our $me = '[MemcacheDBI]'; |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=head1 NAME |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
MemcacheDBI - Queue memcache calls when in a dbh transaction |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
=head1 SYNOPSYS |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
MemcacheDBI is a drop in replacement for DBI. It allows you to do trivial caching of some objects in a somewhat transactionally safe manner. |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
use MemcacheDBI; |
22
|
|
|
|
|
|
|
my $dbh = MemcacheDBI->connect($data_source, $user, $password, {} ); # just like DBI |
23
|
|
|
|
|
|
|
$dbh->memd_init(\%memcache_connection_args) # see Cache::Memcached::Fast |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
# Cache::Memcached::Fast should work using these calls |
26
|
|
|
|
|
|
|
$dbh->memd->get(); |
27
|
|
|
|
|
|
|
$dbh->memd->set(); |
28
|
|
|
|
|
|
|
$memd = $dbh->memd; #get a handle you can use wherever |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
# DBI methods should all work as normal. Additional new methods listed below |
31
|
|
|
|
|
|
|
$dbh->prepare(); |
32
|
|
|
|
|
|
|
$dbh->execute(); |
33
|
|
|
|
|
|
|
etc |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
=head1 DESCRIPTION |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
Attach your memcached to your DBH handle. By doing so we can automatically queue set/get calls so that they happen at the same time as a commit. If a rollback is issued then the queue will be cleared. |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
=head1 CAVEATS |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
As long as DBI and Memcache are both up and running your fine. However this module will experience race conditions when one or the other goes down. We are currently working to see if some of this can be minimized, but be aware it is impossible to protect you if the DB/Memcache servers go down. |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
=head1 METHODS |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
=head2 memd_init |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
Normally you would use a MemcacheDBI->connect to create a new handle. However if you already have a DBH handle you can use this method to create a MemcacheDBI object using your existing handle. |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
Accepts a the following data types |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
Cache::Memcached::Fast (new Cache::Memcached::Fast) |
52
|
|
|
|
|
|
|
A DBI handle (DBI->connect) |
53
|
|
|
|
|
|
|
HASH of arguments to pass to new Cache::Memcached::Fast |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
=cut |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
sub memd_init { |
58
|
0
|
0
|
0
|
0
|
1
|
0
|
warn "[debug $DEBUG]$me->memd_init\n" if $DEBUG && $DEBUG > 3; |
59
|
0
|
|
|
|
|
0
|
my $class = shift; |
60
|
0
|
0
|
|
|
|
0
|
my $node = ref $class ? $class : do{ tie my %node, 'MemcacheDBI::Tie'; warn 'whee'; \%node; }; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
61
|
0
|
|
|
|
|
0
|
while (my $handle = shift) { |
62
|
0
|
0
|
|
|
|
0
|
if (ref $handle eq 'DBI::db') { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
63
|
0
|
|
|
|
|
0
|
$node->{'MemcacheDBI'}->{'dbh'} = $handle; |
64
|
|
|
|
|
|
|
} elsif (ref $handle eq 'Cache::Memcached::Fast') { |
65
|
0
|
|
|
|
|
0
|
$node->{'MemcacheDBI'}->{'memd'} = MemcacheDBI::Memd->memd_init($node,$handle); |
66
|
|
|
|
|
|
|
} elsif (ref $handle eq 'HASH') { |
67
|
0
|
|
|
|
|
0
|
$node->{'MemcacheDBI'}->{'memd'} = MemcacheDBI::Memd->memd_init($node,$handle); |
68
|
|
|
|
|
|
|
} else { |
69
|
0
|
|
|
|
|
0
|
die 'Unknown ref type'.do{my @c = caller; ' at '.$c[1].' line '.$c[2]."\n" }; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
70
|
|
|
|
|
|
|
} |
71
|
|
|
|
|
|
|
} |
72
|
0
|
0
|
|
|
|
0
|
if (! ref $class) { |
73
|
0
|
0
|
|
|
|
0
|
return unless $node->{'MemcacheDBI'}->{'dbh'}; |
74
|
0
|
|
|
|
|
0
|
return bless $node, $class; |
75
|
|
|
|
|
|
|
} |
76
|
0
|
|
|
|
|
0
|
return $class; |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
=head2 memd |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
Get a memcache object that supports get/set/transactions |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
=cut |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
sub memd { |
86
|
0
|
|
|
0
|
1
|
0
|
shift->{'MemcacheDBI'}->{'memd'}; |
87
|
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
=head1 DBI methods can also be used, including but not limited to: |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
=head2 connect |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
The same as DBI->connect, returns a MemcacheDBI object so you can get your additional memcache functionality |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
=cut |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
sub connect { |
98
|
2
|
50
|
33
|
2
|
1
|
1801
|
warn "[debug $DEBUG]$me->connect\n" if $DEBUG && $DEBUG > 3; |
99
|
2
|
|
|
|
|
3
|
my $class = shift; |
100
|
2
|
|
|
|
|
9
|
tie my %node, 'MemcacheDBI::Tie'; |
101
|
2
|
50
|
|
|
|
4
|
eval{ $node{'MemcacheDBI'}->{'dbh'} = DBI->connect(@_) } or die $@.do{my @c = caller; ' at '.$c[1].' line '.$c[2]."\n" }; |
|
2
|
|
|
|
|
2615
|
|
|
2
|
|
|
|
|
229
|
|
|
2
|
|
|
|
|
13
|
|
102
|
0
|
0
|
|
|
|
0
|
return unless $node{'MemcacheDBI'}->{'dbh'}; |
103
|
0
|
|
|
|
|
0
|
return bless \%node, $class; |
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
=head2 commit |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
The same as DBI->commit, however it will also commit the memcached queue |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
=cut |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
sub commit { |
113
|
0
|
0
|
0
|
0
|
1
|
0
|
warn "[debug $DEBUG]$me->commit\n" if $DEBUG && $DEBUG > 3; |
114
|
0
|
|
|
|
|
0
|
my $self = shift; |
115
|
|
|
|
|
|
|
# TODO handle rolling back the memcache stuff if dbh fails |
116
|
0
|
0
|
|
|
|
0
|
warn 'Commit ineffective while AutoCommit is on'.do{my @c = caller; ' at '.$c[1].' line '.$c[2]."\n" } if $self->{'AutoCommit'}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
117
|
0
|
|
|
|
|
0
|
my $memd = $self->memd; |
118
|
0
|
0
|
|
|
|
0
|
$memd->commit if $memd; |
119
|
0
|
|
|
|
|
0
|
$self->{'MemcacheDBI'}->{'dbh'}->commit(@_); |
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
=head2 rollback |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
The same as DBI->rollback, however it will also rollback the memcached queue |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
=cut |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
sub rollback { |
129
|
0
|
0
|
0
|
0
|
1
|
0
|
warn "[debug $DEBUG]$me->rollback\n" if $DEBUG && $DEBUG > 3; |
130
|
0
|
|
|
|
|
0
|
my $self = shift; |
131
|
0
|
|
|
|
|
0
|
delete $self->{'MemcacheDBI'}->{'queue'}; |
132
|
0
|
0
|
|
|
|
0
|
warn 'rollback ineffective with AutoCommit enabled'.do{my @c = caller; ' at '.$c[1].' line '.$c[2]."\n" } if $self->{'AutoCommit'}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
133
|
0
|
|
|
|
|
0
|
$self->{'MemcacheDBI'}->{'dbh'}->rollback(@_); |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
sub AUTOLOAD { |
137
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
138
|
0
|
|
|
|
|
0
|
my($field)=$AUTOLOAD; |
139
|
0
|
|
|
|
|
0
|
$field =~ s/.*://; |
140
|
0
|
|
|
|
|
0
|
my $method = (ref $self).'::'.$field; |
141
|
0
|
0
|
0
|
|
|
0
|
warn "[debug $DEBUG]$me create autoload for $method\n" if $DEBUG && $DEBUG > 1; |
142
|
3
|
|
|
3
|
|
19
|
no strict 'refs'; ## no critic |
|
3
|
|
|
|
|
14
|
|
|
3
|
|
|
|
|
4750
|
|
143
|
|
|
|
|
|
|
*$method = sub { |
144
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
145
|
0
|
0
|
0
|
|
|
0
|
warn "[debug $DEBUG]${me}->{'dbh'}->$field\n" if $DEBUG && $DEBUG > 3; |
146
|
0
|
0
|
|
|
|
0
|
die 'Can\'t locate object method "'.$field.'" via package "'.(ref $self->{'MemcacheDBI'}->{'dbh'}).'"'.do{my @c = caller; ' at '.$c[1].' line '.$c[2]."\n" } unless $self->{'MemcacheDBI'}->{'dbh'}->can($field); |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
147
|
0
|
|
|
|
|
0
|
$self->{'MemcacheDBI'}->{'dbh'}->$field(@_); |
148
|
0
|
|
|
|
|
0
|
}; |
149
|
0
|
0
|
|
|
|
0
|
die 'Can\'t locate object method "'.$field.'" via package "'.(ref $self->{'MemcacheDBI'}->{'dbh'}).'"'.do{my @c = caller; ' at '.$c[1].' line '.$c[2]."\n" } unless $self->{'MemcacheDBI'}->{'dbh'}->can($field); |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
150
|
0
|
|
|
|
|
0
|
$self->$field(@_); |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
package MemcacheDBI::Memd; |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
sub memd_init { |
156
|
0
|
|
|
0
|
|
0
|
my $class = shift; |
157
|
0
|
|
|
|
|
0
|
my $dbh = shift; |
158
|
0
|
|
|
|
|
0
|
my $handle = shift; |
159
|
0
|
|
|
|
|
0
|
tie my %node, 'MemcacheDBI::Tie', 'memd'; |
160
|
0
|
|
|
|
|
0
|
require Cache::Memcached::Fast; |
161
|
0
|
0
|
|
|
|
0
|
$handle = Cache::Memcached::Fast->new($handle) if ref $handle eq 'HASH'; |
162
|
0
|
|
|
|
|
0
|
$node{'MemcacheDBI'}{'memd'} = $handle; |
163
|
0
|
|
|
|
|
0
|
$node{'MemcacheDBI'}{'dbh'} = $dbh; # careful, circular |
164
|
0
|
|
|
|
|
0
|
return bless \%node, $class; |
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
sub get { |
168
|
0
|
|
|
0
|
|
0
|
my ($self,$key) = @_; |
169
|
0
|
0
|
|
|
|
0
|
return if $self->{'MemcacheDBI'}->{'dbh'}->{'MemcacheDBI'}->{'queue_delete'}->{$key}; |
170
|
0
|
0
|
|
|
|
0
|
if (exists $self->{'MemcacheDBI'}->{'dbh'}->{'MemcacheDBI'}->{'queue'}->{$key}) { |
171
|
0
|
|
|
|
|
0
|
return $self->{'MemcacheDBI'}->{'dbh'}->{'MemcacheDBI'}->{'queue'}->{$key}; |
172
|
|
|
|
|
|
|
} |
173
|
0
|
|
|
|
|
0
|
$self->{'MemcacheDBI'}->{'memd'}->get($key); |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
sub set { |
177
|
0
|
|
|
0
|
|
0
|
my ($self,$key,$value) = @_; |
178
|
0
|
|
|
|
|
0
|
delete $self->{'MemcacheDBI'}->{'dbh'}->{'MemcacheDBI'}->{'queue_delete'}->{$key}; |
179
|
0
|
0
|
|
|
|
0
|
if ($self->{'MemcacheDBI'}->{'dbh'}->{'AutoCommit'}) { |
180
|
0
|
|
|
|
|
0
|
delete $self->{'MemcacheDBI'}->{'dbh'}->{'MemcacheDBI'}->{'queue'}->{$key}; |
181
|
0
|
|
|
|
|
0
|
return $self->{'MemcacheDBI'}->{'memd'}->set($key, $value); |
182
|
|
|
|
|
|
|
} |
183
|
0
|
|
|
|
|
0
|
$self->{'MemcacheDBI'}->{'dbh'}->{'MemcacheDBI'}->{'queue'}->{$key} = Clone::clone($value); |
184
|
0
|
|
|
|
|
0
|
1; |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
sub delete { |
188
|
0
|
|
|
0
|
|
0
|
my ($self,$key) = @_; |
189
|
0
|
0
|
|
|
|
0
|
if ($self->{'MemcacheDBI'}->{'dbh'}->{'AutoCommit'}) { |
190
|
0
|
|
|
|
|
0
|
delete $self->{'MemcacheDBI'}->{'dbh'}->{'MemcacheDBI'}->{'queue_delete'}->{$key}; |
191
|
0
|
|
|
|
|
0
|
delete $self->{'MemcacheDBI'}->{'dbh'}->{'MemcacheDBI'}->{'queue'}->{$key}; |
192
|
0
|
|
|
|
|
0
|
return $self->{'MemcacheDBI'}->{'memd'}->delete($key); |
193
|
|
|
|
|
|
|
} |
194
|
0
|
|
|
|
|
0
|
my $val = $self->get($key); |
195
|
0
|
|
|
|
|
0
|
delete $self->{'MemcacheDBI'}->{'dbh'}->{'MemcacheDBI'}->{'queue'}->{$key}; |
196
|
0
|
|
|
|
|
0
|
$self->{'MemcacheDBI'}->{'dbh'}->{'MemcacheDBI'}->{'queue_delete'}->{$key} = 1; |
197
|
0
|
0
|
|
|
|
0
|
$val ? 1 : ''; |
198
|
|
|
|
|
|
|
} |
199
|
0
|
|
|
0
|
|
0
|
sub remove { shift->delete(@_); } |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
sub namespace { |
202
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
203
|
0
|
0
|
0
|
|
|
0
|
if (scalar @_ && !$self->{'MemcacheDBI'}->{'dbh'}->{'AutoCommit'} && ( |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
204
|
|
|
|
|
|
|
$self->{'MemcacheDBI'}->{'dbh'}->{'MemcacheDBI'}->{'queue_delete'} |
205
|
|
|
|
|
|
|
|| $self->{'MemcacheDBI'}->{'dbh'}->{'MemcacheDBI'}->{'queue'} |
206
|
|
|
|
|
|
|
)) { |
207
|
0
|
|
|
|
|
0
|
die 'Cannot set namespace during a transaction'.do{my @c = caller; ' at '.$c[1].' line '.$c[2]."\n" }; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
208
|
|
|
|
|
|
|
} |
209
|
0
|
|
|
|
|
0
|
$self->{'MemcacheDBI'}->{'memd'}->namespace(@_); |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
|
212
|
0
|
|
|
0
|
|
0
|
sub server_versions { shift->{'MemcacheDBI'}->{'memd'}->server_versions(@_); } |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
# do not confuse this with DBH commits |
215
|
|
|
|
|
|
|
sub commit { |
216
|
0
|
|
|
0
|
|
0
|
my ($self) = @_; |
217
|
0
|
|
|
|
|
0
|
my $queue = $self->{'MemcacheDBI'}->{'dbh'}->{'MemcacheDBI'}->{'queue'}; |
218
|
0
|
|
|
|
|
0
|
foreach my $key (keys %$queue) { |
219
|
0
|
|
|
|
|
0
|
$self->{'MemcacheDBI'}->{'memd'}->set($key, $queue->{$key}); |
220
|
|
|
|
|
|
|
} |
221
|
0
|
|
|
|
|
0
|
delete $self->{'MemcacheDBI'}->{'queue'}; |
222
|
|
|
|
|
|
|
|
223
|
0
|
|
|
|
|
0
|
$queue = $self->{'MemcacheDBI'}->{'dbh'}->{'MemcacheDBI'}->{'queue_delete'}; |
224
|
0
|
|
|
|
|
0
|
foreach my $key (keys %$queue) { |
225
|
0
|
|
|
|
|
0
|
$self->{'MemcacheDBI'}->{'memd'}->delete($key); |
226
|
|
|
|
|
|
|
} |
227
|
0
|
|
|
|
|
0
|
delete $self->{'MemcacheDBI'}->{'queue_delete'}; |
228
|
|
|
|
|
|
|
|
229
|
0
|
|
|
|
|
0
|
return 1; |
230
|
|
|
|
|
|
|
} |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
package MemcacheDBI::Tie; |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
# passes all calls to the parent $tie_type unless the key is MemcacheDBI |
235
|
|
|
|
|
|
|
# allows me to wrap my data in a container while somewhat preseving the parents operation |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
sub TIEHASH { |
238
|
2
|
|
|
2
|
|
3
|
my $class = shift; |
239
|
2
|
|
50
|
|
|
16
|
my $tie_type = shift || 'dbh'; # dbh or memd |
240
|
2
|
|
|
|
|
10
|
return bless {MemcacheDBI=>{tie_type=>$tie_type}}, $class; |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
sub FETCH { |
244
|
0
|
|
|
0
|
|
|
my ($self,$key) = @_; |
245
|
0
|
|
|
|
|
|
my $short = $self->{'MemcacheDBI'}; |
246
|
0
|
0
|
|
|
|
|
return $short if $key eq 'MemcacheDBI'; |
247
|
0
|
|
|
|
|
|
$short->{$short->{'tie_type'}}->{$key}; |
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
sub STORE { |
251
|
0
|
|
|
0
|
|
|
my ($self,$key,$value) = @_; |
252
|
0
|
|
|
|
|
|
my $short = $self->{'MemcacheDBI'}; |
253
|
0
|
|
|
|
|
|
$short->{$short->{'tie_type'}}->{$key} = $value; |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
sub DELETE { |
257
|
0
|
|
|
0
|
|
|
my ($self,$key) = @_; |
258
|
0
|
0
|
|
|
|
|
die 'Cannot delete MemcacheDBI'.do{my @c = caller; ' at '.$c[1].' line '.$c[2]."\n" } if $key eq 'MemcacheDBI'; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
259
|
0
|
|
|
|
|
|
my $short = $self->{'MemcacheDBI'}; |
260
|
0
|
|
|
|
|
|
delete $short->{$short->{'tie_type'}}->{$key}; |
261
|
|
|
|
|
|
|
} |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
sub CLEAR { |
264
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
sub FIRSTKEY { |
268
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
269
|
0
|
|
|
|
|
|
my $tmp = $self->{'MemcacheDBI'}->{$self->{'MemcacheDBI'}->{'tie_type'}}; |
270
|
0
|
0
|
|
|
|
|
return unless ref $tmp eq 'HASH'; |
271
|
0
|
|
|
|
|
|
keys %$tmp; |
272
|
0
|
|
|
|
|
|
return scalar each %$tmp; |
273
|
|
|
|
|
|
|
} |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
sub NEXTKEY { |
276
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
277
|
0
|
|
|
|
|
|
my $tmp = $self->{'MemcacheDBI'}->{$self->{'MemcacheDBI'}->{'tie_type'}}; |
278
|
0
|
|
|
|
|
|
return scalar each %$tmp; |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
sub EXISTS { |
282
|
0
|
|
|
0
|
|
|
my ($self,$key) = @_; |
283
|
0
|
|
|
|
|
|
return exists $self->{'MemcacheDBI'}->{$self->{'MemcacheDBI'}->{'tie_type'}}->{$key}; |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
1; |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
=head1 REPOSITORY |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
The code is available on github: |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
https://github.com/oaxlin/MemcacheDBI.git |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
=head1 DISCLAIMER |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED |
297
|
|
|
|
|
|
|
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF |
298
|
|
|
|
|
|
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
299
|
|
|
|
|
|
|
|