Patchwork [07,of,12] localrepo: don't clear filecache on _rollback and destroyed (issue3335) (issue3693)

login
register
mail settings
Submitter Idan Kamara
Date Dec. 17, 2012, 3:35 p.m.
Message ID <92641ad93e4cbb3e570a.1355758532@idan>
Download mbox | patch
Permalink /patch/161/
State Changes Requested, archived
Headers show

Comments

Idan Kamara - Dec. 17, 2012, 3:35 p.m.
# HG changeset patch
# User Idan Kamara <idankk86 at gmail.com>
# Date 1355689904 -7200
# Branch stable
# Node ID 92641ad93e4cbb3e570a6630d5ded31db3b1bec3
# Parent  15e21c2dbb278e679418782a30047b02f69dc6af
localrepo: don't clear filecache on _rollback and destroyed (issue3335) (issue3693)

We need to make sure that if X is in the filecache then it's also in the
filecache owner's __dict__, otherwise it will go out of sync:

repo.X                  # first access to X, records stat info in filecache and updates __dict__
repo._filecache.clear() # removes X from _filecache but it's still in __dict__
repo.invalidate()       # iterates over _filecache and removes entries from __dict__
                        # but X isn't in _filecache, so it's kept in __dict__
repo.X                  # X is fetched from __dict__, bypassing the filecache

Patch

diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -1005,9 +1005,6 @@ 
                         self.sjoin('phaseroots'))
         self.invalidate()
 
-        # Discard all cache entries to force reloading everything.
-        self._filecache.clear()
-
         parentgone = (parents[0] not in self.changelog.nodemap or
                       parents[1] not in self.changelog.nodemap)
         if parentgone:
@@ -1542,10 +1539,7 @@ 
         # head, refresh the tag cache, then immediately add a new head.
         # But I think doing it this way is necessary for the "instant
         # tag cache retrieval" case to work.
-        self.invalidatecaches()
-
-        # Discard all cache entries to force reloading everything.
-        self._filecache.clear()
+        self.invalidate()
 
     def walk(self, match, node=None):
         '''
diff --git a/tests/test-filecache.py b/tests/test-filecache.py
--- a/tests/test-filecache.py
+++ b/tests/test-filecache.py
@@ -4,7 +4,7 @@ 
                     'cacheable']):
     sys.exit(80)
 
-from mercurial import util, scmutil, extensions
+from mercurial import util, scmutil, extensions, hg, ui
 
 filecache = scmutil.filecache
 
@@ -86,6 +86,21 @@ 
     util.cachestat.cacheable = origcacheable
     util.cachestat.__init__ = originit
 
+def test_filecache_synced():
+    # test old behaviour that caused filecached properties to go out of sync
+    os.system('hg init && echo a >> a && hg ci -qAm.')
+    repo = hg.repository(ui.ui())
+    # first rollback clears the filecache, but changelog to stays in __dict__
+    repo.rollback()
+    repo.commit('.')
+    # second rollback comes along and touches the changelog externally
+    # (file is moved)
+    repo.rollback()
+    # but since changelog isn't under the filecache control anymore, we don't
+    # see that it changed, and return the old changelog without reconstructing
+    # it
+    repo.commit('.')
+
 print 'basic:'
 print
 basic(fakerepo())
@@ -93,3 +108,4 @@ 
 print 'fakeuncacheable:'
 print
 fakeuncacheable()
+test_filecache_synced()
diff --git a/tests/test-filecache.py.out b/tests/test-filecache.py.out
--- a/tests/test-filecache.py.out
+++ b/tests/test-filecache.py.out
@@ -13,3 +13,7 @@ 
 creating
 creating
 creating
+repository tip rolled back to revision -1 (undo commit)
+working directory now based on revision -1
+repository tip rolled back to revision -1 (undo commit)
+working directory now based on revision -1