[PATCH 4 of 4] revlog: support writing generaldelta revlogs

Sune Foldager cryo at cyanite.org
Thu May 5 11:27:59 CDT 2011


# HG changeset patch
# User Sune Foldager <cryo at cyanite.org>
# Date 1304611540 -7200
# Node ID 51e850f8e2901a032e5a13f0ea1ea140570ae8b4
# Parent  ff44313cbdf6f92626f2bb8cc1e0b790be52975b
revlog: support writing generaldelta revlogs

When adding revisions, and building a delta chain, deltas are computed against
the previous revision as well as the first parent. The smaller one is then
stored in the revlog. This is similar to the now removed parentdelta feature.

diff -r ff44313cbdf6 -r 51e850f8e290 mercurial/commands.py
--- a/mercurial/commands.py	Thu May 05 18:05:36 2011 +0200
+++ b/mercurial/commands.py	Thu May 05 18:05:40 2011 +0200
@@ -1550,28 +1550,38 @@
     if not r:
         r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
 
+    generaldelta = r.version & revlog.REVLOGGENERALDELTA
+    if generaldelta:
+        basehdr = ' delta'
+    else:
+        basehdr = '  base'
+
     if format == 0:
-        ui.write("   rev    offset  length   base linkrev"
+        ui.write("   rev    offset  length " + basehdr + " linkrev"
                  " nodeid       p1           p2\n")
     elif format == 1:
         ui.write("   rev flag   offset   length"
-                 "     size   base   link     p1     p2       nodeid\n")
+                 "     size " + basehdr + "   link     p1     p2       nodeid\n")
 
     for i in r:
         node = r.node(i)
+        if generaldelta:
+            base = r.deltaparent(i)
+        else:
+            base = r.chainbase(i)
         if format == 0:
             try:
                 pp = r.parents(node)
             except:
                 pp = [nullid, nullid]
             ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
-                    i, r.start(i), r.length(i), r.chainbase(i), r.linkrev(i),
+                    i, r.start(i), r.length(i), base, r.linkrev(i),
                     short(node), short(pp[0]), short(pp[1])))
         elif format == 1:
             pr = r.parentrevs(i)
             ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
                     i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
-                    r.chainbase(i), r.linkrev(i), pr[0], pr[1], short(node)))
+                    base, r.linkrev(i), pr[0], pr[1], short(node)))
 
 def debugindexdot(ui, repo, file_):
     """dump an index DAG as a graphviz dot file"""
diff -r ff44313cbdf6 -r 51e850f8e290 mercurial/localrepo.py
--- a/mercurial/localrepo.py	Thu May 05 18:05:36 2011 +0200
+++ b/mercurial/localrepo.py	Thu May 05 18:05:40 2011 +0200
@@ -21,7 +21,7 @@
 class localrepository(repo.repository):
     capabilities = set(('lookup', 'changegroupsubset', 'branchmap', 'pushkey',
                         'known', 'getbundle'))
-    supportedformats = set(('revlogv1',))
+    supportedformats = set(('revlogv1', 'generaldelta'))
     supported = supportedformats | set(('store', 'fncache', 'shared',
                                         'dotencode'))
 
@@ -61,6 +61,8 @@
                         '\0\0\0\2' # represents revlogv2
                         ' dummy changelog to prevent using the old repo layout'
                     )
+                if self.ui.configbool('format', 'generaldelta', False):
+                    requirements.append("generaldelta")
             else:
                 raise error.RepoError(_("repository %s not found") % path)
         elif create:
@@ -115,6 +117,8 @@
     def _applyrequirements(self, requirements):
         self.requirements = requirements
         self.sopener.options = {}
+        if 'generaldelta' in requirements:
+            self.sopener.options['generaldelta'] = 1
 
     def _writerequirements(self):
         reqfile = self.opener("requires", "w")
diff -r ff44313cbdf6 -r 51e850f8e290 mercurial/revlog.py
--- a/mercurial/revlog.py	Thu May 05 18:05:36 2011 +0200
+++ b/mercurial/revlog.py	Thu May 05 18:05:40 2011 +0200
@@ -227,10 +227,13 @@
         self._nodepos = None
 
         v = REVLOG_DEFAULT_VERSION
-        if hasattr(opener, 'options') and 'defversion' in opener.options:
-            v = opener.options['defversion']
-            if v & REVLOGNG:
-                v |= REVLOGNGINLINEDATA
+        if hasattr(opener, 'options'):
+            if 'defversion' in opener.options:
+                v = opener.options['defversion']
+                if v & REVLOGNG:
+                    v |= REVLOGNGINLINEDATA
+            if v & REVLOGNG and 'generaldelta' in opener.options:
+                v |= REVLOGGENERALDELTA
 
         if shallowroot:
             v |= REVLOGSHALLOW
@@ -1006,8 +1009,12 @@
                 delta = mdiff.textdiff(ptext, t)
             data = compress(delta)
             l = len(data[1]) + len(data[0])
-            base = self.chainbase(rev)
-            dist = l + offset - self.start(base)
+            chainbase = self.chainbase(rev)
+            dist = l + offset - self.start(chainbase)
+            if self._generaldelta:
+                base = rev
+            else:
+                base = chainbase
             return dist, l, data, base
 
         curr = len(self)
@@ -1021,6 +1028,10 @@
         # should we try to build a delta?
         if prev != nullrev:
             d = builddelta(prev)
+            if self._generaldelta and prev != p1r:
+                d2 = builddelta(p1r)
+                if d2 < d:
+                    d = d2
             dist, l, data, base = d
 
         # full versions are inserted when the needed deltas


More information about the Mercurial-devel mailing list