XML datastore: new directory locking procedure

This new procedure use fcntl functions to lock the file during the
	life of the datastore instance.

	Now, locked directory error is not displayed if if nemubot is not
	correctly closed.
This commit is contained in:
nemunaire 2015-04-22 17:30:02 +02:00
parent f19dd81a0d
commit 0f2f14ddda

View File

@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import os import fcntl, os
from nemubot.datastore.abstract import Abstract from nemubot.datastore.abstract import Abstract
@ -32,22 +32,35 @@ class XML(Abstract):
if not os.path.isdir(self.basedir): if not os.path.isdir(self.basedir):
os.mkdir(self.basedir) os.mkdir(self.basedir)
lock_file = os.path.join(self.basedir, ".used_by_nemubot") lock_path = os.path.join(self.basedir, ".used_by_nemubot")
if os.path.exists(lock_file):
with open(lock_file, 'r') as lf: self.lock_file = open(lock_path, 'a+')
ok = True
try:
fcntl.lockf(self.lock_file, fcntl.LOCK_EX | fcntl.LOCK_NB)
except OSError:
ok = False
if not ok:
with open(lock_path, 'r') as lf:
pid = lf.readline() pid = lf.readline()
raise Exception("Data dir already locked, by PID %s" % pid) raise Exception("Data dir already locked, by PID %s" % pid)
with open(lock_file, 'w') as lf: self.lock_file.truncate()
lf.write(str(os.getpid())) self.lock_file.write(str(os.getpid()))
self.lock_file.flush()
return True return True
def close(self): def close(self):
"""Release a locked path""" """Release a locked path"""
lock_file = os.path.join(self.basedir, ".used_by_nemubot") if hasattr(self, "lock_file"):
if os.path.isdir(self.basedir) and os.path.exists(lock_file): self.lock_file.close()
os.unlink(lock_file) lock_path = os.path.join(self.basedir, ".used_by_nemubot")
if os.path.isdir(self.basedir) and os.path.exists(lock_path):
os.unlink(lock_path)
del self.lock_file
return True return True
return False return False