File Coverage

blib/lib/DBM/Deep.pm
Criterion Covered Total %
statement 687 687 100.0
branch 114 130 87.6
condition 32 44 72.7
subroutine 229 229 100.0
pod 26 26 100.0
total 1088 1116 97.4


line stmt bran cond sub pod time code
1             package DBM::Deep;
2              
3 93     93   331443 use 5.008_004;
  93         336  
4              
5 93     77   998 use strict;
  77         295  
  77         1369  
6 77     57   705 use warnings FATAL => 'all';
  57         138  
  57         2004  
7 57     57   426 no warnings 'recursion';
  57         146  
  57         3083  
8              
9             our $VERSION = q(2.0017);
10              
11 57     55   434 use Scalar::Util ();
  55         139  
  55         4818  
12              
13             use overload
14             (
15             '""' =>
16 94846     94846   254360 '0+' => sub { $_[0] },
17 54         549 )[0,2,1,2], # same sub for both
18 55     54   436 fallback => 1;
  54         174  
19              
20 54     54   4870 use constant DEBUG => 0;
  54         124  
  54         4187  
21              
22 54     54   25173 use DBM::Deep::Engine;
  54         132  
  54         4387  
23              
24 3716     3716 1 17018 sub TYPE_HASH () { DBM::Deep::Engine->SIG_HASH }
25 4518     4518 1 19599 sub TYPE_ARRAY () { DBM::Deep::Engine->SIG_ARRAY }
26              
27             my %obj_cache; # In external_refs mode, all objects are registered here,
28             # and dealt with in the END block at the bottom.
29 54     54   357 use constant HAVE_HUFH => scalar eval{ require Hash::Util::FieldHash };
  54         114  
  54         131  
  54         29171  
