/
cache.py
140 lines (111 loc) · 4.37 KB
/
cache.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# -*- coding: utf-8 -*-
from datetime import datetime
from persistent.mapping import PersistentMapping
from plone import api
from plone.i18n.normalizer import IIDNormalizer
from plone.memoize import ram
from plone.memoize.instance import Memojito
from plone.memoize.interfaces import ICacheChooser
from zope.component import getAllUtilitiesRegisteredFor
from zope.component import getUtility
from zope.component import queryUtility
from zope.schema.interfaces import IVocabularyFactory
import logging
logger = logging.getLogger('imio.helpers:cache')
VOLATILE_NAME_MAX_LENGTH = 200
VOLATILE_ATTR = '_volatile_cache_keys'
def cleanVocabularyCacheFor(vocabulary=None):
"""Clean _memojito_ attribute for given p_vocabulary name.
If p_vocabulary is None, it will clean every vocabulary _memojito_ attribute."""
# we received a vocabulary name, just clean this one
if vocabulary:
vocabularies = (queryUtility(IVocabularyFactory, vocabulary), )
else:
# clean every vocabularies having a _memojito_ attribute
vocabularies = getAllUtilitiesRegisteredFor(IVocabularyFactory)
for vocab in vocabularies:
if hasattr(vocab, Memojito.propname):
getattr(vocab, Memojito.propname).clear()
def cleanRamCache():
"""Clean the entire ram.cache."""
cache_chooser = getUtility(ICacheChooser)
thecache = cache_chooser('')
thecache.ramcache.invalidateAll()
def cleanRamCacheFor(methodId, obj=None):
"""Clean ram.cache for given p_methodId."""
cache_chooser = getUtility(ICacheChooser)
thecache = cache_chooser(methodId)
thecache.ramcache.invalidate(methodId)
def get_cachekey_volatile(name):
"""Helper for using a volatile corresponding to p_name
to be used as cachekey stored in a volatile.
If it exists, we return the value, either we store datetime.now()."""
portal = api.portal.get()
# use max_length of VOLATILE_NAME_MAX_LENGTH to avoid cropped names
# that could lead to having 2 names beginning with same part using same volatile...
normalized_name = queryUtility(IIDNormalizer).normalize(
name, max_length=VOLATILE_NAME_MAX_LENGTH)
volatile_name = normalized_name
volatiles = getattr(portal, VOLATILE_ATTR, None)
if volatiles is None:
portal._volatile_cache_keys = PersistentMapping()
volatiles = portal._volatile_cache_keys
date = volatiles.get(volatile_name)
if not date:
date = datetime.now()
volatiles[volatile_name] = date
return date
def invalidate_cachekey_volatile_for(name, get_again=False):
""" """
portal = api.portal.get()
normalized_name = queryUtility(IIDNormalizer).normalize(
name, max_length=VOLATILE_NAME_MAX_LENGTH)
volatile_name = normalized_name
volatiles = getattr(portal, VOLATILE_ATTR, {})
if volatile_name in volatiles:
del volatiles[volatile_name]
# when the key is invalidated, get_cachekey_volatile so it
# stores a new date and it avoids a second write
if get_again:
get_cachekey_volatile(volatile_name)
def _generate_params_key(*args, **kwargs):
items = []
for item in kwargs.items():
elements = []
for i in item:
if isinstance(i, list):
i = tuple(i)
elements.append(i)
items.append(tuple(elements))
return (args, frozenset(items))
def generate_key(func):
"""Return the complete path for a function e.g. module.function"""
if hasattr(func, '_cache_key'):
return func._cache_key
path = [func.__module__]
if hasattr(func, 'im_class'):
path.append(func.im_class.__name__)
path.append(func.__name__)
return '.'.join(path)
def volatile_cache_with_parameters(func):
def get_key(func, *args, **kwargs):
return (
get_cachekey_volatile(generate_key(func)),
_generate_params_key(*args, **kwargs),
)
def cache(get_key):
return ram.cache(get_key)
replacement = cache(get_key)(func)
replacement._cache_key = generate_key(func)
return replacement
def volatile_cache_without_parameters(func):
def get_key(func, *args, **kwargs):
return (
get_cachekey_volatile(generate_key(func)),
(),
)
def cache(get_key):
return ram.cache(get_key)
replacement = cache(get_key)(func)
replacement._cache_key = generate_key(func)
return replacement