[PATCH RFC v2 05/25] review-tui: recompute an ev icted A·R·T cache entry
Christian Brauner <[email protected]>
| Newsgroups | org.kernel.linux.tools |
|---|---|
| Message-ID | <[email protected]> |
_invalidate_caches(change_id) evicts a single series from the A·R·T count cache, but _load_series() only refills that cache when the whole dict is None, so the evicted entry is never recomputed. The series dicts are rebuilt from scratch on every load, so nothing carries the old value forward either, and the series renders '-' in the A·R·T column for the rest of the session. Take, link, upgrade, snooze, unsnooze, waiting and thank all evict exactly one entry, so every one of them hits this. Refill whenever a wanted branch is missing from the cache rather than only when the cache is gone, and merge rather than replace so an intact cache still skips the subprocess. Signed-off-by: Christian Brauner (Amutable) <[email protected]> --- src/b4/review_tui/_tracking_app.py | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/src/b4/review_tui/_tracking_app.py b/src/b4/review_tui/_tracking_app.py index 69da8f58..11e79ef2 100644 --- a/src/b4/review_tui/_tracking_app.py +++ b/src/b4/review_tui/_tracking_app.py @@ -988,7 +988,11 @@ class TrackingApp(LoreNodeShutdownMixin, CheckRunnerMixin, App[Optional[str]]): self._cached_newest_revisions: Optional[Dict[str, int]] = None self._cached_revision_counts: Optional[Dict[str, int]] = None self._cached_revisions: Optional[Dict[str, List[Dict[str, Any]]]] = None - self._cached_art_counts: Optional[Dict[str, Tuple[int, int, int]]] = None + # A None value is a branch whose tip carries no tracking trailer + # block; cached as a miss so the refill below converges. + self._cached_art_counts: Optional[Dict[str, Optional[Tuple[int, int, int]]]] = ( + None + ) def _invalidate_caches(self, change_id: Optional[str] = None) -> None: """Drop cached data so the next _load_series re-fetches. @@ -1190,8 +1194,32 @@ class TrackingApp(LoreNodeShutdownMixin, CheckRunnerMixin, App[Optional[str]]): art_branches[branch_name] = branch_tips[branch_name] # --- Bulk ART counts (1 subprocess instead of N) --- - if self._cached_art_counts is None and art_branches and topdir: - self._cached_art_counts = _get_art_counts_batch(topdir, art_branches) + # Recompute whenever a wanted branch is missing, not only when the + # whole dict is gone: _invalidate_caches(change_id) evicts a single + # entry, which an `is None` test would never notice, leaving that + # series' A·R·T stuck at '-' for the session. + # + # Only the missing ones, though. The targeted eviction keeps the + # other entries precisely so they are not recomputed, and handing + # the whole map to the batch spends that back: one tracking commit + # read per branch under review, on every take, link, snooze or + # thank, to re-derive counts nothing has invalidated. + art_missing = { + name: sha + for name, sha in art_branches.items() + if not self._cached_art_counts or name not in self._cached_art_counts + } + if topdir and art_missing: + counts = _get_art_counts_batch(topdir, art_missing) + if self._cached_art_counts is None: + self._cached_art_counts = {} + self._cached_art_counts.update(counts) + # Misses recorded too, or a branch _get_art_counts_batch declines + # to return stays absent, the difference above never empties and + # a `git cat-file` fires on every reload -- once a second while a + # cron sweep bumps the DB mtime. + for branch_name in art_missing: + self._cached_art_counts.setdefault(branch_name, None) art_map = self._cached_art_counts or {} for series in self._all_series: change_id = series.get('change_id', '') -- 2.53.0