重构文件结构
This commit is contained in:
@@ -10,7 +10,7 @@ import asyncio
|
|||||||
from typing import List, Union
|
from typing import List, Union
|
||||||
from .tree_object import TreeObject
|
from .tree_object import TreeObject
|
||||||
from .blob_object import BlobObject
|
from .blob_object import BlobObject
|
||||||
from utils.log import Logger
|
from ThousandHands.utils.log import Logger
|
||||||
|
|
||||||
logger = Logger("BackupObject")
|
logger = Logger("BackupObject")
|
||||||
|
|
||||||
@@ -19,16 +19,14 @@ class BackupObject:
|
|||||||
"""
|
"""
|
||||||
备份对象,负责管理存储对象(tree、blob)对象、备份信息、恢复等操作
|
备份对象,负责管理存储对象(tree、blob)对象、备份信息、恢复等操作
|
||||||
"""
|
"""
|
||||||
|
|
||||||
backup_name: str
|
backup_name: str
|
||||||
backup_time_lately: str
|
backup_time_lately: str
|
||||||
backup_time_create: str
|
backup_time_create: str
|
||||||
backup_size: int
|
backup_size: int
|
||||||
backup_version_number: int
|
backup_version_number: int
|
||||||
backup_trees: List[Union[TreeObject, BlobObject]] = []
|
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
|
self.backup_name = backup_name
|
||||||
|
|
||||||
# 获取备份路径的绝对路径
|
# 获取备份路径的绝对路径
|
||||||
@@ -39,18 +37,18 @@ class BackupObject:
|
|||||||
os.path.abspath(backup_base_path), backup_name
|
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):
|
if backup_dirs != []:
|
||||||
self.new_backup_flag = True
|
logger.info("load existing backups")
|
||||||
else:
|
self.addBackup(backup_dirs)
|
||||||
self.new_backup_flag = False
|
|
||||||
pass # TODO 读取备份信息
|
|
||||||
|
|
||||||
def createNewBackup(self, backup_dirs: List[str]):
|
|
||||||
|
def addBackup(self, backup_dirs: List[str]):
|
||||||
"""
|
"""
|
||||||
创建新的备份
|
创建新的备份
|
||||||
|
|
||||||
|
:param backup_dirs: 备份目录列表
|
||||||
:return
|
:return
|
||||||
"""
|
"""
|
||||||
for backup_dir in backup_dirs:
|
for backup_dir in backup_dirs:
|
||||||
@@ -62,19 +60,23 @@ class BackupObject:
|
|||||||
logger.info("New backup created successfully.")
|
logger.info("New backup created successfully.")
|
||||||
logger.debug(f"Backup trees: {self.backup_trees}")
|
logger.debug(f"Backup trees: {self.backup_trees}")
|
||||||
|
|
||||||
def backup(self):
|
async def __writeTree(self):
|
||||||
asyncio.run(self.__writeBlobs())
|
|
||||||
|
|
||||||
async def __writeBlobs(self):
|
|
||||||
"""
|
"""
|
||||||
写入所有对象到备份路径
|
写入所有对象到备份路径
|
||||||
"""
|
"""
|
||||||
obj_save_path = os.path.join(self.backup_path, "objects")
|
obj_save_path = os.path.join(self.backup_path, "objects")
|
||||||
for obj in self.backup_trees:
|
for obj in self.backup_trees:
|
||||||
if isinstance(obj, TreeObject):
|
if isinstance(obj, TreeObject):
|
||||||
await obj.writeBlobs(obj_save_path) # 如果是TreeObject,则调用writeBlobs方法
|
await obj.writeTree(
|
||||||
|
obj_save_path
|
||||||
|
) # 如果是TreeObject,则调用writeTree方法
|
||||||
else:
|
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):
|
def recover(self, recover_path: str):
|
||||||
"""
|
"""
|
||||||
@@ -91,3 +93,11 @@ class BackupObject:
|
|||||||
:return
|
:return
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def writeBackupInfo(self):
|
||||||
|
"""
|
||||||
|
写入备份信息
|
||||||
|
|
||||||
|
:return
|
||||||
|
"""
|
||||||
|
pass
|
||||||
@@ -69,7 +69,3 @@ class BlobObject:
|
|||||||
break
|
break
|
||||||
sha1.update(data)
|
sha1.update(data)
|
||||||
return sha1.hexdigest()
|
return sha1.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
def newBlobObject(file_path: str) -> BlobObject:
|
|
||||||
return BlobObject(file_path)
|
|
||||||
@@ -26,7 +26,7 @@ class TreeObject:
|
|||||||
self.__children.append(blob)
|
self.__children.append(blob)
|
||||||
self.__file_map[blob_path] = blob.object_id
|
self.__file_map[blob_path] = blob.object_id
|
||||||
|
|
||||||
async def writeBlobs(self, base_path: str):
|
async def writeTree(self, base_path: str):
|
||||||
tasks = []
|
tasks = []
|
||||||
for child in self.__children:
|
for child in self.__children:
|
||||||
tasks.append(asyncio.create_task(child.writeBlob(base_path)))
|
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)
|
||||||
@@ -18,7 +18,3 @@ class TargetBase(ABC):
|
|||||||
:return
|
:return
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def back(self, back_object: BackupObject):
|
|
||||||
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 tempfile
|
||||||
import os
|
import os
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ class TestBackup():
|
|||||||
with tempfile.TemporaryDirectory() as tmpdir:
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
temp_data_dir = self.createTempDataDir()
|
temp_data_dir = self.createTempDataDir()
|
||||||
b = BackupObject("testBackup", tmpdir)
|
b = BackupObject("testBackup", tmpdir)
|
||||||
b.createNewBackup([temp_data_dir.name])
|
b.addBackup([temp_data_dir.name])
|
||||||
b.backup()
|
b.backup()
|
||||||
temp_data_dir.cleanup()
|
temp_data_dir.cleanup()
|
||||||
assert os.path.exists(b.backup_path+"/objects")
|
assert os.path.exists(b.backup_path+"/objects")
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
from core.objects.blob_object import BlobObject
|
from ThousandHands.core.objects.blob_object import BlobObject
|
||||||
import hashlib
|
import hashlib
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user