diff --git a/Changelog.draft.rst b/Changelog.draft.rst index fe70cfe..66501e2 100644 --- a/Changelog.draft.rst +++ b/Changelog.draft.rst @@ -17,6 +17,9 @@ New Features readonly = True. When e.g. using offlineimap for backup purposes you can thus make sure that no changes in your backup trickle back into the main IMAP server. +* optional: experimental SQLite-based backend for the LocalStatus + cache. Plain text remains the default. Enable by setting + status_backend=sqlite in the [Account ...] section Changes ------- @@ -41,11 +44,3 @@ Pending for the next major release * UIs get shorter and nicer names. (API changing) * Implement IDLE feature. (delayed until next major release) - - -Stalled -======= - -* Learn Sqlite support. - Stalled: it would need to learn the ability to choose between the current - format and SQL to help testing the long term. diff --git a/offlineimap.conf b/offlineimap.conf index f8506b2..33a0810 100644 --- a/offlineimap.conf +++ b/offlineimap.conf @@ -197,6 +197,23 @@ remoterepository = RemoteExample # You can also specify parameters to the commands # presynchook = imapfilter -c someotherconfig.lua +# OfflineImap caches the state of the synchronisation to e.g. be able to +# determine if a mail has been deleted on one side or added on the +# other. +# +# The default and historical backend is 'plain' which writes out the +# state in plain text files. On Repositories with large numbers of +# mails, the performance might not be optimal, as we write out the +# complete file for each change. Another new backend 'sqlite' is +# available which stores the status in sqlite databases. BE AWARE THIS +# IS EXPERIMENTAL STUFF. +# +# If you switch the backend, you may want to delete the old cache +# directory in ~/.offlineimap/Account-/LocalStatus manually +# once you are sure that things work. +# +#status_backend = plain + # If you have a limited amount of bandwidth available you can exclude larger # messages (e.g. those with large attachments etc). If you do this it # will appear to offlineimap that these messages do not exist at all. They diff --git a/offlineimap/repository/LocalStatus.py b/offlineimap/repository/LocalStatus.py index 722f6c3..7d38596 100644 --- a/offlineimap/repository/LocalStatus.py +++ b/offlineimap/repository/LocalStatus.py @@ -18,7 +18,8 @@ from Base import BaseRepository from offlineimap import folder -import offlineimap.folder.LocalStatus +from offlineimap.folder.LocalStatus import LocalStatusFolder +from offlineimap.folder.LocalStatusSQLite import LocalStatusSQLiteFolder import os import re @@ -26,9 +27,25 @@ class LocalStatusRepository(BaseRepository): def __init__(self, reposname, account): BaseRepository.__init__(self, reposname, account) self.directory = os.path.join(account.getaccountmeta(), 'LocalStatus') + + #statusbackend can be 'plain' or 'sqlite' + backend = self.account.getconf('status_backend', 'plain') + if backend == 'sqlite': + self._backend = 'sqlite' + self.LocalStatusFolderClass = LocalStatusSQLiteFolder + self.directory += '-sqlite' + elif backend == 'plain': + self._backend = 'plain' + self.LocalStatusFolderClass = LocalStatusFolder + else: + raise SyntaxWarning("Unknown status_backend '%s' for account '%s'" \ + % (backend, account.name)) + if not os.path.exists(self.directory): os.mkdir(self.directory, 0700) - self.folders = None + + # self._folders is a list of LocalStatusFolders() + self._folders = None def getsep(self): return '.' @@ -40,16 +57,22 @@ class LocalStatusRepository(BaseRepository): return os.path.join(self.directory, foldername) def makefolder(self, foldername): - # "touch" the file, truncating it. + """Create a LocalStatus Folder + + Empty Folder for plain backend. NoOp for sqlite backend as those + are created on demand.""" + # Invalidate the cache. + self._folders = None + if self._backend == 'sqlite': + return + filename = self.getfolderfilename(foldername) file = open(filename + ".tmp", "wt") file.write(offlineimap.folder.LocalStatus.magicline + '\n') - file.flush() - os.fsync(file.fileno()) file.close() os.rename(filename + ".tmp", filename) # Invalidate the cache. - self.folders = None + self._folders = None def getfolder(self, foldername): """Return the Folder() object for a foldername""" @@ -72,4 +95,3 @@ class LocalStatusRepository(BaseRepository): """Forgets the cached list of folders, if any. Useful to run after a sync run.""" self._folders = None -