tools.win_pg_dump_controller

Yohn Y. 2022-06-13 Parent:a38a008ce3e8 Child:92c88f8fb6c9

5:7de4fb4ef2f5 Go to Latest

tools.win_pg_dump_controller/win_pg_dump_controller/store_controller.py

. Не тот порт по умолчанию для postgres

History
awgur@0 1 # coding: utf-8
awgur@0 2
awgur@0 3 import json
awgur@0 4 from datetime import datetime
awgur@0 5 from os.path import exists, join as p_join, basename
awgur@0 6 from os import remove as file_remove
awgur@0 7 from typing import Dict, List
awgur@0 8
awgur@0 9 from .error import Error
awgur@0 10 from .config import DBTask
awgur@0 11
awgur@0 12
awgur@0 13 class StoreError(Error):
awgur@0 14 pass
awgur@0 15
awgur@0 16
awgur@0 17 class StoreControllerBase(object):
awgur@0 18 def get_filename(self, filename: str) -> str:
awgur@0 19 raise NotImplemented()
awgur@0 20
awgur@0 21
awgur@0 22 class IndexItem(object):
awgur@4 23 def __init__(self, controller: StoreControllerBase, time: int, filename: str, epoch: int = 0):
awgur@0 24 self._controller = controller
awgur@0 25 self.filename = filename
awgur@0 26 self.time = time
awgur@4 27 self.epoch = epoch
awgur@0 28 self._my_path = None
awgur@0 29
awgur@0 30 def get_path(self):
awgur@0 31 if self._my_path is None:
awgur@0 32 self._my_path = self._controller.get_filename(self.filename)
awgur@0 33
awgur@0 34 return self._my_path
awgur@0 35
awgur@4 36 def set_epoch(self, num_days: int):
awgur@4 37 """\
awgur@4 38 Устанавливает значение эпохи для элемиента в соответствии с количеством дней в эпохе
awgur@4 39 """
awgur@4 40 self.epoch = divmod(self.time, num_days * 86400)[0] # 86400 - секунд в сутках
awgur@4 41
awgur@1 42 def __str__(self) -> str:
awgur@1 43 return self.filename
awgur@1 44
awgur@4 45 def full_desc(self) -> str:
awgur@4 46 return f'{self.filename} [epoch="{self.epoch}" created={self.get_datetime()}]'
awgur@4 47
awgur@0 48 def get_datetime(self):
awgur@0 49 return datetime.fromtimestamp(self.time)
awgur@0 50
awgur@0 51 def is_exists(self) -> bool:
awgur@0 52 return exists(self.get_path())
awgur@0 53
awgur@0 54 def to_dict(self) -> dict:
awgur@4 55 return dict((i, getattr(self, i)) for i in ('filename', 'time', 'epoch'))
awgur@0 56
awgur@0 57 @classmethod
awgur@0 58 def from_dict(cls, controller: StoreControllerBase, d: Dict):
awgur@0 59 return cls(
awgur@0 60 controller=controller,
awgur@0 61 **d
awgur@0 62 )
awgur@0 63
awgur@0 64 @classmethod
awgur@0 65 def new(cls, controller: StoreControllerBase, short_filename: str):
awgur@0 66 time = datetime.now()
awgur@0 67 time_prefix = time.strftime('%Y-%m-%d_%H-%M-%S')
awgur@0 68 filename = f'{time_prefix} - {short_filename}'
awgur@0 69
awgur@0 70 return cls(
awgur@0 71 controller=controller,
awgur@0 72 time=int(time.timestamp()),
awgur@0 73 filename=filename
awgur@0 74 )
awgur@0 75
awgur@0 76
awgur@0 77 class StoreController(StoreControllerBase):
awgur@0 78 def __init__(self, task: DBTask):
awgur@0 79 self.task = task
awgur@0 80 self.index_name = self.get_filename(f'{task.name}.index')
awgur@0 81 self.idx: Dict[int, IndexItem] = {}
awgur@1 82 self.op_adv_status = []
awgur@0 83
awgur@0 84 if exists(self.index_name):
awgur@0 85 self.load_index()
awgur@0 86
awgur@0 87 def get_filename(self, filename: str) -> str:
awgur@0 88 return str(p_join(self.task.dst_dir, filename))
awgur@0 89
awgur@0 90 def load_index(self) -> None:
awgur@0 91 with open(self.index_name, 'r') as IN:
awgur@0 92 result = {}
awgur@0 93 for itm in json.load(IN):
awgur@0 94 itm = IndexItem.from_dict(self, itm)
awgur@0 95 if itm.is_exists():
awgur@0 96 result[itm.time] = itm
awgur@0 97
awgur@0 98 self.idx = result
awgur@0 99
awgur@4 100 def set_epoch(self, num_days: int):
awgur@4 101 for i in self.idx.values():
awgur@4 102 i.set_epoch(num_days)
awgur@4 103
awgur@0 104 def save_index(self) -> None:
awgur@0 105 with open(self.index_name, 'w') as OUT:
awgur@0 106 json.dump(list(map(lambda x: x.to_dict(), self.idx.values())), OUT)
awgur@0 107
awgur@1 108 def add_op_status(self, msg: str) -> None:
awgur@1 109 self.op_adv_status.append(msg)
awgur@1 110
awgur@0 111 def new_item(self) -> IndexItem:
awgur@0 112 return IndexItem.new(self, f'{self.task.name}.backup')
awgur@0 113
awgur@0 114 def add_item(self, item: IndexItem) -> None:
awgur@0 115 if not item.is_exists():
awgur@0 116 raise StoreError(f'Storing to index file not found: {item.get_path()}')
awgur@0 117
awgur@0 118 if item.time in self.idx and self.idx[item.time].filename != item.filename:
awgur@0 119 if self.idx[item.time].is_exists():
awgur@0 120 file_remove(self.idx[item.time].get_path())
awgur@0 121
awgur@0 122 self.idx[item.time] = item
awgur@0 123
awgur@0 124 def remove(self, item: IndexItem) -> None:
awgur@0 125 if item.time in self.idx:
awgur@0 126 del self.idx[item.time]
awgur@0 127
awgur@0 128 if item.is_exists():
awgur@0 129 file_remove(item.get_path())
awgur@0 130
awgur@0 131 def __iter__(self):
awgur@1 132 for i in sorted(self.idx, reverse=True):
awgur@0 133 yield self.idx[i]
awgur@0 134
awgur@4 135 def clean(self, tier1_days: int, tier2_store_days: int, epoch_days: int) -> List[str]:
awgur@0 136 to_remove = []
awgur@0 137 tier2_idx = {}
awgur@0 138 now = datetime.now()
awgur@0 139
awgur@4 140 self.set_epoch(epoch_days)
awgur@4 141
awgur@0 142 for item in self:
awgur@0 143 if not item.is_exists():
awgur@0 144 to_remove.append(item)
awgur@0 145
awgur@0 146 else:
awgur@0 147 storing_days = (now - item.get_datetime()).days
awgur@0 148
awgur@0 149 if not storing_days <= tier1_days:
awgur@0 150 if storing_days > tier2_store_days:
awgur@0 151 to_remove.append(item)
awgur@0 152
awgur@0 153 else:
awgur@4 154 tier2_storing_days = storing_days - tier1_days
awgur@0 155
awgur@4 156 self.add_op_status(f'"{item.full_desc()}": storing_days={storing_days}'
awgur@4 157 f' tier2_storing_days={tier2_storing_days}')
awgur@0 158
awgur@4 159 if item.epoch in tier2_idx:
awgur@4 160 to_remove.append(tier2_idx[item.epoch])
awgur@1 161
awgur@4 162 tier2_idx[item.epoch] = item
awgur@0 163
awgur@0 164 result = []
awgur@0 165 for item in to_remove:
awgur@0 166 file_remove(item.get_path())
awgur@0 167 result.append(item.filename)
awgur@0 168
awgur@0 169 return result