##// END OF EJS Templates
Move repo.verify
Matt Mackall -
r2778:fdc232d8 default
parent child Browse files
Show More
@@ -0,0 +1,200 b''
1 # verify.py - repository integrity checking for Mercurial
2 #
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
4 #
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
7
8 from node import *
9 from i18n import gettext as _
10 import revlog, mdiff
11
12 def verify(repo):
13 filelinkrevs = {}
14 filenodes = {}
15 changesets = revisions = files = 0
16 errors = [0]
17 warnings = [0]
18 neededmanifests = {}
19
20 def err(msg):
21 repo.ui.warn(msg + "\n")
22 errors[0] += 1
23
24 def warn(msg):
25 repo.ui.warn(msg + "\n")
26 warnings[0] += 1
27
28 def checksize(obj, name):
29 d = obj.checksize()
30 if d[0]:
31 err(_("%s data length off by %d bytes") % (name, d[0]))
32 if d[1]:
33 err(_("%s index contains %d extra bytes") % (name, d[1]))
34
35 def checkversion(obj, name):
36 if obj.version != revlog.REVLOGV0:
37 if not revlogv1:
38 warn(_("warning: `%s' uses revlog format 1") % name)
39 elif revlogv1:
40 warn(_("warning: `%s' uses revlog format 0") % name)
41
42 revlogv1 = repo.revlogversion != revlog.REVLOGV0
43 if repo.ui.verbose or revlogv1 != repo.revlogv1:
44 repo.ui.status(_("repository uses revlog format %d\n") %
45 (revlogv1 and 1 or 0))
46
47 seen = {}
48 repo.ui.status(_("checking changesets\n"))
49 checksize(repo.changelog, "changelog")
50
51 for i in range(repo.changelog.count()):
52 changesets += 1
53 n = repo.changelog.node(i)
54 l = repo.changelog.linkrev(n)
55 if l != i:
56 err(_("incorrect link (%d) for changeset revision %d") %(l, i))
57 if n in seen:
58 err(_("duplicate changeset at revision %d") % i)
59 seen[n] = 1
60
61 for p in repo.changelog.parents(n):
62 if p not in repo.changelog.nodemap:
63 err(_("changeset %s has unknown parent %s") %
64 (short(n), short(p)))
65 try:
66 changes = repo.changelog.read(n)
67 except KeyboardInterrupt:
68 repo.ui.warn(_("interrupted"))
69 raise
70 except Exception, inst:
71 err(_("unpacking changeset %s: %s") % (short(n), inst))
72 continue
73
74 neededmanifests[changes[0]] = n
75
76 for f in changes[3]:
77 filelinkrevs.setdefault(f, []).append(i)
78
79 seen = {}
80 repo.ui.status(_("checking manifests\n"))
81 checkversion(repo.manifest, "manifest")
82 checksize(repo.manifest, "manifest")
83
84 for i in range(repo.manifest.count()):
85 n = repo.manifest.node(i)
86 l = repo.manifest.linkrev(n)
87
88 if l < 0 or l >= repo.changelog.count():
89 err(_("bad manifest link (%d) at revision %d") % (l, i))
90
91 if n in neededmanifests:
92 del neededmanifests[n]
93
94 if n in seen:
95 err(_("duplicate manifest at revision %d") % i)
96
97 seen[n] = 1
98
99 for p in repo.manifest.parents(n):
100 if p not in repo.manifest.nodemap:
101 err(_("manifest %s has unknown parent %s") %
102 (short(n), short(p)))
103
104 try:
105 delta = mdiff.patchtext(repo.manifest.delta(n))
106 except KeyboardInterrupt:
107 repo.ui.warn(_("interrupted"))
108 raise
109 except Exception, inst:
110 err(_("unpacking manifest %s: %s") % (short(n), inst))
111 continue
112
113 try:
114 ff = [ l.split('\0') for l in delta.splitlines() ]
115 for f, fn in ff:
116 filenodes.setdefault(f, {})[bin(fn[:40])] = 1
117 except (ValueError, TypeError), inst:
118 err(_("broken delta in manifest %s: %s") % (short(n), inst))
119
120 repo.ui.status(_("crosschecking files in changesets and manifests\n"))
121
122 for m, c in neededmanifests.items():
123 err(_("Changeset %s refers to unknown manifest %s") %
124 (short(m), short(c)))
125 del neededmanifests
126
127 for f in filenodes:
128 if f not in filelinkrevs:
129 err(_("file %s in manifest but not in changesets") % f)
130
131 for f in filelinkrevs:
132 if f not in filenodes:
133 err(_("file %s in changeset but not in manifest") % f)
134
135 repo.ui.status(_("checking files\n"))
136 ff = filenodes.keys()
137 ff.sort()
138 for f in ff:
139 if f == "/dev/null":
140 continue
141 files += 1
142 if not f:
143 err(_("file without name in manifest %s") % short(n))
144 continue
145 fl = repo.file(f)
146 checkversion(fl, f)
147 checksize(fl, f)
148
149 nodes = {nullid: 1}
150 seen = {}
151 for i in range(fl.count()):
152 revisions += 1
153 n = fl.node(i)
154
155 if n in seen:
156 err(_("%s: duplicate revision %d") % (f, i))
157 if n not in filenodes[f]:
158 err(_("%s: %d:%s not in manifests") % (f, i, short(n)))
159 else:
160 del filenodes[f][n]
161
162 flr = fl.linkrev(n)
163 if flr not in filelinkrevs.get(f, []):
164 err(_("%s:%s points to unexpected changeset %d")
165 % (f, short(n), flr))
166 else:
167 filelinkrevs[f].remove(flr)
168
169 # verify contents
170 try:
171 t = fl.read(n)
172 except KeyboardInterrupt:
173 repo.ui.warn(_("interrupted"))
174 raise
175 except Exception, inst:
176 err(_("unpacking file %s %s: %s") % (f, short(n), inst))
177
178 # verify parents
179 (p1, p2) = fl.parents(n)
180 if p1 not in nodes:
181 err(_("file %s:%s unknown parent 1 %s") %
182 (f, short(n), short(p1)))
183 if p2 not in nodes:
184 err(_("file %s:%s unknown parent 2 %s") %
185 (f, short(n), short(p1)))
186 nodes[n] = 1
187
188 # cross-check
189 for node in filenodes[f]:
190 err(_("node %s in manifests not in %s") % (hex(node), f))
191
192 repo.ui.status(_("%d files, %d changesets, %d total revisions\n") %
193 (files, changesets, revisions))
194
195 if warnings[0]:
196 repo.ui.warn(_("%d warnings encountered!\n") % warnings[0])
197 if errors[0]:
198 repo.ui.warn(_("%d integrity errors encountered!\n") % errors[0])
199 return 1
200
@@ -2325,7 +2325,7 b' def recover(ui, repo):'
2325 operation. It should only be necessary when Mercurial suggests it.
2325 operation. It should only be necessary when Mercurial suggests it.
2326 """
2326 """
2327 if repo.recover():
2327 if repo.recover():
2328 return repo.verify()
2328 return hg.verify(repo)
2329 return 1
2329 return 1
2330
2330
2331 def remove(ui, repo, *pats, **opts):
2331 def remove(ui, repo, *pats, **opts):
@@ -2879,7 +2879,7 b' def verify(ui, repo):'
2879 the changelog, manifest, and tracked files, as well as the
2879 the changelog, manifest, and tracked files, as well as the
2880 integrity of their crosslinks and indices.
2880 integrity of their crosslinks and indices.
2881 """
2881 """
2882 return repo.verify()
2882 return hg.verify(repo)
2883
2883
2884 # Command options and aliases are listed here, alphabetically
2884 # Command options and aliases are listed here, alphabetically
2885
2885
@@ -214,3 +214,8 b' def update(repo, node, allow=False, forc'
214 moddirstate=True, forcemerge=False, wlock=None, show_stats=True):
214 moddirstate=True, forcemerge=False, wlock=None, show_stats=True):
215 return merge.update(repo, node, allow, force, choose, moddirstate,
215 return merge.update(repo, node, allow, force, choose, moddirstate,
216 forcemerge, wlock, show_stats)
216 forcemerge, wlock, show_stats)
217
218 def verify(repo):
219 """verify the consistency of a repository"""
220 import verify as _verify
221 return _verify.verify(repo)
@@ -1693,195 +1693,6 b' class localrepository(repo.repository):'
1693
1693
1694 return newheads - oldheads + 1
1694 return newheads - oldheads + 1
1695
1695
1696 def verify(self):
1697 filelinkrevs = {}
1698 filenodes = {}
1699 changesets = revisions = files = 0
1700 errors = [0]
1701 warnings = [0]
1702 neededmanifests = {}
1703
1704 def err(msg):
1705 self.ui.warn(msg + "\n")
1706 errors[0] += 1
1707
1708 def warn(msg):
1709 self.ui.warn(msg + "\n")
1710 warnings[0] += 1
1711
1712 def checksize(obj, name):
1713 d = obj.checksize()
1714 if d[0]:
1715 err(_("%s data length off by %d bytes") % (name, d[0]))
1716 if d[1]:
1717 err(_("%s index contains %d extra bytes") % (name, d[1]))
1718
1719 def checkversion(obj, name):
1720 if obj.version != revlog.REVLOGV0:
1721 if not revlogv1:
1722 warn(_("warning: `%s' uses revlog format 1") % name)
1723 elif revlogv1:
1724 warn(_("warning: `%s' uses revlog format 0") % name)
1725
1726 revlogv1 = self.revlogversion != revlog.REVLOGV0
1727 if self.ui.verbose or revlogv1 != self.revlogv1:
1728 self.ui.status(_("repository uses revlog format %d\n") %
1729 (revlogv1 and 1 or 0))
1730
1731 seen = {}
1732 self.ui.status(_("checking changesets\n"))
1733 checksize(self.changelog, "changelog")
1734
1735 for i in range(self.changelog.count()):
1736 changesets += 1
1737 n = self.changelog.node(i)
1738 l = self.changelog.linkrev(n)
1739 if l != i:
1740 err(_("incorrect link (%d) for changeset revision %d") %(l, i))
1741 if n in seen:
1742 err(_("duplicate changeset at revision %d") % i)
1743 seen[n] = 1
1744
1745 for p in self.changelog.parents(n):
1746 if p not in self.changelog.nodemap:
1747 err(_("changeset %s has unknown parent %s") %
1748 (short(n), short(p)))
1749 try:
1750 changes = self.changelog.read(n)
1751 except KeyboardInterrupt:
1752 self.ui.warn(_("interrupted"))
1753 raise
1754 except Exception, inst:
1755 err(_("unpacking changeset %s: %s") % (short(n), inst))
1756 continue
1757
1758 neededmanifests[changes[0]] = n
1759
1760 for f in changes[3]:
1761 filelinkrevs.setdefault(f, []).append(i)
1762
1763 seen = {}
1764 self.ui.status(_("checking manifests\n"))
1765 checkversion(self.manifest, "manifest")
1766 checksize(self.manifest, "manifest")
1767
1768 for i in range(self.manifest.count()):
1769 n = self.manifest.node(i)
1770 l = self.manifest.linkrev(n)
1771
1772 if l < 0 or l >= self.changelog.count():
1773 err(_("bad manifest link (%d) at revision %d") % (l, i))
1774
1775 if n in neededmanifests:
1776 del neededmanifests[n]
1777
1778 if n in seen:
1779 err(_("duplicate manifest at revision %d") % i)
1780
1781 seen[n] = 1
1782
1783 for p in self.manifest.parents(n):
1784 if p not in self.manifest.nodemap:
1785 err(_("manifest %s has unknown parent %s") %
1786 (short(n), short(p)))
1787
1788 try:
1789 delta = mdiff.patchtext(self.manifest.delta(n))
1790 except KeyboardInterrupt:
1791 self.ui.warn(_("interrupted"))
1792 raise
1793 except Exception, inst:
1794 err(_("unpacking manifest %s: %s") % (short(n), inst))
1795 continue
1796
1797 try:
1798 ff = [ l.split('\0') for l in delta.splitlines() ]
1799 for f, fn in ff:
1800 filenodes.setdefault(f, {})[bin(fn[:40])] = 1
1801 except (ValueError, TypeError), inst:
1802 err(_("broken delta in manifest %s: %s") % (short(n), inst))
1803
1804 self.ui.status(_("crosschecking files in changesets and manifests\n"))
1805
1806 for m, c in neededmanifests.items():
1807 err(_("Changeset %s refers to unknown manifest %s") %
1808 (short(m), short(c)))
1809 del neededmanifests
1810
1811 for f in filenodes:
1812 if f not in filelinkrevs:
1813 err(_("file %s in manifest but not in changesets") % f)
1814
1815 for f in filelinkrevs:
1816 if f not in filenodes:
1817 err(_("file %s in changeset but not in manifest") % f)
1818
1819 self.ui.status(_("checking files\n"))
1820 ff = filenodes.keys()
1821 ff.sort()
1822 for f in ff:
1823 if f == "/dev/null":
1824 continue
1825 files += 1
1826 if not f:
1827 err(_("file without name in manifest %s") % short(n))
1828 continue
1829 fl = self.file(f)
1830 checkversion(fl, f)
1831 checksize(fl, f)
1832
1833 nodes = {nullid: 1}
1834 seen = {}
1835 for i in range(fl.count()):
1836 revisions += 1
1837 n = fl.node(i)
1838
1839 if n in seen:
1840 err(_("%s: duplicate revision %d") % (f, i))
1841 if n not in filenodes[f]:
1842 err(_("%s: %d:%s not in manifests") % (f, i, short(n)))
1843 else:
1844 del filenodes[f][n]
1845
1846 flr = fl.linkrev(n)
1847 if flr not in filelinkrevs.get(f, []):
1848 err(_("%s:%s points to unexpected changeset %d")
1849 % (f, short(n), flr))
1850 else:
1851 filelinkrevs[f].remove(flr)
1852
1853 # verify contents
1854 try:
1855 t = fl.read(n)
1856 except KeyboardInterrupt:
1857 self.ui.warn(_("interrupted"))
1858 raise
1859 except Exception, inst:
1860 err(_("unpacking file %s %s: %s") % (f, short(n), inst))
1861
1862 # verify parents
1863 (p1, p2) = fl.parents(n)
1864 if p1 not in nodes:
1865 err(_("file %s:%s unknown parent 1 %s") %
1866 (f, short(n), short(p1)))
1867 if p2 not in nodes:
1868 err(_("file %s:%s unknown parent 2 %s") %
1869 (f, short(n), short(p1)))
1870 nodes[n] = 1
1871
1872 # cross-check
1873 for node in filenodes[f]:
1874 err(_("node %s in manifests not in %s") % (hex(node), f))
1875
1876 self.ui.status(_("%d files, %d changesets, %d total revisions\n") %
1877 (files, changesets, revisions))
1878
1879 if warnings[0]:
1880 self.ui.warn(_("%d warnings encountered!\n") % warnings[0])
1881 if errors[0]:
1882 self.ui.warn(_("%d integrity errors encountered!\n") % errors[0])
1883 return 1
1884
1885 def stream_in(self, remote):
1696 def stream_in(self, remote):
1886 fp = remote.stream_out()
1697 fp = remote.stream_out()
1887 resp = int(fp.readline())
1698 resp = int(fp.readline())
@@ -1906,7 +1717,7 b' class localrepository(repo.repository):'
1906 util.bytecount(total_bytes / elapsed)))
1717 util.bytecount(total_bytes / elapsed)))
1907 self.reload()
1718 self.reload()
1908 return len(self.heads()) + 1
1719 return len(self.heads()) + 1
1909
1720
1910 def clone(self, remote, heads=[], stream=False):
1721 def clone(self, remote, heads=[], stream=False):
1911 '''clone remote repository.
1722 '''clone remote repository.
1912
1723
General Comments 0
You need to be logged in to leave comments. Login now