File Coverage

blib/lib/Tie/Persistent.pm
Criterion Covered Total %
statement 158 243 65.0
branch 71 152 46.7
condition 8 26 30.7
subroutine 24 37 64.8
pod 0 2 0.0
total 261 460 56.7


line stmt bran cond sub pod time code
1             # -*-cperl-*-
2              
3 1     1   1378 use strict;
  1         39  
  1         48  
4              
5             package Tie::Persistent;
6              
7 1     1   5 use vars qw($VERSION);
  1         2  
  1         119  
8             $VERSION = '1.00';
9              
10             ######################################################################
11              
12             =head1 NAME
13              
14             Tie::Persistent - persistent data structures via tie made easy
15              
16             =head1 VERSION
17              
18             1.00
19              
20             =head1 SYNOPSIS
21              
22             use Tie::Persistent;
23              
24             tie %DB, 'Tie::Persistent', 'file', 'rw'; # read data from 'file'
25              
26             (tied %DB)->autosync(1); # turn on write back on every modify
27              
28             # now create/add/modify datastruct
29             $DB{key} = "value";
30             (tied %DB)->sync(); # can be called manually
31              
32             untie %DB; # stores data back into 'file'
33              
34             # read stored data, no modification of file data
35             tie %ReadOnly, 'Tie::Persistent', 'file';
36             foreach (keys %ReadOnly) {
37             print "$_ => $ReadOnly{$_}\n";
38             }
39             untie %ReadOnly; # modifications not stored back
40              
41              
42             =head1 DESCRIPTION
43              
44             The Tie::Persistent package makes working with persistent data real
45             easy by using the C interface.
46              
47             It works by storing data contained in a variable into a file (not
48             unlike a database). The primary advantage is speed, as the whole
49             datastructure is kept in memory (which is also a limitation), and, of
50             course, that you can use arbitrary data structures inside the variable
51             (unlike DB_File).
52              
53             Note that it is most useful if the data structure fits into memory.
54             For larger data structures I recommend MLDBM.
55              
56             If you want to make an arbitrary object persistent, just store its
57             ref in a scalar tied to 'Tie::Persistent'.
58              
59             B: not every data structure or object can be made persistent.
60             For example, it may not contain GLOB or CODE refs, as these are not
61             really dumpable (yet?).
62              
63             Also, it works only for variables, you cannot use it for file handles.
64              
65             [A persistent file handle? Hmmm... Hmmm! I've got an idea: I could
66             start a server and send the file descriptor to it via ioctl(FD_SEND)
67             or sendmsg. Later, I could retrieve it back, so it's persistent as
68             long as the server process keeps running. But the whole file handle
69             may contain more than just the file descriptor. There may be
70             an output routine associated with it that I'd somehow have to dump.
71             Now let's see, there was some way to get the bytecode converted back
72             into perl code... ... ]
73              
74             =head1 PARAMETERS
75              
76             C %Hash, 'Tie::Persistent', B, B, I;
77              
78             C @Array, 'Tie::Persistent', B, B, I;
79              
80             C $Scalar, 'Tie::Persistent', B, B, I;
81              
82             =over 4
83              
84             =item B
85              
86             Filename to store the data in. No naming convention is enforced, but I
87             personally use the suffix 'pd' for "Perl Data" (or "Persistent
88             Data"?). No file locking is done; see the section on locking below.
89              
90              
91             =item B (optional)
92              
93             Same as mode for POSIX fopen() or IO::File::open. Basically a
94             combination of 'r', 'w', 'a' and '+'. Semantics:
95              
96             'r' .... read only. Modifications in the data are not stored back
97             into the file. A non-existing file gives an error. This is
98             the default if no mode is given.
99              
100             'rw' ... read/write. Modifications are stored back, if the file does
101             not exist, it is created.
102              
103             'w' .... write only. The file is not read, the variable starts out empty.
104              
105             'a', '+' ... append. Same as 'w', but creates numbered backup files.
106              
107             'ra', 'r+' ... Same as 'rw', but creates numbered backup files.
108              
109             When some kind of write access is specified, a backup file of the
110             old dataset is always created. [You'll thank me for that, believe me.]
111             The reason is simple: when you tie a variable read-write (the contents
112             get restored from the file), and your program isn't fully debugged
113             yet, it may die in the middle of some modifications, but the data
114             will still be written back to the file, possibly leaving them
115             inconsistent. Then you always have at least the previous version
116             that you can restore from.
117              
118             The default backup filenames follow the Emacs notation, i.e. a '~' is
119             appended; for numbered backup files (specified as 'a' or '+'), an
120             additional number and a '~' is appended.
121              
122             For a file 'data.pd', the normal backup file would be 'data.pd~' and
123             the numbered backup files would be 'data.pd~1~', 'data.pd~2~' and so
124             on. The latest backup file is the one with the highest number. The
125             backup filename format can be overridden, see below.
126              
127             =item I (optional, experimental)
128              
129             This can be a reference to another (possibly tied) variable or
130             a name of another tieable package.
131              
132             If a ref is given, it is used internally to store the variable data
133             instead of an anonymous variable ref. This allows to make other tied
134             datastructures persistent, e.g. you could first tie a hash to
135             Tie::IxHash to make it order-preserving and then give it to
136             Tie::Persistent to make it persistent.
137              
138             A plain name is used to create this tied variable internally. Trailing
139             arguments are passed to the other tieable package.
140              
141             Example:
142              
143             tie %h, 'Tie::Persistent', 'file', 'rw', 'Tie::IxHash';
144              
145             or
146              
147             tie %ixh, 'Tie::IxHash';
148             tie %ph, 'Tie::Persistent', 'file', 'w', \%ixh;
149             # you can now use %ixh as an alias for %ph
150              
151             B: This is an experimental feature. It may or may not work
152             with other Tie:: packages. I have only tested it with 'Tie::IxHash'.
153             Please report success or failure.
154              
155             =back
156              
157              
158             =head1 LOCKING
159              
160             The data file is not automatically locked. Locking has to be done
161             outside of the package. I recommend using a module like
162             'Lockfile::Simple' for that.
163              
164             There are typical two scenarios for locking: you either lock just the
165             'tie' and/or 'untie' calls, but not the data manipulation, or you lock
166             the whole 'tie' - modify data - 'untie' sequence.
167              
168              
169             =head1 KEEPING DATA SYCHRONIZED
170              
171             It often is useful to store snapshots of the tied data struct back to
172             the file, e.g. to safeguard against program crashes. You have two
173             possibilities to do that:
174              
175             =over 4
176              
177             =item *
178              
179             use sync() to do it manually or
180              
181             =item *
182              
183             set autosync() to do it on every modification.
184              
185             =back
186              
187             Note that sync() and autosync() are methods of the tied object, so you
188             have to call them like this:
189              
190             (tied %hash)->sync();
191              
192             and
193              
194             (tied @array)->autosync(1); # or '0' to turn off autosync
195              
196             There is a global variable $Autosync (see there) that you can set to
197             change the behaviour on a global level for all subsequent ties.
198              
199             Enabling autosync of course means a quite hefty performance penalty,
200             so think carefully if and how you need it. Maybe there are natural
201             synchronisation points in your application where a manual sync is good
202             enough. Alternatively use MLDBM (if your top-level struct is a hash).
203              
204             Note: autosync only works if the top-level element of the data
205             structure is modified. If you have more complex data structures and
206             modify elements somewhere deep down, you have to synchronize manually.
207             I therefore recommend the following approach, especially if the
208             topmost structure is a hash:
209              
210             =over 4
211              
212             =item *
213              
214             fetch the top-level element into a temporary variable
215              
216             =item *
217              
218             modify the datastructure
219              
220             =item *
221              
222             store back the top-level element, thus triggering a sync.
223              
224             =back
225              
226             E.g.
227              
228             my $ref = $Hash{$key}; # fetch substructure
229             $ref->{$subkey} = $newval; # modify somewhere down under
230             $Hash{$key} = $ref; # store back
231              
232             This programming style has the added advantage that you can switch
233             over to other database packages (for example the MLDBM package, in
234             case your data structures outgrow your memory) quite easily by just
235             changing the 'tie' line!
236              
237              
238             =head1 CONFIGURATION VARIABLES
239              
240             B> controls which format to use to
241             store the data inside the file. 'false' means to use 'Storable', which
242             is faster (and the default), 'true' means to use 'Data::Dumper', which
243             is slower but much more readable and thus meant for debugging. This
244             only influences the way the datastructure is I, format detection
245             on read is automatic.
246              
247             B> gives the default for all tied vars, so modifying it affects all subsequent ties. It's set to 'false' by default.
248              
249             B> points to a sub that determines the
250             backup filename format. It gets the filename as $_[0] and returns the
251             backup filename. The default is
252              
253             sub { "$_[0]~"; }
254              
255             which is the Emacs backup format. For NT, you might want to change
256             this to
257              
258             sub { "$_[0].bak"; }
259              
260             or something.
261              
262             B> points to a sub that
263             determines the numbered backup filename format. It gets the filename
264             and a number as $_[0] and $_[1] respectively and returns the backup
265             filename. The default is
266              
267             sub { "$_[0]~$_[1]~"; }
268              
269             which is the extended Emacs backup format.
270              
271             =head1 NOTES
272              
273             =over 4
274              
275             =item *
276              
277             'Tie::Persistent' uses 'Storable' and 'Data::Dumper' internally, so
278             these must be installed (the CPAN module will do this for you
279             automatically). Actually, 'Storable' is optional but recommended for
280             speed.
281              
282             =item *
283              
284             For testing, I use 'Tie::IxHash', but 'make test' still does some
285             tests if it is not installed.
286              
287             =item *
288              
289             There are two mailing lists at SourceForge.net:
290              
291             http://lists.sourceforge.net/mailman/listinfo/persistent-announce
292             for announcements of new releases.
293              
294             http://lists.sourceforge.net/mailman/listinfo/persistent-discuss
295             for user feedback and feature discussions.
296              
297             =item *
298              
299             The package is available through CPAN and SourceForge.net
300             http://sourceforge.net/projects/persistent/
301              
302             =item *
303              
304             There is an initiative at SourceForge.net to get authors of
305             persistence-packages of any kind to talk to one another.
306             See http://sourceforge.net/projects/POOP/
307              
308             =back
309              
310             =head1 BUGS
311              
312             Numbered backupfile creation might have problems if the filename (not
313             the backup number) contains the first six digits of the speed of light
314             (in m/s).
315              
316             All other bugs, please tell me!
317              
318             =head1 AUTHORS
319              
320             Original version by Roland Giersig
321              
322             Benjamin Liberman added autosyncing and fixed splice.
323              
324             =head1 COPYRIGHT
325              
326             Copyright (c) 1999-2002 Roland Giersig. All rights reserved. This
327             program is free software; you can redistribute it and/or modify it
328             under the same terms as Perl itself.
329              
330             =head1 SEE ALSO
331              
332             L, L, L.
333              
334             =cut
335              
336             ######################################################################
337              
338 1     1   4 use Carp;
  1         5  
  1         81  
339              
340             # we want to be portable
341 1     1   5 use File::Basename;
  1         1  
  1         89  
342 1     1   5 use File::Spec;
  1         1  
  1         101  
343              
344             # uses Storable for performance,
345             # but Data::Dumper is more readable
346              
347             my $Has_Storable;
348             # we check if it's there, given that it's not in the core yet
349              
350             BEGIN {
351 1     1   2 eval { require Storable; };
  1         1084  
352 1         3287 $Has_Storable = (not $@);
353 1 50       5 if ($Has_Storable) {
354 1         65 import Storable;
355             } else {
356 0 0       0 warn "Suggestion: install Storable for better performance.\n" if $^W;
357             }
358             }
359              
360 1     1   1129 use Data::Dumper;
  1         9690  
  1         89  
361             $Data::Dumper::Terse = 0;
362             $Data::Dumper::Indent = 1;
363             $Data::Dumper::Purity = 1;
364              
365             # Configuration vars:
366              
367 1     1   8 use vars qw($Autosync $Readable $BackupFile $NumberedBackupFile);
  1         2  
  1         418  
368              
369             # set to 1 to store new values back to disk after changes
370             $Autosync = 0;
371              
372             # set to 1 to use Data::Dumper
373             $Readable = 0;
374              
375             # format of backup file
376             $BackupFile = sub { "$_[0]~" };
377              
378             # format of numbered backup file
379             $NumberedBackupFile = sub { "$_[0]~$_[1]~" };
380              
381             #
382             # all tie constructors delegate the work to the common '_new'
383             #
384             sub TIEHASH {
385 16     16   360 my $class = shift;
386 16         35 unshift @_, 'HASH';
387 16         46 unshift @_, "${class}::Hash";
388              
389 16         50 goto &_new;
390             }
391              
392             sub TIEARRAY {
393 6     6   318 my $class = shift;
394 6         12 unshift @_, 'ARRAY';
395 6         17 unshift @_, "${class}::Array";
396              
397 6 50       18 croak "TIEARRAY not supported prior to perl v5.005"
398             if $] < 5.005;
399              
400 6         17 goto &_new;
401             }
402              
403             sub TIESCALAR {
404 42     42   577 my $class = shift;
405 42         79 unshift @_, 'SCALAR';
406 42         100 unshift @_, "${class}::Scalar";
407              
408 42         120 goto &_new;
409             }
410              
411             #
412             # import for easier reading
413             #
414             *ISA = \&UNIVERSAL::isa;
415              
416             #
417             # as suggested by Mark-Jason Dominus
418             # now we don't have to copy those object data back into the tie...
419             #
420 0     0   0 sub Rebind::TIEHASH { $_[1] }
421              
422             #
423             # main workhorse
424             #
425             sub _new {
426 64     64   128 my ($class, $type, $file, $mode, $other) = @_;
427 64         95 my $self = [];
428 64         143 bless $self => $class;
429 64         96 $mode = lc($mode);
430 64         135 $self->[1] = $type; # keep for easier DESTROY
431 64         76 $self->[2] = $file; # must be given
432 64   50     153 $self->[3] = $mode || 'r'; # mode defaults to read-only
433 64         97 $self->[4] = $Autosync; # default to global
434              
435 64 50       118 croak "No filename specified"
436             if not defined $file;
437              
438 1     1   4 use vars qw($PersistentData);
  1         2  
  1         2347  
439             # used in 'do' to read data stored with Data::Dumper
440 64         63 local ($PersistentData);
441              
442 64 50       225 if ($mode =~ m/[ra+]/) {
443             # not write-only, we may have to read data back in...
444 64 100       739 if (not -f $file) {
445             # cannot read-only (or append) from non-existing file
446 6 50       28 croak "Cannot find file $file"
447             if (not $mode =~ m/[w+]/);
448             } else {
449             # file exists; check if we later can write it back
450 58 100       203 if ($mode =~ m/[w+a]/) {
451 14         478 my $fdir = dirname($file);
452 14 50       195 croak "Data file dir $fdir is not writeable"
453             if (not -w $fdir);
454 14 50 33     301 croak "Data file $file is not writeable"
455             if (-f $file and not -w $file);
456             }
457              
458             # now read; first try Storable...
459 58         80 eval { $PersistentData = retrieve($file) };
  58         163  
460 58 100       8880 if (not defined $PersistentData) {
461             # nope, now try Data::Dumper...
462 29 50       815 open FILE, $file
463             or croak "Cannot open file $file: $!";
464 29         264 my $firstline = ;
465 29         273 close FILE;
466             # check filetype
467 29 50       77 croak "File $file is not a PersistentData file"
468             if (substr($firstline, 0, 15) ne '$PersistentData');
469             # let the perl parser do the work for us
470 29         8161 do $file;
471             }
472 58 50       161 croak "Cannot load file $file: $@"
473             if $@;
474 58 50       136 confess "?? PersistentData is not a ref "
475             if not defined ref($PersistentData);
476             }
477             }
478              
479             # do we have to chain another var in?
480 64         67 my $objtype;
481             my $tied;
482 64 100       113 if (defined $other) {
483 2 50       6 if (ref $other) {
484 2 50       8 croak "Reference is not a $type"
485             if not ref($other) eq $type;
486 2         5 $self->[0] = $other;
487             } else {
488 0         0 $objtype = $other;
489             }
490             }
491              
492             # what type is the read data?
493 64         194 my $dataref;
494             my $datatype;
495 64 100       141 if (defined ($PersistentData)) {
496 58         81 $dataref = ref($PersistentData);
497 58         81 ($datatype) = grep {ISA($PersistentData, $_)} qw(HASH ARRAY REF SCALAR);
  232         554  
498 58 50 0     137 $objtype ||= $dataref
499             if $dataref ne $datatype;
500             }
501              
502             # now switch depending on type
503 64 100       173 if ($type eq 'HASH') {
    100          
    50          
504             # is a var chained in?
505 16 100       37 if ($self->[0]) {
506 2         4 $tied = tied %{$self->[0]};
  2         5  
507             } else {
508             # no, create one, retieing (sp?) it if necessary...
509 14         16 my %h;
510 14 50       30 $tied = tie %h, $objtype
511             if defined $objtype;
512 14         32 $self->[0] = \%h;
513             }
514             } elsif ($type eq 'ARRAY') {
515             # is a var chained in?
516 6 50       14 if ($self->[0]) {
517 0         0 $tied = tied @{$self->[0]};
  0         0  
518             } else {
519             # no, create one, retieing (sp?) it if necessary...
520 6         7 my @a;
521 6 50       13 $tied = tie @a, $objtype
522             if defined $objtype;
523 6         14 $self->[0] = \@a;
524             }
525             } elsif ($type eq 'SCALAR') {
526             # is a var chained in?
527 42 50       74 if ($self->[0]) {
528 0         0 $tied = tied ${$self->[0]};
  0         0  
529             } else {
530             # no, create one, retieing (sp?) it if necessary...
531 42         43 my $s;
532 42 50       82 $tied = tie $s, $objtype
533             if defined $objtype;
534 42         75 $self->[0] = \$s;
535             }
536             } else {
537 0         0 confess "Don't know how to handle a $type";
538             }
539              
540 64 100       128 if (defined ($PersistentData)) {
541             # we have to restore data
542 58         69 my $tiedref = ref($tied);
543 58         58 my $tiedtype;
544 58 50       88 ($tiedtype) = grep {ISA($tied, $_)} qw(HASH ARRAY REF SCALAR)
  0         0  
545             if defined $tied;
546              
547 58 50 33     296 croak "Persistent data is not of type $type"
      33        
548             if ($dataref eq $datatype and $datatype ne $type
549             and "$type$datatype" ne "SCALARREF");
550 58 50       616 if ($tied) {
551             # the chained var is tied, so we have to cleverly copy
552             # the underlying object back in; we don't have to make
553             # a real deep copy, the upper layer should be OK, as
554             # $PersistentHash was freshly created just for us...
555              
556 0 0       0 croak "Tied data type $tiedtype does not match persistent type $datatype"
557             if ($tiedtype ne $datatype);
558 0 0       0 croak "Cannot copy persistent object $dataref over tied object $tiedref"
559             if ($tiedref ne $dataref);
560              
561 0 0 0     0 if ($tiedtype eq 'HASH') {
    0          
    0          
562 0         0 %{$tied} = %$PersistentData;
  0         0  
563             } elsif ($tiedtype eq 'ARRAY') {
564 0         0 @{$tied} = @$PersistentData;
  0         0  
565             } elsif ($tiedtype eq 'SCALAR' or $tiedtype eq 'REF') {
566 0         0 ${$tied} = $$PersistentData;
  0         0  
567             } else {
568 0         0 confess "Don't know how to copy a $tiedtype object";
569             }
570             } else {
571              
572 58 50 33     121 croak "Cannot copy persistent data type $dataref into $type variable"
573             if ($dataref ne $type and "$type$dataref" ne "SCALARREF");
574              
575             # it's a regular var, so we copy the data the normal way...
576 58 100 33     210 if ($type eq 'HASH') {
    100          
    50          
577 14         56 %{$self->[0]} = %$PersistentData;
  14         107  
578             } elsif ($type eq 'ARRAY') {
579 4         6 @{$self->[0]} = @$PersistentData;
  4         21  
580             } elsif ($type eq 'SCALAR' or $type eq 'REF') {
581 40         40 ${$self->[0]} = $$PersistentData;
  40         81  
582             } else {
583 0         0 confess "Don't know how to copy a $type object";
584             }
585             }
586             }
587 64         359 return $self;
588             }
589              
590             #
591             # generic sync/destructor; write back data on destroy (or modify);
592             # gets imported to the subpackages.
593             #
594             sub sync {
595 68     68 0 822 my $self = shift;
596 68         94 my $type = $self->[1];
597 68         81 my $file = $self->[2];
598 68         84 my $mode = $self->[3];
599              
600             # only overwrite if mode says so
601 68 100       390 return if not ($mode =~ m/[aw+]/);
602              
603             # is this portable? couldn't find a suitable File::Tmpfile or something...
604 24         187 my $tmpfile = "$file." . time . ".$$.tmp";
605              
606             # switch over variable type
607 24         29 my $tied;
608 24 100       72 if ($type eq 'HASH') {
    100          
    50          
609 8         10 $tied = tied %{$self->[0]};
  8         17  
610             } elsif ($type eq 'ARRAY') {
611 2         3 $tied = tied @{$self->[0]};
  2         5  
612             } elsif ($type eq 'SCALAR') {
613 14         10 $tied = tied ${$self->[0]};
  14         31  
614             } else {
615 0         0 confess "Don't know how to handle $type";
616             }
617              
618 24 100 66     87 if ($Readable or not $Has_Storable) {
619             # Data::Dumper is more readable...
620 12 50       814 open DB, ">$tmpfile"
621             or warn ("Tie::Persistent::sync: ",
622             "cannot open $tmpfile for writing, DATA NOT STORED: $!\n"),
623             return;
624 12 50       27 if ($tied) {
625             # for tied vars, we must dump the underlying object...
626 0         0 print DB Data::Dumper->Dump([$tied], [qw(PersistentData)]);
627             } else {
628             # regular vars just dump data...
629 12         110 print DB Data::Dumper->Dump([$self->[0]], [qw(PersistentData)]);
630             }
631 12         1448 close DB;
632             } else {
633             # Storable is faster...
634 12 50       20 if ($tied) {
635             # for tied vars, we must dump the underlying object...
636 0         0 Storable::nstore($tied, $tmpfile);
637             } else {
638             # regular vars just dump data...
639 12         42 Storable::nstore($self->[0], $tmpfile);
640             }
641             }
642              
643             # create backup files
644 24 100       2588 if (-f $file) {
645 18         21 my $backup;
646 18 50       52 if ($mode =~ m/[a+]/) {
647             # create numbered backup files
648 0         0 $backup = _find_next_backup_file($file);
649             } else {
650             # unnumbered backup file
651 18         83 $backup = &$BackupFile($file);
652             }
653 18 50       39 if (defined $backup) {
654 18 50       1122 rename $file, $backup
655             or warn ("Tie::Persistent::sync: ",
656             "cannot backup $file as $backup: $!\n");
657             }
658             }
659              
660 24 50       1003 rename $tmpfile, $file
661             or warn ("Tie::Persistent::sync: ",
662             "cannot rename $tmpfile to $file: $!\n");
663             }
664              
665             *DESTROY = \&sync; # make an alias
666              
667             sub autosync {
668 4     4 0 21 my $val = $_[0]->[4];
669 4 50       13 $_[0]->[4] = $_[1] if @_ > 1;
670 4         9 return $val;
671             }
672              
673             #
674             # find number of next backup file
675             #
676             sub _find_next_backup_file($) {
677 0     0   0 my $f = shift;
678 0         0 my $basefile = basename($f);
679              
680 0         0 my $dir = dirname($f);
681 0 0       0 $dir = File::Spec->curdir() if not $dir;
682              
683 0 0       0 opendir (DIR, $dir)
684             or warn ("Tie::Persistent::_find_next_backup_file: ",
685             "cannot open dir $dir: $!\n"), return undef;
686              
687             # now create a RE matching the backupfile format...
688 0         0 my $nr = -1;
689 0         0 my $re = quotemeta(&$NumberedBackupFile($basefile, 299792));
690 0         0 $re =~ s/299792/(\\d+)/;
691              
692             # find the highest backup number...
693 0         0 foreach (readdir(DIR)) {
694 0 0       0 if (m/\A$re\Z/) {
695 0 0       0 $nr = $1 if $nr < $1;
696             }
697             }
698 0         0 closedir DIR;
699 0         0 $nr++;
700 0         0 return File::Spec->catfile($dir, &$NumberedBackupFile($basefile, $nr));
701             }
702              
703             #
704             # type-specific access functions below
705             #
706              
707             package Tie::Persistent::Hash;
708              
709 36 100   36   407 sub STORE { $_[0]->[0]{$_[1]} = $_[2]; $_[0]->sync() if $_[0]->[4]; }
  36         140  
710 188     188   1890 sub FETCH { $_[0]->[0]{$_[1]} }
711 0     0   0 sub FIRSTKEY { my $a = scalar keys %{$_[0]->[0]}; each %{$_[0]->[0]} }
  0         0  
  0         0  
  0         0  
712 0     0   0 sub NEXTKEY { each %{$_[0]->[0]} }
  0         0  
713 0     0   0 sub EXISTS { exists $_[0]->[0]->{$_[1]} }
714 0 0   0   0 sub DELETE { delete $_[0]->[0]->{$_[1]}; $_[0]->sync() if $_[0]->[4]; }
  0         0  
715 0 0   0   0 sub CLEAR { %{$_[0]->[0]} = (); $_[0]->sync() if $_[0]->[4]; }
  0         0  
  0         0  
716              
717             *sync = \&Tie::Persistent::sync; # import generic
718             *autosync = \&Tie::Persistent::autosync; # import generic
719             *DESTROY = \&Tie::Persistent::DESTROY; # import generic
720              
721              
722             package Tie::Persistent::Array;
723              
724 4     4   49 sub FETCHSIZE { scalar @{$_[0]->[0]} }
  4         18  
725             #is it necessary to sync on STORESIZE???
726 0     0   0 sub STORESIZE { $#{$_[0]->[0]} = $_[1]-1 }
  0         0  
727 54 50   54   185 sub STORE { $_[0]->[0][$_[1]] = $_[2]; $_[0]->sync() if $_[0]->[4]; }
  54         245  
728 104     104   295 sub FETCH { $_[0]->[0][$_[1]] }
729 2 50   2   21 sub CLEAR { @{$_[0]->[0]} = (); $_[0]->sync() if $_[0]->[4]; }
  2         10  
  2         15  
730 2     2   11 sub EXTEND { }
731              
732             sub POP {
733 0     0   0 my $elt = pop(@{$_[0]->[0]});
  0         0  
734 0 0       0 $_[0]->sync() if $_[0]->[4];
735 0         0 return $elt;
736             }
737              
738             sub PUSH {
739 0     0   0 my $this = shift;
740 0         0 my $len = push(@{$this->[0]}, @_);
  0         0  
741 0 0       0 $this->sync() if $this->[4];
742 0         0 return $len;
743             }
744              
745             sub SHIFT {
746 0     0   0 my $elt = shift(@{$_[0]->[0]});
  0         0  
747 0 0       0 $_[0]->sync() if $_[0]->[4];
748 0         0 return $elt;
749             }
750              
751             sub UNSHIFT {
752 0     0   0 my $this = shift;
753 0         0 my $len = unshift(@{$this->[0]}, @_);
  0         0  
754 0 0       0 $this->sync() if $this->[4];
755 0         0 return $len;
756             }
757              
758             sub SPLICE {
759 0     0   0 my $this = shift;
760 0         0 my $sz = @{$this->[0]};
  0         0  
761 0 0       0 my $off = @_ ? shift : 0;
762 0 0       0 $off += $sz if $off < 0;
763 0 0       0 my $len = @_ ? shift : $sz-$off;
764 0 0       0 if( defined wantarray ) {
765 0         0 my @discards = splice(@{$this->[0]}, $off, $len, @_);
  0         0  
766 0 0       0 $this->sync() if $this->[4];
767 0         0 return @discards;
768             } else {
769 0         0 my $last_discard = splice(@{$this->[0]}, $off, $len, @_);
  0         0  
770 0 0       0 $this->sync() if $this->[4];
771 0         0 return $last_discard;
772             }
773             }
774              
775             *sync = \&Tie::Persistent::sync; # import generic
776             *autosync = \&Tie::Persistent::autosync; # import generic
777             *DESTROY = \&Tie::Persistent::DESTROY; # import generic
778              
779              
780             package Tie::Persistent::Scalar;
781              
782 28 50   28   121 sub STORE { ${$_[0]->[0]} = $_[1]; $_[0]->sync() if $_[0]->[4]; }
  28         99  
  28         104  
783 28     28   112 sub FETCH { ${$_[0]->[0]}; }
  28         100  
784              
785             *sync = \&Tie::Persistent::sync; # import generic
786             *autosync = \&Tie::Persistent::autosync; # import generic
787             *DESTROY = \&Tie::Persistent::DESTROY; # import generic
788              
789             1;
790              
791             __END__