1 import threading, pickle, inspect, atexit
2 from . import db, index, cache
5 __all__ = ["environment", "datastore", "autostore"]
7 class environment(object):
8 def __init__(self, *, path=None, getpath=None, recover=False):
14 self.getpath = getpath
15 self.recover = recover
16 self.lk = threading.Lock()
23 self.path = self.getpath()
24 self.bk = db.environment(self.path, recover=self.recover)
25 atexit.register(self.close)
30 if self.bk is not None:
31 atexit.unregister(self.close)
35 class storedesc(object):
40 ret = t.__dict__.get("__didex_attr")
43 for st in inspect.getmro(t):
44 for nm, val in st.__dict__.items():
45 if isinstance(val, storedesc):
50 class datastore(object):
51 def __init__(self, name, *, env=None, path=".", ncache=None):
53 self.lk = threading.Lock()
57 self.env = environment(path=path)
60 ncache = cache.cache()
62 self.cache.load = self._load
67 self._db = self.env().db(self.name)
72 return pickle.loads(self.db().get(id))
74 raise KeyError(id, "could not unpickle data")
76 def _encode(self, obj):
77 return pickle.dumps(obj)
79 def get(self, id, *, load=True):
80 return self.cache.get(id, load=load)
82 @txnfun(lambda self: self.db().env.env)
83 def register(self, obj, *, tx):
84 id = self.db().add(self._encode(obj), tx=tx)
85 for nm, attr in storedescs(obj):
86 attr.register(id, obj, tx)
87 self.cache.put(id, obj)
90 @txnfun(lambda self: self.db().env.env)
91 def unregister(self, id, *, vfy=None, tx):
93 if vfy is not None and obj is not vfy:
94 raise RuntimeError("object identity crisis: " + str(vfy) + " is not cached object " + obj)
95 for nm, attr in storedescs(obj):
96 attr.unregister(id, obj, tx)
97 self.db().remove(id, tx=tx)
100 @txnfun(lambda self: self.db().env.env)
101 def update(self, id, *, vfy=None, tx):
102 obj = self.get(id, load=False)
103 if vfy is not None and obj is not vfy:
104 raise RuntimeError("object identity crisis: " + str(vfy) + " is not cached object " + obj)
105 for nm, attr, in storedescs(obj):
106 attr.update(id, obj, tx)
107 self.db().replace(id, self._encode(obj), tx=tx)
109 class autotype(type):
110 def __call__(self, *args, **kwargs):
111 new = super().__call__(*args, **kwargs)
112 new.id = self.store.register(new)
113 self.store.update(new.id, vfy=new) # This doesn't feel too nice.
116 class autostore(object, metaclass=autotype):
121 self.store.update(self.id, vfy=self)
124 self.store.unregister(self.id, vfy=self)