SQLite: avoid concurrent writes on backend migration

The saveall() method must acquire the lock to make writes.

Reported-and-tested-by: Julien Cubizolles <j.cubizolles@free.fr>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
This commit is contained in:
Nicolas Sebrecht 2017-01-31 01:41:26 +01:00
parent 23b497d191
commit 4df06d57c3
2 changed files with 13 additions and 11 deletions

View File

@ -1,5 +1,5 @@
# Local status cache virtual folder: SQLite backend # Local status cache virtual folder: SQLite backend
# Copyright (C) 2009-2016 Stewart Smith and contributors. # Copyright (C) 2009-2017 Stewart Smith and contributors.
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -282,16 +282,17 @@ class LocalStatusSQLiteFolder(BaseFolder):
def saveall(self): def saveall(self):
"""Saves the entire messagelist to the database.""" """Saves the entire messagelist to the database."""
data = [] with self._databaseFileLock.getLock():
for uid, msg in self.messagelist.items(): data = []
mtime = msg['mtime'] for uid, msg in self.messagelist.items():
flags = ''.join(sorted(msg['flags'])) mtime = msg['mtime']
labels = ', '.join(sorted(msg['labels'])) flags = ''.join(sorted(msg['flags']))
data.append((uid, flags, mtime, labels)) labels = ', '.join(sorted(msg['labels']))
data.append((uid, flags, mtime, labels))
self.__sql_write('INSERT OR REPLACE INTO status ' self.__sql_write('INSERT OR REPLACE INTO status '
'(id,flags,mtime,labels) VALUES (?,?,?,?)', '(id,flags,mtime,labels) VALUES (?,?,?,?)',
data, executemany=True) data, executemany=True)
# Following some pure SQLite functions, where we chose to use # Following some pure SQLite functions, where we chose to use

View File

@ -1,5 +1,5 @@
# Local status cache repository support # Local status cache repository support
# Copyright (C) 2002-2016 John Goerzen & contributors # Copyright (C) 2002-2017 John Goerzen & contributors
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -21,6 +21,7 @@ from offlineimap.folder.LocalStatus import LocalStatusFolder
from offlineimap.folder.LocalStatusSQLite import LocalStatusSQLiteFolder from offlineimap.folder.LocalStatusSQLite import LocalStatusSQLiteFolder
from offlineimap.repository.Base import BaseRepository from offlineimap.repository.Base import BaseRepository
class LocalStatusRepository(BaseRepository): class LocalStatusRepository(BaseRepository):
def __init__(self, reposname, account): def __init__(self, reposname, account):
BaseRepository.__init__(self, reposname, account) BaseRepository.__init__(self, reposname, account)