Linux maintainer tooling and workflows
 help / color / mirror / Atom feed
From: Christian Brauner <brauner@kernel.org>
To: "Kernel.org Tools" <tools@kernel.org>
Cc: Konstantin Ryabitsev <konstantin@linuxfoundation.org>,
	 "Christian Brauner (Amutable)" <brauner@kernel.org>
Subject: [PATCH RFC v2 05/25] review-tui: recompute an evicted A·R·T cache entry
Date: Wed, 12 Aug 2026 23:46:46 +0200	[thread overview]
Message-ID: <20260812-work-b4-multiver-rows-v2-5-305d53cd723a@kernel.org> (raw)
In-Reply-To: <20260812-work-b4-multiver-rows-v2-0-305d53cd723a@kernel.org>

_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) <brauner@kernel.org>
---
 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


  parent reply	other threads:[~2026-08-12 21:47 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-12 21:46 [PATCH RFC v2 00/25] review: track and browse every version of a tracked series Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 01/25] review-tui: fix rethreaded series thread viewing Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 02/25] review: do not clear fields a re-adding caller does not know Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 03/25] review-tui: keep the rethread flag on an upgraded series row Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 04/25] review: guard the tracking-commit amend on the worktree, not the checkout Christian Brauner
2026-08-12 21:46 ` Christian Brauner [this message]
2026-08-12 21:46 ` [PATCH RFC v2 06/25] review: test the prerequisite fixes Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 07/25] review: serialize schema migrations against a concurrent opener Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 08/25] review: test the migration serialization Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 09/25] review: track message counts for all revisions of a series Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 10/25] review: give per-change_id state its own table Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 11/25] review: test per-revision message tracking Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 12/25] review-tui: poll every revision on u/U updates Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 13/25] review: test the per-revision poll sweep Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 14/25] review-tui: resolve the tracked revision in revision lists Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 15/25] review-tui: fall back when a cached thread blob has no series Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 16/25] review-tui: test revision resolution and the range-diff fallback Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 17/25] review: skip the catalog mirror when nothing moved Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 18/25] review: match a stray posting by message-id Christian Brauner
2026-08-12 21:47 ` [PATCH RFC v2 19/25] review: add backward discovery of older series revisions Christian Brauner
2026-08-12 21:47 ` [PATCH RFC v2 20/25] review-tui: add a "Find older revisions" action Christian Brauner
2026-08-12 21:47 ` [PATCH RFC v2 21/25] review: test the catalog mirror, stray matching and backward discovery Christian Brauner
2026-08-12 21:47 ` [PATCH RFC v2 22/25] review-tui: extract the Msgs column renderer from TrackedSeriesItem Christian Brauner
2026-08-12 21:47 ` [PATCH RFC v2 23/25] review-tui: give the unseen badge a column of its own Christian Brauner
2026-08-12 21:47 ` [PATCH RFC v2 24/25] review-tui: expand tracked series into per-version rows Christian Brauner
2026-08-12 21:47 ` [PATCH RFC v2 25/25] review-tui: test per-version tracker rows Christian Brauner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260812-work-b4-multiver-rows-v2-5-305d53cd723a@kernel.org \
    --to=brauner@kernel.org \
    --cc=konstantin@linuxfoundation.org \
    --cc=tools@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox