@@ -57,7 +57,7 @@ class DeferredCache(Generic[KT, VT]):
5757 """Wraps an LruCache, adding support for Deferred results.
5858
5959 It expects that each entry added with set() will be a Deferred; likewise get()
60- may return an ObservableDeferred .
60+ will return a Deferred .
6161 """
6262
6363 __slots__ = (
@@ -130,16 +130,22 @@ def get(
130130 key : KT ,
131131 callback : Optional [Callable [[], None ]] = None ,
132132 update_metrics : bool = True ,
133- ) -> Union [ ObservableDeferred , VT ] :
133+ ) -> defer . Deferred :
134134 """Looks the key up in the caches.
135135
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+
136141 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
139144 update_metrics (bool): whether to update the cache hit rate metrics
140145
141146 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.
143149
144150 Raises:
145151 KeyError if the key is not found in the cache
@@ -152,15 +158,15 @@ def get(
152158 m = self .cache .metrics
153159 assert m # we always have a name, so should always have metrics
154160 m .inc_hits ()
155- return val .deferred
161+ return val .deferred . observe ()
156162
157163 val2 = self .cache .get (
158164 key , _Sentinel .sentinel , callbacks = callbacks , update_metrics = update_metrics
159165 )
160166 if val2 is _Sentinel .sentinel :
161167 raise KeyError ()
162168 else :
163- return val2
169+ return defer . succeed ( val2 )
164170
165171 def get_immediate (
166172 self , key : KT , default : T , update_metrics : bool = True
@@ -173,7 +179,36 @@ def set(
173179 key : KT ,
174180 value : defer .Deferred ,
175181 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+ """
177212 if not isinstance (value , defer .Deferred ):
178213 raise TypeError ("not a Deferred" )
179214
@@ -187,6 +222,8 @@ def set(
187222 if existing_entry :
188223 existing_entry .invalidate ()
189224
225+ # XXX: why don't we invalidate the entry in `self.cache` yet?
226+
190227 self ._pending_deferred_cache [key ] = entry
191228
192229 def compare_and_pop ():
@@ -230,7 +267,9 @@ def eb(_fail):
230267 # _pending_deferred_cache to the real cache.
231268 #
232269 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 ()
234273
235274 def prefill (self , key : KT , value : VT , callback : Callable [[], None ] = None ):
236275 callbacks = [callback ] if callback else []
0 commit comments