fncachestore: defer updating the fncache file to a single file open
Defers updating the fncache file with newly added entries to the end of
the transaction (on e.g. pull), doing a single open call on the fncache
file, instead of opening and closing it each time a new entry is added
to the store.
Implemented by adding a new abstract write() function on store.basicstore
and registering it as a release function on the store lock in
localrepo.lock (compare with dirstate.write).
store.fncachestore overrides write() from basicstore and calls a new
write function on the fncache object, which writes all entries to the
fncache file if it's dirty.
store.fncache.add() now just marks itself as dirty if a new name is added.
--- a/mercurial/localrepo.py Fri Jan 28 13:34:07 2011 +0100
+++ b/mercurial/localrepo.py Fri Jan 28 13:38:34 2011 +0100
@@ -781,8 +781,8 @@
l.lock()
return l
- l = self._lock(self.sjoin("lock"), wait, None, self.invalidate,
- _('repository %s') % self.origroot)
+ l = self._lock(self.sjoin("lock"), wait, self.store.write,
+ self.invalidate, _('repository %s') % self.origroot)
self._lockref = weakref.ref(l)
return l
--- a/mercurial/store.py Fri Jan 28 13:34:07 2011 +0100
+++ b/mercurial/store.py Fri Jan 28 13:38:34 2011 +0100
@@ -213,6 +213,9 @@
def copylist(self):
return ['requires'] + _data.split()
+ def write(self):
+ pass
+
class encodedstore(basicstore):
def __init__(self, path, opener, pathjoiner):
self.pathjoiner = pathjoiner
@@ -243,10 +246,12 @@
def __init__(self, opener):
self.opener = opener
self.entries = None
+ self._dirty = False
def _load(self):
'''fill the entries from the fncache file'''
self.entries = set()
+ self._dirty = False
try:
fp = self.opener('fncache', mode='rb')
except IOError:
@@ -265,12 +270,22 @@
fp.write(encodedir(p) + '\n')
fp.close()
self.entries = set(files)
+ self._dirty = False
+
+ def write(self):
+ if not self._dirty:
+ return
+ fp = self.opener('fncache', mode='wb', atomictemp=True)
+ for p in self.entries:
+ fp.write(encodedir(p) + '\n')
+ fp.rename()
+ self._dirty = False
def add(self, fn):
if self.entries is None:
self._load()
if fn not in self.entries:
- self.opener('fncache', 'ab').write(encodedir(fn) + '\n')
+ self._dirty = True
self.entries.add(fn)
def __contains__(self, fn):
@@ -328,6 +343,9 @@
return (['requires', '00changelog.i'] +
[self.pathjoiner('store', f) for f in d.split()])
+ def write(self):
+ self.fncache.write()
+
def store(requirements, path, opener, pathjoiner=None):
pathjoiner = pathjoiner or os.path.join
if 'store' in requirements: