2008-09-07 19:44:56 +00:00
|
|
|
|
|
|
|
from zope.interface import implements
|
2009-01-06 20:37:03 +00:00
|
|
|
from allmydata.interfaces import ICheckResults, ICheckAndRepairResults, \
|
2012-05-25 19:56:03 +00:00
|
|
|
IDeepCheckResults, IDeepCheckAndRepairResults, IURI, IDisplayableServer
|
2012-05-25 19:58:02 +00:00
|
|
|
from allmydata.util import base32
|
2008-09-07 19:44:56 +00:00
|
|
|
|
2009-01-10 01:00:52 +00:00
|
|
|
class CheckResults:
|
2009-01-06 20:37:03 +00:00
|
|
|
implements(ICheckResults)
|
2008-09-07 19:44:56 +00:00
|
|
|
|
2012-05-25 07:14:46 +00:00
|
|
|
def __init__(self, uri, storage_index,
|
|
|
|
healthy, recoverable, needs_rebalancing,
|
|
|
|
count_shares_needed, count_shares_expected,
|
|
|
|
count_shares_good, count_good_share_hosts,
|
|
|
|
count_recoverable_versions, count_unrecoverable_versions,
|
|
|
|
servers_responding, sharemap,
|
|
|
|
count_wrong_shares, list_corrupt_shares, count_corrupt_shares,
|
|
|
|
list_incompatible_shares, count_incompatible_shares,
|
|
|
|
summary, report, share_problems, servermap):
|
2008-12-19 15:39:24 +00:00
|
|
|
assert IURI.providedBy(uri), uri
|
2012-05-25 19:29:10 +00:00
|
|
|
self._uri = uri
|
|
|
|
self._storage_index = storage_index
|
|
|
|
self._summary = ""
|
|
|
|
self._healthy = bool(healthy)
|
|
|
|
if self._healthy:
|
2012-05-25 07:14:46 +00:00
|
|
|
assert recoverable
|
|
|
|
if not summary:
|
|
|
|
summary = "healthy"
|
2009-01-06 01:28:18 +00:00
|
|
|
else:
|
2012-05-25 07:14:46 +00:00
|
|
|
if not summary:
|
|
|
|
summary = "not healthy"
|
2012-05-25 19:29:10 +00:00
|
|
|
self._recoverable = recoverable
|
|
|
|
if not self._recoverable:
|
|
|
|
assert not self._healthy
|
|
|
|
self._needs_rebalancing_p = bool(needs_rebalancing)
|
2012-05-25 19:55:48 +00:00
|
|
|
|
|
|
|
self._count_shares_needed = count_shares_needed
|
|
|
|
self._count_shares_expected = count_shares_expected
|
|
|
|
self._count_shares_good = count_shares_good
|
|
|
|
self._count_good_share_hosts = count_good_share_hosts
|
|
|
|
self._count_recoverable_versions = count_recoverable_versions
|
|
|
|
self._count_unrecoverable_versions = count_unrecoverable_versions
|
2012-05-25 19:56:20 +00:00
|
|
|
for server in servers_responding:
|
|
|
|
assert IDisplayableServer.providedBy(server), server
|
2012-05-25 19:55:48 +00:00
|
|
|
self._servers_responding = servers_responding
|
2012-05-25 19:56:03 +00:00
|
|
|
for shnum, servers in sharemap.items():
|
|
|
|
for server in servers:
|
|
|
|
assert IDisplayableServer.providedBy(server), server
|
2012-05-25 19:55:48 +00:00
|
|
|
self._sharemap = sharemap
|
|
|
|
self._count_wrong_shares = count_wrong_shares
|
2012-05-25 19:57:53 +00:00
|
|
|
for (server, SI, shnum) in list_corrupt_shares:
|
|
|
|
assert IDisplayableServer.providedBy(server), server
|
2012-05-25 19:55:48 +00:00
|
|
|
self._list_corrupt_shares = list_corrupt_shares
|
|
|
|
self._count_corrupt_shares = count_corrupt_shares
|
2012-05-25 19:57:53 +00:00
|
|
|
for (server, SI, shnum) in list_incompatible_shares:
|
|
|
|
assert IDisplayableServer.providedBy(server), server
|
2012-05-25 19:55:48 +00:00
|
|
|
self._list_incompatible_shares = list_incompatible_shares
|
|
|
|
self._count_incompatible_shares = count_incompatible_shares
|
|
|
|
|
2008-09-07 19:44:56 +00:00
|
|
|
assert isinstance(summary, str) # should be a single string
|
2012-05-25 19:29:10 +00:00
|
|
|
self._summary = summary
|
2008-09-07 19:44:56 +00:00
|
|
|
assert not isinstance(report, str) # should be list of strings
|
2012-05-25 19:29:10 +00:00
|
|
|
self._report = report
|
2012-05-25 07:14:46 +00:00
|
|
|
if servermap:
|
|
|
|
from allmydata.mutable.servermap import ServerMap
|
|
|
|
assert isinstance(servermap, ServerMap), servermap
|
2012-05-25 19:29:10 +00:00
|
|
|
self._servermap = servermap # mutable only
|
2012-05-25 07:14:46 +00:00
|
|
|
self._share_problems = share_problems
|
2008-09-07 19:44:56 +00:00
|
|
|
|
|
|
|
def get_storage_index(self):
|
2012-05-25 19:29:10 +00:00
|
|
|
return self._storage_index
|
2008-09-07 19:44:56 +00:00
|
|
|
def get_storage_index_string(self):
|
2012-05-25 19:29:10 +00:00
|
|
|
return base32.b2a(self._storage_index)
|
2008-10-30 01:09:17 +00:00
|
|
|
def get_uri(self):
|
2012-05-25 19:29:10 +00:00
|
|
|
return self._uri
|
2008-09-07 19:44:56 +00:00
|
|
|
|
|
|
|
def is_healthy(self):
|
2012-05-25 19:29:10 +00:00
|
|
|
return self._healthy
|
2008-11-07 05:35:47 +00:00
|
|
|
def is_recoverable(self):
|
2012-05-25 19:29:10 +00:00
|
|
|
return self._recoverable
|
2008-09-07 19:44:56 +00:00
|
|
|
|
|
|
|
def needs_rebalancing(self):
|
2012-05-25 19:29:10 +00:00
|
|
|
return self._needs_rebalancing_p
|
2012-05-25 07:13:32 +00:00
|
|
|
|
|
|
|
def get_encoding_needed(self):
|
2012-05-25 19:55:48 +00:00
|
|
|
return self._count_shares_needed
|
2012-05-25 07:13:32 +00:00
|
|
|
def get_encoding_expected(self):
|
2012-05-25 19:55:48 +00:00
|
|
|
return self._count_shares_expected
|
2012-05-25 07:13:32 +00:00
|
|
|
|
|
|
|
def get_share_counter_good(self):
|
2012-05-25 19:55:48 +00:00
|
|
|
return self._count_shares_good
|
2012-05-25 07:13:32 +00:00
|
|
|
def get_share_counter_wrong(self):
|
2012-05-25 19:55:48 +00:00
|
|
|
return self._count_wrong_shares
|
2012-05-25 07:13:32 +00:00
|
|
|
|
2012-05-25 19:57:53 +00:00
|
|
|
def get_new_corrupt_shares(self):
|
2012-05-25 19:55:48 +00:00
|
|
|
return self._list_corrupt_shares
|
2012-05-25 19:57:53 +00:00
|
|
|
def get_corrupt_shares(self):
|
|
|
|
return [(s.get_serverid(), SI, shnum)
|
|
|
|
for (s, SI, shnum) in self._list_corrupt_shares]
|
2012-05-25 07:13:32 +00:00
|
|
|
|
2012-05-25 19:57:53 +00:00
|
|
|
def get_new_incompatible_shares(self):
|
2012-05-25 19:55:48 +00:00
|
|
|
return self._list_incompatible_shares
|
2012-05-25 19:57:53 +00:00
|
|
|
def get_incompatible_shares(self):
|
|
|
|
return [(s.get_serverid(), SI, shnum)
|
|
|
|
for (s, SI, shnum) in self._list_incompatible_shares]
|
2012-05-25 07:13:32 +00:00
|
|
|
|
2012-05-25 19:56:20 +00:00
|
|
|
def get_new_servers_responding(self):
|
2012-05-25 19:55:48 +00:00
|
|
|
return self._servers_responding
|
2012-05-25 19:56:20 +00:00
|
|
|
def get_servers_responding(self):
|
|
|
|
return [s.get_serverid() for s in self._servers_responding]
|
2012-05-25 07:13:32 +00:00
|
|
|
|
|
|
|
def get_host_counter_good_shares(self):
|
2012-05-25 19:55:48 +00:00
|
|
|
return self._count_good_share_hosts
|
2012-05-25 07:13:32 +00:00
|
|
|
|
|
|
|
def get_version_counter_recoverable(self):
|
2012-05-25 19:55:48 +00:00
|
|
|
return self._count_recoverable_versions
|
2012-05-25 07:13:32 +00:00
|
|
|
def get_version_counter_unrecoverable(self):
|
2012-05-25 19:55:48 +00:00
|
|
|
return self._count_unrecoverable_versions
|
2012-05-25 07:13:32 +00:00
|
|
|
|
|
|
|
def get_sharemap(self):
|
2012-05-25 19:55:48 +00:00
|
|
|
return self._sharemap
|
2012-05-25 07:13:32 +00:00
|
|
|
|
2012-05-25 07:14:08 +00:00
|
|
|
def as_dict(self):
|
2012-05-25 19:56:03 +00:00
|
|
|
sharemap = {}
|
|
|
|
for shnum, servers in self._sharemap.items():
|
|
|
|
sharemap[shnum] = sorted([s.get_serverid() for s in servers])
|
2012-05-25 19:56:20 +00:00
|
|
|
responding = [s.get_serverid() for s in self._servers_responding]
|
2012-05-25 19:57:53 +00:00
|
|
|
corrupt = [(s.get_serverid(), SI, shnum)
|
|
|
|
for (s, SI, shnum) in self._list_corrupt_shares]
|
|
|
|
incompatible = [(s.get_serverid(), SI, shnum)
|
|
|
|
for (s, SI, shnum) in self._list_incompatible_shares]
|
2012-05-25 19:55:48 +00:00
|
|
|
d = {"count-shares-needed": self._count_shares_needed,
|
|
|
|
"count-shares-expected": self._count_shares_expected,
|
|
|
|
"count-shares-good": self._count_shares_good,
|
|
|
|
"count-good-share-hosts": self._count_good_share_hosts,
|
|
|
|
"count-recoverable-versions": self._count_recoverable_versions,
|
|
|
|
"count-unrecoverable-versions": self._count_unrecoverable_versions,
|
2012-05-25 19:56:20 +00:00
|
|
|
"servers-responding": responding,
|
2012-05-25 19:56:03 +00:00
|
|
|
"sharemap": sharemap,
|
2012-05-25 19:55:48 +00:00
|
|
|
"count-wrong-shares": self._count_wrong_shares,
|
2012-05-25 19:57:53 +00:00
|
|
|
"list-corrupt-shares": corrupt,
|
2012-05-25 19:55:48 +00:00
|
|
|
"count-corrupt-shares": self._count_corrupt_shares,
|
2012-05-25 19:57:53 +00:00
|
|
|
"list-incompatible-shares": incompatible,
|
2012-05-25 19:55:48 +00:00
|
|
|
"count-incompatible-shares": self._count_incompatible_shares,
|
|
|
|
}
|
|
|
|
return d
|
2008-09-07 19:44:56 +00:00
|
|
|
|
|
|
|
def get_summary(self):
|
2012-05-25 19:29:10 +00:00
|
|
|
return self._summary
|
2008-09-07 19:44:56 +00:00
|
|
|
def get_report(self):
|
2012-05-25 19:29:10 +00:00
|
|
|
return self._report
|
2012-05-25 07:14:46 +00:00
|
|
|
def get_share_problems(self):
|
|
|
|
return self._share_problems
|
2008-09-07 19:44:56 +00:00
|
|
|
def get_servermap(self):
|
2012-05-25 19:29:10 +00:00
|
|
|
return self._servermap
|
2008-09-07 19:44:56 +00:00
|
|
|
|
|
|
|
class CheckAndRepairResults:
|
|
|
|
implements(ICheckAndRepairResults)
|
|
|
|
|
|
|
|
def __init__(self, storage_index):
|
|
|
|
self.storage_index = storage_index
|
|
|
|
self.repair_attempted = False
|
|
|
|
|
|
|
|
def get_storage_index(self):
|
|
|
|
return self.storage_index
|
|
|
|
def get_storage_index_string(self):
|
|
|
|
return base32.b2a(self.storage_index)
|
|
|
|
def get_repair_attempted(self):
|
|
|
|
return self.repair_attempted
|
|
|
|
def get_repair_successful(self):
|
2008-09-10 02:45:17 +00:00
|
|
|
if not self.repair_attempted:
|
|
|
|
return False
|
2008-09-07 19:44:56 +00:00
|
|
|
return self.repair_successful
|
|
|
|
def get_pre_repair_results(self):
|
|
|
|
return self.pre_repair_results
|
|
|
|
def get_post_repair_results(self):
|
|
|
|
return self.post_repair_results
|
|
|
|
|
|
|
|
|
|
|
|
class DeepResultsBase:
|
|
|
|
|
|
|
|
def __init__(self, root_storage_index):
|
|
|
|
self.root_storage_index = root_storage_index
|
|
|
|
if root_storage_index is None:
|
2010-02-24 08:02:20 +00:00
|
|
|
self.root_storage_index_s = "<none>" # is this correct?
|
2008-09-07 19:44:56 +00:00
|
|
|
else:
|
2008-09-10 06:14:16 +00:00
|
|
|
self.root_storage_index_s = base32.b2a(root_storage_index)
|
2008-09-07 19:44:56 +00:00
|
|
|
|
|
|
|
self.objects_checked = 0
|
|
|
|
self.objects_healthy = 0
|
|
|
|
self.objects_unhealthy = 0
|
2008-11-07 05:35:47 +00:00
|
|
|
self.objects_unrecoverable = 0
|
2008-09-07 19:44:56 +00:00
|
|
|
self.corrupt_shares = []
|
|
|
|
self.all_results = {}
|
2008-10-23 23:00:31 +00:00
|
|
|
self.all_results_by_storage_index = {}
|
2008-09-10 08:45:04 +00:00
|
|
|
self.stats = {}
|
|
|
|
|
|
|
|
def update_stats(self, new_stats):
|
|
|
|
self.stats.update(new_stats)
|
2008-09-07 19:44:56 +00:00
|
|
|
|
|
|
|
def get_root_storage_index_string(self):
|
|
|
|
return self.root_storage_index_s
|
|
|
|
|
|
|
|
def get_corrupt_shares(self):
|
|
|
|
return self.corrupt_shares
|
|
|
|
|
|
|
|
def get_all_results(self):
|
|
|
|
return self.all_results
|
|
|
|
|
2008-10-23 23:00:31 +00:00
|
|
|
def get_results_for_storage_index(self, storage_index):
|
|
|
|
return self.all_results_by_storage_index[storage_index]
|
|
|
|
|
2008-09-10 08:45:04 +00:00
|
|
|
def get_stats(self):
|
|
|
|
return self.stats
|
|
|
|
|
2008-09-07 19:44:56 +00:00
|
|
|
|
|
|
|
class DeepCheckResults(DeepResultsBase):
|
|
|
|
implements(IDeepCheckResults)
|
|
|
|
|
|
|
|
def add_check(self, r, path):
|
|
|
|
if not r:
|
|
|
|
return # non-distributed object, i.e. LIT file
|
2009-01-06 20:37:03 +00:00
|
|
|
r = ICheckResults(r)
|
2008-09-07 19:44:56 +00:00
|
|
|
assert isinstance(path, (list, tuple))
|
|
|
|
self.objects_checked += 1
|
|
|
|
if r.is_healthy():
|
|
|
|
self.objects_healthy += 1
|
|
|
|
else:
|
|
|
|
self.objects_unhealthy += 1
|
2008-11-07 05:35:47 +00:00
|
|
|
if not r.is_recoverable():
|
|
|
|
self.objects_unrecoverable += 1
|
2008-09-07 19:44:56 +00:00
|
|
|
self.all_results[tuple(path)] = r
|
2008-10-23 23:00:31 +00:00
|
|
|
self.all_results_by_storage_index[r.get_storage_index()] = r
|
2012-05-25 07:13:48 +00:00
|
|
|
self.corrupt_shares.extend(r.get_corrupt_shares())
|
2008-09-07 19:44:56 +00:00
|
|
|
|
|
|
|
def get_counters(self):
|
|
|
|
return {"count-objects-checked": self.objects_checked,
|
|
|
|
"count-objects-healthy": self.objects_healthy,
|
|
|
|
"count-objects-unhealthy": self.objects_unhealthy,
|
2008-11-07 05:35:47 +00:00
|
|
|
"count-objects-unrecoverable": self.objects_unrecoverable,
|
2008-09-07 19:44:56 +00:00
|
|
|
"count-corrupt-shares": len(self.corrupt_shares),
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class DeepCheckAndRepairResults(DeepResultsBase):
|
|
|
|
implements(IDeepCheckAndRepairResults)
|
|
|
|
|
|
|
|
def __init__(self, root_storage_index):
|
|
|
|
DeepResultsBase.__init__(self, root_storage_index)
|
|
|
|
self.objects_healthy_post_repair = 0
|
|
|
|
self.objects_unhealthy_post_repair = 0
|
2008-11-07 05:35:47 +00:00
|
|
|
self.objects_unrecoverable_post_repair = 0
|
2008-09-07 19:44:56 +00:00
|
|
|
self.repairs_attempted = 0
|
|
|
|
self.repairs_successful = 0
|
|
|
|
self.repairs_unsuccessful = 0
|
|
|
|
self.corrupt_shares_post_repair = []
|
|
|
|
|
|
|
|
def add_check_and_repair(self, r, path):
|
|
|
|
if not r:
|
|
|
|
return # non-distributed object, i.e. LIT file
|
|
|
|
r = ICheckAndRepairResults(r)
|
|
|
|
assert isinstance(path, (list, tuple))
|
|
|
|
pre_repair = r.get_pre_repair_results()
|
|
|
|
post_repair = r.get_post_repair_results()
|
|
|
|
self.objects_checked += 1
|
|
|
|
if pre_repair.is_healthy():
|
|
|
|
self.objects_healthy += 1
|
|
|
|
else:
|
|
|
|
self.objects_unhealthy += 1
|
2008-11-07 05:35:47 +00:00
|
|
|
if not pre_repair.is_recoverable():
|
|
|
|
self.objects_unrecoverable += 1
|
2012-05-25 07:13:48 +00:00
|
|
|
self.corrupt_shares.extend(pre_repair.get_corrupt_shares())
|
2008-09-07 19:44:56 +00:00
|
|
|
if r.get_repair_attempted():
|
|
|
|
self.repairs_attempted += 1
|
|
|
|
if r.get_repair_successful():
|
|
|
|
self.repairs_successful += 1
|
|
|
|
else:
|
|
|
|
self.repairs_unsuccessful += 1
|
|
|
|
if post_repair.is_healthy():
|
|
|
|
self.objects_healthy_post_repair += 1
|
|
|
|
else:
|
|
|
|
self.objects_unhealthy_post_repair += 1
|
2008-11-07 05:35:47 +00:00
|
|
|
if not post_repair.is_recoverable():
|
|
|
|
self.objects_unrecoverable_post_repair += 1
|
2008-09-07 19:44:56 +00:00
|
|
|
self.all_results[tuple(path)] = r
|
2008-10-23 23:00:31 +00:00
|
|
|
self.all_results_by_storage_index[r.get_storage_index()] = r
|
2012-05-25 07:13:48 +00:00
|
|
|
self.corrupt_shares_post_repair.extend(post_repair.get_corrupt_shares())
|
2008-09-07 19:44:56 +00:00
|
|
|
|
|
|
|
def get_counters(self):
|
|
|
|
return {"count-objects-checked": self.objects_checked,
|
|
|
|
"count-objects-healthy-pre-repair": self.objects_healthy,
|
|
|
|
"count-objects-unhealthy-pre-repair": self.objects_unhealthy,
|
2008-11-07 05:35:47 +00:00
|
|
|
"count-objects-unrecoverable-pre-repair": self.objects_unrecoverable,
|
2008-09-07 19:44:56 +00:00
|
|
|
"count-objects-healthy-post-repair": self.objects_healthy_post_repair,
|
|
|
|
"count-objects-unhealthy-post-repair": self.objects_unhealthy_post_repair,
|
2008-11-07 05:35:47 +00:00
|
|
|
"count-objects-unrecoverable-post-repair": self.objects_unrecoverable_post_repair,
|
2008-09-07 19:44:56 +00:00
|
|
|
"count-repairs-attempted": self.repairs_attempted,
|
|
|
|
"count-repairs-successful": self.repairs_successful,
|
|
|
|
"count-repairs-unsuccessful": self.repairs_unsuccessful,
|
|
|
|
"count-corrupt-shares-pre-repair": len(self.corrupt_shares),
|
|
|
|
"count-corrupt-shares-post-repair": len(self.corrupt_shares_post_repair),
|
|
|
|
}
|
|
|
|
|
|
|
|
def get_remaining_corrupt_shares(self):
|
|
|
|
return self.corrupt_shares_post_repair
|