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   330867 use 5.008_004;
  93         291  
4              
5 93     77   1023 use strict;
  77         274  
  77         1362  
6 77     57   693 use warnings FATAL => 'all';
  57         143  
  57         2014  
7 57     57   430 no warnings 'recursion';
  57         136  
  57         2833  
8              
9             our $VERSION = q(2.0016);
10              
11 57     55   413 use Scalar::Util ();
  55         119  
  55         3378  
12              
13             use overload
14             (
15             '""' =>
16 94846     94846   279713 '0+' => sub { $_[0] },
17 54         542 )[0,2,1,2], # same sub for both
18 55     54   402 fallback => 1;
  54         187  
19              
20 54     54   5118 use constant DEBUG => 0;
  54         127  
  54         3890  
21              
22 54     54   26048 use DBM::Deep::Engine;
  54         154  
  54         4652  
23              
24 3716     3716 1 17769 sub TYPE_HASH () { DBM::Deep::Engine->SIG_HASH }
25 4518     4518 1 19747 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   388 use constant HAVE_HUFH => scalar eval{ require Hash::Util::FieldHash };
  54         112  
  54         216  
  54         30438  
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   9000 my $proto = shift;
35              
36 5654         7542 my $args;
37 5654 100       13841 if (scalar(@_) > 1) {
    100          
38 3074 100       8164 if ( @_ % 2 ) {
39 5         57 $proto->_throw_error( "Odd number of parameters to " . (caller(1))[2] );
40             }
41 3072         11115 $args = {@_};
42             }
43             elsif ( ref $_[0] ) {
44 2558 50       4163 unless ( eval { local $SIG{'__DIE__'}; %{$_[0]} || 1 } ) {
  2558 100       9013  
  2558         3743  
  2558         13867  
45 5         61 $proto->_throw_error( "Not a hashref in args to " . (caller(1))[2] );
46             }
47 2556         4642 $args = $_[0];
48             }
49             else {
50 28         86 $args = { file => shift };
51             }
52              
53 5650         12501 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 87552 my $class = shift;
61 2716         6427 my $args = $class->_get_args( @_ );
62 2716         4284 my $self;
63              
64 2716 100 100     9188 if (defined($args->{type}) && $args->{type} eq TYPE_ARRAY) {
65 2113         3602 $class = 'DBM::Deep::Array';
66 2113         15094 require DBM::Deep::Array;
67 2113         13719 tie @$self, $class, %$args;
68             }
69             else {
70 606         1053 $class = 'DBM::Deep::Hash';
71 606         26334 require DBM::Deep::Hash;
72 606         4149 tie %$self, $class, %$args;
73             }
74              
75 2704         10791 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   4733 my $class = shift;
82 2937         5196 my ($args) = @_;
83              
84             # locking implicitly enables autoflush
85 2937 100       6347 if ($args->{locking}) { $args->{autoflush} = 1; }
  24         106  
