[issue2137] API: after unbundle, repo.lookup() does not recognized added changeset IDs
Greg Ward
greg-hg at gerg.ca
Tue Apr 13 17:11:27 CDT 2010
On Tue, Apr 13, 2010 at 3:19 PM, Greg Ward <bugs at mercurial.selenic.com> wrote:
>
> New submission from Greg Ward <greg-hg at gerg.ca>:
[...]
> In certain circumstances, the push to target finds no outgoing changesets
> even though unbundle really did add changesets to tmptarget. At a high
> level, I can illustrate the problem like this:
>
> tip1 = hgnode.short(tmptarget.changelog.tip())
> tip2 = hgnode.short(tmptarget.lookup(tip1))
> assert tip1 == tip2
>
> This actually never gets to the assert -- it raises RepoLookupError in the
> call to tmptarget.lookup(tmp1), which seems like a violation of some pretty
> basic contracts.
>
> I'm still digging. Will post more when I have more info and (hopefully) a
> reproduction script.
OK, I can reproduce this with a tiny repo and a fairly small Python
script. The catch is that I have to
1) monkeypatch revlog and set _prereadsize to a small value
2) really patch revlog.py and modify checkinlinesize() so it splits
out 00changelog.d much earlier (like, after 128 bytes instead of 128
kiB)
This is my patch to revlog.py:
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -1010,7 +1010,7 @@
return text
def checkinlinesize(self, tr, fp=None):
- if not self._inline or (self.start(-2) + self.length(-2)) < 131072:
+ if not self._inline or (self.start(-2) + self.length(-2)) < 128:
return
trinfo = tr.find(self.indexfile)
Obviously, a small refactoring here would let me tweak that by
monkeypatching, meaning I could reproduce this problem cleanly.
And here is the Python script that demonstrates the problem:
"""
#!/usr/bin/python
# attempt to reproduce hg issue 2137 (revlog not properly updated after
# unbundle, causing repo.lookup() to fail spuriously)
import sys
from mercurial import ui as hgui, hg, commands, node as hgnode, error, revlog
(path, bundle) = sys.argv[1:3]
revlog._prereadsize = 128
ui = hgui.ui()
ui.setconfig('ui', 'verbose', 'true')
#ui.setconfig('ui', 'debug', 'true')
ui.write('opening %s\n' % path)
repo = hg.repository(ui, path)
cl = repo.changelog
ui.write('initial sanity check\n')
assert len(repo) == len(repo.changelog.index) - 1 == repo.changelog.nodemap.p.l
tip = cl.tip()
assert repo.lookup(hgnode.short(tip)) == tip
# apply the bundle
ui.write('applying bundle\n')
commands.unbundle(ui, repo, bundle, update=False)
# demonstrate the bug: first, expose the low-level problem (changelog's
# nodemap has two different idea's of the changelog's length)
ui.write('testing for the bug\n')
cl = repo.changelog
if cl.nodemap.p.l == len(repo):
print "PASS: cl.nodemap.p.l == len(repo) == %d" % len(repo)
else:
print "FAIL: len(repo) == %d, cl.nodemap.p.l == %d" \
% (len(repo), cl.nodemap.p.l)
# and demonstrate it again the high-level way: looking up the abbreviated
# changeset ID of a changeset that is known to be in the changelog fails
tip1 = cl.tip()
try:
tip2 = repo.lookup(hgnode.short(tip1))
assert tip1 == tip2
print "PASS: looked up tip two ways and got consistent results"
except error.RepoLookupError:
print "FAIL: failed to lookup abbreviated changeset ID of tip"
"""
I'll have a real test script shortly.
Greg
More information about the Mercurial-devel
mailing list