From b6d2e95a91e0961b27cf3cce787b183d46f1ff45 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 23 Aug 2011 14:51:57 -0400 Subject: [PATCH 1/2] Initial commit of the lock manager --- apps/lock_manager/__init__.py | 0 apps/lock_manager/models.py | 54 +++++++++++++++++++++++++++++++++++ apps/lock_manager/tests.py | 16 +++++++++++ apps/lock_manager/views.py | 1 + settings.py | 1 + 5 files changed, 72 insertions(+) create mode 100644 apps/lock_manager/__init__.py create mode 100644 apps/lock_manager/models.py create mode 100644 apps/lock_manager/tests.py create mode 100644 apps/lock_manager/views.py diff --git a/apps/lock_manager/__init__.py b/apps/lock_manager/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apps/lock_manager/models.py b/apps/lock_manager/models.py new file mode 100644 index 0000000000..56a2d3e483 --- /dev/null +++ b/apps/lock_manager/models.py @@ -0,0 +1,54 @@ +import datetime + +from django.db import models +from django.utils.translation import ugettext_lazy as _ +from django.db.utils import IntegrityError +from django.db import transaction + + +class LockError(Exception): + pass + +class LockManager(models.Manager): + @transaction.commit_manually + def acquire_lock(self, name): + lock = self.model(name=name) + try: + lock.save(force_insert=True) + except IntegrityError: + transaction.rollback() + # There is already an existing lock + # Check it's expiration date and if expired delete it and + # re-create it + lock = Lock.objects.get(name=name) + if datetime.datetime.now() > lock.creation_datetime + datetime.timedelta(seconds=lock.expiration): + release_lock(self) + lock.save() + else: + raise LockError('Unable to acquire lock') + else: + transaction.commit() + + @transaction.commit_manually + def release_lock(self, name): + lock = Lock.objects.get(name=name) + lock.delete() + transaction.commit() + +class Lock(models.Model): + creation_datetime = models.DateTimeField(verbose_name=_(u'creation datetime')) + expiration_time = models.IntegerField(default=3600, verbose_name=_(u'expiration time')) + name = models.CharField(max_length=32, verbose_name=_(u'name'), unique=True) + + objects = LockManager() + + def __unicode__(self): + return self.name + + def save(self, *args, **kwargs): + self.creation_datetime = datetime.datetime.now() + super(Lock, self).save(*args, **kwargs) + + class Meta: + verbose_name = _(u'lock') + verbose_name_plural = _(u'locks') diff --git a/apps/lock_manager/tests.py b/apps/lock_manager/tests.py new file mode 100644 index 0000000000..501deb776c --- /dev/null +++ b/apps/lock_manager/tests.py @@ -0,0 +1,16 @@ +""" +This file demonstrates writing tests using the unittest module. These will pass +when you run "manage.py test". + +Replace this with more appropriate tests for your application. +""" + +from django.test import TestCase + + +class SimpleTest(TestCase): + def test_basic_addition(self): + """ + Tests that 1 + 1 always equals 2. + """ + self.assertEqual(1 + 1, 2) diff --git a/apps/lock_manager/views.py b/apps/lock_manager/views.py new file mode 100644 index 0000000000..60f00ef0ef --- /dev/null +++ b/apps/lock_manager/views.py @@ -0,0 +1 @@ +# Create your views here. diff --git a/settings.py b/settings.py index 32867a3281..baf47dd19a 100644 --- a/settings.py +++ b/settings.py @@ -129,6 +129,7 @@ INSTALLED_APPS = ( 'project_tools', 'smart_settings', 'navigation', + 'lock_manager', 'web_theme', 'common', 'metadata', From 9185ed335dc1d3daf0b4b4c774aab1077bb280a4 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 23 Aug 2011 17:34:05 -0400 Subject: [PATCH 2/2] lock manager app updates --- apps/lock_manager/conf/__init__.py | 0 apps/lock_manager/conf/settings.py | 5 +++ apps/lock_manager/exceptions.py | 2 ++ apps/lock_manager/managers.py | 52 ++++++++++++++++++++++++++++++ apps/lock_manager/models.py | 34 ++----------------- 5 files changed, 62 insertions(+), 31 deletions(-) create mode 100644 apps/lock_manager/conf/__init__.py create mode 100644 apps/lock_manager/conf/settings.py create mode 100644 apps/lock_manager/exceptions.py create mode 100644 apps/lock_manager/managers.py diff --git a/apps/lock_manager/conf/__init__.py b/apps/lock_manager/conf/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apps/lock_manager/conf/settings.py b/apps/lock_manager/conf/settings.py new file mode 100644 index 0000000000..05f4ae374c --- /dev/null +++ b/apps/lock_manager/conf/settings.py @@ -0,0 +1,5 @@ +from django.conf import settings + +DEFAULT_LOCK_TIMEOUT_VALUE = 10 + +DEFAULT_LOCK_TIMEOUT = getattr(settings, 'LOCK_MANAGER_DEFAULT_LOCK_TIMEOUT', DEFAULT_LOCK_TIMEOUT_VALUE) diff --git a/apps/lock_manager/exceptions.py b/apps/lock_manager/exceptions.py new file mode 100644 index 0000000000..cede7b1642 --- /dev/null +++ b/apps/lock_manager/exceptions.py @@ -0,0 +1,2 @@ +class LockError(Exception): + pass diff --git a/apps/lock_manager/managers.py b/apps/lock_manager/managers.py new file mode 100644 index 0000000000..96c57ca02b --- /dev/null +++ b/apps/lock_manager/managers.py @@ -0,0 +1,52 @@ +try: + from psycopg2 import OperationalError +except ImportError: + class OperationalError(Exception): + pass + +import datetime + +from django.db.utils import DatabaseError +from django.db.utils import IntegrityError +from django.db import transaction +from django.db import models + +from lock_manager.exceptions import LockError + + +class LockManager(models.Manager): + @transaction.commit_manually + def acquire_lock(self, name, timeout=None): + lock = self.model(name=name, timeout=timeout) + try: + lock.save(force_insert=True) + except IntegrityError: + transaction.rollback() + # There is already an existing lock + # Check it's expiration date and if expired, delete it and + # create it again + lock = self.model.objects.get(name=name) + transaction.rollback() + + if datetime.datetime.now() > lock.creation_datetime + datetime.timedelta(seconds=lock.timeout): + self.release_lock(name) + lock.timeout=timeout + lock.save() + transaction.commit() + else: + raise LockError('Unable to acquire lock') + except DatabaseError: + transaction.rollback() + # Special case for ./manage.py syncdb + except (OperationalError, ImproperlyConfigured): + transaction.rollback() + # Special for DjangoZoom, which executes collectstatic media + # doing syncdb and creating the database tables + else: + transaction.commit() + + @transaction.commit_manually + def release_lock(self, name): + lock = self.model.objects.get(name=name) + lock.delete() + transaction.commit() diff --git a/apps/lock_manager/models.py b/apps/lock_manager/models.py index 56a2d3e483..53c6b6e49d 100644 --- a/apps/lock_manager/models.py +++ b/apps/lock_manager/models.py @@ -2,42 +2,14 @@ import datetime from django.db import models from django.utils.translation import ugettext_lazy as _ -from django.db.utils import IntegrityError -from django.db import transaction +from lock_manager.managers import LockManager +from lock_manager.conf.settings import DEFAULT_LOCK_TIMEOUT -class LockError(Exception): - pass - -class LockManager(models.Manager): - @transaction.commit_manually - def acquire_lock(self, name): - lock = self.model(name=name) - try: - lock.save(force_insert=True) - except IntegrityError: - transaction.rollback() - # There is already an existing lock - # Check it's expiration date and if expired delete it and - # re-create it - lock = Lock.objects.get(name=name) - if datetime.datetime.now() > lock.creation_datetime + datetime.timedelta(seconds=lock.expiration): - release_lock(self) - lock.save() - else: - raise LockError('Unable to acquire lock') - else: - transaction.commit() - - @transaction.commit_manually - def release_lock(self, name): - lock = Lock.objects.get(name=name) - lock.delete() - transaction.commit() class Lock(models.Model): creation_datetime = models.DateTimeField(verbose_name=_(u'creation datetime')) - expiration_time = models.IntegerField(default=3600, verbose_name=_(u'expiration time')) + timeout = models.IntegerField(default=DEFAULT_LOCK_TIMEOUT, verbose_name=_(u'timeout')) name = models.CharField(max_length=32, verbose_name=_(u'name'), unique=True) objects = LockManager()