Patchwork [7,of,7,V2] fncache: clean up fncache during strips

login
register
mail settings
Submitter Durham Goode
Date March 31, 2014, 11:19 p.m.
Message ID <cd31386f635937bb2d0a.1396307989@dev2000.prn2.facebook.com>
Download mbox | patch
Permalink /patch/4174/
State Superseded
Commit f49d60fa40a589e5d5fa26a476f9eb3c23767551
Headers show

Comments

Durham Goode - March 31, 2014, 11:19 p.m.
# HG changeset patch
# User Durham Goode <durham@fb.com>
# Date 1395700995 25200
#      Mon Mar 24 15:43:15 2014 -0700
# Node ID cd31386f635937bb2d0a19e737d73b5098623ec6
# Parent  013a9a420cdfcf7b74e453f55e451db2ea889d15
fncache: clean up fncache during strips

Previously the fncache was cleaned up at read time by noticing when it was out
of sync. This caused writes to happen outside the scope of transactions and
could have caused race conditions. With this change, we'll keep the fncache
up-to-date as we go by removing old entries during repair.strip.
Pierre-Yves David - April 1, 2014, 1:39 a.m.
On 03/31/2014 04:19 PM, Durham Goode wrote:
> +    def remove(self, fn):
> +        if self.entries is None:
> +            self._load()
> +        if fn in self.entries:
> +            self._dirty = True
> +            self.entries.remove(fn)

You can same the double lookup by using exception catching.

Not sure if this is faster.
Matt Mackall - April 1, 2014, 11:50 p.m.
On Mon, 2014-03-31 at 18:39 -0700, Pierre-Yves David wrote:
> 
> On 03/31/2014 04:19 PM, Durham Goode wrote:
> > +    def remove(self, fn):
> > +        if self.entries is None:
> > +            self._load()
> > +        if fn in self.entries:
> > +            self._dirty = True
> > +            self.entries.remove(fn)
> 
> You can same the double lookup by using exception catching.
> 
> Not sure if this is faster.

It's not. It's actually faster to do a name lookup than to set up an
exception frame.

Patch

diff --git a/mercurial/repair.py b/mercurial/repair.py
--- a/mercurial/repair.py
+++ b/mercurial/repair.py
@@ -134,6 +134,8 @@ 
             for i in xrange(offset, len(tr.entries)):
                 file, troffset, ignore = tr.entries[i]
                 repo.sopener(file, 'a').truncate(troffset)
+                if troffset == 0:
+                    repo.store.markremoved(file)
             tr.close()
         except: # re-raises
             tr.abort()
diff --git a/mercurial/store.py b/mercurial/store.py
--- a/mercurial/store.py
+++ b/mercurial/store.py
@@ -343,6 +343,9 @@ 
     def invalidatecaches(self):
         pass
 
+    def markremoved(self, fn):
+        pass
+
     def __contains__(self, path):
         '''Checks if the store contains path'''
         path = "/".join(("data", path))
@@ -421,6 +424,13 @@ 
             self._dirty = True
             self.entries.add(fn)
 
+    def remove(self, fn):
+        if self.entries is None:
+            self._load()
+        if fn in self.entries:
+            self._dirty = True
+            self.entries.remove(fn)
+
     def __contains__(self, fn):
         if self.entries is None:
             self._load()
@@ -495,6 +505,9 @@ 
     def invalidatecaches(self):
         self.fncache.entries = None
 
+    def markremoved(self, fn):
+        self.fncache.remove(fn)
+
     def _exists(self, f):
         ef = self.encode(f)
         try:
diff --git a/tests/test-strip.t b/tests/test-strip.t
--- a/tests/test-strip.t
+++ b/tests/test-strip.t
@@ -336,6 +336,19 @@ 
   saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
   $ restore
 
+verify fncache is kept up-to-date
+
+  $ touch a
+  $ hg ci -qAm a
+  $ cat .hg/store/fncache | sort
+  data/a.i
+  data/bar.i
+  $ hg strip tip
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
+  $ cat .hg/store/fncache
+  data/bar.i
+
 stripping an empty revset
 
   $ hg strip "1 and not 1"