Mercurial > hg
view mercurial/diffutil.py @ 39492:a33f394b2bfd
snapshot: try intermediate snapshot against parents' base
# Regarding The Series Started By This Changeset
This is the first changesets of a group adjusting delta chain strategy to
build a useful chain of intermediate snapshots. The series will introduce a
full strategy to produce chains of multiple snapshots on top of which a
"usual" delta chain will be built.
That strategy will have multiple steps to maximize snapshot reuse, avoiding
pathological cases and improving overall compression in very branchy
repositories. An important property of sparse-revlog using such snapshot-chain
is that they can use very short delta chain without problematic impact on the
resulting compression. Shorter delta chains are important to achieve good
performance.
To make each step clear, we'll introduce them one by one.
See the end of this series for full details.
# Regarding This Changeset
Before this change, if we cannot store the current revision as a delta against
a "simple" candidate (p1, p2, prev), we created a new level-0 snapshot (also
called full snapshot).
As the first step, we introduce a simple strategy: try an intermediate level-1
snapshot against the chain base of the "current revision" parents.
The "current revision" is the one we are currently trying to store in the
revlog, triggering this search for a good delta base.
The first item in the chain is always a level-0 snapshot.
# Effect On The Test Repository
We can already see the effect on the test-repository. Most of the snapshots
have shifted from level 0 to level 1. The overall size has slightly decreased.
(However, keep in mind that this repository only emulates real data)
# Regarding Statistic
The current series focuses on improving the chain built. Improving the
performance of this logic will be done as a second step. Sparse-revlog is
still experimental and disabled by default.
We'll provide more statistic about resulting size and delta chain at the end
of this series.
author | Boris Feld <boris.feld@octobus.net> |
---|---|
date | Fri, 07 Sep 2018 11:17:29 -0400 |
parents | be441eb65f09 |
children | 78b270a55dc6 |
line wrap: on
line source
# diffutil.py - utility functions related to diff and patch # # Copyright 2006 Brendan Cully <brendan@kublai.com> # Copyright 2007 Chris Mason <chris.mason@oracle.com> # Copyright 2018 Octobus <octobus@octobus.net> # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. from __future__ import absolute_import from .i18n import _ from . import ( mdiff, pycompat, ) def diffallopts(ui, opts=None, untrusted=False, section='diff'): '''return diffopts with all features supported and parsed''' return difffeatureopts(ui, opts=opts, untrusted=untrusted, section=section, git=True, whitespace=True, formatchanging=True) def difffeatureopts(ui, opts=None, untrusted=False, section='diff', git=False, whitespace=False, formatchanging=False): '''return diffopts with only opted-in features parsed Features: - git: git-style diffs - whitespace: whitespace options like ignoreblanklines and ignorews - formatchanging: options that will likely break or cause correctness issues with most diff parsers ''' def get(key, name=None, getter=ui.configbool, forceplain=None): if opts: v = opts.get(key) # diffopts flags are either None-default (which is passed # through unchanged, so we can identify unset values), or # some other falsey default (eg --unified, which defaults # to an empty string). We only want to override the config # entries from hgrc with command line values if they # appear to have been set, which is any truthy value, # True, or False. if v or isinstance(v, bool): return v if forceplain is not None and ui.plain(): return forceplain return getter(section, name or key, untrusted=untrusted) # core options, expected to be understood by every diff parser buildopts = { 'nodates': get('nodates'), 'showfunc': get('show_function', 'showfunc'), 'context': get('unified', getter=ui.config), } buildopts['xdiff'] = ui.configbool('experimental', 'xdiff') if git: buildopts['git'] = get('git') # since this is in the experimental section, we need to call # ui.configbool directory buildopts['showsimilarity'] = ui.configbool('experimental', 'extendedheader.similarity') # need to inspect the ui object instead of using get() since we want to # test for an int hconf = ui.config('experimental', 'extendedheader.index') if hconf is not None: hlen = None try: # the hash config could be an integer (for length of hash) or a # word (e.g. short, full, none) hlen = int(hconf) if hlen < 0 or hlen > 40: msg = _("invalid length for extendedheader.index: '%d'\n") ui.warn(msg % hlen) except ValueError: # default value if hconf == 'short' or hconf == '': hlen = 12 elif hconf == 'full': hlen = 40 elif hconf != 'none': msg = _("invalid value for extendedheader.index: '%s'\n") ui.warn(msg % hconf) finally: buildopts['index'] = hlen if whitespace: buildopts['ignorews'] = get('ignore_all_space', 'ignorews') buildopts['ignorewsamount'] = get('ignore_space_change', 'ignorewsamount') buildopts['ignoreblanklines'] = get('ignore_blank_lines', 'ignoreblanklines') buildopts['ignorewseol'] = get('ignore_space_at_eol', 'ignorewseol') if formatchanging: buildopts['text'] = opts and opts.get('text') binary = None if opts is None else opts.get('binary') buildopts['nobinary'] = (not binary if binary is not None else get('nobinary', forceplain=False)) buildopts['noprefix'] = get('noprefix', forceplain=False) buildopts['worddiff'] = get('word_diff', 'word-diff', forceplain=False) return mdiff.diffopts(**pycompat.strkwargs(buildopts))