30             HAVE_HUFH and Hash::Util::FieldHash::fieldhash(%obj_cache);
31              
32             # This is used in all the children of this class in their TIE methods.
33             sub _get_args {
34 5654     5654   9018 my $proto = shift;
35              
36 5654         7356 my $args;
37 5654 100       13022 if (scalar(@_) > 1) {
    100          
38 3074 100       7009 if ( @_ % 2 ) {
39 5         54 $proto->_throw_error( "Odd number of parameters to " . (caller(1))[2] );
40             }
41 3072         10209 $args = {@_};
42             }
43             elsif ( ref $_[0] ) {
44 2558 50       4132 unless ( eval { local $SIG{'__DIE__'}; %{$_[0]} || 1 } ) {
  2558 100       8630  
  2558         3856  
  2558         12806  
45 5         50 $proto->_throw_error( "Not a hashref in args to " . (caller(1))[2] );
46             }
47 2556         4746 $args = $_[0];
48             }
49             else {
50 28         79 $args = { file => shift };
51             }
52              
53 5650         11272 return $args;
54             }
55              
56             # Class constructor method for Perl OO interface.
57             # Calls tie() and returns blessed reference to tied hash or array,
58             # providing a hybrid OO/tie interface.
59             sub new {
60 2716     2716 1 95578 my $class = shift;
61 2716         5922 my $args = $class->_get_args( @_ );
62 2716         4463 my $self;
63              
64 2716 100 100     8928 if (defined($args->{type}) && $args->{type} eq TYPE_ARRAY) {
65 2113         3352 $class = 'DBM::Deep::Array';
66 2113         13421 require DBM::Deep::Array;
67 2113         13315 tie @$self, $class, %$args;
68             }
69             else {
70 606         945 $class = 'DBM::Deep::Hash';
71 606         23702 require DBM::Deep::Hash;
72 606         3744 tie %$self, $class, %$args;
73             }
74              
75 2704         9933 return bless $self, $class;
76             }
77              
78             # This initializer is called from the various TIE* methods. new() calls tie(),
79             # which allows for a single point of entry.
80             sub _init {
81 2937     2937   4247 my $class = shift;
82 2937         4938 my ($args) = @_;
83              
84             # locking implicitly enables autoflush
85 2937 100       6171 if ($args->{locking}) { $args->{autoflush} = 1; }
  24         79  
86              
87             # These are the defaults to be optionally overridden below
88 2937         5651 my $self = bless {
89             type => TYPE_HASH,
90             base_offset => undef,
91             staleness => undef,
92             engine => undef,
93             }, $class;
94              
95 2937 100       7322 unless ( exists $args->{engine} ) {
96             my $class =
97             exists $args->{dbi} ? 'DBM::Deep::Engine::DBI' :
98 396 100       1099 exists $args->{_test} ? 'DBM::Deep::Engine::Test' :
    50          
99             'DBM::Deep::Engine::File' ;
100              
101 54 50   54   31245 eval "use $class"; die $@ if $@;
  54     1   322  
  54     1   1045  
  394     1   30816  
  394     1   1466  
  1     1   9  
  1     1   2  
  1     1   13  
  1     1   8  
  1     1   2  
  1     1   15  
  1     1   8  
  1     1   3  
  1     1   14  
  1     1   7  
  1     1   2  
  1     1   13  
  1     1   8  
  1     1   1  
  1     1   14  
  1     1   8  
  1     1   2  
  1     1   14  
  1     1   8  
  1     1   3  
  1     1   15  
  1     1   7  
  1     1   4  
  1     1   14  
  1     1   11  
  1     1   2  
  1     1   18  
  1     1   7  
  1     1   2  
  1     1   14  
  1     1   6  
  1     1   3  
  1     1   15  
  1     1   7  
  1     1   2  
  1     1   14  
  1     1   8  
  1     1   2  
  1     1   16  
  1     1   7  
  1     1   2  
  1     1   15  
  1     1   8  
  1     1   2  
  1     1   16  
  1     1   8  
  1     1   2  
  1     1   13  
  1     1   7  
  1     1   2  
  1     1   14  
  1     1   6  
  1     1   2  
  1     1   13  
  1     1   7  
  1     1   31  
  1     1   20  
  1     1   8  
  1     1   2  
  1     1   14  
  1     1   8  
  1     1   3  
  1     1   13  
  1     1   10  
  1     1   2  
  1     1   32  
  1     1   15  
  1     1   3  
  1     1   16  
  1     1   12  
  1     1   3  
  1     1   16  
  1     1   7  
  1     1   2  
  1     1   14  
  1     1   16  
  1     1   2  
  1     1   18  
  1     1   7  
  1     1   3  
  1     1   15  
  1     1   6  
  1     1   13  
  1     1   15  
  1     1   8  
  1     1   4  
  1     1   13  
  1     1   16  
  1     1   4  
  1     1   24  
  1     1   10  
  1     1   2  
  1     1   15  
  1     1   22  
  1     1   3  
  1     1   29  
  1     1   7  
  1     1   8  
  1     1   21  
  1     1   7  
  1     1   2  
  1     1   21  
  1     1   6  
  1     1   13  
  1     1   20  
  1     1   7  
  1     1   14  
  1     1   16  
  1     1   7  
  1     1   4  
  1     1   14  
  1     1   7  
  1     1   14  
  1     1   16  
  1     1   15  
  1     1   2  
  1     1   14  
  1     1   7  
  1     1   2  
  1     1   16  
  1     1   22  
  1     1   2  
  1     1   14  
  1     1   7  
  1     1   3  
  1     1   21  
  1     1   18  
  1     1   3  
  1     1   14  
  1     1   28  
  1     1   7  
  1     1   16  
  1     1   7  
  1     1   7  
  1     1   14  
  1     1   7  
  1     1   2  
  1     1   13  
  1     1   8  
  1     1   2  
  1     1   18  
  1     1   14  
  1     1   2  
  1     1   21  
  1     1   7  
  1     1   2  
  1     1   15  
  1     1   18  
  1     1   7  
  1     1   13  
  1     1   9  
  1     1   17  
  1     1   18  
  1     1   6  
  1     1   3  
  1     1   15  
  1     1   7  
  1     1   3  
  1     1   25  
  1     1   7  
  1     1   3  
  1     1   27  
  1     1   7  
  1     1   2  
  1     1   14  
  1         8  
  1         3  
  1         49  
  1         8  
  1         2  
  1         57  
  1         24  
  1         2  
  1         15  
  1         18  
  1         2  
  1         14  
  1         8  
  1         2  
  1         12  
  1         7  
  1         2  
  1         14  
  1         9  
  1         2  
  1         15  
  1         7  
  1         4  
  1         38  
  1         9  
  1         2  
  1         15  
  1         6  
  1         4  
  1         14  
  1         16  
  1         3  
  1         13  
  1         14  
  1         3  
  1         13  
  1         8  
  1         2  
  1         14  
  1         7  
  1         2  
  1         13  
  1         7  
  1         2  
  1         17  
  1         8  
  1         3  
  1         12  
  1         10  
  1         4  
  1         20  
  1         9  
  1         10  
  1         24  
  1         7  
  1         5  
  1         14  
  1         7  
  1         9  
  1         18  
  1         7  
  1         2  
  1         20  
  1         7  
  1         2  
  1         23  
  1         10  
  1         8  
  1         13  
  1         7  
  1         1  
  1         14  
  1         8  
  1         3  
  1         17  
  1         6  
  1         5  
  1         27  
  1         23  
  1         5  
  1         32  
  1         6  
  1         3  
  1         25  
  1         7  
  1         5  
  1         15  
  1         9  
  1         13  
  1         18  
  1         19  
  1         2  
  1         14  
  1         9  
  1         3  
  1         14  
  1         12  
  1         2  
  1         13  
  1         6  
  1         4  
  1         14  
  1         6  
  1         2  
  1         21  
  1         11  
  1         3  
  1         15  
  1         7  
  1         3  
  1         14  
  1         10  
  1         2  
  1         22  
  1         7  
  1         8  
  1         27  
  1         7  
  1         9  
  1         16  
  1         7  
  1         7  
  1         25  
  1         17  
  1         3  
  1         14  
  1         16  
  1         2  
  1         14  
  1         16  
  1         4  
  1         16  
  1         8  
  1         5  
  1         15  
  1         7  
  1         2  
  1         18  
  1         7  
  1         4  
  1         13  
  1         7  
  1         2  
  1         26  
  1         6  
  1         2  
  1         22  
  1         8  
  1         21  
  1         17  
  1         6  
  1         3  
  1         34  
  1         8  
  1         3  
  1         26  
  1         6  
  1         24  
  1         22  
  1         7  
  1         2  
  1         14  
  1         7  
  1         8  
  1         15  
  1         6  
  1         8  
  1         24  
102             $args->{engine} = $class->new({
103 394         739 %{$args},
  394         2782  
104             obj => $self,
105             });
106             }
107              
108             # Grab the parameters we want to use
109 2934         13301 foreach my $param ( keys %$self ) {
110 11733 100       19553 next unless exists $args->{$param};
111 10949         18560 $self->{$param} = $args->{$param};
112             }
113              
114 2934         5731 eval {
115 2934         8392 local $SIG{'__DIE__'};
116              
117 2934         9007 $self->lock_exclusive;
118 2933         5772 $self->_engine->setup( $self );
119 2921         6234 $self->unlock;
120 2934 100       6267 }; if ( $@ ) {
121 16         29 my $e = $@;
122 16         63 eval { local $SIG{'__DIE__'}; $self->unlock; };
  16         55  
  16         64  
123 16         96 die $e;
124             }
125              
126 2919 100 66     7362 if( $self->{engine}->{external_refs}
127             and my $sector = $self->{engine}->load_sector( $self->{base_offset} )
128             ) {
129 16         52 $sector->increment_refcount;
130              
131 16         58 Scalar::Util::weaken( my $feeble_ref = $self );
132 16         153 $obj_cache{ $self } = \$feeble_ref;
133              
134             # Make sure this cache is not a memory hog
135 16         30 if(!HAVE_HUFH) {
136             for(keys %obj_cache) {
137             delete $obj_cache{$_} if not ${$obj_cache{$_}};
138             }
139             }
140             }
141              
142 2919         10847 return $self;
143             }
144              
145             sub TIEHASH {
146 176     178   6948 shift;
147 176         3652 require DBM::Deep::Hash;
148 176         663 return DBM::Deep::Hash->TIEHASH( @_ );
149             }
150              
151             sub TIEARRAY {
152 51     53   2761 shift;
153 51         8567 require DBM::Deep::Array;
154 51         285 return DBM::Deep::Array->TIEARRAY( @_ );
155             }
156              
157             sub lock_exclusive {
158 5831     5833 1 12057 my $self = shift->_get_self;
159 5831         12145 return $self->_engine->lock_exclusive( $self, @_ );
160             }
161             *lock = \&lock_exclusive;
162              
163             sub lock_shared {
164 4627     4629 1 10039 my $self = shift->_get_self;
165             # cluck() the problem with cached File objects.
166 4627 50       8458 unless ( $self->_engine ) {
167 1         2 require Carp;
168 1         14 require Data::Dumper;
169 1         6 Carp::cluck( Data::Dumper->Dump( [$self], ['self'] ) );
170             }
171 4627         8056 return $self->_engine->lock_shared( $self, @_ );
172             }
173              
174             sub unlock {
175 10452     10454 1 23586 my $self = shift->_get_self;
176 10452         20434 return $self->_engine->unlock( $self, @_ );
177             }
178              
179             sub _copy_value {
180 72     72   151 my $self = shift->_get_self;
181 72         167 my ($spot, $value) = @_;
182              
183 72 100       181 if ( !ref $value ) {
184 40         59 ${$spot} = $value;
  40         90  
185             }
186             else {
187 33         123 my $r = Scalar::Util::reftype( $value );
188 33         49 my $tied;
189 33 100       98 if ( $r eq 'ARRAY' ) {
    50          
190 20         57 $tied = tied(@$value);
191             }
192             elsif ( $r eq 'HASH' ) {
193 14         28 $tied = tied(%$value);
194             }
195             else {
196 1         33 __PACKAGE__->_throw_error( "Unknown type for '$value'" );
197             }
198              
199 33 50       63 if ( eval { local $SIG{'__DIE__'}; $tied->isa( __PACKAGE__ ) } ) {
  33         111  
  33         227  
200 33         97 ${$spot} = $tied->_repr;
  33         62  
201 33         65 $tied->_copy_node( ${$spot} );
  33         139  
202             }
203             else {
204 1 0       3 if ( $r eq 'ARRAY' ) {
205 1         14 ${$spot} = [ @{$value} ];
  1         6  
  1         3  
206             }
207             else {
208 1         13 ${$spot} = { %{$value} };
  1         7  
  1         3  
209             }
210             }
211              
212 33         135 my $c = Scalar::Util::blessed( $value );
213 33 100 66     239 if ( defined $c && !$c->isa( __PACKAGE__ ) ) {
214 17         25 ${$spot} = bless ${$spot}, $c
  17         38  
  17         40  
215             }
216             }
217              
218 72         192 return 1;
219             }
220              
221             sub export {
222 13     13 1 88 my $self = shift->_get_self;
223              
224 13         51 my $temp = $self->_repr;
225              
226 13         51 $self->lock_exclusive;
227 13         76 $self->_copy_node( $temp );
228 13         60 $self->unlock;
229              
230 13         38 my $classname = $self->_engine->get_classname( $self );
231 13 100       72 if ( defined $classname ) {
232 5         17 bless $temp, $classname;
233             }
234              
235 13         65 return $temp;
236             }
237              
238             sub _check_legality {
239 98     98   141 my $self = shift;
240 98         170 my ($val) = @_;
241              
242 98         217 my $r = Scalar::Util::reftype( $val );
243              
244 98 100 66     426 return $r if !defined $r || '' eq $r;
245 62 100       161 return $r if 'HASH' eq $r;
246 31 100       114 return $r if 'ARRAY' eq $r;
247              
248 4         37 __PACKAGE__->_throw_error(
249             "Storage of references of type '$r' is not supported."
250             );
251             }
252              
253             sub import {
254 64 100   64   6862 return if !ref $_[0]; # Perl calls import() on use -- ignore
255              
256 13         44 my $self = shift->_get_self;
257 13         45 my ($struct) = @_;
258              
259 13         61 my $type = $self->_check_legality( $struct );
260 13 100       47 if ( !$type ) {
261 3         34 __PACKAGE__->_throw_error( "Cannot import a scalar" );
262             }
263              
264 11 100       49 if ( substr( $type, 0, 1 ) ne $self->_type ) {
265 3 100       16 __PACKAGE__->_throw_error(
    100          
266             "Cannot import " . ('HASH' eq $type ? 'a hash' : 'an array')
267             . " into " . ('HASH' eq $type ? 'an array' : 'a hash')
268             );
269             }
270              
271 9         36 my %seen;
272             my $recurse;
273             $recurse = sub {
274 29     29   75 my ($db, $val) = @_;
275              
276 29 100       174 my $obj = 'HASH' eq Scalar::Util::reftype( $db ) ? tied(%$db) : tied(@$db);
277 29   66     271 $obj ||= $db;
278              
279 29         74 my $r = $self->_check_legality( $val );
280 29 100       105 if ( 'HASH' eq $r ) {
    50          
281 16         103 while ( my ($k, $v) = each %$val ) {
282 30         77 my $r = $self->_check_legality( $v );
283 29 100       79 if ( $r ) {
284 15 100       69 my $temp = 'HASH' eq $r ? {} : [];
285 15 100       62 if ( my $c = Scalar::Util::blessed( $v ) ) {
286 6         30 bless $temp, $c;
287             }
288 15         77 $obj->put( $k, $temp );
289 15         70 $recurse->( $temp, $v );
290             }
291             else {
292 15         49 $obj->put( $k, $v );
293             }
294             }
295             }
296             elsif ( 'ARRAY' eq $r ) {
297 14         72 foreach my $k ( 0 .. $#$val ) {
298 29         61 my $v = $val->[$k];
299 29         81 my $r = $self->_check_legality( $v );
300 27 100       70 if ( $r ) {
301 7 100       24 my $temp = 'HASH' eq $r ? {} : [];
302 7 100       41 if ( my $c = Scalar::Util::blessed( $v ) ) {
303 3         19 bless $temp, $c;
304             }
305 7         22 $obj->put( $k, $temp );
306 7         41 $recurse->( $temp, $v );
307             }
308             else {
309 21         61 $obj->put( $k, $v );
310             }
311             }
312             }
313 9         79 };
314 9         36 $recurse->( $self, $struct );
315              
316 6         48 return 1;
317             }
318              
319             #XXX Need to keep track of who has a fh to this file in order to
320             #XXX close them all prior to optimize on Win32/cygwin
321             # Rebuild entire database into new file, then move
322             # it back on top of original.
323             sub optimize {
324 3     3 1 29 my $self = shift->_get_self;
325              
326             # Optimizing is only something we need to do when we're working with our
327             # own file format. Otherwise, let the other guy do the optimizations.
328 3 50       14 return unless $self->_engine->isa( 'DBM::Deep::Engine::File' );
329              
330             #XXX Need to create a new test for this
331             # if ($self->_engine->storage->{links} > 1) {
332             # $self->_throw_error("Cannot optimize: reference count is greater than 1");
333             # }
334              
335             #XXX Do we have to lock the tempfile?
336              
337             #XXX Should we use tempfile() here instead of a hard-coded name?
338 3         23 my $temp_filename = $self->_engine->storage->{file} . '.tmp';
339             my $db_temp = __PACKAGE__->new(
340             file => $temp_filename,
341             type => $self->_type,
342              
343             # Bring over all the parameters that we need to bring over
344 3         28 ( map { $_ => $self->_engine->$_ } qw(
  9         20  
345             byte_size max_buckets data_sector_size num_txns
346             )),
347             );
348              
349 3         33 $self->lock_exclusive;
350 3         25 $self->_engine->clear_cache;
351 3         14 $self->_copy_node( $db_temp );
352 3         33 $self->unlock;
353 3         35 $db_temp->_engine->storage->close;
354 3         11 undef $db_temp;
355              
356             ##
357             # Attempt to copy user, group and permissions over to new file
358             ##
359 3         42 $self->_engine->storage->copy_stats( $temp_filename );
360              
361             # q.v. perlport for more information on this variable
362 3 50 33     37 if ( $^O eq 'MSWin32' || $^O eq 'cygwin' ) {
363             ##
364             # Potential race condition when optimizing on Win32 with locking.
365             # The Windows filesystem requires that the filehandle be closed
366             # before it is overwritten with rename(). This could be redone
367             # with a soft copy.
368             ##
369 1         3 $self->unlock;
370 1         14 $self->_engine->storage->close;
371             }
372              
373 3 50       15 if (!rename $temp_filename, $self->_engine->storage->{file}) {
374 1         14 unlink $temp_filename;
375 1         22 $self->unlock;
376 1         15 $self->_throw_error("Optimize failed: Cannot copy temp file over original: $!");
377             }
378              
379 3         19 $self->unlock;
380 3         19 $self->_engine->storage->close;
381              
382 3         15 $self->_engine->storage->open;
383 3         10 $self->lock_exclusive;
384 3         29 $self->_engine->setup( $self );
385 3         22 $self->unlock;
386              
387 3         12 return 1;
388             }
389              
390             sub clone {
391 2     2 1 38 my $self = shift->_get_self;
392              
393 2         10 return __PACKAGE__->new(
394             type => $self->_type,
395             base_offset => $self->_base_offset,
396             staleness => $self->_staleness,
397             engine => $self->_engine,
398             );
399             }
400              
401             sub supports {
402 13     13 1 1031 my $self = shift->_get_self;
403 13         57 return $self->_engine->supports( @_ );
404             }
405              
406             sub db_version {
407 3     3 1 17 shift->_get_self->_engine->db_version;
408             }
409              
410             #XXX Migrate this to the engine, where it really belongs and go through some
411             # API - stop poking in the innards of someone else..
412             {
413             my %is_legal_filter = map {
414             $_ => ~~1,
415             } qw(
416             store_key store_value
417             fetch_key fetch_value
418             );
419              
420             sub set_filter {
421 10     10 1 747 my $self = shift->_get_self;
422 10         38 my $type = lc shift;
423 10         18 my $func = shift;
424              
425 10 100       34 if ( $is_legal_filter{$type} ) {
426 9         40 $self->_engine->storage->{"filter_$type"} = $func;
427 9         42 return 1;
428             }
429              
430 2         10 return;
431             }
432              
433 2     2 1 19 sub filter_store_key { $_[0]->set_filter( store_key => $_[1] ); }
434 2     2 1 11 sub filter_store_value { $_[0]->set_filter( store_value => $_[1] ); }
435 2     2 1 8 sub filter_fetch_key { $_[0]->set_filter( fetch_key => $_[1] ); }
436 2     2 1 24 sub filter_fetch_value { $_[0]->set_filter( fetch_value => $_[1] ); }
437             }
438              
439             sub begin_work {
440 278     278 1 123927 my $self = shift->_get_self;
441 278         780 $self->lock_exclusive;
442 278         523 my $rv = eval {
443 278         1241 local $SIG{'__DIE__'};
444 278         801 $self->_engine->begin_work( $self, @_ );
445             };
446 278         609 my $e = $@;
447 278         851 $self->unlock;
448 278 100       633 die $e if $e;
449 276         1193 return $rv;
450             }
451              
452             sub rollback {
453 15     15 1 1109 my $self = shift->_get_self;
454              
455 15         48 $self->lock_exclusive;
456 15         40 my $rv = eval {
457 15         78 local $SIG{'__DIE__'};
458 15         53 $self->_engine->rollback( $self, @_ );
459             };
460 15         72 my $e = $@;
461 15         58 $self->unlock;
462 15 100       90 die $e if $e;
463 13         54 return $rv;
464             }
465              
466             sub commit {
467 13     13 1 1086 my $self = shift->_get_self;
468 13         51 $self->lock_exclusive;
469 13         75 my $rv = eval {
470 13         65 local $SIG{'__DIE__'};
471 13         50 $self->_engine->commit( $self, @_ );
472             };
473 13         58 my $e = $@;
474 13         66 $self->unlock;
475 13 100       71 die $e if $e;
476 11         44 return $rv;
477             }
478              
479             # Accessor methods
480             sub _engine {
481 45582     45582   201635 my $self = $_[0]->_get_self;
482 45582         129171 return $self->{engine};
483             }
484              
485             sub _type {
486 396     396   1705 my $self = $_[0]->_get_self;
487 396         2145 return $self->{type};
488             }
489              
490             sub _base_offset {
491 10782     10782   22338 my $self = $_[0]->_get_self;
492 10782         34601 return $self->{base_offset};
493             }
494              
495             sub _staleness {
496 5526     5526   13261 my $self = $_[0]->_get_self;
497 5526         16201 return $self->{staleness};
498             }
499              
500             # Utility methods
501             sub _throw_error {
502 56     56   305 my $n = 0;
503 56         88 while( 1 ) {
504 175         406 my @caller = caller( ++$n );
505 175 100       6917 next if $caller[0] =~ m/^DBM::Deep/;
506              
507 56         549 die "DBM::Deep: $_[1] at $caller[1] line $caller[2]\n";
508             }
509             }
510              
511             # Store single hash key/value or array element in database.
512             sub STORE {
513 1801     1801   3642 my $self = shift->_get_self;
514 1801         4071 my ($key, $value) = @_;
515 1801         2324 warn "STORE($self, '$key', '@{[defined$value?$value:'undef']}')\n" if DEBUG;
516              
517 1801 100       3190 unless ( $self->_engine->storage->is_writable ) {
518 3         21 $self->_throw_error( 'Cannot write to a readonly filehandle' );
519             }
520              
521 1798         5485 $self->lock_exclusive;
522              
523             # User may be storing a complex value, in which case we do not want it run
524             # through the filtering system.
525 1798 100 100     5852 if ( !ref($value) && $self->_engine->storage->{filter_store_value} ) {
526 3         30 $value = $self->_engine->storage->{filter_store_value}->( $value );
527             }
528              
529 1798         2724 eval {
530 1798         6335 local $SIG{'__DIE__'};
531 1798         4304 $self->_engine->write_value( $self, $key, $value );
532 1798 100       5231 }; if ( my $e = $@ ) {
533 13         39 $self->unlock;
534 13         108 die $e;
535             }
536              
537 1786         5158 $self->unlock;
538              
539 1786         9075 return 1;
540             }
541              
542             # Fetch single value or element given plain key or array index
543             sub FETCH {
544 3135     3135   6282 my $self = shift->_get_self;
545 3135         6452 my ($key) = @_;
546 3135         3830 warn "FETCH($self, '$key')\n" if DEBUG;
547              
548 3135         7576 $self->lock_shared;
549              
550 3135         7593 my $result = $self->_engine->read_value( $self, $key );
551              
552 3134         9773 $self->unlock;
553              
554             # Filters only apply to scalar values, so the ref check is making
555             # sure the fetched bucket is a scalar, not a child hash or array.
556             return ($result && !ref($result) && $self->_engine->storage->{filter_fetch_value})
557 3134 100 100     10619 ? $self->_engine->storage->{filter_fetch_value}->($result)
558             : $result;
559             }
560              
561             # Delete single key/value pair or element given plain key or array index
562             sub DELETE {
563 61     61   341 my $self = shift->_get_self;
564 61         222 my ($key) = @_;
565 61         118 warn "DELETE($self, '$key')\n" if DEBUG;
566              
567 61 100       126 unless ( $self->_engine->storage->is_writable ) {
568 2         5 $self->_throw_error( 'Cannot write to a readonly filehandle' );
569             }
570              
571 60         216 $self->lock_exclusive;
572              
573             ##
574             # Delete bucket
575             ##
576 60         214 my $value = $self->_engine->delete_key( $self, $key);
577              
578 59 100 100     487 if (defined $value && !ref($value) && $self->_engine->storage->{filter_fetch_value}) {
      100        
579 2         19 $value = $self->_engine->storage->{filter_fetch_value}->($value);
580             }
581              
582 59         191 $self->unlock;
583              
584 59         281 return $value;
585             }
586              
587             # Check if a single key or element exists given plain key or array index
588             sub EXISTS {
589 130     130   324 my $self = shift->_get_self;
590 130         304 my ($key) = @_;
591 130         179 warn "EXISTS($self, '$key')\n" if DEBUG;
592              
593 130         361 $self->lock_shared;
594              
595 130         489 my $result = $self->_engine->key_exists( $self, $key );
596              
597 129         403 $self->unlock;
598              
599 129         857 return $result;
600             }
601              
602             # Clear all keys from hash, or all elements from array.
603             sub CLEAR {
604 221     221   627 my $self = shift->_get_self;
605 221         356 warn "CLEAR($self)\n" if DEBUG;
606              
607 221         547 my $engine = $self->_engine;
608 221 100       593 unless ( $engine->storage->is_writable ) {
609 2         16 $self->_throw_error( 'Cannot write to a readonly filehandle' );
610             }
611              
612 220         818 $self->lock_exclusive;
613 220         387 eval {
614 220         646 local $SIG{'__DIE__'};
615 220         705 $engine->clear( $self );
616             };
617 220         459 my $e = $@;
618 220 50 100     681 warn "$e\n" if $e && DEBUG;
619              
620 220         652 $self->unlock;
621              
622 220 100       580 die $e if $e;
623              
624 219         1211 return 1;
625             }
626              
627             # Public method aliases
628 70     70 1 446 sub put { (shift)->STORE( @_ ) }
629 97     97 1 2359 sub get { (shift)->FETCH( @_ ) }
630 11     11 1 1682 sub store { (shift)->STORE( @_ ) }
631 21     21 1 1227 sub fetch { (shift)->FETCH( @_ ) }
632 13     13 1 1148 sub delete { (shift)->DELETE( @_ ) }
633 17     17 1 1784 sub exists { (shift)->EXISTS( @_ ) }
634 10     10 1 1073 sub clear { (shift)->CLEAR( @_ ) }
635              
636 4     4   69 sub _dump_file {shift->_get_self->_engine->_dump_file;}
637              
638             sub _warnif {
639 4     4   8 my $level;
640             {
641 4         28 my($pack, $file, $line, $bitmask) = (caller $level++)[0..2,9];
  16         72  
642 16 100       59 redo if $pack =~ /^DBM::Deep(?:::|\z)/;
643 4 50       24 if(defined &warnings::warnif_at_level) { # perl >= 5.27.8
644 1         15 warnings::warnif_at_level($_[0], $level-1, $_[1]);
645             } else {
646             # In older perl versions (< 5.27.8) there is, unfortunately, no way
647             # to avoid this hack. warnings.pm did not allow us to specify
648             # exactly the call frame we want, so we have to look at the bitmask
649             # ourselves.
650 4 100 66     43 if( vec $bitmask, $warnings::Offsets{$_[0]}, 1,
651             || vec $bitmask, $warnings::Offsets{all}, 1,
652             ) {
653 3 50       31 my $msg = $_[1] =~ /\n\z/ ? $_[1] : "$_[1] at $file line $line.\n";
654             die $msg
655             if vec $bitmask, $warnings::Offsets{$_[0]}+1, 1,
656 3 100 66     30 || vec $bitmask, $warnings::Offsets{all}+1, 1;
657 2         17 warn $msg;
658             }
659             }
660             }
661             }
662              
663             sub _free {
664 16     16   36 my $self = shift;
665 16 50       47 if(my $sector = $self->{engine}->load_sector( $self->{base_offset} )) {
666 16         45 $sector->free;
667             }
668             }
669              
670             sub DESTROY {
671 5777     5777   95674 my $self = shift;
672 5777         11643 my $alter_ego = $self->_get_self;
673 5777 100 66     11208 if( !$alter_ego || $self != $alter_ego ) {
674 2851         9111 return; # Don’t run the destructor twice! (What follows only applies to
675             } # the inner object, not the tie.)
676              
677             # If the engine is gone, the END block has beaten us to it.
678 2927 100       7864 return if !$self->{engine};
679 2926 100       18237 if( $self->{engine}->{external_refs} ) {
680 16         66 $self->_free;
681             }
682             }
683              
684             # Relying on the destructor alone is problematic, as the order in which
685             # objects are discarded is random in global destruction. So we do the
686             # clean-up here before preemptively before global destruction.
687             END {
688             defined $$_ and $$_->_free, delete $$_->{engine}
689 53   0 53   216349 for(values %obj_cache);
690             }
691              
692             1;
693             __END__