tools.win_pg_dump_controller
7:92c88f8fb6c9
Go to Latest
tools.win_pg_dump_controller/win_pg_dump_controller/store_controller.py
.. import D6
4 from datetime import datetime
5 from os.path import exists, join as p_join
6 from os import remove as file_remove
7 from typing import Dict, List
8 from dataclasses import dataclass, asdict
9 from os import stat as f_stat
11 from .error import Error
12 from .config import DBTask
15 class StoreError(Error):
19 class StoreControllerBase(object):
20 def get_filename(self, filename: str) -> str:
21 raise NotImplemented()
24 class IndexItem(object):
25 def __init__(self, controller: StoreControllerBase, time: int, filename: str, epoch: int = 0):
26 self._controller = controller
27 self.filename = filename
33 if self._my_path is None:
34 self._my_path = self._controller.get_filename(self.filename)
38 def set_epoch(self, num_days: int):
40 Устанавливает значение эпохи для элемиента в соответствии с количеством дней в эпохе
42 self.epoch = divmod(self.time, num_days * 86400)[0] # 86400 - секунд в сутках
44 def __str__(self) -> str:
47 def full_desc(self) -> str:
48 return f'{self.filename} [epoch="{self.epoch}" created={self.get_datetime()}]'
50 def get_datetime(self):
51 return datetime.fromtimestamp(self.time)
53 def is_exists(self) -> bool:
54 return exists(self.get_path())
56 def to_dict(self) -> dict:
57 return dict((i, getattr(self, i)) for i in ('filename', 'time', 'epoch'))
60 def from_dict(cls, controller: StoreControllerBase, d: Dict):
62 controller=controller,
67 def new(cls, controller: StoreControllerBase, short_filename: str):
69 time_prefix = time.strftime('%Y-%m-%d_%H-%M-%S')
70 filename = f'{time_prefix} - {short_filename}'
73 controller=controller,
74 time=int(time.timestamp()),
80 class TaskStatus(object):
86 class StoreController(StoreControllerBase):
87 def __init__(self, task: DBTask):
89 self.index_name = self.get_filename(f'{task.name}.index')
90 self.status_name = self.get_filename(f'{task.name}.status')
91 self.idx: Dict[int, IndexItem] = {}
92 self.op_adv_status = []
94 if exists(self.index_name):
97 def get_filename(self, filename: str) -> str:
98 return str(p_join(self.task.dst_dir, filename))
100 def load_index(self) -> None:
101 with open(self.index_name, 'r') as IN:
103 for itm in json.load(IN):
104 itm = IndexItem.from_dict(self, itm)
106 result[itm.time] = itm
110 def set_epoch(self, num_days: int):
111 for i in self.idx.values():
112 i.set_epoch(num_days)
114 def save_index(self) -> None:
115 with open(self.index_name, 'w') as OUT:
116 json.dump(list(map(lambda x: x.to_dict(), self.idx.values())), OUT)
118 def add_op_status(self, msg: str) -> None:
119 self.op_adv_status.append(msg)
121 def new_item(self) -> IndexItem:
122 return IndexItem.new(self, f'{self.task.name}.backup')
124 def add_item(self, item: IndexItem) -> None:
125 if not item.is_exists():
126 raise StoreError(f'Storing to index file not found: {item.get_path()}')
128 if item.time in self.idx and self.idx[item.time].filename != item.filename:
129 if self.idx[item.time].is_exists():
130 file_remove(self.idx[item.time].get_path())
132 self.idx[item.time] = item
134 def remove(self, item: IndexItem) -> None:
135 if item.time in self.idx:
136 del self.idx[item.time]
139 file_remove(item.get_path())
141 def status(self, last_status: bool):
142 res = TaskStatus(status=last_status)
144 for i in self.idx.values():
145 if res.time < i.time:
148 res.size += f_stat(i.get_path()).st_size
150 with open(self.status_name, 'w') as OUT:
151 json.dump(asdict(res), OUT)
154 for i in sorted(self.idx, reverse=True):
157 def clean(self, tier1_days: int, tier2_store_days: int, epoch_days: int) -> List[str]:
162 self.set_epoch(epoch_days)
165 if not item.is_exists():
166 to_remove.append(item)
169 storing_days = (now - item.get_datetime()).days
171 if not storing_days <= tier1_days:
172 if storing_days > tier2_store_days:
173 to_remove.append(item)
176 tier2_storing_days = storing_days - tier1_days
178 self.add_op_status(f'"{item.full_desc()}": storing_days={storing_days}'
179 f' tier2_storing_days={tier2_storing_days}')
181 if item.epoch in tier2_idx:
182 to_remove.append(tier2_idx[item.epoch])
184 tier2_idx[item.epoch] = item
187 for item in to_remove:
188 file_remove(item.get_path())
189 result.append(item.filename)