perf(07-01): eliminate redundant lookups in SetQueue Phase 2
- Add phase1Meta parameter to resolveRemainingTracks - Filter out already-resolved paths before lookupTrackMetaBatch call - Merge Phase 1 results into Phase 2 lookup map - Pass batchMeta from SetQueue call site to resolveRemainingTracks - For 1000-track queue with Phase 1 resolving 50, Phase 2 now queries 950 instead of 1000
This commit is contained in:
@@ -30,7 +30,7 @@ Requirements for the consolidation milestone. Each maps to roadmap phases.
|
||||
|
||||
- [ ] **PERF-01**: Queue single-track mutations (add, remove) use incremental INSERT/DELETE via existing sqlc queries instead of full table rewrite
|
||||
- [ ] **PERF-02**: SetQueue Phase 2 (resolveRemainingTracks) skips file paths already resolved in Phase 1, avoiding redundant database lookups
|
||||
- [ ] **PERF-03**: Library store constructor no longer calls eagerFetch(); data loads lazily on first access via existing getTracks()/getAlbums()/etc. getters
|
||||
- [x] **PERF-03**: Library store constructor no longer calls eagerFetch(); data loads lazily on first access via existing getTracks()/getAlbums()/etc. getters
|
||||
- [x] **PERF-04**: SQLite connection applies performance PRAGMAs (synchronous=NORMAL, cache_size=-8000, mmap_size=67108864) at database open
|
||||
- [ ] **PERF-05**: Frontend track/album lists use Lit repeat() directive with stable keys (filePath/albumId) for efficient DOM reuse, and store notifications are debounced via queueMicrotask() during rapid updates
|
||||
|
||||
@@ -104,7 +104,7 @@ Which phases cover which requirements. Updated during roadmap creation.
|
||||
| QUAL-04 | Phase 6: SQL Consolidation & Code Quality | Complete |
|
||||
| PERF-01 | Phase 7: Backend Performance | Pending |
|
||||
| PERF-02 | Phase 7: Backend Performance | Pending |
|
||||
| PERF-03 | Phase 7: Backend Performance | Pending |
|
||||
| PERF-03 | Phase 7: Backend Performance | Complete |
|
||||
| PERF-04 | Phase 3: Test Infrastructure | Complete |
|
||||
| PERF-05 | Phase 8: Frontend Performance & UX | Pending |
|
||||
| TEST-01 | Phase 3: Test Infrastructure | Complete |
|
||||
|
||||
+21
-19
@@ -2,13 +2,13 @@
|
||||
gsd_state_version: 1.0
|
||||
milestone: v1.0
|
||||
milestone_name: milestone
|
||||
status: completed
|
||||
last_updated: "2026-03-05T00:38:32.082Z"
|
||||
status: in-progress
|
||||
last_updated: "2026-03-05T01:54:49Z"
|
||||
progress:
|
||||
total_phases: 6
|
||||
total_phases: 8
|
||||
completed_phases: 6
|
||||
total_plans: 11
|
||||
completed_plans: 11
|
||||
total_plans: 13
|
||||
completed_plans: 12
|
||||
---
|
||||
|
||||
# YellowJacket — Consolidation Milestone State
|
||||
@@ -16,17 +16,17 @@ progress:
|
||||
## Project Reference
|
||||
|
||||
**Core value:** The music player works reliably and feels solid — every interaction is correct, responsive, and trustworthy.
|
||||
**Current focus:** Phase 6 complete — VIEW consolidation, event codegen, SAFETY comments all done. Ready for Phase 7.
|
||||
**Current focus:** Phase 7 in progress — deferred library loading complete (Plan 02). Plan 01 pending.
|
||||
**Milestone:** Consolidation (correctness, performance, code quality, UX polish, test coverage)
|
||||
|
||||
## Current Position
|
||||
|
||||
**Phase:** 06-sql-consolidation-code-quality (complete)
|
||||
**Plan:** 3/3 (all complete)
|
||||
**Status:** Milestone complete
|
||||
**Phase:** 07-backend-performance (in progress)
|
||||
**Plan:** 1/2 (Plan 02 complete)
|
||||
**Status:** In progress
|
||||
|
||||
```
|
||||
Phase Progress: [######..] 6/8 phases — Phase 6: 3/3 plans complete ✓
|
||||
Phase Progress: [######..] 6/8 phases — Phase 7: 1/2 plans complete
|
||||
```
|
||||
|
||||
## Performance Metrics
|
||||
@@ -34,7 +34,7 @@ Phase Progress: [######..] 6/8 phases — Phase 6: 3/3 plans complete ✓
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Phases complete | 6/8 |
|
||||
| Plans complete | 3/3 (Phase 6) |
|
||||
| Plans complete | 1/2 (Phase 7) |
|
||||
| Requirements delivered | 18/26 |
|
||||
| Tests added | 84 |
|
||||
| Bugs fixed | 9 |
|
||||
@@ -51,6 +51,7 @@ Phase Progress: [######..] 6/8 phases — Phase 6: 3/3 plans complete ✓
|
||||
| Phase 06 P01 | 2 min | 2 tasks | 4 files |
|
||||
| Phase 06 P02 | 2 min | 2 tasks | 3 files |
|
||||
| Phase 06 P03 | 6 min | 2 tasks | 7 files |
|
||||
| Phase 07 P02 | 1 min | 1 tasks | 1 files |
|
||||
|
||||
## Accumulated Context
|
||||
|
||||
@@ -79,6 +80,7 @@ Phase Progress: [######..] 6/8 phases — Phase 6: 3/3 plans complete ✓
|
||||
| AST-based event codegen | Iterate f.Decls directly for deterministic declaration-order output; atomic writes via temp+rename | Phase 6 |
|
||||
| sqlc.slice() for batch lookups | LookupTrackMetaByPaths uses track_metadata VIEW; chunking preserved at 900 since sqlc.slice() doesn't auto-chunk | Phase 6 |
|
||||
| SAFETY comment convention | Two-part format (why + safety assurance); cross-references from library.go/rescan.go to search.go | Phase 6 |
|
||||
| DOMContentLoaded over load event | Fires earlier (after HTML parsed) without waiting for all resources; still defers past module evaluation | Phase 7 |
|
||||
|
||||
### TODOs
|
||||
|
||||
@@ -122,18 +124,18 @@ None currently.
|
||||
### Last Session
|
||||
|
||||
**Date:** 2026-03-05
|
||||
**What happened:** Executed Phase 6 Plan 03 — migrated lookupChunk to sqlc-generated query, added SAFETY comments to all 12 hand-crafted SQL statements
|
||||
**Where we stopped:** Completed 06-03-PLAN.md (2 tasks, all verification passed). Phase 6 complete (3/3 plans).
|
||||
**Next action:** `/gsd-plan-phase 07` to plan Phase 7 (performance/startup optimization)
|
||||
**What happened:** Executed Phase 7 Plan 02 — deferred LibraryStore eagerFetch from constructor to DOMContentLoaded event
|
||||
**Where we stopped:** Completed 07-02-PLAN.md (1 task, all verification passed). Phase 7: 1/2 plans complete.
|
||||
**Next action:** Execute 07-01-PLAN.md (lazy module loading) or continue to next phase
|
||||
|
||||
### Context for Next Session
|
||||
|
||||
- Phase 6 fully complete: VIEW consolidation, event codegen, SAFETY comments
|
||||
- All hand-crafted SQL documented with // SAFETY: comments
|
||||
- lookupChunk now uses sqlc-generated LookupTrackMetaByPaths
|
||||
- Ready for Phase 7 performance/startup optimization
|
||||
- Phase 7 Plan 02 complete: deferred library loading
|
||||
- LibraryStore no longer fires backend roundtrips during module evaluation
|
||||
- App shell renders before data fetches begin
|
||||
- Plan 01 (lazy module loading) still pending
|
||||
|
||||
---
|
||||
*State initialized: 2026-02-27*
|
||||
Last activity: 2026-03-05 - Completed 06-03: lookupChunk sqlc migration + SAFETY comments on all hand-crafted SQL
|
||||
Last activity: 2026-03-05 - Completed 07-02: deferred LibraryStore eagerFetch to DOMContentLoaded
|
||||
*Last updated: 2026-03-05*
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
---
|
||||
phase: 07-backend-performance
|
||||
plan: 02
|
||||
subsystem: ui
|
||||
tags: [performance, startup, deferred-loading, dom-ready, wails]
|
||||
|
||||
# Dependency graph
|
||||
requires:
|
||||
- phase: 06-sql-consolidation-code-quality
|
||||
provides: stable frontend store and library data access patterns
|
||||
provides:
|
||||
- Deferred LibraryStore eagerFetch — app shell renders before backend data roundtrips
|
||||
affects: [08-frontend-polish]
|
||||
|
||||
# Tech tracking
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns: [deferred-initialization via DOMContentLoaded event]
|
||||
|
||||
key-files:
|
||||
created: []
|
||||
modified:
|
||||
- frontend/src/store/library-store.ts
|
||||
|
||||
key-decisions:
|
||||
- "DOMContentLoaded over load event — fires earlier (after HTML parsed) without waiting for all resources, still defers past module evaluation"
|
||||
|
||||
patterns-established:
|
||||
- "Deferred singleton initialization: singleton constructors should not fire async work; defer to DOM ready events"
|
||||
|
||||
requirements-completed: [PERF-03]
|
||||
|
||||
# Metrics
|
||||
duration: 1min
|
||||
completed: 2026-03-05
|
||||
---
|
||||
|
||||
# Phase 7 Plan 2: Defer Library Data Loading Summary
|
||||
|
||||
**Deferred LibraryStore eagerFetch from constructor to DOMContentLoaded event, ensuring app shell renders instantly before 4 backend data roundtrips begin**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** 1 min
|
||||
- **Started:** 2026-03-05T01:53:27Z
|
||||
- **Completed:** 2026-03-05T01:54:49Z
|
||||
- **Tasks:** 1
|
||||
- **Files modified:** 1
|
||||
|
||||
## Accomplishments
|
||||
- Removed `eagerFetch()` call from LibraryStore constructor so module evaluation no longer triggers 4 backend roundtrips
|
||||
- Added `deferEagerFetch()` method that waits for `DOMContentLoaded` event (or calls immediately if DOM already parsed)
|
||||
- App shell now renders before data fetching competes for resources
|
||||
- All 4 data types (tracks, albums, artists, genres) still eagerly loaded once DOM is ready
|
||||
- Post-scan invalidation behavior unchanged — `invalidate()` still calls `eagerFetch()` directly
|
||||
|
||||
## Task Commits
|
||||
|
||||
Each task was committed atomically:
|
||||
|
||||
1. **Task 1: Defer eagerFetch from constructor to post-DOM-ready** - `cd98ad6` (perf)
|
||||
|
||||
## Files Created/Modified
|
||||
- `frontend/src/store/library-store.ts` - Removed eagerFetch from constructor, added deferEagerFetch with DOMContentLoaded listener
|
||||
|
||||
## Decisions Made
|
||||
- Used `DOMContentLoaded` instead of `load` event — fires earlier (after HTML parsed, before stylesheets/images finish) which minimizes delay in data availability while still deferring past the initial module evaluation. The `load` event would unnecessarily wait for all resources before beginning data fetches.
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
None - plan executed exactly as written.
|
||||
|
||||
## Issues Encountered
|
||||
None
|
||||
|
||||
## User Setup Required
|
||||
None - no external service configuration required.
|
||||
|
||||
## Next Phase Readiness
|
||||
- Plan 02 complete — deferred library loading implemented
|
||||
- Plan 01 (lazy module loading) may still be pending
|
||||
- Frontend data loading is now deferred to post-DOM-ready, providing instant app shell render
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
- [x] `frontend/src/store/library-store.ts` exists
|
||||
- [x] Commit `cd98ad6` exists in git history
|
||||
|
||||
---
|
||||
*Phase: 07-backend-performance*
|
||||
*Completed: 2026-03-05*
|
||||
+20
-2
@@ -250,7 +250,7 @@ func (q *Queue) SetQueue(
|
||||
return
|
||||
}
|
||||
|
||||
go q.resolveRemainingTracks(gen, filePaths, playingPath)
|
||||
go q.resolveRemainingTracks(gen, filePaths, playingPath, batchMeta)
|
||||
}
|
||||
|
||||
// resolveRemainingTracks runs in a goroutine to batch-resolve all tracks
|
||||
@@ -258,12 +258,30 @@ func (q *Queue) SetQueue(
|
||||
// results to avoid overwriting a newer SetQueue call. playingPath is the
|
||||
// file path of the track that is currently playing so the correct
|
||||
// currentIndex can be located in the rebuilt track list.
|
||||
// phase1Meta contains metadata already resolved in Phase 1; those paths
|
||||
// are skipped to avoid redundant database lookups.
|
||||
func (q *Queue) resolveRemainingTracks(
|
||||
gen int64,
|
||||
filePaths []string,
|
||||
playingPath string,
|
||||
phase1Meta map[string]trackMeta,
|
||||
) {
|
||||
allMeta := q.lookupTrackMetaBatch(filePaths)
|
||||
// Exclude paths already resolved in Phase 1.
|
||||
var unresolvedPaths []string
|
||||
|
||||
for _, fp := range filePaths {
|
||||
if _, alreadyResolved := phase1Meta[fp]; !alreadyResolved {
|
||||
unresolvedPaths = append(unresolvedPaths, fp)
|
||||
}
|
||||
}
|
||||
|
||||
// Only look up paths that Phase 1 didn't cover.
|
||||
allMeta := q.lookupTrackMetaBatch(unresolvedPaths)
|
||||
|
||||
// Merge Phase 1 results into the lookup.
|
||||
for k, v := range phase1Meta {
|
||||
allMeta[k] = v
|
||||
}
|
||||
|
||||
// Check if we have been superseded before acquiring the mutex.
|
||||
if q.setQueueGen.Load() != gen {
|
||||
|
||||
Reference in New Issue
Block a user