v0.7.0: startup speed — the 21k-track library stops freezing
Three reported symptoms, one shape: every operation was whole-library, whole-file, on the Qt main thread. Measured on the real library (21,482 tracks, 506 playlists, 15 MB library.json). The track table sorted through a QSortFilterProxyModel, which asks data() for a value on every comparison — 580k Python round trips, 8.5 s per table load, paid again on every reload. TrackTableModel now keeps _tracks in canonical (playlist) order plus an _order index list and sorts a key list computed once per track. Nothing used the proxy's filtering. Sorting by # is the identity order, so "source row" still means "playlist position" for drag-reorder. 8.5 s -> 0.13 s; MainWindow() 18.1 s -> 0.79 s. Smart rules compile to closures once per evaluate() instead of being re-dispatched per track — the operator lookup, casefolding the query and parsing the rule's own date constants all leave the 21k-iteration loop (_match_date was re-parsing its own constant 21,482 times per rule). Verified identical membership against the old evaluator on all 20 real smart playlists. 2.54 s -> 0.72 s, and it now runs after the first paint. Also: _reconcile_track skips two to_dict() round trips per unchanged track (MERGEABLE_FIELDS in the resolver is the single source of truth for what a merge touches); no git subprocess on the startup path (Updater.enabled is probed lazily on the background thread, version-button tooltip deferred); and .resolved/ is pruned to the newest 10 snapshots — it had reached 1.7 GB across 73 snapshots inside the Syncthing share. Time to interactive window ~15 s -> 3.2 s. The mid-session freeze when Syncthing delivers a change — a full reload + recompute + table rebuild with the window already on screen, which is what GNOME was offering to force-quit — ~16 s -> 3.8 s. The merge rework itself (playlist ordering, per-machine play journal, quieting the dialog) is queued in TASKS.md as Round 36. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,36 @@ When a round closes, move its finished items to `tasks-done.md`.
|
||||
|
||||
- [ ] archive the done tasks in here to another file, this is crufty....
|
||||
|
||||
## Round 36 — the merge rework (planned, Round 35 covered the speed half)
|
||||
|
||||
The three symptoms in Round 35 shared a root cause; that round fixed the
|
||||
performance half. This is the correctness half.
|
||||
|
||||
- [ ] **Playlist merges lose position.** `_merge_playlist` is a 2-way union with
|
||||
no common ancestor: it takes one side's order wholesale and *appends* the
|
||||
other side's extras, so a track inserted in the middle on one machine
|
||||
arrives at the tail on the other (this is what happened to `nissa one`).
|
||||
Replace with an anchor-based merge — insert each side-only track after its
|
||||
nearest preceding common anchor. Same in `_reconcile_playlist`.
|
||||
- [ ] **mtime is a lie for playlists.** `mark_playlist_settings_dirty` rewrites
|
||||
the whole playlist file for UI-only changes, and because the last column
|
||||
is stretch-sized, *resizing the window* rewrites the open playlist's JSON.
|
||||
So "most recently edited" often means "most recently resized". Give
|
||||
`Playlist` a `date_modified` bumped only in `_set_track_ids`, and merge on
|
||||
that.
|
||||
- [ ] **`max()` play counts discard concurrent plays.** Base 100, one machine
|
||||
plays 5 (105), the other plays 3 (103) → merge keeps 105 and those 3 are
|
||||
gone. Per-machine `plays/<machine-id>.json` journal (machine id kept
|
||||
outside the synced dir): only its owner ever writes it, so play data can
|
||||
never conflict, effective count = base + sum of journals, and `library.json`
|
||||
stops being rewritten every 3 s during playback — which is what generates
|
||||
the conflicts in the first place.
|
||||
- [ ] **Quiet the merge dialog.** Lossless merges (counts and dates only) should
|
||||
be a status-bar line, not a window; keep the dialog for lossy cases, and
|
||||
reuse one instance so six can never stack up again.
|
||||
- [ ] Consider a `.stignore` for `.resolved` so merge backups stop syncing
|
||||
(Round 35 bounded the folder to 10 snapshots, but it still replicates).
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user