Improved environment initialization.
[didex.git] / didex / store.py
1 import threading, pickle
2 from . import db, index, cache
3 from .db import txnfun
4
5 class environment(object):
6     def __init__(self, *, path=None, getpath=None, recover=False):
7         if path is not None:
8             self.path = path
9             self.getpath = None
10         else:
11             self.path = None
12             self.getpath = getpath
13         self.recover = recover
14         self.lk = threading.Lock()
15         self.bk = None
16
17     def __call__(self):
18         with self.lk:
19             if self.bk is None:
20                 if self.path is None:
21                     self.path = self.getpath()
22                 self.bk = db.environment(self.path, recover=self.recover)
23             return self.bk
24
25     def close(self):
26         with self.lk:
27             if self.bk is not None:
28                 self.bk.close()
29                 self.bk = None
30
31 class storedesc(object):
32     pass
33
34 def storedescs(obj):
35     t = type(obj)
36     ret = getattr(t, "__didex_attr", None)
37     if ret is None:
38         ret = []
39         for nm, val in t.__dict__.items():
40             if isinstance(val, storedesc):
41                 ret.append((nm, val))
42         t.__didex_attr = ret
43     return ret
44
45 class store(object):
46     def __init__(self, name, *, env=None, path=".", ncache=None):
47         self.name = name
48         self.lk = threading.Lock()
49         if env:
50             self.env = env
51         else:
52             self.env = environment(path=path)
53         self._db = None
54         if ncache is None:
55             ncache = cache.cache()
56         self.cache = ncache
57         self.cache.load = self._load
58
59     def db(self):
60         with self.lk:
61             if self._db is None:
62                 self._db = self.env().db(self.name)
63             return self._db
64
65     def _load(self, id):
66         try:
67             return pickle.loads(self.db().get(id))
68         except:
69             raise KeyError(id, "could not unpickle data")
70
71     def _encode(self, obj):
72         return pickle.dumps(obj)
73
74     def get(self, id, *, load=True):
75         return self.cache.get(id, load=load)
76
77     @txnfun(lambda self: self.db().env.env)
78     def register(self, obj, *, tx):
79         id = self.db().add(self._encode(obj), tx=tx)
80         for nm, attr in storedescs(obj):
81             attr.register(id, obj, tx)
82         self.cache.put(id, obj)
83         return id
84
85     @txnfun(lambda self: self.db().env.env)
86     def unregister(self, id, *, tx):
87         obj = self.get(id)
88         for nm, attr in storedescs(obj):
89             attr.unregister(id, obj, tx)
90         self.db().remove(id, tx=tx)
91         self.cache.remove(id)
92
93     @txnfun(lambda self: self.db().env.env)
94     def update(self, id, *, tx):
95         obj = self.get(id, load=False)
96         for nm, attr, in storedescs(obj):
97             attr.update(id, obj, tx)
98         self.db().replace(id, self._encode(obj), tx=tx)