File Coverage

blib/lib/MogileFS/FID.pm
Criterion Covered Total %
statement 20 134 14.9
branch 1 38 2.6
condition 0 10 0.0
subroutine 7 36 19.4
pod 0 27 0.0
total 28 245 11.4


line stmt bran cond sub pod time code
1             package MogileFS::FID;
2 21     21   101 use strict;
  21         27  
  21         718  
3 21     21   96 use warnings;
  21         32  
  21         593  
4 21     21   97 use Carp qw(croak);
  21         36  
  21         1063  
5 21     21   95 use MogileFS::ReplicationRequest qw(rr_upgrade);
  21         48  
  21         904  
6 21     21   95 use MogileFS::Server;
  21         34  
  21         698  
7 21     21   99 use overload '""' => \&as_string;
  21         84  
  21         224  
8              
9             BEGIN {
10 21 50   21   1817 my $testing = $ENV{TESTING} ? 1 : 0;
11 21         28290 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 delete {
155 0     0 0   my $fid = shift;
156 0           my $sto = Mgd::get_store();
157 0           my $memc = MogileFS::Config->memcache_client;
158 0 0         if ($memc) {
159 0           $fid->_tryload;
160             }
161 0           $sto->delete_fidid($fid->id);
162 0 0 0       if ($memc && $fid->{_loaded}) {
163 0           $memc->delete("mogfid:$fid->{dmid}:$fid->{dkey}");
164             }
165             }
166              
167             # returns 1 on success, 0 on duplicate key error, dies on exception
168             sub rename {
169 0     0 0   my ($fid, $to_key) = @_;
170 0           my $sto = Mgd::get_store();
171 0           return $sto->rename_file($fid->id, $to_key);
172             }
173              
174             # returns array of devids that this fid is on
175             # NOTE: TODO: by default, this doesn't cache. callers might be surprised from
176             # having an old version later on. before caching is added, auditing needs
177             # to be done.
178             sub devids {
179 0     0 0   my $self = shift;
180              
181             # if it was mass-loaded and stored in _devids arrayref, use
182             # that instead of going to db...
183 0 0         return @{$self->{_devids}} if $self->{_devids};
  0            
184              
185             # else get it from the database
186 0           return Mgd::get_store()->read_store->fid_devids($self->id);
187             }
188              
189             sub devs {
190 0     0 0   my $self = shift;
191 0           return map { Mgd::device_factory()->get_by_id($_) } $self->devids;
  0            
192             }
193              
194             sub devfids {
195 0     0 0   my $self = shift;
196 0           return map { MogileFS::DevFID->new($_, $self) } $self->devids;
  0            
197             }
198              
199              
200             # return FID's class
201             sub class {
202 0     0 0   my $self = shift;
203 0           return Mgd::class_factory()->get_by_id($self->dmid, $self->classid);
204             }
205              
206             # Get reloaded the next time we're bothered.
207             sub want_reload {
208 0     0 0   my $self = shift;
209 0           $self->{_loaded} = 0;
210             }
211              
212             # returns bool: if fid's presumed-to-be-on devids meet the file class'
213             # replication policy rules. dies on failure to load class, world
214             # info, etc.
215             sub devids_meet_policy {
216 0     0 0   my $self = shift;
217 0           my $cls = $self->class;
218              
219 0           my $polobj = $cls->repl_policy_obj;
220              
221 0 0         my $alldev = Mgd::device_factory()->map_by_id
222             or die "No global device map";
223              
224 0           my @devs = $self->devs;
225              
226 0           my %rep_args = (
227             fid => $self->id,
228             on_devs => [@devs],
229             all_devs => $alldev,
230             failed => {},
231             min => $cls->mindevcount,
232             );
233 0           my $rr = rr_upgrade($polobj->replicate_to(%rep_args));
234 0   0       return $rr->is_happy && ! $rr->too_happy;
235             }
236              
237             sub fsck_log {
238 0     0 0   my ($self, $code, $dev) = @_;
239 0 0         Mgd::get_store()->fsck_log(
240             code => $code,
241             fid => $self->id,
242             devid => ($dev ? $dev->id : undef),
243             );
244              
245             }
246              
247             sub forget_cached_devids {
248 0     0 0   my $self = shift;
249 0           $self->{_devids} = undef;
250             }
251              
252             # returns MogileFS::DevFID object, after noting in the db that this fid is on this DB.
253             # it trusts you that it is, and that you've verified it.
254             sub note_on_device {
255 0     0 0   my ($fid, $dev) = @_;
256 0           my $dfid = MogileFS::DevFID->new($dev, $fid);
257 0           $dfid->add_to_db;
258 0           $fid->forget_cached_devids;
259 0           return $dfid;
260             }
261              
262             sub forget_about_device {
263 0     0 0   my ($fid, $dev) = @_;
264 0           $dev->forget_about($fid);
265 0           $fid->forget_cached_devids;
266 0           return 1;
267             }
268              
269             # return an FID's checksum object, undef if it's missing
270             sub checksum {
271 0     0 0   my $self = shift;
272 0 0         my $row = Mgd::get_store()->get_checksum($self->{fidid}) or return undef;
273              
274 0           MogileFS::Checksum->new($row);
275             }
276              
277             1;
278              
279             __END__