##// END OF EJS Templates
compression: introduce a `storage.revlog.zlib.level` configuration...
compression: introduce a `storage.revlog.zlib.level` configuration This option control the zlib compression level used when compression revlog chunk. This is also a good excuse to pave the way for a similar configuration option for the zstd compression engine. Having a dedicated option for each compression algorithm is useful because they don't support the same range of values. Using a higher zlib compression impact CPU consumption at compression time, but does not directly affected decompression time. However dealing with small compressed chunk can directly help decompression and indirectly help other revlog logic. I ran some basic test on repositories using different level. I am using the mercurial, pypy, netbeans and mozilla-central clone from our benchmark suite. All tested repository use sparse-revlog and got all their delta recomputed. The different compression level has a small effect on the repository size (about 10% variation in the total range). My quick analysis is that revlog mostly store small delta, that are not affected by the compression level much. So the variation probably mostly comes from better compression of the snapshots revisions, and snapshot revision only represent a small portion of the repository content. I also made some basic timings measurements. The "read" timings are gathered using simple run of `hg perfrevlogrevisions`, the "write" timings using `hg perfrevlogwrite` (restricted to the last 5000 revisions for netbeans and mozilla central). The timings are gathered on a generic machine, (not one of our performance locked machine), so small variation might not be meaningful. However large trend remains relevant. Keep in mind that these numbers are not pure compression/decompression time. They also involve the full revlog logic. In particular the difference in chunk size has an impact on the delta chain structure, affecting performance when writing or reading them. On read/write performance, the compression level has a bigger impact. Counter-intuitively, the higher compression levels improve "write" performance for the large repositories in our tested setting. Maybe because the last 5000 delta chain end up having a very different shape in this specific spot? Or maybe because of a more general trend of better delta chains thanks to the smaller chunk and snapshot. This series does not intend to change the default compression level. However, these result call for a deeper analysis of this performance difference in the future. Full data ========= repo level .hg/store size 00manifest.d read write ---------------------------------------------------------------- mercurial 1 49,402,813 5,963,475 0.170159 53.250304 mercurial 6 47,197,397 5,875,730 0.182820 56.264320 mercurial 9 47,121,596 5,849,781 0.189219 56.293612 pypy 1 370,830,572 28,462,425 2.679217 460.721984 pypy 6 340,112,317 27,648,747 2.768691 467.537158 pypy 9 338,360,736 27,639,003 2.763495 476.589918 netbeans 1 1,281,847,810 165,495,457 122.477027 520.560316 netbeans 6 1,205,284,353 159,161,207 139.876147 715.930400 netbeans 9 1,197,135,671 155,034,586 141.620281 678.297064 mozilla 1 2,775,497,186 298,527,987 147.867662 751.263721 mozilla 6 2,596,856,420 286,597,671 170.572118 987.056093 mozilla 9 2,587,542,494 287,018,264 163.622338 739.803002

File last commit:

