The track list payload is ~800 bytes a track: repeated keys, per-track cover URLs, unread fields #281

Open
opened 2026-10-06 02:40:28 +00:00 by yonlu · 1 comment
Owner

GetTracks returns one JSON object per track with 25 keys: ~800 bytes per track, 20.5 MB at 26 138 tracks. Roughly:

  • ~350 B/track is key names repeated on every row;
  • four cover URLs (CoverArtPath/Small/Medium/Large) that are identical for every track of an album;
  • artist, album, genre, composer, file type and track length strings repeated per track (~10 tracks per album);
  • LastPlayed and the three larger cover tiers, which the Tracks view does not read (details come from the track cache).

Serializing it is ~170 MB of transient Go allocation (struct per row, reflection-driven marshal, then copies), and parsing it is the WebView's 390 MB peak.

Proposed

Replace GetTracks with a columnar, dictionary-encoded table: one array per column, every repeated string column an index into one shared string table, built straight from the rows without an intermediate []Track. The frontend decodes it once into the same row objects the Tracks view uses (shared strings, so the JS heap shrinks too). Only the columns the Tracks view can display, sort or link by are included.

A Go test pins bytes-per-track on the fixture library so a new column has to raise the budget on purpose.

`GetTracks` returns one JSON object per track with 25 keys: ~800 bytes per track, 20.5 MB at 26 138 tracks. Roughly: - ~350 B/track is **key names** repeated on every row; - four cover URLs (`CoverArtPath/Small/Medium/Large`) that are identical for every track of an album; - artist, album, genre, composer, file type and track length strings repeated per track (~10 tracks per album); - `LastPlayed` and the three larger cover tiers, which the Tracks view does not read (details come from the track cache). Serializing it is ~170 MB of transient Go allocation (struct per row, reflection-driven marshal, then copies), and parsing it is the WebView's 390 MB peak. ### Proposed Replace `GetTracks` with a columnar, dictionary-encoded table: one array per column, every repeated string column an index into one shared string table, built straight from the rows without an intermediate `[]Track`. The frontend decodes it once into the same row objects the Tracks view uses (shared strings, so the JS heap shrinks too). Only the columns the Tracks view can display, sort or link by are included. A Go test pins bytes-per-track on the fixture library so a new column has to raise the budget on purpose.
yonlu self-assigned this 2026-10-06 02:40:43 +00:00
yonlu added the
Status
In Progress
label 2026-10-06 02:40:44 +00:00
Author
Owner

Plan 023 (scoped library payloads), in order 279 → 281 → 280 → 282, then 283 and 284. Measured before/after with make perf against the bulk seed.

Plan 023 (scoped library payloads), in order 279 → 281 → 280 → 282, then 283 and 284. Measured before/after with make perf against the bulk seed.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: yonlu/yellowjacket#281