##// END OF EJS Templates
verify: reference the correct linkrev when a filelog is missing...
Benoit Boissinot -
r8292:29540554 default
parent child Browse files
Show More
@@ -1,255 +1,255 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 of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2, incorporated herein by reference.
6 # GNU General Public License version 2, incorporated herein by reference.
7
7
8 from node import nullid, short
8 from node import nullid, short
9 from i18n import _
9 from i18n import _
10 import revlog, util, error
10 import revlog, util, error
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 lock.release()
17 lock.release()
18
18
19 def _verify(repo):
19 def _verify(repo):
20 mflinkrevs = {}
20 mflinkrevs = {}
21 filelinkrevs = {}
21 filelinkrevs = {}
22 filenodes = {}
22 filenodes = {}
23 revisions = 0
23 revisions = 0
24 badrevs = {}
24 badrevs = {}
25 errors = [0]
25 errors = [0]
26 warnings = [0]
26 warnings = [0]
27 ui = repo.ui
27 ui = repo.ui
28 cl = repo.changelog
28 cl = repo.changelog
29 mf = repo.manifest
29 mf = repo.manifest
30
30
31 if not repo.cancopy():
31 if not repo.cancopy():
32 raise util.Abort(_("cannot verify bundle or remote repos"))
32 raise util.Abort(_("cannot verify bundle or remote repos"))
33
33
34 def err(linkrev, msg, filename=None):
34 def err(linkrev, msg, filename=None):
35 if linkrev != None:
35 if linkrev != None:
36 badrevs[linkrev] = True
36 badrevs[linkrev] = True
37 else:
37 else:
38 linkrev = '?'
38 linkrev = '?'
39 msg = "%s: %s" % (linkrev, msg)
39 msg = "%s: %s" % (linkrev, msg)
40 if filename:
40 if filename:
41 msg = "%s@%s" % (filename, msg)
41 msg = "%s@%s" % (filename, msg)
42 ui.warn(" " + msg + "\n")
42 ui.warn(" " + msg + "\n")
43 errors[0] += 1
43 errors[0] += 1
44
44
45 def exc(linkrev, msg, inst, filename=None):
45 def exc(linkrev, msg, inst, filename=None):
46 if isinstance(inst, KeyboardInterrupt):
46 if isinstance(inst, KeyboardInterrupt):
47 ui.warn(_("interrupted"))
47 ui.warn(_("interrupted"))
48 raise
48 raise
49 err(linkrev, "%s: %s" % (msg, inst), filename)
49 err(linkrev, "%s: %s" % (msg, inst), filename)
50
50
51 def warn(msg):
51 def warn(msg):
52 ui.warn(msg + "\n")
52 ui.warn(msg + "\n")
53 warnings[0] += 1
53 warnings[0] += 1
54
54
55 def checklog(obj, name):
55 def checklog(obj, name, linkrev):
56 if not len(obj) and (havecl or havemf):
56 if not len(obj) and (havecl or havemf):
57 err(0, _("empty or missing %s") % name)
57 err(linkrev, _("empty or missing %s") % name)
58 return
58 return
59
59
60 d = obj.checksize()
60 d = obj.checksize()
61 if d[0]:
61 if d[0]:
62 err(None, _("data length off by %d bytes") % d[0], name)
62 err(None, _("data length off by %d bytes") % d[0], name)
63 if d[1]:
63 if d[1]:
64 err(None, _("index contains %d extra bytes") % d[1], name)
64 err(None, _("index contains %d extra bytes") % d[1], name)
65
65
66 if obj.version != revlog.REVLOGV0:
66 if obj.version != revlog.REVLOGV0:
67 if not revlogv1:
67 if not revlogv1:
68 warn(_("warning: `%s' uses revlog format 1") % name)
68 warn(_("warning: `%s' uses revlog format 1") % name)
69 elif revlogv1:
69 elif revlogv1:
70 warn(_("warning: `%s' uses revlog format 0") % name)
70 warn(_("warning: `%s' uses revlog format 0") % name)
71
71
72 def checkentry(obj, i, node, seen, linkrevs, f):
72 def checkentry(obj, i, node, seen, linkrevs, f):
73 lr = obj.linkrev(obj.rev(node))
73 lr = obj.linkrev(obj.rev(node))
74 if lr < 0 or (havecl and lr not in linkrevs):
74 if lr < 0 or (havecl and lr not in linkrevs):
75 if lr < 0 or lr >= len(cl):
75 if lr < 0 or lr >= len(cl):
76 msg = _("rev %d points to nonexistent changeset %d")
76 msg = _("rev %d points to nonexistent changeset %d")
77 else:
77 else:
78 msg = _("rev %d points to unexpected changeset %d")
78 msg = _("rev %d points to unexpected changeset %d")
79 err(None, msg % (i, lr), f)
79 err(None, msg % (i, lr), f)
80 if linkrevs:
80 if linkrevs:
81 warn(_(" (expected %s)") % " ".join(map(str,linkrevs)))
81 warn(_(" (expected %s)") % " ".join(map(str,linkrevs)))
82 lr = None # can't be trusted
82 lr = None # can't be trusted
83
83
84 try:
84 try:
85 p1, p2 = obj.parents(node)
85 p1, p2 = obj.parents(node)
86 if p1 not in seen and p1 != nullid:
86 if p1 not in seen and p1 != nullid:
87 err(lr, _("unknown parent 1 %s of %s") %
87 err(lr, _("unknown parent 1 %s of %s") %
88 (short(p1), short(n)), f)
88 (short(p1), short(n)), f)
89 if p2 not in seen and p2 != nullid:
89 if p2 not in seen and p2 != nullid:
90 err(lr, _("unknown parent 2 %s of %s") %
90 err(lr, _("unknown parent 2 %s of %s") %
91 (short(p2), short(p1)), f)
91 (short(p2), short(p1)), f)
92 except Exception, inst:
92 except Exception, inst:
93 exc(lr, _("checking parents of %s") % short(node), inst, f)
93 exc(lr, _("checking parents of %s") % short(node), inst, f)
94
94
95 if node in seen:
95 if node in seen:
96 err(lr, _("duplicate revision %d (%d)") % (i, seen[n]), f)
96 err(lr, _("duplicate revision %d (%d)") % (i, seen[n]), f)
97 seen[n] = i
97 seen[n] = i
98 return lr
98 return lr
99
99
100 revlogv1 = cl.version != revlog.REVLOGV0
100 revlogv1 = cl.version != revlog.REVLOGV0
101 if ui.verbose or not revlogv1:
101 if ui.verbose or not revlogv1:
102 ui.status(_("repository uses revlog format %d\n") %
102 ui.status(_("repository uses revlog format %d\n") %
103 (revlogv1 and 1 or 0))
103 (revlogv1 and 1 or 0))
104
104
105 havecl = len(cl) > 0
105 havecl = len(cl) > 0
106 havemf = len(mf) > 0
106 havemf = len(mf) > 0
107
107
108 ui.status(_("checking changesets\n"))
108 ui.status(_("checking changesets\n"))
109 seen = {}
109 seen = {}
110 checklog(cl, "changelog")
110 checklog(cl, "changelog", 0)
111 for i in repo:
111 for i in repo:
112 n = cl.node(i)
112 n = cl.node(i)
113 checkentry(cl, i, n, seen, [i], "changelog")
113 checkentry(cl, i, n, seen, [i], "changelog")
114
114
115 try:
115 try:
116 changes = cl.read(n)
116 changes = cl.read(n)
117 mflinkrevs.setdefault(changes[0], []).append(i)
117 mflinkrevs.setdefault(changes[0], []).append(i)
118 for f in changes[3]:
118 for f in changes[3]:
119 filelinkrevs.setdefault(f, []).append(i)
119 filelinkrevs.setdefault(f, []).append(i)
120 except Exception, inst:
120 except Exception, inst:
121 exc(i, _("unpacking changeset %s") % short(n), inst)
121 exc(i, _("unpacking changeset %s") % short(n), inst)
122
122
123 ui.status(_("checking manifests\n"))
123 ui.status(_("checking manifests\n"))
124 seen = {}
124 seen = {}
125 checklog(mf, "manifest")
125 checklog(mf, "manifest", 0)
126 for i in mf:
126 for i in mf:
127 n = mf.node(i)
127 n = mf.node(i)
128 lr = checkentry(mf, i, n, seen, mflinkrevs.get(n, []), "manifest")
128 lr = checkentry(mf, i, n, seen, mflinkrevs.get(n, []), "manifest")
129 if n in mflinkrevs:
129 if n in mflinkrevs:
130 del mflinkrevs[n]
130 del mflinkrevs[n]
131
131
132 try:
132 try:
133 for f, fn in mf.readdelta(n).iteritems():
133 for f, fn in mf.readdelta(n).iteritems():
134 if not f:
134 if not f:
135 err(lr, _("file without name in manifest"))
135 err(lr, _("file without name in manifest"))
136 elif f != "/dev/null":
136 elif f != "/dev/null":
137 fns = filenodes.setdefault(f, {})
137 fns = filenodes.setdefault(f, {})
138 if fn not in fns:
138 if fn not in fns:
139 fns[fn] = i
139 fns[fn] = i
140 except Exception, inst:
140 except Exception, inst:
141 exc(lr, _("reading manifest delta %s") % short(n), inst)
141 exc(lr, _("reading manifest delta %s") % short(n), inst)
142
142
143 ui.status(_("crosschecking files in changesets and manifests\n"))
143 ui.status(_("crosschecking files in changesets and manifests\n"))
144
144
145 if havemf:
145 if havemf:
146 for c,m in sorted([(c, m) for m in mflinkrevs for c in mflinkrevs[m]]):
146 for c,m in sorted([(c, m) for m in mflinkrevs for c in mflinkrevs[m]]):
147 err(c, _("changeset refers to unknown manifest %s") % short(m))
147 err(c, _("changeset refers to unknown manifest %s") % short(m))
148 del mflinkrevs
148 del mflinkrevs
149
149
150 for f in sorted(filelinkrevs):
150 for f in sorted(filelinkrevs):
151 if f not in filenodes:
151 if f not in filenodes:
152 lr = filelinkrevs[f][0]
152 lr = filelinkrevs[f][0]
153 err(lr, _("in changeset but not in manifest"), f)
153 err(lr, _("in changeset but not in manifest"), f)
154
154
155 if havecl:
155 if havecl:
156 for f in sorted(filenodes):
156 for f in sorted(filenodes):
157 if f not in filelinkrevs:
157 if f not in filelinkrevs:
158 try:
158 try:
159 fl = repo.file(f)
159 fl = repo.file(f)
160 lr = min([fl.linkrev(fl.rev(n)) for n in filenodes[f]])
160 lr = min([fl.linkrev(fl.rev(n)) for n in filenodes[f]])
161 except:
161 except:
162 lr = None
162 lr = None
163 err(lr, _("in manifest but not in changeset"), f)
163 err(lr, _("in manifest but not in changeset"), f)
164
164
165 ui.status(_("checking files\n"))
165 ui.status(_("checking files\n"))
166
166
167 storefiles = {}
167 storefiles = {}
168 for f, f2, size in repo.store.datafiles():
168 for f, f2, size in repo.store.datafiles():
169 if not f:
169 if not f:
170 err(None, _("cannot decode filename '%s'") % f2)
170 err(None, _("cannot decode filename '%s'") % f2)
171 elif size > 0:
171 elif size > 0:
172 storefiles[f] = True
172 storefiles[f] = True
173
173
174 files = sorted(set(filenodes) | set(filelinkrevs))
174 files = sorted(set(filenodes) | set(filelinkrevs))
175 for f in files:
175 for f in files:
176 try:
176 try:
177 linkrevs = filelinkrevs[f]
177 linkrevs = filelinkrevs[f]
178 except KeyError:
178 except KeyError:
179 # in manifest but not in changelog
179 # in manifest but not in changelog
180 linkrevs = []
180 linkrevs = []
181
181
182 if linkrevs:
182 if linkrevs:
183 lr = linkrevs[0]
183 lr = linkrevs[0]
184 else:
184 else:
185 lr = None
185 lr = None
186
186
187 try:
187 try:
188 fl = repo.file(f)
188 fl = repo.file(f)
189 except error.RevlogError, e:
189 except error.RevlogError, e:
190 err(lr, _("broken revlog! (%s)") % e, f)
190 err(lr, _("broken revlog! (%s)") % e, f)
191 continue
191 continue
192
192
193 for ff in fl.files():
193 for ff in fl.files():
194 try:
194 try:
195 del storefiles[ff]
195 del storefiles[ff]
196 except KeyError:
196 except KeyError:
197 err(lr, _("missing revlog!"), ff)
197 err(lr, _("missing revlog!"), ff)
198
198
199 checklog(fl, f)
199 checklog(fl, f, lr)
200 seen = {}
200 seen = {}
201 for i in fl:
201 for i in fl:
202 revisions += 1
202 revisions += 1
203 n = fl.node(i)
203 n = fl.node(i)
204 lr = checkentry(fl, i, n, seen, linkrevs, f)
204 lr = checkentry(fl, i, n, seen, linkrevs, f)
205 if f in filenodes:
205 if f in filenodes:
206 if havemf and n not in filenodes[f]:
206 if havemf and n not in filenodes[f]:
207 err(lr, _("%s not in manifests") % (short(n)), f)
207 err(lr, _("%s not in manifests") % (short(n)), f)
208 else:
208 else:
209 del filenodes[f][n]
209 del filenodes[f][n]
210
210
211 # verify contents
211 # verify contents
212 try:
212 try:
213 t = fl.read(n)
213 t = fl.read(n)
214 rp = fl.renamed(n)
214 rp = fl.renamed(n)
215 if len(t) != fl.size(i):
215 if len(t) != fl.size(i):
216 if len(fl.revision(n)) != fl.size(i):
216 if len(fl.revision(n)) != fl.size(i):
217 err(lr, _("unpacked size is %s, %s expected") %
217 err(lr, _("unpacked size is %s, %s expected") %
218 (len(t), fl.size(i)), f)
218 (len(t), fl.size(i)), f)
219 except Exception, inst:
219 except Exception, inst:
220 exc(lr, _("unpacking %s") % short(n), inst, f)
220 exc(lr, _("unpacking %s") % short(n), inst, f)
221
221
222 # check renames
222 # check renames
223 try:
223 try:
224 if rp:
224 if rp:
225 fl2 = repo.file(rp[0])
225 fl2 = repo.file(rp[0])
226 if not len(fl2):
226 if not len(fl2):
227 err(lr, _("empty or missing copy source revlog %s:%s")
227 err(lr, _("empty or missing copy source revlog %s:%s")
228 % (rp[0], short(rp[1])), f)
228 % (rp[0], short(rp[1])), f)
229 elif rp[1] == nullid:
229 elif rp[1] == nullid:
230 warn(_("warning: %s@%s: copy source revision is nullid %s:%s")
230 warn(_("warning: %s@%s: copy source revision is nullid %s:%s")
231 % (f, lr, rp[0], short(rp[1])))
231 % (f, lr, rp[0], short(rp[1])))
232 else:
232 else:
233 fl2.rev(rp[1])
233 fl2.rev(rp[1])
234 except Exception, inst:
234 except Exception, inst:
235 exc(lr, _("checking rename of %s") % short(n), inst, f)
235 exc(lr, _("checking rename of %s") % short(n), inst, f)
236
236
237 # cross-check
237 # cross-check
238 if f in filenodes:
238 if f in filenodes:
239 fns = [(mf.linkrev(l), n) for n,l in filenodes[f].iteritems()]
239 fns = [(mf.linkrev(l), n) for n,l in filenodes[f].iteritems()]
240 for lr, node in sorted(fns):
240 for lr, node in sorted(fns):
241 err(lr, _("%s in manifests not found") % short(node), f)
241 err(lr, _("%s in manifests not found") % short(node), f)
242
242
243 for f in storefiles:
243 for f in storefiles:
244 warn(_("warning: orphan revlog '%s'") % f)
244 warn(_("warning: orphan revlog '%s'") % f)
245
245
246 ui.status(_("%d files, %d changesets, %d total revisions\n") %
246 ui.status(_("%d files, %d changesets, %d total revisions\n") %
247 (len(files), len(cl), revisions))
247 (len(files), len(cl), revisions))
248 if warnings[0]:
248 if warnings[0]:
249 ui.warn(_("%d warnings encountered!\n") % warnings[0])
249 ui.warn(_("%d warnings encountered!\n") % warnings[0])
250 if errors[0]:
250 if errors[0]:
251 ui.warn(_("%d integrity errors encountered!\n") % errors[0])
251 ui.warn(_("%d integrity errors encountered!\n") % errors[0])
252 if badrevs:
252 if badrevs:
253 ui.warn(_("(first damaged changeset appears to be %d)\n")
253 ui.warn(_("(first damaged changeset appears to be %d)\n")
254 % min(badrevs))
254 % min(badrevs))
255 return 1
255 return 1
@@ -1,83 +1,83 b''
1 % before update 0, strip 1
1 % before update 0, strip 1
2 changeset: 0:cb9a9f314b8b
2 changeset: 0:cb9a9f314b8b
3 user: test
3 user: test
4 date: Thu Jan 01 00:00:00 1970 +0000
4 date: Thu Jan 01 00:00:00 1970 +0000
5 summary: a
5 summary: a
6
6
7 saving bundle to
7 saving bundle to
8 transaction abort!
8 transaction abort!
9 failed to truncate data/b.i
9 failed to truncate data/b.i
10 rollback failed - please run hg recover
10 rollback failed - please run hg recover
11 abort: Permission denied .hg/store/data/b.i
11 abort: Permission denied .hg/store/data/b.i
12 % after update 0, strip 1
12 % after update 0, strip 1
13 checking changesets
13 checking changesets
14 checking manifests
14 checking manifests
15 crosschecking files in changesets and manifests
15 crosschecking files in changesets and manifests
16 checking files
16 checking files
17 warning: orphan revlog 'data/b.i'
17 warning: orphan revlog 'data/b.i'
18 1 files, 1 changesets, 1 total revisions
18 1 files, 1 changesets, 1 total revisions
19 1 warnings encountered!
19 1 warnings encountered!
20 % journal contents
20 % journal contents
21 00changelog.i
21 00changelog.i
22 00manifest.i
22 00manifest.i
23 data/b.i
23 data/b.i
24 data/c.i
24 data/c.i
25 rolling back interrupted transaction
25 rolling back interrupted transaction
26 checking changesets
26 checking changesets
27 checking manifests
27 checking manifests
28 crosschecking files in changesets and manifests
28 crosschecking files in changesets and manifests
29 checking files
29 checking files
30 1 files, 1 changesets, 1 total revisions
30 1 files, 1 changesets, 1 total revisions
31 % before update 0, strip 1
31 % before update 0, strip 1
32 changeset: 0:cb9a9f314b8b
32 changeset: 0:cb9a9f314b8b
33 user: test
33 user: test
34 date: Thu Jan 01 00:00:00 1970 +0000
34 date: Thu Jan 01 00:00:00 1970 +0000
35 summary: a
35 summary: a
36
36
37 abort: Permission denied .hg/store/data/b.i
37 abort: Permission denied .hg/store/data/b.i
38 % after update 0, strip 1
38 % after update 0, strip 1
39 checking changesets
39 checking changesets
40 checking manifests
40 checking manifests
41 crosschecking files in changesets and manifests
41 crosschecking files in changesets and manifests
42 checking files
42 checking files
43 3 files, 3 changesets, 3 total revisions
43 3 files, 3 changesets, 3 total revisions
44 % journal contents
44 % journal contents
45 cat: .hg/store/journal: No such file or directory
45 cat: .hg/store/journal: No such file or directory
46 % before update 0, strip 1
46 % before update 0, strip 1
47 changeset: 0:cb9a9f314b8b
47 changeset: 0:cb9a9f314b8b
48 user: test
48 user: test
49 date: Thu Jan 01 00:00:00 1970 +0000
49 date: Thu Jan 01 00:00:00 1970 +0000
50 summary: a
50 summary: a
51
51
52 saving bundle to
52 saving bundle to
53 transaction abort!
53 transaction abort!
54 failed to truncate 00changelog.i
54 failed to truncate 00changelog.i
55 rollback failed - please run hg recover
55 rollback failed - please run hg recover
56 abort: Permission denied .hg/store/00changelog.i
56 abort: Permission denied .hg/store/00changelog.i
57 % after update 0, strip 1
57 % after update 0, strip 1
58 checking changesets
58 checking changesets
59 checking manifests
59 checking manifests
60 crosschecking files in changesets and manifests
60 crosschecking files in changesets and manifests
61 1: changeset refers to unknown manifest a539ce0c1a22
61 1: changeset refers to unknown manifest a539ce0c1a22
62 2: changeset refers to unknown manifest e3738bf54399
62 2: changeset refers to unknown manifest e3738bf54399
63 b@1: in changeset but not in manifest
63 b@1: in changeset but not in manifest
64 c@2: in changeset but not in manifest
64 c@2: in changeset but not in manifest
65 checking files
65 checking files
66 data/b.i@1: missing revlog!
66 data/b.i@1: missing revlog!
67 0: empty or missing b
67 1: empty or missing b
68 data/c.i@2: missing revlog!
68 data/c.i@2: missing revlog!
69 0: empty or missing c
69 2: empty or missing c
70 3 files, 3 changesets, 1 total revisions
70 3 files, 3 changesets, 1 total revisions
71 8 integrity errors encountered!
71 8 integrity errors encountered!
72 (first damaged changeset appears to be 0)
72 (first damaged changeset appears to be 1)
73 % journal contents
73 % journal contents
74 00changelog.i
74 00changelog.i
75 00manifest.i
75 00manifest.i
76 data/b.i
76 data/b.i
77 data/c.i
77 data/c.i
78 rolling back interrupted transaction
78 rolling back interrupted transaction
79 checking changesets
79 checking changesets
80 checking manifests
80 checking manifests
81 crosschecking files in changesets and manifests
81 crosschecking files in changesets and manifests
82 checking files
82 checking files
83 1 files, 1 changesets, 1 total revisions
83 1 files, 1 changesets, 1 total revisions
General Comments 0
You need to be logged in to leave comments. Login now