r39865:28626957 default
r42210:1fac9b93 default
Show More
gnuarch.py
357 lines | 12.8 KiB | text/x-python | PythonLexer
Martin Geisler
convert: add copyright and license headers to back-ends
r8250 # gnuarch.py - GNU Arch support for the convert extension
#
# Copyright 2008, 2009 Aleix Conchillo Flaque <aleix@member.fsf.org>
# and others
#
# This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
timeless
convert: gnuarch use absolute_import
r28366 from __future__ import absolute_import
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
Pulkit Goyal
py3: use email.parser module to parse email messages...
r35651 import email.parser as emailparser
timeless
convert: gnuarch use absolute_import
r28366 import os
import shutil
import stat
import tempfile
Yuya Nishihara
py3: move up symbol imports to enforce import-checker rules...
r29205
from mercurial.i18n import _
timeless
convert: gnuarch use absolute_import
r28366 from mercurial import (
encoding,
error,
Matt Harbison
py3: convert arguments, cwd and env to native strings when spawning subprocess...
r39851 pycompat,
Matt Harbison
convert: fix a file descriptor leak...
r39865 util,
timeless
convert: gnuarch use absolute_import
r28366 )
Yuya Nishihara
procutil: bulk-replace function calls to point to new module
r37138 from mercurial.utils import (
dateutil,
procutil,
)
timeless
convert: gnuarch use absolute_import
r28366 from . import common
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
timeless
convert: gnuarch use absolute_import
r28366 class gnuarch_source(common.converter_source, common.commandline):
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
Benoit Boissinot
use new style classes
r8778 class gnuarch_rev(object):
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 def __init__(self, rev):
self.rev = rev
self.summary = ''
self.date = None
self.author = ''
Edouard Gomez
convert/gnuarch: parse continuation-of revisions in gnuarch source...
r7583 self.continuationof = None
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 self.add_files = []
self.mod_files = []
self.del_files = []
self.ren_files = {}
self.ren_dirs = {}
Matt Harbison
convert: save an indicator of the repo type for sources and sinks...
r35168 def __init__(self, ui, repotype, path, revs=None):
super(gnuarch_source, self).__init__(ui, repotype, path, revs=revs)
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
if not os.path.exists(os.path.join(path, '{arch}')):
timeless
convert: gnuarch use absolute_import
r28366 raise common.NoRepo(_("%s does not look like a GNU Arch repository")
Martin Geisler
convert: write "repository" instead of "repo"...
r10938 % path)
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
# Could use checktool, but we want to check for baz or tla.
self.execmd = None
Yuya Nishihara
procutil: bulk-replace function calls to point to new module
r37138 if procutil.findexe('baz'):
Patrick Mezard
convert: detect baz before tla...
r6083 self.execmd = 'baz'
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 else:
Yuya Nishihara
procutil: bulk-replace function calls to point to new module
r37138 if procutil.findexe('tla'):
Patrick Mezard
convert: detect baz before tla...
r6083 self.execmd = 'tla'
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 else:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_('cannot find a GNU Arch tool'))
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
timeless
convert: gnuarch use absolute_import
r28366 common.commandline.__init__(self, ui, self.execmd)
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
Matt Mackall
backout dbdb777502dc (issue3077) (issue3071)...
r15381 self.path = os.path.realpath(path)
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 self.tmppath = None
self.treeversion = None
self.lastrev = None
self.changes = {}
self.parents = {}
self.tags = {}
Pulkit Goyal
py3: use email.parser module to parse email messages...
r35651 self.catlogparser = emailparser.Parser()
Brodie Rao
convert: use encoding.encoding instead of locale.getpreferredencoding()...
r11987 self.encoding = encoding.encoding
Edouard Gomez
convert/gnuarch: retrieve known archive names list...
r7584 self.archives = []
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
def before(self):
Edouard Gomez
convert/gnuarch: retrieve known archive names list...
r7584 # Get registered archives
self.archives = [i.rstrip('\n')
for i in self.runlines0('archives', '-n')]
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 if self.execmd == 'tla':
output = self.run0('tree-version', self.path)
else:
output = self.run0('tree-version', '-d', self.path)
self.treeversion = output.strip()
# Get name of temporary directory
version = self.treeversion.split('/')
self.tmppath = os.path.join(tempfile.gettempdir(),
'hg-%s' % version[1])
# Generate parents dictionary
Edouard Gomez
convert/gnuarch: follow continuation-of revisions...
r7585 self.parents[None] = []
treeversion = self.treeversion
child = None
while treeversion:
self.ui.status(_('analyzing tree version %s...\n') % treeversion)
archive = treeversion.split('/')[0]
if archive not in self.archives:
Martin Geisler
convert/gnuarch: wrap long line, format kwargs without spaces
r8662 self.ui.status(_('tree analysis stopped because it points to '
'an unregistered archive %s...\n') % archive)
Edouard Gomez
convert/gnuarch: follow continuation-of revisions...
r7585 break
# Get the complete list of revisions for that tree version
output, status = self.runlines('revisions', '-r', '-f', treeversion)
Mads Kiilerich
fix trivial spelling errors
r17424 self.checkexit(status, 'failed retrieving revisions for %s'
Matt Mackall
many, many trivial check-code fixups
r10282 % treeversion)
Edouard Gomez
convert/gnuarch: follow continuation-of revisions...
r7585
# No new iteration unless a revision has a continuation-of header
treeversion = None
for l in output:
rev = l.strip()
self.changes[rev] = self.gnuarch_rev(rev)
self.parents[rev] = []
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
Edouard Gomez
convert/gnuarch: follow continuation-of revisions...
r7585 # Read author, date and summary
catlog, status = self.run('cat-log', '-d', self.path, rev)
if status:
catlog = self.run0('cat-archive-log', rev)
self._parsecatlog(catlog, rev)
# Populate the parents map
self.parents[child].append(rev)
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
Edouard Gomez
convert/gnuarch: follow continuation-of revisions...
r7585 # Keep track of the current revision as the child of the next
# revision scanned
child = rev
# Check if we have to follow the usual incremental history
# or if we have to 'jump' to a different treeversion given
# by the continuation-of header.
if self.changes[rev].continuationof:
Matt Mackall
many, many trivial check-code fixups
r10282 treeversion = '--'.join(
self.changes[rev].continuationof.split('--')[:-1])
Edouard Gomez
convert/gnuarch: follow continuation-of revisions...
r7585 break
# If we reached a base-0 revision w/o any continuation-of
# header, it means the tree history ends here.
if rev[-6:] == 'base-0':
break
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
def after(self):
Martin Geisler
do not attempt to translate ui.debug output
r9467 self.ui.debug('cleaning up %s\n' % self.tmppath)
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 shutil.rmtree(self.tmppath, ignore_errors=True)
def getheads(self):
return self.parents[None]
def getfile(self, name, rev):
if rev != self.lastrev:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_('internal calling inconsistency'))
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
Patrick Mezard
Use lexists() instead of exists() where appropriate
r12344 if not os.path.lexists(os.path.join(self.tmppath, name)):
Mads Kiilerich
convert: use None value for missing files instead of overloading IOError...
r22296 return None, None
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
Patrick Mezard
convert: merge sources getmode() into getfile()
r11134 return self._getfile(name, rev)
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
Mads Kiilerich
convert: introduce --full for converting all files...
r22300 def getchanges(self, rev, full):
if full:
timeless@mozdev.org
grammar: use does instead of do where appropriate
r26779 raise error.Abort(_("convert from arch does not support --full"))
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 self._update(rev)
changes = []
copies = {}
for f in self.changes[rev].add_files:
changes.append((f, rev))
for f in self.changes[rev].mod_files:
changes.append((f, rev))
for f in self.changes[rev].del_files:
changes.append((f, rev))
for src in self.changes[rev].ren_files:
to = self.changes[rev].ren_files[src]
changes.append((src, rev))
changes.append((to, rev))
Patrick Mezard
convert/gnuarch: fix switched copy source and destination...
r7567 copies[to] = src
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
for src in self.changes[rev].ren_dirs:
to = self.changes[rev].ren_dirs[src]
Benoit Boissinot
fix coding style (reported by pylint)
r10394 chgs, cps = self._rendirchanges(src, to)
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 changes += [(f, rev) for f in chgs]
Patrick Mezard
convert/gnuarch: fix switched copy source and destination...
r7567 copies.update(cps)
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
self.lastrev = rev
Mads Kiilerich
convert: optimize convert of files that are unmodified from p2 in merges...
r24395 return sorted(set(changes)), copies, set()
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
def getcommit(self, rev):
changes = self.changes[rev]
timeless
convert: gnuarch use absolute_import
r28366 return common.commit(author=changes.author, date=changes.date,
desc=changes.summary, parents=self.parents[rev],
rev=rev)
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
def gettags(self):
return self.tags
def _execute(self, cmd, *args, **kwargs):
cmdline = [self.execmd, cmd]
cmdline += args
Yuya Nishihara
procutil: bulk-replace function calls to point to new module
r37138 cmdline = [procutil.shellquote(arg) for arg in cmdline]
Ross Lagerwall
util: replace util.nulldev with os.devnull...
r17391 cmdline += ['>', os.devnull, '2>', os.devnull]
Yuya Nishihara
procutil: bulk-replace function calls to point to new module
r37138 cmdline = procutil.quotecommand(' '.join(cmdline))
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 self.ui.debug(cmdline, '\n')
Matt Harbison
py3: convert arguments, cwd and env to native strings when spawning subprocess...
r39851 return os.system(pycompat.rapply(procutil.tonativestr, cmdline))
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
def _update(self, rev):
Martin Geisler
do not attempt to translate ui.debug output
r9467 self.ui.debug('applying revision %s...\n' % rev)
Edouard Gomez
convert/gnuarch: follow continuation-of revisions...
r7585 changeset, status = self.runlines('replay', '-d', self.tmppath,
rev)
if status:
# Something went wrong while merging (baz or tla
# issue?), get latest revision and try from there
shutil.rmtree(self.tmppath, ignore_errors=True)
Aleix Conchillo Flaque
convert: improve gnu arch source performance and other fixes...
r6049 self._obtainrevision(rev)
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 else:
Edouard Gomez
convert/gnuarch: follow continuation-of revisions...
r7585 old_rev = self.parents[rev][0]
Martin Geisler
do not attempt to translate ui.debug output
r9467 self.ui.debug('computing changeset between %s and %s...\n'
Edouard Gomez
convert/gnuarch: follow continuation-of revisions...
r7585 % (old_rev, rev))
self._parsechangeset(changeset, rev)
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
def _getfile(self, name, rev):
mode = os.lstat(os.path.join(self.tmppath, name)).st_mode
if stat.S_ISLNK(mode):
Matt Harbison
py3: convert os.readlink() path to native strings on Windows...
r39940 data = util.readlink(os.path.join(self.tmppath, name))
Jordi Gutiérrez Hermoso
style: kill ersatz if-else ternary operators...
r24306 if mode:
mode = 'l'
else:
mode = ''
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 else:
Matt Harbison
convert: fix a file descriptor leak...
r39865 data = util.readfile(os.path.join(self.tmppath, name))
Gregory Szorc
global: mass rewrite to use modern octal syntax...
r25658 mode = (mode & 0o111) and 'x' or ''
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 return data, mode
def _exclude(self, name):
Matt Mackall
many, many trivial check-code fixups
r10282 exclude = ['{arch}', '.arch-ids', '.arch-inventory']
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 for exc in exclude:
if name.find(exc) != -1:
return True
return False
def _readcontents(self, path):
files = []
contents = os.listdir(path)
while len(contents) > 0:
c = contents.pop()
p = os.path.join(path, c)
Aleix Conchillo Flaque
convert: do not skip some lines in gnu arch summaries
r6044 # os.walk could be used, but here we avoid internal GNU
# Arch files and directories, thus saving a lot time.
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 if not self._exclude(p):
if os.path.isdir(p):
contents += [os.path.join(c, f) for f in os.listdir(p)]
else:
files.append(c)
return files
def _rendirchanges(self, src, dest):
changes = []
copies = {}
files = self._readcontents(os.path.join(self.tmppath, dest))
for f in files:
s = os.path.join(src, f)
d = os.path.join(dest, f)
changes.append(s)
changes.append(d)
Patrick Mezard
convert/gnuarch: fix switched copy source and destination...
r7567 copies[d] = s
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 return changes, copies
Aleix Conchillo Flaque
convert: improve gnu arch source performance and other fixes...
r6049 def _obtainrevision(self, rev):
Martin Geisler
do not attempt to translate ui.debug output
r9467 self.ui.debug('obtaining revision %s...\n' % rev)
Edouard Gomez
convert/gnuarch: use fully qualified revisions...
r7582 output = self._execute('get', rev, self.tmppath)
Aleix Conchillo Flaque
convert: improve gnu arch source performance and other fixes...
r6049 self.checkexit(output)
Martin Geisler
do not attempt to translate ui.debug output
r9467 self.ui.debug('analyzing revision %s...\n' % rev)
Aleix Conchillo Flaque
convert: improve gnu arch source performance and other fixes...
r6049 files = self._readcontents(self.tmppath)
self.changes[rev].add_files += files
Aleix Conchillo Flaque
convert: added GNU Arch (tla) tests and related fixes
r6079 def _stripbasepath(self, path):
if path.startswith('./'):
return path[2:]
return path
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 def _parsecatlog(self, data, rev):
Edouard Gomez
convert/gnuarch: fix cat-log parsing...
r7578 try:
catlog = self.catlogparser.parsestr(data)
Edouard Gomez
convert/gnuarch: recode cat-log parts to utf-8 to be hg.description friendly
r7592
# Commit date
Boris Feld
util: extract all date-related utils in utils/dateutil module...
r36625 self.changes[rev].date = dateutil.datestr(
dateutil.strdate(catlog['Standard-date'],
Edouard Gomez
convert/gnuarch: fix cat-log parsing...
r7578 '%Y-%m-%d %H:%M:%S'))
Edouard Gomez
convert/gnuarch: recode cat-log parts to utf-8 to be hg.description friendly
r7592
# Commit author
self.changes[rev].author = self.recode(catlog['Creator'])
# Commit description
self.changes[rev].summary = '\n\n'.join((catlog['Summary'],
catlog.get_payload()))
self.changes[rev].summary = self.recode(self.changes[rev].summary)
# Commit revision origin when dealing with a branch or tag
Nicolas Dumazet
use 'x in dict' instead of 'dict.has_key(x)'...
r9391 if 'Continuation-of' in catlog:
Matt Mackall
many, many trivial check-code fixups
r10282 self.changes[rev].continuationof = self.recode(
catlog['Continuation-of'])
Peter Arrenbrecht
cleanup: drop unused assignments
r7875 except Exception:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_('could not parse cat-log of %s') % rev)
Aleix Conchillo Flaque
convert: add full description for gnu arch revisions
r6037
Aleix Conchillo Flaque
convert: improve gnu arch source performance and other fixes...
r6049 def _parsechangeset(self, data, rev):
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 for l in data:
l = l.strip()
Aleix Conchillo Flaque
convert: support binary files, link to files (viceversa) in gnu arch
r6055 # Added file (ignore added directory)
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 if l.startswith('A') and not l.startswith('A/'):
Aleix Conchillo Flaque
convert: added GNU Arch (tla) tests and related fixes
r6079 file = self._stripbasepath(l[1:].strip())
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 if not self._exclude(file):
self.changes[rev].add_files.append(file)
Aleix Conchillo Flaque
convert: support binary files, link to files (viceversa) in gnu arch
r6055 # Deleted file (ignore deleted directory)
elif l.startswith('D') and not l.startswith('D/'):
Aleix Conchillo Flaque
convert: added GNU Arch (tla) tests and related fixes
r6079 file = self._stripbasepath(l[1:].strip())
Aleix Conchillo Flaque
convert: support binary files, link to files (viceversa) in gnu arch
r6055 if not self._exclude(file):
self.changes[rev].del_files.append(file)
# Modified binary file
elif l.startswith('Mb'):
Aleix Conchillo Flaque
convert: added GNU Arch (tla) tests and related fixes
r6079 file = self._stripbasepath(l[2:].strip())
Aleix Conchillo Flaque
convert: support binary files, link to files (viceversa) in gnu arch
r6055 if not self._exclude(file):
self.changes[rev].mod_files.append(file)
# Modified link
elif l.startswith('M->'):
Aleix Conchillo Flaque
convert: added GNU Arch (tla) tests and related fixes
r6079 file = self._stripbasepath(l[3:].strip())
Aleix Conchillo Flaque
convert: support binary files, link to files (viceversa) in gnu arch
r6055 if not self._exclude(file):
self.changes[rev].mod_files.append(file)
# Modified file
elif l.startswith('M'):
Aleix Conchillo Flaque
convert: added GNU Arch (tla) tests and related fixes
r6079 file = self._stripbasepath(l[1:].strip())
Aleix Conchillo Flaque
convert: support binary files, link to files (viceversa) in gnu arch
r6055 if not self._exclude(file):
self.changes[rev].mod_files.append(file)
# Renamed file (or link)
elif l.startswith('=>'):
files = l[2:].strip().split(' ')
if len(files) == 1:
files = l[2:].strip().split('\t')
Aleix Conchillo Flaque
convert: added GNU Arch (tla) tests and related fixes
r6079 src = self._stripbasepath(files[0])
dst = self._stripbasepath(files[1])
if not self._exclude(src) and not self._exclude(dst):
self.changes[rev].ren_files[src] = dst
Aleix Conchillo Flaque
convert: support binary files, link to files (viceversa) in gnu arch
r6055 # Conversion from file to link or from link to file (modified)
elif l.startswith('ch'):
Aleix Conchillo Flaque
convert: added GNU Arch (tla) tests and related fixes
r6079 file = self._stripbasepath(l[2:].strip())
Aleix Conchillo Flaque
convert: support binary files, link to files (viceversa) in gnu arch
r6055 if not self._exclude(file):
self.changes[rev].mod_files.append(file)
# Renamed directory
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 elif l.startswith('/>'):
dirs = l[2:].strip().split(' ')
if len(dirs) == 1:
dirs = l[2:].strip().split('\t')
Aleix Conchillo Flaque
convert: added GNU Arch (tla) tests and related fixes
r6079 src = self._stripbasepath(dirs[0])
dst = self._stripbasepath(dirs[1])
if not self._exclude(src) and not self._exclude(dst):
self.changes[rev].ren_dirs[src] = dst