##// 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 coreconfigitem('experimental', 'httppostargs',
538 coreconfigitem('experimental', 'httppostargs',
539 default=False,
539 default=False,
540 )
540 )
541 coreconfigitem('experimental', 'manifestv2',
542 default=False,
543 )
544 coreconfigitem('experimental', 'mergedriver',
541 coreconfigitem('experimental', 'mergedriver',
545 default=None,
542 default=None,
546 )
543 )
@@ -1,4 +1,3 b''
1
2 Repositories contain a file (``.hg/requires``) containing a list of
1 Repositories contain a file (``.hg/requires``) containing a list of
3 features/capabilities that are *required* for clients to interface
2 features/capabilities that are *required* for clients to interface
4 with the repository. This file has been present in Mercurial since
3 with the repository. This file has been present in Mercurial since
@@ -105,8 +104,10 b' manifestv2'
105 Denotes that version 2 of manifests are being used.
104 Denotes that version 2 of manifests are being used.
106
105
107 Support for this requirement was added in Mercurial 3.4 (released
106 Support for this requirement was added in Mercurial 3.4 (released
108 May 2015). The requirement is currently experimental and is disabled
107 May 2015). The new format failed to meet expectations and support
109 by default.
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 treemanifest
112 treemanifest
112 ============
113 ============
@@ -303,11 +303,15 b" REVLOGV2_REQUIREMENT = 'exp-revlogv2.0'"
303
303
304 class localrepository(object):
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 supportedformats = {
311 supportedformats = {
307 'revlogv1',
312 'revlogv1',
308 'generaldelta',
313 'generaldelta',
309 'treemanifest',
314 'treemanifest',
310 'manifestv2',
311 REVLOGV2_REQUIREMENT,
315 REVLOGV2_REQUIREMENT,
312 }
316 }
313 _basesupported = supportedformats | {
317 _basesupported = supportedformats | {
@@ -322,7 +326,6 b' class localrepository(object):'
322 'revlogv1',
326 'revlogv1',
323 'generaldelta',
327 'generaldelta',
324 'treemanifest',
328 'treemanifest',
325 'manifestv2',
326 }
329 }
327
330
328 # a list of (ui, featureset) functions.
331 # a list of (ui, featureset) functions.
@@ -2261,8 +2264,6 b' def newreporequirements(repo):'
2261 requirements.add('generaldelta')
2264 requirements.add('generaldelta')
2262 if ui.configbool('experimental', 'treemanifest'):
2265 if ui.configbool('experimental', 'treemanifest'):
2263 requirements.add('treemanifest')
2266 requirements.add('treemanifest')
2264 if ui.configbool('experimental', 'manifestv2'):
2265 requirements.add('manifestv2')
2266
2267
2267 revlogv2 = ui.config('experimental', 'revlogv2')
2268 revlogv2 = ui.config('experimental', 'revlogv2')
2268 if revlogv2 == 'enable-unstable-format-and-corrupt-my-data':
2269 if revlogv2 == 'enable-unstable-format-and-corrupt-my-data':
@@ -9,7 +9,6 b' from __future__ import absolute_import'
9
9
10 import heapq
10 import heapq
11 import itertools
11 import itertools
12 import os
13 import struct
12 import struct
14
13
15 from .i18n import _
14 from .i18n import _
@@ -28,7 +27,7 b' from . import ('
28 parsers = policy.importmod(r'parsers')
27 parsers = policy.importmod(r'parsers')
29 propertycache = util.propertycache
28 propertycache = util.propertycache
30
29
31 def _parsev1(data):
30 def _parse(data):
32 # This method does a little bit of excessive-looking
31 # This method does a little bit of excessive-looking
33 # precondition checking. This is so that the behavior of this
32 # precondition checking. This is so that the behavior of this
34 # class exactly matches its C counterpart to try and help
33 # class exactly matches its C counterpart to try and help
@@ -47,43 +46,7 b' def _parsev1(data):'
47 else:
46 else:
48 yield f, bin(n), ''
47 yield f, bin(n), ''
49
48
50 def _parsev2(data):
49 def _text(it):
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):
87 files = []
50 files = []
88 lines = []
51 lines = []
89 _hex = revlog.hex
52 _hex = revlog.hex
@@ -96,19 +59,6 b' def _textv1(it):'
96 _checkforbidden(files)
59 _checkforbidden(files)
97 return ''.join(lines)
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 class lazymanifestiter(object):
62 class lazymanifestiter(object):
113 def __init__(self, lm):
63 def __init__(self, lm):
114 self.pos = 0
64 self.pos = 0
@@ -414,13 +364,7 b' except AttributeError:'
414
364
415 class manifestdict(object):
365 class manifestdict(object):
416 def __init__(self, data=''):
366 def __init__(self, data=''):
417 if data.startswith('\0'):
367 self._lm = _lazymanifest(data)
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)
424
368
425 def __getitem__(self, key):
369 def __getitem__(self, key):
426 return self._lm[key][0]
370 return self._lm[key][0]
@@ -589,12 +533,9 b' class manifestdict(object):'
589 def iterentries(self):
533 def iterentries(self):
590 return self._lm.iterentries()
534 return self._lm.iterentries()
591
535
592 def text(self, usemanifestv2=False):
536 def text(self):
593 if usemanifestv2:
537 # most likely uses native version
594 return _textv2(self._lm.iterentries())
538 return self._lm.text()
595 else:
596 # use (probably) native version for v1
597 return self._lm.text()
598
539
599 def fastdelta(self, base, changes):
540 def fastdelta(self, base, changes):
600 """Given a base manifest text as a bytearray and a list of changes
541 """Given a base manifest text as a bytearray and a list of changes
@@ -1138,12 +1079,12 b' class treemanifest(object):'
1138 if fl:
1079 if fl:
1139 self._flags[f] = fl
1080 self._flags[f] = fl
1140
1081
1141 def text(self, usemanifestv2=False):
1082 def text(self):
1142 """Get the full data of this manifest as a bytestring."""
1083 """Get the full data of this manifest as a bytestring."""
1143 self._load()
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 """Get the full data of this directory as a bytestring. Make sure that
1088 """Get the full data of this directory as a bytestring. Make sure that
1148 any submanifests have been written first, so their nodeids are correct.
1089 any submanifests have been written first, so their nodeids are correct.
1149 """
1090 """
@@ -1151,7 +1092,7 b' class treemanifest(object):'
1151 flags = self.flags
1092 flags = self.flags
1152 dirs = [(d[:-1], self._dirs[d]._node, 't') for d in self._dirs]
1093 dirs = [(d[:-1], self._dirs[d]._node, 't') for d in self._dirs]
1153 files = [(f, self._files[f], flags(f)) for f in self._files]
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 def read(self, gettext, readsubtree):
1097 def read(self, gettext, readsubtree):
1157 def _load_for_read(s):
1098 def _load_for_read(s):
@@ -1208,15 +1149,12 b' class manifestrevlog(revlog.revlog):'
1208 # stacks of commits, the number can go up, hence the config knob below.
1149 # stacks of commits, the number can go up, hence the config knob below.
1209 cachesize = 4
1150 cachesize = 4
1210 optiontreemanifest = False
1151 optiontreemanifest = False
1211 usemanifestv2 = False
1212 opts = getattr(opener, 'options', None)
1152 opts = getattr(opener, 'options', None)
1213 if opts is not None:
1153 if opts is not None:
1214 cachesize = opts.get('manifestcachesize', cachesize)
1154 cachesize = opts.get('manifestcachesize', cachesize)
1215 optiontreemanifest = opts.get('treemanifest', False)
1155 optiontreemanifest = opts.get('treemanifest', False)
1216 usemanifestv2 = opts.get('manifestv2', usemanifestv2)
1217
1156
1218 self._treeondisk = optiontreemanifest or treemanifest
1157 self._treeondisk = optiontreemanifest or treemanifest
1219 self._usemanifestv2 = usemanifestv2
1220
1158
1221 self._fulltextcache = util.lrucachedict(cachesize)
1159 self._fulltextcache = util.lrucachedict(cachesize)
1222
1160
@@ -1262,8 +1200,7 b' class manifestrevlog(revlog.revlog):'
1262 return self._dirlogcache[d]
1200 return self._dirlogcache[d]
1263
1201
1264 def add(self, m, transaction, link, p1, p2, added, removed, readtree=None):
1202 def add(self, m, transaction, link, p1, p2, added, removed, readtree=None):
1265 if (p1 in self.fulltextcache and util.safehasattr(m, 'fastdelta')
1203 if p1 in self.fulltextcache and util.safehasattr(m, 'fastdelta'):
1266 and not self._usemanifestv2):
1267 # If our first parent is in the manifest cache, we can
1204 # If our first parent is in the manifest cache, we can
1268 # compute a delta here using properties we know about the
1205 # compute a delta here using properties we know about the
1269 # manifest up-front, which may save time later for the
1206 # manifest up-front, which may save time later for the
@@ -1290,7 +1227,7 b' class manifestrevlog(revlog.revlog):'
1290 n = self._addtree(m, transaction, link, m1, m2, readtree)
1227 n = self._addtree(m, transaction, link, m1, m2, readtree)
1291 arraytext = None
1228 arraytext = None
1292 else:
1229 else:
1293 text = m.text(self._usemanifestv2)
1230 text = m.text()
1294 n = self.addrevision(text, transaction, link, p1, p2)
1231 n = self.addrevision(text, transaction, link, p1, p2)
1295 arraytext = bytearray(text)
1232 arraytext = bytearray(text)
1296
1233
@@ -1309,13 +1246,13 b' class manifestrevlog(revlog.revlog):'
1309 sublog.add(subm, transaction, link, subp1, subp2, None, None,
1246 sublog.add(subm, transaction, link, subp1, subp2, None, None,
1310 readtree=readtree)
1247 readtree=readtree)
1311 m.writesubtrees(m1, m2, writesubtree)
1248 m.writesubtrees(m1, m2, writesubtree)
1312 text = m.dirtext(self._usemanifestv2)
1249 text = m.dirtext()
1313 n = None
1250 n = None
1314 if self._dir != '':
1251 if self._dir != '':
1315 # Double-check whether contents are unchanged to one parent
1252 # Double-check whether contents are unchanged to one parent
1316 if text == m1.dirtext(self._usemanifestv2):
1253 if text == m1.dirtext():
1317 n = m1.node()
1254 n = m1.node()
1318 elif text == m2.dirtext(self._usemanifestv2):
1255 elif text == m2.dirtext():
1319 n = m2.node()
1256 n = m2.node()
1320
1257
1321 if not n:
1258 if not n:
@@ -1493,19 +1430,6 b' class manifestctx(object):'
1493 Changing the value of `shallow` has no effect on flat manifests.
1430 Changing the value of `shallow` has no effect on flat manifests.
1494 '''
1431 '''
1495 revlog = self._revlog()
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 r = revlog.rev(self._node)
1433 r = revlog.rev(self._node)
1510 d = mdiff.patchtext(revlog.revdiff(revlog.deltaparent(r), r))
1434 d = mdiff.patchtext(revlog.revdiff(revlog.deltaparent(r), r))
1511 return manifestdict(d)
1435 return manifestdict(d)
@@ -1608,7 +1532,7 b' class treemanifestctx(object):'
1608 its 't' flag.
1532 its 't' flag.
1609 '''
1533 '''
1610 revlog = self._revlog()
1534 revlog = self._revlog()
1611 if shallow and not revlog._usemanifestv2:
1535 if shallow:
1612 r = revlog.rev(self._node)
1536 r = revlog.rev(self._node)
1613 d = mdiff.patchtext(revlog.revdiff(revlog.deltaparent(r), r))
1537 d = mdiff.patchtext(revlog.revdiff(revlog.deltaparent(r), r))
1614 return manifestdict(d)
1538 return manifestdict(d)
@@ -46,7 +46,6 b' def blocksourcerequirements(repo):'
46 return {
46 return {
47 # The upgrade code does not yet support these experimental features.
47 # The upgrade code does not yet support these experimental features.
48 # This is an artificial limitation.
48 # This is an artificial limitation.
49 'manifestv2',
50 'treemanifest',
49 'treemanifest',
51 # This was a precursor to generaldelta and was never enabled by default.
50 # This was a precursor to generaldelta and was never enabled by default.
52 # It should (hopefully) not exist in the wild.
51 # It should (hopefully) not exist in the wild.
@@ -11,7 +11,6 b' from mercurial import ('
11 )
11 )
12
12
13 EMTPY_MANIFEST = b''
13 EMTPY_MANIFEST = b''
14 EMTPY_MANIFEST_V2 = b'\0\n'
15
14
16 HASH_1 = b'1' * 40
15 HASH_1 = b'1' * 40
17 BIN_HASH_1 = binascii.unhexlify(HASH_1)
16 BIN_HASH_1 = binascii.unhexlify(HASH_1)
@@ -28,42 +27,6 b' A_SHORT_MANIFEST = ('
28 b'flag2': b'l',
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 A_DEEPER_MANIFEST = (
30 A_DEEPER_MANIFEST = (
68 b'a/b/c/bar.py\0%(hash3)s%(flag1)s\n'
31 b'a/b/c/bar.py\0%(hash3)s%(flag1)s\n'
69 b'a/b/c/bar.txt\0%(hash1)s%(flag1)s\n'
32 b'a/b/c/bar.txt\0%(hash1)s%(flag1)s\n'
@@ -111,11 +74,6 b' class basemanifesttests(object):'
111 self.assertEqual(0, len(m))
74 self.assertEqual(0, len(m))
112 self.assertEqual([], list(m))
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 def testManifest(self):
77 def testManifest(self):
120 m = self.parsemanifest(A_SHORT_MANIFEST)
78 m = self.parsemanifest(A_SHORT_MANIFEST)
121 self.assertEqual([b'bar/baz/qux.py', b'foo'], list(m))
79 self.assertEqual([b'bar/baz/qux.py', b'foo'], list(m))
@@ -126,31 +84,6 b' class basemanifesttests(object):'
126 with self.assertRaises(KeyError):
84 with self.assertRaises(KeyError):
127 m[b'wat']
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 def testSetItem(self):
87 def testSetItem(self):
155 want = BIN_HASH_1
88 want = BIN_HASH_1
156
89
@@ -31,23 +31,18 b' Cannot upgrade shared repositories'
31 abort: cannot upgrade repository; unsupported source requirement: shared
31 abort: cannot upgrade repository; unsupported source requirement: shared
32 [255]
32 [255]
33
33
34 Do not yet support upgrading manifestv2 and treemanifest repos
34 Do not yet support upgrading 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]
40
35
41 $ hg --config experimental.treemanifest=true init treemanifest
36 $ hg --config experimental.treemanifest=true init treemanifest
42 $ hg -R treemanifest debugupgraderepo
37 $ hg -R treemanifest debugupgraderepo
43 abort: cannot upgrade repository; unsupported source requirement: treemanifest
38 abort: cannot upgrade repository; unsupported source requirement: treemanifest
44 [255]
39 [255]
45
40
46 Cannot add manifestv2 or treemanifest requirement during upgrade
41 Cannot add treemanifest requirement during upgrade
47
42
48 $ hg init disallowaddedreq
43 $ hg init disallowaddedreq
49 $ hg -R disallowaddedreq --config experimental.manifestv2=true --config experimental.treemanifest=true debugupgraderepo
44 $ hg -R disallowaddedreq --config experimental.treemanifest=true debugupgraderepo
50 abort: cannot upgrade repository; do not support adding requirement: manifestv2, treemanifest
45 abort: cannot upgrade repository; do not support adding requirement: treemanifest
51 [255]
46 [255]
52
47
53 An upgrade of a repository created with recommended settings only suggests optimizations
48 An upgrade of a repository created with recommended settings only suggests optimizations
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now