/[webpac2]/trunk/lib/WebPAC/Store.pm
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/lib/WebPAC/Store.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 764 - (show annotations)
Wed Oct 25 20:53:48 2006 UTC (17 years, 6 months ago) by dpavlin
File size: 9059 byte(s)
report time needed to store lookup to disk

1 package WebPAC::Store;
2
3 use warnings;
4 use strict;
5
6 use base 'WebPAC::Common';
7 use Storable;
8 use File::Path;
9 use Data::Dump qw/dump/;
10
11 =head1 NAME
12
13 WebPAC::Store - Store WebPAC data on disk
14
15 =head1 VERSION
16
17 Version 0.14
18
19 =cut
20
21 our $VERSION = '0.14';
22
23 =head1 SYNOPSIS
24
25 This module provides disk storage for normalised data and lookups.
26
27 It is one of newer components of WebPAC, so it will change from time to
28 time.
29
30 I will try to keep backward compatiblity by providing multiple back-ends,
31 but this can't be garanteed. In other words, don't delete your input
32 databases just yet :-)
33
34 This has additional advantage. I can create single place to plugin other
35 file formats which provide better performance for particular type of data.
36
37 For now, this is a prototype version.
38
39 use WebPAC::Store;
40
41 my $store = WebPAC::Store->new();
42 ...
43
44 =head1 FUNCTIONS
45
46 =head2 new
47
48 Create new normalised database object
49
50 my $store = new WebPAC::Store(
51 path => '/path/to/cache/ds/',
52 database => 'name',
53 read_only => 1,
54 );
55
56 Optional parameter C<path> defines path to directory
57 in which cache file for C<data_structure> call will be created.
58
59 If called with C<read_only> it will not disable caching if
60 called without write permission (but will die on C<save_ds>).
61
62 Optional parametar C<database> will be used used as subdirectory in path if no
63 database in specified when calling other functions.
64
65 =cut
66
67 sub new {
68 my $class = shift;
69 my $self = {@_};
70 bless($self, $class);
71
72 my $log = $self->_get_logger();
73
74 foreach my $p (qw/path/) {
75 $log->logconfess("need $p") unless ($self->{$p});
76 }
77
78 $self->path( $self->{'path'} );
79
80 $self ? return $self : return undef;
81 }
82
83 =head2 path
84
85 Check if specified cache directory exist, and if not, disable caching.
86
87 $store->path('./cache/');
88
89 If you pass false or zero value to this function, it will disable
90 cacheing.
91
92 You can also call this function to get current cache path.
93
94 my $cache_path = $store->path;
95
96 =cut
97
98 sub path {
99 my $self = shift;
100
101 my $dir = shift;
102
103 return $self->{path} unless defined($dir);
104
105 my $log = $self->_get_logger();
106
107 if ($dir) {
108 my $msg;
109 if (! -e $dir) {
110 if ($self->{'read_only'}) {
111 $msg = "doesn't exist";
112 } else {
113 $log->info("creating $dir");
114 mkpath $dir;
115 }
116 } elsif (! -d $dir) {
117 $msg = "is not directory";
118 } elsif (! -w $dir) {
119 $msg = "not writable" unless ($self->{'read_only'});
120 }
121
122 if ($msg) {
123 $log->warn("cache path $dir $msg, disabling...");
124 undef $self->{'path'};
125 } else {
126 $log->debug("using cache dir $dir");
127 $self->{'path'} = $dir;
128 }
129 } else {
130 $log->debug("disabling cache");
131 undef $self->{'path'};
132 }
133 }
134
135 =head2 load_ds
136
137 Retrive from disk one data_structure records usually using field 000 as key
138
139 my $ds = $store->load_ds(
140 database => 'ps',
141 input => 'name',
142 id => 42,
143 );
144
145 This function will also perform basic sanity checking on returned
146 data and disable caching if data is corrupted (or changed since last
147 update).
148
149 C<input> is used to differenciate different source input databases
150 which are indexed in same database.
151
152 C<database> if B<optional> argument which will override database name used when creating
153 C<WebPAC::Store> object (for simple retrival from multiple databases).
154
155 Returns hash or undef if cacheing is disabled or unavailable.
156
157 =cut
158
159 sub load_ds {
160 my $self = shift;
161
162 my $log = $self->_get_logger;
163
164 my $cache_path = $self->{'path'};
165
166 if (! $cache_path) {
167 $log->warn("path not set, ignoring load_ds");
168 return;
169 }
170
171 $log->logconfess("arguments for load_ds must be HASH") unless (ref(\@_) eq 'ARRAY' && ($#_ % 2 == 1));
172
173 my $args = {@_};
174 my $id = $args->{id};
175
176 $log->logconfess("got hash, but without id") unless (defined($id));
177 $log->logconfess("got hash, but id [$id] isn't number") unless ($id =~ /^\d+$/);
178
179 my $database = $args->{database} || $self->{database} || $log->logconfess("no database?");
180
181 my $input = $args->{input} || '';
182
183 my $cache_file = "$cache_path/ds/$database/$input/$id";
184 $cache_file =~ s#//#/#go;
185
186 $log->debug("using cache_file $cache_file");
187
188 if (-r $cache_file) {
189 my $ds_ref = retrieve($cache_file);
190 if ($ds_ref) {
191 $log->debug("cache hit: $cache_file");
192 if ($ds_ref->{'ds'}) {
193 return $ds_ref->{'ds'};
194 } else {
195 $log->warn("cache entry $cache_file corrupt. Use rm $cache_path/* to re-create it on next run!");
196 undef $self->{'path'};
197 }
198 }
199 } else {
200 #$log->warn("cache entry $cache_file doesn't exist");
201 return undef;
202 }
203
204 return undef;
205 }
206
207 =head2 save_ds
208
209 Store data_structure on disk.
210
211 $store->save_ds(
212 database => 'name',
213 input => 'name',
214 id => $ds->{000}->[0],
215 ds => $ds,
216 );
217
218 C<database> and C<input> are optional.
219
220 =cut
221
222 sub save_ds {
223 my $self = shift;
224
225 die "can't write to database in read_only mode!" if ($self->{'read_only'});
226
227 return unless($self->{'path'});
228
229 my $args = {@_};
230
231 my $log = $self->_get_logger;
232 $log->debug("save_ds arguments:", dump( \@_ ));
233
234 foreach my $f (qw/id ds/) {
235 $log->logconfess("need $f") unless (defined($args->{$f}));
236 }
237
238 my $database = $args->{database} || $self->{database};
239 $log->logconfess("can't find database name") unless (defined($database));
240
241 my $input = $args->{input} || '';
242
243 my $cache_file = $self->{path} . "/ds/$database/$input/";
244 $cache_file =~ s#//#/#go;
245
246 mkpath($cache_file) unless (-d $cache_file);
247
248 $cache_file .= $args->{id};
249
250 $log->debug("creating storable cache file $cache_file");
251
252 return store {
253 ds => $args->{ds},
254 id => $args->{id},
255 }, $cache_file;
256
257 }
258
259 =head2 load_lookup
260
261 Loads lookup hash from file
262
263 $data = $store->load_lookup(
264 database => $database,
265 input => $input,
266 key => $key,
267 );
268
269 C<database> is optional.
270
271 =cut
272
273 sub load_lookup {
274 my $self = shift;
275 my $args = {@_};
276
277 my $log = $self->_get_logger;
278
279 foreach my $r (qw/input key/) {
280 $log->logconfess("need '$r'") unless defined($args->{$r});
281 }
282
283 my $database = $args->{database} || $self->{database} || $log->logconfess("no database?");
284
285 my $path = $self->{path} . "/lookup/$database/" . $args->{input} . '/' . $args->{key};
286
287 if (! -e $path) {
288 $log->error("lookup $path doesn't exist, lookups will be disabled. Try re-indexing $database/", $args->{input});
289 return;
290 }
291
292 if (my $data = retrieve($path)) {
293 $log->info("loaded lookup $path");
294 return $data;
295 } else {
296 $log->logwarn("can't load lookup $database/", $args->{input}, "/", $args->{key}, " from $path: $!");
297 return undef;
298 }
299 }
300
301 =head2 save_lookup
302
303 Save lookup data to file.
304
305 $store->save_lookup(
306 database => $database,
307 input => $input,
308 key => $key,
309 data => $lookup,
310 );
311
312 C<database> is optional.
313
314 =cut
315
316 sub save_lookup {
317 my $self = shift;
318 my $args = {@_};
319
320 my $log = $self->_get_logger;
321
322 foreach my $r (qw/input key data/) {
323 $log->logconfess("need '$r'") unless defined($args->{$r});
324 }
325
326 my $database = $args->{database} || $self->{database} || $log->logconfess("no database?");
327
328 my $path = $self->{path} . "/lookup/$database/" . $args->{input};
329
330 mkpath($path) unless (-d $path);
331
332 $path .= "/" . $args->{key};
333
334 my $t = time();
335
336 if (store $args->{data}, $path) {
337 $log->info(sprintf("saved lookup $path in %.2fs", time() - $t));
338 return 1;
339 } else {
340 $log->logwarn("can't save lookup to $path: $!");
341 return undef;
342 }
343 }
344
345 =head2 load_row
346
347 Loads row from input database cache (used for lookups)
348
349 $row = $store->load_row(
350 database => $database,
351 input => $input,
352 id => 42,
353 );
354
355 C<database> is optional.
356
357 =cut
358
359 sub load_row {
360 my $self = shift;
361 my $args = {@_};
362
363 my $log = $self->_get_logger;
364
365 foreach my $r (qw/input id/) {
366 $log->logconfess("need '$r'") unless defined($args->{$r});
367 }
368
369 my $database = $args->{database} || $self->{database} || $log->logconfess("no database?");
370
371 my $path = $self->{path} . "/row/$database/" . $args->{input} . '/' . $args->{id};
372
373 if (! -e $path) {
374 $log->warn("input row $path doesn't exist, skipping");
375 return;
376 }
377
378 if (my $data = retrieve($path)) {
379 $log->debug("loaded row $path");
380 return $data;
381 } else {
382 $log->logwarn("can't load row from $path: $!");
383 return undef;
384 }
385 }
386
387 =head2 save_row
388
389 Save row data to file.
390
391 $store->save_row(
392 database => $database,
393 input => $input,
394 id => $mfn,
395 row => $lookup,
396 );
397
398 C<database> is optional.
399
400 =cut
401
402 sub save_row {
403 my $self = shift;
404 my $args = {@_};
405
406 my $log = $self->_get_logger;
407
408 foreach my $r (qw/input id row/) {
409 $log->logconfess("need '$r'") unless defined($args->{$r});
410 }
411
412 my $database = $args->{database} || $self->{database} || $log->logconfess("no database?");
413
414 my $path = $self->{path} . "/row/$database/" . $args->{input};
415
416 mkpath($path) unless (-d $path);
417
418 $path .= "/" . $args->{id};
419
420 if (store $args->{row}, $path) {
421 $log->debug("saved row $path");
422 return 1;
423 } else {
424 $log->logwarn("can't save row to $path: $!");
425 return undef;
426 }
427 }
428
429
430 =head1 AUTHOR
431
432 Dobrica Pavlinusic, C<< <dpavlin@rot13.org> >>
433
434 =head1 COPYRIGHT & LICENSE
435
436 Copyright 2005-2006 Dobrica Pavlinusic, All Rights Reserved.
437
438 This program is free software; you can redistribute it and/or modify it
439 under the same terms as Perl itself.
440
441 =cut
442
443 1; # End of WebPAC::Store

  ViewVC Help
Powered by ViewVC 1.1.26