Lock the data directory to avoid concurent modification of XML files

This commit is contained in:
nemunaire 2015-01-05 02:49:21 +01:00
parent 06c85289e0
commit 38aea5dd37

View File

@ -20,6 +20,7 @@ from datetime import datetime, timedelta, timezone
import imp import imp
import ipaddress import ipaddress
import logging import logging
import os
from queue import Queue from queue import Queue
import re import re
from select import select from select import select
@ -64,7 +65,8 @@ class Bot(threading.Thread):
# Context paths # Context paths
self.modules_paths = modules_paths self.modules_paths = modules_paths
self.data_path = data_path self.data_path = None
self.set_data_path(data_path)
# Keep global context: servers and modules # Keep global context: servers and modules
self.servers = dict() self.servers = dict()
@ -177,6 +179,52 @@ class Bot(threading.Thread):
logger.exception("Uncatched exception on server read") logger.exception("Uncatched exception on server read")
# Data path
def set_data_path(self, path):
"""Check if the given path is valid and unlock,
then lock the directory and set the variable
Argument:
path -- the location
"""
lock_file = os.path.join(path, ".used_by_nemubot")
if os.path.isdir(path):
if not os.path.exists(lock_file):
if self.data_path is not None:
self.close_data_path(self.data_path)
self.data_path = path
with open(lock_file, 'w') as lf:
lf.write(str(os.getpid()))
return True
else:
with open(lock_file, 'r') as lf:
pid = lf.readline()
raise Exception("Data dir already locked, by PID %s" % pid)
return False
def close_data_path(self, path=None):
"""Release a locked path
Argument:
path -- the location, self.data_path if None
"""
if path is None:
path = self.data_path
lock_file = os.path.join(path, ".used_by_nemubot")
if os.path.isdir(path) and os.path.exists(lock_file):
os.unlink(lock_file)
return True
return False
# Events methods # Events methods
def add_event(self, evt, eid=None, module_src=None): def add_event(self, evt, eid=None, module_src=None):
@ -406,6 +454,9 @@ class Bot(threading.Thread):
def quit(self): def quit(self):
"""Save and unload modules and disconnect servers""" """Save and unload modules and disconnect servers"""
self.close_data_path()
if self.event_timer is not None: if self.event_timer is not None:
logger.info("Stop the event timer...") logger.info("Stop the event timer...")
self.event_timer.cancel() self.event_timer.cancel()
@ -440,6 +491,7 @@ def hotswap(bak):
bak.stop = True bak.stop = True
if bak.event_timer is not None: if bak.event_timer is not None:
bak.event_timer.cancel() bak.event_timer.cancel()
bak.close_data_path()
new = Bot(str(bak.ip), bak.modules_paths, bak.data_path) new = Bot(str(bak.ip), bak.modules_paths, bak.data_path)
new.servers = bak.servers new.servers = bak.servers