示例#1
0
    def run(self):
        """
        The main refresh state machine.
        
        Takes the conduit through the init->is_configured->refresh
        steps, setting its status at the appropriate time and performing
        nicely in the case of errors. 
        """
        log.debug("Started thread %s (thread: %s)" %
                  (self, thread.get_ident()))
        try:
            log.debug("Refresh %s beginning" % self)
            self.cond.emit("sync-started")

            if not self.dataproviderWrapper.module.is_configured(
                    isSource=self.cond.get_dataprovider_position(
                        self.dataproviderWrapper)[0] == 0,
                    isTwoWay=self.cond.is_two_way()):
                self.dataproviderWrapper.module.set_status(
                    DataProvider.STATUS_DONE_SYNC_NOT_CONFIGURED)
                #Cannot continue if source not configured
                raise Exceptions.StopSync(self.state)

            self.state = self.REFRESH_STATE
            try:
                self.dataproviderWrapper.module.refresh()
                self.dataproviderWrapper.module.set_status(
                    DataProvider.STATUS_DONE_REFRESH_OK)
            except Exceptions.RefreshError:
                self.dataproviderWrapper.module.set_status(
                    DataProvider.STATUS_DONE_REFRESH_ERROR)
                log.warn("RefreshError: %s" % self.dataproviderWrapper)
                #Cannot continue with no source data
                raise Exceptions.StopSync(self.state)
            except Exception:
                self.dataproviderWrapper.module.set_status(
                    DataProvider.STATUS_DONE_REFRESH_ERROR)
                log.critical(
                    "UNKNOWN REFRESH ERROR: %s\n%s" %
                    (self.dataproviderWrapper, traceback.format_exc()))
                #Cannot continue with no source data
                raise Exceptions.StopSync(self.state)

        except Exceptions.StopSync:
            log.warn("Sync Aborted")
            self.aborted = True

        conduit.GLOBALS.mappingDB.save()
        self.cond.emit("sync-completed", self.aborted, self.did_sync_error(),
                       self.did_sync_conflict())
示例#2
0
 def check_thread_not_cancelled(self, dataprovidersToCancel):
     """
     Checks if the thread has been scheduled to be cancelled. If it has
     then this function sets the status of the dataproviders to indicate
     that they were stopped through a cancel operation.
     """
     if self.cancelled:
         for s in dataprovidersToCancel:
             s.module.set_status(DataProvider.STATUS_DONE_SYNC_CANCELLED)
         raise Exceptions.StopSync(self.state)
