]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - src/allmydata/check_results.py
CheckResults: pass IServer to corrupt/incompatible share locators
[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, dictutil
6
7 class CheckResults:
8     implements(ICheckResults)
9
10     def __init__(self, uri, storage_index,
11                  healthy, recoverable, needs_rebalancing,
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         self._needs_rebalancing_p = bool(needs_rebalancing)
35
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 needs_rebalancing(self):
82         return self._needs_rebalancing_p
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_new_corrupt_shares(self):
95         return self._list_corrupt_shares
96     def get_corrupt_shares(self):
97         return [(s.get_serverid(), SI, shnum)
98                 for (s, SI, shnum) in self._list_corrupt_shares]
99
100     def get_new_incompatible_shares(self):
101         return self._list_incompatible_shares
102     def get_incompatible_shares(self):
103         return [(s.get_serverid(), SI, shnum)
104                 for (s, SI, shnum) in self._list_incompatible_shares]
105
106     def get_new_servers_responding(self):
107         return self._servers_responding
108     def get_servers_responding(self):
109         return [s.get_serverid() for s in self._servers_responding]
110
111     def get_host_counter_good_shares(self):
112         return self._count_good_share_hosts
113
114     def get_version_counter_recoverable(self):
115         return self._count_recoverable_versions
116     def get_version_counter_unrecoverable(self):
117         return self._count_unrecoverable_versions
118
119     def get_sharemap(self):
120         sharemap = dictutil.DictOfSets()
121         for shnum, servers in self._sharemap.items():
122             for s in servers:
123                 sharemap.add(shnum, s.get_serverid())
124         return sharemap
125     def get_new_sharemap(self):
126         # this one returns IServers, even when get_sharemap returns serverids
127         return self._sharemap
128
129     def as_dict(self):
130         sharemap = {}
131         for shnum, servers in self._sharemap.items():
132             sharemap[shnum] = sorted([s.get_serverid() for s in servers])
133         responding = [s.get_serverid() for s in self._servers_responding]
134         corrupt = [(s.get_serverid(), SI, shnum)
135                    for (s, SI, shnum) in self._list_corrupt_shares]
136         incompatible = [(s.get_serverid(), SI, shnum)
137                         for (s, SI, shnum) in self._list_incompatible_shares]
138         d = {"count-shares-needed": self._count_shares_needed,
139              "count-shares-expected": self._count_shares_expected,
140              "count-shares-good": self._count_shares_good,
141              "count-good-share-hosts": self._count_good_share_hosts,
142              "count-recoverable-versions": self._count_recoverable_versions,
143              "count-unrecoverable-versions": self._count_unrecoverable_versions,
144              "servers-responding": responding,
145              "sharemap": sharemap,
146              "count-wrong-shares": self._count_wrong_shares,
147              "list-corrupt-shares": corrupt,
148              "count-corrupt-shares": self._count_corrupt_shares,
149              "list-incompatible-shares": incompatible,
150              "count-incompatible-shares": self._count_incompatible_shares,
151              }
152         return d
153
154     def get_summary(self):
155         return self._summary
156     def get_report(self):
157         return self._report
158     def get_share_problems(self):
159         return self._share_problems
160     def get_servermap(self):
161         return self._servermap
162
163 class CheckAndRepairResults:
164     implements(ICheckAndRepairResults)
165
166     def __init__(self, storage_index):
167         self.storage_index = storage_index
168         self.repair_attempted = False
169
170     def get_storage_index(self):
171         return self.storage_index
172     def get_storage_index_string(self):
173         return base32.b2a(self.storage_index)
174     def get_repair_attempted(self):
175         return self.repair_attempted
176     def get_repair_successful(self):
177         if not self.repair_attempted:
178             return False
179         return self.repair_successful
180     def get_pre_repair_results(self):
181         return self.pre_repair_results
182     def get_post_repair_results(self):
183         return self.post_repair_results
184
185
186 class DeepResultsBase:
187
188     def __init__(self, root_storage_index):
189         self.root_storage_index = root_storage_index
190         if root_storage_index is None:
191             self.root_storage_index_s = "<none>"  # is this correct?
192         else:
193             self.root_storage_index_s = base32.b2a(root_storage_index)
194
195         self.objects_checked = 0
196         self.objects_healthy = 0
197         self.objects_unhealthy = 0
198         self.objects_unrecoverable = 0
199         self.corrupt_shares = []
200         self.all_results = {}
201         self.all_results_by_storage_index = {}
202         self.stats = {}
203
204     def update_stats(self, new_stats):
205         self.stats.update(new_stats)
206
207     def get_root_storage_index_string(self):
208         return self.root_storage_index_s
209
210     def get_corrupt_shares(self):
211         return self.corrupt_shares
212
213     def get_all_results(self):
214         return self.all_results
215
216     def get_results_for_storage_index(self, storage_index):
217         return self.all_results_by_storage_index[storage_index]
218
219     def get_stats(self):
220         return self.stats
221
222
223 class DeepCheckResults(DeepResultsBase):
224     implements(IDeepCheckResults)
225
226     def add_check(self, r, path):
227         if not r:
228             return # non-distributed object, i.e. LIT file
229         r = ICheckResults(r)
230         assert isinstance(path, (list, tuple))
231         self.objects_checked += 1
232         if r.is_healthy():
233             self.objects_healthy += 1
234         else:
235             self.objects_unhealthy += 1
236         if not r.is_recoverable():
237             self.objects_unrecoverable += 1
238         self.all_results[tuple(path)] = r
239         self.all_results_by_storage_index[r.get_storage_index()] = r
240         self.corrupt_shares.extend(r.get_corrupt_shares())
241
242     def get_counters(self):
243         return {"count-objects-checked": self.objects_checked,
244                 "count-objects-healthy": self.objects_healthy,
245                 "count-objects-unhealthy": self.objects_unhealthy,
246                 "count-objects-unrecoverable": self.objects_unrecoverable,
247                 "count-corrupt-shares": len(self.corrupt_shares),
248                 }
249
250
251 class DeepCheckAndRepairResults(DeepResultsBase):
252     implements(IDeepCheckAndRepairResults)
253
254     def __init__(self, root_storage_index):
255         DeepResultsBase.__init__(self, root_storage_index)
256         self.objects_healthy_post_repair = 0
257         self.objects_unhealthy_post_repair = 0
258         self.objects_unrecoverable_post_repair = 0
259         self.repairs_attempted = 0
260         self.repairs_successful = 0
261         self.repairs_unsuccessful = 0
262         self.corrupt_shares_post_repair = []
263
264     def add_check_and_repair(self, r, path):
265         if not r:
266             return # non-distributed object, i.e. LIT file
267         r = ICheckAndRepairResults(r)
268         assert isinstance(path, (list, tuple))
269         pre_repair = r.get_pre_repair_results()
270         post_repair = r.get_post_repair_results()
271         self.objects_checked += 1
272         if pre_repair.is_healthy():
273             self.objects_healthy += 1
274         else:
275             self.objects_unhealthy += 1
276         if not pre_repair.is_recoverable():
277             self.objects_unrecoverable += 1
278         self.corrupt_shares.extend(pre_repair.get_corrupt_shares())
279         if r.get_repair_attempted():
280             self.repairs_attempted += 1
281             if r.get_repair_successful():
282                 self.repairs_successful += 1
283             else:
284                 self.repairs_unsuccessful += 1
285         if post_repair.is_healthy():
286             self.objects_healthy_post_repair += 1
287         else:
288             self.objects_unhealthy_post_repair += 1
289         if not post_repair.is_recoverable():
290             self.objects_unrecoverable_post_repair += 1
291         self.all_results[tuple(path)] = r
292         self.all_results_by_storage_index[r.get_storage_index()] = r
293         self.corrupt_shares_post_repair.extend(post_repair.get_corrupt_shares())
294
295     def get_counters(self):
296         return {"count-objects-checked": self.objects_checked,
297                 "count-objects-healthy-pre-repair": self.objects_healthy,
298                 "count-objects-unhealthy-pre-repair": self.objects_unhealthy,
299                 "count-objects-unrecoverable-pre-repair": self.objects_unrecoverable,
300                 "count-objects-healthy-post-repair": self.objects_healthy_post_repair,
301                 "count-objects-unhealthy-post-repair": self.objects_unhealthy_post_repair,
302                 "count-objects-unrecoverable-post-repair": self.objects_unrecoverable_post_repair,
303                 "count-repairs-attempted": self.repairs_attempted,
304                 "count-repairs-successful": self.repairs_successful,
305                 "count-repairs-unsuccessful": self.repairs_unsuccessful,
306                 "count-corrupt-shares-pre-repair": len(self.corrupt_shares),
307                 "count-corrupt-shares-post-repair": len(self.corrupt_shares_post_repair),
308                 }
309
310     def get_remaining_corrupt_shares(self):
311         return self.corrupt_shares_post_repair