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   333383 use 5.008_004;
  93         294  
4              
5 93     77   1079 use strict;
  77         364  
  77         1367  
6 77     57   719 use warnings FATAL => 'all';
  57         146  
  57         2050  
7 57     57   432 no warnings 'recursion';
  57         170  
  57         3215  
8              
9             our $VERSION = q(2.0016_001);
10              
11 57     55   449 use Scalar::Util ();
  55         143  
  55         3517  
12              
13             use overload
14             (
15             '""' =>
16 94846     94846   253138 '0+' => sub { $_[0] },
17 54         483 )[0,2,1,2], # same sub for both
18 55     54   451 fallback => 1;
  54         186  
19              
20 54     54   5008 use constant DEBUG => 0;
  54         118  
  54         4158  
21              
22 54     54   26225 use DBM::Deep::Engine;
  54         141  
  54         4502  
23              
24 3716     3716 1 16918 sub TYPE_HASH () { DBM::Deep::Engine->SIG_HASH }
25 4518     4518 1 22064 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   405 use constant HAVE_HUFH => scalar eval{ require Hash::Util::FieldHash };
  54         103  
  54         137  
  54         31060  
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   8082 my $proto = shift;
35              
36 5654         7336 my $args;
37 5654 100       13597 if (scalar(@_) > 1) {
    100          
38 3074 100       7868 if ( @_ % 2 ) {
39 5         45 $proto->_throw_error( "Odd number of parameters to " . (caller(1))[2] );
40             }
41 3072         10720 $args = {@_};
42             }
43             elsif ( ref $_[0] ) {
44 2558 50       3981 unless ( eval { local $SIG{'__DIE__'}; %{$_[0]} || 1 } ) {
  2558 100       8417  
  2558         3601  
  2558         12638  
45 5         80 $proto->_throw_error( "Not a hashref in args to " . (caller(1))[2] );
46             }
47 2556         4322 $args = $_[0];
48             }
49             else {
50 28         88 $args = { file => shift };
51             }
52              
53 5650         11280 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 99131 my $class = shift;
61 2716         6201 my $args = $class->_get_args( @_ );
62 2716         3923 my $self;
63              
64 2716 100 100     8801 if (defined($args->{type}) && $args->{type} eq TYPE_ARRAY) {
65 2113         3542 $class = 'DBM::Deep::Array';
66 2113         14406 require DBM::Deep::Array;
67 2113         13695 tie @$self, $class, %$args;
68             }
69             else {
70 606         1028 $class = 'DBM::Deep::Hash';
71 606         24865 require DBM::Deep::Hash;
72 606         3957 tie %$self, $class, %$args;
73             }
74              
75 2704         9383 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   4517 my $class = shift;
82 2937         5139 my ($args) = @_;
83              
84             # locking implicitly enables autoflush
85 2937 100       6028 if ($args->{locking}) { $args->{autoflush} = 1; }
  24         80  