86              
87             # These are the defaults to be optionally overridden below
88 2937         5601 my $self = bless {
89             type => TYPE_HASH,
90             base_offset => undef,
91             staleness => undef,
92             engine => undef,
93             }, $class;
94              
95 2937 100       7447 unless ( exists $args->{engine} ) {
96             my $class =
97             exists $args->{dbi} ? 'DBM::Deep::Engine::DBI' :
98 396 100       1727 exists $args->{_test} ? 'DBM::Deep::Engine::Test' :
    50          
99             'DBM::Deep::Engine::File' ;
100              
101 54 50   54   30832 eval "use $class"; die $@ if $@;
  54     1   351  
  54     1   1199  
  394     1   31692  
  394     1   1605  
  1     1   9  
  1     1   2  
  1     1   15  
  1     1   8  
  1     1   3  
  1     1   14  
  1     1   13  
  1     1   4  
  1     1   24  
  1     1   7  
  1     1   2  
  1     1   14  
  1     1   7  
  1     1   2  
  1     1   13  
  1     1   13  
  1     1   3  
  1     1   35  
  1     1   8  
  1     1   3  
  1     1   21  
  1     1   7  
  1     1   2  
  1     1   14  
  1     1   7  
  1     1   2  
  1     1   15  
  1     1   6  
  1     1   3  
  1     1   13  
  1     1   12  
  1     1   4  
  1     1   23  
  1     1   7  
  1     1   2  
  1     1   14  
  1     1   6  
  1     1   4  
  1     1   14  
  1     1   8  
  1     1   2  
  1     1   16  
  1     1   7  
  1     1   2  
  1     1   23  
  1     1   6  
  1     1   3  
  1     1   25  
  1     1   13  
  1     1   4  
  1     1   21  
  1     1   6  
  1     1   3  
  1     1   13  
  1     1   7  
  1     1   2  
  1     1   15  
  1     1   42  
  1     1   4  
  1     1   18  
  1     1   7  
  1     1   2  
  1     1   14  
  1     1   8  
  1     1   2  
  1     1   19  
  1     1   16  
  1     1   8  
  1     1   26  
  1     1   7  
  1     1   2  
  1     1   14  
  1     1   6  
  1     1   2  
  1     1   24  
  1     1   7  
  1     1   2  
  1     1   13  
  1     1   7  
  1     1   3  
  1     1   14  
  1     1   13  
  1     1   5  
  1     1   20  
  1     1   7  
  1     1   2  
  1     1   14  
  1     1   7  
  1     1   3  
  1     1   13  
  1     1   10  
  1     1   3  
  1     1   20  
  1     1   7  
  1     1   2  
  1     1   23  
  1     1   7  
  1     1   3  
  1     1   15  
  1     1   7  
  1     1   2  
  1     1   22  
  1     1   6  
  1     1   3  
  1     1   14  
  1     1   8  
  1     1   3  
  1     1   88  
  1     1   9  
  1     1   3  
  1     1   15  
  1     1   19  
  1     1   4  
  1     1   15  
  1     1   7  
  1     1   3  
  1     1   13  
  1     1   6  
  1     1   2  
  1     1   14  
  1     1   6  
  1     1   2  
  1     1   14  
  1     1   8  
  1     1   2  
  1     1   13  
  1     1   7  
  1     1   2  
  1     1   14  
  1     1   11  
  1     1   13  
  1     1   27  
  1     1   7  
  1     1   3  
  1     1   14  
  1     1   8  
  1     1   2  
  1     1   15  
  1     1   7  
  1     1   2  
  1     1   14  
  1     1   7  
  1     1   2  
  1     1   13  
  1     1   7  
  1     1   3  
  1     1   13  
  1     1   7  
  1     1   2  
  1     1   14  
  1     1   7  
  1     1   2  
  1     1   14  
  1     1   6  
  1     1   3  
  1     1   14  
  1     1   8  
  1     1   3  
  1     1   15  
  1     1   8  
  1     1   2  
  1     1   13  
  1     1   7  
  1     1   2  
  1     1   15  
  1         7  
  1         3  
  1         14  
  1         7  
  1         2  
  1         15  
  1         10  
  1         3  
  1         33  
  1         7  
  1         3  
  1         13  
  1         7  
  1         2  
  1         14  
  1         8  
  1         2  
  1         23  
  1         8  
  1         2  
  1         15  
  1         7  
  1         2  
  1         14  
  1         7  
  1         2  
  1         14  
  1         9  
  1         2  
  1         16  
  1         7  
  1         1  
  1         13  
  1         8  
  1         2  
  1         25  
  1         7  
  1         3  
  1         14  
  1         7  
  1         2  
  1         32  
  1         7  
  1         2  
  1         14  
  1         9  
  1         4  
  1         16  
  1         6  
  1         2  
  1         13  
  1         7  
  1         2  
  1         13  
  1         7  
  1         2  
  1         13  
  1         7  
  1         2  
  1         14  
  1         6  
  1         3  
  1         24  
  1         7  
  1         2  
  1         36  
  1         12  
  1         4  
  1         24  
  1         7  
  1         3  
  1         16  
  1         6  
  1         3  
  1         67  
  1         8  
  1         3  
  1         16  
  1         7  
  1         2  
  1         20  
  1         7  
  1         3  
  1         14  
  1         7  
  1         11  
  1         18  
  1         7  
  1         2  
  1         15  
  1         11  
  1         2  
  1         18  
  1         7  
  1         3  
  1         14  
  1         13  
  1         3  
  1         21  
  1         10  
  1         3  
  1         36  
  1         11  
  1         4  
  1         24  
  1         6  
  1         3  
  1         13  
  1         10  
  1         4  
  1         15  
  1         11  
  1         3  
  1         21  
  1         11  
  1         4  
  1         22  
  1         12  
  1         4  
  1         21  
  1         8  
  1         2  
  1         15  
  1         7  
  1         2  
  1         25  
  1         13  
  1         4  
  1         22  
  1         8  
  1         3  
  1         32  
  1         6  
  1         3  
  1         24  
  1         7  
  1         22  
  1         19  
  1         12  
  1         3  
  1         24  
  1         6  
  1         2  
  1         15  
  1         7  
  1         2  
  1         15  
  1         6  
  1         3  
  1         15  
  1         7  
  1         3  
  1         13  
  1         7  
  1         2  
  1         15  
  1         7  
  1         2  
  1         13  
  1         7  
  1         3  
  1         13  
  1         11  
  1         2  
  1         15  
  1         7  
  1         3  
  1         24  
102             $args->{engine} = $class->new({
103 394         746 %{$args},
  394         3046  
104             obj => $self,
105             });
106             }
107              
108             # Grab the parameters we want to use
109 2934         14277 foreach my $param ( keys %$self ) {
110 11733 100       20495 next unless exists $args->{$param};
111 10949         18791 $self->{$param} = $args->{$param};
112             }
113              
114 2934         6108 eval {
115 2934         9146 local $SIG{'__DIE__'};
116              
117 2934         8903 $self->lock_exclusive;
118 2933         6262 $self->_engine->setup( $self );
119 2921         6627 $self->unlock;
120 2934 100       7271 }; if ( $@ ) {
121 16         33 my $e = $@;
122 16         67 eval { local $SIG{'__DIE__'}; $self->unlock; };
  16         54  
  16         57  
123 16         102 die $e;
124             }
125              
126 2919 100 66     8305 if( $self->{engine}->{external_refs}
127             and my $sector = $self->{engine}->load_sector( $self->{base_offset} )
128             ) {
129 16         66 $sector->increment_refcount;
130              
131 16         67 Scalar::Util::weaken( my $feeble_ref = $self );
132 16         185 $obj_cache{ $self } = \$feeble_ref;
133              
134             # Make sure this cache is not a memory hog
135 16         48 if(!HAVE_HUFH) {
136             for(keys %obj_cache) {
137             delete $obj_cache{$_} if not ${$obj_cache{$_}};
138             }
139             }
140             }
141              
142 2919         12168 return $self;
143             }
144              
145             sub TIEHASH {
146 176     178   5863 shift;
147 176         3659 require DBM::Deep::Hash;
148 176         745 return DBM::Deep::Hash->TIEHASH( @_ );
149             }
150              
151             sub TIEARRAY {
152 51     53   2677 shift;
153 51         9096 require DBM::Deep::Array;
154 51         263 return DBM::Deep::Array->TIEARRAY( @_ );
155             }
156              
157             sub lock_exclusive {
158 5831     5833 1 13657 my $self = shift->_get_self;
159 5831         13204 return $self->_engine->lock_exclusive( $self, @_ );
160             }
161             *lock = \&lock_exclusive;
162              
163             sub lock_shared {
164 4627     4629 1 9906 my $self = shift->_get_self;
165             # cluck() the problem with cached File objects.
166 4627 50       8778 unless ( $self->_engine ) {
167 1         2 require Carp;
168 1         15 require Data::Dumper;
169 1         6 Carp::cluck( Data::Dumper->Dump( [$self], ['self'] ) );
170             }
171 4627         8688 return $self->_engine->lock_shared( $self, @_ );
172             }
173              
174             sub unlock {
175 10452     10454 1 25232 my $self = shift->_get_self;
176 10452         22164 return $self->_engine->unlock( $self, @_ );
177             }
178              
179             sub _copy_value {
180 72     72   184 my $self = shift->_get_self;
181 72         164 my ($spot, $value) = @_;
182              
183 72 100       162 if ( !ref $value ) {
184 40         66 ${$spot} = $value;
  40         103  
185             }
186             else {
187 33         105 my $r = Scalar::Util::reftype( $value );
188 33         48 my $tied;
189 33 100       111 if ( $r eq 'ARRAY' ) {
    50          
190 20         64 $tied = tied(@$value);
191             }
192             elsif ( $r eq 'HASH' ) {
193 14         27 $tied = tied(%$value);
194             }
195             else {
196 1         15 __PACKAGE__->_throw_error( "Unknown type for '$value'" );
197             }
198              
199 33 50       57 if ( eval { local $SIG{'__DIE__'}; $tied->isa( __PACKAGE__ ) } ) {
  33         126  
  33         218  
200 33         113 ${$spot} = $tied->_repr;
  33         78  
201 33         67 $tied->_copy_node( ${$spot} );
  33         120  
202             }
203             else {
204 1 0       2 if ( $r eq 'ARRAY' ) {
205 1         13 ${$spot} = [ @{$value} ];
  1         7  
  1         3  
206             }
207             else {
208 1         13 ${$spot} = { %{$value} };
  1         7  
  1         1  
209             }
210             }
211              
212 33         125 my $c = Scalar::Util::blessed( $value );
213 33 100 66     240 if ( defined $c && !$c->isa( __PACKAGE__ ) ) {
214 17         25 ${$spot} = bless ${$spot}, $c
  17         57  
  17         38  
215             }
216             }
217              
218 72         188 return 1;
219             }
220              
221             sub export {
222 13     13 1 69 my $self = shift->_get_self;
223              
224 13         52 my $temp = $self->_repr;
225              
226 13         42 $self->lock_exclusive;
227 13         88 $self->_copy_node( $temp );
228 13         67 $self->unlock;
229              
230 13         43 my $classname = $self->_engine->get_classname( $self );
231 13 100       71 if ( defined $classname ) {
232 5         17 bless $temp, $classname;
233             }
234              
235 13         59 return $temp;
236             }
237              
238             sub _check_legality {
239 98     98   145 my $self = shift;
240 98         165 my ($val) = @_;
241              
242 98         218 my $r = Scalar::Util::reftype( $val );
243              
244 98 100 66     378 return $r if !defined $r || '' eq $r;
245 62 100       171 return $r if 'HASH' eq $r;
246 31 100       110 return $r if 'ARRAY' eq $r;
247              
248 4         25 __PACKAGE__->_throw_error(
249             "Storage of references of type '$r' is not supported."
250             );
251             }
252              
253             sub import {
254 64 100   64   5828 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         50 my $type = $self->_check_legality( $struct );
260 13 100       41 if ( !$type ) {
261 3         21 __PACKAGE__->_throw_error( "Cannot import a scalar" );
262             }
263              
264 11 100       43 if ( substr( $type, 0, 1 ) ne $self->_type ) {
265 3 100       15 __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         39 my %seen;
272             my $recurse;
273             $recurse = sub {
274 29     29   69 my ($db, $val) = @_;
275              
276 29 100       174 my $obj = 'HASH' eq Scalar::Util::reftype( $db ) ? tied(%$db) : tied(@$db);
277 29   66     244 $obj ||= $db;
278              
279 29         83 my $r = $self->_check_legality( $val );
280 29 100       109 if ( 'HASH' eq $r ) {
    50          
281 16         85 while ( my ($k, $v) = each %$val ) {
282 30         74 my $r = $self->_check_legality( $v );
283 29 100       91 if ( $r ) {
284 15 100       44 my $temp = 'HASH' eq $r ? {} : [];
285 15 100       66 if ( my $c = Scalar::Util::blessed( $v ) ) {
286 6         27 bless $temp, $c;
287             }
288 15         70 $obj->put( $k, $temp );
289 15         91 $recurse->( $temp, $v );
290             }
291             else {
292 15         56 $obj->put( $k, $v );
293             }
294             }
295             }
296             elsif ( 'ARRAY' eq $r ) {
297 14         76 foreach my $k ( 0 .. $#$val ) {
298 29         67 my $v = $val->[$k];
299 29         77 my $r = $self->_check_legality( $v );
300 27 100       70 if ( $r ) {
301 7 100       21 my $temp = 'HASH' eq $r ? {} : [];
302 7 100       41 if ( my $c = Scalar::Util::blessed( $v ) ) {
303 3         14 bless $temp, $c;
304             }
305 7         22 $obj->put( $k, $temp );
306 7         37 $recurse->( $temp, $v );
307             }
308             else {
309 21         58 $obj->put( $k, $v );
310             }
311             }
312             }
313 9         65 };
314 9         30 $recurse->( $self, $struct );
315              
316 6         35 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 33 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       11 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         20 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         21 ( map { $_ => $self->_engine->$_ } qw(
  9         23  
345             byte_size max_buckets data_sector_size num_txns
346             )),
347             );
348              
349 3         32 $self->lock_exclusive;
350 3         19 $self->_engine->clear_cache;
351 3         10 $self->_copy_node( $db_temp );
352 3         21 $self->unlock;
353 3         15 $db_temp->_engine->storage->close;
354 3         19 undef $db_temp;
355              
356             ##
357             # Attempt to copy user, group and permissions over to new file
358             ##
359 3         22 $self->_engine->storage->copy_stats( $temp_filename );
360              
361             # q.v. perlport for more information on this variable
362 3 50 33     28 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         1 $self->unlock;
370 1         14 $self->_engine->storage->close;
371             }
372              
373 3 50       18 if (!rename $temp_filename, $self->_engine->storage->{file}) {
374 1         2 unlink $temp_filename;
375 1         15 $self->unlock;
376 1         7 $self->_throw_error("Optimize failed: Cannot copy temp file over original: $!");
377             }
378              
379 3         16 $self->unlock;
380 3         18 $self->_engine->storage->close;
381              
382 3         17 $self->_engine->storage->open;
383 3         14 $self->lock_exclusive;
384 3         24 $self->_engine->setup( $self );
385 3         16 $self->unlock;
386              
387 3         10 return 1;
388             }
389              
390             sub clone {
391 2     2 1 23 my $self = shift->_get_self;
392              
393 2         11 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 868 my $self = shift->_get_self;
403 13         54 return $self->_engine->supports( @_ );
404             }
405              
406             sub db_version {
407 3     3 1 14 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 565 my $self = shift->_get_self;
422 10         45 my $type = lc shift;
423 10         25 my $func = shift;
424              
425 10 100       32 if ( $is_legal_filter{$type} ) {
426 9         44 $self->_engine->storage->{"filter_$type"} = $func;
427 9         52 return 1;
428             }
429              
430 2         9 return;
431             }
432              
433 2     2 1 20 sub filter_store_key { $_[0]->set_filter( store_key => $_[1] ); }
434 2     2 1 14 sub filter_store_value { $_[0]->set_filter( store_value => $_[1] ); }
435 2     2 1 11 sub filter_fetch_key { $_[0]->set_filter( fetch_key => $_[1] ); }
436 2     2 1 23 sub filter_fetch_value { $_[0]->set_filter( fetch_value => $_[1] ); }
437             }
438              
439             sub begin_work {
440 278     278 1 96654 my $self = shift->_get_self;
441 278         813 $self->lock_exclusive;
442 278         532 my $rv = eval {
443 278         1229 local $SIG{'__DIE__'};
444 278         765 $self->_engine->begin_work( $self, @_ );
445             };
446 278         641 my $e = $@;
447 278         870 $self->unlock;
448 278 100       734 die $e if $e;
449 276         1328 return $rv;
450             }
451              
452             sub rollback {
453 15     15 1 887 my $self = shift->_get_self;
454              
455 15         63 $self->lock_exclusive;
456 15         50 my $rv = eval {
457 15         77 local $SIG{'__DIE__'};
458 15         49 $self->_engine->rollback( $self, @_ );
459             };
460 15         55 my $e = $@;
461 15         57 $self->unlock;
462 15 100       59 die $e if $e;
463 13         55 return $rv;
464             }
465              
466             sub commit {
467 13     13 1 857 my $self = shift->_get_self;
468 13         55 $self->lock_exclusive;
469 13         47 my $rv = eval {
470 13         65 local $SIG{'__DIE__'};
471 13         54 $self->_engine->commit( $self, @_ );
472             };
473 13         68 my $e = $@;
474 13         76 $self->unlock;
475 13 100       87 die $e if $e;
476 11         50 return $rv;
477             }
478              
479             # Accessor methods
480             sub _engine {
481 45582     45582   178081 my $self = $_[0]->_get_self;
482 45582         138431 return $self->{engine};
483             }
484              
485             sub _type {
486 396     396   1657 my $self = $_[0]->_get_self;
487 396         2384 return $self->{type};
488             }
489              
490             sub _base_offset {
491 10782     10782   23126 my $self = $_[0]->_get_self;
492 10782         34298 return $self->{base_offset};
493             }
494              
495             sub _staleness {
496 5526     5526   13634 my $self = $_[0]->_get_self;
497 5526         17901 return $self->{staleness};
498             }
499              
500             # Utility methods
501             sub _throw_error {
502 56     56   277 my $n = 0;
503 56         89 while( 1 ) {
504 175         452 my @caller = caller( ++$n );
505 175 100       6909 next if $caller[0] =~ m/^DBM::Deep/;
506              
507 56         523 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   4049 my $self = shift->_get_self;
514 1801         4333 my ($key, $value) = @_;
515 1801         2404 warn "STORE($self, '$key', '@{[defined$value?$value:'undef']}')\n" if DEBUG;
516              
517 1801 100       3393 unless ( $self->_engine->storage->is_writable ) {
518 3         24 $self->_throw_error( 'Cannot write to a readonly filehandle' );
519             }
520              
521 1798         5922 $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     6211 if ( !ref($value) && $self->_engine->storage->{filter_store_value} ) {
526 3         21 $value = $self->_engine->storage->{filter_store_value}->( $value );
527             }
528              
529 1798         3060 eval {
530 1798         6982 local $SIG{'__DIE__'};
531 1798         4239 $self->_engine->write_value( $self, $key, $value );
532 1798 100       5730 }; if ( my $e = $@ ) {
533 13         55 $self->unlock;
534 13         154 die $e;
535             }
536              
537 1786         5730 $self->unlock;
538              
539 1786         9425 return 1;
540             }
541              
542             # Fetch single value or element given plain key or array index
543             sub FETCH {
544 3135     3135   6558 my $self = shift->_get_self;
545 3135         6827 my ($key) = @_;
546 3135         4378 warn "FETCH($self, '$key')\n" if DEBUG;
547              
548 3135         7945 $self->lock_shared;
549              
550 3135         8484 my $result = $self->_engine->read_value( $self, $key );
551              
552 3134         10801 $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     11304 ? $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   319 my $self = shift->_get_self;
564 61         217 my ($key) = @_;
565 61         116 warn "DELETE($self, '$key')\n" if DEBUG;
566              
567 61 100       160 unless ( $self->_engine->storage->is_writable ) {
568 2         6 $self->_throw_error( 'Cannot write to a readonly filehandle' );
569             }
570              
571 60         237 $self->lock_exclusive;
572              
573             ##
574             # Delete bucket
575             ##
576 60         248 my $value = $self->_engine->delete_key( $self, $key);
577              
578 59 100 100     453 if (defined $value && !ref($value) && $self->_engine->storage->{filter_fetch_value}) {
      100        
579 2         17 $value = $self->_engine->storage->{filter_fetch_value}->($value);
580             }
581              
582 59         208 $self->unlock;
583              
584 59         272 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   337 my $self = shift->_get_self;
590 130         324 my ($key) = @_;
591 130         202 warn "EXISTS($self, '$key')\n" if DEBUG;
592              
593 130         397 $self->lock_shared;
594              
595 130         529 my $result = $self->_engine->key_exists( $self, $key );
596              
597 129         465 $self->unlock;
598              
599 129         871 return $result;
600             }
601              
602             # Clear all keys from hash, or all elements from array.
603             sub CLEAR {
604 221     221   670 my $self = shift->_get_self;
605 221         362 warn "CLEAR($self)\n" if DEBUG;
606              
607 221         646 my $engine = $self->_engine;
608 221 100       537 unless ( $engine->storage->is_writable ) {
609 2         8 $self->_throw_error( 'Cannot write to a readonly filehandle' );
610             }
611              
612 220         819 $self->lock_exclusive;
613 220         401 eval {
614 220         729 local $SIG{'__DIE__'};
615 220         674 $engine->clear( $self );
616             };
617 220         464 my $e = $@;
618 220 50 100     669 warn "$e\n" if $e && DEBUG;
619              
620 220         677 $self->unlock;
621              
622 220 100       630 die $e if $e;
623              
624 219         1351 return 1;
625             }
626              
627             # Public method aliases
628 70     70 1 427 sub put { (shift)->STORE( @_ ) }
629 97     97 1 2022 sub get { (shift)->FETCH( @_ ) }
630 11     11 1 1228 sub store { (shift)->STORE( @_ ) }
631 21     21 1 989 sub fetch { (shift)->FETCH( @_ ) }
632 13     13 1 973 sub delete { (shift)->DELETE( @_ ) }
633 17     17 1 1620 sub exists { (shift)->EXISTS( @_ ) }
634 10     10 1 766 sub clear { (shift)->CLEAR( @_ ) }
635              
636 4     4   41 sub _dump_file {shift->_get_self->_engine->_dump_file;}
637              
638             sub _warnif {
639 4     4   9 my $level;
640             {
641 4         26 my($pack, $file, $line, $bitmask) = (caller $level++)[0..2,9];
  16         103  
642 16 100       76 redo if $pack =~ /^DBM::Deep(?:::|\z)/;
643 4 50       23 if(defined &warnings::warnif_at_level) { # perl >= 5.27.8
644 1         9 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     42 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     39 || vec $bitmask, $warnings'Offsets{all}+1, 1;
657 2         16 warn $msg;
658             }
659             }
660             }
661             }
662              
663             sub _free {
664 16     16   52 my $self = shift;
665 16 50       52 if(my $sector = $self->{engine}->load_sector( $self->{base_offset} )) {
666 16         52 $sector->free;
667             }
668             }
669              
670             sub DESTROY {
671 5777     5777   90066 my $self = shift;
672 5777         12415 my $alter_ego = $self->_get_self;
673 5777 100 66     11625 if( !$alter_ego || $self != $alter_ego ) {
674 2851         10215 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       8739 return if !$self->{engine};
679 2926 100       17934 if( $self->{engine}->{external_refs} ) {
680 16         63 $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   200005 for(values %obj_cache);
690             }
691              
692             1;
693             __END__