From 45e7b53b013999e4cc2f72c080651cc2ece5a346 Mon Sep 17 00:00:00 2001 From: Ludovic Pouzenc Date: Sun, 28 Jun 2015 01:05:47 +0200 Subject: RAID 5 layout implementation (left/right (as)symmetric and RAID 0 impl. --- myraid.py | 122 ++++++++++++++++++++++++++++++++++++++------------------- raidguessfs.py | 14 ++++--- 2 files changed, 91 insertions(+), 45 deletions(-) diff --git a/myraid.py b/myraid.py index 5b44fc4..3706c36 100644 --- a/myraid.py +++ b/myraid.py @@ -22,6 +22,8 @@ import logging, numpy class MyRaid(): """Auxiliary class, managing RAID layer""" + RAID_TYPES = [ '0', '1', '5', '5+0' ] + RAID5_LAYOUTS = [ 'la', 'ra', 'ls', 'rs' ] def __init__(self, *args, **kwargs): self.disks = [] @@ -31,7 +33,7 @@ class MyRaid(): self.raid_chunk_size = 65536 self.raid_disk_order = [] self.raid_disk_count = 0 - self.raid_types = [ '0', '1', '5', '5+0' ] + self.raid_layout = 'ls' def get_raid_start(self): return self.raid_start @@ -48,6 +50,9 @@ class MyRaid(): def get_raid_disk_order_str(self): return ' '.join(map(str,self.raid_disk_order)) + def get_raid_layout(self): + return self.raid_layout + def set_disks(self, disks): self.disks = disks @@ -79,6 +84,12 @@ class MyRaid(): self.raid_disk_order = new_raid_disk_order self.raid_disk_count = len(new_raid_disk_order) + def set_raid_layout(self, new_raid_layout): + if new_raid_layout in MyRaid.RAID5_LAYOUTS: + self.raid_layout = new_raid_layout + else: + raise ValueError('raid_layout has to be one of %s'%' '.join(RAID_LAYOUTS)) + def sizeof_raid_result(self, raid_type): size = self.raid_end - self.raid_start if size <= 0 : @@ -86,14 +97,11 @@ class MyRaid(): else: return { '0' : size * self.raid_disk_count, - '1' : size, + '1' : size if self.raid_disk_count == 2 else 0, '5' : size * (self.raid_disk_count - 1) if self.raid_disk_count >= 3 else 0, '5+0': size * (self.raid_disk_count - 2) if self.raid_disk_count >= 6 and self.raid_disk_count % 2 == 0 else 0, }[raid_type] - def sizeof_disk_parity(self, raid_type): - return self.sizeof_disk_xor(raid_type) / self.raid_sector_size * 16 - def sizeof_disk_xor(self, raid_type): size = self.raid_end - self.raid_start if size <= 0: @@ -101,16 +109,20 @@ class MyRaid(): else: return { '0' : 0, # TODO Could contain some plain text error message - '1' : size, + '1' : size if self.raid_disk_count == 2 else 0, '5' : size if self.raid_disk_count >= 3 else 0, '5+0': size if self.raid_disk_count >= 6 and self.raid_disk_count % 2 == 0 else 0, }[raid_type] + def sizeof_disk_parity(self, raid_type): + return self.sizeof_disk_xor(raid_type) / self.raid_sector_size * 16 + def xor_blocks(self,fd_list, offset, size): - """TODO""" + """Compute bitwise XOR against a bunch of disks slice""" logging.info("Enter xor_blocks(fd_list,%d,%d)"%(offset, size)) - assert(size % 8 == 0), "Size must be multiple of 8" + if size % 8 != 0: + raise ValueError('xor_blocks : size must be multiple of 8') dt = numpy.dtype('= par_disk: + data_disk = data_disk + 1 + + off_disk = self.raid_start + stripe_no * self.raid_chunk_size + segment_off + size2 = min(size, (segment_no+1) * self.raid_chunk_size - offset) + + logging.info("raid.read_result(%s): offset=%d,segment_no=%d,segment_off=%d,stripe_no=%d,par_disk=%d,data_disk=%d,off_disk=%d,size2=%d,segment_off+size2=%d" + % (raid_type,offset,segment_no,segment_off,stripe_no,par_disk,data_disk,off_disk,size2,segment_off+size2) ) + + #TODO recorver from parity if damaged sectors in data_disk data_fd = raid_disks[data_disk] data_fd.seek(off_disk) data = data_fd.read(size2) - + # This kills performance but don't make short reads before EOF - #if size2 < size: + #if size2 > 0 and size2 < size: # data += self.read_result(self,raid_type,offset+size2,size-size2) return data diff --git a/raidguessfs.py b/raidguessfs.py index fba2187..807a2be 100755 --- a/raidguessfs.py +++ b/raidguessfs.py @@ -62,30 +62,33 @@ class RaidGuessFS(fuse.Fuse): self.settings = [ 'disk_count', 'raid_start', 'raid_end', 'raid_chunk_size', 'raid_disk_order', + 'raid_layout', 'bmp_height', 'bmp_width', 'bmp_start_offset' ] self.settings_getters = [ self.d.get_disk_count, self.raid.get_raid_start, self.raid.get_raid_end, self.raid.get_raid_chunk_size, self.raid.get_raid_disk_order_str, + self.raid.get_raid_layout, self.bmp.get_bmp_height, self.bmp.get_bmp_width, self.bmp.get_bmp_start_offset ] self.settings_updaters = [ self.update_disk_count, self.update_raid_start, self.update_raid_end, self.update_raid_chunk_size, self.update_raid_disk_order, + self.raid.set_raid_layout, self.update_bmp_height, self.update_bmp_width, self.update_bmp_start_offset ] self.dentries = { '/' : [ fuse.Direntry(name) for name in ['config','disk','raid','visual'] ], '/config': [ fuse.Direntry(name) for name in self.settings ], - '/raid' : [ fuse.Direntry(name) for name in self.raid.raid_types ], + '/raid' : [ fuse.Direntry(name) for name in myraid.MyRaid.RAID_TYPES ], '/disk' : [ ], # Filled in _refresh_disk_dentries() '/visual': [ ], # Filled in _refresh_disk_dentries() } - for raid_type in self.raid.raid_types: + for raid_type in myraid.MyRaid.RAID_TYPES: self.dentries.update( { '/raid/%s'%raid_type: [ fuse.Direntry(name) for name in ['disk_parity','disk_xor','raid_result'] ], } @@ -116,7 +119,7 @@ class RaidGuessFS(fuse.Fuse): """Update the raid computed attributes after a config change""" logging.debug("Enter _refresh_raid_fattr()") - for raid_type in self.raid.raid_types: + for raid_type in myraid.MyRaid.RAID_TYPES: self.fattr['/raid/%s/disk_parity'%raid_type].st_size = self.raid.sizeof_disk_parity(raid_type) self.fattr['/raid/%s/disk_xor' %raid_type].st_size = self.raid.sizeof_disk_xor (raid_type) self.fattr['/raid/%s/raid_result'%raid_type].st_size = self.raid.sizeof_raid_result(raid_type) @@ -133,6 +136,7 @@ class RaidGuessFS(fuse.Fuse): def update_disk_count(self,arg): i = int(arg) + #TODO : raise exception instead of using assertions assert (i > 0), "Negative value make no sense here" self.d.set_disk_count(i) self.d.open_disks() @@ -214,7 +218,7 @@ class RaidGuessFS(fuse.Fuse): self.fattr = { '/config/%s'%s: self.st.make_fake_file(64,0666) for s in self.settings } - for raid_type in self.raid.raid_types: + for raid_type in myraid.MyRaid.RAID_TYPES: self.fattr.update( { '/raid/%s/disk_parity'%raid_type: self.st.make_fake_file(0), '/raid/%s/disk_xor'%raid_type: self.st.make_fake_file(0), @@ -285,7 +289,7 @@ class RaidGuessFS(fuse.Fuse): if path_chuncks[0] == 'raid': raid_type=path_chuncks[2] - if raid_type in self.raid.raid_types: + if raid_type in myraid.MyRaid.RAID_TYPES: if path_chuncks[4] == 'disk_parity': return self.raid.read_disk_parity(raid_type,offset,size) if path_chuncks[4] == 'disk_xor': -- cgit v1.2.3