BUG-149 - Shared directory tree rebuild is slow and UI-blocking on large shared sets¶
Summary¶
On large shared-directory sets, rebuilding the main-window Shared Files directory
filter tree (CSharedDirsTreeCtrl::FilterTreeReloadTree /
BuildSharedDirectoryTree) is slow and blocks the UI. Adding or removing a shared
directory triggers a full tree rebuild plus a full shared-file reload on the UI
thread.
This item covers the low-risk, tree-local quick wins. The dominant cost - the full shared-file re-walk on add - is tracked separately as [BUG-147], and file-list filter cost as [FEAT-028]/[FEAT-034].
Findings¶
- Uncached filesystem probes per rebuild.
BuildSharedDirectoryTree(SharedDirsTreeCtrl.cpp) callsIsAccessibleDirectoryForSharedTree(LongPathSeams::DirectoryExists) once per directory, with no caching. The member cachem_mapAccessibleDirectoryCacheis wiped at the start of everyFilterTreeReloadTreeand is not used by this path. Every add/remove/filter rebuild re-stats every shared directory; each stat can stall on network/removable/offline volumes. - Live redraw during rebuild.
FilterTreeReloadTreeinserts every node (InsertItem+TVI_SORT) withoutSetRedraw(FALSE), so each insert repaints, relayouts, and re-sorts. - Dead O(n^2) code.
FilterTreeAddSubDirectoriesandFilterTreeIsSubDirectoryare unused (only self-recursive) and rescan the whole directory list recomputing path keys per pair - a latent O(n^2) trap.
Fix (quick wins, tree-local)¶
- #3 redraw guard: wrap the
FilterTreeReloadTreerebuild inSetRedraw(FALSE)...SetRedraw(TRUE)+Invalidate(). - #2 persistent accessibility cache: route the builder's accessibility probe
through the cached member
IsSharedTreeDirectoryAccessible, stop wiping the cache on every rebuild, and invalidate it onOnVolumesChanged(mount/unmount). Unifies the probe onDirectoryExistssemantics. Trade-off: a path that loses reachability without a volume event keeps a stale accessibility overlay until the next volume change; acceptable versus N synchronous stats per rebuild. - #6 dead-code removal: delete
FilterTreeAddSubDirectoriesandFilterTreeIsSubDirectoryplus their header declarations.
The larger add-path full reload (#1) is deferred to [BUG-147].
Acceptance Criteria¶
- [ ] Adding/removing a shared directory no longer re-stats every shared directory on each rebuild (probes served from the persistent cache).
- [ ] Tree rebuild suppresses per-insert repaints.
- [ ] Volume mount/unmount still refreshes directory accessibility overlays.
- [ ] Dead filter-tree helpers are removed; no remaining callers.
- [x] Debug, Release, and diagnostics Release x64 app builds pass before commit.
Resolution¶
Implemented and shipped in 0.7.3-rc.2. The three tree-local quick-win
commits are ancestors of the rc.2 app head 38827709 (tag
emulebb-v0.7.3-rc.2): 8ac553c1 (suppress redraw during rebuild), f42ea4c8
(cache shared-dir accessibility across rebuilds), and ce0933a8 (remove dead
O(n^2) filter-tree helpers) in srchybrid/SharedDirsTreeCtrl.cpp. The rebuild is
now wrapped in SetRedraw(FALSE), accessibility probes are served from the
persistent member cache (invalidated on OnVolumesChanged), and the unused
FilterTreeAddSubDirectories / FilterTreeIsSubDirectory helpers are gone. The
larger add-path full reload remains tracked separately as BUG-147 (deferred
post-0.7.3). Build gates (x64 Debug/Release + diagnostics Release) passed before
the commits. Closed DONE on 2026-06-13.