2 from allmydata.util.spans import DataSpans
4 MODE_CHECK = "MODE_CHECK" # query all peers
5 MODE_ANYTHING = "MODE_ANYTHING" # one recoverable version
6 MODE_WRITE = "MODE_WRITE" # replace all shares, probably.. not for initial
8 MODE_READ = "MODE_READ"
9 MODE_REPAIR = "MODE_REPAIR" # query all peers, get the privkey
11 class NotWriteableError(Exception):
14 class BadShareError(Exception):
15 """This represents an error discovered in a particular share, during
16 retrieve, from which we can recover by using some other share. This does
17 *not* include local coding errors.
20 class NeedMoreDataError(BadShareError):
21 def __init__(self, needed_bytes, encprivkey_offset, encprivkey_length):
22 Exception.__init__(self)
23 self.needed_bytes = needed_bytes # up through EOF
24 self.encprivkey_offset = encprivkey_offset
25 self.encprivkey_length = encprivkey_length
27 return "<NeedMoreDataError (%d bytes)>" % self.needed_bytes
29 class UncoordinatedWriteError(Exception):
31 return ("<%s -- You, oh user, tried to change a file or directory "
32 "at the same time as another process was trying to change it. "
33 " To avoid data loss, don't do this. Please see "
34 "docs/write_coordination.rst for details.>" %
35 (self.__class__.__name__,))
37 class UnrecoverableFileError(Exception):
40 class NotEnoughServersError(Exception):
41 """There were not enough functioning servers available to place shares
42 upon. This might result from all servers being full or having an error, a
43 local bug which causes all server requests to fail in the same way, or
44 from there being zero servers. The first error received (if any) is
45 stored in my .first_error attribute."""
46 def __init__(self, why, first_error=None):
47 Exception.__init__(self, why, first_error)
48 self.first_error = first_error
50 class CorruptShareError(BadShareError):
51 def __init__(self, server, shnum, reason):
52 self.args = (server, shnum, reason)
57 return "<CorruptShareError server=%s shnum[%d]: %s" % \
58 (self.server.get_name(), self.shnum, self.reason)
60 class UnknownVersionError(BadShareError):
61 """The share we received was of a version we don't recognize."""
64 """I cache share data, to reduce the number of round trips used during
65 mutable file operations. All of the data in my cache is for a single
66 storage index, but I will keep information on multiple shares for
69 I maintain a highest-seen sequence number, and will flush all entries
70 each time this number increases (this doesn't necessarily imply that
71 all entries have the same sequence number).
73 My cache is indexed by a (verinfo, shnum) tuple.
75 My cache entries are DataSpans instances, each representing a set of
76 non-overlapping byteranges.
84 # also used by unit tests
87 def add(self, verinfo, shnum, offset, data):
89 if seqnum > self.seqnum:
93 index = (verinfo, shnum)
94 if index in self.cache:
95 self.cache[index].add(offset, data)
98 spans.add(offset, data)
99 self.cache[index] = spans
101 def read(self, verinfo, shnum, offset, length):
102 """Try to satisfy a read request from cache.
103 Returns data, or None if the cache did not hold the entire requested span.
106 # TODO: perhaps return a DataSpans object representing the fragments
107 # that we have, instead of only returning a hit if we can satisfy the
108 # whole request from cache.
110 index = (verinfo, shnum)
111 if index in self.cache:
112 return self.cache[index].get(offset, length)