##// END OF EJS Templates
cleanup: say goodbye to manifestv2 format...
Augie Fackler -
r36391:0147a473 default
parent child Browse files
Show More
@@ -538,9 +538,6 b" coreconfigitem('experimental', 'hook-tra"
538 538 coreconfigitem('experimental', 'httppostargs',
539 539 default=False,
540 540 )
541 coreconfigitem('experimental', 'manifestv2',
542 default=False,
543 )
544 541 coreconfigitem('experimental', 'mergedriver',
545 542 default=None,
546 543 )
@@ -1,4 +1,3 b''
1
2 1 Repositories contain a file (``.hg/requires``) containing a list of
3 2 features/capabilities that are *required* for clients to interface
4 3 with the repository. This file has been present in Mercurial since
@@ -105,8 +104,10 b' manifestv2'
105 104 Denotes that version 2 of manifests are being used.
106 105
107 106 Support for this requirement was added in Mercurial 3.4 (released
108 May 2015). The requirement is currently experimental and is disabled
109 by default.
107 May 2015). The new format failed to meet expectations and support
108 for the format and requirement were removed in Mercurial 4.6
109 (released May 2018) since the feature never graduated frome experiment
110 status.
110 111
111 112 treemanifest
112 113 ============
@@ -303,11 +303,15 b" REVLOGV2_REQUIREMENT = 'exp-revlogv2.0'"
303 303
304 304 class localrepository(object):
305 305
306 # obsolete experimental requirements:
307 # - manifestv2: An experimental new manifest format that allowed
308 # for stem compression of long paths. Experiment ended up not
309 # being successful (repository sizes went up due to worse delta
310 # chains), and the code was deleted in 4.6.
306 311 supportedformats = {
307 312 'revlogv1',
308 313 'generaldelta',
309 314 'treemanifest',
310 'manifestv2',
311 315 REVLOGV2_REQUIREMENT,
312 316 }
313 317 _basesupported = supportedformats | {
@@ -322,7 +326,6 b' class localrepository(object):'
322 326 'revlogv1',
323 327 'generaldelta',
324 328 'treemanifest',
325 'manifestv2',
326 329 }
327 330
328 331 # a list of (ui, featureset) functions.
@@ -2261,8 +2264,6 b' def newreporequirements(repo):'
2261 2264 requirements.add('generaldelta')
2262 2265 if ui.configbool('experimental', 'treemanifest'):
2263 2266 requirements.add('treemanifest')
2264 if ui.configbool('experimental', 'manifestv2'):
2265 requirements.add('manifestv2')
2266 2267
2267 2268 revlogv2 = ui.config('experimental', 'revlogv2')
2268 2269 if revlogv2 == 'enable-unstable-format-and-corrupt-my-data':
@@ -9,7 +9,6 b' from __future__ import absolute_import'
9 9
10 10 import heapq
11 11 import itertools
12 import os
13 12 import struct
14 13
15 14 from .i18n import _
@@ -28,7 +27,7 b' from . import ('
28 27 parsers = policy.importmod(r'parsers')
29 28 propertycache = util.propertycache
30 29
31 def _parsev1(data):
30 def _parse(data):
32 31 # This method does a little bit of excessive-looking
33 32 # precondition checking. This is so that the behavior of this
34 33 # class exactly matches its C counterpart to try and help
@@ -47,43 +46,7 b' def _parsev1(data):'
47 46 else:
48 47 yield f, bin(n), ''
49 48
50 def _parsev2(data):
51 metadataend = data.find('\n')
52 # Just ignore metadata for now
53 pos = metadataend + 1
54 prevf = ''
55 while pos < len(data):
56 end = data.find('\n', pos + 1) # +1 to skip stem length byte
57 if end == -1:
58 raise ValueError('Manifest ended with incomplete file entry.')
59 stemlen = ord(data[pos:pos + 1])
60 items = data[pos + 1:end].split('\0')
61 f = prevf[:stemlen] + items[0]
62 if prevf > f:
63 raise ValueError('Manifest entries not in sorted order.')
64 fl = items[1]
65 # Just ignore metadata (items[2:] for now)
66 n = data[end + 1:end + 21]
67 yield f, n, fl
68 pos = end + 22
69 prevf = f
70
71 def _parse(data):
72 """Generates (path, node, flags) tuples from a manifest text"""
73 if data.startswith('\0'):
74 return iter(_parsev2(data))
75 else:
76 return iter(_parsev1(data))
77
78 def _text(it, usemanifestv2):
79 """Given an iterator over (path, node, flags) tuples, returns a manifest
80 text"""
81 if usemanifestv2:
82 return _textv2(it)
83 else:
84 return _textv1(it)
85
86 def _textv1(it):
49 def _text(it):
87 50 files = []
88 51 lines = []
89 52 _hex = revlog.hex
@@ -96,19 +59,6 b' def _textv1(it):'
96 59 _checkforbidden(files)
97 60 return ''.join(lines)
98 61
99 def _textv2(it):
100 files = []
101 lines = ['\0\n']
102 prevf = ''
103 for f, n, fl in it:
104 files.append(f)
105 stem = os.path.commonprefix([prevf, f])
106 stemlen = min(len(stem), 255)
107 lines.append("%c%s\0%s\n%s\n" % (stemlen, f[stemlen:], fl, n))
108 prevf = f
109 _checkforbidden(files)
110 return ''.join(lines)
111
112 62 class lazymanifestiter(object):
113 63 def __init__(self, lm):
114 64 self.pos = 0
@@ -414,13 +364,7 b' except AttributeError:'
414 364
415 365 class manifestdict(object):
416 366 def __init__(self, data=''):
417 if data.startswith('\0'):
418 #_lazymanifest can not parse v2
419 self._lm = _lazymanifest('')
420 for f, n, fl in _parsev2(data):
421 self._lm[f] = n, fl
422 else:
423 self._lm = _lazymanifest(data)
367 self._lm = _lazymanifest(data)
424 368
425 369 def __getitem__(self, key):
426 370 return self._lm[key][0]
@@ -589,12 +533,9 b' class manifestdict(object):'
589 533 def iterentries(self):
590 534 return self._lm.iterentries()
591 535
592 def text(self, usemanifestv2=False):
593 if usemanifestv2:
594 return _textv2(self._lm.iterentries())
595 else:
596 # use (probably) native version for v1
597 return self._lm.text()
536 def text(self):
537 # most likely uses native version
538 return self._lm.text()
598 539
599 540 def fastdelta(self, base, changes):
600 541 """Given a base manifest text as a bytearray and a list of changes
@@ -1138,12 +1079,12 b' class treemanifest(object):'
1138 1079 if fl:
1139 1080 self._flags[f] = fl
1140 1081
1141 def text(self, usemanifestv2=False):
1082 def text(self):
1142 1083 """Get the full data of this manifest as a bytestring."""
1143 1084 self._load()
1144 return _text(self.iterentries(), usemanifestv2)
1085 return _text(self.iterentries())
1145 1086
1146 def dirtext(self, usemanifestv2=False):
1087 def dirtext(self):
1147 1088 """Get the full data of this directory as a bytestring. Make sure that
1148 1089 any submanifests have been written first, so their nodeids are correct.
1149 1090 """
@@ -1151,7 +1092,7 b' class treemanifest(object):'
1151 1092 flags = self.flags
1152 1093 dirs = [(d[:-1], self._dirs[d]._node, 't') for d in self._dirs]
1153 1094 files = [(f, self._files[f], flags(f)) for f in self._files]
1154 return _text(sorted(dirs + files), usemanifestv2)
1095 return _text(sorted(dirs + files))
1155 1096
1156 1097 def read(self, gettext, readsubtree):
1157 1098 def _load_for_read(s):
@@ -1208,15 +1149,12 b' class manifestrevlog(revlog.revlog):'
1208 1149 # stacks of commits, the number can go up, hence the config knob below.
1209 1150 cachesize = 4
1210 1151 optiontreemanifest = False
1211 usemanifestv2 = False
1212 1152 opts = getattr(opener, 'options', None)
1213 1153 if opts is not None:
1214 1154 cachesize = opts.get('manifestcachesize', cachesize)
1215 1155 optiontreemanifest = opts.get('treemanifest', False)
1216 usemanifestv2 = opts.get('manifestv2', usemanifestv2)
1217 1156
1218 1157 self._treeondisk = optiontreemanifest or treemanifest
1219 self._usemanifestv2 = usemanifestv2
1220 1158
1221 1159 self._fulltextcache = util.lrucachedict(cachesize)
1222 1160
@@ -1262,8 +1200,7 b' class manifestrevlog(revlog.revlog):'
1262 1200 return self._dirlogcache[d]
1263 1201
1264 1202 def add(self, m, transaction, link, p1, p2, added, removed, readtree=None):
1265 if (p1 in self.fulltextcache and util.safehasattr(m, 'fastdelta')
1266 and not self._usemanifestv2):
1203 if p1 in self.fulltextcache and util.safehasattr(m, 'fastdelta'):
1267 1204 # If our first parent is in the manifest cache, we can
1268 1205 # compute a delta here using properties we know about the
1269 1206 # manifest up-front, which may save time later for the
@@ -1290,7 +1227,7 b' class manifestrevlog(revlog.revlog):'
1290 1227 n = self._addtree(m, transaction, link, m1, m2, readtree)
1291 1228 arraytext = None
1292 1229 else:
1293 text = m.text(self._usemanifestv2)
1230 text = m.text()
1294 1231 n = self.addrevision(text, transaction, link, p1, p2)
1295 1232 arraytext = bytearray(text)
1296 1233
@@ -1309,13 +1246,13 b' class manifestrevlog(revlog.revlog):'
1309 1246 sublog.add(subm, transaction, link, subp1, subp2, None, None,
1310 1247 readtree=readtree)
1311 1248 m.writesubtrees(m1, m2, writesubtree)
1312 text = m.dirtext(self._usemanifestv2)
1249 text = m.dirtext()
1313 1250 n = None
1314 1251 if self._dir != '':
1315 1252 # Double-check whether contents are unchanged to one parent
1316 if text == m1.dirtext(self._usemanifestv2):
1253 if text == m1.dirtext():
1317 1254 n = m1.node()
1318 elif text == m2.dirtext(self._usemanifestv2):
1255 elif text == m2.dirtext():
1319 1256 n = m2.node()
1320 1257
1321 1258 if not n:
@@ -1493,19 +1430,6 b' class manifestctx(object):'
1493 1430 Changing the value of `shallow` has no effect on flat manifests.
1494 1431 '''
1495 1432 revlog = self._revlog()
1496 if revlog._usemanifestv2:
1497 # Need to perform a slow delta
1498 r0 = revlog.deltaparent(revlog.rev(self._node))
1499 m0 = self._manifestlog[revlog.node(r0)].read()
1500 m1 = self.read()
1501 md = manifestdict()
1502 for f, ((n0, fl0), (n1, fl1)) in m0.diff(m1).iteritems():
1503 if n1:
1504 md[f] = n1
1505 if fl1:
1506 md.setflag(f, fl1)
1507 return md
1508
1509 1433 r = revlog.rev(self._node)
1510 1434 d = mdiff.patchtext(revlog.revdiff(revlog.deltaparent(r), r))
1511 1435 return manifestdict(d)
@@ -1608,7 +1532,7 b' class treemanifestctx(object):'
1608 1532 its 't' flag.
1609 1533 '''
1610 1534 revlog = self._revlog()
1611 if shallow and not revlog._usemanifestv2:
1535 if shallow:
1612 1536 r = revlog.rev(self._node)
1613 1537 d = mdiff.patchtext(revlog.revdiff(revlog.deltaparent(r), r))
1614 1538 return manifestdict(d)
@@ -46,7 +46,6 b' def blocksourcerequirements(repo):'
46 46 return {
47 47 # The upgrade code does not yet support these experimental features.
48 48 # This is an artificial limitation.
49 'manifestv2',
50 49 'treemanifest',
51 50 # This was a precursor to generaldelta and was never enabled by default.
52 51 # It should (hopefully) not exist in the wild.
@@ -11,7 +11,6 b' from mercurial import ('
11 11 )
12 12
13 13 EMTPY_MANIFEST = b''
14 EMTPY_MANIFEST_V2 = b'\0\n'
15 14
16 15 HASH_1 = b'1' * 40
17 16 BIN_HASH_1 = binascii.unhexlify(HASH_1)
@@ -28,42 +27,6 b' A_SHORT_MANIFEST = ('
28 27 b'flag2': b'l',
29 28 }
30 29
31 # Same data as A_SHORT_MANIFEST
32 A_SHORT_MANIFEST_V2 = (
33 b'\0\n'
34 b'\x00bar/baz/qux.py\0%(flag2)s\n%(hash2)s\n'
35 b'\x00foo\0%(flag1)s\n%(hash1)s\n'
36 ) % {b'hash1': BIN_HASH_1,
37 b'flag1': b'',
38 b'hash2': BIN_HASH_2,
39 b'flag2': b'l',
40 }
41
42 # Same data as A_SHORT_MANIFEST
43 A_METADATA_MANIFEST = (
44 b'\0foo\0bar\n'
45 b'\x00bar/baz/qux.py\0%(flag2)s\0foo\0bar\n%(hash2)s\n' # flag and metadata
46 b'\x00foo\0%(flag1)s\0foo\n%(hash1)s\n' # no flag, but metadata
47 ) % {b'hash1': BIN_HASH_1,
48 b'flag1': b'',
49 b'hash2': BIN_HASH_2,
50 b'flag2': b'l',
51 }
52
53 A_STEM_COMPRESSED_MANIFEST = (
54 b'\0\n'
55 b'\x00bar/baz/qux.py\0%(flag2)s\n%(hash2)s\n'
56 b'\x04qux/foo.py\0%(flag1)s\n%(hash1)s\n' # simple case of 4 stem chars
57 b'\x0az.py\0%(flag1)s\n%(hash1)s\n' # tricky newline = 10 stem characters
58 b'\x00%(verylongdir)sx/x\0\n%(hash1)s\n'
59 b'\xffx/y\0\n%(hash2)s\n' # more than 255 stem chars
60 ) % {b'hash1': BIN_HASH_1,
61 b'flag1': b'',
62 b'hash2': BIN_HASH_2,
63 b'flag2': b'l',
64 b'verylongdir': 255 * b'x',
65 }
66
67 30 A_DEEPER_MANIFEST = (
68 31 b'a/b/c/bar.py\0%(hash3)s%(flag1)s\n'
69 32 b'a/b/c/bar.txt\0%(hash1)s%(flag1)s\n'
@@ -111,11 +74,6 b' class basemanifesttests(object):'
111 74 self.assertEqual(0, len(m))
112 75 self.assertEqual([], list(m))
113 76
114 def testEmptyManifestv2(self):
115 m = self.parsemanifest(EMTPY_MANIFEST_V2)
116 self.assertEqual(0, len(m))
117 self.assertEqual([], list(m))
118
119 77 def testManifest(self):
120 78 m = self.parsemanifest(A_SHORT_MANIFEST)
121 79 self.assertEqual([b'bar/baz/qux.py', b'foo'], list(m))
@@ -126,31 +84,6 b' class basemanifesttests(object):'
126 84 with self.assertRaises(KeyError):
127 85 m[b'wat']
128 86
129 def testParseManifestV2(self):
130 m1 = self.parsemanifest(A_SHORT_MANIFEST)
131 m2 = self.parsemanifest(A_SHORT_MANIFEST_V2)
132 # Should have same content as A_SHORT_MANIFEST
133 self.assertEqual(m1.text(), m2.text())
134
135 def testParseManifestMetadata(self):
136 # Metadata is for future-proofing and should be accepted but ignored
137 m = self.parsemanifest(A_METADATA_MANIFEST)
138 self.assertEqual(A_SHORT_MANIFEST, m.text())
139
140 def testParseManifestStemCompression(self):
141 m = self.parsemanifest(A_STEM_COMPRESSED_MANIFEST)
142 self.assertIn(b'bar/baz/qux.py', m)
143 self.assertIn(b'bar/qux/foo.py', m)
144 self.assertIn(b'bar/qux/foz.py', m)
145 self.assertIn(256 * b'x' + b'/x', m)
146 self.assertIn(256 * b'x' + b'/y', m)
147 self.assertEqual(A_STEM_COMPRESSED_MANIFEST, m.text(usemanifestv2=True))
148
149 def testTextV2(self):
150 m1 = self.parsemanifest(A_SHORT_MANIFEST)
151 v2text = m1.text(usemanifestv2=True)
152 self.assertEqual(A_SHORT_MANIFEST_V2, v2text)
153
154 87 def testSetItem(self):
155 88 want = BIN_HASH_1
156 89
@@ -31,23 +31,18 b' Cannot upgrade shared repositories'
31 31 abort: cannot upgrade repository; unsupported source requirement: shared
32 32 [255]
33 33
34 Do not yet support upgrading manifestv2 and treemanifest repos
35
36 $ hg --config experimental.manifestv2=true init manifestv2
37 $ hg -R manifestv2 debugupgraderepo
38 abort: cannot upgrade repository; unsupported source requirement: manifestv2
39 [255]
34 Do not yet support upgrading treemanifest repos
40 35
41 36 $ hg --config experimental.treemanifest=true init treemanifest
42 37 $ hg -R treemanifest debugupgraderepo
43 38 abort: cannot upgrade repository; unsupported source requirement: treemanifest
44 39 [255]
45 40
46 Cannot add manifestv2 or treemanifest requirement during upgrade
41 Cannot add treemanifest requirement during upgrade
47 42
48 43 $ hg init disallowaddedreq
49 $ hg -R disallowaddedreq --config experimental.manifestv2=true --config experimental.treemanifest=true debugupgraderepo
50 abort: cannot upgrade repository; do not support adding requirement: manifestv2, treemanifest
44 $ hg -R disallowaddedreq --config experimental.treemanifest=true debugupgraderepo
45 abort: cannot upgrade repository; do not support adding requirement: treemanifest
51 46 [255]
52 47
53 48 An upgrade of a repository created with recommended settings only suggests optimizations
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now