File Coverage

blib/lib/DBM/Deep.pm
Criterion Covered Total %
statement 687 687 100.0
branch 109 130 83.8
condition 29 44 65.9
subroutine 229 229 100.0
pod 26 26 100.0
total 1080 1116 96.7


line stmt bran cond sub pod time code
1             package DBM::Deep;
2              
3 100     100   19685255 use 5.008_004;
  100         344  
4              
5 100     84   1374 use strict;
  84         438  
  84         2133  
6 84     63   1000 use warnings FATAL => 'all';
  63         277  
  63         4695  
7 63     63   505 no warnings 'recursion';
  63         156  
  63         3559  
8              
9             our $VERSION = q(2.0019);
10              
11 63     61   538 use Scalar::Util ();
  61         180  
  61         3807  
12              
13             use overload
14             (
15             '""' =>
16 99670     99669   294680 '0+' => sub { $_[0] },
17 60         705 )[0,2,1,2], # same sub for both
18 61     60   1963 fallback => 1;
  60         4433  
19              
20 60     60   6053 use constant DEBUG => 0;
  60         177  
  60         4657  
21              
22 60     60   32177 use DBM::Deep::Engine;
  60         316  
  60         5734  
23              
24 3751     3750 1 23560 sub TYPE_HASH () { DBM::Deep::Engine->SIG_HASH }
25 4538     4538 1 37532 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 60     60   423 use constant HAVE_HUFH => scalar eval{ require Hash::Util::FieldHash };
  60         139  
  60         186  
  60         38203  
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 5687     5687   9702 my $proto = shift;
35              
36 5687         8651 my $args;
37 5687 100       16537 if (scalar(@_) > 1) {
    100          
38 3095 100       9037 if ( @_ % 2 ) {
39 5         60 $proto->_throw_error( "Odd number of parameters to " . (caller(1))[2] );
40             }
41 3093         14316 $args = {@_};
42             }
43             elsif ( ref $_[0] ) {
44 2564 50       5011 unless ( eval { local $SIG{'__DIE__'}; %{$_[0]} || 1 } ) {
  2564 100       23073  
  2564         4227  
  2564         15821  
45 5         68 $proto->_throw_error( "Not a hashref in args to " . (caller(1))[2] );
46             }
47 2562         4910 $args = $_[0];
48             }
49             else {
50 34         122 $args = { file => shift };
51             }
52              
53 5683         13060 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 2727     2727 1 502575 my $class = shift;
61 2727         8848 my $args = $class->_get_args( @_ );
62 2727         4570 my $self;
63              
64 2727 100 100     11712 if (defined($args->{type}) && $args->{type} eq TYPE_ARRAY) {
65 2118         4003 $class = 'DBM::Deep::Array';
66 2118         22534 require DBM::Deep::Array;
67 2118         15175 tie @$self, $class, %$args;
68             }
69             else {
70 612         1179 $class = 'DBM::Deep::Hash';
71 612         34561 require DBM::Deep::Hash;
72 612         4129 tie %$self, $class, %$args;
73             }
74              
75 2715         13955 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 2959     2959   5050 my $class = shift;
82 2959         5878 my ($args) = @_;
83              
84             # locking implicitly enables autoflush
85 2959 100       7729 if ($args->{locking}) { $args->{autoflush} = 1; }
  24         110  
