Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Add type hints to response cache. #8507

Merged
merged 3 commits into from
Oct 9, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/8507.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add type hints to various parts of the code base.
1 change: 1 addition & 0 deletions mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ files =
synapse/types.py,
synapse/util/async_helpers.py,
synapse/util/caches/descriptors.py,
synapse/util/caches/response_cache.py,
synapse/util/caches/stream_change_cache.py,
synapse/util/metrics.py,
tests/replication,
Expand Down
4 changes: 2 additions & 2 deletions synapse/handlers/initial_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def __init__(self, hs: "HomeServer"):
self.storage = hs.get_storage()
self.state_store = self.storage.state

def snapshot_all_rooms(
async def snapshot_all_rooms(
self,
user_id: str,
pagin_config: PaginationConfig,
Expand Down Expand Up @@ -84,7 +84,7 @@ def snapshot_all_rooms(
include_archived,
)

return self.snapshot_cache.wrap(
return await self.snapshot_cache.wrap(
key,
self._snapshot_all_rooms,
user_id,
Expand Down
3 changes: 3 additions & 0 deletions synapse/handlers/room.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@ async def upgrade_room(

# Check if this room is already being upgraded by another person
for key in self._upgrade_response_cache.pending_result_cache:
# The keys of pending_result_cache just need to be hashable, but in
# this case we know that it is a tuple.
assert isinstance(key, tuple)
clokep marked this conversation as resolved.
Show resolved Hide resolved
if key[0] == old_room_id and key[1] != user_id:
# Two different people are trying to upgrade the same room.
# Send the second an error.
Expand Down
46 changes: 25 additions & 21 deletions synapse/util/caches/response_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
from typing import TYPE_CHECKING, Any, Callable, Dict, Hashable, Optional

from twisted.internet import defer

from synapse.logging.context import make_deferred_yieldable, run_in_background
from synapse.util.async_helpers import ObservableDeferred
from synapse.util.caches import register_cache

if TYPE_CHECKING:
from synapse.app.homeserver import HomeServer

logger = logging.getLogger(__name__)


Expand All @@ -31,22 +35,23 @@ class ResponseCache:
used rather than trying to compute a new response.
"""

def __init__(self, hs, name, timeout_ms=0):
self.pending_result_cache = {} # Requests that haven't finished yet.
def __init__(self, hs: "HomeServer", name: str, timeout_ms: float = 0):
# Requests that haven't finished yet.
self.pending_result_cache = {} # type: Dict[Hashable, ObservableDeferred]

self.clock = hs.get_clock()
self.timeout_sec = timeout_ms / 1000.0

self._name = name
self._metrics = register_cache("response_cache", name, self, resizable=False)

def size(self):
def size(self) -> int:
return len(self.pending_result_cache)

def __len__(self):
def __len__(self) -> int:
return self.size()

def get(self, key):
def get(self, key: Hashable) -> Optional[defer.Deferred]:
"""Look up the given key.

Can return either a new Deferred (which also doesn't follow the synapse
Expand All @@ -58,12 +63,11 @@ def get(self, key):
from an absent cache entry.

Args:
key (hashable):
key: key to get/set in the cache

Returns:
twisted.internet.defer.Deferred|None|E: None if there is no entry
for this key; otherwise either a deferred result or the result
itself.
None if there is no entry for this key; otherwise a deferred which
resolves to the result.
"""
result = self.pending_result_cache.get(key)
if result is not None:
Expand All @@ -73,7 +77,7 @@ def get(self, key):
self._metrics.inc_misses()
return None

def set(self, key, deferred):
def set(self, key: Hashable, deferred: defer.Deferred) -> defer.Deferred:
"""Set the entry for the given key to the given deferred.

*deferred* should run its callbacks in the sentinel logcontext (ie,
Expand All @@ -85,12 +89,11 @@ def set(self, key, deferred):
result. You will probably want to make_deferred_yieldable the result.

Args:
key (hashable):
deferred (twisted.internet.defer.Deferred[T):
key: key to get/set in the cache
deferred: The deferred which resolves to the result.

Returns:
twisted.internet.defer.Deferred[T]|T: a new deferred, or the actual
result.
A new deferred which resolves to the actual result.
"""
result = ObservableDeferred(deferred, consumeErrors=True)
self.pending_result_cache[key] = result
Expand All @@ -107,7 +110,9 @@ def remove(r):
result.addBoth(remove)
return result.observe()

def wrap(self, key, callback, *args, **kwargs):
def wrap(
self, key: Hashable, callback: "Callable[..., Any]", *args: Any, **kwargs: Any
) -> defer.Deferred:
"""Wrap together a *get* and *set* call, taking care of logcontexts

First looks up the key in the cache, and if it is present makes it
Expand All @@ -118,29 +123,28 @@ def wrap(self, key, callback, *args, **kwargs):

Example usage:

@defer.inlineCallbacks
def handle_request(request):
async def handle_request(request):
# etc
return result

result = yield response_cache.wrap(
result = await response_cache.wrap(
key,
handle_request,
request,
)

Args:
key (hashable): key to get/set in the cache
key: key to get/set in the cache

callback (callable): function to call if the key is not found in
callback: function to call if the key is not found in
the cache

*args: positional parameters to pass to the callback, if it is used

**kwargs: named parameters to pass to the callback, if it is used

Returns:
twisted.internet.defer.Deferred: yieldable result
Deferred which resolves to the result
"""
result = self.get(key)
if not result:
Expand Down