重构文件结构
This commit is contained in:
@@ -10,7 +10,7 @@ import asyncio
|
||||
from typing import List, Union
|
||||
from .tree_object import TreeObject
|
||||
from .blob_object import BlobObject
|
||||
from utils.log import Logger
|
||||
from ThousandHands.utils.log import Logger
|
||||
|
||||
logger = Logger("BackupObject")
|
||||
|
||||
@@ -19,16 +19,14 @@ class BackupObject:
|
||||
"""
|
||||
备份对象,负责管理存储对象(tree、blob)对象、备份信息、恢复等操作
|
||||
"""
|
||||
|
||||
backup_name: str
|
||||
backup_time_lately: str
|
||||
backup_time_create: str
|
||||
backup_size: int
|
||||
backup_version_number: int
|
||||
backup_trees: List[Union[TreeObject, BlobObject]] = []
|
||||
new_backup_flag: bool
|
||||
|
||||
def __init__(self, backup_name: str, backup_base_path: str):
|
||||
def __init__(self, backup_name: str, backup_base_path: str, backup_dirs: List[str] = []):
|
||||
self.backup_name = backup_name
|
||||
|
||||
# 获取备份路径的绝对路径
|
||||
@@ -39,18 +37,18 @@ class BackupObject:
|
||||
os.path.abspath(backup_base_path), backup_name
|
||||
)
|
||||
|
||||
logger.debug(f"Backup path: {self.backup_path}")
|
||||
logger.debug(f"new backup object,Backup path: {self.backup_path}")
|
||||
|
||||
if not os.path.exists(self.backup_path):
|
||||
self.new_backup_flag = True
|
||||
else:
|
||||
self.new_backup_flag = False
|
||||
pass # TODO 读取备份信息
|
||||
if backup_dirs != []:
|
||||
logger.info("load existing backups")
|
||||
self.addBackup(backup_dirs)
|
||||
|
||||
|
||||
def createNewBackup(self, backup_dirs: List[str]):
|
||||
def addBackup(self, backup_dirs: List[str]):
|
||||
"""
|
||||
创建新的备份
|
||||
|
||||
:param backup_dirs: 备份目录列表
|
||||
:return
|
||||
"""
|
||||
for backup_dir in backup_dirs:
|
||||
@@ -62,19 +60,23 @@ class BackupObject:
|
||||
logger.info("New backup created successfully.")
|
||||
logger.debug(f"Backup trees: {self.backup_trees}")
|
||||
|
||||
def backup(self):
|
||||
asyncio.run(self.__writeBlobs())
|
||||
|
||||
async def __writeBlobs(self):
|
||||
async def __writeTree(self):
|
||||
"""
|
||||
写入所有对象到备份路径
|
||||
"""
|
||||
obj_save_path = os.path.join(self.backup_path, "objects")
|
||||
for obj in self.backup_trees:
|
||||
if isinstance(obj, TreeObject):
|
||||
await obj.writeBlobs(obj_save_path) # 如果是TreeObject,则调用writeBlobs方法
|
||||
await obj.writeTree(
|
||||
obj_save_path
|
||||
) # 如果是TreeObject,则调用writeTree方法
|
||||
else:
|
||||
await obj.writeBlob(obj_save_path) # 如果是BlobObject,则调用writeBlob方法
|
||||
await obj.writeBlob(
|
||||
obj_save_path
|
||||
) # 如果是BlobObject,则调用writeBlob方法
|
||||
|
||||
def backup(self):
|
||||
asyncio.run(self.__writeTree())
|
||||
|
||||
def recover(self, recover_path: str):
|
||||
"""
|
||||
@@ -91,3 +93,11 @@ class BackupObject:
|
||||
:return
|
||||
"""
|
||||
pass
|
||||
|
||||
def writeBackupInfo(self):
|
||||
"""
|
||||
写入备份信息
|
||||
|
||||
:return
|
||||
"""
|
||||
pass
|
||||
@@ -68,8 +68,4 @@ class BlobObject:
|
||||
if not data:
|
||||
break
|
||||
sha1.update(data)
|
||||
return sha1.hexdigest()
|
||||
|
||||
|
||||
def newBlobObject(file_path: str) -> BlobObject:
|
||||
return BlobObject(file_path)
|
||||
return sha1.hexdigest()
|
||||
@@ -26,7 +26,7 @@ class TreeObject:
|
||||
self.__children.append(blob)
|
||||
self.__file_map[blob_path] = blob.object_id
|
||||
|
||||
async def writeBlobs(self, base_path: str):
|
||||
async def writeTree(self, base_path: str):
|
||||
tasks = []
|
||||
for child in self.__children:
|
||||
tasks.append(asyncio.create_task(child.writeBlob(base_path)))
|
||||
21
ThousandHands/core/plan/PlanBackup.py
Normal file
21
ThousandHands/core/plan/PlanBackup.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from typing import List
|
||||
from .PlanBase import PlanBase
|
||||
from ThousandHands.core.objects.backup_object import BackupObject
|
||||
|
||||
|
||||
class PlanBackup(PlanBase):
|
||||
"""
|
||||
备份计划,负责管理存储对象的备份
|
||||
"""
|
||||
|
||||
__backup_object: BackupObject
|
||||
|
||||
def __init__(
|
||||
self, backup_name: str, backup_base_path: str, backup_dirs: List[str] = []
|
||||
):
|
||||
super().__init__()
|
||||
self.__backup_object = BackupObject(backup_name, backup_base_path, backup_dirs)
|
||||
self.name = backup_name
|
||||
|
||||
def execute(self):
|
||||
self.__backup_object.backup()
|
||||
31
ThousandHands/core/plan/PlanBase.py
Normal file
31
ThousandHands/core/plan/PlanBase.py
Normal file
@@ -0,0 +1,31 @@
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
|
||||
class PlanBase(ABC):
|
||||
__priority_factor: int # 优先级因子
|
||||
__executed: bool
|
||||
__time_hour: int
|
||||
__time_minute: int
|
||||
|
||||
name: str
|
||||
|
||||
def __init__(self):
|
||||
self.__priority_factor = 0
|
||||
self.name = ""
|
||||
|
||||
@abstractmethod
|
||||
def execute(self):
|
||||
pass
|
||||
|
||||
def getPriorityFactor(self) -> int:
|
||||
"""
|
||||
获取优先级因子
|
||||
"""
|
||||
return self.__priority_factor
|
||||
|
||||
def getNextTime(self) -> int:
|
||||
# TODO: 实现计划执行
|
||||
return 0
|
||||
|
||||
def isExecuted(self) -> bool:
|
||||
return self.__executed
|
||||
4
ThousandHands/core/plan/TimeHandler.py
Normal file
4
ThousandHands/core/plan/TimeHandler.py
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
class TimeHandler(object):
|
||||
pass
|
||||
|
||||
44
ThousandHands/core/scheduler/scheduler.py
Normal file
44
ThousandHands/core/scheduler/scheduler.py
Normal file
@@ -0,0 +1,44 @@
|
||||
from typing import Dict
|
||||
from ThousandHands.core.plan.PlanBase import PlanBase
|
||||
import sched
|
||||
import time
|
||||
import concurrent.futures
|
||||
|
||||
|
||||
class Scheduler:
|
||||
__plans: Dict[str, sched.Event]
|
||||
__scheduler: sched.scheduler
|
||||
__executor: concurrent.futures.ThreadPoolExecutor
|
||||
|
||||
def __init__(self):
|
||||
self.__plans = {}
|
||||
self.__scheduler = sched.scheduler(time.time, time.sleep)
|
||||
self.__executor = concurrent.futures.ThreadPoolExecutor(max_workers=3)
|
||||
|
||||
def add_plan(self, plan: PlanBase) -> None:
|
||||
if plan.name in self.__plans:
|
||||
raise ValueError("Plan already exists")
|
||||
|
||||
event = self.__scheduler.enter(
|
||||
plan.getNextTime(), plan.getPriorityFactor(), self.__execute_plan, (plan,)
|
||||
)
|
||||
|
||||
self.__plans[plan.name] = event
|
||||
|
||||
def remove_plan(self, plan_name: str) -> None:
|
||||
if plan_name in self.__plans:
|
||||
del self.__plans[plan_name]
|
||||
|
||||
raise ValueError("Plan name not found")
|
||||
|
||||
def run(self):
|
||||
self.__scheduler.run()
|
||||
|
||||
def stop(self):
|
||||
self.__executor.shutdown(wait=True)
|
||||
|
||||
def __execute_plan(self, plan: PlanBase):
|
||||
"""
|
||||
执行计划,并在执行后重新安排(如果需要)
|
||||
"""
|
||||
self.__executor.submit(plan.execute)
|
||||
@@ -17,8 +17,4 @@ class TargetBase(ABC):
|
||||
:param
|
||||
:return
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def back(self, back_object: BackupObject):
|
||||
pass
|
||||
pass
|
||||
10
ThousandHands/core/target/targetNative.py
Normal file
10
ThousandHands/core/target/targetNative.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from .targetBase import TargetBase
|
||||
|
||||
|
||||
class TargetNative(TargetBase):
|
||||
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
|
||||
def test(self) -> bool:
|
||||
return True
|
||||
@@ -1,11 +0,0 @@
|
||||
class Plan:
|
||||
__priority_factor: float # 优先级因子
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def getPriorityFactor(self) -> float:
|
||||
'''
|
||||
获取优先级因子
|
||||
'''
|
||||
return self.__priority_factor
|
||||
@@ -1,15 +0,0 @@
|
||||
from typing import List
|
||||
from .Plan import Plan
|
||||
|
||||
|
||||
class PlanPriorityMinHeap:
|
||||
"""
|
||||
计划优先小顶堆,按照优先级存储多个计划
|
||||
"""
|
||||
|
||||
plans: List[Plan]
|
||||
def __init__(self):
|
||||
self.plans = []
|
||||
|
||||
def addPlan(self, plan: Plan):
|
||||
pass
|
||||
@@ -1,11 +0,0 @@
|
||||
from typing import Callable
|
||||
|
||||
|
||||
class Timer:
|
||||
def __init__(self, name: str, interval: float, callback: Callable):
|
||||
self.name = name
|
||||
self.interval = interval
|
||||
self.callback = callback
|
||||
|
||||
def start(self):
|
||||
pass
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
from core.objects.backup_object import BackupObject
|
||||
from ThousandHands.core.objects.backup_object import BackupObject
|
||||
import tempfile
|
||||
import os
|
||||
|
||||
@@ -25,7 +25,7 @@ class TestBackup():
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
temp_data_dir = self.createTempDataDir()
|
||||
b = BackupObject("testBackup", tmpdir)
|
||||
b.createNewBackup([temp_data_dir.name])
|
||||
b.addBackup([temp_data_dir.name])
|
||||
b.backup()
|
||||
temp_data_dir.cleanup()
|
||||
assert os.path.exists(b.backup_path+"/objects")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import asyncio
|
||||
from core.objects.blob_object import BlobObject
|
||||
from ThousandHands.core.objects.blob_object import BlobObject
|
||||
import hashlib
|
||||
import tempfile
|
||||
|
||||
|
||||
Reference in New Issue
Block a user