/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 713 - (hide annotations)
Tue Sep 26 12:42:49 2006 UTC (17 years, 7 months ago) by dpavlin
File size: 6578 byte(s)
 r1020@llin:  dpavlin | 2006-09-26 14:40:34 +0200
 refactored WebPAC::Store

1 dpavlin 209 package WebPAC::Store;
2    
3     use warnings;
4     use strict;
5    
6     use base 'WebPAC::Common';
7     use Storable;
8 dpavlin 215 use File::Path;
9 dpavlin 713 use Data::Dump qw/dump/;
10 dpavlin 209
11     =head1 NAME
12    
13 dpavlin 710 WebPAC::Store - Store WebPAC data on disk
14 dpavlin 209
15     =head1 VERSION
16    
17 dpavlin 713 Version 0.11
18 dpavlin 209
19     =cut
20    
21 dpavlin 713 our $VERSION = '0.11';
22 dpavlin 209
23     =head1 SYNOPSIS
24    
25 dpavlin 710 This module provides disk storage for normalised data and lookups.
26 dpavlin 209
27 dpavlin 710 It is one of newer components of WebPAC, so it will change from time to
28     time.
29 dpavlin 209
30 dpavlin 710 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 dpavlin 209 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 $foo = WebPAC::Store->new();
42     ...
43    
44     =head1 FUNCTIONS
45    
46     =head2 new
47    
48     Create new normalised database object
49    
50     my $db = new WebPAC::Store(
51     path => '/path/to/cache/ds/',
52 dpavlin 217 database => 'name',
53 dpavlin 209 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 dpavlin 713 Optional parametar C<database> will be used used as subdirectory in path if no
63     database in specified when calling other functions.
64 dpavlin 218
65 dpavlin 209 =cut
66    
67     sub new {
68     my $class = shift;
69 dpavlin 710 my $self = {@_};
70     bless($self, $class);
71 dpavlin 209
72 dpavlin 218 my $log = $self->_get_logger();
73    
74     foreach my $p (qw/path database/) {
75     $log->logconfess("need $p") unless ($self->{$p});
76     }
77    
78 dpavlin 209 $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     $db->path('./cache/ds/');
88    
89     If you pass false or zero value to this function, it will disable
90     cacheing.
91    
92 dpavlin 713 You can also call this function to get current cache path.
93 dpavlin 209
94 dpavlin 713 my $cache_path = $db->path;
95    
96 dpavlin 209 =cut
97    
98     sub path {
99     my $self = shift;
100    
101     my $dir = shift;
102 dpavlin 713
103     return $self->{path} unless defined($dir);
104 dpavlin 209
105     my $log = $self->_get_logger();
106    
107     if ($dir) {
108     my $msg;
109     if (! -e $dir) {
110 dpavlin 215 if ($self->{'read_only'}) {
111     $msg = "doesn't exist";
112     } else {
113     $log->info("creating $dir");
114     mkpath $dir;
115     }
116 dpavlin 209 } 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 dpavlin 217 Retrive from disk one data_structure records usually using field 000 as key
138 dpavlin 209
139 dpavlin 713 my $ds = $db->load_ds(
140     database => 'ps',
141     input => 'name',
142     id => 42,
143     );
144 dpavlin 209
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 dpavlin 713 C<input> is used to differenciate different source input databases
150 dpavlin 218 which are indexed in same database.
151    
152 dpavlin 236 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 dpavlin 209 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 dpavlin 217 if (! $cache_path) {
167     $log->warn("path not set, ignoring load_ds");
168     return;
169 dpavlin 209 }
170    
171 dpavlin 217 $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 dpavlin 218 $log->logconfess("got hash, but id [$id] isn't number") unless ($id =~ /^\d+$/);
178 dpavlin 217
179 dpavlin 236 my $database = $args->{database} || $self->{database};
180 dpavlin 713 my $input = $args->{input} || '';
181 dpavlin 217
182     $log->logconfess("can't find database name") unless ($database);
183    
184 dpavlin 713 my $cache_file = "$cache_path/$database/$input/$id";
185 dpavlin 218 $cache_file =~ s#//#/#go;
186 dpavlin 217
187     $log->debug("using cache_file $cache_file");
188    
189     if (-r $cache_file) {
190     my $ds_ref = retrieve($cache_file);
191     if ($ds_ref) {
192     $log->debug("cache hit: $cache_file");
193     if ($ds_ref->{'ds'}) {
194     return $ds_ref->{'ds'};
195     } else {
196     $log->warn("cache entry $cache_file corrupt. Use rm $cache_path/* to re-create it on next run!");
197     undef $self->{'path'};
198 dpavlin 209 }
199     }
200 dpavlin 217 } else {
201     #$log->warn("cache entry $cache_file doesn't exist");
202     return undef;
203 dpavlin 209 }
204    
205     return undef;
206     }
207    
208     =head2 save_ds
209    
210     Store data_structure on disk.
211    
212     $db->save_ds(
213 dpavlin 713 database => 'name',
214     input => 'name',
215 dpavlin 209 id => $ds->{000}->[0],
216     ds => $ds,
217     );
218    
219     B<Totally broken, but fast.>
220    
221     Depends on filename generated by C<load_ds>.
222    
223     =cut
224    
225     sub save_ds {
226     my $self = shift;
227    
228     die "can't write to database in read_only mode!" if ($self->{'read_only'});
229    
230     return unless($self->{'path'});
231    
232 dpavlin 713 my $args = {@_};
233 dpavlin 209
234     my $log = $self->_get_logger;
235 dpavlin 713 $log->debug("save_ds arguments:", dump( \@_ ));
236 dpavlin 209
237     foreach my $f (qw/id ds/) {
238 dpavlin 713 $log->logconfess("need $f") unless (defined($args->{$f}));
239 dpavlin 209 }
240    
241 dpavlin 713 my $database = $args->{database} || $self->{database};
242 dpavlin 217 $log->logconfess("can't find database name") unless ($database);
243 dpavlin 209
244 dpavlin 713 my $input = $args->{input} || '';
245 dpavlin 217
246 dpavlin 713 my $cache_file = $self->{path} . "/$database/$input/";
247 dpavlin 218 $cache_file =~ s#//#/#go;
248    
249 dpavlin 299 mkpath($cache_file) unless (-d $cache_file);
250    
251 dpavlin 713 $cache_file .= $args->{id};
252 dpavlin 299
253 dpavlin 209 $log->debug("creating storable cache file $cache_file");
254    
255     return store {
256 dpavlin 713 ds => $args->{ds},
257     id => $args->{id},
258 dpavlin 209 }, $cache_file;
259    
260     }
261    
262 dpavlin 710 =head2 save_lookup
263    
264 dpavlin 713 $db->save_lookup(
265     database => $database,
266     input => $input,
267     key => $key,
268     data => $lookup,
269     );
270 dpavlin 710
271     =cut
272    
273     sub save_lookup {
274     my $self = shift;
275 dpavlin 713 my $args = {@_};
276 dpavlin 710
277     my $log = $self->_get_logger;
278    
279 dpavlin 713 foreach my $r (qw/input key data/) {
280     $log->logconfess("need '$r'") unless defined($args->{$r});
281     }
282 dpavlin 710
283 dpavlin 713 my $database = $args->{database} || $self->{database} || $log->logconfess("no database?");
284    
285     my $path = $self->{path} . "/lookup/$database/" . $args->{input};
286    
287 dpavlin 710 mkpath($path) unless (-d $path);
288    
289 dpavlin 713 $path .= "/" . $args->{key};
290 dpavlin 710
291 dpavlin 713 if (store $args->{data}, $path) {
292 dpavlin 710 $log->info("saved lookup $path");
293 dpavlin 713 return 1;
294 dpavlin 710 } else {
295 dpavlin 713 $log->logwarn("can't store lookup $database/", $args->{input}, "/", $args->{key}, " in $path: $!");
296     return undef;
297 dpavlin 710 }
298     }
299    
300    
301 dpavlin 209 =head1 AUTHOR
302    
303     Dobrica Pavlinusic, C<< <dpavlin@rot13.org> >>
304    
305     =head1 COPYRIGHT & LICENSE
306    
307     Copyright 2005 Dobrica Pavlinusic, All Rights Reserved.
308    
309     This program is free software; you can redistribute it and/or modify it
310     under the same terms as Perl itself.
311    
312     =cut
313    
314     1; # End of WebPAC::Store

  ViewVC Help
Powered by ViewVC 1.1.26