mirror of
https://github.com/facebook/sapling.git
synced 2024-10-11 09:17:30 +03:00
d63b523d53
Our hack for preventing overbundling was incorrect. Upstream has 22c0e29cfb77 which is the right fix. We're also seeing missing manifest revisions in bundles for some users, so this change (or the one upstream), might be exposing a deeper bug in the general delta bundle creation.
141 lines
4.9 KiB
Python
141 lines
4.9 KiB
Python
# writecg2.py -- write changegroup2 to disk
|
|
#
|
|
# Copyright 2004-present Facebook.
|
|
#
|
|
# This software may be used and distributed according to the terms of the
|
|
# GNU General Public License version 2 or any later version.
|
|
|
|
'''write changegroup2 to disk
|
|
|
|
For histories with lots of interleaved branches stored with generaldelta,
|
|
bundle1 can be extremely slow to generate. This extension modifies Mercurial to
|
|
read and write changegroup2s to disk.
|
|
'''
|
|
|
|
from mercurial import bundle2
|
|
from mercurial import bundlerepo
|
|
from mercurial import changegroup
|
|
from mercurial import discovery
|
|
from mercurial import error
|
|
from mercurial import exchange
|
|
from mercurial import extensions
|
|
from mercurial import localrepo
|
|
from mercurial import phases
|
|
from mercurial import util
|
|
from mercurial.i18n import _
|
|
from mercurial.node import nullid
|
|
|
|
import os
|
|
import tempfile
|
|
|
|
def overridewritebundle(orig, ui, cg, filename, bundletype, vfs=None):
|
|
if (bundletype.startswith('HG10') and
|
|
isinstance(cg, changegroup.cg2unpacker)):
|
|
bundletype = 'HG2C' + bundletype[4:]
|
|
return orig(ui, cg, filename, bundletype, vfs=vfs)
|
|
|
|
def overridechangegroupsubset(orig, repo, roots, heads, source, version = '01'):
|
|
# we only care about performance for strips, not about 'hg bundle' and
|
|
# similar
|
|
if source != 'strip' or version != '01':
|
|
return orig(repo, roots, heads, source, version=version)
|
|
|
|
# below is all copied from changegroup.py, except with cg1 changed to
|
|
# cg2
|
|
cl = repo.changelog
|
|
if not roots:
|
|
roots = [nullid]
|
|
discbases = []
|
|
for n in roots:
|
|
discbases.extend([p for p in cl.parents(n) if p != nullid])
|
|
# TODO: remove call to nodesbetween.
|
|
csets, roots, heads = cl.nodesbetween(roots, heads)
|
|
included = set(csets)
|
|
discbases = [n for n in discbases if n not in included]
|
|
outgoing = discovery.outgoing(cl, discbases, heads)
|
|
# use packermap because other extensions might override it
|
|
bundler = changegroup.packermap['02'][0](repo)
|
|
gengroup = changegroup.getsubsetraw(repo, outgoing, bundler, source,
|
|
fastpath=False)
|
|
result = changegroup.cg2unpacker(util.chunkbuffer(gengroup), 'UN')
|
|
result.version = '01' # needed to pass writebundle checks
|
|
return result
|
|
|
|
def overridereadbundle(orig, ui, fh, fname, vfs=None):
|
|
# copied from exchange.py
|
|
header = changegroup.readexactly(fh, 4)
|
|
|
|
alg = None
|
|
if not fname:
|
|
fname = "stream"
|
|
if not header.startswith('HG') and header.startswith('\0'):
|
|
fh = changegroup.headerlessfixup(fh, header)
|
|
header = "HG10"
|
|
alg = 'UN'
|
|
elif vfs:
|
|
fname = vfs.join(fname)
|
|
|
|
magic, version = header[0:2], header[2:4]
|
|
|
|
if magic != 'HG':
|
|
raise util.Abort(_('%s: not a Mercurial bundle') % fname)
|
|
if version == '10' or version == '2C':
|
|
if alg is None:
|
|
alg = changegroup.readexactly(fh, 2)
|
|
if version == '10':
|
|
return changegroup.cg1unpacker(fh, alg)
|
|
else:
|
|
return changegroup.cg2unpacker(fh, alg)
|
|
elif version == '20':
|
|
return bundle2.unbundle20(ui, fh)
|
|
else:
|
|
raise util.Abort(_('%s: unknown bundle version %s') % (fname, version))
|
|
|
|
class cg2bundlerepository(bundlerepo.bundlerepository):
|
|
def __init__(self, ui, path, bundlename):
|
|
self.cg2temp = None
|
|
f = util.posixfile(bundlename, "rb")
|
|
bundle = exchange.readbundle(ui, f, bundlename)
|
|
if bundle.compressed and isinstance(bundle, changegroup.cg2unpacker):
|
|
fdtemp, bundlename = tempfile.mkstemp(prefix="hg-bundle-",
|
|
suffix=".hgun")
|
|
self.cg2temp = bundlename
|
|
fptemp = os.fdopen(fdtemp, 'wb')
|
|
|
|
try:
|
|
fptemp.write("HG2CUN")
|
|
while True:
|
|
chunk = bundle.read(2**18)
|
|
if not chunk:
|
|
break
|
|
fptemp.write(chunk)
|
|
finally:
|
|
fptemp.close()
|
|
pass
|
|
f.close()
|
|
super(cg2bundlerepository, self).__init__(ui, path, bundlename)
|
|
|
|
def close(self):
|
|
super(cg2bundlerepository, self).close()
|
|
if self.cg2temp:
|
|
os.unlink(self.cg2temp)
|
|
|
|
bundlerepo.bundlerepository = cg2bundlerepository
|
|
|
|
def extsetup(ui):
|
|
# add bundle types for changegroup2
|
|
bundletypes = changegroup.bundletypes
|
|
cg2types = {}
|
|
for bundletype, hc in bundletypes.iteritems():
|
|
if bundletype.startswith('HG10'):
|
|
header, compressor = hc
|
|
cg2type = 'HG2C' + bundletype[4:]
|
|
cg2header = 'HG2C' + header[4:]
|
|
cg2types[cg2type] = (cg2header, compressor)
|
|
bundletypes.update(cg2types)
|
|
|
|
extensions.wrapfunction(changegroup, 'writebundle', overridewritebundle)
|
|
extensions.wrapfunction(changegroup, 'changegroupsubset',
|
|
overridechangegroupsubset)
|
|
extensions.wrapfunction(exchange, 'readbundle', overridereadbundle)
|