[PATCH 2 of 8] changelog: add cache for abandoned
Matt Mackall
mpm at selenic.com
Wed Jun 1 12:04:35 CDT 2011
On Wed, 2011-06-01 at 18:42 +0200, Martin Geisler wrote:
> # HG changeset patch
> # User Martin Geisler <mg at lazybytes.net>
> # Date 1306945890 -7200
> # Node ID 9095768d8e9fd1278cbf4ed6dfd88f595968926f
> # Parent 9b14fa930acae9dc802d7cec87780ba1a3a9aa8b
> changelog: add cache for abandoned
>
> Some issues:
>
> * The cache is written inside the store...
Why is this cache any different than the branch cache?
> * The delaywriter stuff changelog does was not prepared for creating
> a file with atomictemp=True.
>
> Perhaps this suggests that localrepo.heads should be the one that
> maintains the cache. Most of the code calls repo.heads and not
> repo.changelog.heads, so this would speedup those calls. However,
> discovery uses repo.changelog so that might give problems.
>
> The cache maps each abandoned node to the node that abandoned it.
>
> Changes perfabandoned from
>
> ! wall 0.095847 comb 0.090000 user 0.090000 sys 0.000000 (best of 100)
>
> to
>
> ! wall 0.000004 comb 0.000000 user 0.000000 sys 0.000000 (best of 345012)
>
> on the OpenOffice repository with 276,000 changesets.
>
> diff --git a/mercurial/changelog.py b/mercurial/changelog.py
> --- a/mercurial/changelog.py
> +++ b/mercurial/changelog.py
> @@ -5,7 +5,7 @@
> # This software may be used and distributed according to the terms of the
> # GNU General Public License version 2 or any later version.
>
> -from node import bin, hex, nullid
> +from node import bin, hex, nullid, short
> from i18n import _
> import util, error, revlog, encoding
>
> @@ -88,13 +88,13 @@
> self.offset += len(s)
>
> def delayopener(opener, target, divert, buf):
> - def o(name, mode='r'):
> + def o(name, mode='r', text=False, atomictemp=False):
> if name != target:
> - return opener(name, mode)
> + return opener(name, mode, text, atomictemp)
> if divert:
> - return opener(name + ".a", mode.replace('a', 'w'))
> + return opener(name + ".a", mode.replace('a', 'w'), text, atomictemp)
> # otherwise, divert to memory
> - return appender(opener(name, mode), buf)
> + return appender(opener(name, mode, text, atomictemp), buf)
> return o
>
> class changelog(revlog.revlog):
> @@ -107,6 +107,8 @@
> self._realopener = opener
> self._delayed = False
> self._divert = False
> + self._abandonedcache = {}
> + self._abandonedtip = nullid
>
> def delayupdate(self):
> "delay visibility of index updates to other readers"
> @@ -241,23 +243,92 @@
> text = "\n".join(l)
> return self.addrevision(text, transaction, len(self), p1, p2)
>
> + def _readabandonedcache(self, tip):
> + import os
> + if 'DEBUG' in os.environ:
> + print ' reading abandoned cache for', short(tip)
> + abandoned = {}
> + try:
> + f = self.opener("cache/abandoned")
> + lasttip = bin(f.readline().strip())
> + if 'DEBUG' in os.environ:
> + print ' our tip: ', short(tip)
> + print ' last tip:', short(lasttip)
> +
> + if tip != lasttip:
> + # stale cache
> + f.close()
> + return None
> +
> + for line in f:
> + node, abandoner = line.strip().split()[:2]
> + abandoned[bin(node)] = bin(abandoner)
> + f.close()
> + if 'DEBUG' in os.environ:
> + print ' read up-to-date abandoned cache for', short(lasttip)
> + for k, v in abandoned.iteritems():
> + print ' ', short(k), '->', short(v)
> + return abandoned
> + except (IOError, OSError), inst:
> + if 'DEBUG' in os.environ:
> + print ' error while reading abandoned cache:'
> + print ' ', inst
> + return None
> +
> + def _writeabandonedcache(self, lasttip, abandoned):
> + import os
> + if 'DEBUG' in os.environ:
> + print ' writing abandoned cache for', short(lasttip)
> + for k, v in abandoned.iteritems():
> + print ' ', short(k)[:12], '->', short(v)
> +
> + try:
> + # TODO: this creates the cache in
> + # .hg/store/cache/abandoned.
> + f = self.opener("cache/abandoned", "w", atomictemp=True)
> + f.write("%s\n" % hex(lasttip))
> + for node, abandoner in abandoned.iteritems():
> + f.write("%s %s\n" % (hex(node), hex(abandoner)))
> + f.rename()
> + except (IOError, OSError), inst:
> + if 'DEBUG' in os.environ:
> + print ' error while writing abandoned cache:', inst
> + pass
> +
> + def updateabandonedcache(self):
> + import os
> + tip = self.tip()
> + if tip == self._abandonedtip:
> + if 'DEBUG' in os.environ:
> + print 'no need to update cache'
> + return
> +
> + if 'DEBUG' in os.environ:
> + print 'must update cache'
> +
> + abandoned = self._readabandonedcache(tip)
> + if abandoned is None:
> + if 'DEBUG' in os.environ:
> + print 'found no cache on disk, rebuilding'
> + # no suitable cache found on disk, recompute
> + abandoned = {}
> + for head in self.heads():
> + extra = self.read(head)[5]
> + if 'abandon' in extra:
> + for node in extra['abandon'].split(' '):
> + abandoned[bin(node)] = head
> + abandoned[head] = head
> +
> + for node in abandoned.copy():
> + for head in self.heads():
> + if (head not in abandoned and self.ancestor(head, node) == node):
> + del abandoned[node]
> +
> + self._writeabandonedcache(tip, abandoned)
> +
> + self._abandonedcache = abandoned
> + self._abandonedtip = tip
> +
> def abandoned(self, node):
> - # TODO: need cache
> - abandoned = set()
> -
> - for head in self.heads():
> - extra = self.read(head)[5]
> - if 'abandon' in extra:
> - abandoned.update(map(bin, extra['abandon'].split(' ')))
> - abandoned.add(head)
> -
> - if node in abandoned:
> - for head in self.heads():
> - if head not in abandoned and self.ancestor(head, node) == node:
> - return None
> -
> - return [h for h in self.heads() if
> - hex(node) in self.read(h)[5].get('abandon', '').split(' ')
> - or node == h][0]
> -
> - return None
> + self.updateabandonedcache()
> + return self._abandonedcache.get(node)
> diff --git a/tests/test-abandoned.t b/tests/test-abandoned.t
> --- a/tests/test-abandoned.t
> +++ b/tests/test-abandoned.t
> @@ -39,6 +39,11 @@
> $ hg log
> 0 54dbcd775ef0 init
>
> + $ cat .hg/store/cache/abandoned
> + 339976ff501061539429787f2d34c191ba2f426d
> + 339976ff501061539429787f2d34c191ba2f426d 339976ff501061539429787f2d34c191ba2f426d
> + 0b00c28422ee839b7b5b2a8f0408bd804c350df2 339976ff501061539429787f2d34c191ba2f426d
> +
> $ hg log --abandoned
> 2 339976ff5010 abandoned
> 1 0b00c28422ee x
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel
--
Mathematics is the supreme nostalgia of our time.
More information about the Mercurial-devel
mailing list