class TorrentFile(object): def __init__(self, file_length, pieces_hash_array, piece_size, fs): self.logger = logging.getLogger(__name__) self.pieces_num = file_length / PIECE_SIZE self.piece_list = [] for piece in range(self.pieces_num): self.piece_list.append( Piece(piece, piece_size, fs, pieces_hash_array[piece])) #if have extra smaller pieces if file_length % PIECE_SIZE != 0: last_piece_size = file_length % piece_size self.piece_list.append( Piece(self.pieces_num, last_piece_size, fs, pieces_hash_array[self.pieces_num])) self.pieces_num += 1 self.bm = BitMap(self.pieces_num) self.logger.debug("init bm {}".format(self.bm)) def update_bitmap(self): for i in range(self.pieces_num): if self.piece_list[i].is_complete(): self.bm.set(i) else: self.bm.reset(i) def is_complete(self): # self.update_bitmap() return self.bm.all() ## return the missing pieces def missing_pieces(self): self.update_bitmap() missing_list = [] for i in range(self.pieces_num): if not self.bm.test(i): missing_list.append(self.piece_list[i]) return missing_list def set_piece(self, index, content): self.piece_list[index].set_block(content) self.piece_list[index].write_to_file() def get_info(self): for i in range(self.pieces_num): self.piece_list[i].get_info()
class Piece(object): def __init__(self, piece_index, piece_size, fs, piece_hash): self.block_num = piece_size / BLOCK_SIZE self.block_list = [] self.piece_index = piece_index self.piece_size = piece_size self.piece_hash = piece_hash for block in range(self.block_num): b = Block(piece_index, block, BLOCK_SIZE) self.block_list.append(b) #if have extra smaller blocks if piece_size % BLOCK_SIZE != 0: last_block_size = piece_size % BLOCK_SIZE #print self.block_num,last_block_size self.block_list.append( Block(self.piece_index, self.block_num, last_block_size)) self.block_num += 1 self.bm = BitMap(self.block_num) self.file = fs return def __hash__(self): return hash((self.piece_index, self.piece_size, self.piece_hash)) def __eq__(self, other): return (self.piece_index, self.piece_size, self.piece_hash) == (other.piece_index, self.piece_size, self.piece_hash) def __ne__(self, other): return not (self == other) #check block's bitmap in disk and the whole SHA1 def is_complete(self): #check SHA1 self.file.seek(self.piece_index * PIECE_SIZE) content = self.file.read(self.piece_size) piecehash = hashlib.sha1(content).digest() # print piecehash, self.piece_hash # print self.piece_size return piecehash == self.piece_hash def written_piece_hash(self): self.file.seek(self.piece_index * PIECE_SIZE) content = self.file.read(self.piece_size) piecehash = hashlib.sha1(content).digest() return piecehash def update_bitmap(self): for i in range(len(self.block_list)): if self.block_list[i].is_complete(): self.bm.set(i) else: self.bm.reset(i) def get_info(self): print "piece index:", self.piece_index, " piece size:", self.piece_size #for i in range(self.block_num): # self.block_list[i].get_info() ## set every block def set_block(self, content): size = len(content) for block in self.block_list: #print "boffset",block.block_offset block.set_complete( content[block.block_offset:min(block.block_offset + BLOCK_SIZE, size)]) ## get the content from blocks and write to file def write_to_file(self): self.update_bitmap() if self.bm.all(): payload = bytearray('') for block in self.block_list: payload += block.payload self.file.seek(self.piece_index * PIECE_SIZE) self.file.write(payload) def clear_data(self): for block in self.block_list: block.payload = None def expire(self): for block in self.block_list: block.mark_missing() self.bm = BitMap(self.block_num)
class buddy_malloc: def __init__(self, size, start, headerSize, align): self.level = math.ceil(math.log2(size)) self.size = 1 << self.level print("Total size for buddy: {}".format(self.size)) self.level += 1 self.buckets = [set() for i in range(self.level)] self.in_use = BitMap(2 ** self.level - 1) # initialize root node self.buckets[0].add(start) # misc stuffs self.base = start self.headerSize = headerSize self.align = align self.sizemap = {} def _ptr_to_index(self, ptr, level): return (1 << level) - 1 + ((ptr - self.base) >> (self.level - 1 - level)) def _index_to_ptr(self, index, level): return self.base + ((index - (1 << level) + 1) << (self.level - 1 - level)) def _parent(self, n): return (n - 1) >> 1 def _lchild(self, n): return (n << 1) + 1 def _rchild(self, n): return (n + 1) << 1 def addToMap(self, addr, size): assert(addr not in self.sizemap) self.sizemap[addr] = size def malloc(self, size): if self.align != -1: left = size % self.align if left != 0: diff = self.align - left else: diff = 0 # print 'aligning: adding %d to %d' % (diff, size) size += diff size += self.headerSize dest_level = self.level - 1 - math.ceil(math.log2(size)) level = dest_level while not len(self.buckets[level]) and level >= 0: level -= 1 has_flipped = False if level < 0: return (-1, 0) else: # split curr level while level != dest_level: blk = self.buckets[level].pop() idx = self._ptr_to_index(blk, level) level += 1 self.buckets[level].add(blk) self.buckets[level].add(blk + (1 << (self.level - 1 - level))) addr = self.buckets[level].pop() idx = self._ptr_to_index(addr, level) while idx >= 0: self.in_use.set(idx) idx = self._parent(idx) self.addToMap(addr, 1 << (self.level - 1 - level)) return (addr, 0) def free(self, addr): if addr not in self.sizemap: return -1 level = self.level - 1 - math.ceil(math.log2(self.sizemap[addr])) idx = self._ptr_to_index(addr, level) while idx > 0: parent = self._parent(idx) neighbor = self._rchild(parent) if self._lchild(parent) == idx else self._lchild(parent) self.in_use.reset(idx) if not self.in_use.test(neighbor): # can merge self.buckets[level].remove(self._index_to_ptr(neighbor, level)) else: break level -= 1 idx = parent self.buckets[level].add(self._index_to_ptr(idx, level)) del self.sizemap[addr] return 0 def dump(self): print('Alloc List [ Size %d ]: ' % len(self.sizemap), end='') for item in self.sizemap.items(): print('[ addr:%d sz:%d ]' % item, end='') print('')