##// END OF EJS Templates
verify: print hint to run debugrebuildfncache...
Gregory Szorc -
r25653:9d1e04f5 default
parent child Browse files
Show More
@@ -1,321 +1,326
1 1 # verify.py - repository integrity checking for Mercurial
2 2 #
3 3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from node import nullid, short
9 9 from i18n import _
10 10 import os
11 11 import revlog, util, error
12 12
13 13 def verify(repo):
14 14 lock = repo.lock()
15 15 try:
16 16 return _verify(repo)
17 17 finally:
18 18 lock.release()
19 19
20 20 def _normpath(f):
21 21 # under hg < 2.4, convert didn't sanitize paths properly, so a
22 22 # converted repo may contain repeated slashes
23 23 while '//' in f:
24 24 f = f.replace('//', '/')
25 25 return f
26 26
27 27 def _verify(repo):
28 28 repo = repo.unfiltered()
29 29 mflinkrevs = {}
30 30 filelinkrevs = {}
31 31 filenodes = {}
32 32 revisions = 0
33 33 badrevs = set()
34 34 errors = [0]
35 35 warnings = [0]
36 36 ui = repo.ui
37 37 cl = repo.changelog
38 38 mf = repo.manifest
39 39 lrugetctx = util.lrucachefunc(repo.changectx)
40 40
41 41 if not repo.url().startswith('file:'):
42 42 raise util.Abort(_("cannot verify bundle or remote repos"))
43 43
44 44 def err(linkrev, msg, filename=None):
45 45 if linkrev is not None:
46 46 badrevs.add(linkrev)
47 47 else:
48 48 linkrev = '?'
49 49 msg = "%s: %s" % (linkrev, msg)
50 50 if filename:
51 51 msg = "%s@%s" % (filename, msg)
52 52 ui.warn(" " + msg + "\n")
53 53 errors[0] += 1
54 54
55 55 def exc(linkrev, msg, inst, filename=None):
56 56 if isinstance(inst, KeyboardInterrupt):
57 57 ui.warn(_("interrupted"))
58 58 raise
59 59 if not str(inst):
60 60 inst = repr(inst)
61 61 err(linkrev, "%s: %s" % (msg, inst), filename)
62 62
63 63 def warn(msg):
64 64 ui.warn(msg + "\n")
65 65 warnings[0] += 1
66 66
67 67 def checklog(obj, name, linkrev):
68 68 if not len(obj) and (havecl or havemf):
69 69 err(linkrev, _("empty or missing %s") % name)
70 70 return
71 71
72 72 d = obj.checksize()
73 73 if d[0]:
74 74 err(None, _("data length off by %d bytes") % d[0], name)
75 75 if d[1]:
76 76 err(None, _("index contains %d extra bytes") % d[1], name)
77 77
78 78 if obj.version != revlog.REVLOGV0:
79 79 if not revlogv1:
80 80 warn(_("warning: `%s' uses revlog format 1") % name)
81 81 elif revlogv1:
82 82 warn(_("warning: `%s' uses revlog format 0") % name)
83 83
84 84 def checkentry(obj, i, node, seen, linkrevs, f):
85 85 lr = obj.linkrev(obj.rev(node))
86 86 if lr < 0 or (havecl and lr not in linkrevs):
87 87 if lr < 0 or lr >= len(cl):
88 88 msg = _("rev %d points to nonexistent changeset %d")
89 89 else:
90 90 msg = _("rev %d points to unexpected changeset %d")
91 91 err(None, msg % (i, lr), f)
92 92 if linkrevs:
93 93 if f and len(linkrevs) > 1:
94 94 try:
95 95 # attempt to filter down to real linkrevs
96 96 linkrevs = [l for l in linkrevs
97 97 if lrugetctx(l)[f].filenode() == node]
98 98 except Exception:
99 99 pass
100 100 warn(_(" (expected %s)") % " ".join(map(str, linkrevs)))
101 101 lr = None # can't be trusted
102 102
103 103 try:
104 104 p1, p2 = obj.parents(node)
105 105 if p1 not in seen and p1 != nullid:
106 106 err(lr, _("unknown parent 1 %s of %s") %
107 107 (short(p1), short(node)), f)
108 108 if p2 not in seen and p2 != nullid:
109 109 err(lr, _("unknown parent 2 %s of %s") %
110 110 (short(p2), short(node)), f)
111 111 except Exception, inst:
112 112 exc(lr, _("checking parents of %s") % short(node), inst, f)
113 113
114 114 if node in seen:
115 115 err(lr, _("duplicate revision %d (%d)") % (i, seen[node]), f)
116 116 seen[node] = i
117 117 return lr
118 118
119 119 if os.path.exists(repo.sjoin("journal")):
120 120 ui.warn(_("abandoned transaction found - run hg recover\n"))
121 121
122 122 revlogv1 = cl.version != revlog.REVLOGV0
123 123 if ui.verbose or not revlogv1:
124 124 ui.status(_("repository uses revlog format %d\n") %
125 125 (revlogv1 and 1 or 0))
126 126
127 127 havecl = len(cl) > 0
128 128 havemf = len(mf) > 0
129 129
130 130 ui.status(_("checking changesets\n"))
131 131 refersmf = False
132 132 seen = {}
133 133 checklog(cl, "changelog", 0)
134 134 total = len(repo)
135 135 for i in repo:
136 136 ui.progress(_('checking'), i, total=total, unit=_('changesets'))
137 137 n = cl.node(i)
138 138 checkentry(cl, i, n, seen, [i], "changelog")
139 139
140 140 try:
141 141 changes = cl.read(n)
142 142 if changes[0] != nullid:
143 143 mflinkrevs.setdefault(changes[0], []).append(i)
144 144 refersmf = True
145 145 for f in changes[3]:
146 146 filelinkrevs.setdefault(_normpath(f), []).append(i)
147 147 except Exception, inst:
148 148 refersmf = True
149 149 exc(i, _("unpacking changeset %s") % short(n), inst)
150 150 ui.progress(_('checking'), None)
151 151
152 152 ui.status(_("checking manifests\n"))
153 153 seen = {}
154 154 if refersmf:
155 155 # Do not check manifest if there are only changelog entries with
156 156 # null manifests.
157 157 checklog(mf, "manifest", 0)
158 158 total = len(mf)
159 159 for i in mf:
160 160 ui.progress(_('checking'), i, total=total, unit=_('manifests'))
161 161 n = mf.node(i)
162 162 lr = checkentry(mf, i, n, seen, mflinkrevs.get(n, []), "manifest")
163 163 if n in mflinkrevs:
164 164 del mflinkrevs[n]
165 165 else:
166 166 err(lr, _("%s not in changesets") % short(n), "manifest")
167 167
168 168 try:
169 169 for f, fn in mf.readdelta(n).iteritems():
170 170 if not f:
171 171 err(lr, _("file without name in manifest"))
172 172 elif f != "/dev/null": # ignore this in very old repos
173 173 filenodes.setdefault(_normpath(f), {}).setdefault(fn, lr)
174 174 except Exception, inst:
175 175 exc(lr, _("reading manifest delta %s") % short(n), inst)
176 176 ui.progress(_('checking'), None)
177 177
178 178 ui.status(_("crosschecking files in changesets and manifests\n"))
179 179
180 180 total = len(mflinkrevs) + len(filelinkrevs) + len(filenodes)
181 181 count = 0
182 182 if havemf:
183 183 for c, m in sorted([(c, m) for m in mflinkrevs
184 184 for c in mflinkrevs[m]]):
185 185 count += 1
186 186 if m == nullid:
187 187 continue
188 188 ui.progress(_('crosschecking'), count, total=total)
189 189 err(c, _("changeset refers to unknown manifest %s") % short(m))
190 190 mflinkrevs = None # del is bad here due to scope issues
191 191
192 192 for f in sorted(filelinkrevs):
193 193 count += 1
194 194 ui.progress(_('crosschecking'), count, total=total)
195 195 if f not in filenodes:
196 196 lr = filelinkrevs[f][0]
197 197 err(lr, _("in changeset but not in manifest"), f)
198 198
199 199 if havecl:
200 200 for f in sorted(filenodes):
201 201 count += 1
202 202 ui.progress(_('crosschecking'), count, total=total)
203 203 if f not in filelinkrevs:
204 204 try:
205 205 fl = repo.file(f)
206 206 lr = min([fl.linkrev(fl.rev(n)) for n in filenodes[f]])
207 207 except Exception:
208 208 lr = None
209 209 err(lr, _("in manifest but not in changeset"), f)
210 210
211 211 ui.progress(_('crosschecking'), None)
212 212
213 213 ui.status(_("checking files\n"))
214 214
215 215 storefiles = set()
216 216 for f, f2, size in repo.store.datafiles():
217 217 if not f:
218 218 err(None, _("cannot decode filename '%s'") % f2)
219 219 elif size > 0 or not revlogv1:
220 220 storefiles.add(_normpath(f))
221 221
222 fncachewarned = False
222 223 files = sorted(set(filenodes) | set(filelinkrevs))
223 224 total = len(files)
224 225 for i, f in enumerate(files):
225 226 ui.progress(_('checking'), i, item=f, total=total)
226 227 try:
227 228 linkrevs = filelinkrevs[f]
228 229 except KeyError:
229 230 # in manifest but not in changelog
230 231 linkrevs = []
231 232
232 233 if linkrevs:
233 234 lr = linkrevs[0]
234 235 else:
235 236 lr = None
236 237
237 238 try:
238 239 fl = repo.file(f)
239 240 except error.RevlogError, e:
240 241 err(lr, _("broken revlog! (%s)") % e, f)
241 242 continue
242 243
243 244 for ff in fl.files():
244 245 try:
245 246 storefiles.remove(ff)
246 247 except KeyError:
247 248 warn(_(" warning: revlog '%s' not in fncache!") % ff)
249 fncachewarned = True
248 250
249 251 checklog(fl, f, lr)
250 252 seen = {}
251 253 rp = None
252 254 for i in fl:
253 255 revisions += 1
254 256 n = fl.node(i)
255 257 lr = checkentry(fl, i, n, seen, linkrevs, f)
256 258 if f in filenodes:
257 259 if havemf and n not in filenodes[f]:
258 260 err(lr, _("%s not in manifests") % (short(n)), f)
259 261 else:
260 262 del filenodes[f][n]
261 263
262 264 # verify contents
263 265 try:
264 266 l = len(fl.read(n))
265 267 rp = fl.renamed(n)
266 268 if l != fl.size(i):
267 269 if len(fl.revision(n)) != fl.size(i):
268 270 err(lr, _("unpacked size is %s, %s expected") %
269 271 (l, fl.size(i)), f)
270 272 except error.CensoredNodeError:
271 273 if ui.config("censor", "policy", "abort") == "abort":
272 274 err(lr, _("censored file data"), f)
273 275 except Exception, inst:
274 276 exc(lr, _("unpacking %s") % short(n), inst, f)
275 277
276 278 # check renames
277 279 try:
278 280 if rp:
279 281 if lr is not None and ui.verbose:
280 282 ctx = lrugetctx(lr)
281 283 found = False
282 284 for pctx in ctx.parents():
283 285 if rp[0] in pctx:
284 286 found = True
285 287 break
286 288 if not found:
287 289 warn(_("warning: copy source of '%s' not"
288 290 " in parents of %s") % (f, ctx))
289 291 fl2 = repo.file(rp[0])
290 292 if not len(fl2):
291 293 err(lr, _("empty or missing copy source revlog %s:%s")
292 294 % (rp[0], short(rp[1])), f)
293 295 elif rp[1] == nullid:
294 296 ui.note(_("warning: %s@%s: copy source"
295 297 " revision is nullid %s:%s\n")
296 298 % (f, lr, rp[0], short(rp[1])))
297 299 else:
298 300 fl2.rev(rp[1])
299 301 except Exception, inst:
300 302 exc(lr, _("checking rename of %s") % short(n), inst, f)
301 303
302 304 # cross-check
303 305 if f in filenodes:
304 306 fns = [(lr, n) for n, lr in filenodes[f].iteritems()]
305 307 for lr, node in sorted(fns):
306 308 err(lr, _("%s in manifests not found") % short(node), f)
307 309 ui.progress(_('checking'), None)
308 310
309 311 for f in storefiles:
310 312 warn(_("warning: orphan revlog '%s'") % f)
311 313
312 314 ui.status(_("%d files, %d changesets, %d total revisions\n") %
313 315 (len(files), len(cl), revisions))
314 316 if warnings[0]:
315 317 ui.warn(_("%d warnings encountered!\n") % warnings[0])
318 if fncachewarned:
319 ui.warn(_('hint: run "hg debugrebuildfncache" to recover from '
320 'corrupt fncache\n'))
316 321 if errors[0]:
317 322 ui.warn(_("%d integrity errors encountered!\n") % errors[0])
318 323 if badrevs:
319 324 ui.warn(_("(first damaged changeset appears to be %d)\n")
320 325 % min(badrevs))
321 326 return 1
@@ -1,380 +1,397
1 1 Init repo1:
2 2
3 3 $ hg init repo1
4 4 $ cd repo1
5 5 $ echo "some text" > a
6 6 $ hg add
7 7 adding a
8 8 $ hg ci -m first
9 9 $ cat .hg/store/fncache | sort
10 10 data/a.i
11 11
12 12 Testing a.i/b:
13 13
14 14 $ mkdir a.i
15 15 $ echo "some other text" > a.i/b
16 16 $ hg add
17 17 adding a.i/b (glob)
18 18 $ hg ci -m second
19 19 $ cat .hg/store/fncache | sort
20 20 data/a.i
21 21 data/a.i.hg/b.i
22 22
23 23 Testing a.i.hg/c:
24 24
25 25 $ mkdir a.i.hg
26 26 $ echo "yet another text" > a.i.hg/c
27 27 $ hg add
28 28 adding a.i.hg/c (glob)
29 29 $ hg ci -m third
30 30 $ cat .hg/store/fncache | sort
31 31 data/a.i
32 32 data/a.i.hg.hg/c.i
33 33 data/a.i.hg/b.i
34 34
35 35 Testing verify:
36 36
37 37 $ hg verify
38 38 checking changesets
39 39 checking manifests
40 40 crosschecking files in changesets and manifests
41 41 checking files
42 42 3 files, 3 changesets, 3 total revisions
43 43
44 44 $ rm .hg/store/fncache
45 45
46 46 $ hg verify
47 47 checking changesets
48 48 checking manifests
49 49 crosschecking files in changesets and manifests
50 50 checking files
51 51 warning: revlog 'data/a.i' not in fncache!
52 52 warning: revlog 'data/a.i.hg/c.i' not in fncache!
53 53 warning: revlog 'data/a.i/b.i' not in fncache!
54 54 3 files, 3 changesets, 3 total revisions
55 55 3 warnings encountered!
56 hint: run "hg debugrebuildfncache" to recover from corrupt fncache
57
58 Follow the hint to make sure it works
59
60 $ hg debugrebuildfncache
61 adding data/a.i
62 adding data/a.i.hg/c.i
63 adding data/a.i/b.i
64 3 items added, 0 removed from fncache
65
66 $ hg verify
67 checking changesets
68 checking manifests
69 crosschecking files in changesets and manifests
70 checking files
71 3 files, 3 changesets, 3 total revisions
72
56 73 $ cd ..
57 74
58 75 Non store repo:
59 76
60 77 $ hg --config format.usestore=False init foo
61 78 $ cd foo
62 79 $ mkdir tst.d
63 80 $ echo foo > tst.d/foo
64 81 $ hg ci -Amfoo
65 82 adding tst.d/foo
66 83 $ find .hg | sort
67 84 .hg
68 85 .hg/00changelog.i
69 86 .hg/00manifest.i
70 87 .hg/cache
71 88 .hg/cache/branch2-served
72 89 .hg/cache/rbc-names-v1
73 90 .hg/cache/rbc-revs-v1
74 91 .hg/data
75 92 .hg/data/tst.d.hg
76 93 .hg/data/tst.d.hg/foo.i
77 94 .hg/dirstate
78 95 .hg/last-message.txt
79 96 .hg/phaseroots
80 97 .hg/requires
81 98 .hg/undo
82 99 .hg/undo.backupfiles
83 100 .hg/undo.bookmarks
84 101 .hg/undo.branch
85 102 .hg/undo.desc
86 103 .hg/undo.dirstate
87 104 .hg/undo.phaseroots
88 105 $ cd ..
89 106
90 107 Non fncache repo:
91 108
92 109 $ hg --config format.usefncache=False init bar
93 110 $ cd bar
94 111 $ mkdir tst.d
95 112 $ echo foo > tst.d/Foo
96 113 $ hg ci -Amfoo
97 114 adding tst.d/Foo
98 115 $ find .hg | sort
99 116 .hg
100 117 .hg/00changelog.i
101 118 .hg/cache
102 119 .hg/cache/branch2-served
103 120 .hg/cache/rbc-names-v1
104 121 .hg/cache/rbc-revs-v1
105 122 .hg/dirstate
106 123 .hg/last-message.txt
107 124 .hg/requires
108 125 .hg/store
109 126 .hg/store/00changelog.i
110 127 .hg/store/00manifest.i
111 128 .hg/store/data
112 129 .hg/store/data/tst.d.hg
113 130 .hg/store/data/tst.d.hg/_foo.i
114 131 .hg/store/phaseroots
115 132 .hg/store/undo
116 133 .hg/store/undo.backupfiles
117 134 .hg/store/undo.phaseroots
118 135 .hg/undo.bookmarks
119 136 .hg/undo.branch
120 137 .hg/undo.desc
121 138 .hg/undo.dirstate
122 139 $ cd ..
123 140
124 141 Encoding of reserved / long paths in the store
125 142
126 143 $ hg init r2
127 144 $ cd r2
128 145 $ cat <<EOF > .hg/hgrc
129 146 > [ui]
130 147 > portablefilenames = ignore
131 148 > EOF
132 149
133 150 $ hg import -q --bypass - <<EOF
134 151 > # HG changeset patch
135 152 > # User test
136 153 > # Date 0 0
137 154 > # Node ID 1c7a2f7cb77be1a0def34e4c7cabc562ad98fbd7
138 155 > # Parent 0000000000000000000000000000000000000000
139 156 > 1
140 157 >
141 158 > diff --git a/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345/xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-123456789-12.3456789-12345-ABCDEFGHIJKLMNOPRSTUVWXYZ-abcdefghjiklmnopqrstuvwxyz b/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345/xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-123456789-12.3456789-12345-ABCDEFGHIJKLMNOPRSTUVWXYZ-abcdefghjiklmnopqrstuvwxyz
142 159 > new file mode 100644
143 160 > --- /dev/null
144 161 > +++ b/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345/xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-123456789-12.3456789-12345-ABCDEFGHIJKLMNOPRSTUVWXYZ-abcdefghjiklmnopqrstuvwxyz
145 162 > @@ -0,0 +1,1 @@
146 163 > +foo
147 164 > diff --git a/AUX/SECOND/X.PRN/FOURTH/FI:FTH/SIXTH/SEVENTH/EIGHTH/NINETH/TENTH/ELEVENTH/LOREMIPSUM.TXT b/AUX/SECOND/X.PRN/FOURTH/FI:FTH/SIXTH/SEVENTH/EIGHTH/NINETH/TENTH/ELEVENTH/LOREMIPSUM.TXT
148 165 > new file mode 100644
149 166 > --- /dev/null
150 167 > +++ b/AUX/SECOND/X.PRN/FOURTH/FI:FTH/SIXTH/SEVENTH/EIGHTH/NINETH/TENTH/ELEVENTH/LOREMIPSUM.TXT
151 168 > @@ -0,0 +1,1 @@
152 169 > +foo
153 170 > diff --git a/Project Planning/Resources/AnotherLongDirectoryName/Followedbyanother/AndAnother/AndThenAnExtremelyLongFileName.txt b/Project Planning/Resources/AnotherLongDirectoryName/Followedbyanother/AndAnother/AndThenAnExtremelyLongFileName.txt
154 171 > new file mode 100644
155 172 > --- /dev/null
156 173 > +++ b/Project Planning/Resources/AnotherLongDirectoryName/Followedbyanother/AndAnother/AndThenAnExtremelyLongFileName.txt
157 174 > @@ -0,0 +1,1 @@
158 175 > +foo
159 176 > diff --git a/bla.aux/prn/PRN/lpt/com3/nul/coma/foo.NUL/normal.c b/bla.aux/prn/PRN/lpt/com3/nul/coma/foo.NUL/normal.c
160 177 > new file mode 100644
161 178 > --- /dev/null
162 179 > +++ b/bla.aux/prn/PRN/lpt/com3/nul/coma/foo.NUL/normal.c
163 180 > @@ -0,0 +1,1 @@
164 181 > +foo
165 182 > diff --git a/enterprise/openesbaddons/contrib-imola/corba-bc/netbeansplugin/wsdlExtension/src/main/java/META-INF/services/org.netbeans.modules.xml.wsdl.bindingsupport.spi.ExtensibilityElementTemplateProvider b/enterprise/openesbaddons/contrib-imola/corba-bc/netbeansplugin/wsdlExtension/src/main/java/META-INF/services/org.netbeans.modules.xml.wsdl.bindingsupport.spi.ExtensibilityElementTemplateProvider
166 183 > new file mode 100644
167 184 > --- /dev/null
168 185 > +++ b/enterprise/openesbaddons/contrib-imola/corba-bc/netbeansplugin/wsdlExtension/src/main/java/META-INF/services/org.netbeans.modules.xml.wsdl.bindingsupport.spi.ExtensibilityElementTemplateProvider
169 186 > @@ -0,0 +1,1 @@
170 187 > +foo
171 188 > EOF
172 189
173 190 $ find .hg/store -name *.i | sort
174 191 .hg/store/00changelog.i
175 192 .hg/store/00manifest.i
176 193 .hg/store/data/bla.aux/pr~6e/_p_r_n/lpt/co~6d3/nu~6c/coma/foo._n_u_l/normal.c.i
177 194 .hg/store/dh/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345/xxxxxx168e07b38e65eff86ab579afaaa8e30bfbe0f35f.i
178 195 .hg/store/dh/au~78/second/x.prn/fourth/fi~3afth/sixth/seventh/eighth/nineth/tenth/loremia20419e358ddff1bf8751e38288aff1d7c32ec05.i
179 196 .hg/store/dh/enterpri/openesba/contrib-/corba-bc/netbeans/wsdlexte/src/main/java/org.net7018f27961fdf338a598a40c4683429e7ffb9743.i
180 197 .hg/store/dh/project_/resource/anotherl/followed/andanoth/andthenanextremelylongfilename0d8e1f4187c650e2f1fdca9fd90f786bc0976b6b.i
181 198
182 199 $ cd ..
183 200
184 201 Aborting lock does not prevent fncache writes
185 202
186 203 $ cat > exceptionext.py <<EOF
187 204 > import os
188 205 > from mercurial import commands, util
189 206 > from mercurial.extensions import wrapfunction
190 207 >
191 208 > def lockexception(orig, vfs, lockname, wait, releasefn, acquirefn, desc):
192 209 > def releasewrap():
193 210 > raise util.Abort("forced lock failure")
194 211 > return orig(vfs, lockname, wait, releasewrap, acquirefn, desc)
195 212 >
196 213 > def reposetup(ui, repo):
197 214 > wrapfunction(repo, '_lock', lockexception)
198 215 >
199 216 > cmdtable = {}
200 217 >
201 218 > EOF
202 219 $ extpath=`pwd`/exceptionext.py
203 220 $ hg init fncachetxn
204 221 $ cd fncachetxn
205 222 $ printf "[extensions]\nexceptionext=$extpath\n" >> .hg/hgrc
206 223 $ touch y
207 224 $ hg ci -qAm y
208 225 abort: forced lock failure
209 226 [255]
210 227 $ cat .hg/store/fncache
211 228 data/y.i
212 229
213 230 Aborting transaction prevents fncache change
214 231
215 232 $ cat > ../exceptionext.py <<EOF
216 233 > import os
217 234 > from mercurial import commands, util, localrepo
218 235 > from mercurial.extensions import wrapfunction
219 236 >
220 237 > def wrapper(orig, self, *args, **kwargs):
221 238 > tr = orig(self, *args, **kwargs)
222 239 > def fail(tr):
223 240 > raise util.Abort("forced transaction failure")
224 241 > # zzz prefix to ensure it sorted after store.write
225 242 > tr.addfinalize('zzz-forcefails', fail)
226 243 > return tr
227 244 >
228 245 > def uisetup(ui):
229 246 > wrapfunction(localrepo.localrepository, 'transaction', wrapper)
230 247 >
231 248 > cmdtable = {}
232 249 >
233 250 > EOF
234 251 $ rm -f "${extpath}c"
235 252 $ touch z
236 253 $ hg ci -qAm z
237 254 transaction abort!
238 255 rollback completed
239 256 abort: forced transaction failure
240 257 [255]
241 258 $ cat .hg/store/fncache
242 259 data/y.i
243 260
244 261 Aborted transactions can be recovered later
245 262
246 263 $ cat > ../exceptionext.py <<EOF
247 264 > import os
248 265 > from mercurial import commands, util, transaction, localrepo
249 266 > from mercurial.extensions import wrapfunction
250 267 >
251 268 > def trwrapper(orig, self, *args, **kwargs):
252 269 > tr = orig(self, *args, **kwargs)
253 270 > def fail(tr):
254 271 > raise util.Abort("forced transaction failure")
255 272 > # zzz prefix to ensure it sorted after store.write
256 273 > tr.addfinalize('zzz-forcefails', fail)
257 274 > return tr
258 275 >
259 276 > def abortwrapper(orig, self, *args, **kwargs):
260 277 > raise util.Abort("forced transaction failure")
261 278 >
262 279 > def uisetup(ui):
263 280 > wrapfunction(localrepo.localrepository, 'transaction', trwrapper)
264 281 > wrapfunction(transaction.transaction, '_abort', abortwrapper)
265 282 >
266 283 > cmdtable = {}
267 284 >
268 285 > EOF
269 286 $ rm -f "${extpath}c"
270 287 $ hg up -q 1
271 288 $ touch z
272 289 $ hg ci -qAm z 2>/dev/null
273 290 [255]
274 291 $ cat .hg/store/fncache | sort
275 292 data/y.i
276 293 data/z.i
277 294 $ hg recover
278 295 rolling back interrupted transaction
279 296 checking changesets
280 297 checking manifests
281 298 crosschecking files in changesets and manifests
282 299 checking files
283 300 1 files, 1 changesets, 1 total revisions
284 301 $ cat .hg/store/fncache
285 302 data/y.i
286 303
287 304 $ cd ..
288 305
289 306 debugrebuildfncache does nothing unless repo has fncache requirement
290 307
291 308 $ hg --config format.usefncache=false init nofncache
292 309 $ cd nofncache
293 310 $ hg debugrebuildfncache
294 311 (not rebuilding fncache because repository does not support fncache
295 312
296 313 $ cd ..
297 314
298 315 debugrebuildfncache works on empty repository
299 316
300 317 $ hg init empty
301 318 $ cd empty
302 319 $ hg debugrebuildfncache
303 320 fncache already up to date
304 321 $ cd ..
305 322
306 323 debugrebuildfncache on an up to date repository no-ops
307 324
308 325 $ hg init repo
309 326 $ cd repo
310 327 $ echo initial > foo
311 328 $ echo initial > .bar
312 329 $ hg commit -A -m initial
313 330 adding .bar
314 331 adding foo
315 332
316 333 $ cat .hg/store/fncache | sort
317 334 data/.bar.i
318 335 data/foo.i
319 336
320 337 $ hg debugrebuildfncache
321 338 fncache already up to date
322 339
323 340 debugrebuildfncache restores deleted fncache file
324 341
325 342 $ rm -f .hg/store/fncache
326 343 $ hg debugrebuildfncache
327 344 adding data/.bar.i
328 345 adding data/foo.i
329 346 2 items added, 0 removed from fncache
330 347
331 348 $ cat .hg/store/fncache | sort
332 349 data/.bar.i
333 350 data/foo.i
334 351
335 352 Rebuild after rebuild should no-op
336 353
337 354 $ hg debugrebuildfncache
338 355 fncache already up to date
339 356
340 357 A single missing file should get restored, an extra file should be removed
341 358
342 359 $ cat > .hg/store/fncache << EOF
343 360 > data/foo.i
344 361 > data/bad-entry.i
345 362 > EOF
346 363
347 364 $ hg debugrebuildfncache
348 365 removing data/bad-entry.i
349 366 adding data/.bar.i
350 367 1 items added, 1 removed from fncache
351 368
352 369 $ cat .hg/store/fncache | sort
353 370 data/.bar.i
354 371 data/foo.i
355 372
356 373 $ cd ..
357 374
358 375 Try a simple variation without dotencode to ensure fncache is ignorant of encoding
359 376
360 377 $ hg --config format.dotencode=false init nodotencode
361 378 $ cd nodotencode
362 379 $ echo initial > foo
363 380 $ echo initial > .bar
364 381 $ hg commit -A -m initial
365 382 adding .bar
366 383 adding foo
367 384
368 385 $ cat .hg/store/fncache | sort
369 386 data/.bar.i
370 387 data/foo.i
371 388
372 389 $ rm .hg/store/fncache
373 390 $ hg debugrebuildfncache
374 391 adding data/.bar.i
375 392 adding data/foo.i
376 393 2 items added, 0 removed from fncache
377 394
378 395 $ cat .hg/store/fncache | sort
379 396 data/.bar.i
380 397 data/foo.i
@@ -1,116 +1,117
1 1 prepare repo
2 2
3 3 $ hg init a
4 4 $ cd a
5 5 $ echo "some text" > FOO.txt
6 6 $ echo "another text" > bar.txt
7 7 $ echo "more text" > QUICK.txt
8 8 $ hg add
9 9 adding FOO.txt
10 10 adding QUICK.txt
11 11 adding bar.txt
12 12 $ hg ci -mtest1
13 13
14 14 verify
15 15
16 16 $ hg verify
17 17 checking changesets
18 18 checking manifests
19 19 crosschecking files in changesets and manifests
20 20 checking files
21 21 3 files, 1 changesets, 3 total revisions
22 22
23 23 verify with journal
24 24
25 25 $ touch .hg/store/journal
26 26 $ hg verify
27 27 abandoned transaction found - run hg recover
28 28 checking changesets
29 29 checking manifests
30 30 crosschecking files in changesets and manifests
31 31 checking files
32 32 3 files, 1 changesets, 3 total revisions
33 33 $ rm .hg/store/journal
34 34
35 35 introduce some bugs in repo
36 36
37 37 $ cd .hg/store/data
38 38 $ mv _f_o_o.txt.i X_f_o_o.txt.i
39 39 $ mv bar.txt.i xbar.txt.i
40 40 $ rm _q_u_i_c_k.txt.i
41 41
42 42 $ hg verify
43 43 checking changesets
44 44 checking manifests
45 45 crosschecking files in changesets and manifests
46 46 checking files
47 47 warning: revlog 'data/FOO.txt.i' not in fncache!
48 48 0: empty or missing FOO.txt
49 49 FOO.txt@0: f62022d3d590 in manifests not found
50 50 warning: revlog 'data/QUICK.txt.i' not in fncache!
51 51 0: empty or missing QUICK.txt
52 52 QUICK.txt@0: 88b857db8eba in manifests not found
53 53 warning: revlog 'data/bar.txt.i' not in fncache!
54 54 0: empty or missing bar.txt
55 55 bar.txt@0: 256559129457 in manifests not found
56 56 3 files, 1 changesets, 0 total revisions
57 57 3 warnings encountered!
58 hint: run "hg debugrebuildfncache" to recover from corrupt fncache
58 59 6 integrity errors encountered!
59 60 (first damaged changeset appears to be 0)
60 61 [1]
61 62
62 63 $ cd ../../..
63 64 $ cd ..
64 65
65 66 test changelog without a manifest
66 67
67 68 $ hg init b
68 69 $ cd b
69 70 $ hg branch foo
70 71 marked working directory as branch foo
71 72 (branches are permanent and global, did you want a bookmark?)
72 73 $ hg ci -m branchfoo
73 74 $ hg verify
74 75 checking changesets
75 76 checking manifests
76 77 crosschecking files in changesets and manifests
77 78 checking files
78 79 0 files, 1 changesets, 0 total revisions
79 80
80 81 test revlog corruption
81 82
82 83 $ touch a
83 84 $ hg add a
84 85 $ hg ci -m a
85 86
86 87 $ echo 'corrupted' > b
87 88 $ dd if=.hg/store/data/a.i of=start bs=1 count=20 2>/dev/null
88 89 $ cat start b > .hg/store/data/a.i
89 90
90 91 $ hg verify
91 92 checking changesets
92 93 checking manifests
93 94 crosschecking files in changesets and manifests
94 95 checking files
95 96 a@1: broken revlog! (index data/a.i is corrupted)
96 97 warning: orphan revlog 'data/a.i'
97 98 1 files, 2 changesets, 0 total revisions
98 99 1 warnings encountered!
99 100 1 integrity errors encountered!
100 101 (first damaged changeset appears to be 1)
101 102 [1]
102 103
103 104 $ cd ..
104 105
105 106 test revlog format 0
106 107
107 108 $ revlog-formatv0.py
108 109 $ cd formatv0
109 110 $ hg verify
110 111 repository uses revlog format 0
111 112 checking changesets
112 113 checking manifests
113 114 crosschecking files in changesets and manifests
114 115 checking files
115 116 1 files, 1 changesets, 1 total revisions
116 117 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now