2007-01-05 04:52:51 +00:00
|
|
|
# -*- test-case-name: allmydata.test.test_encode_share -*-
|
|
|
|
|
|
|
|
from zope.interface import implements
|
2006-12-03 00:31:26 +00:00
|
|
|
from twisted.internet import defer
|
2007-03-28 22:31:51 +00:00
|
|
|
from allmydata.util import mathutil
|
2007-02-02 00:13:01 +00:00
|
|
|
from allmydata.util.assertutil import precondition
|
2007-01-12 03:57:14 +00:00
|
|
|
from allmydata.interfaces import ICodecEncoder, ICodecDecoder
|
2007-04-19 00:25:16 +00:00
|
|
|
import zfec
|
2006-12-03 10:01:43 +00:00
|
|
|
|
2007-02-01 23:07:00 +00:00
|
|
|
|
2007-01-05 04:52:51 +00:00
|
|
|
class ReplicatingEncoder(object):
|
2007-01-12 03:57:14 +00:00
|
|
|
implements(ICodecEncoder)
|
2007-01-17 04:29:59 +00:00
|
|
|
ENCODER_TYPE = "rep"
|
2007-01-05 04:52:51 +00:00
|
|
|
|
2007-01-16 04:22:22 +00:00
|
|
|
def set_params(self, data_size, required_shares, max_shares):
|
2007-03-28 05:57:15 +00:00
|
|
|
assert data_size % required_shares == 0
|
2007-03-28 05:17:31 +00:00
|
|
|
assert required_shares <= max_shares
|
2007-01-05 04:52:51 +00:00
|
|
|
self.data_size = data_size
|
|
|
|
self.required_shares = required_shares
|
2007-01-16 04:22:22 +00:00
|
|
|
self.max_shares = max_shares
|
2007-01-05 04:52:51 +00:00
|
|
|
|
|
|
|
def get_encoder_type(self):
|
|
|
|
return self.ENCODER_TYPE
|
|
|
|
|
|
|
|
def get_serialized_params(self):
|
|
|
|
return "%d" % self.required_shares
|
|
|
|
|
2007-03-30 17:52:19 +00:00
|
|
|
def get_block_size(self):
|
|
|
|
return self.data_size
|
|
|
|
|
2007-03-28 05:17:31 +00:00
|
|
|
def encode(self, inshares, desired_shareids=None):
|
2007-03-28 05:57:15 +00:00
|
|
|
assert isinstance(inshares, list)
|
2007-03-28 05:17:31 +00:00
|
|
|
for inshare in inshares:
|
|
|
|
assert isinstance(inshare, str)
|
|
|
|
assert self.required_shares * len(inshare) == self.data_size
|
|
|
|
data = "".join(inshares)
|
2007-02-01 23:07:00 +00:00
|
|
|
if desired_shareids is None:
|
|
|
|
desired_shareids = range(self.max_shares)
|
|
|
|
shares = [data for i in desired_shareids]
|
|
|
|
return defer.succeed((shares, desired_shareids))
|
2007-01-05 04:52:51 +00:00
|
|
|
|
|
|
|
class ReplicatingDecoder(object):
|
2007-01-12 03:57:14 +00:00
|
|
|
implements(ICodecDecoder)
|
2007-01-05 04:52:51 +00:00
|
|
|
|
|
|
|
def set_serialized_params(self, params):
|
|
|
|
self.required_shares = int(params)
|
|
|
|
|
2007-03-30 17:52:19 +00:00
|
|
|
def get_needed_shares(self):
|
2007-01-16 04:22:22 +00:00
|
|
|
return self.required_shares
|
|
|
|
|
2007-02-01 23:07:00 +00:00
|
|
|
def decode(self, some_shares, their_shareids):
|
|
|
|
assert len(some_shares) == self.required_shares
|
|
|
|
assert len(some_shares) == len(their_shareids)
|
2007-03-28 05:57:15 +00:00
|
|
|
data = some_shares[0]
|
|
|
|
|
|
|
|
chunksize = mathutil.div_ceil(len(data), self.required_shares)
|
|
|
|
numchunks = mathutil.div_ceil(len(data), chunksize)
|
|
|
|
l = [ data[i:i+chunksize] for i in range(0, len(data), chunksize) ]
|
|
|
|
|
|
|
|
return defer.succeed(l)
|
2007-01-05 04:52:51 +00:00
|
|
|
|
|
|
|
|
2007-02-01 23:07:00 +00:00
|
|
|
class CRSEncoder(object):
|
2007-01-12 03:57:14 +00:00
|
|
|
implements(ICodecEncoder)
|
2007-03-28 07:05:16 +00:00
|
|
|
ENCODER_TYPE = "crs"
|
2007-01-05 07:42:52 +00:00
|
|
|
|
2007-01-16 04:22:22 +00:00
|
|
|
def set_params(self, data_size, required_shares, max_shares):
|
|
|
|
assert required_shares <= max_shares
|
2007-01-05 04:52:51 +00:00
|
|
|
self.data_size = data_size
|
|
|
|
self.required_shares = required_shares
|
2007-01-16 04:22:22 +00:00
|
|
|
self.max_shares = max_shares
|
2007-02-01 23:07:00 +00:00
|
|
|
self.share_size = mathutil.div_ceil(data_size, required_shares)
|
|
|
|
self.last_share_padding = mathutil.pad_size(self.share_size, required_shares)
|
2007-04-19 00:25:16 +00:00
|
|
|
self.encoder = zfec.Encoder(required_shares, max_shares)
|
2007-01-05 04:52:51 +00:00
|
|
|
|
|
|
|
def get_encoder_type(self):
|
|
|
|
return self.ENCODER_TYPE
|
|
|
|
|
|
|
|
def get_serialized_params(self):
|
2007-03-28 07:05:16 +00:00
|
|
|
return "%d-%d-%d" % (self.data_size, self.required_shares,
|
2007-01-16 04:22:22 +00:00
|
|
|
self.max_shares)
|
2007-01-05 04:52:51 +00:00
|
|
|
|
2007-03-30 17:52:19 +00:00
|
|
|
def get_block_size(self):
|
|
|
|
return self.share_size
|
|
|
|
|
2007-02-01 23:07:00 +00:00
|
|
|
def encode(self, inshares, desired_share_ids=None):
|
|
|
|
precondition(desired_share_ids is None or len(desired_share_ids) <= self.max_shares, desired_share_ids, self.max_shares)
|
|
|
|
|
|
|
|
if desired_share_ids is None:
|
|
|
|
desired_share_ids = range(self.max_shares)
|
|
|
|
|
|
|
|
for inshare in inshares:
|
|
|
|
assert len(inshare) == self.share_size, (len(inshare), self.share_size, self.data_size, self.required_shares)
|
|
|
|
shares = self.encoder.encode(inshares, desired_share_ids)
|
|
|
|
|
|
|
|
return defer.succeed((shares, desired_share_ids))
|
|
|
|
|
|
|
|
class CRSDecoder(object):
|
2007-01-12 03:57:14 +00:00
|
|
|
implements(ICodecDecoder)
|
2007-01-05 04:52:51 +00:00
|
|
|
|
|
|
|
def set_serialized_params(self, params):
|
2007-03-28 07:05:16 +00:00
|
|
|
pieces = params.split("-")
|
2007-01-05 04:52:51 +00:00
|
|
|
self.data_size = int(pieces[0])
|
|
|
|
self.required_shares = int(pieces[1])
|
2007-01-16 04:22:22 +00:00
|
|
|
self.max_shares = int(pieces[2])
|
2007-01-05 04:52:51 +00:00
|
|
|
|
|
|
|
self.chunk_size = self.required_shares
|
|
|
|
self.num_chunks = mathutil.div_ceil(self.data_size, self.chunk_size)
|
|
|
|
self.share_size = self.num_chunks
|
2007-04-19 00:25:16 +00:00
|
|
|
self.decoder = zfec.Decoder(self.required_shares, self.max_shares)
|
2007-01-05 04:52:51 +00:00
|
|
|
|
2007-03-30 17:52:19 +00:00
|
|
|
def get_needed_shares(self):
|
2007-01-16 04:22:22 +00:00
|
|
|
return self.required_shares
|
|
|
|
|
2007-02-01 23:07:00 +00:00
|
|
|
def decode(self, some_shares, their_shareids):
|
2007-07-12 22:33:30 +00:00
|
|
|
precondition(len(some_shares) == len(their_shareids),
|
|
|
|
len(some_shares), len(their_shareids))
|
|
|
|
precondition(len(some_shares) == self.required_shares,
|
|
|
|
len(some_shares), self.required_shares)
|
|
|
|
data = self.decoder.decode(some_shares,
|
|
|
|
[int(s) for s in their_shareids])
|
|
|
|
return defer.succeed(data)
|
2007-01-05 04:52:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
all_encoders = {
|
|
|
|
ReplicatingEncoder.ENCODER_TYPE: (ReplicatingEncoder, ReplicatingDecoder),
|
2007-02-01 23:07:00 +00:00
|
|
|
CRSEncoder.ENCODER_TYPE: (CRSEncoder, CRSDecoder),
|
2007-01-05 04:52:51 +00:00
|
|
|
}
|
2007-01-17 04:29:59 +00:00
|
|
|
|
|
|
|
def get_decoder_by_name(name):
|
|
|
|
decoder_class = all_encoders[name][1]
|
|
|
|
return decoder_class()
|
|
|
|
|