Improve filesystem flushing semantics

fsync the Maildir file, its final directory when writing a new message.

fsync the localstatus file and its final directory when writing the 
local status cache.

This should reduce duplication in the event of hardware trouble.

fixes 

see thread at http://lists.complete.org/offlineimap@complete.org/2007/03/threads.html.gz
This commit is contained in:
John Goerzen 2007-03-28 21:23:18 +01:00
parent 4b564bd568
commit 4f54887265
2 changed files with 26 additions and 2 deletions
offlineimap/folder

@ -1,5 +1,5 @@
# Local status cache virtual folder
# Copyright (C) 2002 - 2003 John Goerzen
# Copyright (C) 2002 - 2007 John Goerzen
# <jgoerzen@complete.org>
#
# This program is free software; you can redistribute it and/or modify
@ -90,8 +90,18 @@ class LocalStatusFolder(BaseFolder):
flags.sort()
flags = ''.join(flags)
file.write("%s:%s\n" % (msg['uid'], flags))
file.flush()
os.fsync(file.fileno())
file.close()
os.rename(self.filename + ".tmp", self.filename)
try:
fd = os.open(os.path.dirname(self.filename), os.O_RDONLY)
os.fsync(fd)
os.close(fd)
except:
pass
finally:
self.savelock.release()

@ -1,5 +1,5 @@
# Maildir folder support
# Copyright (C) 2002 - 2006 John Goerzen
# Copyright (C) 2002 - 2007 John Goerzen
# <jgoerzen@complete.org>
#
# This program is free software; you can redistribute it and/or modify
@ -169,6 +169,11 @@ class MaildirFolder(BaseFolder):
ui.debug('maildir', 'savemessage: using temporary name %s' % tmpmessagename)
file = open(os.path.join(tmpdir, tmpmessagename), "wt")
file.write(content)
# Make sure the data hits the disk
file.flush()
os.fsync(file.fileno())
file.close()
if rtime != None:
os.utime(os.path.join(tmpdir,tmpmessagename), (rtime,rtime))
@ -177,6 +182,15 @@ class MaildirFolder(BaseFolder):
os.link(os.path.join(tmpdir, tmpmessagename),
os.path.join(newdir, messagename))
os.unlink(os.path.join(tmpdir, tmpmessagename))
try:
# fsync the directory (safer semantics in Linux)
fd = os.open(newdir, os.O_RDONLY)
os.fsync(fd)
os.close(fd)
except:
pass
self.messagelist[uid] = {'uid': uid, 'flags': [],
'filename': os.path.join(newdir, messagename)}
self.savemessageflags(uid, flags)