def __init__(self, ID, *url, **kw): """ Instantiates me with an item store keyed to the supplied hashable I{ID}. Ensures that I have access to a class-wide instance of a L{Search} object so that I can update the database's full-text index when writing values containing text content. In addition to any engine-specifying keywords supplied, the following are particular to this constructor: @param ID: A hashable object that is used as my unique identifier. @keyword search: Set C{True} if text indexing is to be updated when items are added, updated, or deleted. """ try: self.ID = hash(ID) except: raise TypeError("Item IDs must be hashable") # In-memory Caches self.data, self.keyCache = {}, {} # For tracking lazy writes self.writeTracker = DeferredTracker() # My very own persistent items store if url: self.i = items.Items(self.ID, url[0], **kw) else: self.i = items.Items(self.ID) self.isPreloadMode = False
class PersistentDictBase(DictMixin, object): """ I am a base class for a database-persistent dictionary-like object uniquely identified by the hashable constructor argument I{ID}. Before you use any instance of me, you must specify the parameters for creating an SQLAlchemy database engine. A single argument is used, which specifies a connection to a database via an RFC-1738 url. In addition, the following keyword options can be employed, which are listed in the API docs for L{sasync} and L{sasync.database.AccessBroker}. You can set an engine globally, for all instances of me, via the L{sasync.engine} package-level function, or via the L{AccessBroker.engine} class method. Alternatively, you can specify an engine for one particular instance by supplying the parameters to my constructor. In my default mode of operation, both read and write item accesses occur asynchronously and return deferreds. However, you can put me into B{load} mode by calling my L{preload} method. At that point, all my items will be accessed synchronously as with any other dictionary. No other deferreds will be returned from any item access. Lazy writing will still be done, but behind the scenes and with no API access to write completions. B{IMPORTANT}: As with all sasync data store objects, make sure you call my L{shutdown} method for an instance of me that you're done with before allowing that instance to be deleted. @ivar isPreloadMode: Boolean flag that indicates if I am operating in preload mode. """ def __init__(self, ID, *url, **kw): """ Instantiates me with an item store keyed to the supplied hashable I{ID}. Ensures that I have access to a class-wide instance of a L{Search} object so that I can update the database's full-text index when writing values containing text content. In addition to any engine-specifying keywords supplied, the following are particular to this constructor: @param ID: A hashable object that is used as my unique identifier. @keyword search: Set C{True} if text indexing is to be updated when items are added, updated, or deleted. """ try: self.ID = hash(ID) except: raise TypeError("Item IDs must be hashable") # In-memory Caches self.data, self.keyCache = {}, {} # For tracking lazy writes self.writeTracker = DeferredTracker() # My very own persistent items store if url: self.i = items.Items(self.ID, url[0], **kw) else: self.i = items.Items(self.ID) self.isPreloadMode = False def preload(self): """ This method preloads all my items from the database (which may take a while), returning a C{Deferred} that fires when everything's ready and I've completed the transition into B{preload} mode. """ d = self.loadAll() d.addCallback(lambda _: setattr(self, 'isPreloadMode', True)) return d def shutdown(self, *null): """ Shuts down my database L{Transactor} and its synchronous task queue. """ d = self.writeTracker.deferToAll() d.addCallback(self.i.shutdown) return d def loadAll(self, *null): """ Loads all items from the database, setting my in-memory dict and key cache accordingly. """ def loaded(items): self.data.clear() self.data.update(items) self.keyCache = dict.fromkeys(items.keys(), True) return self.data return self.i.loadAll().addCallback(loaded) def deferToWrites(self, lastOnly=False): """ @see: L{DeferredTracker.deferToAll} """ if lastOnly: d = self.writeTracker.deferToLast() else: d = self.writeTracker.deferToAll() return d