Instead of inserting the path of the apps into the Python app, the apps are now referenced by their full import path. This app name claves with external or native Python libraries. Example: Mayan statistics app vs. Python new statistics library. Every app reference is now prepended with 'mayan.apps'. Existing config.yml files need to be updated manually. Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
124 lines
3.6 KiB
Python
124 lines
3.6 KiB
Python
from __future__ import unicode_literals
|
|
|
|
import hashlib
|
|
import logging
|
|
import json
|
|
import os
|
|
import threading
|
|
import time
|
|
import uuid
|
|
|
|
from django.conf import settings
|
|
from django.core.files import locks
|
|
from django.utils.encoding import force_bytes, force_text
|
|
|
|
from mayan.apps.common.settings import setting_temporary_directory
|
|
|
|
from ..exceptions import LockError
|
|
from ..settings import setting_default_lock_timeout
|
|
|
|
from .base import LockingBackend
|
|
|
|
lock = threading.Lock()
|
|
logger = logging.getLogger(__name__)
|
|
|
|
lock_file = os.path.join(
|
|
setting_temporary_directory.value, hashlib.sha256(force_bytes(settings.SECRET_KEY)).hexdigest()
|
|
)
|
|
open(lock_file, 'a').close()
|
|
logger.debug('lock_file: %s', lock_file)
|
|
|
|
|
|
class FileLock(LockingBackend):
|
|
lock_file = lock_file
|
|
|
|
@classmethod
|
|
def acquire_lock(cls, name, timeout=None):
|
|
super(FileLock, cls).acquire_lock(name=name, timeout=timeout)
|
|
instance = FileLock(
|
|
name=name, timeout=timeout or setting_default_lock_timeout.value
|
|
)
|
|
return instance
|
|
|
|
@classmethod
|
|
def purge_locks(cls):
|
|
super(FileLock, cls).purge_locks()
|
|
lock.acquire()
|
|
with open(cls.lock_file, 'r+') as file_object:
|
|
locks.lock(f=file_object, flags=locks.LOCK_EX)
|
|
file_object.seek(0)
|
|
file_object.truncate()
|
|
lock.release()
|
|
|
|
def _get_lock_dictionary(self):
|
|
if self.timeout:
|
|
result = {
|
|
'expiration': time.time() + self.timeout,
|
|
'uuid': self.uuid
|
|
}
|
|
else:
|
|
result = {
|
|
'expiration': 0,
|
|
'uuid': self.uuid
|
|
}
|
|
|
|
return result
|
|
|
|
def __init__(self, name, timeout=None):
|
|
self.name = name
|
|
self.timeout = timeout or setting_default_lock_timeout.value
|
|
self.uuid = force_text(uuid.uuid4())
|
|
|
|
lock.acquire()
|
|
with open(self.__class__.lock_file, 'r+') as file_object:
|
|
locks.lock(f=file_object, flags=locks.LOCK_EX)
|
|
|
|
data = file_object.read()
|
|
|
|
if data:
|
|
file_locks = json.loads(data)
|
|
else:
|
|
file_locks = {}
|
|
|
|
if name in file_locks:
|
|
# Someone already got this lock, check to see if it is expired
|
|
if file_locks[name]['expiration'] and time.time() > file_locks[name]['expiration']:
|
|
# It expires and has expired, we re-acquired it
|
|
file_locks[name] = self._get_lock_dictionary()
|
|
else:
|
|
lock.release()
|
|
raise LockError
|
|
else:
|
|
file_locks[name] = self._get_lock_dictionary()
|
|
|
|
file_object.seek(0)
|
|
file_object.truncate()
|
|
file_object.write(json.dumps(file_locks))
|
|
lock.release()
|
|
|
|
def release(self):
|
|
super(FileLock, self).release()
|
|
|
|
lock.acquire()
|
|
with open(self.__class__.lock_file, 'r+') as file_object:
|
|
locks.lock(f=file_object, flags=locks.LOCK_EX)
|
|
try:
|
|
file_locks = json.loads(file_object.read())
|
|
except EOFError:
|
|
file_locks = {}
|
|
|
|
if self.name in file_locks:
|
|
if file_locks[self.name]['uuid'] == self.uuid:
|
|
file_locks.pop(self.name)
|
|
else:
|
|
# Lock expired and someone else acquired it
|
|
pass
|
|
else:
|
|
# Lock expired and someone else released it
|
|
pass
|
|
|
|
file_object.seek(0)
|
|
file_object.truncate()
|
|
file_object.write(json.dumps(file_locks))
|
|
lock.release()
|