/offlineimap/head: changeset 347
Preparing for 3.99.7
This commit is contained in:
parent
399f7d9de9
commit
3cb8fb0062
@ -1,3 +1,33 @@
|
||||
offlineimap (3.99.7) unstable; urgency=low
|
||||
|
||||
* This is a 4.0 TRACK release, and may be unstable or in flux!
|
||||
* Converted entire manual to DocBook SGML so it will be easier to
|
||||
expand in the future. The HTML manual, also, looks far nicer now
|
||||
than it did before.
|
||||
* Fixed the Tk.VerboseUI -- small, silly error introduced in 3.99.6.
|
||||
* Multiple performance and reliability enhancements to syncing
|
||||
algorithms, as described below.
|
||||
* The process of uploading new messages from local folders to the IMAP
|
||||
server was not internally multi-threaded previously. Now it is.
|
||||
This means that if you have a single folder with lots of new messages
|
||||
locally, the processing time should be dramatically sped up. Moreover,
|
||||
the process should be more reliable because we do not risk connections
|
||||
going dead.
|
||||
* The process of synchronizing flags has been overhauled and optimized.
|
||||
Previously, for each message where a flag (seen, replied, etc.) was
|
||||
changed, we'd issue a separate command to the IMAP server to adjust
|
||||
things. Now, we issue one command for each flag. In other words,
|
||||
instead of seing 45 messages saying something like "Adding flag S to
|
||||
message 1421", you now see one message saying "Adding flag S to 45
|
||||
messages" -- and the interaction with the IMAP server may well be
|
||||
almost 45 times faster on this. We will now issue at most four
|
||||
commands per flag operation (add or remove) per folder, where before,
|
||||
we may have issued as many as two per message. Should be a
|
||||
large speedup in most cases, but a small slowdown in a few.
|
||||
* Potentially increased the reliability of writing files to the Maildir.
|
||||
|
||||
-- John Goerzen <jgoerzen@complete.org> Wed, 8 Jan 2003 07:05:01 -0600
|
||||
|
||||
offlineimap (3.99.6) unstable; urgency=low
|
||||
|
||||
* This a 4.0 TRACK release, and may be unstable or in flux!
|
||||
|
@ -2,7 +2,7 @@ Source: offlineimap
|
||||
Section: mail
|
||||
Priority: optional
|
||||
Maintainer: John Goerzen <jgoerzen@complete.org>
|
||||
Build-Depends-Indep: debhelper (>> 3.0.0), python2.2 (>= 2.2.1-4), python2.2-dev (>= 2.2.1-4), groff
|
||||
Build-Depends-Indep: debhelper (>> 3.0.0), python2.2 (>= 2.2.1-4), python2.2-dev (>= 2.2.1-4), groff, docbook-utils
|
||||
Standards-Version: 3.5.2
|
||||
|
||||
Package: offlineimap
|
||||
|
@ -131,7 +131,7 @@ class BaseFolder:
|
||||
|
||||
def addmessagesflags(self, uidlist, flags):
|
||||
for uid in uidlist:
|
||||
self.addmessageflags(uid)
|
||||
self.addmessageflags(uid, flags)
|
||||
|
||||
def deletemessageflags(self, uid, flags):
|
||||
"""Removes each flag given from the message's flag set. If a given
|
||||
@ -143,6 +143,10 @@ class BaseFolder:
|
||||
newflags.sort()
|
||||
self.savemessageflags(uid, newflags)
|
||||
|
||||
def deletemessagesflags(self, uidlist, flags):
|
||||
for uid in uidlist:
|
||||
self.deletemessageflags(uid, flags)
|
||||
|
||||
def deletemessage(self, uid):
|
||||
raise NotImplementedException
|
||||
|
||||
@ -150,6 +154,35 @@ class BaseFolder:
|
||||
for uid in uidlist:
|
||||
self.deletemessage(uid)
|
||||
|
||||
def syncmessagesto_neguid_msg(self, uid, dest, applyto, register = 1):
|
||||
if register:
|
||||
UIBase.getglobalui().registerthread(self.getaccountname())
|
||||
UIBase.getglobalui().copyingmessage(uid, self, applyto)
|
||||
successobject = None
|
||||
successuid = None
|
||||
message = self.getmessage(uid)
|
||||
flags = self.getmessageflags(uid)
|
||||
for tryappend in applyto:
|
||||
successuid = tryappend.savemessage(uid, message, flags)
|
||||
if successuid >= 0:
|
||||
successobject = tryappend
|
||||
break
|
||||
# Did we succeed?
|
||||
if successobject != None:
|
||||
if successuid: # Only if IMAP actually assigned a UID
|
||||
# Copy the message to the other remote servers.
|
||||
for appendserver in \
|
||||
[x for x in applyto if x != successobject]:
|
||||
appendserver.savemessage(successuid, message, flags)
|
||||
# Copy to its new name on the local server and delete
|
||||
# the one without a UID.
|
||||
self.savemessage(successuid, message, flags)
|
||||
self.deletemessage(uid) # It'll be re-downloaded.
|
||||
else:
|
||||
# Did not find any server to take this message. Ignore.
|
||||
pass
|
||||
|
||||
|
||||
def syncmessagesto_neguid(self, dest, applyto):
|
||||
"""Pass 1 of folder synchronization.
|
||||
|
||||
@ -158,33 +191,28 @@ class BaseFolder:
|
||||
and once that succeeds, get the UID, add it to the others for real,
|
||||
add it to local for real, and delete the fake one."""
|
||||
|
||||
for uid in self.getmessagelist().keys():
|
||||
if uid >= 0:
|
||||
continue
|
||||
UIBase.getglobalui().copyingmessage(uid, self, applyto)
|
||||
successobject = None
|
||||
successuid = None
|
||||
message = self.getmessage(uid)
|
||||
flags = self.getmessageflags(uid)
|
||||
for tryappend in applyto:
|
||||
successuid = tryappend.savemessage(uid, message, flags)
|
||||
if successuid >= 0:
|
||||
successobject = tryappend
|
||||
break
|
||||
# Did we succeed?
|
||||
if successobject != None:
|
||||
if successuid: # Only if IMAP actually assigned a UID
|
||||
# Copy the message to the other remote servers.
|
||||
for appendserver in \
|
||||
[x for x in applyto if x != successobject]:
|
||||
appendserver.savemessage(successuid, message, flags)
|
||||
# Copy to its new name on the local server and delete
|
||||
# the one without a UID.
|
||||
self.savemessage(successuid, message, flags)
|
||||
self.deletemessage(uid) # It'll be re-downloaded.
|
||||
uidlist = [uid for uid in self.getmessagelist().keys() if uid < 0]
|
||||
threads = []
|
||||
|
||||
usethread = None
|
||||
if applyto != None:
|
||||
usethread = applyto[0]
|
||||
|
||||
for uid in uidlist:
|
||||
if usethread:
|
||||
usethread.waitforthread()
|
||||
thread = InstanceLimitedThread(\
|
||||
usethread.getcopyinstancelimit(),
|
||||
target = self.syncmessagesto_neguid_msg,
|
||||
name = "New msg sync from %s" % self.getvisiblename(),
|
||||
args = (uid, dest, applyto))
|
||||
thread.setDaemon(1)
|
||||
thread.start()
|
||||
threads.append(thread)
|
||||
else:
|
||||
# Did not find any server to take this message. Ignore.
|
||||
pass
|
||||
self.syncmessagesto_neguid_msg(uid, dest, applyto, register = 0)
|
||||
for thread in threads:
|
||||
thread.join()
|
||||
|
||||
def copymessageto(self, uid, applyto, register = 1):
|
||||
# Sometimes, it could be the case that if a sync takes awhile,
|
||||
@ -260,6 +288,17 @@ class BaseFolder:
|
||||
|
||||
Look for any flag matching issues -- set dest message to have the
|
||||
same flags that we have."""
|
||||
|
||||
# As an optimization over previous versions, we store up which flags
|
||||
# are being used for an add or a delete. For each flag, we store
|
||||
# a list of uids to which it should be added. Then, we can call
|
||||
# addmessagesflags() to apply them in bulk, rather than one
|
||||
# call per message as before. This should result in some significant
|
||||
# performance improvements.
|
||||
|
||||
addflaglist = {}
|
||||
delflaglist = {}
|
||||
|
||||
for uid in self.getmessagelist().keys():
|
||||
if uid < 0: # Ignore messages missed by pass 1
|
||||
continue
|
||||
@ -267,17 +306,26 @@ class BaseFolder:
|
||||
destflags = dest.getmessageflags(uid)
|
||||
|
||||
addflags = [x for x in selfflags if x not in destflags]
|
||||
if len(addflags):
|
||||
UIBase.getglobalui().addingflags(uid, addflags, applyto)
|
||||
for object in applyto:
|
||||
object.addmessageflags(uid, addflags)
|
||||
|
||||
for flag in addflags:
|
||||
if not flag in addflaglist:
|
||||
addflaglist[flag] = []
|
||||
addflaglist[flag].append(uid)
|
||||
|
||||
delflags = [x for x in destflags if x not in selfflags]
|
||||
if len(delflags):
|
||||
UIBase.getglobalui().deletingflags(uid, delflags, applyto)
|
||||
for object in applyto:
|
||||
object.deletemessageflags(uid, delflags)
|
||||
for flag in delflags:
|
||||
if not flag in delflaglist:
|
||||
delflaglist[flag] = []
|
||||
delflaglist[flag].append(uid)
|
||||
|
||||
for object in applyto:
|
||||
for flag in addflaglist.keys():
|
||||
UIBase.getglobalui().addingflags(addflaglist[flag], flag, [object])
|
||||
object.addmessagesflags(addflaglist[flag], [flag])
|
||||
for flag in delflaglist.keys():
|
||||
UIBase.getglobalui().deletingflags(addflaglist[flag], flag, [object])
|
||||
object.deletemessagesflags(delflaglist[flag], [flag])
|
||||
|
||||
def syncmessagesto(self, dest, applyto = None):
|
||||
"""Syncs messages in this folder to the destination.
|
||||
If applyto is specified, it should be a list of folders (don't forget
|
||||
|
@ -198,6 +198,15 @@ class IMAPFolder(BaseFolder):
|
||||
self.addmessagesflags([uid], flags)
|
||||
|
||||
def addmessagesflags(self, uidlist, flags):
|
||||
self.processmessagesflags('+', uidlist, flags)
|
||||
|
||||
def deletemessageflags(self, uid, flags):
|
||||
self.deletemessagesflags([uid], flags)
|
||||
|
||||
def deletemessagesflags(self, uidlist, flags):
|
||||
self.processmessagesflags('-', uidlist, flags)
|
||||
|
||||
def processmessagesflags(self, operation, uidlist, flags):
|
||||
imapobj = self.imapserver.acquireconnection()
|
||||
try:
|
||||
try:
|
||||
@ -207,7 +216,7 @@ class IMAPFolder(BaseFolder):
|
||||
return
|
||||
r = imapobj.uid('store',
|
||||
imaputil.listjoin(uidlist),
|
||||
'+FLAGS',
|
||||
operation + 'FLAGS',
|
||||
imaputil.flagsmaildir2imap(flags))
|
||||
assert r[0] == 'OK', 'Error with store: ' + r[1]
|
||||
r = r[1]
|
||||
@ -234,10 +243,15 @@ class IMAPFolder(BaseFolder):
|
||||
except ValueError: # Let it slide if it's not in the list
|
||||
pass
|
||||
for uid in needupdate:
|
||||
for flag in flags:
|
||||
if not flag in self.messagelist[uid]['flags']:
|
||||
self.messagelist[uid]['flags'].append(flag)
|
||||
self.messagelist[uid]['flags'].sort()
|
||||
if operation == '+':
|
||||
for flag in flags:
|
||||
if not flag in self.messagelist[uid]['flags']:
|
||||
self.messagelist[uid]['flags'].append(flag)
|
||||
self.messagelist[uid]['flags'].sort()
|
||||
elif operation == '-':
|
||||
for flag in flags:
|
||||
if flag in self.messagelist[uid]['flags']:
|
||||
self.messagelist[uid]['flags'].remove(flag)
|
||||
|
||||
def deletemessage(self, uid):
|
||||
self.deletemessages([uid])
|
||||
|
@ -170,12 +170,13 @@ class MaildirFolder(BaseFolder):
|
||||
attempts += 1
|
||||
else:
|
||||
break
|
||||
file = open(os.path.join(tmpdir, messagename), "wt")
|
||||
tmpmessagename = messagename.split(',')[0]
|
||||
file = open(os.path.join(tmpdir, tmpmessagename), "wt")
|
||||
file.write(content)
|
||||
file.close()
|
||||
os.link(os.path.join(tmpdir, messagename),
|
||||
os.link(os.path.join(tmpdir, tmpmessagename),
|
||||
os.path.join(newdir, messagename))
|
||||
os.unlink(os.path.join(tmpdir, messagename))
|
||||
os.unlink(os.path.join(tmpdir, tmpmessagename))
|
||||
self.messagelist[uid] = {'uid': uid, 'flags': [],
|
||||
'filename': os.path.join(newdir, messagename)}
|
||||
self.savemessageflags(uid, flags)
|
||||
|
@ -63,13 +63,13 @@ class BlinkenBase:
|
||||
s.gettf().setcolor('red')
|
||||
s.__class__.__bases__[-1].deletingmessage(s, uid, destlist)
|
||||
|
||||
def addingflags(s, uid, flags, destlist):
|
||||
def addingflags(s, uidlist, flags, destlist):
|
||||
s.gettf().setcolor('yellow')
|
||||
s.__class__.__bases__[-1].addingflags(s, uid, flags, destlist)
|
||||
s.__class__.__bases__[-1].addingflags(s, uidlist, flags, destlist)
|
||||
|
||||
def deletingflags(s, uid, flags, destlist):
|
||||
def deletingflags(s, uidlist, flags, destlist):
|
||||
s.gettf().setcolor('pink')
|
||||
s.__class__.__bases__[-1].deletingflags(s, uid, flags, destlist)
|
||||
s.__class__.__bases__[-1].deletingflags(s, uidlist, flags, destlist)
|
||||
|
||||
def init_banner(s):
|
||||
s.availablethreadframes = {}
|
||||
|
@ -221,17 +221,17 @@ class UIBase:
|
||||
", ".join([str(u) for u in uidlist]),
|
||||
ds))
|
||||
|
||||
def addingflags(s, uid, flags, destlist):
|
||||
def addingflags(s, uidlist, flags, destlist):
|
||||
if s.verbose >= 0:
|
||||
ds = s.folderlist(destlist)
|
||||
s._msg("Adding flags %s to message %d on %s" % \
|
||||
(", ".join(flags), uid, ds))
|
||||
s._msg("Adding flags %s to %d messages on %s" % \
|
||||
(", ".join(flags), len(uidlist), ds))
|
||||
|
||||
def deletingflags(s, uid, flags, destlist):
|
||||
def deletingflags(s, uidlist, flags, destlist):
|
||||
if s.verbose >= 0:
|
||||
ds = s.folderlist(destlist)
|
||||
s._msg("Deleting flags %s to message %d on %s" % \
|
||||
(", ".join(flags), uid, ds))
|
||||
s._msg("Deleting flags %s to %d messages on %s" % \
|
||||
(", ".join(flags), len(uidlist), ds))
|
||||
|
||||
################################################## Threads
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user