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
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""A dogpile.cache proxy that caches objects in the request local cache."""
from dogpile.cache import api
from dogpile.cache import proxy
from oslo_context import context as oslo_context
from oslo_serialization import msgpackutils
from keystone.models import revoke_model
class _RevokeModelHandler(object):
# NOTE(morganfainberg): There needs to be reserved "registry" entries set
# in oslo_serialization for application-specific handlers. We picked 127
# here since it's waaaaaay far out before oslo_serialization will use it.
identity = 127
handles = (revoke_model.RevokeTree,)
def __init__(self, registry):
self._registry = registry
def serialize(self, obj):
return msgpackutils.dumps(obj.revoke_map,
registry=self._registry)
def deserialize(self, data):
revoke_map = msgpackutils.loads(data, registry=self._registry)
revoke_tree = revoke_model.RevokeTree()
revoke_tree.revoke_map = revoke_map
return revoke_tree
# Register our new handler.
_registry = msgpackutils.default_registry
_registry.frozen = False
_registry.register(_RevokeModelHandler(registry=_registry))
_registry.frozen = True
class _ResponseCacheProxy(proxy.ProxyBackend):
__key_pfx = '_request_cache_%s'
def _get_request_context(self):
# Return the current context or a new/empty context.
return oslo_context.get_current() or oslo_context.RequestContext()
def _get_request_key(self, key):
return self.__key_pfx % key
def _set_local_cache(self, key, value, ctx=None):
# Set a serialized version of the returned value in local cache for
# subsequent calls to the memoized method.
if not ctx:
ctx = self._get_request_context()
serialize = {'payload': value.payload, 'metadata': value.metadata}
setattr(ctx, self._get_request_key(key), msgpackutils.dumps(serialize))
ctx.update_store()
def _get_local_cache(self, key):
# Return the version from our local request cache if it exists.
ctx = self._get_request_context()
try:
value = getattr(ctx, self._get_request_key(key))
except AttributeError:
return api.NO_VALUE
value = msgpackutils.loads(value)
return api.CachedValue(payload=value['payload'],
metadata=value['metadata'])
def _delete_local_cache(self, key):
# On invalidate/delete remove the value from the local request cache
ctx = self._get_request_context()
try:
delattr(ctx, self._get_request_key(key))
ctx.update_store()
except AttributeError: # nosec
# NOTE(morganfainberg): We will simply pass here, this value has
# not been cached locally in the request.
pass
def get(self, key):
value = self._get_local_cache(key)
if value is api.NO_VALUE:
value = self.proxied.get(key)
if value is not api.NO_VALUE:
self._set_local_cache(key, value)
return value
def set(self, key, value):
self._set_local_cache(key, value)
self.proxied.set(key, value)
def delete(self, key):
self._delete_local_cache(key)
self.proxied.delete(key)
def get_multi(self, keys):
values = {}
for key in keys:
v = self._get_local_cache(key)
if v is not api.NO_VALUE:
values[key] = v
query_keys = set(keys).difference(set(values.keys()))
values.update(dict(
zip(query_keys, self.proxied.get_multi(query_keys))))
return [values[k] for k in keys]
def set_multi(self, mapping):
ctx = self._get_request_context()
for k, v in mapping.items():
self._set_local_cache(k, v, ctx)
self.proxied.set_multi(mapping)
def delete_multi(self, keys):
for k in keys:
self._delete_local_cache(k)
self.proxied.delete_multi(keys)
|