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