localrepo: always write the filtered phasecache when nodes are destroyed (
issue3827)
When the strip command is run, it calls repo.destroyed, which in turn checks if
we read _phasecache, and if we did calls filterunknown on it and flushes the
changes immediately. But in some cases, nothing causes _phasecache to be read,
so we miss out on this and the file remains the same on-disk.
Then a call to invalidate comes, which should refresh _phasecache if it
changed, but it didn't, so it keeps using the old one with the stripped
revision which causes an IndexError.
Test written by Yuya Nishihara.
--- a/mercurial/localrepo.py Tue Mar 19 16:19:20 2013 -0700
+++ b/mercurial/localrepo.py Sat Mar 23 13:34:50 2013 +0200
@@ -1416,9 +1416,8 @@
# removed. We can either remove phasecache from the filecache,
# causing it to reload next time it is accessed, or simply filter
# the removed nodes now and write the updated cache.
- if '_phasecache' in self._filecache:
- self._phasecache.filterunknown(self)
- self._phasecache.write()
+ self._phasecache.filterunknown(self)
+ self._phasecache.write()
# update the 'served' branch cache to help read only server process
# Thanks to branchcach collaboration this is done from the nearest
--- a/tests/test-commandserver.py Tue Mar 19 16:19:20 2013 -0700
+++ b/tests/test-commandserver.py Sat Mar 23 13:34:50 2013 +0200
@@ -236,6 +236,27 @@
f.close()
runcommand(server, ['status', '-i', '-u'])
+def phasecacheafterstrip(server):
+ readchannel(server)
+
+ # create new head, 5:731265503d86
+ runcommand(server, ['update', '-C', '0'])
+ f = open('a', 'ab')
+ f.write('a\n')
+ f.close()
+ runcommand(server, ['commit', '-Am.', 'a'])
+ runcommand(server, ['log', '-Gq'])
+
+ # make it public; draft marker moves to 4:7966c8e3734d
+ runcommand(server, ['phase', '-p', '.'])
+ runcommand(server, ['phase', '.']) # load _phasecache.phaseroots
+
+ # strip 1::4 outside server
+ os.system('hg --config extensions.mq= strip 1')
+
+ # shouldn't raise "7966c8e3734d: no node!"
+ runcommand(server, ['branches'])
+
if __name__ == '__main__':
os.system('hg init')
@@ -258,3 +279,4 @@
check(rollback)
check(branch)
check(hgignore)
+ check(phasecacheafterstrip)
--- a/tests/test-commandserver.py.out Tue Mar 19 16:19:20 2013 -0700
+++ b/tests/test-commandserver.py.out Sat Mar 23 13:34:50 2013 +0200
@@ -164,3 +164,29 @@
adding .hgignore
runcommand status -i -u
I ignored-file
+
+testing phasecacheafterstrip:
+
+ runcommand update -C 0
+1 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ runcommand commit -Am. a
+created new head
+ runcommand log -Gq
+@ 5:731265503d86
+|
+| o 4:7966c8e3734d
+| |
+| o 3:b9b85890c400
+| |
+| o 2:aef17e88f5f0
+| |
+| o 1:d3a0a68be6de
+|/
+o 0:eff892de26ec
+
+ runcommand phase -p .
+ runcommand phase .
+5: public
+saved backup bundle to $TESTTMP/.hg/strip-backup/d3a0a68be6de-backup.hg
+ runcommand branches
+default 1:731265503d86