Patchwork [STABLE] localrepo: always write the filtered phasecache when nodes are destroyed (issue3827)

login
register
mail settings
Submitter Idan Kamara
Date March 23, 2013, 11:35 a.m.
Message ID <4797cd3fdd351f18314f.1364038554@idan>
Download mbox | patch
Permalink /patch/1174/
State Accepted
Commit 1c8e0d6ac3b0269a409caf40a23cc83569ce9474
Headers show

Comments

Idan Kamara - March 23, 2013, 11:35 a.m.
# HG changeset patch
# User Idan Kamara <idankk86@gmail.com>
# Date 1364038490 -7200
#      Sat Mar 23 13:34:50 2013 +0200
# Node ID 4797cd3fdd351f18314fc8fd8e475afe2c748539
# Parent  ac0336471ba766cc3c1234473e75d4478819e50d
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.

Patch

diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -1407,9 +1407,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 branchcache collaboration this is done from the nearest
diff --git a/tests/test-commandserver.py b/tests/test-commandserver.py
--- a/tests/test-commandserver.py
+++ b/tests/test-commandserver.py
@@ -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)
diff --git a/tests/test-commandserver.py.out b/tests/test-commandserver.py.out
--- a/tests/test-commandserver.py.out
+++ b/tests/test-commandserver.py.out
@@ -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