[PATCH 04 of 11 v2] localrepo: decorate dirstate() with filecache

Idan Kamara idankk86 at gmail.com
Mon Jul 25 07:09:11 CDT 2011


# HG changeset patch
# User Idan Kamara <idankk86 at gmail.com>
# Date 1311595717 -10800
# Node ID 5a728dc76ad8ec3be9bdce47e24a0157997f3a00
# Parent  dfba7752392c9e7af6792ed337040b70d48d1fac
localrepo: decorate dirstate() with filecache

We refresh the stat info when releasing repo.wlock(), right after writing it.

Also, invalidate the dirstate by deleting its attribute. This will force a
stat by the decorator that actually checks if anything changed, rather than
reading it again every time.

Note that prior to this, there was a single dirstate instance created for a
localrepo. It was invalidated by calling dirstate.invalidated(), clearing
its internal attributes.

As a consequence, the following construct is no longer safe:

  ds = repo.dirstate # keep a reference to the repo's dirstate
  wlock = repo.wlock()
  try:
      ds.setparents(...)
  finally:
      wlock.release() # dirstate should be written here

Since it's possible that the dirstate was modified between lines #1 and #2,
therefore changes to the old dirstate won't get written when the lock releases,
because a new instance was created by the decorator.

diff -r dfba7752392c -r 5a728dc76ad8 mercurial/localrepo.py
--- a/mercurial/localrepo.py	Mon Jul 25 15:08:37 2011 +0300
+++ b/mercurial/localrepo.py	Mon Jul 25 15:08:37 2011 +0300
@@ -17,6 +17,7 @@
 from lock import release
 import weakref, errno, os, time, inspect
 propertycache = util.propertycache
+filecache = scmutil.filecache
 
 class localrepository(repo.repository):
     capabilities = set(('lookup', 'changegroupsubset', 'branchmap', 'pushkey',
@@ -187,7 +188,7 @@
     def manifest(self):
         return manifest.manifest(self.sopener)
 
-    @propertycache
+    @filecache('dirstate')
     def dirstate(self):
         warned = [0]
         def validate(node):
@@ -797,6 +798,20 @@
         self._branchcache = None # in UTF-8
         self._branchcachetip = None
 
+    def invalidatedirstate(self):
+        '''Invalidates the dirstate, causing the next call to dirstate
+        to check if it was modified since the last time it was read,
+        rereading it if it has.
+
+        This is different to dirstate.invalidate() that it doesn't always
+        rereads the dirstate. Use dirstate.invalidate() if you want to
+        explicitly read the dirstate again (i.e. restoring it to a previous
+        known good state).'''
+        try:
+            delattr(self, 'dirstate')
+        except AttributeError:
+            pass
+
     def invalidate(self):
         for a in ("changelog", "manifest", "_bookmarks", "_bookmarkcurrent"):
             if a in self.__dict__:
@@ -841,8 +856,14 @@
             l.lock()
             return l
 
-        l = self._lock(self.join("wlock"), wait, self.dirstate.write,
-                       self.dirstate.invalidate, _('working directory of %s') %
+        def unlock():
+            self.dirstate.write()
+            ce = self._filecache.get('dirstate')
+            if ce:
+                ce.refresh()
+
+        l = self._lock(self.join("wlock"), wait, unlock,
+                       self.invalidatedirstate, _('working directory of %s') %
                        self.origroot)
         self._wlockref = weakref.ref(l)
         return l


More information about the Mercurial-devel mailing list