from allmydata.interfaces import IMutableFileNode, IDirectoryNode,\
IURI, IFileNode, IMutableFileURI, IVerifierURI, IFilesystemNode, \
ExistingChildError, ICheckable
+from allmydata.immutable.checker import DeepCheckResults
from allmydata.util import hashutil, mathutil
from allmydata.util.hashutil import netstring
from allmydata.util.limiter import ConcurrencyLimiter
d.addCallback(_got_list)
return d
+ def deep_check(self, verify=False, repair=False):
+ results = DeepCheckResults()
+ found = set()
+ found.add(self.get_verifier())
+
+ limiter = ConcurrencyLimiter(10)
+
+ d = self._add_check_from_node(self, results, limiter, verify, repair)
+ d.addCallback(lambda res:
+ self._add_deepcheck_from_dirnode(self,
+ found, results, limiter,
+ verify, repair))
+ d.addCallback(lambda res: results)
+ return d
+
+ def _add_check_from_node(self, node, results, limiter, verify, repair):
+ d = limiter.add(node.check, verify, repair)
+ d.addCallback(results.add_check)
+ return d
+
+ def _add_deepcheck_from_dirnode(self, node, found, results, limiter,
+ verify, repair):
+ d = limiter.add(node.list)
+ def _got_list(children):
+ dl = []
+ for name, (child, metadata) in children.iteritems():
+ verifier = child.get_verifier()
+ if verifier in found:
+ # avoid loops
+ continue
+ dl.append(self._add_check_from_node(child,
+ results, limiter,
+ verify, repair))
+ if IDirectoryNode.providedBy(child):
+ dl.append(self._add_deepcheck_from_node(child, found,
+ results, limiter,
+ verify, repair))
+ if dl:
+ return defer.DeferredList(dl)
+ d.addCallback(_got_list)
+ return d
+
class DeepStats:
def __init__(self):
self.stats = {}
from twisted.internet import defer
from twisted.python import log
from allmydata import storage
-from allmydata.interfaces import IVerifierURI, ICheckerResults
+from allmydata.interfaces import IVerifierURI, \
+ ICheckerResults, IDeepCheckResults
from allmydata.immutable import download
from allmydata.util import hashutil, base32
s += "Not Healthy!\n"
return s
+class DeepCheckResults:
+ implements(IDeepCheckResults)
+
+ def __init__(self):
+ self.objects_checked = 0
+ self.objects_healthy = 0
+ self.repairs_attempted = 0
+ self.repairs_successful = 0
+ self.problems = []
+ self.server_problems = {}
+
+ def add_check(self, r):
+ self.objects_checked += 1
+ if r.is_healthy:
+ self.objects_healthy += 1
+ else:
+ self.problems.append(r)
+
+ def add_repair(self, is_successful):
+ self.repairs_attempted += 1
+ if is_successful:
+ self.repairs_successful += 1
+
+ def count_objects_checked(self):
+ return self.objects_checked
+ def count_objects_healthy(self):
+ return self.objects_healthy
+ def count_repairs_attempted(self):
+ return self.repairs_attempted
+ def count_repairs_successful(self):
+ return self.repairs_successful
+ def get_server_problems(self):
+ return self.server_problems
+ def get_problems(self):
+ return self.problems
+
class SimpleCHKFileChecker:
"""Return a list of (needed, total, found, sharemap), where sharemap maps
from twisted.internet import defer
from allmydata.interfaces import IFileNode, IFileURI, IURI, ICheckable
from allmydata import uri
-from allmydata.immutable.checker import Results, \
+from allmydata.immutable.checker import Results, DeepCheckResults, \
SimpleCHKFileChecker, SimpleCHKFileVerifier
class FileNode:
v = SimpleCHKFileChecker(peer_getter, vcap)
return v.check()
+ def deep_check(self, verify=False, repair=False):
+ d = self.check(verify, repair)
+ def _done(r):
+ dr = DeepCheckResults()
+ dr.add_check(r)
+ return dr
+ d.addCallback(_done)
+ return d
+
def download(self, target):
downloader = self._client.getServiceNamed("downloader")
return downloader.download(self.uri, target)
taken.
"""
+ def deep_check(verify=False, repair=False):
+ """Check upon the health of me and everything I can reach.
+
+ This is a recursive form of check(), useable on dirnodes. (it can be
+ called safely on filenodes too, but only checks the one object).
+
+ I return a Deferred that fires with an IDeepCheckResults object.
+ """
+
class ICheckerResults(Interface):
"""I contain the detailed results of a check/verify/repair operation.
# same nodeid, they will fail as a pair, and overall reliability is
# decreased.
+class IDeepCheckResults(Interface):
+ """I contain the results of a deep-check operation.
+
+ This is returned by a call to ICheckable.deep_check().
+ """
+
+ def count_objects_checked():
+ """Return the number of objects that were checked."""
+ def count_objects_healthy():
+ """Return the number of objects that were fully healthy."""
+ def count_repairs_attempted():
+ """Return the number of repair operations that were attempted."""
+ def count_repairs_successful():
+ """Return the number of repair operations that succeeded in bringing
+ the object back up to full health."""
+ def get_server_problems():
+ """Return a dict, mapping server nodeid to a count of how many
+ problems involved that server."""
+ def get_problems():
+ """Return a list of ICheckerResults, one for each object that
+ was not fully healthy."""
class IClient(Interface):
from allmydata.util.assertutil import precondition
from allmydata.uri import WriteableSSKFileURI
from allmydata.immutable.encode import NotEnoughSharesError
+from allmydata.immutable.checker import DeepCheckResults
from pycryptopp.publickey import rsa
from pycryptopp.cipher.aes import AES
checker = MutableChecker(self)
return checker.check(verify, repair)
+ def deep_check(self, verify=False, repair=False):
+ d = self.check(verify, repair)
+ def _done(r):
+ dr = DeepCheckResults()
+ dr.add_check(r)
+ return dr
+ d.addCallback(_done)
+ return d
+
# allow the use of IDownloadTarget
def download(self, target):
# fake it. TODO: make this cleaner.
d.addCallback(_done)
return d
+ def _test_deepcheck_create(self):
+ d = self.client.create_empty_dirnode()
+ def _created_root(rootnode):
+ self._rootnode = rootnode
+ d.addCallback(_created_root)
+ def _done(res):
+ return self._rootnode
+ d.addCallback(_done)
+ return d
+
+ def test_deepcheck(self):
+ d = self._test_deepcheck_create()
+ d.addCallback(lambda rootnode: rootnode.deep_check())
+ def _check_results(r):
+ self.failUnlessEqual(r.count_objects_checked(), 1)
+ self.failUnlessEqual(r.count_objects_healthy(), 1)
+ self.failUnlessEqual(r.count_repairs_attempted(), 0)
+ self.failUnlessEqual(r.count_repairs_successful(), 0)
+ self.failUnlessEqual(len(r.get_server_problems()), 0)
+ self.failUnlessEqual(len(r.get_problems()), 0)
+ d.addCallback(_check_results)
+ return d
+
def test_readonly(self):
fileuri = make_chk_file_uri(1234)
filenode = self.client.create_node_from_uri(fileuri)