| 5 import config |
5 import config |
| 6 import logging |
6 import logging |
| 7 import time |
7 import time |
| 8 import borgend |
8 import borgend |
| 9 import repository |
9 import repository |
| 10 import sleep |
10 import dreamtime |
| 11 from enum import IntEnum |
11 from enum import IntEnum |
| 12 from instance import BorgInstance |
12 from instance import BorgInstance |
| 13 from threading import Thread, Lock, Condition |
13 from threading import Thread, Lock, Condition |
| 14 from scheduler import TerminableThread |
14 from scheduler import TerminableThread |
| 15 |
15 |
| 141 scheduling=config.check_string(cfg, 'scheduling', |
141 scheduling=config.check_string(cfg, 'scheduling', |
| 142 'Scheduling mode', loc, |
142 'Scheduling mode', loc, |
| 143 default="dreamtime") |
143 default="dreamtime") |
| 144 |
144 |
| 145 if scheduling=="dreamtime": |
145 if scheduling=="dreamtime": |
| 146 self.timeclass=sleep.DreamTime |
146 self.timeclass=dreamtime.DreamTime |
| 147 elif scheduling=="realtime": |
147 elif scheduling=="realtime": |
| 148 self.timeclass=sleep.MonotonicTime |
148 self.timeclass=dreamtime.MonotonicTime |
| 149 elif scheduling=="manual": |
149 elif scheduling=="manual": |
| 150 self.backup_interval=0 |
150 self.backup_interval=0 |
| 151 else: |
151 else: |
| 152 logging.error("Invalid time class '%s' for %s" % (scheduling, loc)) |
152 logging.error("Invalid time class '%s' for %s" % (scheduling, loc)) |
| 153 |
153 |
| 170 self.scheduled_operation=None |
170 self.scheduled_operation=None |
| 171 self.lastrun_when=None |
171 self.lastrun_when=None |
| 172 self.lastrun_finished=None |
172 self.lastrun_finished=None |
| 173 self.state=State.INACTIVE |
173 self.state=State.INACTIVE |
| 174 self.errors=Errors.OK |
174 self.errors=Errors.OK |
| 175 self.timeclass=sleep.DreamTime |
175 self.timeclass=dreamtime.DreamTime |
| 176 |
176 |
| 177 self.__decode_config(cfg) |
177 self.__decode_config(cfg) |
| 178 |
178 |
| 179 super().__init__(target = self.__main_thread, name = self.backup_name) |
179 super().__init__(target = self.__main_thread, name = self.backup_name) |
| 180 self.daemon=True |
180 self.daemon=True |
| 298 self.thread_res=t_res |
298 self.thread_res=t_res |
| 299 self.borg_instance=inst |
299 self.borg_instance=inst |
| 300 self.current_operation=op |
300 self.current_operation=op |
| 301 # Update scheduled time to real starting time to schedule |
301 # Update scheduled time to real starting time to schedule |
| 302 # next run relative to this |
302 # next run relative to this |
| 303 self.current_operation.time=sleep.MonotonicTime.now() |
303 self.current_operation.time=dreamtime.MonotonicTime.now() |
| 304 self.state=State.ACTIVE |
304 self.state=State.ACTIVE |
| 305 # Reset error status when starting a new operation |
305 # Reset error status when starting a new operation |
| 306 self.errors=Errors.OK |
306 self.errors=Errors.OK |
| 307 self.__update_status() |
307 self.__update_status() |
| 308 |
308 |
| 470 return Operation(Operation.CREATE, tm, reason='initial') |
470 return Operation(Operation.CREATE, tm, reason='initial') |
| 471 elif not self.errors.ok(): |
471 elif not self.errors.ok(): |
| 472 if self.retry_interval==0: |
472 if self.retry_interval==0: |
| 473 return None |
473 return None |
| 474 else: |
474 else: |
| 475 tm=sleep.MonotonicTime(self.lastrun_finished+self.retry_interval) |
475 tm=dreamtime.MonotonicTime(self.lastrun_finished+self.retry_interval) |
| 476 return Operation(Operation.CREATE, tm, reason='retry') |
476 return Operation(Operation.CREATE, tm, reason='retry') |
| 477 else: |
477 else: |
| 478 if self.backup_interval==0: |
478 if self.backup_interval==0: |
| 479 return None |
479 return None |
| 480 else: |
480 else: |
| 516 with self._cond: |
516 with self._cond: |
| 517 res=self.__status_unlocked() |
517 res=self.__status_unlocked() |
| 518 return res[0] |
518 return res[0] |
| 519 |
519 |
| 520 def create(self): |
520 def create(self): |
| 521 op=Operation(Operation.CREATE, sleep.MonotonicTime.now(), reason='manual') |
521 op=Operation(Operation.CREATE, dreamtime.MonotonicTime.now(), reason='manual') |
| 522 with self._cond: |
522 with self._cond: |
| 523 self.scheduled_operation=op |
523 self.scheduled_operation=op |
| 524 self._cond.notify() |
524 self._cond.notify() |
| 525 |
525 |
| 526 def prune(self): |
526 def prune(self): |
| 527 op=Operation(Operation.PRUNE, sleep.MonotonicTime.now(), reason='manual') |
527 op=Operation(Operation.PRUNE, dreamtime.MonotonicTime.now(), reason='manual') |
| 528 with self._cond: |
528 with self._cond: |
| 529 self.scheduled_operation=op |
529 self.scheduled_operation=op |
| 530 self._cond.notify() |
530 self._cond.notify() |
| 531 |
531 |
| 532 # TODO: Decide exact (manual) abort mechanism. Perhaps two stages |
532 # TODO: Decide exact (manual) abort mechanism. Perhaps two stages |