]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - src/allmydata/check_results.py
Remove 'needs-rebalancing' and add 'count-happiness' to checker reports; repair tests...
[tahoe-lafs/tahoe-lafs.git] / src / allmydata / check_results.py
1
2 from zope.interface import implements
3 from allmydata.interfaces import ICheckResults, ICheckAndRepairResults, \
4      IDeepCheckResults, IDeepCheckAndRepairResults, IURI, IDisplayableServer
5 from allmydata.util import base32
6
7 class CheckResults:
8     implements(ICheckResults)
9
10     def __init__(self, uri, storage_index,
11                  healthy, recoverable, count_happiness,
12                  count_shares_needed, count_shares_expected,
13                  count_shares_good, count_good_share_hosts,
14                  count_recoverable_versions, count_unrecoverable_versions,
15                  servers_responding, sharemap,
16                  count_wrong_shares, list_corrupt_shares, count_corrupt_shares,
17                  list_incompatible_shares, count_incompatible_shares,
18                  summary, report, share_problems, servermap):
19         assert IURI.providedBy(uri), uri
20         self._uri = uri
21         self._storage_index = storage_index
22         self._summary = ""
23         self._healthy = bool(healthy)
24         if self._healthy:
25             assert recoverable
26             if not summary:
27                 summary = "healthy"
28         else:
29             if not summary:
30                 summary = "not healthy"
31         self._recoverable = recoverable
32         if not self._recoverable:
33             assert not self._healthy
34
35         self._count_happiness = count_happiness
36         self._count_shares_needed = count_shares_needed
37         self._count_shares_expected = count_shares_expected
38         self._count_shares_good = count_shares_good
39         self._count_good_share_hosts = count_good_share_hosts
40         self._count_recoverable_versions = count_recoverable_versions
41         self._count_unrecoverable_versions = count_unrecoverable_versions
42         for server in servers_responding:
43             assert IDisplayableServer.providedBy(server), server
44         self._servers_responding = servers_responding
45         for shnum, servers in sharemap.items():
46             for server in servers:
47                 assert IDisplayableServer.providedBy(server), server
48         self._sharemap = sharemap
49         self._count_wrong_shares = count_wrong_shares
50         for (server, SI, shnum) in list_corrupt_shares:
51             assert IDisplayableServer.providedBy(server), server
52         self._list_corrupt_shares = list_corrupt_shares
53         self._count_corrupt_shares = count_corrupt_shares
54         for (server, SI, shnum) in list_incompatible_shares:
55             assert IDisplayableServer.providedBy(server), server
56         self._list_incompatible_shares = list_incompatible_shares
57         self._count_incompatible_shares = count_incompatible_shares
58
59         assert isinstance(summary, str) # should be a single string
60         self._summary = summary
61         assert not isinstance(report, str) # should be list of strings
62         self._report = report
63         if servermap:
64             from allmydata.mutable.servermap import ServerMap
65             assert isinstance(servermap, ServerMap), servermap
66         self._servermap = servermap # mutable only
67         self._share_problems = share_problems
68
69     def get_storage_index(self):
70         return self._storage_index
71     def get_storage_index_string(self):
72         return base32.b2a(self._storage_index)
73     def get_uri(self):
74         return self._uri
75
76     def is_healthy(self):
77         return self._healthy
78     def is_recoverable(self):
79         return self._recoverable
80
81     def get_happiness(self):
82         return self._count_happiness
83
84     def get_encoding_needed(self):
85         return self._count_shares_needed
86     def get_encoding_expected(self):
87         return self._count_shares_expected
88
89     def get_share_counter_good(self):
90         return self._count_shares_good
91     def get_share_counter_wrong(self):
92         return self._count_wrong_shares
93
94     def get_corrupt_shares(self):
95         return self._list_corrupt_shares
96
97     def get_incompatible_shares(self):
98         return self._list_incompatible_shares
99
100     def get_servers_responding(self):
101         return self._servers_responding
102
103     def get_host_counter_good_shares(self):
104         return self._count_good_share_hosts
105
106     def get_version_counter_recoverable(self):
107         return self._count_recoverable_versions
108     def get_version_counter_unrecoverable(self):
109         return self._count_unrecoverable_versions
110
111     def get_sharemap(self):
112         return self._sharemap
113
114     def as_dict(self):
115         sharemap = {}
116         for shnum, servers in self._sharemap.items():
117             sharemap[shnum] = sorted([s.get_serverid() for s in servers])
118         responding = [s.get_serverid() for s in self._servers_responding]
119         corrupt = [(s.get_serverid(), SI, shnum)
120                    for (s, SI, shnum) in self._list_corrupt_shares]
121         incompatible = [(s.get_serverid(), SI, shnum)
122                         for (s, SI, shnum) in self._list_incompatible_shares]
123         d = {"count-happiness": self._count_happiness,
124              "count-shares-needed": self._count_shares_needed,
125              "count-shares-expected": self._count_shares_expected,
126              "count-shares-good": self._count_shares_good,
127              "count-good-share-hosts": self._count_good_share_hosts,
128              "count-recoverable-versions": self._count_recoverable_versions,
129              "count-unrecoverable-versions": self._count_unrecoverable_versions,
130              "servers-responding": responding,
131              "sharemap": sharemap,
132              "count-wrong-shares": self._count_wrong_shares,
133              "list-corrupt-shares": corrupt,
134              "count-corrupt-shares": self._count_corrupt_shares,
135              "list-incompatible-shares": incompatible,
136              "count-incompatible-shares": self._count_incompatible_shares,
137              }
138         return d
139
140     def get_summary(self):
141         return self._summary
142     def get_report(self):
143         return self._report
144     def get_share_problems(self):
145         return self._share_problems
146     def get_servermap(self):
147         return self._servermap
148
149 class CheckAndRepairResults:
150     implements(ICheckAndRepairResults)
151
152     def __init__(self, storage_index):
153         self.storage_index = storage_index
154         self.repair_attempted = False
155
156     def get_storage_index(self):
157         return self.storage_index
158     def get_storage_index_string(self):
159         return base32.b2a(self.storage_index)
160     def get_repair_attempted(self):
161         return self.repair_attempted
162     def get_repair_successful(self):
163         if not self.repair_attempted:
164             return False
165         return self.repair_successful
166     def get_pre_repair_results(self):
167         return self.pre_repair_results
168     def get_post_repair_results(self):
169         return self.post_repair_results
170
171
172 class DeepResultsBase:
173
174     def __init__(self, root_storage_index):
175         self.root_storage_index = root_storage_index
176         if root_storage_index is None:
177             self.root_storage_index_s = "<none>"  # is this correct?
178         else:
179             self.root_storage_index_s = base32.b2a(root_storage_index)
180
181         self.objects_checked = 0
182         self.objects_healthy = 0
183         self.objects_unhealthy = 0
184         self.objects_unrecoverable = 0
185         self.corrupt_shares = []
186         self.all_results = {}
187         self.all_results_by_storage_index = {}
188         self.stats = {}
189
190     def update_stats(self, new_stats):
191         self.stats.update(new_stats)
192
193     def get_root_storage_index_string(self):
194         return self.root_storage_index_s
195
196     def get_corrupt_shares(self):
197         return self.corrupt_shares
198
199     def get_all_results(self):
200         return self.all_results
201
202     def get_results_for_storage_index(self, storage_index):
203         return self.all_results_by_storage_index[storage_index]
204
205     def get_stats(self):
206         return self.stats
207
208
209 class DeepCheckResults(DeepResultsBase):
210     implements(IDeepCheckResults)
211
212     def add_check(self, r, path):
213         if not r:
214             return # non-distributed object, i.e. LIT file
215         r = ICheckResults(r)
216         assert isinstance(path, (list, tuple))
217         self.objects_checked += 1
218         if r.is_healthy():
219             self.objects_healthy += 1
220         else:
221             self.objects_unhealthy += 1
222         if not r.is_recoverable():
223             self.objects_unrecoverable += 1
224         self.all_results[tuple(path)] = r
225         self.all_results_by_storage_index[r.get_storage_index()] = r
226         self.corrupt_shares.extend(r.get_corrupt_shares())
227
228     def get_counters(self):
229         return {"count-objects-checked": self.objects_checked,
230                 "count-objects-healthy": self.objects_healthy,
231                 "count-objects-unhealthy": self.objects_unhealthy,
232                 "count-objects-unrecoverable": self.objects_unrecoverable,
233                 "count-corrupt-shares": len(self.corrupt_shares),
234                 }
235
236
237 class DeepCheckAndRepairResults(DeepResultsBase):
238     implements(IDeepCheckAndRepairResults)
239
240     def __init__(self, root_storage_index):
241         DeepResultsBase.__init__(self, root_storage_index)
242         self.objects_healthy_post_repair = 0
243         self.objects_unhealthy_post_repair = 0
244         self.objects_unrecoverable_post_repair = 0
245         self.repairs_attempted = 0
246         self.repairs_successful = 0
247         self.repairs_unsuccessful = 0
248         self.corrupt_shares_post_repair = []
249
250     def add_check_and_repair(self, r, path):
251         if not r:
252             return # non-distributed object, i.e. LIT file
253         r = ICheckAndRepairResults(r)
254         assert isinstance(path, (list, tuple))
255         pre_repair = r.get_pre_repair_results()
256         post_repair = r.get_post_repair_results()
257         self.objects_checked += 1
258         if pre_repair.is_healthy():
259             self.objects_healthy += 1
260         else:
261             self.objects_unhealthy += 1
262         if not pre_repair.is_recoverable():
263             self.objects_unrecoverable += 1
264         self.corrupt_shares.extend(pre_repair.get_corrupt_shares())
265         if r.get_repair_attempted():
266             self.repairs_attempted += 1
267             if r.get_repair_successful():
268                 self.repairs_successful += 1
269             else:
270                 self.repairs_unsuccessful += 1
271         if post_repair.is_healthy():
272             self.objects_healthy_post_repair += 1
273         else:
274             self.objects_unhealthy_post_repair += 1
275         if not post_repair.is_recoverable():
276             self.objects_unrecoverable_post_repair += 1
277         self.all_results[tuple(path)] = r
278         self.all_results_by_storage_index[r.get_storage_index()] = r
279         self.corrupt_shares_post_repair.extend(post_repair.get_corrupt_shares())
280
281     def get_counters(self):
282         return {"count-objects-checked": self.objects_checked,
283                 "count-objects-healthy-pre-repair": self.objects_healthy,
284                 "count-objects-unhealthy-pre-repair": self.objects_unhealthy,
285                 "count-objects-unrecoverable-pre-repair": self.objects_unrecoverable,
286                 "count-objects-healthy-post-repair": self.objects_healthy_post_repair,
287                 "count-objects-unhealthy-post-repair": self.objects_unhealthy_post_repair,
288                 "count-objects-unrecoverable-post-repair": self.objects_unrecoverable_post_repair,
289                 "count-repairs-attempted": self.repairs_attempted,
290                 "count-repairs-successful": self.repairs_successful,
291                 "count-repairs-unsuccessful": self.repairs_unsuccessful,
292                 "count-corrupt-shares-pre-repair": len(self.corrupt_shares),
293                 "count-corrupt-shares-post-repair": len(self.corrupt_shares_post_repair),
294                 }
295
296     def get_remaining_corrupt_shares(self):
297         return self.corrupt_shares_post_repair