From 8950191cebfc907b7ec9a643b71d6734d90f4e9b Mon Sep 17 00:00:00 2001 From: Fredrik Tolf Date: Wed, 18 Mar 2015 07:20:34 +0100 Subject: [PATCH] Made the transactional database functions accept an optional external transaction. --- didex/db.py | 84 ++++++++++++++++++++++++++++++---------------------------- didex/index.py | 62 ++++++++++++++++++------------------------- 2 files changed, 69 insertions(+), 77 deletions(-) diff --git a/didex/db.py b/didex/db.py index 224cb2f..75aee02 100644 --- a/didex/db.py +++ b/didex/db.py @@ -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) diff --git a/didex/index.py b/didex/index.py index 5d206ff..2f3fdef 100644 --- a/didex/index.py +++ b/didex/index.py @@ -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 -- 2.11.0