294 status, callback=self.__status_unlocked() |
294 status, callback=self.__status_unlocked() |
295 else: |
295 else: |
296 self.logger.debug('Unrecognised log entry %s' % str(status)) |
296 self.logger.debug('Unrecognised log entry %s' % str(status)) |
297 |
297 |
298 if callback: |
298 if callback: |
299 callback(status, errors=errormsg) |
299 callback(status, errorlog=errormsg) |
300 |
300 |
301 self.logger.debug('Waiting for borg subprocess to terminate in log thread') |
301 self.logger.debug('Waiting for borg subprocess to terminate in log thread') |
302 |
302 |
303 self.borg_instance.wait() |
303 self.borg_instance.wait() |
304 |
304 |
352 self.logger.info('borg info: Could not discover a previous backup') |
352 self.logger.info('borg info: Could not discover a previous backup') |
353 |
353 |
354 def __do_launch(self, op, archive_or_repository, |
354 def __do_launch(self, op, archive_or_repository, |
355 common_params, op_params, paths=[]): |
355 common_params, op_params, paths=[]): |
356 |
356 |
|
357 self.logger.debug('Creating BorgInstance') |
|
358 |
357 inst=BorgInstance(op.operation, archive_or_repository, |
359 inst=BorgInstance(op.operation, archive_or_repository, |
358 common_params, op_params, paths) |
360 common_params, op_params, paths) |
|
361 |
|
362 self.logger.debug('Launching BorgInstance via repository') |
359 |
363 |
360 # Only the Repository object has access to the passphrase |
364 # Only the Repository object has access to the passphrase |
361 self.repository.launch_borg_instance(inst) |
365 self.repository.launch_borg_instance(inst) |
362 |
366 |
363 self.logger.debug('Creating listener threads') |
367 self.logger.debug('Creating listener threads') |
454 self.state=State.INACTIVE |
458 self.state=State.INACTIVE |
455 self.__update_status() |
459 self.__update_status() |
456 |
460 |
457 def __main_thread(self): |
461 def __main_thread(self): |
458 with self._cond: |
462 with self._cond: |
459 try: |
463 while not self._terminate: |
460 while not self._terminate: |
464 try: |
461 assert(not self.current_operation) |
465 assert(not self.current_operation) |
462 self.__main_thread_wait_schedule() |
466 self.__main_thread_wait_schedule() |
463 if not self._terminate: |
467 if not self._terminate: |
464 self.__main_thread_queue_and_launch() |
468 self.__main_thread_queue_and_launch() |
465 except Exception as err: |
469 except Exception as err: |
466 self.logger.exception("Error with backup '%s'" % self.backup_name) |
470 self.logger.exception("Error with backup '%s'" % self.backup_name) |
467 self.errors=Errors.ERRORS |
471 self.errors=Errors.ERRORS |
468 |
472 self.__cleanup() |
469 self.state=State.INACTIVE |
473 |
470 self.scheduled_operation=None |
474 self.__cleanup() |
471 |
475 |
472 # Clean up to terminate: kill borg instance and communication threads |
476 def __cleanup(self): |
473 if self.borg_instance: |
477 self.state=State.INACTIVE |
|
478 self.scheduled_operation=None |
|
479 self.current_operation=None |
|
480 thread_log=self.thread_log |
|
481 thread_res=self.thread_res |
|
482 borg_instance=self.borg_instance |
|
483 self.thread_log=None |
|
484 self.thread_res=None |
|
485 self.borg_instance=None |
|
486 |
|
487 self._cond.release() |
|
488 try: |
|
489 if borg_instance: |
474 self.logger.debug("Terminating a borg instance") |
490 self.logger.debug("Terminating a borg instance") |
475 self.borg_instance.terminate() |
491 borg_instance.terminate() |
476 |
492 |
477 # Store threads to use outside lock |
493 if thread_log: |
478 thread_log=self.thread_log |
494 self.logger.debug("Waiting for log thread to terminate") |
479 thread_res=self.thread_res |
495 thread_log.join() |
480 self.thread_log=None |
496 |
481 self.thread_res=None |
497 if thread_res: |
482 |
498 self.logger.debug("Waiting for result thread to terminate") |
483 self.logger.debug("Waiting for log and result threads to terminate") |
499 thread_res.join() |
484 |
500 finally: |
485 if thread_log: |
501 self._cond.acquire() |
486 thread_log.join() |
|
487 |
|
488 if thread_res: |
|
489 thread_res.join() |
|
490 |
502 |
491 # Main thread/2. Schedule next operation if there is no manually |
503 # Main thread/2. Schedule next operation if there is no manually |
492 # requested one |
504 # requested one |
493 def __main_thread_wait_schedule(self): |
505 def __main_thread_wait_schedule(self): |
494 op=None |
506 op=None |