line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# Arch Perl library, Copyright (C) 2004 Mikhael Goikhman |
2
|
|
|
|
|
|
|
# |
3
|
|
|
|
|
|
|
# This program is free software; you can redistribute it and/or modify |
4
|
|
|
|
|
|
|
# it under the terms of the GNU General Public License as published by |
5
|
|
|
|
|
|
|
# the Free Software Foundation; either version 2 of the License, or |
6
|
|
|
|
|
|
|
# (at your option) any later version. |
7
|
|
|
|
|
|
|
# |
8
|
|
|
|
|
|
|
# This program is distributed in the hope that it will be useful, |
9
|
|
|
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
10
|
|
|
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11
|
|
|
|
|
|
|
# GNU General Public License for more details. |
12
|
|
|
|
|
|
|
# |
13
|
|
|
|
|
|
|
# You should have received a copy of the GNU General Public License |
14
|
|
|
|
|
|
|
# along with this program; if not, write to the Free Software |
15
|
|
|
|
|
|
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
16
|
|
|
|
|
|
|
|
17
|
31
|
|
|
31
|
|
794
|
use 5.005; |
|
31
|
|
|
|
|
109
|
|
|
31
|
|
|
|
|
1412
|
|
18
|
31
|
|
|
31
|
|
186
|
use strict; |
|
31
|
|
|
|
|
58
|
|
|
31
|
|
|
|
|
179514
|
|
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
package Arch::SharedIndex; |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
sub new ($%) { |
23
|
48
|
|
|
48
|
1
|
278
|
my $class = shift; |
24
|
48
|
|
|
|
|
1368
|
my %init = @_; |
25
|
|
|
|
|
|
|
|
26
|
48
|
50
|
|
|
|
366
|
my $file = $init{file} or die "No index file given\n"; |
27
|
48
|
50
|
|
|
|
308
|
my $can_create = exists $init{can_create}? $init{can_create}: 1; |
28
|
48
|
50
|
|
|
|
330
|
my $time_renewal = exists $init{time_renewal}? $init{time_renewal}: |
|
|
50
|
|
|
|
|
|
29
|
|
|
|
|
|
|
$init{max_size}? 1: 0; |
30
|
|
|
|
|
|
|
|
31
|
48
|
|
50
|
|
|
2364
|
my $self = { |
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
32
|
|
|
|
|
|
|
file => $file, |
33
|
|
|
|
|
|
|
can_create => $can_create, |
34
|
|
|
|
|
|
|
max_size => int($init{max_size} || 0), |
35
|
|
|
|
|
|
|
expiration => int($init{expiration} || 0), |
36
|
|
|
|
|
|
|
time_renewal => $time_renewal, |
37
|
|
|
|
|
|
|
perl_data => $init{perl_data} || 0, |
38
|
|
|
|
|
|
|
perl_data_indent => $init{perl_data_indent} || 0, |
39
|
|
|
|
|
|
|
perl_data_pair => $init{perl_data_pair} || "=>", |
40
|
|
|
|
|
|
|
}; |
41
|
|
|
|
|
|
|
|
42
|
48
|
|
|
|
|
374
|
bless $self, $class; |
43
|
48
|
|
|
|
|
490
|
return $self; |
44
|
|
|
|
|
|
|
} |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
sub encode_value ($$) { |
47
|
4264
|
|
|
4264
|
1
|
4778
|
my $self = shift; |
48
|
4264
|
100
|
|
|
|
12128
|
return unless $self->{perl_data}; |
49
|
2193
|
|
|
|
|
2415
|
my $value = shift; |
50
|
|
|
|
|
|
|
# Data::Dumper is one of the silly-API modules; configure every time. |
51
|
|
|
|
|
|
|
# Object oriented API is a bit slower and less backward compatible. |
52
|
|
|
|
|
|
|
# Avoid unused variable warnings by separate declaration/assignment. |
53
|
2193
|
|
|
|
|
42771
|
require Data::Dumper; |
54
|
2193
|
|
|
|
|
211546
|
local $Data::Dumper::Indent; |
55
|
2193
|
|
|
|
|
2350
|
local $Data::Dumper::Pair; |
56
|
2193
|
|
|
|
|
2414
|
local $Data::Dumper::Quotekeys; |
57
|
2193
|
|
|
|
|
2021
|
local $Data::Dumper::Terse; |
58
|
2193
|
|
|
|
|
3469
|
$Data::Dumper::Indent = $self->{perl_data_indent}; |
59
|
2193
|
|
|
|
|
3932
|
$Data::Dumper::Pair = $self->{perl_data_pair}; |
60
|
2193
|
|
|
|
|
3011
|
$Data::Dumper::Quotekeys = 0; |
61
|
2193
|
|
|
|
|
2542
|
$Data::Dumper::Terse = 1; |
62
|
2193
|
|
|
|
|
8953
|
$$value = Data::Dumper->Dump([$$value]); |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
sub decode_value ($$) { |
66
|
3422
|
|
|
3422
|
1
|
6040
|
my $self = shift; |
67
|
3422
|
100
|
|
|
|
10542
|
return unless $self->{perl_data}; |
68
|
2598
|
|
|
|
|
3424
|
my $value = shift; |
69
|
2598
|
|
|
|
|
221828
|
$$value = eval $$value; |
70
|
|
|
|
|
|
|
} |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
sub delete_value ($$$) { |
73
|
116
|
|
|
116
|
1
|
142
|
my $self = shift; |
74
|
116
|
|
|
|
|
214
|
my ($key, $token) = @_; |
75
|
|
|
|
|
|
|
# super class implementation |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
sub fetch_value ($$$) { |
79
|
1252
|
|
|
1252
|
1
|
2351
|
my $self = shift; |
80
|
1252
|
|
|
|
|
5736
|
my ($key, $token) = @_; |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
# super class implementation |
83
|
1252
|
|
|
|
|
7822
|
my $value = $token; |
84
|
1252
|
|
|
|
|
3594
|
$self->decode_value(\$value); |
85
|
1252
|
|
|
|
|
10460
|
return $value; |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
sub store_value ($$$) { |
89
|
2137
|
|
|
2137
|
1
|
2651
|
my $self = shift; |
90
|
2137
|
|
|
|
|
3267
|
my ($key, $token, $value) = @_; |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
# super class implementation |
93
|
2137
|
|
|
|
|
4237
|
$self->encode_value(\$value); |
94
|
2137
|
|
|
|
|
82085
|
$token = $value; |
95
|
2137
|
|
|
|
|
4226
|
return $token; |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
sub index_list_to_hash ($$) { |
99
|
86
|
|
|
86
|
0
|
236
|
my $self = shift; |
100
|
86
|
|
|
|
|
166
|
my $index_list = shift; |
101
|
|
|
|
|
|
|
|
102
|
86
|
|
|
|
|
222
|
my $index_hash = {}; |
103
|
86
|
|
|
|
|
413
|
foreach my $entry (@$index_list) { |
104
|
3622
|
|
|
|
|
51485
|
$index_hash->{$entry->[0]} = $entry; |
105
|
|
|
|
|
|
|
} |
106
|
86
|
|
|
|
|
283
|
return $index_hash; |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
sub _do_delete ($$$) { |
110
|
8
|
|
|
8
|
|
35
|
my $self = shift; |
111
|
8
|
|
|
|
|
27
|
my $index_list = shift; |
112
|
8
|
|
|
|
|
26
|
my $keys = shift; |
113
|
|
|
|
|
|
|
|
114
|
8
|
|
|
|
|
60
|
my %keys = map { $_ => 1 } @$keys; |
|
242
|
|
|
|
|
782
|
|
115
|
8
|
|
100
|
|
|
316
|
for (my $num = @$index_list - 1; %keys && $num >= 0; $num--) { |
116
|
591
|
|
|
|
|
795
|
my $index_entry = $index_list->[$num]; |
117
|
591
|
|
|
|
|
860
|
my ($key, $token) = @$index_entry; |
118
|
591
|
100
|
|
|
|
2906
|
next unless $keys{$key}; |
119
|
232
|
|
|
|
|
652
|
$self->delete_value($key, $token); |
120
|
232
|
|
|
|
|
382
|
splice(@$index_list, $num, 1); |
121
|
232
|
|
|
|
|
1685
|
delete $keys{$key}; |
122
|
|
|
|
|
|
|
} |
123
|
8
|
|
|
|
|
68
|
return @$keys - keys %keys; |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
sub _do_fetch ($$$) { |
127
|
24
|
|
|
24
|
|
112
|
my $self = shift; |
128
|
24
|
|
|
|
|
49
|
my $index_list = shift; |
129
|
24
|
|
|
|
|
37
|
my $keys = shift; |
130
|
24
|
|
|
|
|
115
|
my @values = (); |
131
|
24
|
|
|
|
|
241
|
my $index_hash = $self->index_list_to_hash($index_list); |
132
|
|
|
|
|
|
|
|
133
|
24
|
|
|
|
|
49
|
my $time; |
134
|
24
|
|
|
|
|
68
|
foreach my $key (@$keys) { |
135
|
2144
|
|
|
|
|
4032
|
my $index_entry = $index_hash->{$key}; |
136
|
2144
|
100
|
|
|
|
5582
|
my $value = $index_entry? |
137
|
|
|
|
|
|
|
$self->fetch_value(@$index_entry): undef; |
138
|
2144
|
100
|
66
|
|
|
7978
|
if (defined $value && $self->{time_renewal}) { |
139
|
1154
|
|
66
|
|
|
4902
|
$time ||= time(); |
140
|
1154
|
|
|
|
|
1900
|
$index_entry->[2] = $time; |
141
|
|
|
|
|
|
|
} |
142
|
2144
|
|
|
|
|
4056
|
push @values, $value; |
143
|
|
|
|
|
|
|
} |
144
|
24
|
|
|
|
|
591
|
return \@values; |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
sub _do_store ($$$) { |
148
|
62
|
|
|
62
|
|
125
|
my $self = shift; |
149
|
62
|
|
|
|
|
105
|
my $index_list = shift; |
150
|
62
|
|
|
|
|
96
|
my @new_key_values = @{shift()}; |
|
62
|
|
|
|
|
1101
|
|
151
|
62
|
|
|
|
|
150
|
my $entries_stored = 0; |
152
|
62
|
|
|
|
|
429
|
my $index_hash = $self->index_list_to_hash($index_list); |
153
|
|
|
|
|
|
|
|
154
|
62
|
|
|
|
|
431
|
my $time = time; |
155
|
62
|
|
|
|
|
177
|
my %seen = (); |
156
|
62
|
|
|
|
|
486
|
while (my ($key, $value) = splice(@new_key_values, 0, 2)) { |
157
|
4264
|
50
|
|
|
|
9531
|
next if $seen{$key}; $seen{$key} = 1; |
|
4264
|
|
|
|
|
8431
|
|
158
|
4264
|
|
|
|
|
6102
|
my $old_entry = $index_hash->{$key}; |
159
|
4264
|
100
|
|
|
|
8335
|
my $old_token = $old_entry? $old_entry->[1]: undef; |
160
|
4264
|
|
|
|
|
11948
|
my $new_token = $self->store_value($key, $old_token, $value); |
161
|
4264
|
50
|
|
|
|
9616
|
next unless defined $new_token; |
162
|
|
|
|
|
|
|
|
163
|
4264
|
|
|
|
|
11588
|
my $new_entry = [ $key, $new_token, $time ]; |
164
|
4264
|
100
|
|
|
|
7838
|
if (defined $old_entry) { |
165
|
1294
|
|
|
|
|
4936
|
@$old_entry = @$new_entry; |
166
|
|
|
|
|
|
|
} else { |
167
|
2970
|
|
|
|
|
5155
|
push @$index_list, $new_entry; |
168
|
|
|
|
|
|
|
} |
169
|
4264
|
|
|
|
|
16433
|
$entries_stored++; |
170
|
|
|
|
|
|
|
} |
171
|
62
|
|
|
|
|
2027
|
return $entries_stored; |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
sub delete ($@) { |
175
|
4
|
|
|
4
|
1
|
51
|
my $self = shift; |
176
|
4
|
50
|
|
|
|
239
|
my $keys = ref($_[0]) eq 'ARRAY'? shift: [ @_ ]; |
177
|
4
|
|
|
|
|
133
|
my $entries_deleted; |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
$self->query_index_list(sub ($) { |
180
|
4
|
|
|
4
|
|
30
|
my $index_list = shift; |
181
|
4
|
|
|
|
|
425
|
$entries_deleted = $self->_do_delete($index_list, $keys); |
182
|
4
|
|
|
|
|
805
|
}); |
183
|
4
|
|
|
|
|
52
|
return $entries_deleted; |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
sub fetch ($@) { |
187
|
4
|
|
|
4
|
1
|
12
|
my $self = shift; |
188
|
4
|
|
|
|
|
14
|
my $single_ref = ref($_[0]) eq 'ARRAY'; |
189
|
4
|
50
|
|
|
|
57
|
my $keys = $single_ref? shift: [ @_ ]; |
190
|
4
|
|
|
|
|
10
|
my $values = []; |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
$self->query_index_list(sub ($) { |
193
|
4
|
|
|
4
|
|
14
|
my $index_list = shift; |
194
|
4
|
|
|
|
|
32
|
$values = $self->_do_fetch($index_list, $keys); |
195
|
4
|
|
|
|
|
85
|
}); |
196
|
4
|
50
|
|
|
|
219
|
return $single_ref? $values: wantarray? @$values: $values->[0]; |
|
|
50
|
|
|
|
|
|
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
sub store ($%) { |
200
|
30
|
|
|
30
|
1
|
80
|
my $self = shift; |
201
|
0
|
|
|
|
|
0
|
my $new_key_values = |
202
|
30
|
50
|
|
|
|
760
|
ref($_[0]) eq 'HASH'? [ %{shift()} ]: # unordered |
|
|
50
|
|
|
|
|
|
203
|
|
|
|
|
|
|
ref($_[0]) eq 'ARRAY'? shift: [ @_ ]; # ordered |
204
|
30
|
|
|
|
|
60
|
my $entries_stored; |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
$self->query_index_list(sub ($) { |
207
|
30
|
|
|
30
|
|
165
|
my $index_list = shift; |
208
|
30
|
|
|
|
|
155
|
$entries_stored = $self->_do_store($index_list, $new_key_values); |
209
|
30
|
|
|
|
|
265
|
}); |
210
|
30
|
|
|
|
|
490
|
return $entries_stored; |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
sub fetch_store ($$@) { |
214
|
20
|
|
|
20
|
1
|
60
|
my $self = shift; |
215
|
20
|
|
50
|
|
|
160
|
my $code = shift || die "No code given"; |
216
|
20
|
|
|
|
|
60
|
my $single_ref = ref($_[0]) eq 'ARRAY'; |
217
|
20
|
50
|
|
|
|
160
|
my $keys = $single_ref? shift: [ @_ ]; |
218
|
20
|
|
|
|
|
40
|
my $values; |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
$self->query_index_list(sub ($) { |
221
|
20
|
|
|
20
|
|
50
|
my $index_list = shift; |
222
|
20
|
|
|
|
|
130
|
$values = $self->_do_fetch($index_list, $keys); |
223
|
20
|
|
|
|
|
40
|
my (@new_keys, @missing_idxs); |
224
|
20
|
|
|
|
|
40
|
my $run_idx = 0; |
225
|
20
|
100
|
|
|
|
90
|
@new_keys = grep { (defined $values->[$run_idx]? 0: |
|
1980
|
|
|
|
|
3950
|
|
226
|
|
|
|
|
|
|
push @missing_idxs, $run_idx) * ++$run_idx } @$keys; |
227
|
|
|
|
|
|
|
|
228
|
20
|
50
|
33
|
|
|
190
|
if ($ENV{DEBUG} && ("$ENV{DEBUG}" & "\2") ne "\0") { |
229
|
0
|
0
|
|
|
|
0
|
my $status = @new_keys? @new_keys == @$keys? "miss": |
|
|
0
|
|
|
|
|
|
230
|
|
|
|
|
|
|
"partial hit-miss": "hit"; |
231
|
0
|
|
|
|
|
0
|
my $keystr = join(', ', @$keys); |
232
|
0
|
0
|
|
|
|
0
|
substr($keystr, 57) = "..." if length($keystr) > 60; |
233
|
0
|
|
|
|
|
0
|
print STDERR "Shared fetch_store ($keystr): $status\n"; |
234
|
|
|
|
|
|
|
} |
235
|
20
|
100
|
|
|
|
80
|
return unless @new_keys; |
236
|
|
|
|
|
|
|
|
237
|
10
|
50
|
|
|
|
30
|
my @new_key_values = map { $_ => ref($code) ne 'CODE'? |
|
990
|
|
|
|
|
2520
|
|
238
|
|
|
|
|
|
|
$code: &$code($_) } @new_keys; |
239
|
10
|
|
|
|
|
170
|
my $num_stored = $self->_do_store($index_list, \@new_key_values); |
240
|
10
|
50
|
|
|
|
60
|
warn "fetch_store: not all new values are actually stored\n" |
241
|
|
|
|
|
|
|
if $num_stored < @new_keys; |
242
|
990
|
|
|
|
|
1660
|
@$values[@missing_idxs] = |
243
|
10
|
|
|
|
|
100
|
@new_key_values[map { $_ * 2 + 1 } 0 .. @new_keys - 1]; |
244
|
20
|
|
|
|
|
220
|
}); |
245
|
20
|
50
|
|
|
|
1200
|
return $single_ref? $values: wantarray? @$values: $values->[0]; |
|
|
50
|
|
|
|
|
|
246
|
|
|
|
|
|
|
} |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
sub keys ($) { |
249
|
4
|
|
|
4
|
1
|
17
|
my $self = shift; |
250
|
4
|
|
|
|
|
16
|
my @keys; |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
$self->query_index_list(sub ($) { |
253
|
4
|
|
|
4
|
|
14
|
my $index_list = shift; |
254
|
4
|
|
|
|
|
24
|
@keys = map { $_->[0] } @$index_list; |
|
164
|
|
|
|
|
777
|
|
255
|
4
|
|
|
|
|
89
|
}); |
256
|
4
|
50
|
|
|
|
181
|
return wantarray? @keys: \@keys; |
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
sub values ($) { |
260
|
4
|
|
|
4
|
1
|
13
|
my $self = shift; |
261
|
4
|
|
|
|
|
16
|
my @values; |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
$self->query_index_list(sub ($) { |
264
|
4
|
|
|
4
|
|
12
|
my $index_list = shift; |
265
|
4
|
|
|
|
|
13
|
@values = map { $self->fetch_value(@$_) } @$index_list; |
|
164
|
|
|
|
|
682
|
|
266
|
4
|
|
|
|
|
54
|
}); |
267
|
4
|
50
|
|
|
|
94
|
return wantarray? @values: \@values; |
268
|
|
|
|
|
|
|
} |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
sub hash ($) { |
271
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
272
|
0
|
|
|
|
|
0
|
my %hash; |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
$self->query_index_list(sub ($) { |
275
|
0
|
|
|
0
|
|
0
|
my $index_list = shift; |
276
|
0
|
|
|
|
|
0
|
%hash = map { $_->[0] => $self->fetch_value(@$_) } @$index_list; |
|
0
|
|
|
|
|
0
|
|
277
|
0
|
|
|
|
|
0
|
}); |
278
|
0
|
0
|
|
|
|
0
|
return wantarray? %hash: \%hash; |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
sub list ($) { |
282
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
283
|
0
|
|
|
|
|
0
|
my @list; |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
$self->query_index_list(sub ($) { |
286
|
0
|
|
|
0
|
|
0
|
my $index_list = shift; |
287
|
0
|
|
|
|
|
0
|
@list = map { [ $_->[0] => $self->fetch_value(@$_) ] } |
|
0
|
|
|
|
|
0
|
|
288
|
|
|
|
|
|
|
@$index_list; |
289
|
0
|
|
|
|
|
0
|
}); |
290
|
0
|
0
|
|
|
|
0
|
return wantarray? @list: \@list; |
291
|
|
|
|
|
|
|
} |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
sub grep ($;$) { |
294
|
4
|
|
|
4
|
1
|
13
|
my $self = shift; |
295
|
4
|
|
100
|
82
|
|
41
|
my $code = shift || sub { $_[1] }; |
|
82
|
|
|
|
|
187
|
|
296
|
4
|
|
|
|
|
244
|
my @keys; |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
$self->query_index_list(sub ($) { |
299
|
4
|
|
|
4
|
|
9
|
my $index_list = shift; |
300
|
100
|
|
|
|
|
262
|
@keys = map { $_->[0] } |
|
164
|
|
|
|
|
588
|
|
301
|
4
|
|
|
|
|
15
|
grep { &$code($_->[0], $self->fetch_value(@$_)) } |
302
|
|
|
|
|
|
|
@$index_list; |
303
|
4
|
|
|
|
|
51
|
}); |
304
|
4
|
50
|
|
|
|
226
|
return wantarray? @keys: \@keys; |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
sub filter ($;$) { |
308
|
4
|
|
|
4
|
1
|
34
|
my $self = shift; |
309
|
4
|
|
50
|
0
|
|
38
|
my $code = shift || sub { $_[1] }; |
|
0
|
|
|
|
|
0
|
|
310
|
4
|
|
|
|
|
8
|
my @keys; |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
$self->query_index_list(sub ($) { |
313
|
4
|
|
|
4
|
|
498
|
my $index_list = shift; |
314
|
46
|
|
|
|
|
268
|
@keys = map { $_->[0] } |
|
249
|
|
|
|
|
834
|
|
315
|
4
|
|
|
|
|
20
|
grep { &$code($_->[0], $self->fetch_value(@$_)) } |
316
|
|
|
|
|
|
|
@$index_list; |
317
|
4
|
|
|
|
|
127
|
$self->_do_delete($index_list, \@keys); |
318
|
4
|
|
|
|
|
543
|
}); |
319
|
4
|
50
|
|
|
|
145
|
return wantarray? @keys: \@keys; |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
sub update ($$;$) { |
323
|
22
|
|
|
22
|
1
|
124
|
my $self = shift; |
324
|
22
|
|
|
|
|
72
|
my $code = shift; |
325
|
22
|
|
|
|
|
110
|
my $grep_code = shift; |
326
|
22
|
50
|
|
|
|
221
|
die "No code or value given" unless defined $code; |
327
|
22
|
|
|
|
|
111
|
my $entries_updated; |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
$self->query_index_list(sub ($) { |
330
|
22
|
|
|
22
|
|
88
|
my $index_list = shift; |
331
|
304
|
100
|
|
|
|
1616
|
$entries_updated = $self->_do_store($index_list, [ |
332
|
1478
|
50
|
|
|
|
15180
|
map { $_->[0] => ref($code) ne 'CODE'? $code: |
333
|
|
|
|
|
|
|
&$code($_->[0], $self->fetch_value(@$_)) } |
334
|
22
|
|
|
|
|
195
|
grep { $grep_code? &$grep_code( |
335
|
|
|
|
|
|
|
$_->[0], $self->fetch_value(@$_)): 1 } |
336
|
|
|
|
|
|
|
@$index_list |
337
|
|
|
|
|
|
|
]); |
338
|
22
|
|
|
|
|
2030
|
}); |
339
|
22
|
|
|
|
|
509
|
return $entries_updated; |
340
|
|
|
|
|
|
|
} |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
sub query_index_list ($$) { |
343
|
96
|
|
|
96
|
0
|
372
|
my $self = shift; |
344
|
96
|
|
|
|
|
188
|
my $code = shift; |
345
|
|
|
|
|
|
|
|
346
|
96
|
|
|
|
|
584
|
my $file = $self->{file}; |
347
|
96
|
100
|
66
|
|
|
7243
|
if (!-f $file && $self->{can_create}) { |
348
|
30
|
50
|
|
|
|
3765
|
open FH, ">$file" or die "Can't create index file ($file)\n"; |
349
|
30
|
|
|
|
|
455
|
close FH; |
350
|
|
|
|
|
|
|
} |
351
|
96
|
50
|
|
|
|
2466
|
-f $file or die "No index file ($file)\n"; |
352
|
|
|
|
|
|
|
|
353
|
96
|
50
|
|
|
|
6746
|
open FH, "+<$file" or die "Can't open $file for updating: $!\n"; |
354
|
96
|
|
|
|
|
3429441
|
flock FH, 2; # wait for exclusive lock |
355
|
96
|
|
|
|
|
937
|
seek FH, 0, 0; # rewind to beginning |
356
|
96
|
|
|
|
|
19561
|
my @content = ; # get current content |
357
|
96
|
|
|
|
|
721
|
chomp @content; |
358
|
|
|
|
|
|
|
|
359
|
9480
|
50
|
|
|
|
15226
|
my $index_list = [ grep { defined } map { |
|
4740
|
|
|
|
|
39577
|
|
360
|
96
|
|
|
|
|
325
|
/^(\d+)\t(.+?)\t(.*)/? [ $2, $3, $1 ]: |
361
|
|
|
|
|
|
|
warn("Corrupt line ($_) in $file; ignored\n"), undef |
362
|
|
|
|
|
|
|
} @content ]; |
363
|
|
|
|
|
|
|
|
364
|
96
|
50
|
|
|
|
804
|
if ($self->{expiration}) { |
365
|
0
|
|
|
|
|
0
|
my $time = time(); |
366
|
0
|
|
|
|
|
0
|
my $diff = $self->{expiration}; |
367
|
0
|
|
|
|
|
0
|
my @expired_keys = map { $_->[0] } |
|
0
|
|
|
|
|
0
|
|
368
|
0
|
|
|
|
|
0
|
grep { $time - $_->[2] > $diff } @$index_list; |
369
|
0
|
0
|
|
|
|
0
|
$self->_do_delete($index_list, \@expired_keys) if @expired_keys; |
370
|
|
|
|
|
|
|
} |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
# apply callback filter |
373
|
96
|
|
|
|
|
627
|
&$code($index_list); |
374
|
|
|
|
|
|
|
|
375
|
96
|
50
|
33
|
|
|
1917
|
if ($self->{max_size} && @$index_list > $self->{max_size}) { |
376
|
0
|
|
|
|
|
0
|
my @excess_nums = (0 .. @$index_list - $self->{max_size} - 1); |
377
|
0
|
|
|
|
|
0
|
my @excess_keys = map { $_->[0] } (@$index_list)[@excess_nums]; |
|
0
|
|
|
|
|
0
|
|
378
|
0
|
|
|
|
|
0
|
$self->_do_delete($index_list, \@excess_keys); |
379
|
|
|
|
|
|
|
} |
380
|
|
|
|
|
|
|
|
381
|
96
|
|
|
|
|
713
|
my @new_content = map { "$_->[2]\t$_->[0]\t$_->[1]" } @$index_list; |
|
7478
|
|
|
|
|
95279
|
|
382
|
96
|
|
|
|
|
2256
|
my $is_changed = join('', @content) ne join('', @new_content); |
383
|
|
|
|
|
|
|
|
384
|
96
|
100
|
|
|
|
327
|
if ($is_changed) { |
385
|
58
|
|
|
|
|
617
|
seek FH, 0, 0; # rewind again |
386
|
58
|
|
|
|
|
4975
|
truncate FH, 0; # empty the file |
387
|
58
|
|
|
|
|
217
|
print FH map { "$_$/" } @new_content; |
|
4782
|
|
|
|
|
14527
|
|
388
|
|
|
|
|
|
|
} |
389
|
96
|
|
|
|
|
87627
|
close FH; # release file |
390
|
|
|
|
|
|
|
} |
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
1; |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
__END__ |