File Coverage

blib/lib/MogileFS/FID.pm
Criterion Covered Total %
statement 20 136 14.7
branch 1 38 2.6
condition 0 10 0.0
subroutine 7 37 18.9
pod 0 28 0.0
total 28 249 11.2


line stmt bran cond sub pod time code
1             package MogileFS::FID;
2 21     21   134 use strict;
  21         49  
  21         984  
3 21     21   128 use warnings;
  21         40  
  21         745  
4 21     21   123 use Carp qw(croak);
  21         48  
  21         1373  
5 21     21   131 use MogileFS::ReplicationRequest qw(rr_upgrade);
  21         45  
  21         1117  
6 21     21   136 use MogileFS::Server;
  21         45  
  21         1005  
7 21     21   237 use overload '""' => \&as_string;
  21         49  
  21         277  
8              
9             BEGIN {
10 21 50   21   2233 my $testing = $ENV{TESTING} ? 1 : 0;
11 21         48104 eval "sub TESTING () { $testing }";
12             }
13              
14             sub new {
15 0     0 0   my ($class, $fidid) = @_;
16 0 0         croak("Invalid fidid") unless $fidid;
17 0           return bless {
18             fidid => $fidid,
19             dmid => undef,
20             dkey => undef,
21             length => undef,
22             classid => undef,
23             devcount => undef,
24             _loaded => 0,
25             _devids => undef, # undef, or pre-loaded arrayref devid list
26             }, $class;
27             }
28              
29             sub as_string {
30 0     0 0   my $self = shift;
31 0           "FID[f=$self->{fidid}]";
32             }
33              
34             # mutates/blesses given row.
35             sub new_from_db_row {
36 0     0 0   my ($class, $row) = @_;
37             # TODO: sanity check provided row more?
38 0 0         $row->{fidid} = delete $row->{fid} or die "Missing 'fid' column";
39 0           $row->{_loaded} = 1;
40 0           return bless $row, $class;
41             }
42              
43             # quick port of old API. perhaps not ideal.
44             sub new_from_dmid_and_key {
45 0     0 0   my ($class, $dmid, $key) = @_;
46 0 0         my $row = Mgd::get_store()->read_store->file_row_from_dmid_key($dmid, $key)
47             or return undef;
48 0           return $class->new_from_db_row($row);
49             }
50              
51             # given a bunch of ::FID objects, populates their devids en-masse
52             # (for the fsck worker, which doesn't want to do many database
53             # round-trips)
54             sub mass_load_devids {
55 0     0 0   my ($class, @fids) = @_;
56 0           my $sto = Mgd::get_store();
57 0           my $locs = $sto->fid_devids_multiple(map { $_->id } @fids);
  0            
58 0           my @ret;
59 0           foreach my $fid (@fids) {
60 0   0       $fid->{_devids} = $locs->{$fid->id} || [];
61             }
62             }
63             # --------------------------------------------------------------------------
64              
65             sub exists {
66 0     0 0   my $self = shift;
67 0           $self->_tryload;
68 0           return $self->{_loaded};
69             }
70              
71             sub classid {
72 0     0 0   my $self = shift;
73 0           $self->_load;
74 0           return $self->{classid};
75             }
76              
77             sub dmid {
78 0     0 0   my $self = shift;
79 0           $self->_load;
80 0           return $self->{dmid};
81             }
82              
83             sub length {
84 0     0 0   my $self = shift;
85 0           $self->_load;
86 0           return $self->{length};
87             }
88              
89             sub devcount {
90 0     0 0   my $self = shift;
91 0           $self->_load;
92 0           return $self->{devcount};
93             }
94              
95 0     0 0   sub id { $_[0]{fidid} }
96              
97             # force loading, or die.
98             sub _load {
99 0 0   0     return 1 if $_[0]{_loaded};
100 0           my $self = shift;
101 0 0         croak("FID\#$self->fidid} doesn't exist") unless $self->_tryload;
102             }
103              
104             # return 1 if loaded, or 0 if not exist
105             sub _tryload {
106 0 0   0     return 1 if $_[0]{_loaded};
107 0           my $self = shift;
108 0 0         my $row = Mgd::get_store()->file_row_from_fidid($self->{fidid})
109             or return 0;
110 0           $self->{$_} = $row->{$_} foreach qw(dmid dkey length classid devcount);
111 0           $self->{_loaded} = 1;
112 0           return 1;
113             }
114              
115             sub update_devcount {
116 0     0 0   my ($self, %opts) = @_;
117              
118 0           my $no_lock = delete $opts{no_lock};
119 0 0         croak "Bogus options" if %opts;
120              
121 0 0         return 1 if MogileFS::Config->server_setting_cached('skip_devcount');
122              
123 0           my $fidid = $self->{fidid};
124              
125 0           my $sto = Mgd::get_store();
126 0 0         if ($no_lock) {
127 0           return $sto->update_devcount($fidid);
128             } else {
129 0           return $sto->update_devcount_atomic($fidid);
130             }
131             }
132              
133             sub update_class {
134 0     0 0   my ($self, %opts) = @_;
135              
136 0           my $classid = delete $opts{classid};
137 0 0         croak "Bogus options" if %opts;
138              
139 0           my $sto = Mgd::get_store();
140 0           return $sto->update_classid($self->{fidid}, $classid);
141             }
142              
143             sub enqueue_for_replication {
144 0     0 0   my ($self, %opts) = @_;
145 0           my $in = delete $opts{in};
146 0           my $from_dev = delete $opts{from_device}; # devid or Device object
147 0 0         croak("Unknown options to enqueue_for_replication") if %opts;
148 0   0       my $from_devid = (ref $from_dev ? $from_dev->id : $from_dev) || undef;
149             # Still schedule for the future, but don't delay long
150 0           $in = 1 if (TESTING && $in);
151 0           Mgd::get_store()->enqueue_for_replication($self->id, $from_devid, $in);
152             }
153              
154             sub mark_unreachable {
155 0     0 0   my $self = shift;
156             # update database table
157 0           Mgd::get_store()->mark_fidid_unreachable($self->id);
158             }
159              
160             sub delete {
161 0     0 0   my $fid = shift;
162 0           my $sto = Mgd::get_store();
163 0           my $memc = MogileFS::Config->memcache_client;
164 0 0         if ($memc) {
165 0           $fid->_tryload;
166             }
167 0           $sto->delete_fidid($fid->id);
168 0 0 0       if ($memc && $fid->{_loaded}) {
169 0           $memc->delete("mogfid:$fid->{dmid}:$fid->{dkey}");
170             }
171             }
172              
173             # returns 1 on success, 0 on duplicate key error, dies on exception
174             sub rename {
175 0     0 0   my ($fid, $to_key) = @_;
176 0           my $sto = Mgd::get_store();
177 0           return $sto->rename_file($fid->id, $to_key);
178             }
179              
180             # returns array of devids that this fid is on
181             # NOTE: TODO: by default, this doesn't cache. callers might be surprised from
182             # having an old version later on. before caching is added, auditing needs
183             # to be done.
184             sub devids {
185 0     0 0   my $self = shift;
186              
187             # if it was mass-loaded and stored in _devids arrayref, use
188             # that instead of going to db...
189 0 0         return @{$self->{_devids}} if $self->{_devids};
  0            
190              
191             # else get it from the database
192 0           return Mgd::get_store()->read_store->fid_devids($self->id);
193             }
194              
195             sub devs {
196 0     0 0   my $self = shift;
197 0           return map { Mgd::device_factory()->get_by_id($_) } $self->devids;
  0            
198             }
199              
200             sub devfids {
201 0     0 0   my $self = shift;
202 0           return map { MogileFS::DevFID->new($_, $self) } $self->devids;
  0            
203             }
204              
205              
206             # return FID's class
207             sub class {
208 0     0 0   my $self = shift;
209 0           return Mgd::class_factory()->get_by_id($self->dmid, $self->classid);
210             }
211              
212             # Get reloaded the next time we're bothered.
213             sub want_reload {
214 0     0 0   my $self = shift;
215 0           $self->{_loaded} = 0;
216             }
217              
218             # returns bool: if fid's presumed-to-be-on devids meet the file class'
219             # replication policy rules. dies on failure to load class, world
220             # info, etc.
221             sub devids_meet_policy {
222 0     0 0   my $self = shift;
223 0           my $cls = $self->class;
224              
225 0           my $polobj = $cls->repl_policy_obj;
226              
227 0 0         my $alldev = Mgd::device_factory()->map_by_id
228             or die "No global device map";
229              
230 0           my @devs = $self->devs;
231              
232 0           my %rep_args = (
233             fid => $self->id,
234             on_devs => [@devs],
235             all_devs => $alldev,
236             failed => {},
237             min => $cls->mindevcount,
238             );
239 0           my $rr = rr_upgrade($polobj->replicate_to(%rep_args));
240 0   0       return $rr->is_happy && ! $rr->too_happy;
241             }
242              
243             sub fsck_log {
244 0     0 0   my ($self, $code, $dev) = @_;
245 0 0         Mgd::get_store()->fsck_log(
246             code => $code,
247             fid => $self->id,
248             devid => ($dev ? $dev->id : undef),
249             );
250              
251             }
252              
253             sub forget_cached_devids {
254 0     0 0   my $self = shift;
255 0           $self->{_devids} = undef;
256             }
257              
258             # returns MogileFS::DevFID object, after noting in the db that this fid is on this DB.
259             # it trusts you that it is, and that you've verified it.
260             sub note_on_device {
261 0     0 0   my ($fid, $dev) = @_;
262 0           my $dfid = MogileFS::DevFID->new($dev, $fid);
263 0           $dfid->add_to_db;
264 0           $fid->forget_cached_devids;
265 0           return $dfid;
266             }
267              
268             sub forget_about_device {
269 0     0 0   my ($fid, $dev) = @_;
270 0           $dev->forget_about($fid);
271 0           $fid->forget_cached_devids;
272 0           return 1;
273             }
274              
275             # return an FID's checksum object, undef if it's missing
276             sub checksum {
277 0     0 0   my $self = shift;
278 0 0         my $row = Mgd::get_store()->get_checksum($self->{fidid}) or return undef;
279              
280 0           MogileFS::Checksum->new($row);
281             }
282              
283             1;
284              
285             __END__