[PATCH STABLE RFC] transplant: avoid a dirstate race when transplanting multiple changesets
Matt Mackall
mpm at selenic.com
Thu Jan 27 18:40:40 UTC 2011
On Thu, 2011-01-27 at 09:44 -0500, Greg Ward wrote:
> On Wed, Jan 26, 2011 at 6:56 PM, Matt Mackall <mpm at selenic.com> wrote:
> > So usually after update or commit, we mark a file in state 'normal',
> > which records the current time in the dirstate.
> >
> > If the file then gets modified in the same second without the size
> > changing, then the next commit -in the same process- could miss the
> > change.
>
> That's my understanding.
>
> > But if we actually write out the dirstate, we blank out the timestamp of
> > any files where timestamp matches a window around the current second,
> > which is like the normallookup state but only for files inside the risk
> > window.
>
> Ahhh, that explains why my first dimly-understood attempt at fixing
> the bug (dirstate.write() after each commit() in transplant) worked.
> That was just a bigger hammer than calling normallookup() on each file
> known to be modified by the transplanted changeset.
>
> Unfortunately, I'm having a hard time writing a little standalone
> Python script to reproduce the (alleged) bug. Here's what I have so
> far:
>
> """
> from mercurial import ui, hg, match, node
>
> def replacebyte(fn, b):
> f = open("file1", "rb+")
> f.seek(0, 0)
> f.write(b)
> f.close()
>
> repo = hg.repository(ui.ui(), '.')
> print "before commit 1:", repo.dirstate._map['file1']
> m = match.exact(repo.root, '', ['file1'])
> replacebyte("file1", "x")
> n = repo.commit(text="x", user="test", date=(0, 0), match=m)
> print len(repo) - 1
> print "after commit 1:", repo.dirstate._map['file1']
> replacebyte("file1", "y")
> n = repo.commit(text="y", user="test", date=(0, 0), match=m)
> print len(repo) - 1
> print "after commit 2:", repo.dirstate._map['file1']
> """
>
> This is meant to be run at the end of the current
> test-transplant-multiple.t: i.e. we are already in a repo that's
> tracking 'file1'.
>
> The above is *supposed* to be an abstraction of what transplant does
> to expose the bug, but it doesn't work. The two committed changesets
> are fine. Huh. Any clue what I'm missing?
I suspect it's related to locking. I think transplant holds a lock
across multiple commits, which means it's not writing and reloading the
dirstate.
--
Mathematics is the supreme nostalgia of our time.
More information about the Mercurial-devel
mailing list