@@ -57,7 +57,7 @@ class DeferredCache(Generic[KT, VT]):
57
57
"""Wraps an LruCache, adding support for Deferred results.
58
58
59
59
It expects that each entry added with set() will be a Deferred; likewise get()
60
- may return an ObservableDeferred .
60
+ will return a Deferred .
61
61
"""
62
62
63
63
__slots__ = (
@@ -130,16 +130,22 @@ def get(
130
130
key : KT ,
131
131
callback : Optional [Callable [[], None ]] = None ,
132
132
update_metrics : bool = True ,
133
- ) -> Union [ ObservableDeferred , VT ] :
133
+ ) -> defer . Deferred :
134
134
"""Looks the key up in the caches.
135
135
136
+ For symmetry with set(), this method does *not* follow the synapse logcontext
137
+ rules: the logcontext will not be cleared on return, and the Deferred will run
138
+ its callbacks in the sentinel context. In other words: wrap the result with
139
+ make_deferred_yieldable() before `await`ing it.
140
+
136
141
Args:
137
- key(tuple)
138
- callback(fn) : Gets called when the entry in the cache is invalidated
142
+ key:
143
+ callback: Gets called when the entry in the cache is invalidated
139
144
update_metrics (bool): whether to update the cache hit rate metrics
140
145
141
146
Returns:
142
- Either an ObservableDeferred or the result itself
147
+ A Deferred which completes with the result. Note that this may later fail
148
+ if there is an ongoing set() operation which later completes with a failure.
143
149
144
150
Raises:
145
151
KeyError if the key is not found in the cache
@@ -152,15 +158,15 @@ def get(
152
158
m = self .cache .metrics
153
159
assert m # we always have a name, so should always have metrics
154
160
m .inc_hits ()
155
- return val .deferred
161
+ return val .deferred . observe ()
156
162
157
163
val2 = self .cache .get (
158
164
key , _Sentinel .sentinel , callbacks = callbacks , update_metrics = update_metrics
159
165
)
160
166
if val2 is _Sentinel .sentinel :
161
167
raise KeyError ()
162
168
else :
163
- return val2
169
+ return defer . succeed ( val2 )
164
170
165
171
def get_immediate (
166
172
self , key : KT , default : T , update_metrics : bool = True
@@ -173,7 +179,36 @@ def set(
173
179
key : KT ,
174
180
value : defer .Deferred ,
175
181
callback : Optional [Callable [[], None ]] = None ,
176
- ) -> ObservableDeferred :
182
+ ) -> defer .Deferred :
183
+ """Adds a new entry to the cache (or updates an existing one).
184
+
185
+ The given `value` *must* be a Deferred.
186
+
187
+ First any existing entry for the same key is invalidated. Then a new entry
188
+ is added to the cache for the given key.
189
+
190
+ Until the `value` completes, calls to `get()` for the key will also result in an
191
+ incomplete Deferred, which will ultimately complete with the same result as
192
+ `value`.
193
+
194
+ If `value` completes successfully, subsequent calls to `get()` will then return
195
+ a completed deferred with the same result. If it *fails*, the cache is
196
+ invalidated and subequent calls to `get()` will raise a KeyError.
197
+
198
+ If another call to `set()` happens before `value` completes, then (a) any
199
+ invalidation callbacks registered in the interim will be called, (b) any
200
+ `get()`s in the interim will continue to complete with the result from the
201
+ *original* `value`, (c) any future calls to `get()` will complete with the
202
+ result from the *new* `value`.
203
+
204
+ It is expected that `value` does *not* follow the synapse logcontext rules - ie,
205
+ if it is incomplete, it runs its callbacks in the sentinel context.
206
+
207
+ Args:
208
+ key: Key to be set
209
+ value: a deferred which will complete with a result to add to the cache
210
+ callback: An optional callback to be called when the entry is invalidated
211
+ """
177
212
if not isinstance (value , defer .Deferred ):
178
213
raise TypeError ("not a Deferred" )
179
214
@@ -187,6 +222,8 @@ def set(
187
222
if existing_entry :
188
223
existing_entry .invalidate ()
189
224
225
+ # XXX: why don't we invalidate the entry in `self.cache` yet?
226
+
190
227
self ._pending_deferred_cache [key ] = entry
191
228
192
229
def compare_and_pop ():
@@ -230,7 +267,9 @@ def eb(_fail):
230
267
# _pending_deferred_cache to the real cache.
231
268
#
232
269
observer .addCallbacks (cb , eb )
233
- return observable
270
+
271
+ # we return a new Deferred which will be called before any subsequent observers.
272
+ return observable .observe ()
234
273
235
274
def prefill (self , key : KT , value : VT , callback : Callable [[], None ] = None ):
236
275
callbacks = [callback ] if callback else []
0 commit comments