5 use MogileFS
::ReplicationRequest
qw(rr_upgrade);
7 use overload
'""' => \
&as_string
;
10 my $testing = $ENV{TESTING
} ?
1 : 0;
11 eval "sub TESTING () { $testing }";
15 my ($class, $fidid) = @_;
16 croak
("Invalid fidid") unless $fidid;
25 _devids
=> undef, # undef, or pre-loaded arrayref devid list
31 "FID[f=$self->{fidid}]";
34 # mutates/blesses given row.
36 my ($class, $row) = @_;
37 # TODO: sanity check provided row more?
38 $row->{fidid
} = delete $row->{fid
} or die "Missing 'fid' column";
40 return bless $row, $class;
43 # quick port of old API. perhaps not ideal.
44 sub new_from_dmid_and_key
{
45 my ($class, $dmid, $key) = @_;
46 my $row = Mgd
::get_store
()->read_store->file_row_from_dmid_key($dmid, $key)
48 return $class->new_from_db_row($row);
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
54 sub mass_load_devids
{
55 my ($class, @fids) = @_;
56 my $sto = Mgd
::get_store
();
57 my $locs = $sto->fid_devids_multiple(map { $_->id } @fids);
59 foreach my $fid (@fids) {
60 $fid->{_devids
} = $locs->{$fid->id} || [];
63 # --------------------------------------------------------------------------
68 return $self->{_loaded
};
74 return $self->{classid
};
86 return $self->{length};
92 return $self->{devcount
};
95 sub id
{ $_[0]{fidid
} }
97 # force loading, or die.
99 return 1 if $_[0]{_loaded
};
101 croak
("FID\#$self->fidid} doesn't exist") unless $self->_tryload;
104 # return 1 if loaded, or 0 if not exist
106 return 1 if $_[0]{_loaded
};
108 my $row = Mgd
::get_store
()->file_row_from_fidid($self->{fidid
})
110 $self->{$_} = $row->{$_} foreach qw(dmid dkey length classid devcount);
111 $self->{_loaded
} = 1;
115 sub update_devcount
{
116 my ($self, %opts) = @_;
118 my $no_lock = delete $opts{no_lock
};
119 croak
"Bogus options" if %opts;
121 return 1 if MogileFS
::Config
->server_setting_cached('skip_devcount');
123 my $fidid = $self->{fidid
};
125 my $sto = Mgd
::get_store
();
127 return $sto->update_devcount($fidid);
129 return $sto->update_devcount_atomic($fidid);
134 my ($self, %opts) = @_;
136 my $classid = delete $opts{classid
};
137 croak
"Bogus options" if %opts;
139 my $sto = Mgd
::get_store
();
140 return $sto->update_classid($self->{fidid
}, $classid);
143 sub enqueue_for_replication
{
144 my ($self, %opts) = @_;
145 my $in = delete $opts{in};
146 my $from_dev = delete $opts{from_device
}; # devid or Device object
147 croak
("Unknown options to enqueue_for_replication") if %opts;
148 my $from_devid = (ref $from_dev ?
$from_dev->id : $from_dev) || undef;
149 # Still schedule for the future, but don't delay long
150 $in = 1 if (TESTING
&& $in);
151 Mgd
::get_store
()->enqueue_for_replication($self->id, $from_devid, $in);
154 sub mark_unreachable
{
156 # update database table
157 Mgd
::get_store
()->mark_fidid_unreachable($self->id);
162 my $sto = Mgd
::get_store
();
163 my $memc = MogileFS
::Config
->memcache_client;
167 $sto->delete_fidid($fid->id);
168 if ($memc && $fid->{_loaded
}) {
169 $memc->delete("mogfid:$fid->{dmid}:$fid->{dkey}");
173 # returns 1 on success, 0 on duplicate key error, dies on exception
175 my ($fid, $to_key) = @_;
176 my $sto = Mgd
::get_store
();
177 return $sto->rename_file($fid->id, $to_key);
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
187 # if it was mass-loaded and stored in _devids arrayref, use
188 # that instead of going to db...
189 return @
{$self->{_devids
}} if $self->{_devids
};
191 # else get it from the database
192 return Mgd
::get_store
()->read_store->fid_devids($self->id);
197 return map { Mgd
::device_factory
()->get_by_id($_) } $self->devids;
202 return map { MogileFS
::DevFID
->new($_, $self) } $self->devids;
209 return Mgd
::class_factory
()->get_by_id($self->dmid, $self->classid);
212 # Get reloaded the next time we're bothered.
215 $self->{_loaded
} = 0;
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
221 sub devids_meet_policy
{
223 my $cls = $self->class;
225 my $polobj = $cls->repl_policy_obj;
227 my $alldev = Mgd
::device_factory
()->map_by_id
228 or die "No global device map";
230 my @devs = $self->devs;
237 min
=> $cls->mindevcount,
239 my $rr = rr_upgrade
($polobj->replicate_to(%rep_args));
240 return $rr->is_happy && ! $rr->too_happy;
244 my ($self, $code, $dev) = @_;
245 Mgd
::get_store
()->fsck_log(
248 devid
=> ($dev ?
$dev->id : undef),
253 sub forget_cached_devids
{
255 $self->{_devids
} = undef;
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.
261 my ($fid, $dev) = @_;
262 my $dfid = MogileFS
::DevFID
->new($dev, $fid);
264 $fid->forget_cached_devids;
268 sub forget_about_device
{
269 my ($fid, $dev) = @_;
270 $dev->forget_about($fid);
271 $fid->forget_cached_devids;
275 # return an FID's checksum object, undef if it's missing
278 my $row = Mgd
::get_store
()->get_checksum($self->{fidid
}) or return undef;
280 MogileFS
::Checksum
->new($row);
289 MogileFS::FID - represents a unique, immutable version of a file
293 This class represents a "fid", or "file id", which is a unique
294 revision of a file. If you upload a file with the same key
295 ("filename") a dozen times, each one has a unique "fid". Fids are
296 immutable, and are what are replicated around the MogileFS farm.