File Coverage

blib/lib/Class/PObject/Driver/file.pm
Criterion Covered Total %
statement 115 157 73.2
branch 40 66 60.6
condition 16 28 57.1
subroutine 14 14 100.0
pod 5 6 83.3
total 190 271 70.1


line stmt bran cond sub pod time code
1             package Class::PObject::Driver::file;
2              
3             # file.pm,v 1.18 2003/09/09 08:46:36 sherzodr Exp
4              
5 3     3   17 use strict;
  3         6  
  3         104  
6             #use diagnostics;
7 3     3   18 use File::Spec;
  3         4  
  3         71  
8 3     3   16 use Log::Agent;
  3         5  
  3         374  
9 3     3   1756 use Class::PObject::Driver;
  3         8  
  3         93  
10 3     3   18 use vars ('$f', '$VERSION', '@ISA');
  3         6  
  3         179  
11 3     3   15 use Fcntl (':DEFAULT', ':flock', ':mode');
  3         6  
  3         7811  
12              
13             @ISA = ("Class::PObject::Driver");
14             $VERSION = '2.00';
15             $f = 'obj%05d.cpo';
16              
17             # called when pobject's save() method is called. Note: this is not
18             # the same as save() method as the one called by pobject. This is different!
19             sub save {
20 11     11 1 19 my $self = shift;
21 11   33     37 my $class = ref($self) || $self;
22 11         22 my ($object_name, $props, $columns) = @_;
23              
24 11         276 logtrc 3, "%s->save()", $class;
25              
26             # if 'id' does not already exist, we're being asked to save a newly
27             # created object. Before we do that, we create a new id for the object:
28 11 50 66     993 $columns->{id} ||= $self->generate_id($object_name, $props) or return;
29              
30             # _filename() returns the name of the file this particular object should
31             # be stored in. Look into _filename() for details
32 11 50       62 my $filename = $self->_filename($object_name, $props, $columns->{id}) or return;
33              
34             # if we can't open the file, we set error message, and return undef
35 11 50       976 unless ( sysopen(FH, $filename, O_WRONLY|O_CREAT|O_TRUNC, 0666) ) {
36 0         0 $self->errstr("couldn't open '$filename': $!");
37 0         0 logerr $self->errstr;
38             return undef
39 0         0 }
40             # we do the same if we can't get exclusive lock on the file
41 11 50       100 unless (flock(FH, LOCK_EX) ) {
42 0         0 $self->errstr("couldn't lock '$filename': $!");
43 0         0 logerr $self->errstr;
44             return undef
45 0         0 }
46              
47             # and store frozen data into file:
48 11         82 print FH $self->freeze($object_name, $props, $columns);
49             # if we can't close the file handle, it means we couldn't store it.
50 11 50       569 unless( close(FH) ) {
51 0         0 $self->errstr("couldn't save the object: $!");
52 0         0 logerr $self->errstr;
53             return undef
54 0         0 }
55             # if everything went swell, we should return object id
56 11         59 return $columns->{id}
57             }
58              
59              
60              
61              
62             sub load_ids {
63 43     43 1 73 my $self = shift;
64 43   33     129 my $class = ref($self) || $self;
65 43         78 my ($object_name, $props, $terms, $args) = @_;
66              
67 43         1551 logtrc 3, "%s->load_ids(@_)", $class;
68              
69             # if we come this far, we're being asked to return either all the objects,
70             # or by some criteria
71 43         8885 my @data_set = ( );
72 43   100     175 $args ||= { };
73              
74             # to do it, we need to figure out which directory the objects of this
75             # type are most likely to be stored. For details look into '_dir()'
76 43 50       310 my $object_dir = $self->_dir($object_name, $props) or return;
77              
78             # and iterate through each object file. For some reason I prefer using
79             # IO::Dir for retrieving objects, seems 'cleaner' this way
80 43         2965 require IO::Dir;
81 43         79726 my %files = ();
82 43 50       274 unless(tie %files, "IO::Dir", $object_dir) {
83 0         0 $self->errstr("couldn't open '$object_dir': $!");
84 0         0 logerr $self->errstr;
85             return undef
86 0         0 }
87 43         3670 my $n = 0;
88 43         273 while ( my ($filename, $stat) = each %files ) {
89             # if 'limit' was given, and 'offset' is missing and sort is not given,
90             # then check we have already reached our 'limit'. Otherwise, we need to
91             # load all the objects to the memory before we can return the data set
92 222 50 100     35648 if ( defined($args->{limit}) && (!$args->{offset}) && (!$args->{'sort'}) && ($n == $args->{limit}) ) {
      66        
      33        
93             last
94 0         0 }
95             # if it is a directory, then skip to the next file
96 222 100       5177 if ( S_ISDIR($stat->mode) ) {
97             next
98 86         1156 }
99              
100             # defining a regex pattern to check against the filename to determine
101             # if it can be the file object stored in
102 136         1007 my $filef_pattern = $f;
103 136         684 $filef_pattern =~ s/\%\d*d/\\d\+/g;
104 136         359 $filef_pattern =~ s/\./\\./g;
105              
106 136 100       771 unless ( $filename =~ m/^$filef_pattern$/ ) {
107             next
108 43         370 }
109             # we open the file with read-only flag
110 93 50       4456 unless (sysopen(FH, File::Spec->catfile($object_dir, $filename), O_RDONLY)) {
111 0         0 $self->errstr("couldn't open '$filename': $!");
112 0         0 logerr $self->errstr;
113             return undef
114 0         0 }
115 93 50       809 unless(flock(FH, LOCK_SH)) {
116 0         0 $self->errstr("couldn't lock '$filename': $!");
117 0         0 logerr $self->errstr;
118             return undef
119 0         0 }
120 93         348 local $/ = undef;
121 93         2178 my $datastr = ; close(FH);
  93         8844  
122 93 50       239 unless( defined $datastr ) {
123             next
124 0         0 }
125 93         398 my $data = $self->thaw($object_name, $props, $datastr);
126 93 100       328 if ( $self->_matches_terms($data, $terms) ) {
127 69 100       204 push @data_set, keys %$args ? $data : $data->{id};
128 69         661 $n++
129             }
130             }
131 43         974 untie(%files);
132              
133             # returning post-processed data set
134 43 100       1418 unless ( keys %$args ) {
135             return \@data_set
136 26         147 }
137              
138 17         107 my $data_set = $self->_filter_by_args(\@data_set, $args);
139 17         40 return [ map { $_->{id} } @$data_set ]
  29         219  
140             }
141              
142              
143              
144              
145              
146              
147              
148              
149              
150              
151              
152              
153              
154              
155             # load_by_id() is called only while object is to be retrieved by its id
156             sub load {
157 50     50 1 108 my $self = shift;
158 50   33     149 my $class = ref($self) || $self;
159 50         104 my ($object_name, $props, $id) = @_;
160              
161 50         1557 logtrc 3, "%s->load(%s)", $class, join ", ", @_;
162              
163             # determine the name of the file for this object
164 50 50       4736 my $filename = $self->_filename($object_name, $props, $id) or return;
165              
166             # open that file
167 50 100       1970 unless ( sysopen(FH, $filename, O_RDONLY) ) {
168 1         22 $self->errstr("couldn't open '$filename': $!");
169             return undef
170 1         8 }
171             # lock the file handle
172 49 50       387 unless(flock(FH, LOCK_SH)) {
173 0         0 $self->errstr("couldn't lock '$filename': $!");
174             return undef
175 0         0 }
176             # undefined record separator
177 49         207 local $/ = undef;
178             # slurp the whole file in
179 49         1137 my $data_str = ;
180 49         645 close(FH);
181 49 50       165 unless ( $data_str ) {
182 0         0 $self->errstr("object is empty");
183             return undef
184 0         0 }
185 49         222 return $self->thaw($object_name, $props, $data_str)
186             }
187              
188              
189              
190              
191             sub remove {
192 6     6 1 16 my ($self, $object_name, $props, $id) = @_;
193              
194 6         26 my $filename = $self->_filename($object_name, $props, $id);
195 6 50       794 unless ( unlink($filename) ) {
196 0         0 $self->errstr("couldn't unlink '$filename': $!");
197             return undef
198 0         0 }
199 6         27 return 1
200             }
201              
202              
203              
204              
205              
206              
207              
208             sub drop_datasource {
209 5     5 1 11 my ($self, $object_name, $props, $i) = @_;
210              
211              
212 5         20 my $dir = $self->_dir($object_name, $props);
213 5         136 logtrc 3, "removing '%s'", $dir;
214 5         495 require File::Path;
215 5 50       2886 unless ( File::Path::rmtree($dir) ) {
216 0         0 $self->errstr( "couldn't unlink '%s': %s", $dir, $!);
217             return undef
218 0         0 }
219 5         25 return 1
220             }
221              
222              
223              
224              
225              
226              
227              
228             sub generate_id {
229 7     7 0 15 my ($self, $object_name, $props) = @_;
230              
231 7 50       34 my $dir = $self->_dir($object_name, $props) or return;
232              
233 7         114 my $filename = File::Spec->catfile($dir, 'counter.cpo');
234              
235 7 50       3156 unless (sysopen(FH, $filename, O_RDWR|O_CREAT)) {
236 0         0 $self->errstr("couldn't open/create '$filename': $!");
237             return undef
238 0         0 }
239 7 50       85 unless (flock(FH, LOCK_EX) ) {
240 0         0 $self->errstr("couldn't lock '$filename': $!");
241             return undef
242 0         0 }
243 7   100     256 my $num = || 0;
244 7 50       57 unless (seek(FH, 0, 0)) {
245 0         0 $self->errstr("couldn't seek to the start of '$filename': $!");
246             return undef
247 0         0 }
248 7 50       378 unless (truncate(FH, 0)) {
249 0         0 $self->errstr("couldn't truncate '$filename': $!");
250             return undef
251 0         0 }
252 7         43 print FH ++$num, "\n";
253 7 50       400 unless(close(FH)) {
254 0         0 $self->errstr("couldn't update '$filename': $!");
255             return undef
256 0         0 }
257 7         52 return $num
258             }
259              
260              
261              
262              
263             sub _filename {
264 67     67   148 my ($self, $object_name, $props, $id) = @_;
265              
266 67 50 33     334 unless ( $object_name && defined($id) ) {
267 0         0 logcroak "Usage: _filename(\$id)";
268             }
269 67 50       191 my $dir = $self->_dir($object_name, $props) or return;
270 67         1175 return File::Spec->catfile($dir, sprintf($f, $id))
271             }
272              
273              
274             sub _dir {
275 122     122   205 my ($self, $object_name, $props) = @_;
276              
277 122         199 my ($object_dir, $object_name_as_str);
278 122         229 my $dir = $props->{datasource};
279              
280             # if 'datasource' was not specified, we should
281             # create a location for object of this type in the
282             # system's temp folder:
283 122 50       430 unless ( defined $dir ) {
284 0         0 $dir = File::Spec->tmpdir()
285             }
286              
287             # creating a dirified version of the object name
288 122         161 $object_name_as_str = $object_name;
289 122         1067 $object_name_as_str =~ s/\W+/_/g;
290 122         1544 $object_dir = File::Spec->catfile($dir, $object_name_as_str);
291              
292             # if the directory that we just created doesn't exist,
293             # we should create it
294 122 100       3192 unless ( -e $object_dir ) {
295 5         37 require File::Path;
296 5 50       1280 unless (File::Path::mkpath($object_dir) ) {
297 0         0 $self->errstr("couldn't create datasource '$object_dir': $!");
298             return undef
299 0         0 }
300             }
301             # return the directory
302 122         610 return $object_dir
303             }
304              
305             1;
306              
307             __END__;