backup.py

changeset 76
4b08fca3ce34
parent 74
4f56142e7497
child 78
83b43987e61e
--- a/backup.py	Sat Jan 27 12:19:39 2018 +0000
+++ b/backup.py	Sun Jan 28 00:11:18 2018 +0000
@@ -7,6 +7,7 @@
 import time
 import borgend
 import repository
+import sleep
 from enum import IntEnum
 from instance import BorgInstance
 from threading import Thread, Lock, Condition
@@ -53,20 +54,19 @@
 class Operation:
     CREATE='create'
     PRUNE='prune'
-    def __init__(self, operation, when_monotonic, **kwargs):
+    def __init__(self, operation, time, **kwargs):
         self.operation=operation
-        self.when_monotonic=when_monotonic
+        self.time=time
         self.detail=kwargs
 
     def when(self):
-        return self.when_monotonic-time.monotonic()+time.time()
+        return self.time.realtime()
 
 
 class Status(Operation):
     def __init__(self, backup, op=None):
         if op:
-            super().__init__(op.operation, op.when_monotonic,
-                             **op.detail)
+            super().__init__(op.operation, op.time, **op.detail)
         else:
             super().__init__(None, None)
 
@@ -137,6 +137,20 @@
                                                     'Retry interval', loc,
                                                     config.defaults['retry_interval'])
 
+
+        scheduling=config.check_string(cfg, 'scheduling',
+                                      'Scheduling mode', loc,
+                                      default="dreamtime")
+
+        if scheduling=="dreamtime":
+            self.timeclass=sleep.DreamTime
+        elif scheduling=="realtime":
+            self.timeclass=sleep.MonotonicTime
+        elif scheduling=="manual":
+            self.backup_interval=0
+        else:
+            logging.error("Invalid time class '%s' for %s" % (scheduling, loc))
+
         self.paths=config.check_nonempty_list_of_strings(cfg, 'paths', 'Paths', loc)
 
         self.borg_parameters=config.BorgParameters.from_config(cfg, loc)
@@ -158,6 +172,7 @@
         self.lastrun_finished=None
         self.state=State.INACTIVE
         self.errors=Errors.OK
+        self.timeclass=sleep.DreamTime
 
         self.__decode_config(cfg)
 
@@ -285,7 +300,7 @@
         self.current_operation=op
         # Update scheduled time to real starting time to schedule
         # next run relative to this
-        self.current_operation.when_monotonic=time.monotonic()
+        self.current_operation.time=sleep.MonotonicTime.now()
         self.state=State.ACTIVE
         # Reset error status when starting a new operation
         self.errors=Errors.OK
@@ -354,7 +369,7 @@
             self.errors=self.errors.combine(Errors.ERRORS)
 
         if self.current_operation.operation=='create':
-            self.lastrun_when=self.current_operation.when_monotonic
+            self.lastrun_when=self.current_operation.time.monotonic()
             self.lastrun_finished=time.monotonic()
         self.thread_res=None
         self.thread_log=None
@@ -404,17 +419,17 @@
         if not self.scheduled_operation:
             op=self.__next_operation_unlocked()
         if op:
-            now=time.monotonic()
-            delay=max(0, op.when_monotonic-now)
-            self.logger.info("Scheduling '%s' (detail: %s) in %d seconds" %
-                             (str(op.operation), op.detail or 'none', delay))
+            self.logger.info("Scheduling '%s' (detail: %s) in %d seconds [%s]" %
+                             (str(op.operation), op.detail or 'none',
+                              op.time.seconds_to(),
+                              op.time.__class__.__name__))
 
             self.scheduled_operation=op
             self.state=State.SCHEDULED
             self.__update_status()
 
             # Wait under scheduled wait
-            self.scheduler.wait_until(now+delay, self._cond, self.backup_name)
+            self.scheduler.wait_until(op.time, self._cond, self.backup_name)
         else:
             # Nothing scheduled - just wait
             self.logger.info("Waiting for manual scheduling")
@@ -444,7 +459,6 @@
 
     def __next_operation_unlocked(self):
         # TODO: pruning as well
-        now=time.monotonic()
         if not self.lastrun_finished:
             initial_interval=self.retry_interval
             if initial_interval==0:
@@ -452,21 +466,20 @@
             if initial_interval==0:
                 return None
             else:
-                return Operation(Operation.CREATE, now+initial_interval,
-                                 reason='initial')
+                tm=self.timeclass.after(initial_interval)
+                return Operation(Operation.CREATE, tm, reason='initial')
         elif not self.errors.ok():
             if self.retry_interval==0:
                 return None
             else:
-                return Operation(Operation.CREATE,
-                                 self.lastrun_finished+self.retry_interval,
-                                 reason='retry')
+                tm=sleep.MonotonicTime(self.lastrun_finished+self.retry_interval)
+                return Operation(Operation.CREATE, tm, reason='retry')
         else:
             if self.backup_interval==0:
                 return None
             else:
-                return Operation(Operation.CREATE,
-                                 self.lastrun_when+self.backup_interval)
+                tm=self.timeclass.from_monotonic(self.lastrun_when+self.backup_interval)
+                return Operation(Operation.CREATE, tm)
 
     def __status_unlocked(self):
         callback=self.__status_update_callback
@@ -505,13 +518,13 @@
         return res[0]
 
     def create(self):
-        op=Operation(Operation.CREATE, time.monotonic(), reason='manual')
+        op=Operation(Operation.CREATE, sleep.MonotonicTime.now(), reason='manual')
         with self._cond:
             self.scheduled_operation=op
             self._cond.notify()
 
     def prune(self):
-        op=Operation(Operation.PRUNE, time.monotonic(), reason='manual')
+        op=Operation(Operation.PRUNE, sleep.MonotonicTime.now(), reason='manual')
         with self._cond:
             self.scheduled_operation=op
             self._cond.notify()

mercurial