Skip to content

Commit

Permalink
Implement atomic transaction support
Browse files Browse the repository at this point in the history
Starting in django1.6 and required for django1.8,
use atomic transactions instead of the deprecated
unless_managed. Specify django1.6 in setup.py.
  • Loading branch information
codehelp committed Feb 25, 2015
1 parent f71c2cc commit a99ab98
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 14 deletions.
30 changes: 18 additions & 12 deletions django_kvstore/backends/db.py
Expand Up @@ -15,17 +15,22 @@
"""

import base64
import logging
from django_kvstore.backends.base import BaseStorage
from django.db import connection, transaction, DatabaseError
from django.db.utils import IntegrityError

try:
import cPickle as pickle
except ImportError:
import pickle


class StorageClass(BaseStorage):
def __init__(self, table, params):
BaseStorage.__init__(self, params)
self._table = table
self.logger = logging.getLogger(__name__)

def get(self, key):
cursor = connection.cursor()
Expand All @@ -37,24 +42,25 @@ def get(self, key):

def set(self, key, value):
encoded = base64.encodestring(pickle.dumps(value, 2)).strip()
cursor = connection.cursor()
cursor.execute("SELECT kee FROM %s WHERE kee = %%s" % self._table, [key])
# report database errors after the atomic transaction has rolled back
try:
if cursor.fetchone():
cursor.execute("UPDATE %s SET value = %%s WHERE kee = %%s" % self._table, [encoded, key])
else:
cursor.execute("INSERT INTO %s (kee, value) VALUES (%%s, %%s)" % self._table, [key, encoded])
except DatabaseError, e:
# To be threadsafe, updates/inserts are allowed to fail silently
with transaction.atomic():
cursor = connection.cursor()
cursor.execute("SELECT kee FROM %s WHERE kee = %%s" % self._table, [key])
if cursor.fetchone():
cursor.execute("UPDATE %s SET value = %%s WHERE kee = %%s" % self._table, [encoded, key])
else:
cursor.execute("INSERT INTO %s (kee, value) VALUES (%%s, %%s)" % self._table, [key, encoded])
except (DatabaseError, IntegrityError):
# Report the atomic failure
self.logger.info("set operation for %s failed and has been rolled back", key)
return False
else:
transaction.commit_unless_managed()
return True
return True

@transaction.atomic()
def delete(self, key):
cursor = connection.cursor()
cursor.execute("DELETE FROM %s WHERE kee = %%s" % self._table, [key])
transaction.commit_unless_managed()

def has_key(self, key):
cursor = connection.cursor()
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Expand Up @@ -63,6 +63,6 @@
provides=['django_kvstore'],
include_package_data=True,
zip_safe=True,
requires=['Django(>=1.1.1)'],
install_requires=['Django>=1.1.1'],
requires=['Django(>=1.6)'],
install_requires=['Django>=1.6'],
)

0 comments on commit a99ab98

Please sign in to comment.