The background update installs and conformance-checks every catalog package again on every run, twice, with nothing to update (about 150 s per daemon start) #586
Labels
No labels
code-review
correctness
dos
performance
security
severity/high
severity/low
severity/medium
tech-debt
Kind/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status
Need More Info
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
h-dv/code-index#586
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found on the development machine while following up #520, 2026-11-13, on the released v0.41.52 (the same pattern is in the daemon log since at least 2026-11-11).
What happens
After a daemon is ready it starts
code-index plugin update --root <project>in the background. On a project with eleven catalog packages and nothing to update, one such runupdate_notifications 0 of 11 checked package(s) have something to act on,installed … verdict passed … verdict recordedfor 11 distinct digests in one run.Duration of the last five runs on this machine, from the daemon log ("checking configured plugin updates in the background" to "… check finished"): 162 s, 154 s, 169 s, 66 s, 156 s. Three of them started within 25 minutes of each other today.
The verdict files of these digests already existed before each run; they are rewritten every time.
Why it matters
approverefused 19 times in 2.5 minutes). The lock scope is fixed on the next-train branch; the work itself is not.Expected
To establish first
Acceptance
Round 1 of the fix (lane r40, on its branch, not merged): cause found, conformance work removed; a second cause remains.
Cause, both parts present since commit
118b4311, first released in v0.41.24:Round 1 reuses the existing verdict gate (digest and schema, passing outcome, engine version and flags, coverage of the granted capabilities; the code-index build is not part of a verdict's key) and handles each digest once per run. The run now prints what it did, for example
update_work 7 compared, 7 already verified, 0 installed, 0 conformance-checked. Named updates (plugin update <id>) already returned early when the catalog pin equals the current digest and did not have this defect.Lead's measurement, quiet machine (load 1.4), a copy of this machine's package home (45 stored archives, 141 MiB), a scratch project with the seven first-party languages, the real catalog,
plugin update --root <project>run twice:So the repeated conformance was about a third of the cost. The same run at debug level shows the rest: 563 complete archive reads and 581 metadata parses in one run; the archives of the active packages are read 75 times each. This is the defect class of #581 again (the store is enumerated and every archive read and hashed in full, many times per process), on the update path, which the #581 fix did not touch.
Round 2 is running: enumerate the store once per run, read and hash an archive only when a decision needs its bytes, a counting test with a ceiling that does not depend on how many unrelated packages are installed, and the same two counts for the other operator commands (
languages enable,plugin status,plugin doctor,approve,link add,languages list) as a table.Fixed on the next-train branch (lane r40, two rounds, merged locally as
968a57eb; not released yet).Second cause, attributed. In the run of 563 archive reads, 38 archives were read once and the seven active ones 75 times each. The reads came from: the store scan (45),
consider→ resolve / displacers / withdrawn →getfor local candidates (203), the catalog prefilter (154), the catalogconsider(147), and two moregetper package (14). Everygetread the archive and hashed it twice.Change.
plugin statusandplugin doctoruse the same snapshot.Lead's measurement, copy of this machine's package home (45 archives, 141 MiB), scratch project with the seven first-party languages, real catalog. The machine was not quiet for the last row (load 8), which makes that figure an upper bound:
plugin update --root(The read and parse counts of the first row are the worker's; the other figures are mine.)
Other commands on the same store, after the change (my run):
plugin status2.1 s (45 reads),plugin doctor1.6 s (45 reads; 164 before, per the worker),languages list0.6 s (7 reads).Tests. A no-op update on a store with 0 and with 8 unrelated installed packages performs the same number of full reads (1, for the first verification of content in the fixture) and never more; a new catalog digest is installed and checked exactly once; a verdict recorded for another engine configuration is renewed exactly once; one run never handles a digest twice. The worker reported the mutations red (four in each round).
Not changed, counted for a later lane (worker's figures, same store):
languages enablefor seven languages on a fresh project: 77 full reads, 98 parses, 12.7 s. The caller chain is bundled adoption →cmd_add→ admit → activation, each with its own store value.plugin addof an installed digest: 29 reads.languages list: 7 reads, 14 parses.plugin statusandplugin doctorstill read every archive once (45); they could work from manifests.One red in the worker's full indexer run, not attributed to this change:
member_lookup::a_thousand_overriding_users_cost_one_decision_not_one_per_sitetook 94 s against its 60 s ceiling while three workers were building on the machine. Alone it takes 5.2 s on this lane's tree (two runs) and 12.8 s on the branch before the merge under the same load. The full gate run on a quiet machine decides it.Released in v0.41.53 (
59b8bc3d); verified on the installed binaries.A background update with nothing to do no longer reinstalls or rechecks packages already verified for this engine, and reads each archive at most once per run. On a store with 45 packages, it went from 43 s and 584 complete archive reads to 1.4 s and 7 reads;
plugin statusandplugin doctoralso read each installed archive once.Verified on the installed release:
586_noop_update: the update installs and conformance-checks nothing and completes in under 10 s. PASS: .260299055s; 0 installed, 0 conformance-checkedRemaining scope:
languages enablefor several languages,plugin addandlanguages liststill read installed archives more often than needed: 77, 29 and 7 complete reads on a store with 45 archives.