def _can_disk_snapshot_storage_merge(
            self, node: tree.StorageNode) -> (bool, int):
        if node.is_root and len(node.children) > 1:
            return False, 0  # 不支持:此时如果合并,那么快照树会分裂为两棵树

        if node.is_leaf:
            return False, 0  # 不支持:当前节点为叶子,应该走删除逻辑,而非回收逻辑

        storage_obj = node.storage
        if storage_obj.status != m.SnapshotStorage.STATUS_RECYCLING:
            return False, 0

        parent_storage_obj = self._get_parent_storage_obj_by_node(node)
        if parent_storage_obj and parent_storage_obj in (
                m.SnapshotStorage.STATUS_CREATING,
                m.SnapshotStorage.STATUS_WRITING,
                m.SnapshotStorage.STATUS_HASHING,
                m.SnapshotStorage.STATUS_ABNORMAL):
            return False, 0  # 不支持:父快照存储正在生成中

        if rt.PathInMount.is_in_not_mount(storage_obj.image_path):
            return False

        if storage_obj.is_cdp:
            if node.is_root:
                return False, 0  # 不支持:如果cdp在根节点中
            if self._is_child_depend_with_timestamp(node):
                return False, 0  # 不支持:cdp文件的中间有依赖的情况
            if srm.get_srm().is_storage_writing(parent_storage_obj.image_path):
                return False, 0  # 不支持:父快照存储正在写入中
            """可回收"""
            return True, self.TYPE_CDP

        # else is_qcow
        if node.storage.file_level_deduplication:
            return False, 0  # 不支持:带有文件级去重

        if self._is_children_in_other_file(node):
            if node.is_root:
                return False, 0  # 不支持:如果该节点为根节点
            if parent_storage_obj and parent_storage_obj.is_cdp:
                return False, 0  # 不支持:父快照是CDP文件
            if parent_storage_obj.disk_bytes != node.storage.disk_bytes:
                return False, 0  # 不支持:父快照是CDP文件
            if self._is_multi_snapshot_in_the_qcow(node):
                return False, 0  # 不支持:有其他快照点在该qcow文件中
            if srm.get_srm().is_storage_writing(parent_storage_obj.image_path):
                return False, 0  # 不支持:父快照存储正在写入中
            """可回收"""
            return True, self.TYPE_QCOW_MOVE_DATA

        # else not is_children_in_other_file
        if srm.get_srm().is_storage_writing(node.storage.image_path):
            return False, 0  # 不支持:快照存储所在文件正在写入中
        """可回收"""
        return True, self.TYPE_QCOW_REMOVE
Exemple #2
0
    def _query_parent_storage_and_chain(
            self) -> (storage.Storage, chain.StorageChainForRW, str):
        if self.is_root_node:
            parent_storage = None
            tree_ident = self._query_tree_ident_from_children()
            depend_nodes = list()
        else:
            parent_storage = self._query_parent_storage()
            tree_ident = parent_storage.tree_ident
            storage_tree = tree.generate(tree_ident)
            depend_nodes = storage_tree.fetch_nodes_to_root(self.parent_ident)

        rw_chain = chain.StorageChainForRW(srm.get_srm(), self.caller_name,
                                           self.parent_timestamp)
        for node in depend_nodes:
            if node.storage.status == m.SnapshotStorage.STATUS_CREATING:
                raise exc.generate_exception_and_logger(
                    r'快照存储链无效,存在创建中的快照存储',
                    f'invalid storage chain, {node.storage}', 0)
            if node.storage.status == m.SnapshotStorage.STATUS_ABNORMAL:
                raise exc.generate_exception_and_logger(
                    r'快照存储链无效,存在异常的快照存储',
                    f'invalid storage chain, {node.storage}', 0)
            rw_chain.insert_tail(node.storage)

        return parent_storage, rw_chain, tree_ident
 def __init__(self, storage_obj: m.SnapshotStorage, call_name: str):
     super(DeleteWork, self).__init__()
     assert storage_obj.status in (
         m.SnapshotStorage.STATUS_RECYCLING,
         m.SnapshotStorage.STATUS_ABNORMAL,
     )
     self.duplicated = False
     self.w_chain = chain.StorageChainForWrite(
         srm.get_srm(), call_name).insert_tail(storage_obj)
 def _create_write_chain(self, storage_tree,
                         call_name) -> chain.StorageChainForWrite:
     write_chain = chain.StorageChainForWrite(srm.get_srm(), call_name)
     depend_nodes = storage_tree.fetch_nodes_to_root(
         self.parent_storage.ident)
     for node in depend_nodes:
         write_chain.insert_tail(node.storage)
     write_chain.insert_tail(self.new_storage.storage_obj)
     return write_chain
