Made the transactional database functions accept an optional external transaction.
authorFredrik Tolf <fredrik@dolda2000.com>
Wed, 18 Mar 2015 06:20:34 +0000 (07:20 +0100)
committerFredrik Tolf <fredrik@dolda2000.com>
Wed, 18 Mar 2015 06:20:34 +0000 (07:20 +0100)
didex/db.py
didex/index.py

index 224cb2f..75aee02 100644 (file)
@@ -81,6 +81,23 @@ class txn(object):
             self.abort()
         return False
 
+def txnfun(envfun):
+    def fxf(fun):
+        def wrapper(self, *args, tx=None, **kwargs):
+            if tx is None:
+                while True:
+                    try:
+                        with txn(envfun(self)) as ltx:
+                            ret = fun(self, *args, tx=ltx, **kwargs)
+                            ltx.commit()
+                            return ret
+                    except deadlock:
+                        continue
+            else:
+                return fun(self, *args, tx=tx, **kwargs)
+        return wrapper
+    return fxf
+
 class database(object):
     def __init__(self, env, name, create, mode):
         self.env = env
@@ -102,7 +119,8 @@ class database(object):
                 continue
             return ret
 
-    def _nextseq(self, tx):
+    @txnfun(lambda self: self.env.env)
+    def _nextseq(self, *, tx):
         if self.cf.has_key(b"seq", txn=tx.tx):
             seq = struct.unpack(">Q", self.cf.get(b"seq", txn=tx.tx))[0]
         else:
@@ -110,45 +128,29 @@ class database(object):
         self.cf.put(b"seq", struct.pack(">Q", seq + 1), txn=tx.tx)
         return seq
 
-    def add(self, ob):
-        while True:
-            try:
-                with txn(self.env.env) as tx:
-                    seq = self._nextseq(tx)
-                    self.ob.put(struct.pack(">Q", seq), ob, txn=tx.tx, flags=bd.DB_NOOVERWRITE)
-                    tx.commit()
-                    return seq
-            except deadlock:
-                continue
-
-    def replace(self, id, ob):
-        while True:
-            try:
-                with txn(self.env.env) as tx:
-                    key = struct.pack(">Q", id)
-                    if not self.ob.has_key(key, txn=tx.tx):
-                        raise KeyError(id)
-                    self.ob.put(key, ob, txn=tx.tx)
-                    tx.commit()
-                    return
-            except deadlock:
-                continue
+    @txnfun(lambda self: self.env.env)
+    def add(self, ob, *, tx):
+        seq = self._nextseq(tx=tx)
+        self.ob.put(struct.pack(">Q", seq), ob, txn=tx.tx, flags=bd.DB_NOOVERWRITE)
+        return seq
 
-    def get(self, id):
-        while True:
-            try:
-                return self.ob[struct.pack(">Q", id)]
-            except KeyError:
-                raise KeyError(id) from None
-            except deadlock:
-                continue
+    @txnfun(lambda self: self.env.env)
+    def replace(self, id, ob, *, tx):
+        key = struct.pack(">Q", id)
+        if not self.ob.has_key(key, txn=tx.tx):
+            raise KeyError(id)
+        self.ob.put(key, ob, txn=tx.tx)
+
+    @txnfun(lambda self: self.env.env)
+    def get(self, id, *, tx):
+        ret = self.ob.get(struct.pack(">Q", id), None)
+        if ret is None:
+            raise KeyError(id)
+        return ret
 
-    def remove(self, id):
-        while True:
-            try:
-                with txn(self.env.env) as tx:
-                    self.ob.delete(struct.pack(">Q", id), txn=tx.tx)
-                    tx.commit()
-                    return
-            except deadlock:
-                continue
+    @txnfun(lambda self: self.env.env)
+    def remove(self, id, *, tx):
+        key = struct.pack(">Q", id)
+        if not self.ob.has_key(key, txn=tx.tx):
+            raise KeyError(id)
+        self.ob.delete(key, txn=tx.tx)
index 5d206ff..2f3fdef 100644 (file)
@@ -1,6 +1,6 @@
 import struct, contextlib
 from . import db, lib
-from .db import bd
+from .db import bd, txnfun
 
 deadlock = bd.DBLockDeadlockError
 notfound = bd.DBNotFoundError
@@ -177,39 +177,29 @@ class ordered(index, lib.closable):
             except deadlock:
                 continue
 
-    def put(self, key, id):
-        while True:
-            try:
-                with db.txn(self.db.env.env) as tx:
-                    obid = struct.pack(">Q", id)
-                    if not self.db.ob.has_key(obid, txn=tx.tx):
-                        raise ValueError("no such object in database: " + str(id))
-                    try:
-                        self.bk.put(self.typ.encode(key), obid, txn=tx.tx, flags=bd.DB_NODUPDATA)
-                    except bd.DBKeyExistError:
-                        return False
-                    tx.commit()
-                    return True
-            except deadlock:
-                continue
-
-    def remove(self, key, id):
-        while True:
+    @txnfun(lambda self: self.db.env.env)
+    def put(self, key, id, *, tx):
+        obid = struct.pack(">Q", id)
+        if not self.db.ob.has_key(obid, txn=tx.tx):
+            raise ValueError("no such object in database: " + str(id))
+        try:
+            self.bk.put(self.typ.encode(key), obid, txn=tx.tx, flags=bd.DB_NODUPDATA)
+        except bd.DBKeyExistError:
+            return False
+        return True
+
+    @txnfun(lambda self: self.db.env.env)
+    def remove(self, key, id, *, tx):
+        obid = struct.pack(">Q", id)
+        if not self.db.ob.has_key(obid, txn=tx.tx):
+            raise ValueError("no such object in database: " + str(id))
+        cur = self.bk.cursor(txn=tx.tx)
+        try:
             try:
-                with db.txn(self.db.env.env) as tx:
-                    obid = struct.pack(">Q", id)
-                    if not self.db.ob.has_key(obid, txn=tx.tx):
-                        raise ValueError("no such object in database: " + str(id))
-                    cur = self.bk.cursor(txn=tx.tx)
-                    try:
-                        try:
-                            cur.get_both(self.typ.encode(key), obid)
-                        except notfound:
-                            return False
-                        cur.delete()
-                    finally:
-                        cur.close()
-                    tx.commit()
-                    return True
-            except deadlock:
-                continue
+                cur.get_both(self.typ.encode(key), obid)
+            except notfound:
+                return False
+            cur.delete()
+        finally:
+            cur.close()
+        return True