示例#3
0
    def run(self):
        """
        The main syncronisation state machine.
        
        Takes the conduit through the refresh->get,put,get,put->done 
        steps, setting its status at the appropriate time and performing
        nicely in the case of errors. 
        
        It is also threaded so remember
         1. Syncronization should not block the GUI
         2. Due to pygtk/gtk single threadedness do not attempt to
            communicate with the gui in any way other than signals, which
            since Glib 2.10 are threadsafe.
            
        If any error occurs during sync raise a L{conduit.Exceptions.StopSync}
        exception otherwise exit normally 

        @raise Exceptions.StopSync: Raises a L{conduit.Exceptions.StopSync} 
        exception if the synchronisation state machine does not complete, in
        some way, without success.
        """
        log.debug("Started thread %s (thread: %s)" %
                  (self, thread.get_ident()))
        try:
            log.debug("Sync %s beginning. Slow: %s, Twoway: %s" %
                      (self, self.cond.do_slow_sync(), self.cond.is_two_way()))
            #Variable to exit the loop
            finished = False
            #Keep track of those sinks that didnt refresh ok
            sinkDidntRefreshOK = {}
            sinkDidntConfigureOK = {}

            #Error handling is a bit complex because we need to send
            #signals back to the gui for display, and because some errors
            #are not fatal. If there is an error, set the
            #'working' statuses immediately (Sync, Refresh) and set the
            #Negative status (error, conflict, etc) at the end so they remain
            #on the GUI and the user can see them.
            #UNLESS the error is Fatal (causes us to throw a stopsync exceptiion)
            #in which case set the error status immediately.
            self.cond.emit("sync-started")
            while not finished:
                self.check_thread_not_cancelled([self.source] + self.sinks)
                log.debug("Syncworker state %s" % self.state)

                #Check dps have been configured
                if self.state is self.CONFIGURE_STATE:
                    if not self.source.module.is_configured(
                            isSource=True, isTwoWay=self.cond.is_two_way()):
                        self.source.module.set_status(
                            DataProvider.STATUS_DONE_SYNC_NOT_CONFIGURED)
                        #Cannot continue if source not configured
                        raise Exceptions.StopSync(self.state)

                    for sink in self.sinks:
                        if not sink.module.is_configured(
                                isSource=False,
                                isTwoWay=self.cond.is_two_way()):
                            sinkDidntConfigureOK[sink] = True
                            self.sinkErrors[
                                sink] = DataProvider.STATUS_DONE_SYNC_NOT_CONFIGURED
                    #Need to have at least one successfully configured sink
                    if len(sinkDidntConfigureOK) < len(self.sinks):
                        #If this thread is a sync thread do a sync
                        self.state = self.REFRESH_STATE
                    else:
                        #We are finished
                        log.warn("Not enough configured datasinks")
                        self.aborted = True
                        self.state = self.DONE_STATE

                #refresh state
                elif self.state is self.REFRESH_STATE:
                    log.debug("Source Status = %s" %
                              self.source.module.get_status())
                    #Refresh the source
                    try:
                        self.source.module.refresh()
                        self.source.module.set_status(
                            DataProvider.STATUS_DONE_REFRESH_OK)
                    except Exceptions.RefreshError:
                        self.source.module.set_status(
                            DataProvider.STATUS_DONE_REFRESH_ERROR)
                        log.warn("RefreshError: %s" % self.source)
                        #Cannot continue with no source data
                        raise Exceptions.StopSync(self.state)
                    except Exception:
                        log.critical("UNKNOWN REFRESH ERROR: %s\n%s" %
                                     (self.source, traceback.format_exc()))
                        self.source.module.set_status(
                            DataProvider.STATUS_DONE_REFRESH_ERROR)
                        #Cannot continue with no source data
                        raise Exceptions.StopSync(self.state)

                    #Refresh all the sinks. At least one must refresh successfully
                    for sink in self.sinks:
                        self.check_thread_not_cancelled([self.source, sink])
                        if sink not in sinkDidntConfigureOK:
                            try:
                                sink.module.refresh()
                                sink.module.set_status(
                                    DataProvider.STATUS_DONE_REFRESH_OK)
                            except Exceptions.RefreshError:
                                log.warn("RefreshError: %s" % sink)
                                sinkDidntRefreshOK[sink] = True
                                self.sinkErrors[
                                    sink] = DataProvider.STATUS_DONE_REFRESH_ERROR
                            except Exception:
                                log.critical("UNKNOWN REFRESH ERROR: %s\n%s" %
                                             (sink, traceback.format_exc()))
                                sinkDidntRefreshOK[sink] = True
                                self.sinkErrors[
                                    sink] = DataProvider.STATUS_DONE_REFRESH_ERROR

                    #Need to have at least one successfully refreshed sink
                    if len(sinkDidntRefreshOK) < len(self.sinks):
                        #If this thread is a sync thread do a sync
                        if self.do_sync:
                            self.state = self.SYNC_STATE
                        else:
                            #This must be a refresh thread so we are done
                            self.state = self.DONE_STATE
                    else:
                        #We are finished
                        log.info("Not enough sinks refreshed")
                        self.aborted = True
                        self.state = self.DONE_STATE

                #synchronize state
                elif self.state is self.SYNC_STATE:
                    for sink in self.sinks:
                        self.check_thread_not_cancelled([self.source, sink])
                        #only sync with those sinks that refresh'd OK
                        if sink not in sinkDidntRefreshOK:
                            try:
                                #now perform a one or two way sync depending on the user prefs
                                #and the capabilities of the dataprovider
                                if self.cond.is_two_way():
                                    #two way
                                    self.two_way_sync(self.source, sink)
                                else:
                                    #one way
                                    self.one_way_sync(self.source, sink)
                            except Exceptions.SyncronizeFatalError, err:
                                log.warn("%s\n%s" %
                                         (err, traceback.format_exc()))
                                sink.module.set_status(
                                    DataProvider.STATUS_DONE_SYNC_ERROR)
                                self.source.module.set_status(
                                    DataProvider.STATUS_DONE_SYNC_ERROR)
                                #cannot continue with this source, sink pair
                                continue
                            except Exception:
                                log.critical(
                                    "UNKNOWN SYNCHRONIZATION ERROR\n%s" %
                                    traceback.format_exc())
                                sink.module.set_status(
                                    DataProvider.STATUS_DONE_SYNC_ERROR)
                                self.source.module.set_status(
                                    DataProvider.STATUS_DONE_SYNC_ERROR)
                                #cannot continue with this source, sink pair
                                continue