I'm going to drop this "Remove the re-try logic from
svn_fs_fs__path_rev_absolute()" follow-up patch, as I don't want to get
into checking or messing with the txn-correctness of FSFS now.  If
Daniel or anyone else wants to pursue it, I'd be glad to help.

- Julian


On Thu, 2010-12-02, Daniel Shahaf wrote:
> Julian Foad wrote on Thu, Dec 02, 2010 at 14:33:19 +0000:
> > On Thu, 2010-12-02 at 14:56 +0200, Daniel Shahaf wrote:
> > > Julian Foad wrote on Thu, Dec 02, 2010 at 12:15:19 +0000:
> > > > Remove the re-try logic from svn_fs_fs__path_rev_absolute().  Since
> > > > r1040832, all its callers correctly account for the possibility of an
> > > > out-of-date result due to a concurrent packing operation.
> > > > 
> > > > The re-try logic was introduced in r875097 and reduced but did not 
> > > > eliminate
> > > > the window of opportunity for the caller to use an out-of-date result.
> > > > 
> > > > See the email thread 
> > > > <http://svn.haxx.se/dev/archive-2010-12/0019.shtml>,
> > > > subject "Re: svn commit: r1040832 - Port a fix for a FSFS packing race".
> > > > 
> > > > * subversion/libsvn_fs_fs/fs_fs.c
> > > >   (svn_fs_fs__path_rev_absolute): Remove the re-try logic.
> > > > 
> > > > * subversion/libsvn_fs_fs/fs_fs.h
> > > >   (svn_fs_fs__path_rev_absolute): Update the doc string accordingly.
> > > >  
> > > 
> > > In fact, doesn't the correctness of this change depend on the fact that
> > > svn_fs_fs__with_write_lock() calls update_min_unpacked_rev() before
> > > executing the body() callback?
> > 
> > Yes, it does.  Do you think it shouldn't?
> > 
> 
> I'm not sure whether it "should" or "shouldn't" depend.  The change IS
> correct, but it is only correct because the ffd->min_unpacked_rev is
> known to be up-to-date whenever the write lock is held.
> 
> That's a bit of a spaghetti effect there.  Now, is there another such
> effect that means the patch is wrong?  (I haven't come up with one yet,
> but that doesn't mean there isn't any.)
> 
> > >   (Otherwise we don't know whether there
> > > is a "concurrent" packer, or just ffd->min_unpacked_rev is stale.)
> > 
> > You know, I'm not too clear on the design intention here.  I would have
> > assumed it would be the job of all the fs_fs.c code to ensure that
> > ffd->min_unpacked_rev is never stale (due to its own actions) at any
> > point where it matters.  But the way it does that seems to be to re-read
> > the file in several places, instead of simply updating
> > ffd->min_unpacked_rev when it writes the file.  Maybe the idea was that
> > that method would pick up both internal and concurrent (external)
> > changes in the same way - I don't know.  Seems odd.
> > 
> 
> Yes, that was the idea.  If two processes access the filesystem at the
> same time, and one of them calls svn_fs_pack(), then the other's
> ffd->min_unpacked_rev would be stale.
> 
> It's the same story with ffd->youngest_rev, by the way; compare
> ensure_revision_exists(), which I believe predates the packing logic.
> 
> > Do you have an idea whether something should be done differently?  I
> > don't, not without studying it further.
> > 
> 
> I'm not sure.  Ultimately, ffd->min_unpacked_rev is just a cache, so we
> have to update it when we're about to do something that depends on its
> value.
> 
> In the meantime, let me at least attempt to define the "something" which
> perhaps should be done differently:
> 
> Given the way packing works today, it's possible for a revision file to
> stop existing where you expected it to exist.  Today the code informs
> itself of that situation by re-reading min-packed-rev and retrying.
> (Further up the stack, the code calculating the offset to seek to also
> needs to know whether it's seeking a pack file or a revision file.)
> 
> > I note that the following comment in pack_shard() is not quite right:
> > 
> >   /* Update the min-unpacked-rev file to reflect our newly packed shard.
> >    * (ffd->min_unpacked_rev will be updated by open_pack_or_rev_file().)
> > 
> > That may or may not be true, but it doesn't seem like this function has
> > any right to make that assertion.
> > 
> 
> We could remove the comment and have that function call 
> update_min_unpacked_rev().
> (This would also save us a failed disk access later.)
> 
> But is it strictly *necessary* to do so?  I think not: by not calling
> update_min_unpacked_rev(), we cause ffd->min_unpacked_rev to become
> stale --- a situation which the code has to account for anyway.
> 
> > And in pack_revprop_shard(), it's the same, verbatim:
> > 
> >   /* Update the min-unpacked-rev file to reflect our newly packed shard.
> > 
> > should say 'the min-unpacked-revprop file';
> > 
> >    * (ffd->min_unpacked_rev will be updated by open_pack_or_rev_file().)
> > 
> > and that second line looks completely bogus in this context.
> > 
> 
> Yes, whoever did the copy-paste forgot to update some places.
> 
> > 
> > > > Index: subversion/libsvn_fs_fs/fs_fs.h
> > > > ===================================================================
> > > > --- subversion/libsvn_fs_fs/fs_fs.h     (revision 1041339)
> > > > +++ subversion/libsvn_fs_fs/fs_fs.h     (working copy)
> > > > @@ -411,8 +411,10 @@ svn_error_t *svn_fs_fs__move_into_place(
> > > >     Allocate *PATH in POOL.
> > > >  
> > > >     Note: If the caller does not have the write lock on FS, then the 
> > > > path is
> > > > -   not guaranteed to remain correct after the function returns, 
> > > > because the
> > > > -   revision might become packed just after this call. */
> > > > +   not guaranteed to be correct or to remain correct after the function
> > > > +   returns, because the revision might become packed before or after 
> > > > this
> > > > +   call.  If a file exists at that path, then it is correct; if not, 
> > > > then
> > > > +   the caller should call update_min_unpacked_rev() and re-try once. */
> > > 
> > > +1 semantically.  However, update_min_unpacked_rev() is private to
> > > fs_fs.c, so technically you aren't supposed to mention it in this
> > > context.
> > 
> > Good point.  Really that means any external caller of this API has to
> > hold the write lock.  Calling update_min_unpacked_rev() and re-trying is
> > only an option for internal callers (within fs_fs.c).  I wonder if this
> > should give us a clue about the questions above.
> > 
> 
> First, I still think having the update_min_unpacked_rev() reference
> there is useful.
> 
> Would it be a layering violation for code in libsvn_fs_fs outside of
> fs_fs.c to call update_min_unpacked_rev()?  I'm not sure.
> 
> > - Julian
> > 
> > 
> > > >  svn_error_t *
> > > >  svn_fs_fs__path_rev_absolute(const char **path,
> > > >                               svn_fs_t *fs,
> > > 
> > 
> > 


Reply via email to