from allmydata.interfaces import IDownloadTarget, IDownloader, \
IFileURI, IVerifierURI, \
IDownloadStatus, IDownloadResults, IValidatedThingProxy, \
- IStorageBroker, NotEnoughSharesError, NoServersError, \
+ IStorageBroker, NotEnoughSharesError, NoSharesError, NoServersError, \
UnableToFetchCriticalDownloadDataError
from allmydata.immutable import layout
from allmydata.monitor import Monitor
self._results.timings["peer_selection"] = now - self._started
if len(self._share_buckets) < self._verifycap.needed_shares:
- raise NotEnoughSharesError("Failed to get enough shareholders",
- len(self._share_buckets),
- self._verifycap.needed_shares)
+ msg = "Failed to get enough shareholders: have %d, need %d" \
+ % (len(self._share_buckets), self._verifycap.needed_shares)
+ if self._share_buckets:
+ raise NotEnoughSharesError(msg)
+ else:
+ raise NoSharesError(msg)
#for s in self._share_vbuckets.values():
# for vb in s:
potential_shnums = list(available_shnums - handled_shnums)
if len(potential_shnums) < (self._verifycap.needed_shares - len(self.active_buckets)):
have = len(potential_shnums) + len(self.active_buckets)
- raise NotEnoughSharesError("Unable to activate enough shares",
- have, self._verifycap.needed_shares)
+ msg = "Unable to activate enough shares: have %d, need %d" \
+ % (have, self._verifycap.needed_shares)
+ if have:
+ raise NotEnoughSharesError(msg)
+ else:
+ raise NoSharesError(msg)
# For the next share, choose a primary share if available, else a randomly chosen
# secondary share.
potential_shnums.sort()
from allmydata.util.assertutil import _assert, precondition
from allmydata.codec import CRSEncoder
from allmydata.interfaces import IEncoder, IStorageBucketWriter, \
- IEncryptedUploadable, IUploadStatus, NotEnoughSharesError
+ IEncryptedUploadable, IUploadStatus, NotEnoughSharesError, NoSharesError
"""
The goal of the encoder is to turn the original file into a series of
self.log("they weren't in our list of landlords", parent=ln,
level=log.WEIRD, umid="TQGFRw")
if len(self.landlords) < self.shares_of_happiness:
- msg = "lost too many shareholders during upload: %s" % why
- raise NotEnoughSharesError(msg, len(self.landlords),
- self.shares_of_happiness)
+ msg = "lost too many shareholders during upload (still have %d, want %d): %s" % \
+ (len(self.landlords), self.shares_of_happiness, why)
+ if self.landlords:
+ raise NotEnoughSharesError(msg)
+ else:
+ raise NoSharesError(msg)
self.log("but we can still continue with %s shares, we'll be happy "
"with at least %s" % (len(self.landlords),
self.shares_of_happiness),
# otherwise be consumed. Allow non-NotEnoughSharesError exceptions
# to pass through as an unhandled errback. We use this in lieu of
# consumeErrors=True to allow coding errors to be logged.
- f.trap(NotEnoughSharesError)
+ f.trap(NotEnoughSharesError, NoSharesError)
return None
for d0 in dl:
d0.addErrback(_eatNotEnoughSharesError)
from allmydata.util.rrefutil import add_version_to_remote_reference
from allmydata.interfaces import IUploadable, IUploader, IUploadResults, \
IEncryptedUploadable, RIEncryptedUploadable, IUploadStatus, \
- NotEnoughSharesError, InsufficientVersionError, NoServersError
+ NotEnoughSharesError, NoSharesError, NoServersError, \
+ InsufficientVersionError
from allmydata.immutable import layout
from pycryptopp.cipher.aes import AES
placed_shares = self.total_shares - len(self.homeless_shares)
if placed_shares < self.shares_of_happiness:
msg = ("placed %d shares out of %d total (%d homeless), "
+ "want to place %d, "
"sent %d queries to %d peers, "
"%d queries placed some shares, %d placed none, "
"got %d errors" %
(self.total_shares - len(self.homeless_shares),
self.total_shares, len(self.homeless_shares),
+ self.shares_of_happiness,
self.query_count, self.num_peers_contacted,
self.good_query_count, self.bad_query_count,
self.error_count))
if self.last_failure_msg:
msg += " (%s)" % (self.last_failure_msg,)
log.msg(msg, level=log.UNUSUAL, parent=self._log_parent)
- raise NotEnoughSharesError(msg, placed_shares,
- self.shares_of_happiness)
+ if placed_shares:
+ raise NotEnoughSharesError(msg)
+ else:
+ raise NoSharesError(msg)
else:
# we placed enough to be happy, so we're done
if self._status:
"""
class NotEnoughSharesError(Exception):
- def __init__(self, msg, got, needed):
- Exception.__init__(self, msg)
- self.got = got
- self.needed = needed
- self.servermap = None
+ """Download was unable to get enough shares, or upload was unable to
+ place 'shares_of_happiness' shares."""
+
+class NoSharesError(Exception):
+ """Upload or Download was unable to get any shares at all."""
class UnableToFetchCriticalDownloadDataError(Exception):
"""I was unable to fetch some piece of critical data which is supposed to
self.log(format=format,
level=log.WEIRD, umid="ezTfjw", **args)
err = NotEnoughSharesError("%s, last failure: %s" %
- (format % args, self._last_failure),
- len(self.shares), k)
+ (format % args, self._last_failure))
if self._bad_shares:
self.log("We found some bad shares this pass. You should "
"update the servermap and try again to check "
def _check1((rc, out, err)):
self.failIfEqual(rc, 0)
self.failUnless("410 Gone" in err, err)
- self.failUnless("NotEnoughSharesError: 1 share found, but we need 3" in err,
- err)
+ self.failUnlessIn("NotEnoughSharesError: ", err)
+ self.failUnlessIn("Failed to get enough shareholders: have 1, need 3", err)
d.addCallback(_check1)
return d
from allmydata.util import log, base32
from allmydata.scripts import runner
from allmydata.interfaces import IDirectoryNode, IFileNode, IFileURI, \
- NoSuchChildError, NotEnoughSharesError
+ NoSuchChildError, NotEnoughSharesError, NoSharesError
from allmydata.monitor import Monitor
from allmydata.mutable.common import NotMutableError
from allmydata.mutable import layout as mutable_layout
bad_n = self.clients[1].create_node_from_uri(bad_u.to_string())
# this should cause an error during download
- d = self.shouldFail2(NotEnoughSharesError, "'download bad node'",
+ d = self.shouldFail2(NoSharesError, "'download bad node'",
None,
bad_n.read, MemoryConsumer(), offset=2)
return d
log.msg("finished downloading non-existend URI",
level=log.UNUSUAL, facility="tahoe.tests")
self.failUnless(isinstance(res, Failure))
- self.failUnless(res.check(NotEnoughSharesError),
- "expected NotEnoughSharesError, got %s" % res)
- # TODO: files that have zero peers should get a special kind
- # of NotEnoughSharesError, which can be used to suggest that
- # the URI might be wrong or that they've never uploaded the
- # file in the first place.
+ self.failUnless(res.check(NoSharesError),
+ "expected NoSharesError, got %s" % res)
d1.addBoth(_baduri_should_fail)
return d1
d.addCallback(_download_nonexistent_uri)
import allmydata # for __full_version__
from allmydata import uri, monitor
from allmydata.immutable import upload
-from allmydata.interfaces import IFileURI, FileTooLargeError, NotEnoughSharesError
+from allmydata.interfaces import IFileURI, FileTooLargeError, \
+ NotEnoughSharesError, NoSharesError
from allmydata.util.assertutil import precondition
from allmydata.util.deferredutil import DeferredListShouldSucceed
from no_network import GridTestMixin
self.u.parent = self.node
def _should_fail(self, f):
- self.failUnless(isinstance(f, Failure) and f.check(NotEnoughSharesError), f)
+ self.failUnless(isinstance(f, Failure) and f.check(NoSharesError), f)
def test_data_large(self):
data = DATA
d.addCallback(lambda ignored:
self.shouldHTTPError("GET unrecoverable",
- 410, "Gone", "NotEnoughSharesError",
+ 410, "Gone", "NoSharesError",
self.GET, self.fileurls["0shares"]))
def _check_zero_shares(body):
self.failIf("<html>" in body, body)
body = " ".join(body.strip().split())
- exp = ("NotEnoughSharesError: no shares could be found. "
+ exp = ("NoSharesError: no shares could be found. "
"Zero shares usually indicates a corrupt URI, or that "
"no servers were connected, but it might also indicate "
"severe corruption. You should perform a filecheck on "
- "this object to learn more.")
+ "this object to learn more. The full error message is: "
+ "Failed to get enough shareholders: have 0, need 3")
self.failUnlessEqual(exp, body)
d.addCallback(_check_zero_shares)
def _check_one_share(body):
self.failIf("<html>" in body, body)
body = " ".join(body.strip().split())
- exp = ("NotEnoughSharesError: 1 share found, but we need "
- "3 to recover the file. This indicates that some "
+ exp = ("NotEnoughSharesError: This indicates that some "
"servers were unavailable, or that shares have been "
"lost to server departure, hard drive failure, or disk "
"corruption. You should perform a filecheck on "
- "this object to learn more.")
+ "this object to learn more. The full error message is:"
+ " Failed to get enough shareholders: have 1, need 3")
self.failUnlessEqual(exp, body)
d.addCallback(_check_one_share)
from twisted.web import http, server
+from twisted.python import log
from zope.interface import Interface
from nevow import loaders, appserver
from nevow.inevow import IRequest
from nevow.util import resource_filename
from allmydata.interfaces import ExistingChildError, NoSuchChildError, \
- FileTooLargeError, NotEnoughSharesError
+ FileTooLargeError, NotEnoughSharesError, NoSharesError
from allmydata.mutable.common import UnrecoverableFileError
from allmydata.util import abbreviate # TODO: consolidate
name = f.value.args[0]
return ("No such child: %s" % name.encode("utf-8"), http.NOT_FOUND)
if f.check(NotEnoughSharesError):
- got = f.value.got
- needed = f.value.needed
- if got == 0:
- t = ("NotEnoughSharesError: no shares could be found. "
- "Zero shares usually indicates a corrupt URI, or that "
- "no servers were connected, but it might also indicate "
- "severe corruption. You should perform a filecheck on "
- "this object to learn more.")
- else:
- t = ("NotEnoughSharesError: %d share%s found, but we need "
- "%d to recover the file. This indicates that some "
- "servers were unavailable, or that shares have been "
- "lost to server departure, hard drive failure, or disk "
- "corruption. You should perform a filecheck on "
- "this object to learn more.") % (got, plural(got), needed)
+ t = ("NotEnoughSharesError: This indicates that some "
+ "servers were unavailable, or that shares have been "
+ "lost to server departure, hard drive failure, or disk "
+ "corruption. You should perform a filecheck on "
+ "this object to learn more.\n\nThe full error message is:\n"
+ "%s") % str(f.value)
+ return (t, http.GONE)
+ if f.check(NoSharesError):
+ t = ("NoSharesError: no shares could be found. "
+ "Zero shares usually indicates a corrupt URI, or that "
+ "no servers were connected, but it might also indicate "
+ "severe corruption. You should perform a filecheck on "
+ "this object to learn more.\n\nThe full error message is:\n"
+ "%s") % str(f.value)
return (t, http.GONE)
if f.check(UnrecoverableFileError):
t = ("UnrecoverableFileError: the directory (or mutable file) could "
req.finishRequest(False)
def renderHTTP_exception(self, ctx, f):
- text, code = humanize_failure(f)
+ try:
+ text, code = humanize_failure(f)
+ except:
+ log.msg("exception in humanize_failure")
+ log.msg("argument was %s" % (f,))
+ log.err()
+ text, code = str(f), None
if code is not None:
return self.simple(ctx, text, code)
if f.check(server.UnsupportedMethod):