86              
87             # These are the defaults to be optionally overridden below
88 2937         5465 my $self = bless {
89             type => TYPE_HASH,
90             base_offset => undef,
91             staleness => undef,
92             engine => undef,
93             }, $class;
94              
95 2937 100       7239 unless ( exists $args->{engine} ) {
96             my $class =
97             exists $args->{dbi} ? 'DBM::Deep::Engine::DBI' :
98 396 100       1245 exists $args->{_test} ? 'DBM::Deep::Engine::Test' :
    50          
99             'DBM::Deep::Engine::File' ;
100              
101 54 50   54   32140 eval "use $class"; die $@ if $@;
  54     1   311  
  54     1   1067  
  394     1   30180  
  394     1   1455  
  1     1   6  
  1     1   8  
  1     1   37  
  1     1   6  
  1     1   2  
  1     1   13  
  1     1   7  
  1     1   1  
  1     1   13  
  1     1   7  
  1     1   4  
  1     1   13  
  1     1   7  
  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   8  
  1     1   2  
  1     1   29  
  1     1   7  
  1     1   4  
  1     1   23  
  1     1   20  
  1     1   2  
  1     1   15  
  1     1   6  
  1     1   3  
  1     1   23  
  1     1   7  
  1     1   2  
  1     1   14  
  1     1   6  
  1     1   3  
  1     1   18  
  1     1   6  
  1     1   2  
  1     1   13  
  1     1   7  
  1     1   2  
  1     1   13  
  1     1   12  
  1     1   2  
  1     1   14  
  1     1   7  
  1     1   2  
  1     1   28  
  1     1   7  
  1     1   3  
  1     1   12  
  1     1   6  
  1     1   2  
  1     1   14  
  1     1   7  
  1     1   3  
  1     1   24  
  1     1   7  
  1     1   2  
  1     1   24  
  1     1   7  
  1     1   2  
  1     1   14  
  1     1   7  
  1     1   3  
  1     1   14  
  1     1   7  
  1     1   2  
  1     1   15  
  1     1   7  
  1     1   2  
  1     1   13  
  1     1   6  
  1     1   3  
  1     1   13  
  1     1   6  
  1     1   2  
  1     1   23  
  1     1   7  
  1     1   2  
  1     1   14  
  1     1   7  
  1     1   2  
  1     1   23  
  1     1   8  
  1     1   2  
  1     1   15  
  1     1   7  
  1     1   2  
  1     1   13  
  1     1   6  
  1     1   3  
  1     1   14  
  1     1   7  
  1     1   2  
  1     1   30  
  1     1   7  
  1     1   2  
  1     1   16  
  1     1   7  
  1     1   2  
  1     1   13  
  1     1   6  
  1     1   7  
  1     1   14  
  1     1   8  
  1     1   2  
  1     1   13  
  1     1   7  
  1     1   1  
  1     1   14  
  1     1   7  
  1     1   1  
  1     1   13  
  1     1   6  
  1     1   2  
  1     1   14  
  1     1   6  
  1     1   3  
  1     1   13  
  1     1   6  
  1     1   2  
  1     1   15  
  1     1   7  
  1     1   2  
  1     1   15  
  1     1   14  
  1     1   4  
  1     1   16  
  1     1   7  
  1     1   2  
  1     1   22  
  1     1   20  
  1     1   3  
  1     1   15  
  1     1   6  
  1     1   2  
  1     1   13  
  1     1   6  
  1     1   2  
  1     1   13  
  1     1   6  
  1     1   3  
  1     1   14  
  1     1   7  
  1     1   2  
  1     1   13  
  1     1   7  
  1     1   13  
  1     1   19  
  1     1   7  
  1     1   2  
  1     1   23  
  1     1   8  
  1     1   2  
  1     1   21  
  1     1   6  
  1     1   2  
  1     1   15  
  1     1   8  
  1     1   2  
  1     1   14  
  1         7  
  1         2  
  1         12  
  1         7  
  1         2  
  1         25  
  1         7  
  1         2  
  1         13  
  1         7  
  1         2  
  1         14  
  1         8  
  1         2  
  1         15  
  1         8  
  1         2  
  1         14  
  1         8  
  1         2  
  1         13  
  1         6  
  1         2  
  1         14  
  1         7  
  1         2  
  1         14  
  1         7  
  1         2  
  1         14  
  1         6  
  1         2  
  1         14  
  1         6  
  1         4  
  1         14  
  1         6  
  1         2  
  1         14  
  1         7  
  1         2  
  1         15  
  1         8  
  1         2  
  1         14  
  1         7  
  1         3  
  1         14  
  1         7  
  1         1  
  1         22  
  1         7  
  1         2  
  1         15  
  1         7  
  1         2  
  1         14  
  1         8  
  1         1  
  1         14  
  1         6  
  1         2  
  1         16  
  1         6  
  1         8  
  1         13  
  1         6  
  1         3  
  1         13  
  1         6  
  1         2  
  1         12  
  1         6  
  1         2  
  1         14  
  1         6  
  1         2  
  1         14  
  1         7  
  1         2  
  1         13  
  1         7  
  1         3  
  1         23  
  1         7  
  1         2  
  1         16  
  1         6  
  1         2  
  1         14  
  1         7  
  1         2  
  1         13  
  1         6  
  1         2  
  1         13  
  1         9  
  1         1  
  1         15  
  1         7  
  1         3  
  1         13  
  1         7  
  1         2  
  1         14  
  1         6  
  1         2  
  1         13  
  1         7  
  1         3  
  1         14  
  1         7  
  1         2  
  1         25  
  1         7  
  1         2  
  1         13  
  1         7  
  1         2  
  1         13  
  1         7  
  1         2  
  1         13  
  1         6  
  1         2  
  1         13  
  1         7  
  1         3  
  1         16  
  1         6  
  1         2  
  1         13  
  1         8  
  1         2  
  1         13  
  1         6  
  1         3  
  1         14  
  1         7  
  1         2  
  1         13  
  1         18  
  1         2  
  1         22  
  1         7  
  1         3  
  1         13  
  1         6  
  1         10  
  1         16  
  1         7  
  1         3  
  1         25  
  1         7  
  1         2  
  1         23  
  1         7  
  1         10  
  1         17  
  1         8  
  1         2  
  1         13  
  1         7  
  1         2  
  1         14  
  1         7  
  1         3  
  1         12  
102             $args->{engine} = $class->new({
103 394         622 %{$args},
  394         2861  
104             obj => $self,
105             });
106             }
107              
108             # Grab the parameters we want to use
109 2934         13624 foreach my $param ( keys %$self ) {
110 11733 100       20606 next unless exists $args->{$param};
111 10949         18279 $self->{$param} = $args->{$param};
112             }
113              
114 2934         5767 eval {
115 2934         8122 local $SIG{'__DIE__'};
116              
117 2934         8319 $self->lock_exclusive;
118 2933         6105 $self->_engine->setup( $self );
119 2921         7012 $self->unlock;
120 2934 100       6343 }; if ( $@ ) {
121 16         32 my $e = $@;
122 16         61 eval { local $SIG{'__DIE__'}; $self->unlock; };
  16         57  
  16         59  
123 16         98 die $e;
124             }
125              
126 2919 100 66     7799 if( $self->{engine}->{external_refs}
127             and my $sector = $self->{engine}->load_sector( $self->{base_offset} )
128             ) {
129 16         49 $sector->increment_refcount;
130              
131 16         65 Scalar::Util::weaken( my $feeble_ref = $self );
132 16         128 $obj_cache{ $self } = \$feeble_ref;
133              
134             # Make sure this cache is not a memory hog
135 16         62 if(!HAVE_HUFH) {
136             for(keys %obj_cache) {
137             delete $obj_cache{$_} if not ${$obj_cache{$_}};
138             }
139             }
140             }
141              
142 2919         11327 return $self;
143             }
144              
145             sub TIEHASH {
146 176     178   6856 shift;
147 176         3676 require DBM::Deep::Hash;
148 176         675 return DBM::Deep::Hash->TIEHASH( @_ );
149             }
150              
151             sub TIEARRAY {
152 51     53   2824 shift;
153 51         8924 require DBM::Deep::Array;
154 51         278 return DBM::Deep::Array->TIEARRAY( @_ );
155             }
156              
157             sub lock_exclusive {
158 5831     5833 1 12306 my $self = shift->_get_self;
159 5831         12132 return $self->_engine->lock_exclusive( $self, @_ );
160             }
161             *lock = \&lock_exclusive;
162              
163             sub lock_shared {
164 4627     4629 1 9559 my $self = shift->_get_self;
165             # cluck() the problem with cached File objects.
166 4627 50       8229 unless ( $self->_engine ) {
167 1         2 require Carp;
168 1         27 require Data::Dumper;
169 1         7 Carp::cluck( Data::Dumper->Dump( [$self], ['self'] ) );
170             }
171 4627         8355 return $self->_engine->lock_shared( $self, @_ );
172             }
173              
174             sub unlock {
175 10452     10454 1 24641 my $self = shift->_get_self;
176 10452         22361 return $self->_engine->unlock( $self, @_ );
177             }
178              
179             sub _copy_value {
180 72     72   164 my $self = shift->_get_self;
181 72         170 my ($spot, $value) = @_;
182              
183 72 100       176 if ( !ref $value ) {
184 40         59 ${$spot} = $value;
  40         104  
185             }
186             else {
187 33         101 my $r = Scalar::Util::reftype( $value );
188 33         47 my $tied;
189 33 100       116 if ( $r eq 'ARRAY' ) {
    50          
190 20         47 $tied = tied(@$value);
191             }
192             elsif ( $r eq 'HASH' ) {
193 14         29 $tied = tied(%$value);
194             }
195             else {
196 1         13 __PACKAGE__->_throw_error( "Unknown type for '$value'" );
197             }
198              
199 33 50       68 if ( eval { local $SIG{'__DIE__'}; $tied->isa( __PACKAGE__ ) } ) {
  33         128  
  33         250  
200 33         101 ${$spot} = $tied->_repr;
  33         74  
201 33         79 $tied->_copy_node( ${$spot} );
  33         154  
202             }
203             else {
204 1 0       2 if ( $r eq 'ARRAY' ) {
205 1         24 ${$spot} = [ @{$value} ];
  1         6  
  1         2  
206             }
207             else {
208 1         14 ${$spot} = { %{$value} };
  1         7  
  1         2  
209             }
210             }
211              
212 33         154 my $c = Scalar::Util::blessed( $value );
213 33 100 66     291 if ( defined $c && !$c->isa( __PACKAGE__ ) ) {
214 17         47 ${$spot} = bless ${$spot}, $c
  17         48  
  17         386  
215             }
216             }
217              
218 72         195 return 1;
219             }
220              
221             sub export {
222 13     13 1 81 my $self = shift->_get_self;
223              
224 13         60 my $temp = $self->_repr;
225              
226 13         59 $self->lock_exclusive;
227 13         99 $self->_copy_node( $temp );
228 13         58 $self->unlock;
229              
230 13         51 my $classname = $self->_engine->get_classname( $self );
231 13 100       69 if ( defined $classname ) {
232 5         24 bless $temp, $classname;
233             }
234              
235 13         61 return $temp;
236             }
237              
238             sub _check_legality {
239 98     98   170 my $self = shift;
240 98         152 my ($val) = @_;
241              
242 98         217 my $r = Scalar::Util::reftype( $val );
243              
244 98 100 66     374 return $r if !defined $r || '' eq $r;
245 62 100       170 return $r if 'HASH' eq $r;
246 31 100       103 return $r if 'ARRAY' eq $r;
247              
248 4         32 __PACKAGE__->_throw_error(
249             "Storage of references of type '$r' is not supported."
250             );
251             }
252              
253             sub import {
254 64 100   64   5995 return if !ref $_[0]; # Perl calls import() on use -- ignore
255              
256 13         39 my $self = shift->_get_self;
257 13         44 my ($struct) = @_;
258              
259 13         52 my $type = $self->_check_legality( $struct );
260 13 100       65 if ( !$type ) {
261 3         21 __PACKAGE__->_throw_error( "Cannot import a scalar" );
262             }
263              
264 11 100       58 if ( substr( $type, 0, 1 ) ne $self->_type ) {
265 3 100       24 __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         33 my %seen;
272             my $recurse;
273             $recurse = sub {
274 29     29   69 my ($db, $val) = @_;
275              
276 29 100       141 my $obj = 'HASH' eq Scalar::Util::reftype( $db ) ? tied(%$db) : tied(@$db);
277 29   66     263 $obj ||= $db;
278              
279 29         80 my $r = $self->_check_legality( $val );
280 29 100       118 if ( 'HASH' eq $r ) {
    50          
281 16         86 while ( my ($k, $v) = each %$val ) {
282 30         88 my $r = $self->_check_legality( $v );
283 29 100       97 if ( $r ) {
284 15 100       68 my $temp = 'HASH' eq $r ? {} : [];
285 15 100       68 if ( my $c = Scalar::Util::blessed( $v ) ) {
286 6         27 bless $temp, $c;
287             }
288 15         79 $obj->put( $k, $temp );
289 15         69 $recurse->( $temp, $v );
290             }
291             else {
292 15         48 $obj->put( $k, $v );
293             }
294             }
295             }
296             elsif ( 'ARRAY' eq $r ) {
297 14         69 foreach my $k ( 0 .. $#$val ) {
298 29         64 my $v = $val->[$k];
299 29         77 my $r = $self->_check_legality( $v );
300 27 100       68 if ( $r ) {
301 7 100       25 my $temp = 'HASH' eq $r ? {} : [];
302 7 100       37 if ( my $c = Scalar::Util::blessed( $v ) ) {
303 3         12 bless $temp, $c;
304             }
305 7         24 $obj->put( $k, $temp );
306 7         56 $recurse->( $temp, $v );
307             }
308             else {
309 21         54 $obj->put( $k, $v );
310             }
311             }
312             }
313 9         83 };
314 9         28 $recurse->( $self, $struct );
315              
316 6         36 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       18 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         18 ( map { $_ => $self->_engine->$_ } qw(
  9         21  
345             byte_size max_buckets data_sector_size num_txns
346             )),
347             );
348              
349 3         25 $self->lock_exclusive;
350 3         25 $self->_engine->clear_cache;
351 3         12 $self->_copy_node( $db_temp );
352 3         40 $self->unlock;
353 3         25 $db_temp->_engine->storage->close;
354 3         12 undef $db_temp;
355              
356             ##
357             # Attempt to copy user, group and permissions over to new file
358             ##
359 3         24 $self->_engine->storage->copy_stats( $temp_filename );
360              
361             # q.v. perlport for more information on this variable
362 3 50 33     29 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         2 $self->unlock;
370 1         14 $self->_engine->storage->close;
371             }
372              
373 3 50       14 if (!rename $temp_filename, $self->_engine->storage->{file}) {
374 1         2 unlink $temp_filename;
375 1         22 $self->unlock;
376 1         24 $self->_throw_error("Optimize failed: Cannot copy temp file over original: $!");
377             }
378              
379 3         21 $self->unlock;
380 3         21 $self->_engine->storage->close;
381              
382 3         16 $self->_engine->storage->open;
383 3         14 $self->lock_exclusive;
384 3         33 $self->_engine->setup( $self );
385 3         27 $self->unlock;
386              
387 3         11 return 1;
388             }
389              
390             sub clone {
391 2     2 1 23 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 1455 my $self = shift->_get_self;
403 13         62 return $self->_engine->supports( @_ );
404             }
405              
406             sub db_version {
407 3     3 1 16 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 607 my $self = shift->_get_self;
422 10         36 my $type = lc shift;
423 10         21 my $func = shift;
424              
425 10 100       28 if ( $is_legal_filter{$type} ) {
426 9         31 $self->_engine->storage->{"filter_$type"} = $func;
427 9         56 return 1;
428             }
429              
430 2         15 return;
431             }
432              
433 2     2 1 18 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 6 sub filter_fetch_key { $_[0]->set_filter( fetch_key => $_[1] ); }
436 2     2 1 29 sub filter_fetch_value { $_[0]->set_filter( fetch_value => $_[1] ); }
437             }
438              
439             sub begin_work {
440 278     278 1 120992 my $self = shift->_get_self;
441 278         832 $self->lock_exclusive;
442 278         509 my $rv = eval {
443 278         1214 local $SIG{'__DIE__'};
444 278         761 $self->_engine->begin_work( $self, @_ );
445             };
446 278         650 my $e = $@;
447 278         822 $self->unlock;
448 278 100       707 die $e if $e;
449 276         1281 return $rv;
450             }
451              
452             sub rollback {
453 15     15 1 817 my $self = shift->_get_self;
454              
455 15         55 $self->lock_exclusive;
456 15         61 my $rv = eval {
457 15         83 local $SIG{'__DIE__'};
458 15         54 $self->_engine->rollback( $self, @_ );
459             };
460 15         83 my $e = $@;
461 15         63 $self->unlock;
462 15 100       74 die $e if $e;
463 13         71 return $rv;
464             }
465              
466             sub commit {
467 13     13 1 761 my $self = shift->_get_self;
468 13         51 $self->lock_exclusive;
469 13         51 my $rv = eval {
470 13         64 local $SIG{'__DIE__'};
471 13         48 $self->_engine->commit( $self, @_ );
472             };
473 13         56 my $e = $@;
474 13         64 $self->unlock;
475 13 100       80 die $e if $e;
476 11         51 return $rv;
477             }
478              
479             # Accessor methods
480             sub _engine {
481 45582     45582   198280 my $self = $_[0]->_get_self;
482 45582         126481 return $self->{engine};
483             }
484              
485             sub _type {
486 396     396   1560 my $self = $_[0]->_get_self;
487 396         2124 return $self->{type};
488             }
489              
490             sub _base_offset {
491 10782     10782   22105 my $self = $_[0]->_get_self;
492 10782         31805 return $self->{base_offset};
493             }
494              
495             sub _staleness {
496 5526     5526   13786 my $self = $_[0]->_get_self;
497 5526         16500 return $self->{staleness};
498             }
499              
500             # Utility methods
501             sub _throw_error {
502 56     56   310 my $n = 0;
503 56         96 while( 1 ) {
504 175         423 my @caller = caller( ++$n );
505 175 100       7032 next if $caller[0] =~ m/^DBM::Deep/;
506              
507 56         571 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   4052 my $self = shift->_get_self;
514 1801         4169 my ($key, $value) = @_;
515 1801         2389 warn "STORE($self, '$key', '@{[defined$value?$value:'undef']}')\n" if DEBUG;
516              
517 1801 100       3308 unless ( $self->_engine->storage->is_writable ) {
518 3         21 $self->_throw_error( 'Cannot write to a readonly filehandle' );
519             }
520              
521 1798         5306 $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     5920 if ( !ref($value) && $self->_engine->storage->{filter_store_value} ) {
526 3         26 $value = $self->_engine->storage->{filter_store_value}->( $value );
527             }
528              
529 1798         2796 eval {
530 1798         6481 local $SIG{'__DIE__'};
531 1798         3881 $self->_engine->write_value( $self, $key, $value );
532 1798 100       5172 }; if ( my $e = $@ ) {
533 13         40 $self->unlock;
534 13         182 die $e;
535             }
536              
537 1786         5529 $self->unlock;
538              
539 1786         9136 return 1;
540             }
541              
542             # Fetch single value or element given plain key or array index
543             sub FETCH {
544 3135     3135   6264 my $self = shift->_get_self;
545 3135         6622 my ($key) = @_;
546 3135         3895 warn "FETCH($self, '$key')\n" if DEBUG;
547              
548 3135         7639 $self->lock_shared;
549              
550 3135         7599 my $result = $self->_engine->read_value( $self, $key );
551              
552 3134         10397 $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     10957 ? $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   268 my $self = shift->_get_self;
564 61         212 my ($key) = @_;
565 61         179 warn "DELETE($self, '$key')\n" if DEBUG;
566              
567 61 100       154 unless ( $self->_engine->storage->is_writable ) {
568 2         6 $self->_throw_error( 'Cannot write to a readonly filehandle' );
569             }
570              
571 60         231 $self->lock_exclusive;
572              
573             ##
574             # Delete bucket
575             ##
576 60         215 my $value = $self->_engine->delete_key( $self, $key);
577              
578 59 100 100     412 if (defined $value && !ref($value) && $self->_engine->storage->{filter_fetch_value}) {
      100        
579 2         18 $value = $self->_engine->storage->{filter_fetch_value}->($value);
580             }
581              
582 59         208 $self->unlock;
583              
584 59         301 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   331 my $self = shift->_get_self;
590 130         283 my ($key) = @_;
591 130         223 warn "EXISTS($self, '$key')\n" if DEBUG;
592              
593 130         422 $self->lock_shared;
594              
595 130         460 my $result = $self->_engine->key_exists( $self, $key );
596              
597 129         444 $self->unlock;
598              
599 129         1038 return $result;
600             }
601              
602             # Clear all keys from hash, or all elements from array.
603             sub CLEAR {
604 221     221   629 my $self = shift->_get_self;
605 221         362 warn "CLEAR($self)\n" if DEBUG;
606              
607 221         593 my $engine = $self->_engine;
608 221 100       553 unless ( $engine->storage->is_writable ) {
609 2         5 $self->_throw_error( 'Cannot write to a readonly filehandle' );
610             }
611              
612 220         792 $self->lock_exclusive;
613 220         451 eval {
614 220         688 local $SIG{'__DIE__'};
615 220         685 $engine->clear( $self );
616             };
617 220         522 my $e = $@;
618 220 50 100     682 warn "$e\n" if $e && DEBUG;
619              
620 220         673 $self->unlock;
621              
622 220 100       607 die $e if $e;
623              
624 219         1276 return 1;
625             }
626              
627             # Public method aliases
628 70     70 1 426 sub put { (shift)->STORE( @_ ) }
629 97     97 1 1969 sub get { (shift)->FETCH( @_ ) }
630 11     11 1 1245 sub store { (shift)->STORE( @_ ) }
631 21     21 1 927 sub fetch { (shift)->FETCH( @_ ) }
632 13     13 1 924 sub delete { (shift)->DELETE( @_ ) }
633 17     17 1 1498 sub exists { (shift)->EXISTS( @_ ) }
634 10     10 1 717 sub clear { (shift)->CLEAR( @_ ) }
635              
636 4     4   46 sub _dump_file {shift->_get_self->_engine->_dump_file;}
637              
638             sub _warnif {
639 4     4   7 my $level;
640             {
641 4         28 my($pack, $file, $line, $bitmask) = (caller $level++)[0..2,9];
  16         88  
642 16 100       89 redo if $pack =~ /^DBM::Deep(?:::|\z)/;
643 4 50       22 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     31 if( vec $bitmask, $warnings::Offsets{$_[0]}, 1,
651             || vec $bitmask, $warnings::Offsets{all}, 1,
652             ) {
653 3 50       29 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     32 || vec $bitmask, $warnings::Offsets{all}+1, 1;
657 2         14 warn $msg;
658             }
659             }
660             }
661             }
662              
663             sub _free {
664 16     16   39 my $self = shift;
665 16 50       75 if(my $sector = $self->{engine}->load_sector( $self->{base_offset} )) {
666 16         44 $sector->free;
667             }
668             }
669              
670             sub DESTROY {
671 5777     5777   95825 my $self = shift;
672 5777         11675 my $alter_ego = $self->_get_self;
673 5777 100 66     11002 if( !$alter_ego || $self != $alter_ego ) {
674 2851         8943 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       7914 return if !$self->{engine};
679 2926 100       17526 if( $self->{engine}->{external_refs} ) {
680 16         59 $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   216789 for(values %obj_cache);
690             }
691              
692             1;
693             __END__