Added live-object store and simple indexing.
[didex.git] / didex / store.py
diff --git a/didex/store.py b/didex/store.py
new file mode 100644 (file)
index 0000000..15d2eca
--- /dev/null
@@ -0,0 +1,90 @@
+import threading, pickle
+from . import db, index, cache
+from .db import txnfun
+
+class environment(object):
+    def __init__(self, path):
+        self.path = path
+        self.lk = threading.Lock()
+        self.bk = None
+
+    def __call__(self):
+        with self.lk:
+            if self.bk is None:
+                self.bk = db.environment(self.path)
+            return self.bk
+
+    def close(self):
+        with self.lk:
+            if self.bk is not None:
+                self.bk.close()
+                self.bk = None
+
+class storedesc(object):
+    pass
+
+def storedescs(obj):
+    t = type(obj)
+    ret = getattr(t, "__didex_attr", None)
+    if ret is None:
+        ret = []
+        for nm, val in t.__dict__.items():
+            if isinstance(val, storedesc):
+                ret.append((nm, val))
+        t.__didex_attr = ret
+    return ret
+
+class store(object):
+    def __init__(self, name, *, env=None, path=".", ncache=None):
+        self.name = name
+        self.lk = threading.Lock()
+        if env:
+            self.env = env
+        else:
+            self.env = environment(path)
+        self._db = None
+        if ncache is None:
+            ncache = cache.cache()
+        self.cache = ncache
+        self.cache.load = self._load
+
+    def db(self):
+        with self.lk:
+            if self._db is None:
+                self._db = self.env().db(self.name)
+            return self._db
+
+    def _load(self, id):
+        try:
+            return pickle.loads(self.db().get(id))
+        except:
+            raise KeyError(id, "could not unpickle data")
+
+    def _encode(self, obj):
+        return pickle.dumps(obj)
+
+    def get(self, id, *, load=True):
+        return self.cache.get(id, load=load)
+
+    @txnfun(lambda self: self.db().env.env)
+    def register(self, obj, *, tx):
+        id = self.db().add(self._encode(obj), tx=tx)
+        for nm, attr in storedescs(obj):
+            attr.register(id, obj, tx)
+        self.cache.put(id, obj)
+        return id
+
+    @txnfun(lambda self: self.db().env.env)
+    def unregister(self, id, *, tx):
+        obj = self.get(id)
+        for nm, attr in storedescs(obj):
+            attr.unregister(id, obj, tx)
+        self.db().remove(id, tx=tx)
+        self.cache.remove(id)
+
+    @txnfun(lambda self: self.db().env.env)
+    def update(self, id, *, tx):
+        obj = self.get(id, load=False)
+        for nm, attr, in storedescs(obj):
+            attr.update(id, obj, tx)
+        self.db().replace(id, self._encode(obj), tx=tx)