感谢朋友支持本博客,欢迎共同探讨交流,由于能力和时间有限,错误之处在所难免,欢迎指正!
如果转载,请保留作者信息。
博客地址:http://blog.csdn.net/gaoxingnengjisuan
邮箱地址:[email protected]
PS:最近没有登录博客,很多朋友的留言没有看见,这里道歉!还有就是本人较少上QQ,可以邮件交流。
def object_audit(self, location): """ Audits the given object location. 对partition进行一些检查 如果有问题抛出相应的异常; 如果抛AuditException这样的异常,说明partition出现问题,需要隔离,然后同步; 检查文件的完整性,该方法封装了obj server的DiskFile类; 该类有一个_handle_close_quarantine方法,用来检测文件是否需要被隔离; 如果发现损坏,则直接将文件移动到隔离目录下; 1 对于location确定的对象数据进行检测,来判断文件是否损坏,检测方法包括: 检测文件长度和读取文件长度值是否相同,以及通过检测etag值是否相同; 2 在文件损坏的情况下,设置损坏对象文件的哈希值为空; 3 移动损坏对象文件到隔离区域; """ def raise_dfq(msg): raise DiskFileQuarantined(msg) try: # 管理磁盘上的object文件类; # 用来初始化object,其中包括了一切对于一个object的操作; # get_diskfile_from_audit_location:获取磁盘文件的具体路径; # 获取由audit_location =(path, device, partition)所确定的具体路径; # 应该就是指定对象的具体路径; df = self.diskfile_mgr.get_diskfile_from_audit_location(location) with df.open(): # 获取对象元数据字典; metadata = df.get_metadata() # 获取对象的大小; obj_size = int(metadata['Content-Length']) if self.stats_sizes: self.record_stats(obj_size) # 对象数据没有被损坏; if self.zero_byte_only_at_fps and obj_size: self.passes += 1 return # df.reader方法在后面for循环中会调用类class DiskFileReader下的方法__iter__, # 在这个方法中会进一步调用方法close,而在close方法中会实现以下步骤: # 通过检测文件长度和读取文件长度值是否相同,以及通过检测etag值是否相同, # 来判断文件是否损坏,是否需要被隔离; # 在文件损坏的情况下,设置损坏对象文件的哈希值为空; # 并移动损坏对象文件到隔离区域,以便后续通过复制操作实现损坏文件的恢复; # 关闭打开的文件fp; reader = df.reader(_quarantine_hook=raise_dfq) with closing(reader): for chunk in reader: chunk_len = len(chunk) self.bytes_running_time = ratelimit_sleep( self.bytes_running_time, self.max_bytes_per_second, incr_by=chunk_len) self.bytes_processed += chunk_len self.total_bytes_processed += chunk_len except DiskFileNotExist: return except DiskFileQuarantined as err: self.quarantines += 1 self.logger.error(_('ERROR Object %(obj)s failed audit and was' ' quarantined: %(err)s'), {'obj': location, 'err': err}) self.passes += 11.调用方法get_diskfile_from_audit_location获取指定对象的具体路径;
def reader(self, keep_cache=False, _quarantine_hook=lambda m: None): dr = DiskFileReader( self._fp, self._data_file, int(self._metadata['Content-Length']), self._metadata['ETag'], self._threadpool, self._disk_chunk_size, self._mgr.keep_cache_size, self._device_path, self._logger, quarantine_hook=_quarantine_hook, keep_cache=keep_cache) self._fp = None return dr
def __iter__(self): """Returns an iterator over the data file.""" try: ...... finally: # 这里的close方法: # 通过检测文件长度和读取文件长度值是否相同,以及通过检测etag值是否相同, # 来判断文件是否损坏,是否需要被隔离; # 在文件损坏的情况下,设置损坏对象文件的哈希值为空; # 并移动损坏对象文件到隔离区域,以便后续通过复制操作实现损坏文件的恢复; # 关闭打开的文件fp; if not self._suppress_file_closing: self.close()
def close(self): """ Close the open file handle if present. For this specific implementation, this method will handle quarantining the file if necessary. 通过检测文件长度和读取文件长度值是否相同,以及通过检测etag值是否相同, 来判断文件是否损坏,是否需要被隔离; 在文件损坏的情况下,设置损坏对象文件的哈希值为空; 并移动损坏对象文件到隔离区域,以便后续通过复制操作实现损坏文件的恢复; 关闭打开的文件fp; """ if self._fp: # 通过检测文件长度和读取文件长度值是否相同,以及通过检测etag值是否相同, # 来判断文件是否损坏,是否需要被隔离; # 在文件损坏的情况下,设置损坏对象文件的哈希值为空; # 并移动损坏对象文件到隔离区域,以便后续通过复制操作实现损坏文件的恢复; try: if self._started_at_0 and self._read_to_eof: self._handle_close_quarantine() except DiskFileQuarantined: raise except (Exception, Timeout) as e: self._logger.error(_( 'ERROR DiskFile %(data_file)s' ' close failure: %(exc)s : %(stack)s'), {'exc': e, 'stack': ''.join(traceback.format_stack()), 'data_file': self._data_file}) finally: fp, self._fp = self._fp, None fp.close()
def _handle_close_quarantine(self): """ Check if file needs to be quarantined 通过检测文件长度和读取文件长度值是否相同,以及通过检测etag值是否相同, 来判断文件是否损坏,是否需要被隔离; 在文件损坏的情况下,设置损坏对象文件的哈希值为空; 并移动损坏对象文件到隔离区域,以便后续通过复制操作实现损坏文件的恢复; """ # 如果文件的长度和读取文件长度不相同,则为_quarantine方法传入的是读取的长度不匹配; # 如果etag不相同,则为_quarantine方法传入的是md5值不匹配; if self._bytes_read != self._obj_size: self._quarantine( "Bytes read: %s, does not match metadata: %s" % ( self._bytes_read, self._obj_size)) elif self._iter_etag and self._etag != self._iter_etag.hexdigest(): self._quarantine( "ETag %s and file's md5 %s do not match" % ( self._etag, self._iter_etag.hexdigest()))
def _quarantine(self, msg): """ 在文件损坏的情况下,设置损坏对象文件的哈希值为空; 并移动损坏对象文件到隔离区域,以便后续通过复制操作实现损坏文件的恢复; """ # 在文件损坏的情况下,设置损坏对象文件的哈希值为空; # 并移动损坏对象文件到隔离区域,以便后续通过复制操作实现损坏文件的恢复; self._quarantined_dir = self._threadpool.run_in_thread( quarantine_renamer, self._device_path, self._data_file) self._logger.warn("Quarantined object %s: %s" % (self._data_file, msg)) self._logger.increment('quarantines') self._quarantine_hook(msg)
def quarantine_renamer(device_path, corrupted_file_path): """ 在文件损坏的情况下,设置损坏对象文件的哈希值为空; 并移动损坏对象文件到隔离区域,以便后续通过复制操作实现损坏文件的恢复; """ # 损坏文件的路径; from_dir = dirname(corrupted_file_path) # 文件隔离区域的路径; to_dir = join(device_path, 'quarantined', 'objects', basename(from_dir)) # 设置损坏对象文件的哈希值为空; invalidate_hash(dirname(from_dir)) # 实现复制损坏对象文件到隔离区域; try: renamer(from_dir, to_dir) except OSError as e: if e.errno not in (errno.EEXIST, errno.ENOTEMPTY): raise to_dir = "%s-%s" % (to_dir, uuid.uuid4().hex) renamer(from_dir, to_dir) return to_dir
def invalidate_hash(suffix_dir): """ Invalidates the hash for a suffix_dir in the partition's hashes file. 设置suffix_dir的哈希值为空; """ suffix = basename(suffix_dir) partition_dir = dirname(suffix_dir) hashes_file = join(partition_dir, HASH_FILE) with lock_path(partition_dir): try: with open(hashes_file, 'rb') as fp: hashes = pickle.load(fp) if suffix in hashes and not hashes[suffix]: return except Exception: return hashes[suffix] = None write_pickle(hashes, hashes_file, partition_dir, PICKLE_PROTOCOL)
def renamer(old, new): """ 实现复制损坏对象文件到隔离区域; """ try: mkdirs(os.path.dirname(new)) os.rename(old, new) except OSError: mkdirs(os.path.dirname(new)) os.rename(old, new)