@@ -25,8 +25,7 @@ async def set(self, item: DocItem, value: str) -> None:
2525
2626 All keys from a single page are stored together, expiring a week after the first set.
2727 """
28- url_key = remove_suffix (item .relative_url_path , ".html" )
29- redis_key = f"{ self .namespace } :{ item .package } :{ url_key } "
28+ redis_key = f"{ self .namespace } :{ item_key (item )} "
3029 needs_expire = False
3130
3231 with await self ._get_pool_connection () as connection :
@@ -44,10 +43,36 @@ async def set(self, item: DocItem, value: str) -> None:
4443 @namespace_lock
4544 async def get (self , item : DocItem ) -> Optional [str ]:
4645 """Return the Markdown content of the symbol `item` if it exists."""
47- url_key = remove_suffix (item .relative_url_path , ".html" )
46+ with await self ._get_pool_connection () as connection :
47+ return await connection .hget (f"{ self .namespace } :{ item_key (item )} " , item .symbol_id , encoding = "utf8" )
4848
49+ @namespace_lock
50+ async def delete (self , package : str ) -> bool :
51+ """Remove all values for `package`; return True if at least one key was deleted, False otherwise."""
52+ with await self ._get_pool_connection () as connection :
53+ package_keys = [
54+ package_key async for package_key in connection .iscan (match = f"{ self .namespace } :{ package } :*" )
55+ ]
56+ if package_keys :
57+ await connection .delete (* package_keys )
58+ return True
59+ return False
60+
61+
62+ class StaleItemCounter (RedisObject ):
63+ """Manage increment counters for stale `DocItem`s."""
64+
65+ @namespace_lock
66+ async def increment_for (self , item : DocItem ) -> int :
67+ """
68+ Increment the counter for `item` by 1, set it to expire in 3 weeks and return the new value.
69+
70+ If the counter didn't exist, initialize it with 1.
71+ """
72+ key = f"{ self .namespace } :{ item_key (item )} :{ item .symbol_id } "
4973 with await self ._get_pool_connection () as connection :
50- return await connection .hget (f"{ self .namespace } :{ item .package } :{ url_key } " , item .symbol_id , encoding = "utf8" )
74+ await connection .expire (key , WEEK_SECONDS * 3 )
75+ return int (await connection .incr (key ))
5176
5277 @namespace_lock
5378 async def delete (self , package : str ) -> bool :
@@ -62,10 +87,6 @@ async def delete(self, package: str) -> bool:
6287 return False
6388
6489
65- def remove_suffix (string : str , suffix : str ) -> str :
66- """Remove `suffix` from end of `string`."""
67- # TODO replace usages with str.removesuffix on 3.9
68- if string .endswith (suffix ):
69- return string [:- len (suffix )]
70- else :
71- return string
90+ def item_key (item : DocItem ) -> str :
91+ """Get the redis redis key string from `item`."""
92+ return f"{ item .package } :{ item .relative_url_path .removesuffix ('.html' )} "
0 commit comments