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