This is an automated email from the ASF dual-hosted git repository.
sbp pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-release.git
The following commit(s) were added to refs/heads/main by this push:
new d682dd2 Use data from ASFQuart only, and cache it
d682dd2 is described below
commit d682dd2a0e10babbe34ef3147092bf72e11a3dd3
Author: Sean B. Palmer <[email protected]>
AuthorDate: Wed Jul 23 20:26:21 2025 +0100
Use data from ASFQuart only, and cache it
---
atr/storage/__init__.py | 83 +++++++++++++++++++++++--------------------------
1 file changed, 39 insertions(+), 44 deletions(-)
diff --git a/atr/storage/__init__.py b/atr/storage/__init__.py
index 70cd257..657b011 100644
--- a/atr/storage/__init__.py
+++ b/atr/storage/__init__.py
@@ -18,10 +18,13 @@
from __future__ import annotations
import contextlib
+import json
import logging
import time
from typing import TYPE_CHECKING, Final
+import asfquart.session
+
if TYPE_CHECKING:
from collections.abc import AsyncGenerator
@@ -313,8 +316,8 @@ class Write:
class ContextManagers:
def __init__(self, cache_for_at_most_seconds: int = 600):
self.__cache_for_at_most_seconds = cache_for_at_most_seconds
- self.__member_of: dict[str, set[str]] = {}
- self.__participant_of: dict[str, set[str]] = {}
+ self.__member_of_cache: dict[str, set[str]] = {}
+ self.__participant_of_cache: dict[str, set[str]] = {}
self.__last_refreshed = None
def __outdated(self) -> bool:
@@ -324,63 +327,55 @@ class ContextManagers:
since_last_refresh = now - self.__last_refreshed
return since_last_refresh > self.__cache_for_at_most_seconds
- async def __refresh(self, data: db.Session) -> None:
- start = time.perf_counter_ns()
- committees = await data.committee().all()
- for committee in committees:
- for member in committee.committee_members:
- if member not in self.__member_of:
- self.__member_of[member] = set()
- self.__member_of[member].add(committee.name)
- for participant in committee.committers:
- if participant not in self.__participant_of:
- self.__participant_of[participant] = set()
- self.__participant_of[participant].add(committee.name)
- self.__last_refreshed = int(time.time())
- finish = time.perf_counter_ns()
- logging.info(f"ContextManagers.__refresh took {finish - start:,} ns")
+ async def __member_and_participant(self, data: db.Session, asf_uid: str |
None) -> tuple[set[str], set[str]]:
+ if asf_uid is not None:
+ if not self.__outdated():
+ return self.__member_of_cache[asf_uid],
self.__participant_of_cache[asf_uid]
- async def member_of(self, data: db.Session, asf_uid: str | None = None) ->
set[str]:
start = time.perf_counter_ns()
+ try:
+ asfquart_session = await asfquart.session.read()
+ except Exception:
+ if asf_uid is None:
+ raise AccessError("No ASF UID, and not in an ASFQuart session")
+ asfquart_session_json = await data.ns_text_get("asfquart_session",
asf_uid)
+ if asfquart_session_json is None:
+ raise AccessError("No cached ASFQuart session")
+ asfquart_session = json.loads(asfquart_session_json)
+
+ if asfquart_session is None:
+ raise AccessError("No ASFQuart session")
if asf_uid is None:
- return set()
- if self.__outdated():
- # This races, but it doesn't matter
- await self.__refresh(data)
- committee_names_set = self.__member_of[asf_uid]
- finish = time.perf_counter_ns()
- logging.info(f"ContextManagers.member_of took {finish - start:,} ns")
- return committee_names_set
+ asf_uid = asfquart_session.uid
+ if asf_uid is None:
+ raise AccessError("No ASF UID, and not set in the ASFQuart
session")
+ elif asfquart_session.uid != asf_uid:
+ raise AccessError("ASF UID mismatch")
+
+ # TODO: Use our own LDAP calls instead of using sqlite as a cache
+ await data.ns_text_set("asfquart_session", asf_uid,
json.dumps(asfquart_session))
+ self.__member_of_cache[asf_uid] = set(asfquart_session.committees)
+ self.__participant_of_cache[asf_uid] = set(asfquart_session.projects)
+ self.__last_refreshed = int(time.time())
- async def participant_of(self, data: db.Session, asf_uid: str | None =
None) -> set[str]:
- start = time.perf_counter_ns()
- if asf_uid is None:
- return set()
- if self.__outdated():
- # This races, but it doesn't matter
- await self.__refresh(data)
- committee_names_set = self.__participant_of[asf_uid]
finish = time.perf_counter_ns()
- logging.info(f"ContextManagers.participant_of took {finish - start:,}
ns")
- return committee_names_set
+ logging.info(f"ContextManagers.__member_and_participant took {finish -
start:,} ns")
+
+ return self.__member_of_cache[asf_uid],
self.__participant_of_cache[asf_uid]
@contextlib.asynccontextmanager
async def read(self, asf_uid: str | None = None) -> AsyncGenerator[Read]:
async with db.session() as data:
# TODO: Replace data with a DatabaseReader instance
- member_of = await self.member_of(data, asf_uid)
- participant_of = await self.participant_of(data, asf_uid)
- r = Read(data, asf_uid, member_of, participant_of)
- yield r
+ member_of, participant_of = await
self.__member_and_participant(data, asf_uid)
+ yield Read(data, asf_uid, member_of, participant_of)
@contextlib.asynccontextmanager
async def write(self, asf_uid: str | None = None) -> AsyncGenerator[Write]:
async with db.session() as data:
# TODO: Replace data with a DatabaseWriter instance
- member_of = await self.member_of(data, asf_uid)
- participant_of = await self.participant_of(data, asf_uid)
- w = Write(data, asf_uid, member_of, participant_of)
- yield w
+ member_of, participant_of = await
self.__member_and_participant(data, asf_uid)
+ yield Write(data, asf_uid, member_of, participant_of)
_MANAGERS: Final[ContextManagers] = ContextManagers()
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]