[PATCH 3/3] UIDMaps: correctly protect from concurrent writes

Nicolas Sebrecht nicolas.s-dev at laposte.net
Tue Jun 28 14:48:02 BST 2016


Signed-off-by: Nicolas Sebrecht <nicolas.s-dev at laposte.net>
---
 offlineimap/folder/UIDMaps.py | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/offlineimap/folder/UIDMaps.py b/offlineimap/folder/UIDMaps.py
index 038284c..980adfb 100644
--- a/offlineimap/folder/UIDMaps.py
+++ b/offlineimap/folder/UIDMaps.py
@@ -78,10 +78,19 @@ class MappedIMAPFolder(IMAPFolder):
 
     def _savemaps(self):
         mapfilename = self._getmapfilename()
-        with open(mapfilename + ".tmp", 'wt') as mapfilefd:
-            for (key, value) in self.diskl2r.items():
-                mapfilefd.write("%d:%d\n"% (key, value))
-        os.rename(mapfilename + '.tmp', mapfilename)
+        mapfilenamelock = "%s.lock"% mapfilename
+        with open(mapfilenamelock, 'w') as mapfilelock:
+            # The "account" lock already prevents from multiple access by
+            # different processes. However, we still need to protect for
+            # multiple access from different threads.
+            try:
+                fnctl.lockf(mapfilelock, fnctl.LOCK_EX) # Blocks until acquired.
+            except NameError:
+                pass # Windows...
+            with open(mapfilename, 'wt') as mapfilefd:
+                for (key, value) in self.diskl2r.items():
+                    mapfilefd.write("%d:%d\n"% (key, value))
+            # The lock is released when the file descriptor ends.
 
     def _uidlist(self, mapping, items):
         try:
-- 
2.7.4





More information about the OfflineIMAP-project mailing list