|
1 """Various tools. |
|
2 |
|
3 .. warning:: |
|
4 |
|
5 This module should be considered as internal implementation details. Use |
|
6 with caution, as the API may change without notice. |
|
7 """ |
|
8 |
|
9 #: A short-term cache for user clones. |
|
10 #: used by cached_build_user to speed-up repetitive calls to build_user |
|
11 #: The expiration is handled in a dumb and brutal way: the whole cache is |
|
12 #: cleared every 5 minutes. |
|
13 _user_cache = {} |
|
14 |
|
15 |
|
16 def clone_user(repo, user): |
|
17 """Clone a CWUser instance. |
|
18 |
|
19 .. warning:: |
|
20 |
|
21 The returned clone is detached from any cnx. |
|
22 Before using it in any way, it should be attached to a cnx that has not |
|
23 this user already loaded. |
|
24 """ |
|
25 CWUser = repo.vreg['etypes'].etype_class('CWUser') |
|
26 clone = CWUser( |
|
27 None, |
|
28 rset=user.cw_rset.copy(), |
|
29 row=user.cw_row, |
|
30 col=user.cw_col, |
|
31 groups=set(user._groups) if hasattr(user, '_groups') else None, |
|
32 properties=dict(user._properties) |
|
33 if hasattr(user, '_properties') else None) |
|
34 clone.cw_attr_cache = dict(user.cw_attr_cache) |
|
35 return clone |
|
36 |
|
37 |
|
38 def cnx_attach_entity(cnx, entity): |
|
39 """Attach an entity to a cnx.""" |
|
40 entity._cw = cnx |
|
41 if entity.cw_rset: |
|
42 entity.cw_rset.req = cnx |
|
43 |
|
44 |
|
45 def cached_build_user(repo, eid): |
|
46 """Cached version of |
|
47 :meth:`cubicweb.server.repository.Repository._build_user` |
|
48 """ |
|
49 with repo.internal_cnx() as cnx: |
|
50 if eid in _user_cache: |
|
51 entity = clone_user(repo, _user_cache[eid]) |
|
52 # XXX the cnx is needed here so that the CWUser instance has an |
|
53 # access to the vreg, which it needs when its 'prefered_language' |
|
54 # property is accessed. |
|
55 # If this property did not need a cnx to access a vreg, we could |
|
56 # avoid the internal_cnx() and save more time. |
|
57 cnx_attach_entity(cnx, entity) |
|
58 return entity |
|
59 |
|
60 user = repo._build_user(cnx, eid) |
|
61 user.cw_clear_relation_cache() |
|
62 _user_cache[eid] = clone_user(repo, user) |
|
63 return user |
|
64 |
|
65 |
|
66 def clear_cache(): |
|
67 """Clear the user cache""" |
|
68 _user_cache.clear() |
|
69 |
|
70 |
|
71 def includeme(config): |
|
72 """Start the cache maintenance loop task. |
|
73 |
|
74 Automatically included by :func:`cubicweb.pyramid.make_cubicweb_application`. |
|
75 """ |
|
76 repo = config.registry['cubicweb.repository'] |
|
77 interval = int(config.registry.settings.get( |
|
78 'cubicweb.usercache.expiration_time', 60*5)) |
|
79 repo.looping_task(interval, clear_cache) |