* perf(subsonic): keep album/mediafile params on stack in response helpers
Two helpers were forcing their entire value parameter onto the heap via
pointer-to-field aliasing, adding one full-struct heap allocation per
response item on hot Subsonic endpoints (search3, getAlbumList2, etc.).
- childFromMediaFile assigned &mf.BirthTime to the returned Child,
pulling the whole ~1KB model.MediaFile to the heap on every call.
- buildDiscSubtitles passed &a.UpdatedAt to NewArtworkID inside a loop,
pulling the whole model.Album to the heap on every album with discs.
Both now copy the time.Time to a stack-local and use gg.P / &local so
only the small time.Time escapes. Verified via go build -gcflags=-m=2:
moved to heap: mf and moved to heap: a are gone at these sites.
* perf(metadata): avoid per-track closure allocations in PID computation
createGetPID was a factory that returned nested closures capturing
mf model.MediaFile (~992 bytes) by reference. Since it is called three
times per track during scans (trackPID, albumID, artistID), every track
triggered the allocation of three closures plus a heap copy of the full
MediaFile.
Refactor the body into package-level functions (computePID, getPIDAttr)
that take hash as an explicit parameter and the inner slice.Map callback
to an indexed for loop, removing the closure-capture of mf entirely.
trackPID/albumID/artistID now call computePID directly.
The tiny createGetPID wrapper was kept only for tests; move the
closure-building into the test file so production has no dead API.
Verified via go build -gcflags=-m=2 on model/metadata: no
"moved to heap: mf" anywhere in persistent_ids.go, and the callers in
map_mediafile.go / map_participants.go no longer heap-promote their
MediaFile argument.