-from allmydata.util import idlib
-from allmydata.util.spans import DataSpans
-
MODE_CHECK = "MODE_CHECK" # query all peers
MODE_ANYTHING = "MODE_ANYTHING" # one recoverable version
MODE_WRITE = "MODE_WRITE" # replace all shares, probably.. not for initial
# creation
MODE_READ = "MODE_READ"
+MODE_REPAIR = "MODE_REPAIR" # query all peers, get the privkey
class NotWriteableError(Exception):
pass
-class NeedMoreDataError(Exception):
+class BadShareError(Exception):
+ """This represents an error discovered in a particular share, during
+ retrieve, from which we can recover by using some other share. This does
+ *not* include local coding errors.
+ """
+
+class NeedMoreDataError(BadShareError):
def __init__(self, needed_bytes, encprivkey_offset, encprivkey_length):
Exception.__init__(self)
self.needed_bytes = needed_bytes # up through EOF
return ("<%s -- You, oh user, tried to change a file or directory "
"at the same time as another process was trying to change it. "
" To avoid data loss, don't do this. Please see "
- "docs/write_coordination.html for details.>" %
+ "docs/write_coordination.rst for details.>" %
(self.__class__.__name__,))
class UnrecoverableFileError(Exception):
Exception.__init__(self, why, first_error)
self.first_error = first_error
-class CorruptShareError(Exception):
- def __init__(self, peerid, shnum, reason):
- self.args = (peerid, shnum, reason)
- self.peerid = peerid
+class CorruptShareError(BadShareError):
+ def __init__(self, server, shnum, reason):
+ self.args = (server, shnum, reason)
+ self.server = server
self.shnum = shnum
self.reason = reason
def __str__(self):
- short_peerid = idlib.nodeid_b2a(self.peerid)[:8]
- return "<CorruptShareError peerid=%s shnum[%d]: %s" % (short_peerid,
- self.shnum,
- self.reason)
+ return "<CorruptShareError server=%s shnum[%d]: %s" % \
+ (self.server.get_name(), self.shnum, self.reason)
-class UnknownVersionError(Exception):
+class UnknownVersionError(BadShareError):
"""The share we received was of a version we don't recognize."""
-
-class ResponseCache:
- """I cache share data, to reduce the number of round trips used during
- mutable file operations. All of the data in my cache is for a single
- storage index, but I will keep information on multiple shares for
- that storage index.
-
- I maintain a highest-seen sequence number, and will flush all entries
- each time this number increases (this doesn't necessarily imply that
- all entries have the same sequence number).
-
- My cache is indexed by a (verinfo, shnum) tuple.
-
- My cache entries are DataSpans instances, each representing a set of
- non-overlapping byteranges.
- """
-
- def __init__(self):
- self.cache = {}
- self.seqnum = None
-
- def _clear(self):
- # also used by unit tests
- self.cache = {}
-
- def add(self, verinfo, shnum, offset, data):
- seqnum = verinfo[0]
- if seqnum > self.seqnum:
- self._clear()
- self.seqnum = seqnum
-
- index = (verinfo, shnum)
- if index in self.cache:
- self.cache[index].add(offset, data)
- else:
- spans = DataSpans()
- spans.add(offset, data)
- self.cache[index] = spans
-
- def read(self, verinfo, shnum, offset, length):
- """Try to satisfy a read request from cache.
- Returns data, or None if the cache did not hold the entire requested span.
- """
-
- # TODO: perhaps return a DataSpans object representing the fragments
- # that we have, instead of only returning a hit if we can satisfy the
- # whole request from cache.
-
- index = (verinfo, shnum)
- if index in self.cache:
- return self.cache[index].get(offset, length)
- else:
- return None