Index: server/mogilefsd =================================================================== RCS file: /home/cvspub/wcmtools/mogilefs/server/mogilefsd,v retrieving revision 1.114 retrieving revision 1.116 diff -u -r1.114 -r1.116 --- server/mogilefsd 28 Feb 2006 20:52:27 -0000 1.114 +++ server/mogilefsd 2 Mar 2006 06:05:08 -0000 1.116 @@ -2425,22 +2425,50 @@ } return $self->err_line("no_devices") unless @dests; + my $explicit_fid_used = $fid ? 1 : 0; # setup the new mapping. we store the devices that we picked for # this file in here, knowing that they might not be used. create_close # is responsible for actually mapping in file_on. NOTE: fid is being # passed in, it's either some number they gave us, or it's going to be # undef which translates into NULL which means to automatically create # one. that should be fine. - $dbh->do("INSERT INTO tempfile SET ". - " fid=?, dmid=?, dkey=?, classid=?, createtime=UNIX_TIMESTAMP(), devids=?", - undef, $fid, $dmid, $key, $classid, join(',', @dests)); - return undef if $dbh->err; - unless (defined $fid) { - # if they did not give us a fid, then we want to grab the one that was - # theoretically automatically generated - $fid = $dbh->{mysql_insertid}; # FIXME: mysql-ism + my $ins_tempfile = sub { + $dbh->do("INSERT INTO tempfile SET ". + " fid=?, dmid=?, dkey=?, classid=?, createtime=UNIX_TIMESTAMP(), devids=?", + undef, $fid, $dmid, $key, $classid, join(',', @dests)); + return undef if $dbh->err; + unless (defined $fid) { + # if they did not give us a fid, then we want to grab the one that was + # theoretically automatically generated + $fid = $dbh->{mysql_insertid}; # FIXME: mysql-ism + } + return undef unless defined $fid && $fid > 0; + return 1; + }; + + return undef unless $ins_tempfile->(); + + my $fid_in_use = sub { + my $exists = $dbh->selectrow_array("SELECT COUNT(*) FROM file WHERE fid=?", undef, $fid); + die if $dbh->err; + return $exists ? 1 : 0; + }; + + # if the fid is in use, do something + while ($fid_in_use->($fid)) { + return $self->err_line("fid_in_use") if $explicit_fid_used; + + # mysql could have been restarted with an empty tempfile table, causing + # innodb to reuse a fid number. so we need to seed the tempfile table... + + # get the highest fid from the filetable and insert a dummy row + $fid = $dbh->selectrow_array("SELECT MAX(fid) FROM file"); + $ins_tempfile->(); + + # then do a normal auto-increment + $fid = undef; + return undef unless $ins_tempfile->(); } - return undef unless defined $fid && $fid > 0; # original single path support return $self->ok_line({