]> git.hungrycats.org Git - bees/commitdiff
scan-next: log real dedupes the do-nothing floor declines
authorZygo Blaxell <bees@furryterror.org>
Wed, 15 Jul 2026 22:24:06 +0000 (18:24 -0400)
committerZygo Blaxell <bees@furryterror.org>
Sat, 5 Sep 2026 04:04:13 +0000 (00:04 -0400)
plan_accept_null counts every extent where the do-nothing floor wins, but
that lumps together the common no-duplicates case with the diagnostically
interesting one: an extent where a real covering was built and then lost
to the floor because its reference/extent cost outweighed the space it
would free.  Only the counter moved; nothing said which extents, how much
they would have freed, or why the floor rejected them.

Emit a "plan: null" log line when the floor wins and the best competing
real plan has a non-zero operation count.  The zero-op case (no duplicate
found, or none surviving the gates) ties the floor at debt 0 and stays
silent, so the line does not fire for every scanned extent.  When it does
fire the losing plan's debt is necessarily >= 0 (a negative-debt plan
would have displaced the floor), so the line reports the aggregate cost
that sank it: bytes_freed found, physical_freed earned, refs_added /
refs_created spent, extents_delta, and the positive space debt.  This is
the ref-cost-vs-physical-freed breakdown that names the cause -- a
compressed dst freed wholesale earns little physical credit against the
references its removal must rewrite.

Add plan_null_declined alongside so the interesting subset of
plan_accept_null is countable without grepping.

Assisted-by: Claude-Code:claude-opus-4-8
Assisted-by: Claude-Code:claude-opus-5
src/bees-scan-next.cc

index d99eec532893f8705c61cf300f400c8f2d9456db..a91785c97c2adb0e778a35058308c075df9acdcd 100644 (file)
@@ -3785,6 +3785,55 @@ Planner::run(const BtrfsTreeItem &bti,
                });
        // Record which plan type won the ballot (Plan A / Plan B / do-nothing).
        (*winner_it)->count_accepted();
+
+       // Diagnostic: the do-nothing floor won — but did it decline a *real*
+       // dedupe?  The common case (an extent with no duplicates) leaves the
+       // real plans with zero operations and debt tied at the floor (0.0);
+       // those must stay silent or this line fires for every scanned extent.
+       // Only when a covering with actual dedupe/copy ops was built and still
+       // lost (its debt is necessarily >= 0 here, since a negative-debt plan
+       // would have displaced the floor) do we emit a line.  A `plan: null`
+       // line is then exactly one beneficial-looking dedupe the floor gave up,
+       // carrying the ref-cost-vs-physical-freed breakdown that names why:
+       // refs_added/refs_created are the debt the plan adds, physical_freed the
+       // credit it earns, and a compressed dst freed wholesale earns little.
+       const bool null_won =
+               (!plan_a || winner_it->get() != plan_a.get()) &&
+               (!plan_b || winner_it->get() != plan_b.get());
+       if (null_won) {
+               const BeesPlan *declined = nullptr;
+               for (const BeesPlan *cand : {
+                       static_cast<const BeesPlan *>(plan_a.get()),
+                       static_cast<const BeesPlan *>(plan_b.get()),
+               }) {
+                       if (!cand) {
+                               continue;
+                       }
+                       // A real plan with no operations means no duplicate was
+                       // found (or none survived the gates): the no-op common
+                       // case.  Skip it so only genuine floor declines log.
+                       if (cand->cost().m_plan_ops == 0) {
+                               continue;
+                       }
+                       if (!declined || cand->cost().m_space_debt < declined->cost().m_space_debt) {
+                               declined = cand;
+                       }
+               }
+               if (declined) {
+                       BEESCOUNT(plan_null_declined);
+                       const auto &c = declined->cost();
+                       BEESLOGINFO("plan: null "
+                               << pretty(c.m_bytes_freed) << " declined "
+                               << c.m_plan_ops << "ops {"
+                               << to_hex(m_start.bytenr()) << "}"
+                               << " freed " << pretty(c.m_physical_freed)
+                               << " refs_added " << c.m_refs_added
+                               << " rc " << c.m_refs_created
+                               << " ed " << c.m_extents_delta
+                               << " debt +" << fixed << setprecision(1)
+                               << c.m_space_debt);
+               }
+       }
        plan = scan_next_build_extent_plan(m_ctx, **winner_it,
                *m_filter_cache, m_rewrite_policy);