caching: recreate mfctx instead of reusing

Summary:
The upstream manifestctx class has changed to keep a reference to the
manifestlog instead of to the repo. This means that if we access an old mfctx
after repo.manifestlog has been invalidated, it will still have a reference to
the old manifestlog and the old manifestrevlog.

This created a bug where writes would fail because they saw the old
manifestrevlog, and even worse, they would truncate the manifest revlog back to
the last state that process had seen it (i.e. from before the latest db sync),
instead of truncating just the writes done by this transaction.

Test Plan:
I copied it to a server that had issues before the change, and
verified that it no longer truncated the manifest revlog incorrectly.  I'm still
trying to think how I could reproduce the issue in a test.

Reviewers: #mercurial, phillco

Reviewed By: phillco

Differential Revision: https://phabricator.intern.facebook.com/D4789920

Signature: t1:4789920:1490735433:187e8b22d7ce89bfb2f88d9fc3c9932842bab4f8
This commit is contained in:
Durham Goode 2017-03-28 14:48:49 -07:00
parent 92eadab685
commit 5b35b8b9b1

View File

@ -657,8 +657,16 @@ def wraprepo(repo):
self._filecache.pop('manifestlog', None)
self._filecache.pop('_phasecache', None)
# Refill the cache
self.manifestlog._dirmancache = oldmancache
# Refill the cache. We can't just reuse the exact contents of
# the old cached ctx, since the old ctx contains a reference to
# the old revlog, which is now out of date.
mfl = self.manifestlog
for dirname, lrucache in oldmancache.iteritems():
if dirname == '':
for oldmfnode in lrucache:
oldmfctx = lrucache[oldmfnode]
if oldmfctx._data is not None:
mfl[oldmfnode]._data = oldmfctx._data
heads = set(self.heads())
heads.discard(nullid)