[PATCH 4/4] Implement single threading mode

Sebastian Spaeth Sebastian at SSpaeth.de
Mon Jan 10 10:00:41 GMT 2011


Don't sync accounts in subthreads when:
 1) option singlethreading has been chosen
 2) There is only 1 account to sync
 3) maxacountsync setting is 1 (default)

Do note that in cases 2) and 3) each account will still be synced in
multithreaded fashion (within the account), we will just not spawn
separate threads to launch and supervise the account synchronization.

Signed-off-by: Sebastian Spaeth <Sebastian at SSpaeth.de>
---
 offlineimap/init.py       |   64 ++++++++++++++++++++++++++------------------
 offlineimap/syncmaster.py |    4 +--
 2 files changed, 39 insertions(+), 29 deletions(-)

diff --git a/offlineimap/init.py b/offlineimap/init.py
index 4347bf1..f1f1bd6 100644
--- a/offlineimap/init.py
+++ b/offlineimap/init.py
@@ -17,17 +17,11 @@
 #    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 
 import imaplib
-from offlineimap import imapserver, threadutil, version, syncmaster, accounts
+import offlineimap
+import offlineimap.accounts
 from offlineimap.localeval import LocalEval
 from offlineimap.threadutil import InstanceLimitedThread, ExitNotifyThread
-import offlineimap.ui
 from offlineimap.CustomConfig import CustomConfigParser
-from optparse import OptionParser
-import re, os, sys
-from threading import *
-import threading, socket
-import signal
-import logging
 
 try:
     import fcntl
@@ -174,7 +168,7 @@ class OfflineImap:
                 options.singlethreaded = True
             profiledir = options.profiledir
             os.mkdir(profiledir)
-            threadutil.setprofiledir(profiledir)
+            offlineimap.threadutil.setprofiledir(profiledir)
             logging.warn("Profile mode: Potentially large data will be "
                          "created in '%s'" % profiledir)
 
@@ -221,18 +215,18 @@ class OfflineImap:
 
         if options.runonce:
             # FIXME: maybe need a better
-            for section in accounts.getaccountlist(config):
+            for section in offlineimap.accounts.getaccountlist(config):
                 config.remove_option('Account ' + section, "autorefresh")
 
         if options.quick:
-            for section in accounts.getaccountlist(config):
+            for section in offlineimap.accounts.getaccountlist(config):
                 config.set('Account ' + section, "quick", '-1')
 
         if options.folders:
             foldernames = options.folders.replace(" ", "").split(",")
             folderfilter = "lambda f: f in %s" % foldernames
             folderincludes = "[]"
-            for accountname in accounts.getaccountlist(config):
+            for accountname in offlineimap.accounts.getaccountlist(config):
                 account_section = 'Account ' + accountname
                 remote_repo_section = 'Repository ' + \
                                       config.get(account_section, 'remoterepository')
@@ -272,7 +266,7 @@ class OfflineImap:
                 activeaccounts = options.accounts
             activeaccounts = activeaccounts.replace(" ", "")
             activeaccounts = activeaccounts.split(",")
-            allaccounts = accounts.AccountHashGenerator(config)
+            allaccounts = offlineimap.accounts.AccountHashGenerator(config)
     
             syncaccounts = []
             for account in activeaccounts:
@@ -291,19 +285,16 @@ class OfflineImap:
             remoterepos = None
             localrepos = None
     
-            if options.singlethreading:
-                threadutil.initInstanceLimit("ACCOUNTLIMIT", 1)
-            else:
-                threadutil.initInstanceLimit("ACCOUNTLIMIT",
-                                             config.getdefaultint("general", "maxsyncaccounts", 1))
+            offlineimap.threadutil.initInstanceLimit("ACCOUNTLIMIT",
+                                   config.getdefaultint("general", "maxsyncaccounts", 1))
     
             for reposname in config.getsectionlist('Repository'):
                 for instancename in ["FOLDER_" + reposname,
                                      "MSGCOPY_" + reposname]:
                     if options.singlethreading:
-                        threadutil.initInstanceLimit(instancename, 1)
+                        offlineimap.threadutil.initInstanceLimit(instancename, 1)
                     else:
-                        threadutil.initInstanceLimit(instancename,
+                        offlineimap.threadutil.initInstanceLimit(instancename,
                                                      config.getdefaultint('Repository ' + reposname, "maxconnections", 1))
             siglisteners = []
             def sig_handler(signum, frame):
@@ -324,15 +315,24 @@ class OfflineImap:
             signal.signal(signal.SIGUSR1,sig_handler)
             signal.signal(signal.SIGUSR2,sig_handler)
     
-            threadutil.initexitnotify()
-            t = ExitNotifyThread(target=syncmaster.syncitall,
+            #various initializations that need to be performed:
+            offlineimap.threadutil.initexitnotify()       #TODO: Why?
+            offlineimap.mbnames.init(config, syncaccounts)
+
+            if options.singlethreading or len(syncaccounts) == 1 \
+                    or config.getdefaultint("general", "maxsyncaccounts", 1) == 1:
+                #singlethreaded
+                self.sync_singlethreaded(syncaccounts, config, siglisteners)
+            else:
+                # multithreaded
+                t = ExitNotifyThread(target=offlineimap.syncmaster.syncitall,
                                  name='Sync Runner',
                                  kwargs = {'accounts': syncaccounts,
                                            'config': config,
                                            'siglisteners': siglisteners})
-            t.setDaemon(1)
-            t.start()
-            threadutil.exitnotifymonitorloop(threadutil.threadexited)
+                t.setDaemon(1)
+                t.start()
+                offlineimap.threadutil.exitnotifymonitorloop(offlineimap.threadutil.threadexited)
 
         except KeyboardInterrupt:
             ui.terminate(1, errormsg = 'CTRL-C pressed, aborting...')
@@ -342,4 +342,16 @@ class OfflineImap:
         except:
             ui.mainException()
 
-        
+    def sync_singlethreaded(self, accounts, config, siglisteners):
+        """Executed if we do not want a separate syncmaster thread
+
+        :param accounts: A list of accounts that should be synced
+        :param config: The CustomConfig object
+        :param siglisteners: The signal listeners list, defined in run()
+        """
+        for accountname in accounts:
+            account = offlineimap.accounts.SyncableAccount(config, accountname)
+            siglistener = offlineimap.accounts.SigListener()
+            siglisteners.append(siglistener)
+            currentThread().name = "Account sync %s" % accountname
+            account.syncrunner(siglistener=siglistener)
diff --git a/offlineimap/syncmaster.py b/offlineimap/syncmaster.py
index 2da8e3e..5a0a2fb 100644
--- a/offlineimap/syncmaster.py
+++ b/offlineimap/syncmaster.py
@@ -16,7 +16,6 @@
 #    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 import mbnames
 from offlineimap.threadutil import threadlist, InstanceLimitedThread, ExitNotifyThread
 from offlineimap.accounts import SyncableAccount, SigListener
 from threading import currentThread
@@ -33,11 +32,10 @@ def syncaccount(threads, config, accountname, siglisteners):
     thread.setDaemon(1)
     thread.start()
     threads.add(thread)
-    
+
 def syncitall(accounts, config, siglisteners):
     currentThread().setExitMessage('SYNC_WITH_TIMER_TERMINATE')
     threads = threadlist()
-    mbnames.init(config, accounts)
     for accountname in accounts:
         syncaccount(threads, config, accountname, siglisteners)
     # Wait for the threads to finish.
-- 
1.7.1





More information about the OfflineIMAP-project mailing list