File Coverage

blib/lib/MLDBM/Sync/SDBM_File.pm
Criterion Covered Total %
statement 83 88 94.3
branch 24 34 70.5
condition 6 9 66.6
subroutine 11 11 100.0
pod n/a
total 124 142 87.3


line stmt bran cond sub pod time code
1              
2             package MLDBM::Sync::SDBM_File;
3             $VERSION = .17;
4              
5 7     7   6902 use SDBM_File;
  7         6135  
  7         347  
6 7     7   54 use strict;
  7         10  
  7         233  
7 7     7   35 use vars qw(@ISA $MaxSegments $MaxSegmentLength %KEYS $Zlib $VERSION);
  7         87  
  7         18445  
8              
9             @ISA = qw(SDBM_File);
10             $MaxSegments = 8192; # to a 1M limit
11             # leave room for key index pad
12             $MaxSegmentLength = 128;
13 7     7   9925 eval "use Compress::Zlib";
  7         719104  
  7         2164  
14             $Zlib = $@ ? 0 : 1;
15              
16             sub FETCH {
17 23     23   105 my($self, $key) = @_;
18 23         25 my $segment_length = $MaxSegmentLength;
19              
20 23         22 my $total_rv;
21 23         55 for(my $index = 0; $index < $MaxSegments; $index++) {
22 29         47 my $rv = $self->SUPER::FETCH(_index_key($key, $index));
23 29 100       220 if(defined $rv) {
24 28   100     81 $total_rv ||= '';
25 28         202 $total_rv .= $rv;
26 28 100       74 last if length($rv) < $segment_length;
27             } else {
28 1         2 last;
29             }
30             }
31              
32 23 100       39 if(defined $total_rv) {
33 22         78 $total_rv =~ s/^(..)//s;
34 22         44 my $type = $1;
35 22 50       35 if($type eq 'G}') {
    0          
36 22         221 $total_rv = uncompress($total_rv);
37             } elsif ($type eq 'N}') {
38             # nothing
39             } else {
40             # old SDBM_File ?
41 0         0 $total_rv = $type . $total_rv;
42             }
43             }
44              
45 23         1624 $total_rv;
46             }
47              
48             sub STORE {
49 13     13   200 my($self, $key, $value) = @_;
50 13         21 my $segment_length = $MaxSegmentLength;
51              
52             # DELETE KEYS FIRST
53 13         69 for(my $index = 0; $index < $MaxSegments; $index++) {
54 19         44 my $index_key = _index_key($key, $index);
55 19         206 my $rv = $self->SUPER::FETCH($index_key);
56 19 100       49 if(defined $rv) {
57 7         74 $self->SUPER::DELETE($index_key);
58             } else {
59 12         18 last;
60             }
61 7 100       20 last if length($rv) < $segment_length;
62             }
63              
64             # G - Gzip compression
65             # N - No compression
66             #
67 13         15 my $old_value = $value;
68 13 50 33     105 $value = ($Zlib && (length($value) >= $segment_length/2)) ? "G}".compress($value) : "N}".$value;
69              
70 13         3903 my($total_rv, $last_index);
71 13         40 for(my $index = 0; $index < $MaxSegments; $index++) {
72 38 50       66 if($index == $MaxSegments) {
73 0         0 die("can't store more than $MaxSegments segments of $MaxSegmentLength bytes per key in ".__PACKAGE__);
74             }
75 38         148 $value =~ s/^(.{0,$segment_length})//so;
76 38         82 my $segment = $1;
77            
78 38 100       77 last if length($segment) == 0;
79             # print "STORING "._index_key($key, $index)." $segment\n";
80 25         51 my $rv = $self->SUPER::STORE(_index_key($key, $index), $segment);
81 25         44 $total_rv .= $segment;
82 25         60 $last_index = $index;
83             }
84              
85             # use Time::HiRes;
86             # print "[".&Time::HiRes::time()."] STORED ".($last_index+1)." segments for length ".
87             # length($total_rv)." bytes for value ".length($old_value)."\n";
88              
89 13         53 $old_value;
90             }
91              
92             sub DELETE {
93 12     12   50 my($self, $key) = @_;
94 12         15 my $segment_length = $MaxSegmentLength;
95              
96 12         12 my $total_rv;
97 12         28 for(my $index = 0; $index < $MaxSegments; $index++) {
98 18         29 my $index_key = _index_key($key, $index);
99 18   50     170 my $rv = $self->SUPER::FETCH($index_key) || '';
100 18         215 $self->SUPER::DELETE($index_key);
101 18   100     51 $total_rv ||= '';
102 18         26 $total_rv .= $rv;
103 18 100       46 last if length($rv) < $segment_length;
104             }
105              
106 12         45 $total_rv =~ s/^(..)//s;
107 12         24 my $type = $1;
108 12 50       23 if($type eq 'G}') {
    0          
109 12         29 $total_rv = uncompress($total_rv);
110             } elsif ($type eq 'N}') {
111             # normal
112             } else {
113             # old SDBM_File
114 0         0 $total_rv = $type.$total_rv;
115             }
116              
117 12         515 $total_rv;
118             }
119              
120             sub FIRSTKEY {
121 5     5   41 my $self = shift;
122              
123 5         60 my $key = $self->SUPER::FIRSTKEY();
124 5         10 my @keys = ();
125 5 100       12 if (defined $key) {
126 3         4 do {
127 30 50       49 if($key !~ /\*\*\d+$/s) {
128 30 50       43 if(my $new_key = _decode_key($key)) {
129 30         149 push(@keys, $new_key);
130             }
131             }
132             } while($key = $self->SUPER::NEXTKEY($key));
133             }
134 5         19 $KEYS{$self} = \@keys;
135              
136 5         11 $self->NEXTKEY;
137             }
138              
139             sub NEXTKEY {
140 35     35   101 my $self = shift;
141 35         28 shift(@{$KEYS{$self}});
  35         114  
142             }
143              
144             sub _index_key {
145 91     91   151 my($key, $index) = @_;
146 91         137 $key =~ s/([\%\*])/uc sprintf("%%%02x",ord($1))/esg;
  0         0  
147 91 100       1198 $index ? $key.'**'.$index : $key;
148             }
149              
150             sub _decode_key {
151 30     30   28 my $key = shift;
152 30         24 $key =~ s/%([0-9a-fA-F]{2})/pack("c",hex($1))/ge;
  0         0  
153 30         66 $key;
154             }
155              
156             1;
157