Exemple #5
0
    def execute(self) -> pool.Handle:
        """
        1. 更新数据库记录,新建立的存储对象指向父节点
            * 父快照为qcow类型文件时,支持父快照还在日志表中 CreateInJournal;
              也就是,创建文件的时序与日志的时序不一致
              需要在日志表中记录当前节点,支持创建父快照时,调整当前节点的父
            * 其余情况,其父快照必须已经在存储对象表中
        2. 调用底层模块创建存储文件
            * 如果创建突然中断,那么数据库记录会保持为 Creating 状态,下次启动时进行状态修正
            * 如果创建失败,那么标记为 Abnormal 状态,后台回收线程异步进行状态修正
        3. 更新数据库记录,将建立的存储对象标记为 Writing 状态

        :remark:
        1. 仅仅支持单次的创建时序与依赖关系顺序不一致
            也就是不支持依赖链上有超过一个 CreateInJournal 类型的节点,且这些节点在未来某个时刻会真实创建;
            上层逻辑应杜绝出现此类状况
            参考 CreateQcowStorage
        """
        handle: pool.Handle = pool.generate_handle(self._handle, True,
                                                   self.raw_flag)
        new_snapshot: storage.Storage = None
        try:
            with deal_handle_when_excption(handle):
                with lm.get_journal_locker(
                        self.trace_msg), lm.get_storage_locker(
                            self.trace_msg), s.transaction():
                    parent_storage = self._query_parent_storage()
                    new_snapshot = self._create_new_storage(parent_storage)
                    handle.storage_chain = (chain.StorageChainForWrite(
                        srm.get_srm(), self.caller_name).insert_tail(
                            new_snapshot.storage_obj).acquire())

                with handle.locker:
                    handle.raw_handle, handle.ice_endpoint = (
                        action.DiskSnapshotAction.create_cdp_snapshot(
                            handle.storage_chain.last_storage_item,
                            handle.raw_flag))

                with lm.get_storage_locker(self.trace_msg), s.transaction():
                    new_snapshot.update_status(
                        m.SnapshotStorage.STATUS_WRITING)

                return handle
        except Exception as e:
            self._set_storage_abnormal_when_except(new_snapshot)
            raise e
Exemple #6
0
    def generate_qcow(parent_storage_obj: m.SnapshotStorage, folder,
                      new_disk_bytes):
        if parent_storage_obj is None:
            return ImagePathGenerator.generate_new_qcow(folder)
        """
        需要创建新的文件的情况
        1. 如果与父的disk_bytes不同,
        2. 如果与父的存储目录路径不同,
        3. 如果父文件不是qcow,
        4. 如果父文件正在创建或写入中,

        其他情况
        1. 复用父快照文件 
        """
        if (new_disk_bytes != parent_storage_obj.disk_bytes
                or parent_storage_obj.type != m.SnapshotStorage.TYPE_QCOW
                or folder != os.path.split(parent_storage_obj.image_path)[0]
                or srm.get_srm().is_storage_writing(
                    parent_storage_obj.image_path)):
            return ImagePathGenerator.generate_new_qcow(folder)
        else:
            return parent_storage_obj.image_path
    def _can_disk_snapshot_storage_delete(node: tree.StorageNode) -> bool:
        storage_obj: m.SnapshotStorage = node.storage

        if storage_obj.status != m.SnapshotStorage.STATUS_RECYCLING:
            return False

        ref_manager = srm.get_srm()

        if ref_manager.is_storage_using(storage_obj.ident):
            return False

        if rt.PathInMount.is_in_not_mount(storage_obj.image_path):
            return False

        if storage_obj.is_qcow and ref_manager.is_storage_writing(
                storage_obj.image_path):
            return False

        for child_node in node.children:
            if child_node.storage_obj.storage_status != m.SnapshotStorage.STATUS_RECYCLING:
                return False

        return True
Exemple #8
0
 def _generate_chain(self, depend_nodes):
     r_chain = chain.StorageChainForRead(srm.get_srm(), self.caller_name,
                                         self.timestamp)
     for node in depend_nodes:
         r_chain.insert_tail(node.storage)
     return r_chain
 def __init__(self, storage_obj: m.SnapshotStorage, call_name: str):
     call_name += f' DeleteQcowSnapshotWork {storage_obj.ident}'
     super(DeleteQcowSnapshotWork, self).__init__(storage_obj, call_name)
     assert storage_obj.is_qcow
     assert not srm.get_srm().is_storage_writing(storage_obj.image_path)