##// END OF EJS Templates
verify: add rename link checking
Matt Mackall -
r3744:d626fc9e default
parent child Browse files
Show More
@@ -1,194 +1,206
1 # verify.py - repository integrity checking for Mercurial
1 # verify.py - repository integrity checking for Mercurial
2 #
2 #
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from node import *
8 from node import *
9 from i18n import gettext as _
9 from i18n import gettext as _
10 import revlog, mdiff
10 import revlog, mdiff
11
11
12 def verify(repo):
12 def verify(repo):
13 filelinkrevs = {}
13 filelinkrevs = {}
14 filenodes = {}
14 filenodes = {}
15 changesets = revisions = files = 0
15 changesets = revisions = files = 0
16 errors = [0]
16 errors = [0]
17 warnings = [0]
17 warnings = [0]
18 neededmanifests = {}
18 neededmanifests = {}
19
19
20 def err(msg):
20 def err(msg):
21 repo.ui.warn(msg + "\n")
21 repo.ui.warn(msg + "\n")
22 errors[0] += 1
22 errors[0] += 1
23
23
24 def warn(msg):
24 def warn(msg):
25 repo.ui.warn(msg + "\n")
25 repo.ui.warn(msg + "\n")
26 warnings[0] += 1
26 warnings[0] += 1
27
27
28 def checksize(obj, name):
28 def checksize(obj, name):
29 d = obj.checksize()
29 d = obj.checksize()
30 if d[0]:
30 if d[0]:
31 err(_("%s data length off by %d bytes") % (name, d[0]))
31 err(_("%s data length off by %d bytes") % (name, d[0]))
32 if d[1]:
32 if d[1]:
33 err(_("%s index contains %d extra bytes") % (name, d[1]))
33 err(_("%s index contains %d extra bytes") % (name, d[1]))
34
34
35 def checkversion(obj, name):
35 def checkversion(obj, name):
36 if obj.version != revlog.REVLOGV0:
36 if obj.version != revlog.REVLOGV0:
37 if not revlogv1:
37 if not revlogv1:
38 warn(_("warning: `%s' uses revlog format 1") % name)
38 warn(_("warning: `%s' uses revlog format 1") % name)
39 elif revlogv1:
39 elif revlogv1:
40 warn(_("warning: `%s' uses revlog format 0") % name)
40 warn(_("warning: `%s' uses revlog format 0") % name)
41
41
42 revlogv1 = repo.revlogversion != revlog.REVLOGV0
42 revlogv1 = repo.revlogversion != revlog.REVLOGV0
43 if repo.ui.verbose or revlogv1 != repo.revlogv1:
43 if repo.ui.verbose or revlogv1 != repo.revlogv1:
44 repo.ui.status(_("repository uses revlog format %d\n") %
44 repo.ui.status(_("repository uses revlog format %d\n") %
45 (revlogv1 and 1 or 0))
45 (revlogv1 and 1 or 0))
46
46
47 seen = {}
47 seen = {}
48 repo.ui.status(_("checking changesets\n"))
48 repo.ui.status(_("checking changesets\n"))
49 checksize(repo.changelog, "changelog")
49 checksize(repo.changelog, "changelog")
50
50
51 for i in xrange(repo.changelog.count()):
51 for i in xrange(repo.changelog.count()):
52 changesets += 1
52 changesets += 1
53 n = repo.changelog.node(i)
53 n = repo.changelog.node(i)
54 l = repo.changelog.linkrev(n)
54 l = repo.changelog.linkrev(n)
55 if l != i:
55 if l != i:
56 err(_("incorrect link (%d) for changeset revision %d") %(l, i))
56 err(_("incorrect link (%d) for changeset revision %d") %(l, i))
57 if n in seen:
57 if n in seen:
58 err(_("duplicate changeset at revision %d") % i)
58 err(_("duplicate changeset at revision %d") % i)
59 seen[n] = 1
59 seen[n] = 1
60
60
61 for p in repo.changelog.parents(n):
61 for p in repo.changelog.parents(n):
62 if p not in repo.changelog.nodemap:
62 if p not in repo.changelog.nodemap:
63 err(_("changeset %s has unknown parent %s") %
63 err(_("changeset %s has unknown parent %s") %
64 (short(n), short(p)))
64 (short(n), short(p)))
65 try:
65 try:
66 changes = repo.changelog.read(n)
66 changes = repo.changelog.read(n)
67 except KeyboardInterrupt:
67 except KeyboardInterrupt:
68 repo.ui.warn(_("interrupted"))
68 repo.ui.warn(_("interrupted"))
69 raise
69 raise
70 except Exception, inst:
70 except Exception, inst:
71 err(_("unpacking changeset %s: %s") % (short(n), inst))
71 err(_("unpacking changeset %s: %s") % (short(n), inst))
72 continue
72 continue
73
73
74 neededmanifests[changes[0]] = n
74 neededmanifests[changes[0]] = n
75
75
76 for f in changes[3]:
76 for f in changes[3]:
77 filelinkrevs.setdefault(f, []).append(i)
77 filelinkrevs.setdefault(f, []).append(i)
78
78
79 seen = {}
79 seen = {}
80 repo.ui.status(_("checking manifests\n"))
80 repo.ui.status(_("checking manifests\n"))
81 checkversion(repo.manifest, "manifest")
81 checkversion(repo.manifest, "manifest")
82 checksize(repo.manifest, "manifest")
82 checksize(repo.manifest, "manifest")
83
83
84 for i in xrange(repo.manifest.count()):
84 for i in xrange(repo.manifest.count()):
85 n = repo.manifest.node(i)
85 n = repo.manifest.node(i)
86 l = repo.manifest.linkrev(n)
86 l = repo.manifest.linkrev(n)
87
87
88 if l < 0 or l >= repo.changelog.count():
88 if l < 0 or l >= repo.changelog.count():
89 err(_("bad manifest link (%d) at revision %d") % (l, i))
89 err(_("bad manifest link (%d) at revision %d") % (l, i))
90
90
91 if n in neededmanifests:
91 if n in neededmanifests:
92 del neededmanifests[n]
92 del neededmanifests[n]
93
93
94 if n in seen:
94 if n in seen:
95 err(_("duplicate manifest at revision %d") % i)
95 err(_("duplicate manifest at revision %d") % i)
96
96
97 seen[n] = 1
97 seen[n] = 1
98
98
99 for p in repo.manifest.parents(n):
99 for p in repo.manifest.parents(n):
100 if p not in repo.manifest.nodemap:
100 if p not in repo.manifest.nodemap:
101 err(_("manifest %s has unknown parent %s") %
101 err(_("manifest %s has unknown parent %s") %
102 (short(n), short(p)))
102 (short(n), short(p)))
103
103
104 try:
104 try:
105 for f, fn in repo.manifest.readdelta(n).iteritems():
105 for f, fn in repo.manifest.readdelta(n).iteritems():
106 filenodes.setdefault(f, {})[fn] = 1
106 filenodes.setdefault(f, {})[fn] = 1
107 except KeyboardInterrupt:
107 except KeyboardInterrupt:
108 repo.ui.warn(_("interrupted"))
108 repo.ui.warn(_("interrupted"))
109 raise
109 raise
110 except Exception, inst:
110 except Exception, inst:
111 err(_("reading delta for manifest %s: %s") % (short(n), inst))
111 err(_("reading delta for manifest %s: %s") % (short(n), inst))
112 continue
112 continue
113
113
114 repo.ui.status(_("crosschecking files in changesets and manifests\n"))
114 repo.ui.status(_("crosschecking files in changesets and manifests\n"))
115
115
116 for m, c in neededmanifests.items():
116 for m, c in neededmanifests.items():
117 err(_("Changeset %s refers to unknown manifest %s") %
117 err(_("Changeset %s refers to unknown manifest %s") %
118 (short(m), short(c)))
118 (short(m), short(c)))
119 del neededmanifests
119 del neededmanifests
120
120
121 for f in filenodes:
121 for f in filenodes:
122 if f not in filelinkrevs:
122 if f not in filelinkrevs:
123 err(_("file %s in manifest but not in changesets") % f)
123 err(_("file %s in manifest but not in changesets") % f)
124
124
125 for f in filelinkrevs:
125 for f in filelinkrevs:
126 if f not in filenodes:
126 if f not in filenodes:
127 err(_("file %s in changeset but not in manifest") % f)
127 err(_("file %s in changeset but not in manifest") % f)
128
128
129 repo.ui.status(_("checking files\n"))
129 repo.ui.status(_("checking files\n"))
130 ff = filenodes.keys()
130 ff = filenodes.keys()
131 ff.sort()
131 ff.sort()
132 for f in ff:
132 for f in ff:
133 if f == "/dev/null":
133 if f == "/dev/null":
134 continue
134 continue
135 files += 1
135 files += 1
136 if not f:
136 if not f:
137 err(_("file without name in manifest %s") % short(n))
137 err(_("file without name in manifest %s") % short(n))
138 continue
138 continue
139 fl = repo.file(f)
139 fl = repo.file(f)
140 checkversion(fl, f)
140 checkversion(fl, f)
141 checksize(fl, f)
141 checksize(fl, f)
142
142
143 nodes = {nullid: 1}
143 nodes = {nullid: 1}
144 seen = {}
144 seen = {}
145 for i in xrange(fl.count()):
145 for i in xrange(fl.count()):
146 revisions += 1
146 revisions += 1
147 n = fl.node(i)
147 n = fl.node(i)
148
148
149 if n in seen:
149 if n in seen:
150 err(_("%s: duplicate revision %d") % (f, i))
150 err(_("%s: duplicate revision %d") % (f, i))
151 if n not in filenodes[f]:
151 if n not in filenodes[f]:
152 err(_("%s: %d:%s not in manifests") % (f, i, short(n)))
152 err(_("%s: %d:%s not in manifests") % (f, i, short(n)))
153 else:
153 else:
154 del filenodes[f][n]
154 del filenodes[f][n]
155
155
156 flr = fl.linkrev(n)
156 flr = fl.linkrev(n)
157 if flr not in filelinkrevs.get(f, []):
157 if flr not in filelinkrevs.get(f, []):
158 err(_("%s:%s points to unexpected changeset %d")
158 err(_("%s:%s points to unexpected changeset %d")
159 % (f, short(n), flr))
159 % (f, short(n), flr))
160 else:
160 else:
161 filelinkrevs[f].remove(flr)
161 filelinkrevs[f].remove(flr)
162
162
163 # verify contents
163 # verify contents
164 try:
164 try:
165 t = fl.read(n)
165 t = fl.read(n)
166 except KeyboardInterrupt:
166 except KeyboardInterrupt:
167 repo.ui.warn(_("interrupted"))
167 repo.ui.warn(_("interrupted"))
168 raise
168 raise
169 except Exception, inst:
169 except Exception, inst:
170 err(_("unpacking file %s %s: %s") % (f, short(n), inst))
170 err(_("unpacking file %s %s: %s") % (f, short(n), inst))
171
171
172 # verify parents
172 # verify parents
173 (p1, p2) = fl.parents(n)
173 (p1, p2) = fl.parents(n)
174 if p1 not in nodes:
174 if p1 not in nodes:
175 err(_("file %s:%s unknown parent 1 %s") %
175 err(_("file %s:%s unknown parent 1 %s") %
176 (f, short(n), short(p1)))
176 (f, short(n), short(p1)))
177 if p2 not in nodes:
177 if p2 not in nodes:
178 err(_("file %s:%s unknown parent 2 %s") %
178 err(_("file %s:%s unknown parent 2 %s") %
179 (f, short(n), short(p1)))
179 (f, short(n), short(p1)))
180 nodes[n] = 1
180 nodes[n] = 1
181
181
182 # check renames
183 try:
184 rp = fl.renamed(n)
185 if rp:
186 fl2 = repo.file(rp[0])
187 rev = fl2.rev(rp[1])
188 except KeyboardInterrupt:
189 repo.ui.warn(_("interrupted"))
190 raise
191 except Exception, inst:
192 err(_("checking rename on file %s %s: %s") % (f, short(n), inst))
193
182 # cross-check
194 # cross-check
183 for node in filenodes[f]:
195 for node in filenodes[f]:
184 err(_("node %s in manifests not in %s") % (hex(node), f))
196 err(_("node %s in manifests not in %s") % (hex(node), f))
185
197
186 repo.ui.status(_("%d files, %d changesets, %d total revisions\n") %
198 repo.ui.status(_("%d files, %d changesets, %d total revisions\n") %
187 (files, changesets, revisions))
199 (files, changesets, revisions))
188
200
189 if warnings[0]:
201 if warnings[0]:
190 repo.ui.warn(_("%d warnings encountered!\n") % warnings[0])
202 repo.ui.warn(_("%d warnings encountered!\n") % warnings[0])
191 if errors[0]:
203 if errors[0]:
192 repo.ui.warn(_("%d integrity errors encountered!\n") % errors[0])
204 repo.ui.warn(_("%d integrity errors encountered!\n") % errors[0])
193 return 1
205 return 1
194
206
General Comments 0
You need to be logged in to leave comments. Login now