diff -r 1817f8946c22 -r faf279e33298 cubicweb/pyramid/tools.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cubicweb/pyramid/tools.py Mon Sep 26 14:52:12 2016 +0200 @@ -0,0 +1,79 @@ +"""Various tools. + +.. warning:: + + This module should be considered as internal implementation details. Use + with caution, as the API may change without notice. +""" + +#: A short-term cache for user clones. +#: used by cached_build_user to speed-up repetitive calls to build_user +#: The expiration is handled in a dumb and brutal way: the whole cache is +#: cleared every 5 minutes. +_user_cache = {} + + +def clone_user(repo, user): + """Clone a CWUser instance. + + .. warning:: + + The returned clone is detached from any cnx. + Before using it in any way, it should be attached to a cnx that has not + this user already loaded. + """ + CWUser = repo.vreg['etypes'].etype_class('CWUser') + clone = CWUser( + None, + rset=user.cw_rset.copy(), + row=user.cw_row, + col=user.cw_col, + groups=set(user._groups) if hasattr(user, '_groups') else None, + properties=dict(user._properties) + if hasattr(user, '_properties') else None) + clone.cw_attr_cache = dict(user.cw_attr_cache) + return clone + + +def cnx_attach_entity(cnx, entity): + """Attach an entity to a cnx.""" + entity._cw = cnx + if entity.cw_rset: + entity.cw_rset.req = cnx + + +def cached_build_user(repo, eid): + """Cached version of + :meth:`cubicweb.server.repository.Repository._build_user` + """ + with repo.internal_cnx() as cnx: + if eid in _user_cache: + entity = clone_user(repo, _user_cache[eid]) + # XXX the cnx is needed here so that the CWUser instance has an + # access to the vreg, which it needs when its 'prefered_language' + # property is accessed. + # If this property did not need a cnx to access a vreg, we could + # avoid the internal_cnx() and save more time. + cnx_attach_entity(cnx, entity) + return entity + + user = repo._build_user(cnx, eid) + user.cw_clear_relation_cache() + _user_cache[eid] = clone_user(repo, user) + return user + + +def clear_cache(): + """Clear the user cache""" + _user_cache.clear() + + +def includeme(config): + """Start the cache maintenance loop task. + + Automatically included by :func:`cubicweb.pyramid.make_cubicweb_application`. + """ + repo = config.registry['cubicweb.repository'] + interval = int(config.registry.settings.get( + 'cubicweb.usercache.expiration_time', 60*5)) + repo.looping_task(interval, clear_cache)