get rid of offlineimap/syncmaster.py

Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
This commit is contained in:
Nicolas Sebrecht 2016-05-17 02:25:52 +02:00
parent 857b2f449a
commit 7ab18276f9
3 changed files with 41 additions and 60 deletions

View File

@ -25,7 +25,7 @@ import logging
from optparse import OptionParser from optparse import OptionParser
import offlineimap import offlineimap
from offlineimap import accounts, threadutil, syncmaster, folder from offlineimap import accounts, threadutil, folder
from offlineimap import globals from offlineimap import globals
from offlineimap.ui import UI_LIST, setglobalui, getglobalui from offlineimap.ui import UI_LIST, setglobalui, getglobalui
from offlineimap.CustomConfig import CustomConfigParser from offlineimap.CustomConfig import CustomConfigParser
@ -36,6 +36,28 @@ import traceback
import collections import collections
def syncaccount(config, accountname):
"""Return a new running thread for this account."""
account = accounts.SyncableAccount(config, accountname)
thread = threadutil.InstanceLimitedThread(instancename = 'ACCOUNTLIMIT',
target = account.syncrunner,
name = "Account sync %s" % accountname)
thread.setDaemon(True)
thread.start()
return thread
def syncitall(accounts, config):
"""The target when in multithreading mode for running accounts threads."""
threads = threadutil.accountThreads() # The collection of accounts threads.
for accountname in accounts:
# Start a new thread per account and store it in the collection.
threads.add(syncaccount(config, accountname))
# Wait for the threads to finish.
threads.wait() # Blocks until all accounts are processed.
class OfflineImap: class OfflineImap:
"""The main class that encapsulates the high level use of OfflineImap. """The main class that encapsulates the high level use of OfflineImap.
@ -388,9 +410,11 @@ class OfflineImap:
self.__sync_singlethreaded(syncaccounts) self.__sync_singlethreaded(syncaccounts)
else: else:
# multithreaded # multithreaded
t = threadutil.ExitNotifyThread(target=syncmaster.syncitall, t = threadutil.ExitNotifyThread(target=syncitall,
name='Sync Runner', name='Sync Runner',
kwargs={'accounts': syncaccounts, 'config': self.config}) kwargs={'accounts': syncaccounts, 'config': self.config})
# Special exit message for the monitor to stop looping.
t.exit_message = threadutil.STOP_MONITOR
t.start() t.start()
threadutil.monitor() threadutil.monitor()
@ -407,13 +431,12 @@ class OfflineImap:
return 1 return 1
def __sync_singlethreaded(self, accs): def __sync_singlethreaded(self, accs):
"""Executed if we do not want a separate syncmaster thread """Executed in singlethreaded mode only.
:param accs: A list of accounts that should be synced :param accs: A list of accounts that should be synced
""" """
for accountname in accs: for accountname in accs:
account = offlineimap.accounts.SyncableAccount(self.config, account = accounts.SyncableAccount(self.config, accountname)
accountname)
threading.currentThread().name = "Account sync %s"% accountname threading.currentThread().name = "Account sync %s"% accountname
account.syncrunner() account.syncrunner()

View File

@ -1,45 +0,0 @@
# OfflineIMAP synchronization master code
# Copyright (C) 2002-2007 John Goerzen
# <jgoerzen@complete.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
from offlineimap.threadutil import accountThreads, InstanceLimitedThread, STOP_MONITOR
from offlineimap.accounts import SyncableAccount
from threading import currentThread
def syncaccount(config, accountname):
"""Return a new running thread for this account."""
account = SyncableAccount(config, accountname)
thread = InstanceLimitedThread(instancename = 'ACCOUNTLIMIT',
target = account.syncrunner,
name = "Account sync %s" % accountname)
thread.setDaemon(True)
thread.start()
return thread
def syncitall(accounts, config):
"""The target when in multithreading mode for running accounts threads."""
# Special exit message for the monitor to stop looping so the main thread
# can exit.
currentThread().exit_message = STOP_MONITOR
threads = accountThreads() # The collection of accounts threads.
for accountname in accounts:
# Start a new thread per account and store it in the collection.
threads.add(syncaccount(config, accountname))
# Wait for the threads to finish.
threads.wait() # Blocks until all accounts are processed.

View File

@ -84,7 +84,7 @@ class accountThreads(object):
# Exit-notify threads # Exit-notify threads
###################################################################### ######################################################################
exitthreads = Queue() exitedThreads = Queue()
def monitor(): def monitor():
"""An infinite "monitoring" loop watching for finished ExitNotifyThread's. """An infinite "monitoring" loop watching for finished ExitNotifyThread's.
@ -103,17 +103,20 @@ def monitor():
:type callback: a callable function :type callback: a callable function
""" """
global exitthreads global exitedThreads
ui = getglobalui() ui = getglobalui()
while True: while True:
# Loop forever and call 'callback' for each thread that exited # Loop forever and call 'callback' for each thread that exited
try: try:
# We need a timeout in the get() call, so that ctrl-c can throw # We need a timeout in the get() call, so that ctrl-c can throw a
# a SIGINT (http://bugs.python.org/issue1360). A timeout with empty # SIGINT (http://bugs.python.org/issue1360). A timeout with empty
# Queue will raise `Empty`. # Queue will raise `Empty`.
thread = exitthreads.get(True, 60) #
# request to abort when callback returns true # ExitNotifyThread add themselves to the exitedThreads queue once
# they are done (normally or with exception).
thread = exitedThreads.get(True, 60)
# Request to abort when callback returns True.
if thread.exit_exception is not None: if thread.exit_exception is not None:
if isinstance(thread.exit_exception, SystemExit): if isinstance(thread.exit_exception, SystemExit):
@ -128,6 +131,7 @@ def monitor():
" and the ui did not stop the program."% " and the ui did not stop the program."%
(repr(thread.exit_exception), type(thread.exit_exception))) (repr(thread.exit_exception), type(thread.exit_exception)))
# Only the monitor thread has this exit message set.
elif thread.exit_message == STOP_MONITOR: elif thread.exit_message == STOP_MONITOR:
break # Exit the loop here. break # Exit the loop here.
else: else:
@ -160,9 +164,9 @@ class ExitNotifyThread(Thread):
self._exit_stacktrace = None self._exit_stacktrace = None
def run(self): def run(self):
"""Allow profiling of a run.""" """Allow profiling of a run and store exceptions."""
global exitthreads global exitedThreads
try: try:
if not ExitNotifyThread.profiledir: # normal case if not ExitNotifyThread.profiledir: # normal case
Thread.run(self) Thread.run(self)
@ -183,8 +187,7 @@ class ExitNotifyThread(Thread):
tb = traceback.format_exc() tb = traceback.format_exc()
self.set_exit_exception(e, tb) self.set_exit_exception(e, tb)
if exitthreads: exitedThreads.put(self, True)
exitthreads.put(self, True)
def set_exit_exception(self, exc, st=None): def set_exit_exception(self, exc, st=None):
"""Sets Exception and stacktrace of a thread, so that other """Sets Exception and stacktrace of a thread, so that other