86              
87             # These are the defaults to be optionally overridden below
88 2959         6884 my $self = bless {
89             type => TYPE_HASH,
90             base_offset => undef,
91             staleness => undef,
92             engine => undef,
93             }, $class;
94              
95 2959 100       8718 unless ( exists $args->{engine} ) {
96             my $class =
97             exists $args->{dbi} ? 'DBM::Deep::Engine::DBI' :
98 413 100       1301 exists $args->{_test} ? 'DBM::Deep::Engine::Test' :
    50          
99             'DBM::Deep::Engine::File' ;
100              
101 59 50   59   37385 eval "use $class"; die $@ if $@;
  59     1   415  
  59     1   1715  
  411     1   43467  
  411     1   1717  
  1     1   25  
  1     1   3  
  1     1   32  
  1     1   10  
  1     1   3  
  1     1   22  
  1     1   8  
  1     1   3  
  1     1   20  
  1     1   8  
  1     1   2  
  1     1   19  
  1     1   8  
  1     1   2  
  1     1   21  
  1     1   6  
  1     1   1  
  1     1   12  
  1     1   6  
  1     1   1  
  1     1   13  
  1     1   5  
  1     1   2  
  1     1   12  
  1     1   8  
  1     1   2  
  1     1   20  
  1     1   9  
  1     1   3  
  1     1   21  
  1     1   9  
  1     1   2  
  1     1   24  
  1     1   8  
  1     1   2  
  1     1   19  
  1     1   9  
  1     1   3  
  1     1   20  
  1     1   9  
  1     1   2  
  1     1   22  
  1     1   11  
  1     1   2  
  1     1   25  
  1     1   7  
  1     1   2  
  1     1   19  
  1     1   9  
  1     1   2  
  1     1   18  
  1     1   8  
  1     1   2  
  1     1   20  
  1     1   8  
  1     1   3  
  1     1   18  
  1     1   9  
  1     1   3  
  1     1   21  
  1     1   9  
  1     1   3  
  1     1   21  
  1     1   10  
  1     1   3  
  1     1   120  
  1     1   9  
  1     1   3  
  1     1   34  
  1     1   8  
  1     1   3  
  1     1   19  
  1     1   8  
  1     1   3  
  1     1   19  
  1     1   11  
  1     1   3  
  1     1   21  
  1     1   5  
  1     1   2  
  1     1   13  
  1     1   8  
  1     1   2  
  1     1   19  
  1     1   10  
  1     1   3  
  1     1   19  
  1     1   9  
  1     1   2  
  1     1   19  
  1     1   10  
  1     1   4  
  1     1   23  
  1     1   8  
  1     1   3  
  1     1   19  
  1     1   7  
  1     1   1  
  1     1   16  
  1     1   9  
  1     1   3  
  1     1   21  
  1     1   5  
  1     1   1  
  1     1   13  
  1     1   10  
  1     1   4  
  1     1   23  
  1     1   9  
  1     1   3  
  1     1   22  
  1     1   7  
  1     1   3  
  1     1   17  
  1     1   9  
  1     1   3  
  1     1   19  
  1     1   8  
  1     1   5  
  1     1   20  
  1     1   9  
  1     1   3  
  1     1   19  
  1     1   8  
  1     1   4  
  1     1   20  
  1     1   8  
  1     1   3  
  1     1   21  
  1     1   9  
  1     1   2  
  1     1   20  
  1     1   7  
  1     1   3  
  1     1   19  
  1     1   11  
  1     1   4  
  1     1   22  
  1     1   8  
  1     1   3  
  1     1   19  
  1     1   11  
  1     1   4  
  1     1   39  
  1     1   9  
  1     1   2  
  1     1   20  
  1     1   8  
  1     1   2  
  1     1   19  
  1     1   5  
  1     1   3  
  1     1   13  
  1     1   5  
  1     1   1  
  1     1   14  
  1     1   5  
  1     1   2  
  1     1   12  
  1     1   9  
  1     1   2  
  1     1   20  
  1     1   4  
  1     1   3  
  1     1   13  
  1         8  
  1         3  
  1         20  
  1         9  
  1         3  
  1         20  
  1         9  
  1         2  
  1         21  
  1         8  
  1         2  
  1         22  
  1         9  
  1         3  
  1         20  
  1         8  
  1         3  
  1         20  
  1         5  
  1         2  
  1         14  
  1         5  
  1         1  
  1         12  
  1         9  
  1         2  
  1         21  
  1         5  
  1         2  
  1         12  
  1         8  
  1         5  
  1         20  
  1         8  
  1         3  
  1         19  
  1         5  
  1         2  
  1         14  
  1         7  
  1         3  
  1         20  
  1         12  
  1         3  
  1         23  
  1         5  
  1         2  
  1         13  
  1         5  
  1         2  
  1         14  
  1         5  
  1         1  
  1         14  
  1         5  
  1         2  
  1         12  
  1         9  
  1         2  
  1         21  
  1         6  
  1         2  
  1         15  
  1         8  
  1         3  
  1         18  
  1         6  
  1         1  
  1         15  
  1         4  
  1         2  
  1         13  
  1         9  
  1         3  
  1         21  
  1         5  
  1         2  
  1         13  
  1         7  
  1         2  
  1         14  
  1         8  
  1         2  
  1         21  
  1         4  
  1         1  
  1         13  
  1         7  
  1         2  
  1         19  
  1         9  
  1         3  
  1         21  
  1         4  
  1         1  
  1         13  
  1         6  
  1         2  
  1         12  
  1         4  
  1         2  
  1         14  
  1         4  
  1         3  
  1         12  
  1         17  
  1         2  
  1         17  
  1         5  
  1         2  
  1         12  
  1         9  
  1         2  
  1         19  
  1         10  
  1         4  
  1         21  
  1         5  
  1         3  
  1         13  
  1         6  
  1         1  
  1         13  
  1         9  
  1         2  
  1         18  
  1         5  
  1         1  
  1         14  
  1         10  
  1         2  
  1         20  
  1         4  
  1         2  
  1         13  
  1         8  
  1         2  
  1         19  
  1         5  
  1         1  
  1         12  
  1         9  
  1         2  
  1         21  
  1         5  
  1         2  
  1         13  
  1         9  
  1         2  
  1         21  
  1         4  
  1         2  
  1         12  
  1         8  
  1         3  
  1         20  
  1         6  
  1         2  
  1         15  
  1         12  
  1         2  
  1         21  
  1         6  
  1         1  
  1         13  
  1         7  
  1         2  
  1         19  
102             $args->{engine} = $class->new({
103 411         773 %{$args},
  411         3740  
104             obj => $self,
105             });
106             }
107              
108             # Grab the parameters we want to use
109 2956         27256 foreach my $param ( keys %$self ) {
110 11821 100       24375 next unless exists $args->{$param};
111 11003         25425 $self->{$param} = $args->{$param};
112             }
113              
114 2956         10638 eval {
115 2956         11615 local $SIG{'__DIE__'};
116              
117 2956         10821 $self->lock_exclusive;
118 2955         8279 $self->_engine->setup( $self );
119 2943         8669 $self->unlock;
120 2956 100       7195 }; if ( $@ ) {
121 16         32 my $e = $@;
122 16         43 eval { local $SIG{'__DIE__'}; $self->unlock; };
  16         58  
  16         113  
123 16         128 die $e;
124             }
125              
126 2941 100 66     9931 if( $self->{engine}->{external_refs}
127             and my $sector = $self->{engine}->load_sector( $self->{base_offset} )
128             ) {
129 23         99 $sector->increment_refcount;
130              
131 23         59 Scalar::Util::weaken( my $feeble_ref = $self );
132 23         214 $obj_cache{ $self } = \$feeble_ref;
133              
134             # Make sure this cache is not a memory hog
135 23         43 if(!HAVE_HUFH) {
136             for(keys %obj_cache) {
137             delete $obj_cache{$_} if not ${$obj_cache{$_}};
138             }
139             }
140             }
141              
142 2941         16387 return $self;
143             }
144              
145             sub TIEHASH {
146 182     184   553260 shift;
147 182         6147 require DBM::Deep::Hash;
148 182         729 return DBM::Deep::Hash->TIEHASH( @_ );
149             }
150              
151             sub TIEARRAY {
152 56     58   3433 shift;
153 56         12895 require DBM::Deep::Array;
154 56         385 return DBM::Deep::Array->TIEARRAY( @_ );
155             }
156              
157             sub lock_exclusive {
158 8394     8396 1 22923 my $self = shift->_get_self;
159 8394         22966 return $self->_engine->lock_exclusive( $self, @_ );
160             }
161             *lock = \&lock_exclusive;
162              
163             sub lock_shared {
164 6820     6822 1 15927 my $self = shift->_get_self;
165             # cluck() the problem with cached File objects.
166 6820 50       18475 unless ( $self->_engine ) {
167 1         1 require Carp;
168 1         13 require Data::Dumper;
169 1         4 Carp::cluck( Data::Dumper->Dump( [$self], ['self'] ) );
170             }
171 6820         15281 return $self->_engine->lock_shared( $self, @_ );
172             }
173              
174             sub unlock {
175 15201     15203 1 40871 my $self = shift->_get_self;
176 15201         36920 return $self->_engine->unlock( $self, @_ );
177             }
178              
179             sub _copy_value {
180 72     72   180 my $self = shift->_get_self;
181 72         184 my ($spot, $value) = @_;
182              
183 72 100       177 if ( !ref $value ) {
184 40         81 ${$spot} = $value;
  40         111  
185             }
186             else {
187 33         99 my $r = Scalar::Util::reftype( $value );
188 33         64 my $tied;
189 33 100       111 if ( $r eq 'ARRAY' ) {
    50          
190 20         52 $tied = tied(@$value);
191             }
192             elsif ( $r eq 'HASH' ) {
193 14         33 $tied = tied(%$value);
194             }
195             else {
196 1         12 __PACKAGE__->_throw_error( "Unknown type for '$value'" );
197             }
198              
199 33 50       61 if ( eval { local $SIG{'__DIE__'}; $tied->isa( __PACKAGE__ ) } ) {
  33         184  
  33         302  
200 33         106 ${$spot} = $tied->_repr;
  33         70  
201 33         71 $tied->_copy_node( ${$spot} );
  33         161  
202             }
203             else {
204 1 0       3 if ( $r eq 'ARRAY' ) {
205 1         14 ${$spot} = [ @{$value} ];
  1         5  
  1         1  
206             }
207             else {
208 1         14 ${$spot} = { %{$value} };
  1         4  
  1         1  
209             }
210             }
211              
212 33         102 my $c = Scalar::Util::blessed( $value );
213 33 100 66     310 if ( defined $c && !$c->isa( __PACKAGE__ ) ) {
214 17         31 ${$spot} = bless ${$spot}, $c
  17         49  
  17         50  
215             }
216             }
217              
218 72         295 return 1;
219             }
220              
221             sub export {
222 13     13 1 93 my $self = shift->_get_self;
223              
224 13         68 my $temp = $self->_repr;
225              
226 13         61 $self->lock_exclusive;
227 13         72 $self->_copy_node( $temp );
228 13         82 $self->unlock;
229              
230 13         45 my $classname = $self->_engine->get_classname( $self );
231 13 100       61 if ( defined $classname ) {
232 5         19 bless $temp, $classname;
233             }
234              
235 13         104 return $temp;
236             }
237              
238             sub _check_legality {
239 98     98   156 my $self = shift;
240 98         172 my ($val) = @_;
241              
242 98         204 my $r = Scalar::Util::reftype( $val );
243              
244 98 100 66     366 return $r if !defined $r || '' eq $r;
245 62 100       180 return $r if 'HASH' eq $r;
246 31 100       107 return $r if 'ARRAY' eq $r;
247              
248 4         27 __PACKAGE__->_throw_error(
249             "Storage of references of type '$r' is not supported."
250             );
251             }
252              
253             sub import {
254 67 100   67   147378 return if !ref $_[0]; # Perl calls import() on use -- ignore
255              
256 13         56 my $self = shift->_get_self;
257 13         38 my ($struct) = @_;
258              
259 13         84 my $type = $self->_check_legality( $struct );
260 13 100       31 if ( !$type ) {
261 3         19 __PACKAGE__->_throw_error( "Cannot import a scalar" );
262             }
263              
264 11 100       44 if ( substr( $type, 0, 1 ) ne $self->_type ) {
265 3 100       17 __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         48 my %seen;
272             my $recurse;
273             $recurse = sub {
274 29     29   77 my ($db, $val) = @_;
275              
276 29 100       134 my $obj = 'HASH' eq Scalar::Util::reftype( $db ) ? tied(%$db) : tied(@$db);
277 29   66     294 $obj ||= $db;
278              
279 29         80 my $r = $self->_check_legality( $val );
280 29 100       129 if ( 'HASH' eq $r ) {
    50          
281 16         88 while ( my ($k, $v) = each %$val ) {
282 30         82 my $r = $self->_check_legality( $v );
283 29 100       77 if ( $r ) {
284 15 100       49 my $temp = 'HASH' eq $r ? {} : [];
285 15 100       47 if ( my $c = Scalar::Util::blessed( $v ) ) {
286 6         28 bless $temp, $c;
287             }
288 15         62 $obj->put( $k, $temp );
289 15         87 $recurse->( $temp, $v );
290             }
291             else {
292 15         132 $obj->put( $k, $v );
293             }
294             }
295             }
296             elsif ( 'ARRAY' eq $r ) {
297 14         115 foreach my $k ( 0 .. $#$val ) {
298 29         64 my $v = $val->[$k];
299 29         90 my $r = $self->_check_legality( $v );
300 27 100       68 if ( $r ) {
301 7 100       26 my $temp = 'HASH' eq $r ? {} : [];
302 7 100       34 if ( my $c = Scalar::Util::blessed( $v ) ) {
303 3         12 bless $temp, $c;
304             }
305 7         40 $obj->put( $k, $temp );
306 7         49 $recurse->( $temp, $v );
307             }
308             else {
309 21         67 $obj->put( $k, $v );
310             }
311             }
312             }
313 9         77 };
314 9         27 $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 30 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         21 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         14 ( map { $_ => $self->_engine->$_ } qw(
  9         22  
345             byte_size max_buckets data_sector_size num_txns
346             )),
347             );
348              
349 3         23 $self->lock_exclusive;
350 3         14 $self->_engine->clear_cache;
351 3         13 $self->_copy_node( $db_temp );
352 3         38 $self->unlock;
353 3         13 $db_temp->_engine->storage->close;
354 3         10 undef $db_temp;
355              
356             ##
357             # Attempt to copy user, group and permissions over to new file
358             ##
359 3         19 $self->_engine->storage->copy_stats( $temp_filename );
360              
361             # q.v. perlport for more information on this variable
362 3 50 33     23 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         13 $self->_engine->storage->close;
371             }
372              
373 3 50       15 if (!rename $temp_filename, $self->_engine->storage->{file}) {
374 1         1 unlink $temp_filename;
375 1         13 $self->unlock;
376 1         7 $self->_throw_error("Optimize failed: Cannot copy temp file over original: $!");
377             }
378              
379 3         18 $self->unlock;
380 3         23 $self->_engine->storage->close;
381              
382 3         34 $self->_engine->storage->open;
383 3         9 $self->lock_exclusive;
384 3         28 $self->_engine->setup( $self );
385 3         18 $self->unlock;
386              
387 3         10 return 1;
388             }
389              
390             sub clone {
391 2     2 1 36 my $self = shift->_get_self;
392              
393 2         13 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 644 my $self = shift->_get_self;
403 13         77 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 1009 my $self = shift->_get_self;
422 10         45 my $type = lc shift;
423 10         24 my $func = shift;
424              
425 10 100       52 if ( $is_legal_filter{$type} ) {
426 9         50 $self->_engine->storage->{"filter_$type"} = $func;
427 9         55 return 1;
428             }
429              
430 2         16 return;
431             }
432              
433 2     2 1 26 sub filter_store_key { $_[0]->set_filter( store_key => $_[1] ); }
434 2     2 1 42 sub filter_store_value { $_[0]->set_filter( store_value => $_[1] ); }
435 2     2 1 9 sub filter_fetch_key { $_[0]->set_filter( fetch_key => $_[1] ); }
436 2     2 1 26 sub filter_fetch_value { $_[0]->set_filter( fetch_value => $_[1] ); }
437             }
438              
439             sub begin_work {
440 278     278 1 113257 my $self = shift->_get_self;
441 278         1251 $self->lock_exclusive;
442 278         508 my $rv = eval {
443 278         1315 local $SIG{'__DIE__'};
444 278         717 $self->_engine->begin_work( $self, @_ );
445             };
446 278         557 my $e = $@;
447 278         804 $self->unlock;
448 278 100       639 die $e if $e;
449 276         1265 return $rv;
450             }
451              
452             sub rollback {
453 15     15 1 652 my $self = shift->_get_self;
454              
455 15         61 $self->lock_exclusive;
456 15         52 my $rv = eval {
457 15         98 local $SIG{'__DIE__'};
458 15         61 $self->_engine->rollback( $self, @_ );
459             };
460 15         66 my $e = $@;
461 15         80 $self->unlock;
462 15 100       66 die $e if $e;
463 13         62 return $rv;
464             }
465              
466             sub commit {
467 13     13 1 739 my $self = shift->_get_self;
468 13         52 $self->lock_exclusive;
469 13         68 my $rv = eval {
470 13         68 local $SIG{'__DIE__'};
471 13         43 $self->_engine->commit( $self, @_ );
472             };
473 13         54 my $e = $@;
474 13         54 $self->unlock;
475 13 100       51 die $e if $e;
476 11         72 return $rv;
477             }
478              
479             # Accessor methods
480             sub _engine {
481 65668     65668   252256 my $self = $_[0]->_get_self;
482 65668         226299 return $self->{engine};
483             }
484              
485             sub _type {
486 413     413   1121 my $self = $_[0]->_get_self;
487 413         2548 return $self->{type};
488             }
489              
490             sub _base_offset {
491 12658     12658   30149 my $self = $_[0]->_get_self;
492 12658         45752 return $self->{base_offset};
493             }
494              
495             sub _staleness {
496 7368     7368   22286 my $self = $_[0]->_get_self;
497 7368         25994 return $self->{staleness};
498             }
499              
500             # Utility methods
501             sub _throw_error {
502 56     56   324 my $n = 0;
503 56         101 while( 1 ) {
504 175         499 my @caller = caller( ++$n );
505 175 100       7620 next if $caller[0] =~ m/^DBM::Deep/;
506              
507 56         660 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 2893     2893   6877 my $self = shift->_get_self;
514 2893         8506 my ($key, $value) = @_;
515 2893         3785 warn "STORE($self, '$key', '@{[defined$value?$value:'undef']}')\n" if DEBUG;
516              
517 2893 100       6520 unless ( $self->_engine->storage->is_writable ) {
518 3         31 $self->_throw_error( 'Cannot write to a readonly filehandle' );
519             }
520              
521 2890         9496 $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 2890 100 100     9561 if ( !ref($value) && $self->_engine->storage->{filter_store_value} ) {
526 3         39 $value = $self->_engine->storage->{filter_store_value}->( $value );
527             }
528              
529 2890         5605 eval {
530 2890         12142 local $SIG{'__DIE__'};
531 2890         6703 $self->_engine->write_value( $self, $key, $value );
532 2890 100       9370 }; if ( my $e = $@ ) {
533 21         125 $self->unlock;
534 21         177 die $e;
535             }
536              
537 2870         10173 $self->unlock;
538              
539 2870         15485 return 1;
540             }
541              
542             # Fetch single value or element given plain key or array index
543             sub FETCH {
544 3880     3880   11617 my $self = shift->_get_self;
545 3880         10062 my ($key) = @_;
546 3880         6143 warn "FETCH($self, '$key')\n" if DEBUG;
547              
548 3880         13432 $self->lock_shared;
549              
550 3880         11546 my $result = $self->_engine->read_value( $self, $key );
551              
552 3879         14940 $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 3879 100 100     17628 ? $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 63     63   196 my $self = shift->_get_self;
564 63         185 my ($key) = @_;
565 63         154 warn "DELETE($self, '$key')\n" if DEBUG;
566              
567 63 100       180 unless ( $self->_engine->storage->is_writable ) {
568 2         12 $self->_throw_error( 'Cannot write to a readonly filehandle' );
569             }
570              
571 62         314 $self->lock_exclusive;
572              
573             ##
574             # Delete bucket
575             ##
576 62         206 my $value = $self->_engine->delete_key( $self, $key);
577              
578 61 100 100     607 if (defined $value && !ref($value) && $self->_engine->storage->{filter_fetch_value}) {
      100        
579 2         38 $value = $self->_engine->storage->{filter_fetch_value}->($value);
580             }
581              
582 61         293 $self->unlock;
583              
584 61         429 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   342 my $self = shift->_get_self;
590 130         298 my ($key) = @_;
591 130         175 warn "EXISTS($self, '$key')\n" if DEBUG;
592              
593 130         390 $self->lock_shared;
594              
595 130         344 my $result = $self->_engine->key_exists( $self, $key );
596              
597 129         386 $self->unlock;
598              
599 129         892 return $result;
600             }
601              
602             # Clear all keys from hash, or all elements from array.
603             sub CLEAR {
604 224     224   619 my $self = shift->_get_self;
605 224         552 warn "CLEAR($self)\n" if DEBUG;
606              
607 224         522 my $engine = $self->_engine;
608 224 100       597 unless ( $engine->storage->is_writable ) {
609 2         5 $self->_throw_error( 'Cannot write to a readonly filehandle' );
610             }
611              
612 223         737 $self->lock_exclusive;
613 223         380 eval {
614 223         691 local $SIG{'__DIE__'};
615 223         911 $engine->clear( $self );
616             };
617 223         452 my $e = $@;
618 223 50 100     679 warn "$e\n" if $e && DEBUG;
619              
620 223         647 $self->unlock;
621              
622 223 100       519 die $e if $e;
623              
624 222         1298 return 1;
625             }
626              
627             # Public method aliases
628 70     70 1 305 sub put { (shift)->STORE( @_ ) }
629 97     97 1 5024 sub get { (shift)->FETCH( @_ ) }
630 11     11 1 1071 sub store { (shift)->STORE( @_ ) }
631 21     21 1 988 sub fetch { (shift)->FETCH( @_ ) }
632 13     13 1 846 sub delete { (shift)->DELETE( @_ ) }
633 17     17 1 1638 sub exists { (shift)->EXISTS( @_ ) }
634 10     10 1 599 sub clear { (shift)->CLEAR( @_ ) }
635              
636 4     4   44 sub _dump_file {shift->_get_self->_engine->_dump_file;}
637              
638             sub _warnif {
639 4     4   7 my $level;
640             {
641 4         22 my($pack, $file, $line, $bitmask) = (caller $level++)[0..2,9];
  16         81  
642 16 100       58 redo if $pack =~ /^DBM::Deep(?:::|\z)/;
643 4 50       30 if(defined &warnings::warnif_at_level) { # perl >= 5.27.8
644 4         171 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 1 0 0     4 if( vec $bitmask, $warnings::Offsets{$_[0]}, 1,
651             || vec $bitmask, $warnings::Offsets{all}, 1,
652             ) {
653 1 0       21 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 1 0 0     7 || vec $bitmask, $warnings::Offsets{all}+1, 1;
657 1         2 warn $msg;
658             }
659             }
660             }
661             }
662              
663             sub _free {
664 23     23   51 my $self = shift;
665 23 50       112 if(my $sector = $self->{engine}->load_sector( $self->{base_offset} )) {
666 23         72 $sector->free;
667             }
668             }
669              
670             sub DESTROY {
671 5807     5807   135986 my $self = shift;
672 5807         14403 my $alter_ego = $self->_get_self;
673 5807 100 66     14025 if( !$alter_ego || $self != $alter_ego ) {
674 2863         11603 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 2945 100       8758 return if !$self->{engine};
679 2944 100       24416 if( $self->{engine}->{external_refs} ) {
680 19         96 $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 58   33 58   5129568 for(values %obj_cache);
690             }
691              
692             1;
693             __END__