o k`'@sddlZddlmZddlmZmZddgZiZddZGdd d e Z Gd d d e Z Gd d d e Z dddZ GdddeZdS)N) Component) ThreadLocal threading CacheManagercachedcCsN|r t|dd>nd}|D] }d|d@t|A}q|t|N}|t|<|S)z(Return a hash of the given property key.riCBi)ordlen _id_to_key)sresultcr,/usr/lib/python3/dist-packages/trac/cache.py key_to_ids  rc@ eZdZdZddZddZdS)CachedPropertyBasez]Base class for cached property descriptors. :since 1.0.2: inherits from `property`. cCs||_t||dSN) retriever functoolsupdate_wrapper)selfrrrr__init__*szCachedPropertyBase.__init__cCs@|jj}|D]}|j||ur|}nqd|j|j|fS)Nz%s.%s.%s)r__name__mro__dict__get __module__)rclsattrbaserrrmake_key.s zCachedPropertyBase.make_keyN)rr __qualname____doc__rr!rrrrr$s rc@r)CachedSingletonPropertyaCached property descriptor for classes behaving as singletons in the scope of one `~trac.env.Environment` instance. This means there will be no more than one cache to monitor in the database for this kind of cache. Therefore, using only "static" information for the key is enough. For the same reason it is also safe to store the corresponding id as a property of the descriptor instance. cCsT|dur|Sz|j}Wntyt||}|_Ynwt|j||j|Sr)idAttributeErrorrr!renvrrrinstanceownerr%rrr__get__Bs  zCachedSingletonProperty.__get__cCsHz|j}Wntyt||j}|_Ynwt|j|dSr)r%r&rr! __class__rr' invalidaterr)r%rrr __delete__Ks   z"CachedSingletonProperty.__delete__N)rrr"r#r+r/rrrrr$7s r$cs0eZdZdZfddZddZddZZS)CachedPropertya+Cached property descriptor for classes having potentially multiple instances associated to a single `~trac.env.Environment` instance. As we'll have potentially many different caches to monitor for this kind of cache, the key needs to be augmented by a string unique to each instance of the owner class. As the resulting id will be different for each instance of the owner class, we can't store it as a property of the descriptor class, so we store it back in the attribute used for augmenting the key (``key_attr``). cst|||_dSr)superrkey_attr)rrr2r,rrr`s  zCachedProperty.__init__cCs\|dur|St||j}t|tr#t||d|}t||j|t|j ||j |SN:) getattrr2 isinstancestrrr!setattrrr'rrr(rrrr+ds  zCachedProperty.__get__cCsPt||j}t|trt||jd|}t||j|t|j  |dSr4) r6r2r7r8rr!r,r9rr'r-r.rrrr/ms  zCachedProperty.__delete__)rrr"r#rr+r/ __classcell__rrr3rr0Ss   r0cs"tdr tSfdd}|S)a Method decorator creating a cached attribute from a data retrieval method. Accessing the cached attribute gives back the cached value. The data retrieval method is transparently called by the `CacheManager` on first use after the program start or after the cache has been invalidated. Invalidating the cache for this value is done by ``del``\ eting the attribute. Note that the cache validity is maintained using the `cache` table in the database. Cache invalidation is performed within a transaction block, and can be nested within another transaction block. When the decorator is used in a class for which instances behave as singletons within the scope of a given `~trac.env.Environment` (typically `~trac.core.Component` classes), the key used to identify the attribute in the database is constructed from the names of the containing module, class and retriever method:: class WikiSystem(Component): @cached def pages(self): return {name for name, in self.env.db_query( "SELECT DISTINCT name FROM wiki")} Otherwise, when the decorator is used in non-"singleton" objects, a string specifying the name of an attribute containing a string unique to the instance must be passed to the decorator. This value will be appended to the key constructed from module, class and method name:: class SomeClass(object): def __init__(self, env, name): self.env = env self.name = name self._metadata_id = name @cached('_metadata_id') def metadata(self): ... Note that in this case the key attribute is overwritten with a hash of the key on first access, so it should not be used for any other purpose. In either case, this decorator requires that the object on which it is used has an ``env`` attribute containing the application `~trac.env.Environment`. .. versionchanged:: 1.0 The data retrieval method used to be called with a single argument ``db`` containing a reference to a database connection. This is the same connection that can be retrieved via the normal `~trac.env.Environment.db_query` or `~trac.env.Environment.db_transaction`, so this is no longer needed and is not supported. __call__cs t|Sr)r0)fn fn_or_attrrr decorators zcached..decorator)hasattrr$)r>r?rr=rrus ; c@s4eZdZdZdZddZddZddZd d Zd S) rzCache manager.TcCs"i|_tddd|_t|_dS)N)metacache)_cacher_localrRLock_lockrrrrrszCacheManager.__init__cCsd|j_|j_dS)z!Reset per-request cache metadata.N)rDrArBrGrrrreset_metadataszCacheManager.reset_metadatac Cs|jj}|jj}|dur#|jd}t||j_}|j|j_}||d}z||\}} | |kr7|WSWn t yAYnw|jj} |j sz"|j|\}} ||<| |krl|WWdWdSWn t yxd} Ynw| d|fD]\}nd}|| kr|WdWdS||}||f||<|j|<|||<|WdWdS1swYWddS1swYdS)z*Get cached or fresh data for the given id.Nz SELECT id, generation FROM cache(SELECT generation FROM cache WHERE id=%s) rDrArBr'db_querydictrCcopyrKeyErrorrF) rr%rr) local_meta local_cacherA db_generationdata generationdbrrrrsX       "zCacheManager.getc Cs|jjV}|j:|d|f|d|fs!|d|dt|df|j|dz|jj|=Wn t t fy:YnwWdn1sEwYWddSWddS1s]wYdS)z(Invalidate cached data for the given id.z4UPDATE cache SET generation=generation+1 WHERE id=%srJz%INSERT INTO cache VALUES (%s, %s, %s)rz N) r'db_transactionrFr rrCpoprDrBrN TypeError)rr%rTrrrr-s(   "zCacheManager.invalidateN) rrr"r#requiredrrHrr-rrrrrs 0r)r trac.corertrac.util.concurrencyrr__all__r rpropertyrr$r0rrrrrrs   "B