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             # $Id: file.pm,v 1.18 2003/09/09 08:46:36 sherzodr Exp $
4              
5 4     4   19 use strict;
  4         5  
  4         144  
6             #use diagnostics;
7 4     4   19 use File::Spec;
  4         7  
  4         119  
8 4     4   19 use Log::Agent;
  4         5  
  4         449  
9 4     4   1864 use Class::PObject::Driver;
  4         11  
  4         182  
10 4     4   27 use vars ('$f', '$VERSION', '@ISA');
  4         5  
  4         264  
11 4     4   20 use Fcntl (':DEFAULT', ':flock', ':mode');
  4         9  
  4         10651  
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 12     12 1 16 my $self = shift;
21 12   33     30 my $class = ref($self) || $self;
22 12         17 my ($object_name, $props, $columns) = @_;
23              
24 12         237 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 12 50 66     824 $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 12 50       40 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 12 50       687 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 12 50       66 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 12         146 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 12 50       525 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             return $columns->{id}
57 12         58 }
58              
59              
60              
61              
62             sub load_ids {
63 46     46 1 55 my $self = shift;
64 46   33     109 my $class = ref($self) || $self;
65 46         73 my ($object_name, $props, $terms, $args) = @_;
66              
67 46         955 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 46         2736 my @data_set = ( );
72 46   100     149 $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 46 50       93 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 46         2598 require IO::Dir;
81 46         78360 my %files = ();
82 46 50       176 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 46         2791 my $n = 0;
88 46         145 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 233 50 100     22987 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 233 100       3558 if ( S_ISDIR($stat->mode) ) {
97             next
98 92         799 }
99              
100             # defining a regex pattern to check against the filename to determine
101             # if it can be the file object stored in
102 141         806 my $filef_pattern = $f;
103 141         469 $filef_pattern =~ s/\%\d*d/\\d\+/g;
104 141         256 $filef_pattern =~ s/\./\\./g;
105              
106 141 100       604 unless ( $filename =~ m/^$filef_pattern$/ ) {
107             next
108 46         251 }
109             # we open the file with read-only flag
110 95 50       2467 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 95 50       486 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 95         295 local $/ = undef;
121 95         1076 my $datastr = ; close(FH);
  95         500  
122 95 50       159 unless( defined $datastr ) {
123             next
124 0         0 }
125 95         289 my $data = $self->thaw($object_name, $props, $datastr);
126 95 100       235 if ( $self->_matches_terms($data, $terms) ) {
127 71 100       170 push @data_set, keys %$args ? $data : $data->{id};
128 71         429 $n++
129             }
130             }
131 46         643 untie(%files);
132              
133             # returning post-processed data set
134 46 100       940 unless ( keys %$args ) {
135             return \@data_set
136 31         171 }
137              
138 15         50 my $data_set = $self->_filter_by_args(\@data_set, $args);
139 15         21 return [ map { $_->{id} } @$data_set ]
  27         125  
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 51     51 1 62 my $self = shift;
158 51   33     109 my $class = ref($self) || $self;
159 51         64 my ($object_name, $props, $id) = @_;
160              
161 51         1093 logtrc 3, "%s->load(%s)", $class, join ", ", @_;
162              
163             # determine the name of the file for this object
164 51 50       3254 my $filename = $self->_filename($object_name, $props, $id) or return;
165              
166             # open that file
167 51 100       990 unless ( sysopen(FH, $filename, O_RDONLY) ) {
168 1         19 $self->errstr("couldn't open '$filename': $!");
169             return undef
170 1         8 }
171             # lock the file handle
172 50 50       216 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 50         147 local $/ = undef;
178             # slurp the whole file in
179 50         684 my $data_str = ;
180 50         273 close(FH);
181 50 50       91 unless ( $data_str ) {
182 0         0 $self->errstr("object is empty");
183             return undef
184 0         0 }
185 50         193 return $self->thaw($object_name, $props, $data_str)
186             }
187              
188              
189              
190              
191             sub remove {
192 7     7 1 16 my ($self, $object_name, $props, $id) = @_;
193              
194 7         23 my $filename = $self->_filename($object_name, $props, $id);
195 7 50       601 unless ( unlink($filename) ) {
196 0         0 $self->errstr("couldn't unlink '$filename': $!");
197             return undef
198 0         0 }
199 7         30 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         15 my $dir = $self->_dir($object_name, $props);
213 5         121 logtrc 3, "removing '%s'", $dir;
214 5         368 require File::Path;
215 5 50       1965 unless ( File::Path::rmtree($dir) ) {
216 0         0 $self->errstr( "couldn't unlink '%s': %s", $dir, $!);
217             return undef
218 0         0 }
219 5         23 return 1
220             }
221              
222              
223              
224              
225              
226              
227              
228             sub generate_id {
229 8     8 0 13 my ($self, $object_name, $props) = @_;
230              
231 8 50       17 my $dir = $self->_dir($object_name, $props) or return;
232              
233 8         95 my $filename = File::Spec->catfile($dir, 'counter.cpo');
234              
235 8 50       412 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 8 50       62 unless (flock(FH, LOCK_EX) ) {
240 0         0 $self->errstr("couldn't lock '$filename': $!");
241             return undef
242 0         0 }
243 8   100     169 my $num = || 0;
244 8 50       51 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 8 50       253 unless (truncate(FH, 0)) {
249 0         0 $self->errstr("couldn't truncate '$filename': $!");
250             return undef
251 0         0 }
252 8         157 print FH ++$num, "\n";
253 8 50       222 unless(close(FH)) {
254 0         0 $self->errstr("couldn't update '$filename': $!");
255             return undef
256 0         0 }
257 8         47 return $num
258             }
259              
260              
261              
262              
263             sub _filename {
264 70     70   111 my ($self, $object_name, $props, $id) = @_;
265              
266 70 50 33     297 unless ( $object_name && defined($id) ) {
267 0         0 logcroak "Usage: _filename(\$id)";
268             }
269 70 50       115 my $dir = $self->_dir($object_name, $props) or return;
270 70         742 return File::Spec->catfile($dir, sprintf($f, $id))
271             }
272              
273              
274             sub _dir {
275 129     129   141 my ($self, $object_name, $props) = @_;
276              
277 129         103 my ($object_dir, $object_name_as_str);
278 129         163 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 129 50       206 unless ( defined $dir ) {
284 0         0 $dir = File::Spec->tmpdir()
285             }
286              
287             # creating a dirified version of the object name
288 129         119 $object_name_as_str = $object_name;
289 129         473 $object_name_as_str =~ s/\W+/_/g;
290 129         1061 $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 129 100       2028 unless ( -e $object_dir ) {
295 6         41 require File::Path;
296 6 50       1852 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 129         386 return $object_dir
303             }
304              
305             1;
306              
307             __END__;